From 16f504a9dca3fe3b70568f67b7d41241ae485288 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:49:04 +0200 Subject: Adding upstream version 7.0.6-dfsg. Signed-off-by: Daniel Baumann --- include/iprt/Makefile.kup | 0 include/iprt/alloc.h | 46 + include/iprt/alloca.h | 110 + include/iprt/asm-amd64-x86-watcom-16.h | 831 +++ include/iprt/asm-amd64-x86-watcom-32.h | 737 +++ include/iprt/asm-amd64-x86.h | 3447 +++++++++++ include/iprt/asm-arm.h | 321 + include/iprt/asm-math.h | 445 ++ include/iprt/asm-watcom-x86-16.h | 983 +++ include/iprt/asm-watcom-x86-32.h | 741 +++ include/iprt/asm.h | 8132 +++++++++++++++++++++++++ include/iprt/asmdefs.mac | 1379 +++++ include/iprt/asn1-generator-asn1-decoder.h | 40 + include/iprt/asn1-generator-core.h | 50 + include/iprt/asn1-generator-init.h | 48 + include/iprt/asn1-generator-internal-header.h | 39 + include/iprt/asn1-generator-pass.h | 1757 ++++++ include/iprt/asn1-generator-sanity.h | 38 + include/iprt/asn1.h | 2368 +++++++ include/iprt/assert.h | 2893 +++++++++ include/iprt/assertcompile.h | 263 + include/iprt/avl.h | 1195 ++++ include/iprt/base64.h | 353 ++ include/iprt/bignum.h | 197 + include/iprt/bldprog-strtab-template.cpp.h | 1335 ++++ include/iprt/bldprog-strtab.h | 259 + include/iprt/buildconfig.h | 138 + include/iprt/cdefs.h | 4901 +++++++++++++++ include/iprt/cdrom.h | 195 + include/iprt/cidr.h | 76 + include/iprt/circbuf.h | 165 + include/iprt/condvar.h | 297 + include/iprt/coredumper.h | 105 + include/iprt/cpp/Makefile.kup | 0 include/iprt/cpp/autores.h | 216 + include/iprt/cpp/exception.h | 118 + include/iprt/cpp/hardavlrange.h | 1284 ++++ include/iprt/cpp/hardavlslaballocator.h | 218 + include/iprt/cpp/list.h | 1143 ++++ include/iprt/cpp/lock.h | 179 + include/iprt/cpp/meta.h | 125 + include/iprt/cpp/ministring.h | 1638 +++++ include/iprt/cpp/mtlist.h | 185 + include/iprt/cpp/path.h | 249 + include/iprt/cpp/restanyobject.h | 139 + include/iprt/cpp/restarray.h | 463 ++ include/iprt/cpp/restbase.h | 1106 ++++ include/iprt/cpp/restclient.h | 826 +++ include/iprt/cpp/restoutput.h | 280 + include/iprt/cpp/reststringmap.h | 499 ++ include/iprt/cpp/utils.h | 149 + include/iprt/cpp/xml.h | 1247 ++++ include/iprt/cpuset.h | 353 ++ include/iprt/crc.h | 250 + include/iprt/critsect.h | 768 +++ include/iprt/crypto/Makefile.kup | 0 include/iprt/crypto/applecodesign.h | 290 + include/iprt/crypto/cipher.h | 156 + include/iprt/crypto/digest.h | 331 + include/iprt/crypto/key.h | 126 + include/iprt/crypto/misc.h | 76 + include/iprt/crypto/pem.h | 304 + include/iprt/crypto/pkcs7.h | 709 +++ include/iprt/crypto/pkix.h | 582 ++ include/iprt/crypto/rc4.h | 73 + include/iprt/crypto/rsa.h | 166 + include/iprt/crypto/spc.h | 533 ++ include/iprt/crypto/ssl.h | 143 + include/iprt/crypto/store.h | 410 ++ include/iprt/crypto/taf.h | 202 + include/iprt/crypto/tsp.h | 148 + include/iprt/crypto/x509.h | 1180 ++++ include/iprt/ctype.h | 251 + include/iprt/dbg.h | 2034 +++++++ include/iprt/dir.h | 894 +++ include/iprt/dvm.h | 639 ++ include/iprt/efi.h | 299 + include/iprt/env.h | 473 ++ include/iprt/err.h | 2823 +++++++++ include/iprt/err.mac | 1201 ++++ include/iprt/err.sed | 55 + include/iprt/errcore.h | 947 +++ include/iprt/errno.h | 441 ++ include/iprt/expreval.h | 159 + include/iprt/file.h | 1826 ++++++ include/iprt/formats/Makefile.kup | 0 include/iprt/formats/apfs.h | 244 + include/iprt/formats/asn1.h | 107 + include/iprt/formats/bmp.h | 192 + include/iprt/formats/codeview.h | 870 +++ include/iprt/formats/cpio.h | 210 + include/iprt/formats/dwarf.h | 542 ++ include/iprt/formats/dwarf.mac | 471 ++ include/iprt/formats/efi-common.h | 102 + include/iprt/formats/efi-fat.h | 92 + include/iprt/formats/efi-fv.h | 131 + include/iprt/formats/efi-signature.h | 138 + include/iprt/formats/efi-varstore.h | 160 + include/iprt/formats/elf-amd64.h | 131 + include/iprt/formats/elf-common.h | 348 ++ include/iprt/formats/elf-i386.h | 134 + include/iprt/formats/elf.h | 98 + include/iprt/formats/elf32.h | 200 + include/iprt/formats/elf64.h | 199 + include/iprt/formats/ext.h | 998 +++ include/iprt/formats/fat.h | 759 +++ include/iprt/formats/hfs.h | 691 +++ include/iprt/formats/iso9660.h | 1516 +++++ include/iprt/formats/lx.h | 510 ++ include/iprt/formats/mach-o.h | 860 +++ include/iprt/formats/mz.h | 77 + include/iprt/formats/mz.mac | 66 + include/iprt/formats/ntfs.h | 782 +++ include/iprt/formats/omf.h | 260 + include/iprt/formats/pe.mac | 732 +++ include/iprt/formats/pecoff.h | 2610 ++++++++ include/iprt/formats/riff.h | 247 + include/iprt/formats/tpm.h | 313 + include/iprt/formats/tracelog.h | 239 + include/iprt/formats/udf.h | 2232 +++++++ include/iprt/formats/wim.h | 160 + include/iprt/formats/xar.h | 90 + include/iprt/formats/xfs.h | 721 +++ include/iprt/fs.h | 668 ++ include/iprt/fsisomaker.h | 826 +++ include/iprt/fsvfs.h | 204 + include/iprt/ftp.h | 390 ++ include/iprt/fuzz.h | 971 +++ include/iprt/getopt.h | 564 ++ include/iprt/handle.h | 81 + include/iprt/handletable.h | 259 + include/iprt/heap.h | 369 ++ include/iprt/http-common.h | 286 + include/iprt/http-server.h | 244 + include/iprt/http.h | 746 +++ include/iprt/inifile.h | 150 + include/iprt/initterm.h | 291 + include/iprt/ioqueue.h | 405 ++ include/iprt/json.h | 384 ++ include/iprt/krnlmod.h | 202 + include/iprt/latin1.h | 404 ++ include/iprt/ldr.h | 1340 ++++ include/iprt/ldrlazy.h | 122 + include/iprt/linux/Makefile.kup | 0 include/iprt/linux/symvers.h | 89 + include/iprt/linux/sysfs.h | 487 ++ include/iprt/linux/version.h | 205 + include/iprt/list-off32.h | 514 ++ include/iprt/list.h | 560 ++ include/iprt/locale.h | 113 + include/iprt/localipc.h | 354 ++ include/iprt/lockvalidator.h | 1143 ++++ include/iprt/log.h | 2869 +++++++++ include/iprt/mangling.h | 4320 +++++++++++++ include/iprt/manifest.h | 560 ++ include/iprt/md2.h | 139 + include/iprt/md4.h | 142 + include/iprt/md5.h | 148 + include/iprt/mem.h | 1239 ++++ include/iprt/memcache.h | 170 + include/iprt/memobj.h | 795 +++ include/iprt/mempool.h | 178 + include/iprt/memsafer.h | 270 + include/iprt/memtracker.h | 257 + include/iprt/message.h | 394 ++ include/iprt/mp.h | 521 ++ include/iprt/net.h | 1064 ++++ include/iprt/nocrt/Makefile.kup | 0 include/iprt/nocrt/algorithm | 164 + include/iprt/nocrt/amd64/Makefile.kup | 0 include/iprt/nocrt/amd64/math.h | 115 + include/iprt/nocrt/assert.h | 57 + include/iprt/nocrt/cassert | 49 + include/iprt/nocrt/compiler/compiler.h | 52 + include/iprt/nocrt/compiler/gcc.h | 134 + include/iprt/nocrt/compiler/msc.h | 62 + include/iprt/nocrt/compiler/watcom.h | 108 + include/iprt/nocrt/cstddef | 52 + include/iprt/nocrt/cstdlib | 47 + include/iprt/nocrt/ctype.h | 61 + include/iprt/nocrt/direct.h | 43 + include/iprt/nocrt/errno.h | 56 + include/iprt/nocrt/exception | 90 + include/iprt/nocrt/fcntl.h | 90 + include/iprt/nocrt/fenv.h | 49 + include/iprt/nocrt/float.h | 131 + include/iprt/nocrt/fstream | 206 + include/iprt/nocrt/inttypes.h | 75 + include/iprt/nocrt/io.h | 48 + include/iprt/nocrt/iomanip | 166 + include/iprt/nocrt/ios | 525 ++ include/iprt/nocrt/iosfwd | 81 + include/iprt/nocrt/iostream | 53 + include/iprt/nocrt/limits | 494 ++ include/iprt/nocrt/limits.h | 109 + include/iprt/nocrt/malloc.h | 49 + include/iprt/nocrt/math.h | 859 +++ include/iprt/nocrt/memory | 108 + include/iprt/nocrt/new | 118 + include/iprt/nocrt/ostream | 280 + include/iprt/nocrt/process.h | 43 + include/iprt/nocrt/setjmp.h | 68 + include/iprt/nocrt/signal.h | 43 + include/iprt/nocrt/stdarg.h | 45 + include/iprt/nocrt/stdbool.h | 58 + include/iprt/nocrt/stddef.h | 48 + include/iprt/nocrt/stdint.h | 46 + include/iprt/nocrt/stdio.h | 226 + include/iprt/nocrt/stdlib.h | 227 + include/iprt/nocrt/string | 322 + include/iprt/nocrt/string.h | 254 + include/iprt/nocrt/sys/stat.h | 138 + include/iprt/nocrt/sys/types.h | 66 + include/iprt/nocrt/time.h | 107 + include/iprt/nocrt/type_traits | 88 + include/iprt/nocrt/unistd.h | 125 + include/iprt/nocrt/vector | 398 ++ include/iprt/nocrt/x86/Makefile.kup | 0 include/iprt/nocrt/x86/fenv-x86-amd64.h | 219 + include/iprt/nocrt/x86/math.h | 114 + include/iprt/nt/Makefile.kup | 0 include/iprt/nt/dispmprt.h | 61 + include/iprt/nt/hyperv.h | 1768 ++++++ include/iprt/nt/miniport.h | 61 + include/iprt/nt/ndis.h | 61 + include/iprt/nt/nt-and-windows.h | 68 + include/iprt/nt/nt-structures.h | 146 + include/iprt/nt/nt.h | 3824 ++++++++++++ include/iprt/nt/ntddk.h | 83 + include/iprt/nt/rx.h | 65 + include/iprt/nt/tdikrnl.h | 50 + include/iprt/nt/vid.h | 313 + include/iprt/nt/video.h | 59 + include/iprt/nt/wdm.h | 81 + include/iprt/once.h | 231 + include/iprt/param.h | 137 + include/iprt/path.h | 1674 +++++ include/iprt/pipe.h | 293 + include/iprt/poll.h | 265 + include/iprt/power.h | 125 + include/iprt/process.h | 479 ++ include/iprt/queueatomic.h | 137 + include/iprt/rand.h | 330 + include/iprt/req.h | 643 ++ include/iprt/runtime-loader.h | 189 + include/iprt/runtime.h | 99 + include/iprt/s3.h | 283 + include/iprt/sanitized/intrin.h | 62 + include/iprt/sanitized/iterator | 60 + include/iprt/sanitized/sstream | 62 + include/iprt/sanitized/string | 61 + include/iprt/semaphore.h | 1450 +++++ include/iprt/serialport.h | 377 ++ include/iprt/setjmp-without-sigmask.h | 64 + include/iprt/sg.h | 460 ++ include/iprt/sha.h | 593 ++ include/iprt/shmem.h | 180 + include/iprt/socket.h | 430 ++ include/iprt/solaris/kmoddeps.mac | 193 + include/iprt/sort.h | 141 + include/iprt/spinlock.h | 105 + include/iprt/stdarg.h | 79 + include/iprt/stdint.h | 349 ++ include/iprt/strcache.h | 201 + include/iprt/stream.h | 542 ++ include/iprt/string.h | 3725 +++++++++++ include/iprt/symlink.h | 189 + include/iprt/system.h | 379 ++ include/iprt/table.h | 726 +++ include/iprt/tar.h | 184 + include/iprt/tcp.h | 514 ++ include/iprt/test.h | 1485 +++++ include/iprt/thread.h | 1023 ++++ include/iprt/time.h | 1352 ++++ include/iprt/timer.h | 400 ++ include/iprt/tpm.h | 156 + include/iprt/trace.h | 228 + include/iprt/tracelog.h | 706 +++ include/iprt/types.h | 3890 ++++++++++++ include/iprt/udp.h | 191 + include/iprt/uint128.h | 1479 +++++ include/iprt/uint256.h | 1241 ++++ include/iprt/uint32.h | 1068 ++++ include/iprt/uint64.h | 1343 ++++ include/iprt/uni.h | 491 ++ include/iprt/uri.h | 380 ++ include/iprt/utf16.h | 1527 +++++ include/iprt/uuid.h | 198 + include/iprt/vector.h | 389 ++ include/iprt/vfs.h | 2021 ++++++ include/iprt/vfslowlevel.h | 1588 +++++ include/iprt/win/Makefile.kup | 0 include/iprt/win/audioclient.h | 59 + include/iprt/win/commctrl.h | 61 + include/iprt/win/context-amd64.mac | 118 + include/iprt/win/context-x86.mac | 101 + include/iprt/win/credentialprovider.h | 58 + include/iprt/win/d3d8.h | 60 + include/iprt/win/d3d9.h | 68 + include/iprt/win/d3dkmthk.h | 61 + include/iprt/win/dbghelp.h | 61 + include/iprt/win/dshow.h | 56 + include/iprt/win/endpointvolume.h | 58 + include/iprt/win/imagehlp.h | 61 + include/iprt/win/intsafe.h | 77 + include/iprt/win/iphlpapi.h | 50 + include/iprt/win/ks.h | 54 + include/iprt/win/lazy-dbghelp.h | 151 + include/iprt/win/mmreg.h | 53 + include/iprt/win/netioapi.h | 46 + include/iprt/win/ntdddisk.h | 50 + include/iprt/win/ntddndis.h | 50 + include/iprt/win/ntverp.h | 50 + include/iprt/win/objbase.h | 69 + include/iprt/win/objidl.h | 63 + include/iprt/win/rpcproxy.h | 75 + include/iprt/win/setupapi.h | 59 + include/iprt/win/shlobj.h | 67 + include/iprt/win/shlwapi.h | 53 + include/iprt/win/windef.h | 65 + include/iprt/win/windows.h | 110 + include/iprt/win/winsock.h | 64 + include/iprt/win/winsock2.h | 74 + include/iprt/win/ws2tcpip.h | 67 + include/iprt/x86-helpers.h | 261 + include/iprt/x86.h | 4860 +++++++++++++++ include/iprt/x86.mac | 1409 +++++ include/iprt/x86extra.mac | 225 + include/iprt/zero.h | 67 + include/iprt/zip.h | 533 ++ 330 files changed, 166956 insertions(+) create mode 100644 include/iprt/Makefile.kup create mode 100644 include/iprt/alloc.h create mode 100644 include/iprt/alloca.h create mode 100644 include/iprt/asm-amd64-x86-watcom-16.h create mode 100644 include/iprt/asm-amd64-x86-watcom-32.h create mode 100644 include/iprt/asm-amd64-x86.h create mode 100644 include/iprt/asm-arm.h create mode 100644 include/iprt/asm-math.h create mode 100644 include/iprt/asm-watcom-x86-16.h create mode 100644 include/iprt/asm-watcom-x86-32.h create mode 100644 include/iprt/asm.h create mode 100644 include/iprt/asmdefs.mac create mode 100644 include/iprt/asn1-generator-asn1-decoder.h create mode 100644 include/iprt/asn1-generator-core.h create mode 100644 include/iprt/asn1-generator-init.h create mode 100644 include/iprt/asn1-generator-internal-header.h create mode 100644 include/iprt/asn1-generator-pass.h create mode 100644 include/iprt/asn1-generator-sanity.h create mode 100644 include/iprt/asn1.h create mode 100644 include/iprt/assert.h create mode 100644 include/iprt/assertcompile.h create mode 100644 include/iprt/avl.h create mode 100644 include/iprt/base64.h create mode 100644 include/iprt/bignum.h create mode 100644 include/iprt/bldprog-strtab-template.cpp.h create mode 100644 include/iprt/bldprog-strtab.h create mode 100644 include/iprt/buildconfig.h create mode 100644 include/iprt/cdefs.h create mode 100644 include/iprt/cdrom.h create mode 100644 include/iprt/cidr.h create mode 100644 include/iprt/circbuf.h create mode 100644 include/iprt/condvar.h create mode 100644 include/iprt/coredumper.h create mode 100644 include/iprt/cpp/Makefile.kup create mode 100644 include/iprt/cpp/autores.h create mode 100644 include/iprt/cpp/exception.h create mode 100644 include/iprt/cpp/hardavlrange.h create mode 100644 include/iprt/cpp/hardavlslaballocator.h create mode 100644 include/iprt/cpp/list.h create mode 100644 include/iprt/cpp/lock.h create mode 100644 include/iprt/cpp/meta.h create mode 100644 include/iprt/cpp/ministring.h create mode 100644 include/iprt/cpp/mtlist.h create mode 100644 include/iprt/cpp/path.h create mode 100644 include/iprt/cpp/restanyobject.h create mode 100644 include/iprt/cpp/restarray.h create mode 100644 include/iprt/cpp/restbase.h create mode 100644 include/iprt/cpp/restclient.h create mode 100644 include/iprt/cpp/restoutput.h create mode 100644 include/iprt/cpp/reststringmap.h create mode 100644 include/iprt/cpp/utils.h create mode 100644 include/iprt/cpp/xml.h create mode 100644 include/iprt/cpuset.h create mode 100644 include/iprt/crc.h create mode 100644 include/iprt/critsect.h create mode 100644 include/iprt/crypto/Makefile.kup create mode 100644 include/iprt/crypto/applecodesign.h create mode 100644 include/iprt/crypto/cipher.h create mode 100644 include/iprt/crypto/digest.h create mode 100644 include/iprt/crypto/key.h create mode 100644 include/iprt/crypto/misc.h create mode 100644 include/iprt/crypto/pem.h create mode 100644 include/iprt/crypto/pkcs7.h create mode 100644 include/iprt/crypto/pkix.h create mode 100644 include/iprt/crypto/rc4.h create mode 100644 include/iprt/crypto/rsa.h create mode 100644 include/iprt/crypto/spc.h create mode 100644 include/iprt/crypto/ssl.h create mode 100644 include/iprt/crypto/store.h create mode 100644 include/iprt/crypto/taf.h create mode 100644 include/iprt/crypto/tsp.h create mode 100644 include/iprt/crypto/x509.h create mode 100644 include/iprt/ctype.h create mode 100644 include/iprt/dbg.h create mode 100644 include/iprt/dir.h create mode 100644 include/iprt/dvm.h create mode 100644 include/iprt/efi.h create mode 100644 include/iprt/env.h create mode 100644 include/iprt/err.h create mode 100644 include/iprt/err.mac create mode 100644 include/iprt/err.sed create mode 100644 include/iprt/errcore.h create mode 100644 include/iprt/errno.h create mode 100644 include/iprt/expreval.h create mode 100644 include/iprt/file.h create mode 100644 include/iprt/formats/Makefile.kup create mode 100644 include/iprt/formats/apfs.h create mode 100644 include/iprt/formats/asn1.h create mode 100644 include/iprt/formats/bmp.h create mode 100644 include/iprt/formats/codeview.h create mode 100644 include/iprt/formats/cpio.h create mode 100644 include/iprt/formats/dwarf.h create mode 100644 include/iprt/formats/dwarf.mac create mode 100644 include/iprt/formats/efi-common.h create mode 100644 include/iprt/formats/efi-fat.h create mode 100644 include/iprt/formats/efi-fv.h create mode 100644 include/iprt/formats/efi-signature.h create mode 100644 include/iprt/formats/efi-varstore.h create mode 100644 include/iprt/formats/elf-amd64.h create mode 100644 include/iprt/formats/elf-common.h create mode 100644 include/iprt/formats/elf-i386.h create mode 100644 include/iprt/formats/elf.h create mode 100644 include/iprt/formats/elf32.h create mode 100644 include/iprt/formats/elf64.h create mode 100644 include/iprt/formats/ext.h create mode 100644 include/iprt/formats/fat.h create mode 100644 include/iprt/formats/hfs.h create mode 100644 include/iprt/formats/iso9660.h create mode 100644 include/iprt/formats/lx.h create mode 100644 include/iprt/formats/mach-o.h create mode 100644 include/iprt/formats/mz.h create mode 100644 include/iprt/formats/mz.mac create mode 100644 include/iprt/formats/ntfs.h create mode 100644 include/iprt/formats/omf.h create mode 100644 include/iprt/formats/pe.mac create mode 100644 include/iprt/formats/pecoff.h create mode 100644 include/iprt/formats/riff.h create mode 100644 include/iprt/formats/tpm.h create mode 100644 include/iprt/formats/tracelog.h create mode 100644 include/iprt/formats/udf.h create mode 100644 include/iprt/formats/wim.h create mode 100644 include/iprt/formats/xar.h create mode 100644 include/iprt/formats/xfs.h create mode 100644 include/iprt/fs.h create mode 100644 include/iprt/fsisomaker.h create mode 100644 include/iprt/fsvfs.h create mode 100644 include/iprt/ftp.h create mode 100644 include/iprt/fuzz.h create mode 100644 include/iprt/getopt.h create mode 100644 include/iprt/handle.h create mode 100644 include/iprt/handletable.h create mode 100644 include/iprt/heap.h create mode 100644 include/iprt/http-common.h create mode 100644 include/iprt/http-server.h create mode 100644 include/iprt/http.h create mode 100644 include/iprt/inifile.h create mode 100644 include/iprt/initterm.h create mode 100644 include/iprt/ioqueue.h create mode 100644 include/iprt/json.h create mode 100644 include/iprt/krnlmod.h create mode 100644 include/iprt/latin1.h create mode 100644 include/iprt/ldr.h create mode 100644 include/iprt/ldrlazy.h create mode 100644 include/iprt/linux/Makefile.kup create mode 100644 include/iprt/linux/symvers.h create mode 100644 include/iprt/linux/sysfs.h create mode 100644 include/iprt/linux/version.h create mode 100644 include/iprt/list-off32.h create mode 100644 include/iprt/list.h create mode 100644 include/iprt/locale.h create mode 100644 include/iprt/localipc.h create mode 100644 include/iprt/lockvalidator.h create mode 100644 include/iprt/log.h create mode 100644 include/iprt/mangling.h create mode 100644 include/iprt/manifest.h create mode 100644 include/iprt/md2.h create mode 100644 include/iprt/md4.h create mode 100644 include/iprt/md5.h create mode 100644 include/iprt/mem.h create mode 100644 include/iprt/memcache.h create mode 100644 include/iprt/memobj.h create mode 100644 include/iprt/mempool.h create mode 100644 include/iprt/memsafer.h create mode 100644 include/iprt/memtracker.h create mode 100644 include/iprt/message.h create mode 100644 include/iprt/mp.h create mode 100644 include/iprt/net.h create mode 100644 include/iprt/nocrt/Makefile.kup create mode 100644 include/iprt/nocrt/algorithm create mode 100644 include/iprt/nocrt/amd64/Makefile.kup create mode 100644 include/iprt/nocrt/amd64/math.h create mode 100644 include/iprt/nocrt/assert.h create mode 100644 include/iprt/nocrt/cassert create mode 100644 include/iprt/nocrt/compiler/compiler.h create mode 100644 include/iprt/nocrt/compiler/gcc.h create mode 100644 include/iprt/nocrt/compiler/msc.h create mode 100644 include/iprt/nocrt/compiler/watcom.h create mode 100644 include/iprt/nocrt/cstddef create mode 100644 include/iprt/nocrt/cstdlib create mode 100644 include/iprt/nocrt/ctype.h create mode 100644 include/iprt/nocrt/direct.h create mode 100644 include/iprt/nocrt/errno.h create mode 100644 include/iprt/nocrt/exception create mode 100644 include/iprt/nocrt/fcntl.h create mode 100644 include/iprt/nocrt/fenv.h create mode 100644 include/iprt/nocrt/float.h create mode 100644 include/iprt/nocrt/fstream create mode 100644 include/iprt/nocrt/inttypes.h create mode 100644 include/iprt/nocrt/io.h create mode 100644 include/iprt/nocrt/iomanip create mode 100644 include/iprt/nocrt/ios create mode 100644 include/iprt/nocrt/iosfwd create mode 100644 include/iprt/nocrt/iostream create mode 100644 include/iprt/nocrt/limits create mode 100644 include/iprt/nocrt/limits.h create mode 100644 include/iprt/nocrt/malloc.h create mode 100644 include/iprt/nocrt/math.h create mode 100644 include/iprt/nocrt/memory create mode 100644 include/iprt/nocrt/new create mode 100644 include/iprt/nocrt/ostream create mode 100644 include/iprt/nocrt/process.h create mode 100644 include/iprt/nocrt/setjmp.h create mode 100644 include/iprt/nocrt/signal.h create mode 100644 include/iprt/nocrt/stdarg.h create mode 100644 include/iprt/nocrt/stdbool.h create mode 100644 include/iprt/nocrt/stddef.h create mode 100644 include/iprt/nocrt/stdint.h create mode 100644 include/iprt/nocrt/stdio.h create mode 100644 include/iprt/nocrt/stdlib.h create mode 100644 include/iprt/nocrt/string create mode 100644 include/iprt/nocrt/string.h create mode 100644 include/iprt/nocrt/sys/stat.h create mode 100644 include/iprt/nocrt/sys/types.h create mode 100644 include/iprt/nocrt/time.h create mode 100644 include/iprt/nocrt/type_traits create mode 100644 include/iprt/nocrt/unistd.h create mode 100644 include/iprt/nocrt/vector create mode 100644 include/iprt/nocrt/x86/Makefile.kup create mode 100644 include/iprt/nocrt/x86/fenv-x86-amd64.h create mode 100644 include/iprt/nocrt/x86/math.h create mode 100644 include/iprt/nt/Makefile.kup create mode 100644 include/iprt/nt/dispmprt.h create mode 100644 include/iprt/nt/hyperv.h create mode 100644 include/iprt/nt/miniport.h create mode 100644 include/iprt/nt/ndis.h create mode 100644 include/iprt/nt/nt-and-windows.h create mode 100644 include/iprt/nt/nt-structures.h create mode 100644 include/iprt/nt/nt.h create mode 100644 include/iprt/nt/ntddk.h create mode 100644 include/iprt/nt/rx.h create mode 100644 include/iprt/nt/tdikrnl.h create mode 100644 include/iprt/nt/vid.h create mode 100644 include/iprt/nt/video.h create mode 100644 include/iprt/nt/wdm.h create mode 100644 include/iprt/once.h create mode 100644 include/iprt/param.h create mode 100644 include/iprt/path.h create mode 100644 include/iprt/pipe.h create mode 100644 include/iprt/poll.h create mode 100644 include/iprt/power.h create mode 100644 include/iprt/process.h create mode 100644 include/iprt/queueatomic.h create mode 100644 include/iprt/rand.h create mode 100644 include/iprt/req.h create mode 100644 include/iprt/runtime-loader.h create mode 100644 include/iprt/runtime.h create mode 100644 include/iprt/s3.h create mode 100644 include/iprt/sanitized/intrin.h create mode 100644 include/iprt/sanitized/iterator create mode 100644 include/iprt/sanitized/sstream create mode 100644 include/iprt/sanitized/string create mode 100644 include/iprt/semaphore.h create mode 100644 include/iprt/serialport.h create mode 100644 include/iprt/setjmp-without-sigmask.h create mode 100644 include/iprt/sg.h create mode 100644 include/iprt/sha.h create mode 100644 include/iprt/shmem.h create mode 100644 include/iprt/socket.h create mode 100644 include/iprt/solaris/kmoddeps.mac create mode 100644 include/iprt/sort.h create mode 100644 include/iprt/spinlock.h create mode 100644 include/iprt/stdarg.h create mode 100644 include/iprt/stdint.h create mode 100644 include/iprt/strcache.h create mode 100644 include/iprt/stream.h create mode 100644 include/iprt/string.h create mode 100644 include/iprt/symlink.h create mode 100644 include/iprt/system.h create mode 100644 include/iprt/table.h create mode 100644 include/iprt/tar.h create mode 100644 include/iprt/tcp.h create mode 100644 include/iprt/test.h create mode 100644 include/iprt/thread.h create mode 100644 include/iprt/time.h create mode 100644 include/iprt/timer.h create mode 100644 include/iprt/tpm.h create mode 100644 include/iprt/trace.h create mode 100644 include/iprt/tracelog.h create mode 100644 include/iprt/types.h create mode 100644 include/iprt/udp.h create mode 100644 include/iprt/uint128.h create mode 100644 include/iprt/uint256.h create mode 100644 include/iprt/uint32.h create mode 100644 include/iprt/uint64.h create mode 100644 include/iprt/uni.h create mode 100644 include/iprt/uri.h create mode 100644 include/iprt/utf16.h create mode 100644 include/iprt/uuid.h create mode 100644 include/iprt/vector.h create mode 100644 include/iprt/vfs.h create mode 100644 include/iprt/vfslowlevel.h create mode 100644 include/iprt/win/Makefile.kup create mode 100644 include/iprt/win/audioclient.h create mode 100644 include/iprt/win/commctrl.h create mode 100644 include/iprt/win/context-amd64.mac create mode 100644 include/iprt/win/context-x86.mac create mode 100644 include/iprt/win/credentialprovider.h create mode 100644 include/iprt/win/d3d8.h create mode 100644 include/iprt/win/d3d9.h create mode 100644 include/iprt/win/d3dkmthk.h create mode 100644 include/iprt/win/dbghelp.h create mode 100644 include/iprt/win/dshow.h create mode 100644 include/iprt/win/endpointvolume.h create mode 100644 include/iprt/win/imagehlp.h create mode 100644 include/iprt/win/intsafe.h create mode 100644 include/iprt/win/iphlpapi.h create mode 100644 include/iprt/win/ks.h create mode 100644 include/iprt/win/lazy-dbghelp.h create mode 100644 include/iprt/win/mmreg.h create mode 100644 include/iprt/win/netioapi.h create mode 100644 include/iprt/win/ntdddisk.h create mode 100644 include/iprt/win/ntddndis.h create mode 100644 include/iprt/win/ntverp.h create mode 100644 include/iprt/win/objbase.h create mode 100644 include/iprt/win/objidl.h create mode 100644 include/iprt/win/rpcproxy.h create mode 100644 include/iprt/win/setupapi.h create mode 100644 include/iprt/win/shlobj.h create mode 100644 include/iprt/win/shlwapi.h create mode 100644 include/iprt/win/windef.h create mode 100644 include/iprt/win/windows.h create mode 100644 include/iprt/win/winsock.h create mode 100644 include/iprt/win/winsock2.h create mode 100644 include/iprt/win/ws2tcpip.h create mode 100644 include/iprt/x86-helpers.h create mode 100644 include/iprt/x86.h create mode 100644 include/iprt/x86.mac create mode 100644 include/iprt/x86extra.mac create mode 100644 include/iprt/zero.h create mode 100644 include/iprt/zip.h (limited to 'include/iprt') diff --git a/include/iprt/Makefile.kup b/include/iprt/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/alloc.h b/include/iprt/alloc.h new file mode 100644 index 00000000..a0d6561d --- /dev/null +++ b/include/iprt/alloc.h @@ -0,0 +1,46 @@ +/** @file + * IPRT - Memory Allocation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_alloc_h +#define IPRT_INCLUDED_alloc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Forwarding to the canonical header. */ +#include + +#endif /* !IPRT_INCLUDED_alloc_h */ + diff --git a/include/iprt/alloca.h b/include/iprt/alloca.h new file mode 100644 index 00000000..1866d975 --- /dev/null +++ b/include/iprt/alloca.h @@ -0,0 +1,110 @@ +/** @file + * IPRT - alloca(). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_alloca_h +#define IPRT_INCLUDED_alloca_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if defined(IN_RC) || defined(IN_RING0_AGNOSTIC) +# error "No alloca() in raw-mode and agnostic ring-0 context as it may have external dependencies like libgcc." +#endif + +/* + * If there are more difficult platforms out there, we'll do OS + * specific #ifdefs. But for now we'll just include the headers + * which normally contains the alloca() prototype. + * When we're in kernel territory it starts getting a bit more + * interesting of course... + */ +#if defined(IN_RING0) \ + && ( defined(RT_OS_DARWIN) \ + || defined(RT_OS_FREEBSD) \ + || defined(RT_OS_LINUX) \ + || defined(RT_OS_NETBSD) \ + || defined(RT_OS_SOLARIS)) +/* ASSUMES GNU C */ +# define alloca(cb) __builtin_alloca(cb) + +#elif defined(IPRT_NO_CRT) && defined(RT_OS_WINDOWS) +# include + +RT_C_DECLS_BEGIN +# ifdef RT_ARCH_X86 +void * __cdecl _alloca(size_t); +# else +void *_alloca(size_t); +# endif +# define alloca _alloca +RT_C_DECLS_END + +#else +# include +# if !defined(RT_OS_DARWIN) && !defined(RT_OS_FREEBSD) && !defined(RT_OS_NETBSD) +# include +# endif +# if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) +# include +# endif + +# if defined(RT_OS_SOLARIS) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) \ + && defined(_SYS_REGSET_H) && !defined(IPRT_NO_SOLARIS_UCONTEXT_CLEANUPS) +/* Solaris' sys/regset.h pollutes the namespace with register constants that + frequently conflicts with structure members and variable/parameter names. */ +# undef CS +# undef DS +# undef EAX +# undef EBP +# undef EBX +# undef ECX +# undef EDI +# undef EDX +# undef EFL +# undef EIP +# undef ERR +# undef ES +# undef ESI +# undef ESP +# undef FS +# undef GS +# undef SS +# undef TRAPNO +# undef UESP +# endif +#endif + +#endif /* !IPRT_INCLUDED_alloca_h */ + diff --git a/include/iprt/asm-amd64-x86-watcom-16.h b/include/iprt/asm-amd64-x86-watcom-16.h new file mode 100644 index 00000000..a3fd3ebd --- /dev/null +++ b/include/iprt/asm-amd64-x86-watcom-16.h @@ -0,0 +1,831 @@ +/** @file + * IPRT - AMD64 and x86 Specific Assembly Functions, 16-bit Watcom C pragma aux. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_watcom_16_h +#define IPRT_INCLUDED_asm_amd64_x86_watcom_16_h +/* no pragma once */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_h +# error "Don't include this header directly." +#endif + +/* + * Turns out we cannot use 'ds' for segment stuff here because the compiler + * seems to insists on loading the DGROUP segment into 'ds' before calling + * stuff when using -ecc. Using 'es' instead as this seems to work fine. + * + * Note! The #undef that preceds the #pragma aux statements is for undoing + * the mangling, because the symbol in #pragma aux [symbol] statements + * doesn't get subjected to preprocessing. This is also why we include + * the watcom header at both the top and the bottom of asm-amd64-x86.h file. + */ + +#undef ASMGetIDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetIDTR = \ + ".286p" \ + "sidt fword ptr es:[bx]" \ + parm [es bx] \ + modify exact []; +#endif + +#undef ASMGetIdtrLimit +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetIdtrLimit = \ + ".286p" \ + "sub sp, 8" \ + "mov bx, sp" \ + "sidt fword ptr ss:[bx]" \ + "mov bx, ss:[bx]" \ + "add sp, 8" \ + parm [] \ + value [bx] \ + modify exact [bx]; +#endif + +#undef ASMSetIDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetIDTR = \ + ".286p" \ + "lidt fword ptr es:[bx]" \ + parm [es bx] nomemory \ + modify nomemory; +#endif + +#undef ASMGetGDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetGDTR = \ + ".286p" \ + "sgdt fword ptr es:[bx]" \ + parm [es bx] \ + modify exact []; +#endif + +#undef ASMSetGDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetGDTR = \ + ".286p" \ + "lgdt fword ptr es:[bx]" \ + parm [es bx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMGetCS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCS = \ + "mov ax, cs" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetDS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDS = \ + "mov ax, ds" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetES +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetES = \ + "mov ax, es" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetFS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetFS = \ + ".386" \ + "mov ax, fs" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetGS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetGS = \ + ".386" \ + "mov ax, gs" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetSS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetSS = \ + "mov ax, ss" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetTR = \ + ".286" \ + "str ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetLDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetLDTR = \ + ".286" \ + "sldt ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +/** @todo ASMGetSegAttr */ + +#undef ASMGetFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetFlags = \ + "pushf" \ + "pop ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMSetFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetFlags = \ + "push ax" \ + "popf" \ + parm [ax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMChangeFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMChangeFlags = \ + "pushf" \ + "pop ax" \ + "and dx, ax" \ + "or dx, cx" \ + "push dx" \ + "popf" \ + parm [dx] [cx] nomemory \ + value [ax] \ + modify exact [dx] nomemory; +#endif + +#undef ASMAddFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMAddFlags = \ + "pushf" \ + "pop ax" \ + "or dx, ax" \ + "push dx" \ + "popf" \ + parm [dx] nomemory \ + value [ax] \ + modify exact [dx] nomemory; +#endif + +#undef ASMClearFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMClearFlags = \ + "pushf" \ + "pop ax" \ + "and dx, ax" \ + "push dx" \ + "popf" \ + parm [dx] nomemory \ + value [ax] \ + modify exact [dx] nomemory; +#endif + +/* Note! Must use the 64-bit integer return value convension. + The order of registers in the value [set] does not seem to mean anything. */ +#undef ASMReadTSC +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMReadTSC = \ + ".586" \ + "rdtsc" \ + "mov ebx, edx" \ + "mov ecx, eax" \ + "shr ecx, 16" \ + "xchg eax, edx" \ + "shr eax, 16" \ + parm [] nomemory \ + value [dx cx bx ax] \ + modify exact [ax bx cx dx] nomemory; +#endif + +/** @todo ASMReadTscWithAux if needed (rdtscp not recognized by compiler) */ + + +/* ASMCpuId: Implemented externally, too many parameters. */ +/* ASMCpuId_Idx_ECX: Implemented externally, too many parameters. */ +/* ASMCpuIdExSlow: Always implemented externally. */ +/* ASMCpuId_ECX_EDX: Implemented externally, too many parameters. */ + +#undef ASMCpuId_EAX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMCpuId_EAX = \ + ".586" \ + "xchg ax, dx" \ + "shl eax, 16" \ + "mov ax, dx" \ + "cpuid" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [ax dx] \ + value [ax dx] \ + modify exact [ax bx cx dx]; +#endif + +#undef ASMCpuId_EBX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMCpuId_EBX = \ + ".586" \ + "xchg ax, dx" \ + "shl eax, 16" \ + "mov ax, dx" \ + "cpuid" \ + "mov ax, bx" \ + "shr ebx, 16" \ + parm [ax dx] \ + value [ax bx] \ + modify exact [ax bx cx dx]; +#endif + +#undef ASMCpuId_ECX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMCpuId_ECX = \ + ".586" \ + "xchg ax, dx" \ + "shl eax, 16" \ + "mov ax, dx" \ + "cpuid" \ + "mov ax, cx" \ + "shr ecx, 16" \ + parm [ax dx] \ + value [ax cx] \ + modify exact [ax bx cx dx]; +#endif + +#undef ASMCpuId_EDX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMCpuId_EDX = \ + ".586" \ + "xchg ax, dx" \ + "shl eax, 16" \ + "mov ax, dx" \ + "cpuid" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [ax dx] \ + value [ax dx] \ + modify exact [ax bx cx dx]; +#endif + +/* ASMHasCpuId: MSC inline in main source file. */ +/* ASMGetApicId: Implemented externally, lazy bird. */ + +/* Note! Again, when returning two registers, watcom have certain fixed ordering rules (low:high): + ax:bx, ax:cx, ax:dx, ax:si, ax:di + bx:cx, bx:dx, bx:si, bx:di + dx:cx, si:cx, di:cx + si:dx, di:dx + si:di + This ordering seems to apply to parameter values too. */ +#undef ASMGetCR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCR0 = \ + ".386" \ + "mov eax, cr0" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetCR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetCR0 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov cr0, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMGetCR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCR2 = \ + ".386" \ + "mov eax, cr2" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetCR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetCR2 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov cr2, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMGetCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCR3 = \ + ".386" \ + "mov eax, cr3" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetCR3 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov cr3, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMReloadCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMReloadCR3 = \ + ".386" \ + "mov eax, cr3" \ + "mov cr3, eax" \ + parm [] nomemory \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetCR4 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCR4 = \ + ".386" \ + "mov eax, cr4" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetCR4 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetCR4 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov cr4, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +/* ASMGetCR8: Don't bother for 16-bit. */ +/* ASMSetCR8: Don't bother for 16-bit. */ + +#undef ASMIntEnable +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMIntEnable = \ + "sti" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMIntDisable +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMIntDisable = \ + "cli" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMIntDisableFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMIntDisableFlags = \ + "pushf" \ + "cli" \ + "pop ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [] nomemory; +#endif + +#undef ASMHalt +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMHalt = \ + "hlt" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMRdMsr +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMRdMsr = \ + ".586" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "rdmsr" \ + "mov ebx, edx" \ + "mov ecx, eax" \ + "shr ecx, 16" \ + "xchg eax, edx" \ + "shr eax, 16" \ + parm [ax cx] nomemory \ + value [dx cx bx ax] \ + modify exact [ax bx cx dx] nomemory; +#endif + +/* ASMWrMsr: Implemented externally, lazy bird. */ +/* ASMRdMsrEx: Implemented externally, lazy bird. */ +/* ASMWrMsrEx: Implemented externally, lazy bird. */ + +#undef ASMRdMsr_Low +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMRdMsr_Low = \ + ".586" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "rdmsr" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [ax cx] nomemory \ + value [ax dx] \ + modify exact [ax bx cx dx] nomemory; +#endif + +#undef ASMRdMsr_High +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMRdMsr_High = \ + ".586" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "rdmsr" \ + "mov eax, edx" \ + "shr edx, 16" \ + parm [ax cx] nomemory \ + value [ax dx] \ + modify exact [ax bx cx dx] nomemory; +#endif + + +#undef ASMGetDR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR0 = \ + ".386" \ + "mov eax, dr0" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR1 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR1 = \ + ".386" \ + "mov eax, dr1" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR2 = \ + ".386" \ + "mov eax, dr2" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR3 = \ + ".386" \ + "mov eax, dr3" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR6 = \ + ".386" \ + "mov eax, dr6" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetAndClearDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetAndClearDR6 = \ + ".386" \ + "mov edx, 0ffff0ff0h" \ + "mov eax, dr6" \ + "mov dr6, edx" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR7 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR7 = \ + ".386" \ + "mov eax, dr7" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetDR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR0 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr0, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR1 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR1 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr1, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR2 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr2, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR3 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr3, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR6 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr6, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR7 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR7 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr7, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +/* Yeah, could've used outp here, but this keeps the main file simpler. */ +#undef ASMOutU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutU8 = \ + "out dx, al" \ + parm [dx] [al] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInU8 = \ + "in al, dx" \ + parm [dx] nomemory \ + value [al] \ + modify exact [] nomemory; +#endif + +#undef ASMOutU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutU16 = \ + "out dx, ax" \ + parm [dx] [ax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInU16 = \ + "in ax, dx" \ + parm [dx] nomemory \ + value [ax] \ + modify exact [] nomemory; +#endif + +#undef ASMOutU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutU32 = \ + ".386" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "mov eax, ecx" \ + "out dx, eax" \ + parm [dx] [ax cx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInU32 = \ + ".386" \ + "in eax, dx" \ + "mov ecx, eax" \ + "shr ecx, 16" \ + parm [dx] nomemory \ + value [ax cx] \ + modify exact [] nomemory; +#endif + +#undef ASMOutStrU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutStrU8 = \ + ".186" \ + "mov ax, ds" \ + "mov ds, di" \ + "rep outsb" \ + "mov ds, ax" \ + parm [dx] [si di] [cx] nomemory \ + modify exact [si cx ax] nomemory; +#endif + +#undef ASMInStrU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInStrU8 = \ + ".186" \ + "rep insb" \ + parm [dx] [di es] [cx] \ + modify exact [di cx]; +#endif + +#undef ASMOutStrU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutStrU16 = \ + ".186" \ + "mov ax, ds" \ + "mov ds, di" \ + "rep outsw" \ + "mov ds, ax" \ + parm [dx] [si di] [cx] nomemory \ + modify exact [si cx ax] nomemory; +#endif + +#undef ASMInStrU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInStrU16 = \ + ".186" \ + "rep insw" \ + parm [dx] [di es] [cx] \ + modify exact [di cx]; +#endif + +#undef ASMOutStrU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutStrU32 = \ + ".386" \ + "mov ax, ds" \ + "mov ds, di" \ + "rep outsd" \ + "mov ds, ax" \ + parm [dx] [si di] [cx] nomemory \ + modify exact [si cx ax] nomemory; +#endif + +#undef ASMInStrU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInStrU32 = \ + ".386" \ + "rep insd" \ + parm [dx] [es di] [cx] \ + modify exact [di cx]; +#endif + +#undef ASMInvalidatePage +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInvalidatePage = \ + ".486" \ + "shl edx, 16" \ + "mov dx, ax" \ + "invlpg [edx]" \ + parm [ax dx] \ + modify exact [dx]; +#endif + +#undef ASMWriteBackAndInvalidateCaches +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMWriteBackAndInvalidateCaches = \ + ".486" \ + "wbinvd" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInvalidateInternalCaches +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInvalidateInternalCaches = \ + ".486" \ + "invd" \ + parm [] \ + modify exact []; +#endif + +#endif /* !IPRT_INCLUDED_asm_amd64_x86_watcom_16_h */ + diff --git a/include/iprt/asm-amd64-x86-watcom-32.h b/include/iprt/asm-amd64-x86-watcom-32.h new file mode 100644 index 00000000..4486bb5b --- /dev/null +++ b/include/iprt/asm-amd64-x86-watcom-32.h @@ -0,0 +1,737 @@ +/** @file + * IPRT - AMD64 and x86 Specific Assembly Functions, 32-bit Watcom C pragma aux. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_watcom_32_h +#define IPRT_INCLUDED_asm_amd64_x86_watcom_32_h +/* no pragma once */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_h +# error "Don't include this header directly." +#endif + +#ifndef __FLAT__ +# error "Only works with flat pointers! (-mf)" +#endif + +/* + * Note! The #undef that preceds the #pragma aux statements is for undoing + * the mangling, because the symbol in #pragma aux [symbol] statements + * doesn't get subjected to preprocessing. This is also why we include + * the watcom header at both the top and the bottom of asm-amd64-x86.h file. + */ + +#undef ASMGetIDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetIDTR = \ + "sidt fword ptr [ecx]" \ + parm [ecx] \ + modify exact []; +#endif + +#undef ASMGetIdtrLimit +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetIdtrLimit = \ + "sub esp, 8" \ + "sidt fword ptr [esp]" \ + "mov cx, [esp]" \ + "add esp, 8" \ + parm [] \ + value [cx] \ + modify exact [ecx]; +#endif + +#undef ASMSetIDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetIDTR = \ + "lidt fword ptr [ecx]" \ + parm [ecx] nomemory \ + modify nomemory; +#endif + +#undef ASMGetGDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetGDTR = \ + "sgdt fword ptr [ecx]" \ + parm [ecx] \ + modify exact []; +#endif + +#undef ASMSetGDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetGDTR = \ + "lgdt fword ptr [ecx]" \ + parm [ecx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMGetCS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCS = \ + "mov ax, cs" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDS = \ + "mov ax, ds" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetES +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetES = \ + "mov ax, es" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetFS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetFS = \ + "mov ax, fs" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetGS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetGS = \ + "mov ax, gs" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetSS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetSS = \ + "mov ax, ss" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetTR = \ + "str ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetLDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetLDTR = \ + "sldt ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +/** @todo ASMGetSegAttr */ + +#undef ASMGetFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetFlags = \ + "pushfd" \ + "pop eax" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetFlags = \ + "push eax" \ + "popfd" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMChangeFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMChangeFlags = \ + "pushfd" \ + "pop eax" \ + "and edx, eax" \ + "or edx, ecx" \ + "push edx" \ + "popfd" \ + parm [edx] [ecx] nomemory \ + value [eax] \ + modify exact [edx] nomemory; +#endif + +#undef ASMAddFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMAddFlags = \ + "pushfd" \ + "pop eax" \ + "or edx, eax" \ + "push edx" \ + "popfd" \ + parm [edx] nomemory \ + value [eax] \ + modify exact [edx] nomemory; +#endif + +#undef ASMClearFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMClearFlags = \ + "pushfd" \ + "pop eax" \ + "and edx, eax" \ + "push edx" \ + "popfd" \ + parm [edx] nomemory \ + value [eax] \ + modify exact [edx] nomemory; +#endif + +/* Note! Must use the 64-bit integer return value convension. + The order of registers in the value [set] does not seem to mean anything. */ +#undef ASMReadTSC +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMReadTSC = \ + ".586" \ + "rdtsc" \ + parm [] nomemory \ + value [eax edx] \ + modify exact [edx eax] nomemory; +#endif + +#undef ASMReadTscWithAux +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMReadTscWithAux = \ + 0x0f 0x01 0xf9 \ + "mov [ebx], ecx" \ + parm [ebx] \ + value [eax edx] \ + modify exact [eax edx ecx]; +#endif + +/* ASMCpuId: Implemented externally, too many parameters. */ +/* ASMCpuId_Idx_ECX: Implemented externally, too many parameters. */ +/* ASMCpuIdExSlow: Always implemented externally. */ + +#undef ASMCpuId_ECX_EDX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_ECX_EDX = \ + ".586" \ + "cpuid" \ + "mov [edi], ecx" \ + "mov [esi], edx" \ + parm [eax] [edi] [esi] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMCpuId_EAX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_EAX = \ + ".586" \ + "cpuid" \ + parm [eax] \ + value [eax] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMCpuId_EBX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_EBX = \ + ".586" \ + "cpuid" \ + parm [eax] \ + value [ebx] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMCpuId_ECX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_ECX = \ + ".586" \ + "cpuid" \ + parm [eax] \ + value [ecx] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMCpuId_EDX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_EDX = \ + ".586" \ + "cpuid" \ + parm [eax] \ + value [edx] \ + modify exact [eax ebx ecx edx]; +#endif + +/* ASMHasCpuId: MSC inline in main source file. */ + +#undef ASMGetApicId +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetApicId = \ + ".586" \ + "xor eax, eax" \ + "cpuid" \ + "shr ebx,24" \ + parm [] \ + value [bl] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMGetCR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCR0 = \ + "mov eax, cr0" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetCR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetCR0 = \ + "mov cr0, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMGetCR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCR2 = \ + "mov eax, cr2" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetCR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetCR2 = \ + "mov cr2, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMGetCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCR3 = \ + "mov eax, cr3" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetCR3 = \ + "mov cr3, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMReloadCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMReloadCR3 = \ + "mov eax, cr3" \ + "mov cr3, eax" \ + parm [] nomemory \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetCR4 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCR4 = \ + "mov eax, cr4" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetCR4 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetCR4 = \ + "mov cr4, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +/* ASMGetCR8: Don't bother for 32-bit. */ +/* ASMSetCR8: Don't bother for 32-bit. */ + +#undef ASMIntEnable +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMIntEnable = \ + "sti" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMIntDisable +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMIntDisable = \ + "cli" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMIntDisableFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMIntDisableFlags = \ + "pushfd" \ + "cli" \ + "pop eax" \ + parm [] nomemory \ + value [eax] \ + modify exact [] nomemory; +#endif + +#undef ASMHalt +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMHalt = \ + "hlt" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMRdMsr +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMRdMsr = \ + ".586" \ + "rdmsr" \ + parm [ecx] nomemory \ + value [eax edx] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMWrMsr +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMWrMsr = \ + ".586" \ + "wrmsr" \ + parm [ecx] [eax edx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMRdMsrEx +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMRdMsrEx = \ + ".586" \ + "rdmsr" \ + parm [ecx] [edi] nomemory \ + value [eax edx] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMWrMsrEx +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMWrMsrEx = \ + ".586" \ + "wrmsr" \ + parm [ecx] [edi] [eax edx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMRdMsr_Low +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMRdMsr_Low = \ + ".586" \ + "rdmsr" \ + parm [ecx] nomemory \ + value [eax] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMRdMsr_High +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMRdMsr_High = \ + ".586" \ + "rdmsr" \ + parm [ecx] nomemory \ + value [edx] \ + modify exact [eax edx] nomemory; +#endif + + +#undef ASMGetDR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR0 = \ + "mov eax, dr0" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDR1 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR1 = \ + "mov eax, dr1" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR2 = \ + "mov eax, dr2" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR3 = \ + "mov eax, dr3" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR6 = \ + "mov eax, dr6" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetAndClearDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetAndClearDR6 = \ + "mov edx, 0ffff0ff0h" \ + "mov eax, dr6" \ + "mov dr6, edx" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMGetDR7 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR7 = \ + "mov eax, dr7" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetDR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR0 = \ + "mov dr0, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR1 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR1 = \ + "mov dr1, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR2 = \ + "mov dr2, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR3 = \ + "mov dr3, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR6 = \ + "mov dr6, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR7 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR7 = \ + "mov dr7, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +/* Yeah, could've used outp here, but this keeps the main file simpler. */ +#undef ASMOutU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutU8 = \ + "out dx, al" \ + parm [dx] [al] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInU8 = \ + "in al, dx" \ + parm [dx] nomemory \ + value [al] \ + modify exact [] nomemory; +#endif + +#undef ASMOutU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutU16 = \ + "out dx, ax" \ + parm [dx] [ax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInU16 = \ + "in ax, dx" \ + parm [dx] nomemory \ + value [ax] \ + modify exact [] nomemory; +#endif + +#undef ASMOutU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutU32 = \ + "out dx, eax" \ + parm [dx] [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInU32 = \ + "in eax, dx" \ + parm [dx] nomemory \ + value [eax] \ + modify exact [] nomemory; +#endif + +#undef ASMOutStrU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutStrU8 = \ + "rep outsb" \ + parm [dx] [esi] [ecx] nomemory \ + modify exact [esi ecx] nomemory; +#endif + +#undef ASMInStrU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInStrU8 = \ + "rep insb" \ + parm [dx] [edi] [ecx] \ + modify exact [edi ecx]; +#endif + +#undef ASMOutStrU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutStrU16 = \ + "rep outsw" \ + parm [dx] [esi] [ecx] nomemory \ + modify exact [esi ecx] nomemory; +#endif + +#undef ASMInStrU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInStrU16 = \ + "rep insw" \ + parm [dx] [edi] [ecx] \ + modify exact [edi ecx]; +#endif + +#undef ASMOutStrU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutStrU32 = \ + "rep outsd" \ + parm [dx] [esi] [ecx] nomemory \ + modify exact [esi ecx] nomemory; +#endif + +#undef ASMInStrU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInStrU32 = \ + "rep insd" \ + parm [dx] [edi] [ecx] \ + modify exact [edi ecx]; +#endif + +#undef ASMInvalidatePage +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInvalidatePage = \ + "invlpg [eax]" \ + parm [eax] \ + modify exact []; +#endif + +#undef ASMWriteBackAndInvalidateCaches +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMWriteBackAndInvalidateCaches = \ + ".486" \ + "wbinvd" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInvalidateInternalCaches +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInvalidateInternalCaches = \ + ".486" \ + "invd" \ + parm [] \ + modify exact []; +#endif + +#endif /* !IPRT_INCLUDED_asm_amd64_x86_watcom_32_h */ + diff --git a/include/iprt/asm-amd64-x86.h b/include/iprt/asm-amd64-x86.h new file mode 100644 index 00000000..0bfa1925 --- /dev/null +++ b/include/iprt/asm-amd64-x86.h @@ -0,0 +1,3447 @@ +/** @file + * IPRT - AMD64 and x86 Specific Assembly Functions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_h +#define IPRT_INCLUDED_asm_amd64_x86_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#if !defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86) +# error "Not on AMD64 or x86" +#endif + +#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN +/* Emit the intrinsics at all optimization levels. */ +# include +# pragma intrinsic(_ReadWriteBarrier) +# pragma intrinsic(__cpuid) +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 /*?*/ +# pragma intrinsic(__cpuidex) +# endif +# pragma intrinsic(_enable) +# pragma intrinsic(_disable) +# pragma intrinsic(__rdtsc) +# pragma intrinsic(__readmsr) +# pragma intrinsic(__writemsr) +# pragma intrinsic(__outbyte) +# pragma intrinsic(__outbytestring) +# pragma intrinsic(__outword) +# pragma intrinsic(__outwordstring) +# pragma intrinsic(__outdword) +# pragma intrinsic(__outdwordstring) +# pragma intrinsic(__inbyte) +# pragma intrinsic(__inbytestring) +# pragma intrinsic(__inword) +# pragma intrinsic(__inwordstring) +# pragma intrinsic(__indword) +# pragma intrinsic(__indwordstring) +# pragma intrinsic(__invlpg) +# pragma intrinsic(__wbinvd) +# pragma intrinsic(__readcr0) +# pragma intrinsic(__readcr2) +# pragma intrinsic(__readcr3) +# pragma intrinsic(__readcr4) +# pragma intrinsic(__writecr0) +# pragma intrinsic(__writecr3) +# pragma intrinsic(__writecr4) +# pragma intrinsic(__readdr) +# pragma intrinsic(__writedr) +# ifdef RT_ARCH_AMD64 +# pragma intrinsic(__readcr8) +# pragma intrinsic(__writecr8) +# endif +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2005 +# pragma intrinsic(__halt) +# endif +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 +/*# pragma intrinsic(__readeflags) - buggy intrinsics in VC++ 2010, reordering/optimizers issues +# pragma intrinsic(__writeeflags) */ +# pragma intrinsic(__rdtscp) +# endif +# if defined(RT_ARCH_AMD64) && RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 /*?*/ +# pragma intrinsic(_readfsbase_u64) +# pragma intrinsic(_readgsbase_u64) +# pragma intrinsic(_writefsbase_u64) +# pragma intrinsic(_writegsbase_u64) +# endif +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 +# pragma intrinsic(__lidt) +# pragma intrinsic(__sidt) +# pragma intrinsic(_lgdt) +# pragma intrinsic(_sgdt) +# endif +#endif + + +/* + * Undefine all symbols we have Watcom C/C++ #pragma aux'es for. + */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 +# include "asm-amd64-x86-watcom-16.h" +#elif defined(__WATCOMC__) && ARCH_BITS == 32 +# include "asm-amd64-x86-watcom-32.h" +#endif + + +/** @defgroup grp_rt_asm_amd64_x86 AMD64 and x86 Specific ASM Routines + * @ingroup grp_rt_asm + * @{ + */ + +/** @todo find a more proper place for these structures? */ + +#pragma pack(1) +/** IDTR */ +typedef struct RTIDTR +{ + /** Size of the IDT. */ + uint16_t cbIdt; + /** Address of the IDT. */ +#if ARCH_BITS != 64 + uint32_t pIdt; +#else + uint64_t pIdt; +#endif +} RTIDTR, RT_FAR *PRTIDTR; +#pragma pack() + +#pragma pack(1) +/** @internal */ +typedef struct RTIDTRALIGNEDINT +{ + /** Alignment padding. */ + uint16_t au16Padding[ARCH_BITS == 64 ? 3 : 1]; + /** The IDTR structure. */ + RTIDTR Idtr; +} RTIDTRALIGNEDINT; +#pragma pack() + +/** Wrapped RTIDTR for preventing misalignment exceptions. */ +typedef union RTIDTRALIGNED +{ + /** Try make sure this structure has optimal alignment. */ + uint64_t auAlignmentHack[ARCH_BITS == 64 ? 2 : 1]; + /** Aligned structure. */ + RTIDTRALIGNEDINT s; +} RTIDTRALIGNED; +AssertCompileSize(RTIDTRALIGNED, ((ARCH_BITS == 64) + 1) * 8); +/** Pointer to a an RTIDTR alignment wrapper. */ +typedef RTIDTRALIGNED RT_FAR *PRIDTRALIGNED; + + +#pragma pack(1) +/** GDTR */ +typedef struct RTGDTR +{ + /** Size of the GDT. */ + uint16_t cbGdt; + /** Address of the GDT. */ +#if ARCH_BITS != 64 + uint32_t pGdt; +#else + uint64_t pGdt; +#endif +} RTGDTR, RT_FAR *PRTGDTR; +#pragma pack() + +#pragma pack(1) +/** @internal */ +typedef struct RTGDTRALIGNEDINT +{ + /** Alignment padding. */ + uint16_t au16Padding[ARCH_BITS == 64 ? 3 : 1]; + /** The GDTR structure. */ + RTGDTR Gdtr; +} RTGDTRALIGNEDINT; +#pragma pack() + +/** Wrapped RTGDTR for preventing misalignment exceptions. */ +typedef union RTGDTRALIGNED +{ + /** Try make sure this structure has optimal alignment. */ + uint64_t auAlignmentHack[ARCH_BITS == 64 ? 2 : 1]; + /** Aligned structure. */ + RTGDTRALIGNEDINT s; +} RTGDTRALIGNED; +AssertCompileSize(RTIDTRALIGNED, ((ARCH_BITS == 64) + 1) * 8); +/** Pointer to a an RTGDTR alignment wrapper. */ +typedef RTGDTRALIGNED RT_FAR *PRGDTRALIGNED; + + +/** + * Gets the content of the IDTR CPU register. + * @param pIdtr Where to store the IDTR contents. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMGetIDTR(PRTIDTR pIdtr); +#else +DECLINLINE(void) ASMGetIDTR(PRTIDTR pIdtr) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + __sidt(pIdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("sidt %0" : "=m" (*pIdtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pIdtr] + sidt [rax] +# else + mov eax, [pIdtr] + sidt [eax] +# endif + } +# endif +} +#endif + + +/** + * Gets the content of the IDTR.LIMIT CPU register. + * @returns IDTR limit. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMGetIdtrLimit(void); +#else +DECLINLINE(uint16_t) ASMGetIdtrLimit(void) +{ + RTIDTRALIGNED TmpIdtr; +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + __sidt(&TmpIdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("sidt %0" : "=m" (TmpIdtr.s.Idtr)); +# else + __asm + { + sidt [TmpIdtr.s.Idtr] + } +# endif + return TmpIdtr.s.Idtr.cbIdt; +} +#endif + + +/** + * Sets the content of the IDTR CPU register. + * @param pIdtr Where to load the IDTR contents from + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetIDTR(const RTIDTR RT_FAR *pIdtr); +#else +DECLINLINE(void) ASMSetIDTR(const RTIDTR RT_FAR *pIdtr) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + __lidt((void *)pIdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lidt %0" : : "m" (*pIdtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pIdtr] + lidt [rax] +# else + mov eax, [pIdtr] + lidt [eax] +# endif + } +# endif +} +#endif + + +/** + * Gets the content of the GDTR CPU register. + * @param pGdtr Where to store the GDTR contents. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMGetGDTR(PRTGDTR pGdtr); +#else +DECLINLINE(void) ASMGetGDTR(PRTGDTR pGdtr) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + _sgdt(pGdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("sgdt %0" : "=m" (*pGdtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pGdtr] + sgdt [rax] +# else + mov eax, [pGdtr] + sgdt [eax] +# endif + } +# endif +} +#endif + + +/** + * Sets the content of the GDTR CPU register. + * @param pGdtr Where to load the GDTR contents from + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetGDTR(const RTGDTR RT_FAR *pGdtr); +#else +DECLINLINE(void) ASMSetGDTR(const RTGDTR RT_FAR *pGdtr) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + _lgdt((void *)pGdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lgdt %0" : : "m" (*pGdtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pGdtr] + lgdt [rax] +# else + mov eax, [pGdtr] + lgdt [eax] +# endif + } +# endif +} +#endif + + + +/** + * Get the cs register. + * @returns cs. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetCS(void); +#else +DECLINLINE(RTSEL) ASMGetCS(void) +{ + RTSEL SelCS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%cs, %0\n\t" : "=r" (SelCS)); +# else + __asm + { + mov ax, cs + mov [SelCS], ax + } +# endif + return SelCS; +} +#endif + + +/** + * Get the DS register. + * @returns DS. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetDS(void); +#else +DECLINLINE(RTSEL) ASMGetDS(void) +{ + RTSEL SelDS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%ds, %0\n\t" : "=r" (SelDS)); +# else + __asm + { + mov ax, ds + mov [SelDS], ax + } +# endif + return SelDS; +} +#endif + + +/** + * Get the ES register. + * @returns ES. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetES(void); +#else +DECLINLINE(RTSEL) ASMGetES(void) +{ + RTSEL SelES; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%es, %0\n\t" : "=r" (SelES)); +# else + __asm + { + mov ax, es + mov [SelES], ax + } +# endif + return SelES; +} +#endif + + +/** + * Get the FS register. + * @returns FS. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetFS(void); +#else +DECLINLINE(RTSEL) ASMGetFS(void) +{ + RTSEL SelFS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%fs, %0\n\t" : "=r" (SelFS)); +# else + __asm + { + mov ax, fs + mov [SelFS], ax + } +# endif + return SelFS; +} +# endif + +#ifdef RT_ARCH_AMD64 + +/** + * Get the FS base register. + * @returns FS base address. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/ +DECLASM(uint64_t) ASMGetFSBase(void); +#else +DECLINLINE(uint64_t) ASMGetFSBase(void) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 + return (uint64_t)_readfsbase_u64(); +# elif RT_INLINE_ASM_GNU_STYLE + uint64_t uFSBase; + __asm__ __volatile__("rdfsbase %0\n\t" : "=r" (uFSBase)); + return uFSBase; +# endif +} +# endif + + +/** + * Set the FS base register. + * @param uNewBase The new base value. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/ +DECLASM(void) ASMSetFSBase(uint64_t uNewBase); +#else +DECLINLINE(void) ASMSetFSBase(uint64_t uNewBase) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 + _writefsbase_u64(uNewBase); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wrfsbase %0\n\t" : : "r" (uNewBase)); +# endif +} +# endif + +#endif /* RT_ARCH_AMD64 */ + +/** + * Get the GS register. + * @returns GS. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetGS(void); +#else +DECLINLINE(RTSEL) ASMGetGS(void) +{ + RTSEL SelGS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%gs, %0\n\t" : "=r" (SelGS)); +# else + __asm + { + mov ax, gs + mov [SelGS], ax + } +# endif + return SelGS; +} +#endif + +#ifdef RT_ARCH_AMD64 + +/** + * Get the GS base register. + * @returns GS base address. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/ +DECLASM(uint64_t) ASMGetGSBase(void); +#else +DECLINLINE(uint64_t) ASMGetGSBase(void) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 + return (uint64_t)_readgsbase_u64(); +# elif RT_INLINE_ASM_GNU_STYLE + uint64_t uGSBase; + __asm__ __volatile__("rdgsbase %0\n\t" : "=r" (uGSBase)); + return uGSBase; +# endif +} +# endif + + +/** + * Set the GS base register. + * @param uNewBase The new base value. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/ +DECLASM(void) ASMSetGSBase(uint64_t uNewBase); +#else +DECLINLINE(void) ASMSetGSBase(uint64_t uNewBase) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 + _writegsbase_u64(uNewBase); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wrgsbase %0\n\t" : : "r" (uNewBase)); +# endif +} +# endif + +#endif /* RT_ARCH_AMD64 */ + + +/** + * Get the SS register. + * @returns SS. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetSS(void); +#else +DECLINLINE(RTSEL) ASMGetSS(void) +{ + RTSEL SelSS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%ss, %0\n\t" : "=r" (SelSS)); +# else + __asm + { + mov ax, ss + mov [SelSS], ax + } +# endif + return SelSS; +} +#endif + + +/** + * Get the TR register. + * @returns TR. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetTR(void); +#else +DECLINLINE(RTSEL) ASMGetTR(void) +{ + RTSEL SelTR; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("str %w0\n\t" : "=r" (SelTR)); +# else + __asm + { + str ax + mov [SelTR], ax + } +# endif + return SelTR; +} +#endif + + +/** + * Get the LDTR register. + * @returns LDTR. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetLDTR(void); +#else +DECLINLINE(RTSEL) ASMGetLDTR(void) +{ + RTSEL SelLDTR; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("sldt %w0\n\t" : "=r" (SelLDTR)); +# else + __asm + { + sldt ax + mov [SelLDTR], ax + } +# endif + return SelLDTR; +} +#endif + + +/** + * Get the access rights for the segment selector. + * + * @returns The access rights on success or UINT32_MAX on failure. + * @param uSel The selector value. + * + * @remarks Using UINT32_MAX for failure is chosen because valid access rights + * always have bits 0:7 as 0 (on both Intel & AMD). + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMGetSegAttr(uint32_t uSel); +#else +DECLINLINE(uint32_t) ASMGetSegAttr(uint32_t uSel) +{ + uint32_t uAttr; + /* LAR only accesses 16-bit of the source operand, but eax for the + destination operand is required for getting the full 32-bit access rights. */ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lar %1, %%eax\n\t" + "jz done%=\n\t" + "movl $0xffffffff, %%eax\n\t" + "done%=:\n\t" + "movl %%eax, %0\n\t" + : "=r" (uAttr) + : "r" (uSel) + : "cc", "%eax"); +# else + __asm + { + lar eax, [uSel] + jz done + mov eax, 0ffffffffh + done: + mov [uAttr], eax + } +# endif + return uAttr; +} +#endif + + +/** + * Get the [RE]FLAGS register. + * @returns [RE]FLAGS. + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */ +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMGetFlags(void); +#else +DECLINLINE(RTCCUINTREG) ASMGetFlags(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "popq %0\n\t" + : "=r" (uFlags)); +# else + __asm__ __volatile__("pushfl\n\t" + "popl %0\n\t" + : "=r" (uFlags)); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + uFlags = __readeflags(); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + pushfq + pop [uFlags] +# else + pushfd + pop [uFlags] +# endif + } +# endif + return uFlags; +} +#endif + + +/** + * Set the [RE]FLAGS register. + * @param uFlags The new [RE]FLAGS value. + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - see __readeflags() above. */ +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetFlags(RTCCUINTREG uFlags); +#else +DECLINLINE(void) ASMSetFlags(RTCCUINTREG uFlags) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushq %0\n\t" + "popfq\n\t" + : : "g" (uFlags)); +# else + __asm__ __volatile__("pushl %0\n\t" + "popfl\n\t" + : : "g" (uFlags)); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + __writeeflags(uFlags); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + push [uFlags] + popfq +# else + push [uFlags] + popfd +# endif + } +# endif +} +#endif + + +/** + * Modifies the [RE]FLAGS register. + * @returns Original value. + * @param fAndEfl Flags to keep (applied first). + * @param fOrEfl Flags to be set. + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */ +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl); +#else +DECLINLINE(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl) +{ + RTCCUINTREG fOldEfl; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "movq (%%rsp), %0\n\t" + "andq %0, %1\n\t" + "orq %3, %1\n\t" + "mov %1, (%%rsp)\n\t" + "popfq\n\t" + : "=&r" (fOldEfl), + "=r" (fAndEfl) + : "1" (fAndEfl), + "rn" (fOrEfl) ); +# else + __asm__ __volatile__("pushfl\n\t" + "movl (%%esp), %0\n\t" + "andl %1, (%%esp)\n\t" + "orl %2, (%%esp)\n\t" + "popfl\n\t" + : "=&r" (fOldEfl) + : "rn" (fAndEfl), + "rn" (fOrEfl) ); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + fOldEfl = __readeflags(); + __writeeflags((fOldEfl & fAndEfl) | fOrEfl); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [fAndEfl] + mov rcx, [fOrEfl] + pushfq + mov rax, [rsp] + and rdx, rax + or rdx, rcx + mov [rsp], rdx + popfq + mov [fOldEfl], rax +# else + mov edx, [fAndEfl] + mov ecx, [fOrEfl] + pushfd + mov eax, [esp] + and edx, eax + or edx, ecx + mov [esp], edx + popfd + mov [fOldEfl], eax +# endif + } +# endif + return fOldEfl; +} +#endif + + +/** + * Modifies the [RE]FLAGS register by ORing in one or more flags. + * @returns Original value. + * @param fOrEfl The flags to be set (ORed in). + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */ +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl); +#else +DECLINLINE(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl) +{ + RTCCUINTREG fOldEfl; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "movq (%%rsp), %0\n\t" + "orq %1, (%%rsp)\n\t" + "popfq\n\t" + : "=&r" (fOldEfl) + : "rn" (fOrEfl) ); +# else + __asm__ __volatile__("pushfl\n\t" + "movl (%%esp), %0\n\t" + "orl %1, (%%esp)\n\t" + "popfl\n\t" + : "=&r" (fOldEfl) + : "rn" (fOrEfl) ); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + fOldEfl = __readeflags(); + __writeeflags(fOldEfl | fOrEfl); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rcx, [fOrEfl] + pushfq + mov rdx, [rsp] + or [rsp], rcx + popfq + mov [fOldEfl], rax +# else + mov ecx, [fOrEfl] + pushfd + mov edx, [esp] + or [esp], ecx + popfd + mov [fOldEfl], eax +# endif + } +# endif + return fOldEfl; +} +#endif + + +/** + * Modifies the [RE]FLAGS register by AND'ing out one or more flags. + * @returns Original value. + * @param fAndEfl The flags to keep. + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */ +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl); +#else +DECLINLINE(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl) +{ + RTCCUINTREG fOldEfl; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "movq (%%rsp), %0\n\t" + "andq %1, (%%rsp)\n\t" + "popfq\n\t" + : "=&r" (fOldEfl) + : "rn" (fAndEfl) ); +# else + __asm__ __volatile__("pushfl\n\t" + "movl (%%esp), %0\n\t" + "andl %1, (%%esp)\n\t" + "popfl\n\t" + : "=&r" (fOldEfl) + : "rn" (fAndEfl) ); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + fOldEfl = __readeflags(); + __writeeflags(fOldEfl & fAndEfl); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [fAndEfl] + pushfq + mov rdx, [rsp] + and [rsp], rdx + popfq + mov [fOldEfl], rax +# else + mov edx, [fAndEfl] + pushfd + mov edx, [esp] + and [esp], edx + popfd + mov [fOldEfl], eax +# endif + } +# endif + return fOldEfl; +} +#endif + + +/** + * Gets the content of the CPU timestamp counter register. + * + * @returns TSC. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMReadTSC(void); +#else +DECLINLINE(uint64_t) ASMReadTSC(void) +{ + RTUINT64U u; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdtsc\n\t" : "=a" (u.s.Lo), "=d" (u.s.Hi)); +# else +# if RT_INLINE_ASM_USES_INTRIN + u.u = __rdtsc(); +# else + __asm + { + rdtsc + mov [u.s.Lo], eax + mov [u.s.Hi], edx + } +# endif +# endif + return u.u; +} +#endif + + +/** + * Gets the content of the CPU timestamp counter register and the + * assoicated AUX value. + * + * @returns TSC. + * @param puAux Where to store the AUX value. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2008 +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMReadTscWithAux(uint32_t RT_FAR *puAux); +#else +DECLINLINE(uint64_t) ASMReadTscWithAux(uint32_t RT_FAR *puAux) +{ + RTUINT64U u; +# if RT_INLINE_ASM_GNU_STYLE + /* rdtscp is not supported by ancient linux build VM of course :-( */ + /*__asm__ __volatile__("rdtscp\n\t" : "=a" (u.s.Lo), "=d" (u.s.Hi), "=c" (*puAux)); */ + __asm__ __volatile__(".byte 0x0f,0x01,0xf9\n\t" : "=a" (u.s.Lo), "=d" (u.s.Hi), "=c" (*puAux)); +# else +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + u.u = __rdtscp(puAux); +# else + __asm + { + rdtscp + mov [u.s.Lo], eax + mov [u.s.Hi], edx + mov eax, [puAux] + mov [eax], ecx + } +# endif +# endif + return u.u; +} +#endif + + +/** + * Performs the cpuid instruction returning all registers. + * + * @param uOperator CPUID operation (eax). + * @param pvEAX Where to store eax. + * @param pvEBX Where to store ebx. + * @param pvECX Where to store ecx. + * @param pvEDX Where to store edx. + * @remark We're using void pointers to ease the use of special bitfield structures and such. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +DECLASM(void) ASMCpuId(uint32_t uOperator, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX); +#else +DECLINLINE(void) ASMCpuId(uint32_t uOperator, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uRAX, uRBX, uRCX, uRDX; + __asm__ __volatile__ ("cpuid\n\t" + : "=a" (uRAX), + "=b" (uRBX), + "=c" (uRCX), + "=d" (uRDX) + : "0" (uOperator), "2" (0)); + *(uint32_t RT_FAR *)pvEAX = (uint32_t)uRAX; + *(uint32_t RT_FAR *)pvEBX = (uint32_t)uRBX; + *(uint32_t RT_FAR *)pvECX = (uint32_t)uRCX; + *(uint32_t RT_FAR *)pvEDX = (uint32_t)uRDX; +# else + __asm__ __volatile__ ("xchgl %%ebx, %1\n\t" + "cpuid\n\t" + "xchgl %%ebx, %1\n\t" + : "=a" (*(uint32_t *)pvEAX), + "=r" (*(uint32_t *)pvEBX), + "=c" (*(uint32_t *)pvECX), + "=d" (*(uint32_t *)pvEDX) + : "0" (uOperator), "2" (0)); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + *(uint32_t RT_FAR *)pvEAX = aInfo[0]; + *(uint32_t RT_FAR *)pvEBX = aInfo[1]; + *(uint32_t RT_FAR *)pvECX = aInfo[2]; + *(uint32_t RT_FAR *)pvEDX = aInfo[3]; + +# else + uint32_t uEAX; + uint32_t uEBX; + uint32_t uECX; + uint32_t uEDX; + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [uEAX], eax + mov [uEBX], ebx + mov [uECX], ecx + mov [uEDX], edx + pop ebx + } + *(uint32_t RT_FAR *)pvEAX = uEAX; + *(uint32_t RT_FAR *)pvEBX = uEBX; + *(uint32_t RT_FAR *)pvECX = uECX; + *(uint32_t RT_FAR *)pvEDX = uEDX; +# endif +} +#endif + + +/** + * Performs the CPUID instruction with EAX and ECX input returning ALL output + * registers. + * + * @param uOperator CPUID operation (eax). + * @param uIdxECX ecx index + * @param pvEAX Where to store eax. + * @param pvEBX Where to store ebx. + * @param pvECX Where to store ecx. + * @param pvEDX Where to store edx. + * @remark We're using void pointers to ease the use of special bitfield structures and such. + */ +#if RT_INLINE_ASM_EXTERNAL || RT_INLINE_ASM_USES_INTRIN +DECLASM(void) ASMCpuId_Idx_ECX(uint32_t uOperator, uint32_t uIdxECX, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX); +#else +DECLINLINE(void) ASMCpuId_Idx_ECX(uint32_t uOperator, uint32_t uIdxECX, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uRAX, uRBX, uRCX, uRDX; + __asm__ ("cpuid\n\t" + : "=a" (uRAX), + "=b" (uRBX), + "=c" (uRCX), + "=d" (uRDX) + : "0" (uOperator), + "2" (uIdxECX)); + *(uint32_t RT_FAR *)pvEAX = (uint32_t)uRAX; + *(uint32_t RT_FAR *)pvEBX = (uint32_t)uRBX; + *(uint32_t RT_FAR *)pvECX = (uint32_t)uRCX; + *(uint32_t RT_FAR *)pvEDX = (uint32_t)uRDX; +# else + __asm__ ("xchgl %%ebx, %1\n\t" + "cpuid\n\t" + "xchgl %%ebx, %1\n\t" + : "=a" (*(uint32_t *)pvEAX), + "=r" (*(uint32_t *)pvEBX), + "=c" (*(uint32_t *)pvECX), + "=d" (*(uint32_t *)pvEDX) + : "0" (uOperator), + "2" (uIdxECX)); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuidex(aInfo, uOperator, uIdxECX); + *(uint32_t RT_FAR *)pvEAX = aInfo[0]; + *(uint32_t RT_FAR *)pvEBX = aInfo[1]; + *(uint32_t RT_FAR *)pvECX = aInfo[2]; + *(uint32_t RT_FAR *)pvEDX = aInfo[3]; + +# else + uint32_t uEAX; + uint32_t uEBX; + uint32_t uECX; + uint32_t uEDX; + __asm + { + push ebx + mov eax, [uOperator] + mov ecx, [uIdxECX] + cpuid + mov [uEAX], eax + mov [uEBX], ebx + mov [uECX], ecx + mov [uEDX], edx + pop ebx + } + *(uint32_t RT_FAR *)pvEAX = uEAX; + *(uint32_t RT_FAR *)pvEBX = uEBX; + *(uint32_t RT_FAR *)pvECX = uECX; + *(uint32_t RT_FAR *)pvEDX = uEDX; +# endif +} +#endif + + +/** + * CPUID variant that initializes all 4 registers before the CPUID instruction. + * + * @returns The EAX result value. + * @param uOperator CPUID operation (eax). + * @param uInitEBX The value to assign EBX prior to the CPUID instruction. + * @param uInitECX The value to assign ECX prior to the CPUID instruction. + * @param uInitEDX The value to assign EDX prior to the CPUID instruction. + * @param pvEAX Where to store eax. Optional. + * @param pvEBX Where to store ebx. Optional. + * @param pvECX Where to store ecx. Optional. + * @param pvEDX Where to store edx. Optional. + */ +DECLASM(uint32_t) ASMCpuIdExSlow(uint32_t uOperator, uint32_t uInitEBX, uint32_t uInitECX, uint32_t uInitEDX, + void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX); + + +/** + * Performs the cpuid instruction returning ecx and edx. + * + * @param uOperator CPUID operation (eax). + * @param pvECX Where to store ecx. + * @param pvEDX Where to store edx. + * @remark We're using void pointers to ease the use of special bitfield structures and such. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMCpuId_ECX_EDX(uint32_t uOperator, void RT_FAR *pvECX, void RT_FAR *pvEDX); +#else +DECLINLINE(void) ASMCpuId_ECX_EDX(uint32_t uOperator, void RT_FAR *pvECX, void RT_FAR *pvEDX) +{ + uint32_t uEBX; + ASMCpuId(uOperator, &uOperator, &uEBX, pvECX, pvEDX); +} +#endif + + +/** + * Performs the cpuid instruction returning eax. + * + * @param uOperator CPUID operation (eax). + * @returns EAX after cpuid operation. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_EAX(uint32_t uOperator); +#else +DECLINLINE(uint32_t) ASMCpuId_EAX(uint32_t uOperator) +{ + RTCCUINTREG xAX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ ("cpuid" + : "=a" (xAX) + : "0" (uOperator) + : "rbx", "rcx", "rdx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ ("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx\n\t" + : "=a" (xAX) + : "0" (uOperator) + : "ecx", "edx"); +# else + __asm__ ("cpuid" + : "=a" (xAX) + : "0" (uOperator) + : "edx", "ecx", "ebx"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + xAX = aInfo[0]; + +# else + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [xAX], eax + pop ebx + } +# endif + return (uint32_t)xAX; +} +#endif + + +/** + * Performs the cpuid instruction returning ebx. + * + * @param uOperator CPUID operation (eax). + * @returns EBX after cpuid operation. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_EBX(uint32_t uOperator); +#else +DECLINLINE(uint32_t) ASMCpuId_EBX(uint32_t uOperator) +{ + RTCCUINTREG xBX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpill; + __asm__ ("cpuid" + : "=a" (uSpill), + "=b" (xBX) + : "0" (uOperator) + : "rdx", "rcx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ ("push %%ebx\n\t" + "cpuid\n\t" + "mov %%ebx, %%edx\n\t" + "pop %%ebx\n\t" + : "=a" (uOperator), + "=d" (xBX) + : "0" (uOperator) + : "ecx"); +# else + __asm__ ("cpuid" + : "=a" (uOperator), + "=b" (xBX) + : "0" (uOperator) + : "edx", "ecx"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + xBX = aInfo[1]; + +# else + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [xBX], ebx + pop ebx + } +# endif + return (uint32_t)xBX; +} +#endif + + +/** + * Performs the cpuid instruction returning ecx. + * + * @param uOperator CPUID operation (eax). + * @returns ECX after cpuid operation. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_ECX(uint32_t uOperator); +#else +DECLINLINE(uint32_t) ASMCpuId_ECX(uint32_t uOperator) +{ + RTCCUINTREG xCX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpill; + __asm__ ("cpuid" + : "=a" (uSpill), + "=c" (xCX) + : "0" (uOperator) + : "rbx", "rdx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ ("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx\n\t" + : "=a" (uOperator), + "=c" (xCX) + : "0" (uOperator) + : "edx"); +# else + __asm__ ("cpuid" + : "=a" (uOperator), + "=c" (xCX) + : "0" (uOperator) + : "ebx", "edx"); + +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + xCX = aInfo[2]; + +# else + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [xCX], ecx + pop ebx + } +# endif + return (uint32_t)xCX; +} +#endif + + +/** + * Performs the cpuid instruction returning edx. + * + * @param uOperator CPUID operation (eax). + * @returns EDX after cpuid operation. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_EDX(uint32_t uOperator); +#else +DECLINLINE(uint32_t) ASMCpuId_EDX(uint32_t uOperator) +{ + RTCCUINTREG xDX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpill; + __asm__ ("cpuid" + : "=a" (uSpill), + "=d" (xDX) + : "0" (uOperator) + : "rbx", "rcx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ ("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx\n\t" + : "=a" (uOperator), + "=d" (xDX) + : "0" (uOperator) + : "ecx"); +# else + __asm__ ("cpuid" + : "=a" (uOperator), + "=d" (xDX) + : "0" (uOperator) + : "ebx", "ecx"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + xDX = aInfo[3]; + +# else + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [xDX], edx + pop ebx + } +# endif + return (uint32_t)xDX; +} +#endif + + +/** + * Checks if the current CPU supports CPUID. + * + * @returns true if CPUID is supported. + */ +#ifdef __WATCOMC__ +DECLASM(bool) ASMHasCpuId(void); +#else +DECLINLINE(bool) ASMHasCpuId(void) +{ +# ifdef RT_ARCH_AMD64 + return true; /* ASSUME that all amd64 compatible CPUs have cpuid. */ +# else /* !RT_ARCH_AMD64 */ + bool fRet = false; +# if RT_INLINE_ASM_GNU_STYLE + uint32_t u1; + uint32_t u2; + __asm__ ("pushf\n\t" + "pop %1\n\t" + "mov %1, %2\n\t" + "xorl $0x200000, %1\n\t" + "push %1\n\t" + "popf\n\t" + "pushf\n\t" + "pop %1\n\t" + "cmpl %1, %2\n\t" + "setne %0\n\t" + "push %2\n\t" + "popf\n\t" + : "=m" (fRet), "=r" (u1), "=r" (u2)); +# else + __asm + { + pushfd + pop eax + mov ebx, eax + xor eax, 0200000h + push eax + popfd + pushfd + pop eax + cmp eax, ebx + setne fRet + push ebx + popfd + } +# endif + return fRet; +# endif /* !RT_ARCH_AMD64 */ +} +#endif + + +/** + * Gets the APIC ID of the current CPU. + * + * @returns the APIC ID. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMGetApicId(void); +#else +DECLINLINE(uint8_t) ASMGetApicId(void) +{ + RTCCUINTREG xBX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpill; + __asm__ __volatile__ ("cpuid" + : "=a" (uSpill), + "=b" (xBX) + : "0" (1) + : "rcx", "rdx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + RTCCUINTREG uSpill; + __asm__ __volatile__ ("mov %%ebx,%1\n\t" + "cpuid\n\t" + "xchgl %%ebx,%1\n\t" + : "=a" (uSpill), + "=rm" (xBX) + : "0" (1) + : "ecx", "edx"); +# else + RTCCUINTREG uSpill; + __asm__ __volatile__ ("cpuid" + : "=a" (uSpill), + "=b" (xBX) + : "0" (1) + : "ecx", "edx"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, 1); + xBX = aInfo[1]; + +# else + __asm + { + push ebx + mov eax, 1 + cpuid + mov [xBX], ebx + pop ebx + } +# endif + return (uint8_t)(xBX >> 24); +} +#endif + + +/** + * Gets the APIC ID of the current CPU using leaf 0xb. + * + * @returns the APIC ID. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2010 /*?*/ +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMGetApicIdExt0B(void); +#else +DECLINLINE(uint32_t) ASMGetApicIdExt0B(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG xDX; +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpillEax, uSpillEcx; + __asm__ __volatile__ ("cpuid" + : "=a" (uSpillEax), + "=c" (uSpillEcx), + "=d" (xDX) + : "0" (0xb), + "1" (0) + : "rbx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + RTCCUINTREG uSpillEax, uSpillEcx, uSpillEbx; + __asm__ __volatile__ ("mov %%ebx,%2\n\t" + "cpuid\n\t" + "xchgl %%ebx,%2\n\t" + : "=a" (uSpillEax), + "=c" (uSpillEcx), + "=rm" (uSpillEbx), + "=d" (xDX) + : "0" (0xb), + "1" (0)); +# else + RTCCUINTREG uSpillEax, uSpillEcx; + __asm__ __volatile__ ("cpuid" + : "=a" (uSpillEax), + "=c" (uSpillEcx), + "=d" (xDX) + : "0" (0xb), + "1" (0) + : "ebx"); +# endif + return (uint32_t)xDX; + +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 /*?*/ + + int aInfo[4]; + __cpuidex(aInfo, 0xb, 0); + return aInfo[3]; + +# else + RTCCUINTREG xDX; + __asm + { + push ebx + mov eax, 0xb + xor ecx, ecx + cpuid + mov [xDX], edx + pop ebx + } + return (uint32_t)xDX; +# endif +} +#endif + + +/** + * Gets the APIC ID of the current CPU using leaf 8000001E. + * + * @returns the APIC ID. + */ +DECLINLINE(uint32_t) ASMGetApicIdExt8000001E(void) +{ + return ASMCpuId_EAX(0x8000001e); +} + + +/** + * Tests if this is a genuine Intel CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsIntelCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsIntelCpu(uEBX, uECX, uEDX); +} + + +/** + * Tests if this is an authentic AMD CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsAmdCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsAmdCpu(uEBX, uECX, uEDX); +} + + +/** + * Tests if this is a centaur hauling VIA CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsViaCentaurCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsViaCentaurCpu(uEBX, uECX, uEDX); +} + + +/** + * Tests if this is a Shanghai CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsShanghaiCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsShanghaiCpu(uEBX, uECX, uEDX); +} + + +/** + * Tests if this is a genuine Hygon CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsHygonCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsHygonCpu(uEBX, uECX, uEDX); +} + + +/** + * Get cr0. + * @returns cr0. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR0(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR0(void) +{ + RTCCUINTXREG uCR0; +# if RT_INLINE_ASM_USES_INTRIN + uCR0 = __readcr0(); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr0, %0\t\n" : "=r" (uCR0)); +# else + __asm__ __volatile__("movl %%cr0, %0\t\n" : "=r" (uCR0)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr0 + mov [uCR0], rax +# else + mov eax, cr0 + mov [uCR0], eax +# endif + } +# endif + return uCR0; +} +#endif + + +/** + * Sets the CR0 register. + * @param uCR0 The new CR0 value. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR0(RTCCUINTXREG uCR0); +#else +DECLINLINE(void) ASMSetCR0(RTCCUINTXREG uCR0) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writecr0(uCR0); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%cr0\n\t" :: "r" (uCR0)); +# else + __asm__ __volatile__("movl %0, %%cr0\n\t" :: "r" (uCR0)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uCR0] + mov cr0, rax +# else + mov eax, [uCR0] + mov cr0, eax +# endif + } +# endif +} +#endif + + +/** + * Get cr2. + * @returns cr2. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR2(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR2(void) +{ + RTCCUINTXREG uCR2; +# if RT_INLINE_ASM_USES_INTRIN + uCR2 = __readcr2(); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr2, %0\t\n" : "=r" (uCR2)); +# else + __asm__ __volatile__("movl %%cr2, %0\t\n" : "=r" (uCR2)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr2 + mov [uCR2], rax +# else + mov eax, cr2 + mov [uCR2], eax +# endif + } +# endif + return uCR2; +} +#endif + + +/** + * Sets the CR2 register. + * @param uCR2 The new CR0 value. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR2(RTCCUINTXREG uCR2); +#else +DECLINLINE(void) ASMSetCR2(RTCCUINTXREG uCR2) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%cr2\n\t" :: "r" (uCR2)); +# else + __asm__ __volatile__("movl %0, %%cr2\n\t" :: "r" (uCR2)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uCR2] + mov cr2, rax +# else + mov eax, [uCR2] + mov cr2, eax +# endif + } +# endif +} +#endif + + +/** + * Get cr3. + * @returns cr3. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR3(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR3(void) +{ + RTCCUINTXREG uCR3; +# if RT_INLINE_ASM_USES_INTRIN + uCR3 = __readcr3(); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr3, %0\t\n" : "=r" (uCR3)); +# else + __asm__ __volatile__("movl %%cr3, %0\t\n" : "=r" (uCR3)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr3 + mov [uCR3], rax +# else + mov eax, cr3 + mov [uCR3], eax +# endif + } +# endif + return uCR3; +} +#endif + + +/** + * Sets the CR3 register. + * + * @param uCR3 New CR3 value. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR3(RTCCUINTXREG uCR3); +#else +DECLINLINE(void) ASMSetCR3(RTCCUINTXREG uCR3) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writecr3(uCR3); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%cr3\n\t" : : "r" (uCR3)); +# else + __asm__ __volatile__("movl %0, %%cr3\n\t" : : "r" (uCR3)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uCR3] + mov cr3, rax +# else + mov eax, [uCR3] + mov cr3, eax +# endif + } +# endif +} +#endif + + +/** + * Reloads the CR3 register. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMReloadCR3(void); +#else +DECLINLINE(void) ASMReloadCR3(void) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writecr3(__readcr3()); + +# elif RT_INLINE_ASM_GNU_STYLE + RTCCUINTXREG u; +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr3, %0\n\t" + "movq %0, %%cr3\n\t" + : "=r" (u)); +# else + __asm__ __volatile__("movl %%cr3, %0\n\t" + "movl %0, %%cr3\n\t" + : "=r" (u)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr3 + mov cr3, rax +# else + mov eax, cr3 + mov cr3, eax +# endif + } +# endif +} +#endif + + +/** + * Get cr4. + * @returns cr4. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR4(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR4(void) +{ + RTCCUINTXREG uCR4; +# if RT_INLINE_ASM_USES_INTRIN + uCR4 = __readcr4(); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr4, %0\t\n" : "=r" (uCR4)); +# else + __asm__ __volatile__("movl %%cr4, %0\t\n" : "=r" (uCR4)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr4 + mov [uCR4], rax +# else + push eax /* just in case */ + /*mov eax, cr4*/ + _emit 0x0f + _emit 0x20 + _emit 0xe0 + mov [uCR4], eax + pop eax +# endif + } +# endif + return uCR4; +} +#endif + + +/** + * Sets the CR4 register. + * + * @param uCR4 New CR4 value. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR4(RTCCUINTXREG uCR4); +#else +DECLINLINE(void) ASMSetCR4(RTCCUINTXREG uCR4) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writecr4(uCR4); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%cr4\n\t" : : "r" (uCR4)); +# else + __asm__ __volatile__("movl %0, %%cr4\n\t" : : "r" (uCR4)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uCR4] + mov cr4, rax +# else + mov eax, [uCR4] + _emit 0x0F + _emit 0x22 + _emit 0xE0 /* mov cr4, eax */ +# endif + } +# endif +} +#endif + + +/** + * Get cr8. + * @returns cr8. + * @remark The lock prefix hack for access from non-64-bit modes is NOT used and 0 is returned. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +DECLASM(RTCCUINTXREG) ASMGetCR8(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR8(void) +{ +# ifdef RT_ARCH_AMD64 + RTCCUINTXREG uCR8; +# if RT_INLINE_ASM_USES_INTRIN + uCR8 = __readcr8(); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movq %%cr8, %0\t\n" : "=r" (uCR8)); +# else + __asm + { + mov rax, cr8 + mov [uCR8], rax + } +# endif + return uCR8; +# else /* !RT_ARCH_AMD64 */ + return 0; +# endif /* !RT_ARCH_AMD64 */ +} +#endif + + +/** + * Get XCR0 (eXtended feature Control Register 0). + * @returns xcr0. + */ +DECLASM(uint64_t) ASMGetXcr0(void); + +/** + * Sets the XCR0 register. + * @param uXcr0 The new XCR0 value. + */ +DECLASM(void) ASMSetXcr0(uint64_t uXcr0); + +struct X86XSAVEAREA; +/** + * Save extended CPU state. + * @param pXStateArea Where to save the state. + * @param fComponents Which state components to save. + */ +DECLASM(void) ASMXSave(struct X86XSAVEAREA RT_FAR *pXStateArea, uint64_t fComponents); + +/** + * Loads extended CPU state. + * @param pXStateArea Where to load the state from. + * @param fComponents Which state components to load. + */ +DECLASM(void) ASMXRstor(struct X86XSAVEAREA const RT_FAR *pXStateArea, uint64_t fComponents); + + +struct X86FXSTATE; +/** + * Save FPU and SSE CPU state. + * @param pXStateArea Where to save the state. + */ +DECLASM(void) ASMFxSave(struct X86FXSTATE RT_FAR *pXStateArea); + +/** + * Load FPU and SSE CPU state. + * @param pXStateArea Where to load the state from. + */ +DECLASM(void) ASMFxRstor(struct X86FXSTATE const RT_FAR *pXStateArea); + + +/** + * Enables interrupts (EFLAGS.IF). + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMIntEnable(void); +#else +DECLINLINE(void) ASMIntEnable(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm("sti\n"); +# elif RT_INLINE_ASM_USES_INTRIN + _enable(); +# else + __asm sti +# endif +} +#endif + + +/** + * Disables interrupts (!EFLAGS.IF). + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMIntDisable(void); +#else +DECLINLINE(void) ASMIntDisable(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm("cli\n"); +# elif RT_INLINE_ASM_USES_INTRIN + _disable(); +# else + __asm cli +# endif +} +#endif + + +/** + * Disables interrupts and returns previous xFLAGS. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMIntDisableFlags(void); +#else +DECLINLINE(RTCCUINTREG) ASMIntDisableFlags(void) +{ + RTCCUINTREG xFlags; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "cli\n\t" + "popq %0\n\t" + : "=r" (xFlags)); +# else + __asm__ __volatile__("pushfl\n\t" + "cli\n\t" + "popl %0\n\t" + : "=r" (xFlags)); +# endif +# elif RT_INLINE_ASM_USES_INTRIN && !defined(RT_ARCH_X86) + xFlags = ASMGetFlags(); + _disable(); +# else + __asm { + pushfd + cli + pop [xFlags] + } +# endif + return xFlags; +} +#endif + + +/** + * Are interrupts enabled? + * + * @returns true / false. + */ +DECLINLINE(bool) ASMIntAreEnabled(void) +{ + RTCCUINTREG uFlags = ASMGetFlags(); + return uFlags & 0x200 /* X86_EFL_IF */ ? true : false; +} + + +/** + * Halts the CPU until interrupted. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2005 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMHalt(void); +#else +DECLINLINE(void) ASMHalt(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("hlt\n\t"); +# elif RT_INLINE_ASM_USES_INTRIN + __halt(); +# else + __asm { + hlt + } +# endif +} +#endif + + +/** + * Reads a machine specific register. + * + * @returns Register content. + * @param uRegister Register to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMRdMsr(uint32_t uRegister); +#else +DECLINLINE(uint64_t) ASMRdMsr(uint32_t uRegister) +{ + RTUINT64U u; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdmsr\n\t" + : "=a" (u.s.Lo), + "=d" (u.s.Hi) + : "c" (uRegister)); + +# elif RT_INLINE_ASM_USES_INTRIN + u.u = __readmsr(uRegister); + +# else + __asm + { + mov ecx, [uRegister] + rdmsr + mov [u.s.Lo], eax + mov [u.s.Hi], edx + } +# endif + + return u.u; +} +#endif + + +/** + * Writes a machine specific register. + * + * @returns Register content. + * @param uRegister Register to write to. + * @param u64Val Value to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val); +#else +DECLINLINE(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val) +{ + RTUINT64U u; + + u.u = u64Val; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wrmsr\n\t" + ::"a" (u.s.Lo), + "d" (u.s.Hi), + "c" (uRegister)); + +# elif RT_INLINE_ASM_USES_INTRIN + __writemsr(uRegister, u.u); + +# else + __asm + { + mov ecx, [uRegister] + mov edx, [u.s.Hi] + mov eax, [u.s.Lo] + wrmsr + } +# endif +} +#endif + + +/** + * Reads a machine specific register, extended version (for AMD). + * + * @returns Register content. + * @param uRegister Register to read. + * @param uXDI RDI/EDI value. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM_386(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI); +#else +DECLINLINE(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI) +{ + RTUINT64U u; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdmsr\n\t" + : "=a" (u.s.Lo), + "=d" (u.s.Hi) + : "c" (uRegister), + "D" (uXDI)); + +# else + __asm + { + mov ecx, [uRegister] + xchg edi, [uXDI] + rdmsr + mov [u.s.Lo], eax + mov [u.s.Hi], edx + xchg edi, [uXDI] + } +# endif + + return u.u; +} +#endif + + +/** + * Writes a machine specific register, extended version (for AMD). + * + * @returns Register content. + * @param uRegister Register to write to. + * @param uXDI RDI/EDI value. + * @param u64Val Value to write. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM_386(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI, uint64_t u64Val); +#else +DECLINLINE(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI, uint64_t u64Val) +{ + RTUINT64U u; + + u.u = u64Val; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wrmsr\n\t" + ::"a" (u.s.Lo), + "d" (u.s.Hi), + "c" (uRegister), + "D" (uXDI)); + +# else + __asm + { + mov ecx, [uRegister] + xchg edi, [uXDI] + mov edx, [u.s.Hi] + mov eax, [u.s.Lo] + wrmsr + xchg edi, [uXDI] + } +# endif +} +#endif + + + +/** + * Reads low part of a machine specific register. + * + * @returns Register content. + * @param uRegister Register to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRdMsr_Low(uint32_t uRegister); +#else +DECLINLINE(uint32_t) ASMRdMsr_Low(uint32_t uRegister) +{ + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdmsr\n\t" + : "=a" (u32) + : "c" (uRegister) + : "edx"); + +# elif RT_INLINE_ASM_USES_INTRIN + u32 = (uint32_t)__readmsr(uRegister); + +#else + __asm + { + mov ecx, [uRegister] + rdmsr + mov [u32], eax + } +# endif + + return u32; +} +#endif + + +/** + * Reads high part of a machine specific register. + * + * @returns Register content. + * @param uRegister Register to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRdMsr_High(uint32_t uRegister); +#else +DECLINLINE(uint32_t) ASMRdMsr_High(uint32_t uRegister) +{ + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdmsr\n\t" + : "=d" (u32) + : "c" (uRegister) + : "eax"); + +# elif RT_INLINE_ASM_USES_INTRIN + u32 = (uint32_t)(__readmsr(uRegister) >> 32); + +# else + __asm + { + mov ecx, [uRegister] + rdmsr + mov [u32], edx + } +# endif + + return u32; +} +#endif + + +/** + * Gets dr0. + * + * @returns dr0. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR0(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR0(void) +{ + RTCCUINTXREG uDR0; +# if RT_INLINE_ASM_USES_INTRIN + uDR0 = __readdr(0); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr0, %0\n\t" : "=r" (uDR0)); +# else + __asm__ __volatile__("movl %%dr0, %0\n\t" : "=r" (uDR0)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr0 + mov [uDR0], rax +# else + mov eax, dr0 + mov [uDR0], eax +# endif + } +# endif + return uDR0; +} +#endif + + +/** + * Gets dr1. + * + * @returns dr1. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR1(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR1(void) +{ + RTCCUINTXREG uDR1; +# if RT_INLINE_ASM_USES_INTRIN + uDR1 = __readdr(1); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr1, %0\n\t" : "=r" (uDR1)); +# else + __asm__ __volatile__("movl %%dr1, %0\n\t" : "=r" (uDR1)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr1 + mov [uDR1], rax +# else + mov eax, dr1 + mov [uDR1], eax +# endif + } +# endif + return uDR1; +} +#endif + + +/** + * Gets dr2. + * + * @returns dr2. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR2(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR2(void) +{ + RTCCUINTXREG uDR2; +# if RT_INLINE_ASM_USES_INTRIN + uDR2 = __readdr(2); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr2, %0\n\t" : "=r" (uDR2)); +# else + __asm__ __volatile__("movl %%dr2, %0\n\t" : "=r" (uDR2)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr2 + mov [uDR2], rax +# else + mov eax, dr2 + mov [uDR2], eax +# endif + } +# endif + return uDR2; +} +#endif + + +/** + * Gets dr3. + * + * @returns dr3. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR3(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR3(void) +{ + RTCCUINTXREG uDR3; +# if RT_INLINE_ASM_USES_INTRIN + uDR3 = __readdr(3); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr3, %0\n\t" : "=r" (uDR3)); +# else + __asm__ __volatile__("movl %%dr3, %0\n\t" : "=r" (uDR3)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr3 + mov [uDR3], rax +# else + mov eax, dr3 + mov [uDR3], eax +# endif + } +# endif + return uDR3; +} +#endif + + +/** + * Gets dr6. + * + * @returns dr6. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR6(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR6(void) +{ + RTCCUINTXREG uDR6; +# if RT_INLINE_ASM_USES_INTRIN + uDR6 = __readdr(6); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr6, %0\n\t" : "=r" (uDR6)); +# else + __asm__ __volatile__("movl %%dr6, %0\n\t" : "=r" (uDR6)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr6 + mov [uDR6], rax +# else + mov eax, dr6 + mov [uDR6], eax +# endif + } +# endif + return uDR6; +} +#endif + + +/** + * Reads and clears DR6. + * + * @returns DR6. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetAndClearDR6(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetAndClearDR6(void) +{ + RTCCUINTXREG uDR6; +# if RT_INLINE_ASM_USES_INTRIN + uDR6 = __readdr(6); + __writedr(6, 0xffff0ff0U); /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */ +# elif RT_INLINE_ASM_GNU_STYLE + RTCCUINTXREG uNewValue = 0xffff0ff0U;/* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */ +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr6, %0\n\t" + "movq %1, %%dr6\n\t" + : "=r" (uDR6) + : "r" (uNewValue)); +# else + __asm__ __volatile__("movl %%dr6, %0\n\t" + "movl %1, %%dr6\n\t" + : "=r" (uDR6) + : "r" (uNewValue)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr6 + mov [uDR6], rax + mov rcx, rax + mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */ + mov dr6, rcx +# else + mov eax, dr6 + mov [uDR6], eax + mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 is zero. */ + mov dr6, ecx +# endif + } +# endif + return uDR6; +} +#endif + + +/** + * Gets dr7. + * + * @returns dr7. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR7(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR7(void) +{ + RTCCUINTXREG uDR7; +# if RT_INLINE_ASM_USES_INTRIN + uDR7 = __readdr(7); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr7, %0\n\t" : "=r" (uDR7)); +# else + __asm__ __volatile__("movl %%dr7, %0\n\t" : "=r" (uDR7)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr7 + mov [uDR7], rax +# else + mov eax, dr7 + mov [uDR7], eax +# endif + } +# endif + return uDR7; +} +#endif + + +/** + * Sets dr0. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR0(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR0(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(0, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr0\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr0\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr0, rax +# else + mov eax, [uDRVal] + mov dr0, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr1. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR1(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR1(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(1, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr1\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr1\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr1, rax +# else + mov eax, [uDRVal] + mov dr1, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr2. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR2(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR2(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(2, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr2\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr2\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr2, rax +# else + mov eax, [uDRVal] + mov dr2, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr3. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR3(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR3(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(3, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr3\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr3\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr3, rax +# else + mov eax, [uDRVal] + mov dr3, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr6. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR6(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR6(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(6, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr6\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr6\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr6, rax +# else + mov eax, [uDRVal] + mov dr6, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr7. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR7(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR7(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(7, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr7\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr7\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr7, rax +# else + mov eax, [uDRVal] + mov dr7, eax +# endif + } +# endif +} +#endif + + +/** + * Writes a 8-bit unsigned integer to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param u8 8-bit integer to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU8(RTIOPORT Port, uint8_t u8); +#else +DECLINLINE(void) ASMOutU8(RTIOPORT Port, uint8_t u8) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("outb %b1, %w0\n\t" + :: "Nd" (Port), + "a" (u8)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outbyte(Port, u8); + +# else + __asm + { + mov dx, [Port] + mov al, [u8] + out dx, al + } +# endif +} +#endif + + +/** + * Reads a 8-bit unsigned integer from an I/O port, ordered. + * + * @returns 8-bit integer. + * @param Port I/O port to read from. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMInU8(RTIOPORT Port); +#else +DECLINLINE(uint8_t) ASMInU8(RTIOPORT Port) +{ + uint8_t u8; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("inb %w1, %b0\n\t" + : "=a" (u8) + : "Nd" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + u8 = __inbyte(Port); + +# else + __asm + { + mov dx, [Port] + in al, dx + mov [u8], al + } +# endif + return u8; +} +#endif + + +/** + * Writes a 16-bit unsigned integer to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param u16 16-bit integer to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU16(RTIOPORT Port, uint16_t u16); +#else +DECLINLINE(void) ASMOutU16(RTIOPORT Port, uint16_t u16) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("outw %w1, %w0\n\t" + :: "Nd" (Port), + "a" (u16)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outword(Port, u16); + +# else + __asm + { + mov dx, [Port] + mov ax, [u16] + out dx, ax + } +# endif +} +#endif + + +/** + * Reads a 16-bit unsigned integer from an I/O port, ordered. + * + * @returns 16-bit integer. + * @param Port I/O port to read from. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMInU16(RTIOPORT Port); +#else +DECLINLINE(uint16_t) ASMInU16(RTIOPORT Port) +{ + uint16_t u16; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("inw %w1, %w0\n\t" + : "=a" (u16) + : "Nd" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + u16 = __inword(Port); + +# else + __asm + { + mov dx, [Port] + in ax, dx + mov [u16], ax + } +# endif + return u16; +} +#endif + + +/** + * Writes a 32-bit unsigned integer to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param u32 32-bit integer to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU32(RTIOPORT Port, uint32_t u32); +#else +DECLINLINE(void) ASMOutU32(RTIOPORT Port, uint32_t u32) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("outl %1, %w0\n\t" + :: "Nd" (Port), + "a" (u32)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outdword(Port, u32); + +# else + __asm + { + mov dx, [Port] + mov eax, [u32] + out dx, eax + } +# endif +} +#endif + + +/** + * Reads a 32-bit unsigned integer from an I/O port, ordered. + * + * @returns 32-bit integer. + * @param Port I/O port to read from. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMInU32(RTIOPORT Port); +#else +DECLINLINE(uint32_t) ASMInU32(RTIOPORT Port) +{ + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("inl %w1, %0\n\t" + : "=a" (u32) + : "Nd" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + u32 = __indword(Port); + +# else + __asm + { + mov dx, [Port] + in eax, dx + mov [u32], eax + } +# endif + return u32; +} +#endif + + +/** + * Writes a string of 8-bit unsigned integer items to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param pau8 Pointer to the string buffer. + * @param c The number of items to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU8(RTIOPORT Port, uint8_t const RT_FAR *pau8, size_t c); +#else +DECLINLINE(void) ASMOutStrU8(RTIOPORT Port, uint8_t const RT_FAR *pau8, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; outsb\n\t" + : "+S" (pau8), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outbytestring(Port, (unsigned char RT_FAR *)pau8, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau8] + xchg esi, eax + rep outsb + xchg esi, eax + } +# endif +} +#endif + + +/** + * Reads a string of 8-bit unsigned integer items from an I/O port, ordered. + * + * @param Port I/O port to read from. + * @param pau8 Pointer to the string buffer (output). + * @param c The number of items to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU8(RTIOPORT Port, uint8_t RT_FAR *pau8, size_t c); +#else +DECLINLINE(void) ASMInStrU8(RTIOPORT Port, uint8_t RT_FAR *pau8, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; insb\n\t" + : "+D" (pau8), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __inbytestring(Port, pau8, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau8] + xchg edi, eax + rep insb + xchg edi, eax + } +# endif +} +#endif + + +/** + * Writes a string of 16-bit unsigned integer items to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param pau16 Pointer to the string buffer. + * @param c The number of items to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU16(RTIOPORT Port, uint16_t const RT_FAR *pau16, size_t c); +#else +DECLINLINE(void) ASMOutStrU16(RTIOPORT Port, uint16_t const RT_FAR *pau16, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; outsw\n\t" + : "+S" (pau16), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outwordstring(Port, (unsigned short RT_FAR *)pau16, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau16] + xchg esi, eax + rep outsw + xchg esi, eax + } +# endif +} +#endif + + +/** + * Reads a string of 16-bit unsigned integer items from an I/O port, ordered. + * + * @param Port I/O port to read from. + * @param pau16 Pointer to the string buffer (output). + * @param c The number of items to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU16(RTIOPORT Port, uint16_t RT_FAR *pau16, size_t c); +#else +DECLINLINE(void) ASMInStrU16(RTIOPORT Port, uint16_t RT_FAR *pau16, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; insw\n\t" + : "+D" (pau16), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __inwordstring(Port, pau16, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau16] + xchg edi, eax + rep insw + xchg edi, eax + } +# endif +} +#endif + + +/** + * Writes a string of 32-bit unsigned integer items to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param pau32 Pointer to the string buffer. + * @param c The number of items to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU32(RTIOPORT Port, uint32_t const RT_FAR *pau32, size_t c); +#else +DECLINLINE(void) ASMOutStrU32(RTIOPORT Port, uint32_t const RT_FAR *pau32, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; outsl\n\t" + : "+S" (pau32), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outdwordstring(Port, (unsigned long RT_FAR *)pau32, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau32] + xchg esi, eax + rep outsd + xchg esi, eax + } +# endif +} +#endif + + +/** + * Reads a string of 32-bit unsigned integer items from an I/O port, ordered. + * + * @param Port I/O port to read from. + * @param pau32 Pointer to the string buffer (output). + * @param c The number of items to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU32(RTIOPORT Port, uint32_t RT_FAR *pau32, size_t c); +#else +DECLINLINE(void) ASMInStrU32(RTIOPORT Port, uint32_t RT_FAR *pau32, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; insl\n\t" + : "+D" (pau32), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __indwordstring(Port, (unsigned long RT_FAR *)pau32, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau32] + xchg edi, eax + rep insd + xchg edi, eax + } +# endif +} +#endif + + +/** + * Invalidate page. + * + * @param uPtr Address of the page to invalidate. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInvalidatePage(RTCCUINTXREG uPtr); +#else +DECLINLINE(void) ASMInvalidatePage(RTCCUINTXREG uPtr) +{ +# if RT_INLINE_ASM_USES_INTRIN + __invlpg((void RT_FAR *)uPtr); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("invlpg %0\n\t" + : : "m" (*(uint8_t RT_FAR *)(uintptr_t)uPtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uPtr] + invlpg [rax] +# else + mov eax, [uPtr] + invlpg [eax] +# endif + } +# endif +} +#endif + + +/** + * Write back the internal caches and invalidate them. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMWriteBackAndInvalidateCaches(void); +#else +DECLINLINE(void) ASMWriteBackAndInvalidateCaches(void) +{ +# if RT_INLINE_ASM_USES_INTRIN + __wbinvd(); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wbinvd"); +# else + __asm + { + wbinvd + } +# endif +} +#endif + + +/** + * Invalidate internal and (perhaps) external caches without first + * flushing dirty cache lines. Use with extreme care. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInvalidateInternalCaches(void); +#else +DECLINLINE(void) ASMInvalidateInternalCaches(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("invd"); +# else + __asm + { + invd + } +# endif +} +#endif + + +/** + * Memory load/store fence, waits for any pending writes and reads to complete. + * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set. + */ +DECLINLINE(void) ASMMemoryFenceSSE2(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xf0\n\t"); +#elif RT_INLINE_ASM_USES_INTRIN + _mm_mfence(); +#else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xf0 + } +#endif +} + + +/** + * Memory store fence, waits for any writes to complete. + * Requires the X86_CPUID_FEATURE_EDX_SSE CPUID bit set. + */ +DECLINLINE(void) ASMWriteFenceSSE(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xf8\n\t"); +#elif RT_INLINE_ASM_USES_INTRIN + _mm_sfence(); +#else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xf8 + } +#endif +} + + +/** + * Memory load fence, waits for any pending reads to complete. + * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set. + */ +DECLINLINE(void) ASMReadFenceSSE2(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xe8\n\t"); +#elif RT_INLINE_ASM_USES_INTRIN + _mm_lfence(); +#else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xe8 + } +#endif +} + +#if !defined(_MSC_VER) || !defined(RT_ARCH_AMD64) + +/* + * Clear the AC bit in the EFLAGS register. + * Requires the X86_CPUID_STEXT_FEATURE_EBX_SMAP CPUID bit set. + * Requires to be executed in R0. + */ +DECLINLINE(void) ASMClearAC(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0x01,0xca\n\t"); +#else + __asm + { + _emit 0x0f + _emit 0x01 + _emit 0xca + } +#endif +} + + +/* + * Set the AC bit in the EFLAGS register. + * Requires the X86_CPUID_STEXT_FEATURE_EBX_SMAP CPUID bit set. + * Requires to be executed in R0. + */ +DECLINLINE(void) ASMSetAC(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0x01,0xcb\n\t"); +#else + __asm + { + _emit 0x0f + _emit 0x01 + _emit 0xcb + } +#endif +} + +#endif /* !_MSC_VER || !RT_ARCH_AMD64 */ + + +/* + * Include #pragma aux definitions for Watcom C/C++. + */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 +# define IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +# undef IPRT_INCLUDED_asm_amd64_x86_watcom_16_h +# include "asm-amd64-x86-watcom-16.h" +#elif defined(__WATCOMC__) && ARCH_BITS == 32 +# define IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +# undef IPRT_INCLUDED_asm_amd64_x86_watcom_32_h +# include "asm-amd64-x86-watcom-32.h" +#endif + + +/** @} */ +#endif /* !IPRT_INCLUDED_asm_amd64_x86_h */ + diff --git a/include/iprt/asm-arm.h b/include/iprt/asm-arm.h new file mode 100644 index 00000000..b9d287fa --- /dev/null +++ b/include/iprt/asm-arm.h @@ -0,0 +1,321 @@ +/** @file + * IPRT - ARM Specific Assembly Functions. + */ + +/* + * Copyright (C) 2015-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_arm_h +#define IPRT_INCLUDED_asm_arm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#if !defined(RT_ARCH_ARM64) && !defined(RT_ARCH_ARM32) +# error "Not on ARM64 or ARM32" +#endif + +/** @defgroup grp_rt_asm_arm ARM Specific ASM Routines + * @ingroup grp_rt_asm + * @{ + */ + + +#if 0 /* figure out arm64 */ + +/** + * Get the CPSR (Current Program Status) register. + * @returns CPSR. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(RTCCUINTREG) ASMGetFlags(void); +#else +DECLINLINE(RTCCUINTREG) ASMGetFlags(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_ARM64 + __asm__ __volatile__("mrs %0, nzcv\n\t" : "=r" (uFlags)); +# else + __asm__ __volatile__("mrs %0, cpsr\n\t" : "=r" (uFlags)); +# endif +# else +# error "Unsupported compiler" +# endif + return uFlags; +} +#endif + + +/** + * Set the CPSR register. + * @param uFlags The new CPSR value. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMSetFlags(RTCCUINTREG uFlags); +#else +DECLINLINE(void) ASMSetFlags(RTCCUINTREG uFlags) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("msr cpsr_c, %0\n\t" + : : "r" (uFlags)); +# else +# error "Unsupported compiler" +# endif +} +#endif + +#endif + + +/** + * Gets the content of the CNTVCT_EL0 (or CNTPCT) register. + * + * @returns CNTVCT_EL0 value. + * @note We call this TSC to better fit in with existing x86/amd64 based code. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(uint64_t) ASMReadTSC(void); +#else +DECLINLINE(uint64_t) ASMReadTSC(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + uint64_t u64; +# ifdef RT_ARCH_ARM64 + __asm__ __volatile__("isb\n\t" + "mrs %0, CNTVCT_EL0\n\t" + : "=r" (u64)); +# else + uint32_t u32Spill; + uint32_t u32Comp; + __asm__ __volatile__("isb\n" + "Lagain:\n\t" + "mrrc p15, 0, %[uSpill], %H[uRet], c14\n\t" /* CNTPCT high into uRet.hi */ + "mrrc p15, 0, %[uRet], %[uSpill], c14\n\t" /* CNTPCT low into uRet.lo */ + "mrrc p15, 0, %[uSpill], %[uHiComp], c14\n\t" /* CNTPCT high into uHiComp */ + "cmp %H[uRet], %[uHiComp]\n\t" + "b.eq Lagain\n\t" /* Redo if high value changed. */ + : [uRet] "=r" (u64) + , "=r" (uHiComp) + , "=r" (uSpill)); +# endif + return u64; + +# else +# error "Unsupported compiler" +# endif +} +#endif + +#if 0 /* port to arm64, armv7 and check */ + +/** + * Enables interrupts (IRQ and FIQ). + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMIntEnable(void); +#else +DECLINLINE(void) ASMIntEnable(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("mrs %0, cpsr\n\t" + "bic %0, %0, #0xc0\n\t" + "msr cpsr_c, %0\n\t" + : "=r" (uFlags)); +# else +# error "Unsupported compiler" +# endif +} +#endif + + +/** + * Disables interrupts (IRQ and FIQ). + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMIntDisable(void); +#else +DECLINLINE(void) ASMIntDisable(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("mrs %0, cpsr\n\t" + "orr %0, %0, #0xc0\n\t" + "msr cpsr_c, %0\n\t" + : "=r" (uFlags)); +# else +# error "Unsupported compiler" +# endif +} +#endif + + +/** + * Disables interrupts and returns previous uFLAGS. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(RTCCUINTREG) ASMIntDisableFlags(void); +#else +DECLINLINE(RTCCUINTREG) ASMIntDisableFlags(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uNewFlags; + __asm__ __volatile__("mrs %0, cpsr\n\t" + "orr %1, %0, #0xc0\n\t" + "msr cpsr_c, %1\n\t" + : "=r" (uFlags) + , "=r" (uNewFlags)); +# else +# error "Unsupported compiler" +# endif + return uFlags; +} +#endif + + +/** + * Are interrupts enabled? + * + * @returns true / false. + */ +DECLINLINE(bool) ASMIntAreEnabled(void) +{ +/** @todo r=bird: reversed, but does both need to be enabled? */ + return ASMGetFlags() & 0xc0 /* IRQ and FIQ bits */ ? true : false; +} + +#endif + +/** + * Halts the CPU until interrupted. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMHalt(void); +#else +DECLINLINE(void) ASMHalt(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ("wfi\n\t"); /* wait for interrupt */ +# else +# error "Unsupported compiler" +# endif +} +#endif + +#if 0 +/** + * Gets the CPU ID of the current CPU. + * + * @returns the CPU ID. + * @note the name of this method is a bit misleading but serves the purpose + * and prevents #ifdef orgies in other places. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(uint8_t) ASMGetApicId(void); +#else +DECLINLINE(uint8_t) ASMGetApicId(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uCpuId; + __asm__ ("mrc p15, 0, %0, c0, c0, 5\n\t" /* CPU ID Register, privileged */ + : "=r" (uCpuId)); + return uCpuId; +# else +# error "Unsupported compiler" +# endif +} +#endif +#endif + +#if 0 + +/** + * Invalidate page. + * + * @param pv Address of the page to invalidate. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMInvalidatePage(void *pv); +#else +DECLINLINE(void) ASMInvalidatePage(void *pv) +{ +# if RT_INLINE_ASM_GNU_STYLE + +# else +# error "Unsupported compiler" +# endif +} +#endif + + +/** + * Write back the internal caches and invalidate them. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMWriteBackAndInvalidateCaches(void); +#else +DECLINLINE(void) ASMWriteBackAndInvalidateCaches(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + +# else +# error "Unsupported compiler" +# endif +} +#endif + + +/** + * Invalidate internal and (perhaps) external caches without first + * flushing dirty cache lines. Use with extreme care. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMInvalidateInternalCaches(void); +#else +DECLINLINE(void) ASMInvalidateInternalCaches(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + +# else +# error "Unsupported compiler" +# endif +} +#endif + +#endif + + +/** @} */ +#endif /* !IPRT_INCLUDED_asm_arm_h */ + diff --git a/include/iprt/asm-math.h b/include/iprt/asm-math.h new file mode 100644 index 00000000..d379111c --- /dev/null +++ b/include/iprt/asm-math.h @@ -0,0 +1,445 @@ +/** @file + * IPRT - Assembly Routines for Optimizing some Integers Math Operations. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_math_h +#define IPRT_INCLUDED_asm_math_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN +/* Emit the intrinsics at all optimization levels. */ +# include +# pragma intrinsic(__emul) +# pragma intrinsic(__emulu) +# ifdef RT_ARCH_AMD64 +# pragma intrinsic(_mul128) +# pragma intrinsic(_umul128) +# endif +#endif + + +/** @defgroup grp_rt_asm_math Interger Math Optimizations + * @ingroup grp_rt_asm + * @{ */ + +/** + * Multiplies two unsigned 32-bit values returning an unsigned 64-bit result. + * + * @returns u32F1 * u32F2. + */ + +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_X86) +DECLASM(uint64_t) ASMMult2xU32RetU64(uint32_t u32F1, uint32_t u32F2); +#else +DECLINLINE(uint64_t) ASMMult2xU32RetU64(uint32_t u32F1, uint32_t u32F2) +{ +# ifdef RT_ARCH_X86 + uint64_t u64; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("mull %%edx" + : "=A" (u64) + : "a" (u32F2), "d" (u32F1)); +# elif RT_INLINE_ASM_USES_INTRIN + u64 = __emulu(u32F1, u32F2); +# else + __asm + { + mov edx, [u32F1] + mov eax, [u32F2] + mul edx + mov dword ptr [u64], eax + mov dword ptr [u64 + 4], edx + } +# endif + return u64; +# else /* generic: */ + return (uint64_t)u32F1 * u32F2; +# endif +} +#endif + + +/** + * Multiplies two signed 32-bit values returning a signed 64-bit result. + * + * @returns u32F1 * u32F2. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_X86) +DECLASM(int64_t) ASMMult2xS32RetS64(int32_t i32F1, int32_t i32F2); +#else +DECLINLINE(int64_t) ASMMult2xS32RetS64(int32_t i32F1, int32_t i32F2) +{ +# ifdef RT_ARCH_X86 + int64_t i64; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("imull %%edx" + : "=A" (i64) + : "a" (i32F2), "d" (i32F1)); +# elif RT_INLINE_ASM_USES_INTRIN + i64 = __emul(i32F1, i32F2); +# else + __asm + { + mov edx, [i32F1] + mov eax, [i32F2] + imul edx + mov dword ptr [i64], eax + mov dword ptr [i64 + 4], edx + } +# endif + return i64; +# else /* generic: */ + return (int64_t)i32F1 * i32F2; +# endif +} +#endif + + +DECLINLINE(uint64_t) ASMMult2xU64Ret2xU64(uint64_t u64F1, uint64_t u64F2, uint64_t *pu64ProdHi) +{ +#if defined(RT_ARCH_AMD64) && (RT_INLINE_ASM_GNU_STYLE || RT_INLINE_ASM_USES_INTRIN) +# if RT_INLINE_ASM_GNU_STYLE + uint64_t u64Low, u64High; + __asm__ __volatile__("mulq %%rdx" + : "=a" (u64Low), "=d" (u64High) + : "0" (u64F1), "1" (u64F2)); + *pu64ProdHi = u64High; + return u64Low; +# elif RT_INLINE_ASM_USES_INTRIN + return _umul128(u64F1, u64F2, pu64ProdHi); +# else +# error "hmm" +# endif +#else /* generic: */ + /* + * F1 * F2 = Prod + * -- -- + * ab * cd = b*d + a*d*10 + b*c*10 + a*c*100 + * + * Where a, b, c and d are 'digits', and 10 is max digit + 1. + * + * Our digits are 32-bit wide, so instead of 10 we multiply by 4G. + * Prod = F1.s.Lo*F2.s.Lo + F1.s.Hi*F2.s.Lo*4G + * + F1.s.Lo*F2.s.Hi*4G + F1.s.Hi*F2.s.Hi*4G*4G + */ + RTUINT128U Prod; + RTUINT64U Tmp1; + uint64_t u64Tmp; + RTUINT64U F1, F2; + F1.u = u64F1; + F2.u = u64F2; + + Prod.s.Lo = ASMMult2xU32RetU64(F1.s.Lo, F2.s.Lo); + + Tmp1.u = ASMMult2xU32RetU64(F1.s.Hi, F2.s.Lo); + u64Tmp = (uint64_t)Prod.DWords.dw1 + Tmp1.s.Lo; + Prod.DWords.dw1 = (uint32_t)u64Tmp; + Prod.s.Hi = Tmp1.s.Hi; + Prod.s.Hi += u64Tmp >> 32; /* carry */ + + Tmp1.u = ASMMult2xU32RetU64(F1.s.Lo, F2.s.Hi); + u64Tmp = (uint64_t)Prod.DWords.dw1 + Tmp1.s.Lo; + Prod.DWords.dw1 = (uint32_t)u64Tmp; + u64Tmp >>= 32; /* carry */ + u64Tmp += Prod.DWords.dw2; + u64Tmp += Tmp1.s.Hi; + Prod.DWords.dw2 = (uint32_t)u64Tmp; + Prod.DWords.dw3 += u64Tmp >> 32; /* carry */ + + Prod.s.Hi += ASMMult2xU32RetU64(F1.s.Hi, F2.s.Hi); + *pu64ProdHi = Prod.s.Hi; + return Prod.s.Lo; +#endif +} + + + +/** + * Divides a 64-bit unsigned by a 32-bit unsigned returning an unsigned 32-bit result. + * + * @returns u64 / u32. + */ +#if RT_INLINE_ASM_EXTERNAL && defined(RT_ARCH_X86) +DECLASM(uint32_t) ASMDivU64ByU32RetU32(uint64_t u64, uint32_t u32); +#else +DECLINLINE(uint32_t) ASMDivU64ByU32RetU32(uint64_t u64, uint32_t u32) +{ +# ifdef RT_ARCH_X86 +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uDummy; + __asm__ __volatile__("divl %3" + : "=a" (u32), "=d"(uDummy) + : "A" (u64), "r" (u32)); +# else + __asm + { + mov eax, dword ptr [u64] + mov edx, dword ptr [u64 + 4] + mov ecx, [u32] + div ecx + mov [u32], eax + } +# endif + return u32; +# else /* generic: */ + return (uint32_t)(u64 / u32); +# endif +} +#endif + + +/** + * Divides a 64-bit signed by a 32-bit signed returning a signed 32-bit result. + * + * @returns u64 / u32. + */ +#if RT_INLINE_ASM_EXTERNAL && defined(RT_ARCH_X86) +DECLASM(int32_t) ASMDivS64ByS32RetS32(int64_t i64, int32_t i32); +#else +DECLINLINE(int32_t) ASMDivS64ByS32RetS32(int64_t i64, int32_t i32) +{ +# ifdef RT_ARCH_X86 +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG iDummy; + __asm__ __volatile__("idivl %3" + : "=a" (i32), "=d"(iDummy) + : "A" (i64), "r" (i32)); +# else + __asm + { + mov eax, dword ptr [i64] + mov edx, dword ptr [i64 + 4] + mov ecx, [i32] + idiv ecx + mov [i32], eax + } +# endif + return i32; +# else /* generic: */ + return (int32_t)(i64 / i32); +# endif +} +#endif + + +/** + * Performs 64-bit unsigned by a 32-bit unsigned division with a 32-bit unsigned result, + * returning the rest. + * + * @returns u64 % u32. + * + * @remarks It is important that the result is <= UINT32_MAX or we'll overflow and crash. + */ +#if RT_INLINE_ASM_EXTERNAL && defined(RT_ARCH_X86) +DECLASM(uint32_t) ASMModU64ByU32RetU32(uint64_t u64, uint32_t u32); +#else +DECLINLINE(uint32_t) ASMModU64ByU32RetU32(uint64_t u64, uint32_t u32) +{ +# ifdef RT_ARCH_X86 +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uDummy; + __asm__ __volatile__("divl %3" + : "=a" (uDummy), "=d"(u32) + : "A" (u64), "r" (u32)); +# else + __asm + { + mov eax, dword ptr [u64] + mov edx, dword ptr [u64 + 4] + mov ecx, [u32] + div ecx + mov [u32], edx + } +# endif + return u32; +# else /* generic: */ + return (uint32_t)(u64 % u32); +# endif +} +#endif + + +/** + * Performs 64-bit signed by a 32-bit signed division with a 32-bit signed result, + * returning the rest. + * + * @returns u64 % u32. + * + * @remarks It is important that the result is <= UINT32_MAX or we'll overflow and crash. + */ +#if RT_INLINE_ASM_EXTERNAL && defined(RT_ARCH_X86) +DECLASM(int32_t) ASMModS64ByS32RetS32(int64_t i64, int32_t i32); +#else +DECLINLINE(int32_t) ASMModS64ByS32RetS32(int64_t i64, int32_t i32) +{ +# ifdef RT_ARCH_X86 +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG iDummy; + __asm__ __volatile__("idivl %3" + : "=a" (iDummy), "=d"(i32) + : "A" (i64), "r" (i32)); +# else + __asm + { + mov eax, dword ptr [i64] + mov edx, dword ptr [i64 + 4] + mov ecx, [i32] + idiv ecx + mov [i32], edx + } +# endif + return i32; +# else /* generic: */ + return (int32_t)(i64 % i32); +# endif +} +#endif + + +/** + * Multiple a 32-bit by a 32-bit integer and divide the result by a 32-bit integer + * using a 64 bit intermediate result. + * + * @returns (u32A * u32B) / u32C. + * @param u32A The 32-bit value (A). + * @param u32B The 32-bit value to multiple by A. + * @param u32C The 32-bit value to divide A*B by. + * + * @remarks Architecture specific. + * @remarks Make sure the result won't ever exceed 32-bit, because hardware + * exception may be raised if it does. + * @remarks On x86 this may be used to avoid dragging in 64-bit builtin + * arithmetics functions. + */ +#if RT_INLINE_ASM_EXTERNAL && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) +DECLASM(uint32_t) ASMMultU32ByU32DivByU32(uint32_t u32A, uint32_t u32B, uint32_t u32C); +#else +DECLINLINE(uint32_t) ASMMultU32ByU32DivByU32(uint32_t u32A, uint32_t u32B, uint32_t u32C) +{ +# if RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) + uint32_t u32Result, u32Spill; + __asm__ __volatile__("mull %2\n\t" + "divl %3\n\t" + : "=&a" (u32Result), + "=&d" (u32Spill) + : "r" (u32B), + "r" (u32C), + "0" (u32A)); + return u32Result; +# else + return (uint32_t)(((uint64_t)u32A * u32B) / u32C); +# endif +} +#endif + + +/** + * Multiple a 64-bit by a 32-bit integer and divide the result by a 32-bit integer + * using a 96 bit intermediate result. + * + * @returns (u64A * u32B) / u32C. + * @param u64A The 64-bit value. + * @param u32B The 32-bit value to multiple by A. + * @param u32C The 32-bit value to divide A*B by. + * + * @remarks Architecture specific. + * @remarks Make sure the result won't ever exceed 64-bit, because hardware + * exception may be raised if it does. + * @remarks On x86 this may be used to avoid dragging in 64-bit builtin + * arithmetics function. + */ +#if RT_INLINE_ASM_EXTERNAL || !defined(__GNUC__) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(uint64_t) ASMMultU64ByU32DivByU32(uint64_t u64A, uint32_t u32B, uint32_t u32C); +#else +DECLINLINE(uint64_t) ASMMultU64ByU32DivByU32(uint64_t u64A, uint32_t u32B, uint32_t u32C) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + uint64_t u64Result, u64Spill; + __asm__ __volatile__("mulq %2\n\t" + "divq %3\n\t" + : "=&a" (u64Result), + "=&d" (u64Spill) + : "r" ((uint64_t)u32B), + "r" ((uint64_t)u32C), + "0" (u64A)); + return u64Result; +# else + uint32_t u32Dummy; + uint64_t u64Result; + __asm__ __volatile__("mull %%ecx \n\t" /* eax = u64Lo.lo = (u64A.lo * u32B).lo + edx = u64Lo.hi = (u64A.lo * u32B).hi */ + "xchg %%eax,%%esi \n\t" /* esi = u64Lo.lo + eax = u64A.hi */ + "xchg %%edx,%%edi \n\t" /* edi = u64Low.hi + edx = u32C */ + "xchg %%edx,%%ecx \n\t" /* ecx = u32C + edx = u32B */ + "mull %%edx \n\t" /* eax = u64Hi.lo = (u64A.hi * u32B).lo + edx = u64Hi.hi = (u64A.hi * u32B).hi */ + "addl %%edi,%%eax \n\t" /* u64Hi.lo += u64Lo.hi */ + "adcl $0,%%edx \n\t" /* u64Hi.hi += carry */ + "divl %%ecx \n\t" /* eax = u64Hi / u32C + edx = u64Hi % u32C */ + "movl %%eax,%%edi \n\t" /* edi = u64Result.hi = u64Hi / u32C */ + "movl %%esi,%%eax \n\t" /* eax = u64Lo.lo */ + "divl %%ecx \n\t" /* u64Result.lo */ + "movl %%edi,%%edx \n\t" /* u64Result.hi */ + : "=A"(u64Result), "=c"(u32Dummy), + "=S"(u32Dummy), "=D"(u32Dummy) + : "a"((uint32_t)u64A), + "S"((uint32_t)(u64A >> 32)), + "c"(u32B), + "D"(u32C)); + return u64Result; +# endif +# else + RTUINT64U u; + uint64_t u64Lo = (uint64_t)(u64A & 0xffffffff) * u32B; + uint64_t u64Hi = (uint64_t)(u64A >> 32) * u32B; + u64Hi += (u64Lo >> 32); + u.s.Hi = (uint32_t)(u64Hi / u32C); + u.s.Lo = (uint32_t)((((u64Hi % u32C) << 32) + (u64Lo & 0xffffffff)) / u32C); + return u.u; +# endif +} +#endif + +/** @} */ +#endif /* !IPRT_INCLUDED_asm_math_h */ + diff --git a/include/iprt/asm-watcom-x86-16.h b/include/iprt/asm-watcom-x86-16.h new file mode 100644 index 00000000..db8d4e69 --- /dev/null +++ b/include/iprt/asm-watcom-x86-16.h @@ -0,0 +1,983 @@ +/** @file + * IPRT - Assembly Functions, x86 16-bit Watcom C/C++ pragma aux. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_watcom_x86_16_h +#define IPRT_INCLUDED_asm_watcom_x86_16_h +/* no pragma once */ + +#ifndef IPRT_INCLUDED_asm_h +# error "Don't include this header directly." +#endif + +/* + * Turns out we cannot use 'ds' for segment stuff here because the compiler + * seems to insists on loading the DGROUP segment into 'ds' before calling + * stuff when using -ecc. Using 'es' instead as this seems to work fine. + * + * Note! The #undef that preceds the #pragma aux statements is for undoing + * the mangling, because the symbol in #pragma aux [symbol] statements + * doesn't get subjected to preprocessing. This is also why we include + * the watcom header at both the top and the bottom of asm.h file. + */ + +#undef ASMCompilerBarrier +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if 0 /* overkill version. */ +# pragma aux ASMCompilerBarrier = \ + "nop" \ + parm [] \ + modify exact [ax bx cx dx es ds]; +# else +# pragma aux ASMCompilerBarrier = \ + "" \ + parm [] \ + modify exact []; +# endif +#endif + +#undef ASMNopPause +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMNopPause = \ + ".686p" \ + ".xmm2" \ + "pause" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMAtomicXchgU8 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU8 = \ + "xchg es:[bx], al" \ + parm [es bx] [al] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMAtomicXchgU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU16 = \ + "xchg es:[bx], ax" \ + parm [es bx] [ax] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicXchgU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU32 = \ + ".386" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "xchg es:[bx], ecx" \ + "mov eax, ecx" \ + "shr ecx, 16" \ + parm [es bx] [ax cx] \ + value [ax cx] \ + modify exact [ax cx]; +#endif + +#undef ASMAtomicXchgU64 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU64 = \ + ".586" \ + "shl eax, 16" \ + "mov ax, bx" /* eax = high dword */ \ + "shl ecx, 16" \ + "mov cx, dx" /* ecx = low dword */ \ + "mov ebx, ecx" /* ebx = low */ \ + "mov ecx, eax" /* ecx = high */ \ + "try_again:" \ + "lock cmpxchg8b es:[si]" \ + "jnz try_again" \ + "xchg eax, edx" \ + "mov ebx, eax" \ + "shr eax, 16" \ + "mov ecx, edx" \ + "shr ecx, 16" \ + parm [es si] [dx cx bx ax] \ + value [dx cx bx ax] \ + modify exact [dx cx bx ax]; +#endif + +#undef ASMAtomicCmpXchgU8 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU8 = \ + ".486" \ + "lock cmpxchg es:[bx], cl" \ + "setz al" \ + parm [es bx] [cl] [al] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMAtomicCmpXchgU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU16 = \ + ".486" \ + "lock cmpxchg es:[bx], cx" \ + "setz al" \ + parm [es bx] [cx] [ax] \ + value [al] \ + modify exact [ax]; +#endif + +#undef ASMAtomicCmpXchgU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU32 = \ + ".486" \ + "shl ecx, 16" \ + "mov cx, dx" \ + "shl eax, 16" \ + "mov ax, di" \ + "rol eax, 16" \ + "lock cmpxchg es:[bx], ecx" \ + "setz al" \ + parm [es bx] [cx dx] [ax di] \ + value [al] \ + modify exact [ax cx]; +#endif + +/* ASMAtomicCmpXchgU64: External assembly implementation, too few registers for parameters. */ +/* ASMAtomicCmpXchgExU32: External assembly implementation, too few registers for parameters. */ +/* ASMAtomicCmpXchgExU64: External assembly implementation, too few registers for parameters. */ + +#undef ASMSerializeInstructionCpuId +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionCpuId = \ + ".586" \ + "xor eax, eax" \ + "cpuid" \ + parm [] \ + modify exact [ax bx cx dx]; +#endif + +#undef ASMSerializeInstructionIRet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionIRet = \ + "pushf" \ + "push cs" \ + "call foo" /* 'push offset done' doesn't work */ \ + "jmp done" \ + "foo:" \ + "iret" \ + "done:" \ + parm [] \ + modify exact []; +#endif + +#undef ASMSerializeInstructionRdTscp +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionRdTscp = \ + 0x0f 0x01 0xf9 \ + parm [] \ + modify exact [ax dx cx]; +#endif + +#undef ASMAtomicReadU64 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicReadU64 = \ + ".586" \ + "xor eax, eax" \ + "xor edx, edx" \ + "xor ebx, ebx" \ + "xor ecx, ecx" \ + "lock cmpxchg8b es:[si]" \ + "xchg eax, edx" \ + "mov ebx, eax" \ + "shr eax, 16" \ + "mov ecx, edx" \ + "shr ecx, 16" \ + parm [es si] \ + value [dx cx bx ax] \ + modify exact [dx cx bx ax]; +#endif + +#undef ASMAtomicUoReadU64 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoReadU64 = \ + ".586" \ + "xor eax, eax" \ + "xor edx, edx" \ + "xor ebx, ebx" \ + "xor ecx, ecx" \ + "lock cmpxchg8b es:[si]" \ + "xchg eax, edx" \ + "mov ebx, eax" \ + "shr eax, 16" \ + "mov ecx, edx" \ + "shr ecx, 16" \ + parm [es si] \ + value [dx cx bx ax] \ + modify exact [dx cx bx ax]; +#endif + +#undef ASMAtomicAddU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicAddU16 = \ + ".486" \ + "lock xadd es:[bx], ax" \ + parm [es bx] [ax] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicAddU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicAddU32 = \ + ".486" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock xadd es:[bx], edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] [ax dx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +#undef ASMAtomicIncU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicIncU16 = \ + ".486" \ + "mov ax, 1" \ + "lock xadd es:[bx], ax" \ + "inc ax" \ + parm [es bx] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicIncU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicIncU32 = \ + ".486" \ + "mov edx, 1" \ + "lock xadd es:[bx], edx" \ + "inc edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +/* ASMAtomicIncU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicDecU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicDecU16 = \ + ".486" \ + "mov ax, 0ffffh" \ + "lock xadd es:[bx], ax" \ + "dec ax" \ + parm [es bx] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicDecU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicDecU32 = \ + ".486" \ + "mov edx, 0ffffffffh" \ + "lock xadd es:[bx], edx" \ + "dec edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +/* ASMAtomicDecU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicOrU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicOrU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock or es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +/* ASMAtomicOrU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicAndU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicAndU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock and es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +/* ASMAtomicAndU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoOrU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoOrU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "or es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +/* ASMAtomicUoOrU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoAndU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoAndU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "and es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +/* ASMAtomicUoAndU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoIncU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoIncU32 = \ + ".486" \ + "mov edx, 1" \ + "xadd es:[bx], edx" \ + "inc edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +#undef ASMAtomicUoDecU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoDecU32 = \ + ".486" \ + "mov edx, 0ffffffffh" \ + "xadd es:[bx], edx" \ + "dec edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +#undef ASMMemZeroPage +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMMemZeroPage = \ + "mov cx, 2048" \ + "xor ax, ax" \ + "rep stosw" \ + parm [es di] \ + modify exact [ax cx di]; +# else +# pragma aux ASMMemZeroPage = \ + "mov ecx, 1024" \ + "xor eax, eax" \ + "rep stosd" \ + parm [es di] \ + modify exact [ax cx di]; +# endif +#endif + +#undef ASMMemZero32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMMemZero32 = \ + "xor ax, ax" \ + "shr cx, 1" \ + "shr cx, 1" \ + "rep stosw" \ + parm [es di] [cx] \ + modify exact [ax dx cx di]; +# else +# pragma aux ASMMemZero32 = \ + "and ecx, 0ffffh" /* probably not necessary, lazy bird should check... */ \ + "shr ecx, 2" \ + "xor eax, eax" \ + "rep stosd" \ + parm [es di] [cx] \ + modify exact [ax cx di]; +# endif +#endif + +#undef ASMMemFill32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMMemFill32 = \ + " shr cx, 1" \ + " shr cx, 1" \ + " jz done" \ + "again:" \ + " stosw" \ + " xchg ax, dx" \ + " stosw" \ + " xchg ax, dx" \ + " dec cx" \ + " jnz again" \ + "done:" \ + parm [es di] [cx] [ax dx]\ + modify exact [cx di]; +# else +# pragma aux ASMMemFill32 = \ + "and ecx, 0ffffh" /* probably not necessary, lazy bird should check... */ \ + "shr ecx, 2" \ + "shl eax, 16" \ + "mov ax, dx" \ + "rol eax, 16" \ + "rep stosd" \ + parm [es di] [cx] [ax dx]\ + modify exact [ax cx di]; +# endif +#endif + +#undef ASMProbeReadByte +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMProbeReadByte = \ + "mov al, es:[bx]" \ + parm [es bx] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMBitSet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitSet = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" \ + " mov al, 1" \ + " shl al, cl" /* al=bitmask */ \ + " or es:[bx], al" \ + parm [es bx] [ax cx] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitSet = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bts es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +# endif +#endif + +#undef ASMAtomicBitSet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitSet = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock bts es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +#undef ASMBitClear +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitClear = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" \ + " mov al, 1" \ + " shl al, cl" \ + " not al" /* al=bitmask */ \ + " and es:[bx], al" \ + parm [es bx] [ax cx] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitClear = \ + "shl edx, 16" \ + "mov dx, ax" \ + "btr es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +# endif +#endif + +#undef ASMAtomicBitClear +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitClear = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock btr es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +#undef ASMBitToggle +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitToggle = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" \ + " mov al, 1" \ + " shl al, cl" /* al=bitmask */ \ + " xor es:[bx], al" \ + parm [es bx] [ax cx] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitToggle = \ + "shl edx, 16" \ + "mov dx, ax" \ + "btc es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +# endif +#endif + +#undef ASMAtomicBitToggle +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitToggle = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock btc es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +#undef ASMBitTestAndSet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitTestAndSet = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" /* cl=byte shift count */ \ + " mov ah, 1" \ + " shl ah, cl" /* ah=bitmask */ \ + " mov al, es:[bx]" \ + " or ah, al" \ + " mov es:[bx], ah" \ + " shr al, cl" \ + " and al, 1" \ + parm [es bx] [ax cx] \ + value [al] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitTestAndSet = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bts es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +# endif +#endif + +#undef ASMAtomicBitTestAndSet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndSet = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock bts es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +#endif + +#undef ASMBitTestAndClear +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitTestAndClear = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" /* cl=byte shift count */ \ + " mov ah, 1" \ + " shl ah, cl" \ + " not ah" /* ah=bitmask */ \ + " mov al, es:[bx]" \ + " and ah, al" \ + " mov es:[bx], ah" \ + " shr al, cl" \ + " and al, 1" \ + parm [es bx] [ax cx] \ + value [al] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitTestAndClear = \ + "shl edx, 16" \ + "mov dx, ax" \ + "btr es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +# endif +#endif + +#undef ASMAtomicBitTestAndClear +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndClear = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock btr es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +#endif + +#undef ASMBitTestAndToggle +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitTestAndToggle = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" /* cl=byte shift count */ \ + " mov ah, 1" \ + " shl ah, cl" /* ah=bitmask */ \ + " mov al, es:[bx]" \ + " xor ah, al" \ + " mov es:[bx], ah" \ + " shr al, cl" \ + " and al, 1" \ + parm [es bx] [ax cx] \ + value [al] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitTestAndToggle = \ + "shl edx, 16" \ + "mov dx, ax" \ + "btc es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +# endif +#endif + +#undef ASMAtomicBitTestAndToggle +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndToggle = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock btc es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +#endif + +#undef ASMBitTest +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitTest = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" \ + " mov al, es:[bx]" \ + " shr al, cl" \ + " and al, 1" \ + parm [es bx] [ax cx] \ + value [al] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitTest = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bt es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] nomemory \ + value [al] \ + modify exact [ax dx] nomemory; +# endif +#endif + +/* ASMBitFirstClear: External file. */ +/* ASMBitNextClear: External file. */ +/* ASMBitFirstSet: External file. */ +/* ASMBitNextSet: External file. */ + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitFirstSetU32: External file. */ +#else +# undef ASMBitFirstSetU32 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitFirstSetU32 = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bsf eax, edx" \ + "jz not_found" \ + "inc ax" \ + "jmp done" \ + "not_found:" \ + "xor ax, ax" \ + "done:" \ + parm [ax dx] nomemory \ + value [ax] \ + modify exact [ax dx] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitFirstSetU64: External file. */ +#else +# undef ASMBitFirstSetU64 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitFirstSetU64 = \ + ".386" \ + "shl ecx, 16" \ + "mov cx, dx" \ + "bsf ecx, ecx" \ + "jz not_found_low" \ + "mov ax, cx" \ + "inc ax" \ + "jmp done" \ + \ + "not_found_low:" \ + "shr eax, 16" \ + "mov ax, bx" \ + "bsf eax, eax" \ + "jz not_found_high" \ + "add ax, 33" \ + "jmp done" \ + \ + "not_found_high:" \ + "xor ax, ax" \ + "done:" \ + parm [dx cx bx ax] nomemory \ + value [ax] \ + modify exact [ax cx] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitFirstSetU16: External file. */ +#else +# undef ASMBitFirstSetU16 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitFirstSetU16 = \ + "bsf ax, ax" \ + "jz not_found" \ + "inc ax" \ + "jmp done" \ + "not_found:" \ + "xor ax, ax" \ + "done:" \ + parm [ax] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitLastSetU32: External file. */ +#else +# undef ASMBitLastSetU32 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitLastSetU32 = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bsr eax, edx" \ + "jz not_found" \ + "inc ax" \ + "jmp done" \ + "not_found:" \ + "xor ax, ax" \ + "done:" \ + parm [ax dx] nomemory \ + value [ax] \ + modify exact [ax dx] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitLastSetU64: External file. */ +#else +# undef ASMBitLastSetU64 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitLastSetU64 = \ + ".386" \ + "shl ecx, 16" \ + "mov cx, dx" \ + "bsf ecx, ecx" \ + "jz not_found_low" \ + "mov ax, cx" \ + "inc ax" \ + "jmp done" \ + \ + "not_found_low:" \ + "shr eax, 16" \ + "mov ax, bx" \ + "bsf eax, eax" \ + "jz not_found_high" \ + "add ax, 33" \ + "jmp done" \ + \ + "not_found_high:" \ + "xor ax, ax" \ + "done:" \ + parm [dx cx bx ax] nomemory \ + value [ax] \ + modify exact [ax cx] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitLastSetU16: External file. */ +#else +# undef ASMBitLastSetU16 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitLastSetU16 = \ + "bsr ax, ax" \ + "jz not_found" \ + "inc ax" \ + "jmp done" \ + "not_found:" \ + "xor ax, ax" \ + "done:" \ + parm [ax] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +# endif +#endif + +#undef ASMByteSwapU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMByteSwapU16 = \ + "xchg al, ah" \ + parm [ax] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMByteSwapU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMByteSwapU32 = \ + "xchg dh, al" \ + "xchg dl, ah" \ + parm [ax dx] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMRotateLeftU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMRotateLeftU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "rol edx, cl" \ + "mov eax, edx" \ + "shr edx, 16" \ + parm [ax dx] [cx] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMRotateRightU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMRotateRightU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "ror edx, cl" \ + "mov eax, edx" \ + "shr edx, 16" \ + parm [ax dx] [cx] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#endif /* !IPRT_INCLUDED_asm_watcom_x86_16_h */ diff --git a/include/iprt/asm-watcom-x86-32.h b/include/iprt/asm-watcom-x86-32.h new file mode 100644 index 00000000..e52c59b2 --- /dev/null +++ b/include/iprt/asm-watcom-x86-32.h @@ -0,0 +1,741 @@ +/** @file + * IPRT - Assembly Functions, x86 32-bit Watcom C/C++ pragma aux. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_watcom_x86_32_h +#define IPRT_INCLUDED_asm_watcom_x86_32_h +/* no pragma once */ + +#ifndef IPRT_INCLUDED_asm_h +# error "Don't include this header directly." +#endif + +#ifndef __FLAT__ +# error "Only works with flat pointers! (-mf)" +#endif + +/* + * Note! The #undef that preceds the #pragma aux statements is for undoing + * the mangling, because the symbol in #pragma aux [symbol] statements + * doesn't get subjected to preprocessing. This is also why we include + * the watcom header at both the top and the bottom of asm.h file. + */ + +#undef ASMCompilerBarrier +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +# if 0 /* overkill version. */ +# pragma aux ASMCompilerBarrier = \ + "nop" \ + parm [] \ + modify exact [eax ebx ecx edx es ds fs gs]; +# else +# pragma aux ASMCompilerBarrier = \ + "" \ + parm [] \ + modify exact []; +# endif +#endif + +#undef ASMNopPause +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMNopPause = \ + ".686p" \ + ".xmm2" \ + "pause" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMAtomicXchgU8 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU8 = \ + "xchg [ecx], al" \ + parm [ecx] [al] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMAtomicXchgU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU16 = \ + "xchg [ecx], ax" \ + parm [ecx] [ax] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicXchgU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU32 = \ + "xchg [ecx], eax" \ + parm [ecx] [eax] \ + value [eax] \ + modify exact [eax]; +#endif + +#undef ASMAtomicXchgU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU64 = \ + ".586" \ + "try_again:" \ + "lock cmpxchg8b [esi]" \ + "jnz try_again" \ + parm [esi] [ebx ecx] \ + value [eax edx] \ + modify exact [edx ecx ebx eax]; +#endif + +#undef ASMAtomicCmpXchgU8 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU8 = \ + ".486" \ + "lock cmpxchg [edx], cl" \ + "setz al" \ + parm [edx] [cl] [al] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMAtomicCmpXchgU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU16 = \ + ".486" \ + "lock cmpxchg [edx], cx" \ + "setz al" \ + parm [edx] [cx] [ax] \ + value [al] \ + modify exact [ax]; +#endif + +#undef ASMAtomicCmpXchgU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU32 = \ + ".486" \ + "lock cmpxchg [edx], ecx" \ + "setz al" \ + parm [edx] [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicCmpXchgU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU64 = \ + ".586" \ + "lock cmpxchg8b [edi]" \ + "setz al" \ + parm [edi] [ebx ecx] [eax edx] \ + value [al] \ + modify exact [eax edx]; +#endif + +#undef ASMAtomicCmpXchgExU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgExU32 = \ + ".586" \ + "lock cmpxchg [edx], ecx" \ + "mov [edi], eax" \ + "setz al" \ + parm [edx] [ecx] [eax] [edi] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicCmpXchgExU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgExU64 = \ + ".586" \ + "lock cmpxchg8b [edi]" \ + "mov [esi], eax" \ + "mov [esi + 4], edx" \ + "setz al" \ + parm [edi] [ebx ecx] [eax edx] [esi] \ + value [al] \ + modify exact [eax edx]; +#endif + +#undef ASMSerializeInstructionCpuId +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionCpuId = \ + ".586" \ + "xor eax, eax" \ + "cpuid" \ + parm [] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMSerializeInstructionIRet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionIRet = \ + "pushf" \ + "push cs" \ + "call foo" /* 'push offset done' doesn't work */ \ + "jmp done" \ + "foo:" \ + "iret" \ + "done:" \ + parm [] \ + modify exact []; +#endif + +#undef ASMSerializeInstructionRdTscp +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionRdTscp = \ + 0x0f 0x01 0xf9 \ + parm [] \ + modify exact [eax edx ecx]; +#endif + +#undef ASMAtomicReadU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicReadU64 = \ + ".586" \ + "xor eax, eax" \ + "mov edx, eax" \ + "mov ebx, eax" \ + "mov ecx, eax" \ + "lock cmpxchg8b [edi]" \ + parm [edi] \ + value [eax edx] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMAtomicUoReadU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoReadU64 = \ + ".586" \ + "xor eax, eax" \ + "mov edx, eax" \ + "mov ebx, eax" \ + "mov ecx, eax" \ + "lock cmpxchg8b [edi]" \ + parm [edi] \ + value [eax edx] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMAtomicAddU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicAddU16 = \ + ".486" \ + "lock xadd [ecx], ax" \ + parm [ecx] [ax] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicAddU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicAddU32 = \ + ".486" \ + "lock xadd [ecx], eax" \ + parm [ecx] [eax] \ + value [eax] \ + modify exact [eax]; +#endif + +#undef ASMAtomicIncU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicIncU16 = \ + ".486" \ + "mov ax, 1" \ + "lock xadd [ecx], ax" \ + "inc ax" \ + parm [ecx] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicIncU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicIncU32 = \ + ".486" \ + "mov eax, 1" \ + "lock xadd [ecx], eax" \ + "inc eax" \ + parm [ecx] \ + value [eax] \ + modify exact [eax]; +#endif + +/* ASMAtomicIncU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicDecU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicDecU16 = \ + ".486" \ + "mov ax, 0ffffh" \ + "lock xadd [ecx], ax" \ + "dec ax" \ + parm [ecx] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicDecU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicDecU32 = \ + ".486" \ + "mov eax, 0ffffffffh" \ + "lock xadd [ecx], eax" \ + "dec eax" \ + parm [ecx] \ + value [eax] \ + modify exact [eax]; +#endif + +/* ASMAtomicDecU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicOrU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicOrU32 = \ + "lock or [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +/* ASMAtomicOrU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicAndU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicAndU32 = \ + "lock and [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +/* ASMAtomicAndU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoOrU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoOrU32 = \ + "or [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +/* ASMAtomicUoOrU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoAndU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoAndU32 = \ + "and [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +/* ASMAtomicUoAndU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoIncU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoIncU32 = \ + ".486" \ + "xadd [ecx], eax" \ + "inc eax" \ + parm [ecx] \ + value [eax] \ + modify exact [eax]; +#endif + +#undef ASMAtomicUoDecU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoDecU32 = \ + ".486" \ + "mov eax, 0ffffffffh" \ + "xadd [ecx], eax" \ + "dec eax" \ + parm [ecx] \ + value [eax] \ + modify exact [eax]; +#endif + +#undef ASMMemZeroPage +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMMemZeroPage = \ + "mov ecx, 1024" \ + "xor eax, eax" \ + "rep stosd" \ + parm [edi] \ + modify exact [eax ecx edi]; +#endif + +#undef ASMMemZero32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMMemZero32 = \ + "shr ecx, 2" \ + "xor eax, eax" \ + "rep stosd" \ + parm [edi] [ecx] \ + modify exact [eax ecx edi]; +#endif + +#undef ASMMemFill32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMMemFill32 = \ + "shr ecx, 2" \ + "rep stosd" \ + parm [edi] [ecx] [eax]\ + modify exact [ecx edi]; +#endif + +#undef ASMProbeReadByte +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMProbeReadByte = \ + "mov al, [ecx]" \ + parm [ecx] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMBitSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitSet = \ + "bts [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMAtomicBitSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitSet = \ + "lock bts [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMBitClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitClear = \ + "btr [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMAtomicBitClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitClear = \ + "lock btr [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMBitToggle +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitToggle = \ + "btc [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMAtomicBitToggle +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitToggle = \ + "lock btc [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + + +#undef ASMBitTestAndSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitTestAndSet = \ + "bts [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicBitTestAndSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndSet = \ + "lock bts [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMBitTestAndClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitTestAndClear = \ + "btr [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicBitTestAndClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndClear = \ + "lock btr [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMBitTestAndToggle +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitTestAndToggle = \ + "btc [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicBitTestAndToggle +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndToggle = \ + "lock btc [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMBitTest +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitTest = \ + "bt [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] nomemory \ + value [al] \ + modify exact [eax] nomemory; +#endif + +#if 0 +/** @todo this is way to much inline assembly, better off in an external function. */ +#undef ASMBitFirstClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstClear = \ + "mov edx, edi" /* save start of bitmap for later */ \ + "add ecx, 31" \ + "shr ecx, 5" /* cDWord = RT_ALIGN_32(cBits, 32) / 32; */ \ + "mov eax, 0ffffffffh" \ + "repe scasd" \ + "je done" \ + "lea edi, [edi - 4]" /* rewind edi */ \ + "xor eax, [edi]" /* load inverted bits */ \ + "sub edi, edx" /* calc byte offset */ \ + "shl edi, 3" /* convert byte to bit offset */ \ + "mov edx, eax" \ + "bsf eax, edx" \ + "add eax, edi" \ + "done:" \ + parm [edi] [ecx] \ + value [eax] \ + modify exact [eax ecx edx edi]; +#endif + +/* ASMBitNextClear: Too much work, do when needed. */ + +/** @todo this is way to much inline assembly, better off in an external function. */ +#undef ASMBitFirstSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstSet = \ + "mov edx, edi" /* save start of bitmap for later */ \ + "add ecx, 31" \ + "shr ecx, 5" /* cDWord = RT_ALIGN_32(cBits, 32) / 32; */ \ + "mov eax, 0ffffffffh" \ + "repe scasd" \ + "je done" \ + "lea edi, [edi - 4]" /* rewind edi */ \ + "mov eax, [edi]" /* reload previous dword */ \ + "sub edi, edx" /* calc byte offset */ \ + "shl edi, 3" /* convert byte to bit offset */ \ + "mov edx, eax" \ + "bsf eax, edx" \ + "add eax, edi" \ + "done:" \ + parm [edi] [ecx] \ + value [eax] \ + modify exact [eax ecx edx edi]; +#endif + +/* ASMBitNextSet: Too much work, do when needed. */ +#else +/* ASMBitFirstClear: External file. */ +/* ASMBitNextClear: External file. */ +/* ASMBitFirstSet: External file. */ +/* ASMBitNextSet: External file. */ +#endif + +#undef ASMBitFirstSetU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstSetU32 = \ + "bsf eax, eax" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMBitFirstSetU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstSetU64 = \ + "bsf eax, eax" \ + "jz not_found_low" \ + "inc eax" \ + "jmp done" \ + \ + "not_found_low:" \ + "bsf eax, edx" \ + "jz not_found_high" \ + "add eax, 33" \ + "jmp done" \ + \ + "not_found_high:" \ + "xor eax, eax" \ + "done:" \ + parm [eax edx] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMBitFirstSetU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstSetU16 = \ + "movzx eax, ax" \ + "bsf eax, eax" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [ax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMBitLastSetU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitLastSetU32 = \ + "bsr eax, eax" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMBitLastSetU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitLastSetU64 = \ + "xchg eax, edx" \ + "bsr eax, eax" \ + "jz not_found_high" \ + "add eax, 33" \ + "jmp done" \ + \ + "not_found_high:" \ + "bsr eax, edx" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [eax edx] nomemory \ + value [eax] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMBitLastSetU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitLastSetU16 = \ + "movzx eax, ax" \ + "bsr eax, eax" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [ax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMByteSwapU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMByteSwapU16 = \ + "ror ax, 8" \ + parm [ax] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMByteSwapU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMByteSwapU32 = \ + "bswap eax" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMRotateLeftU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMRotateLeftU32 = \ + "rol eax, cl" \ + parm [eax] [ecx] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMRotateRightU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMRotateRightU32 = \ + "ror eax, cl" \ + parm [eax] [ecx] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#endif /* !IPRT_INCLUDED_asm_watcom_x86_32_h */ + diff --git a/include/iprt/asm.h b/include/iprt/asm.h new file mode 100644 index 00000000..100555ed --- /dev/null +++ b/include/iprt/asm.h @@ -0,0 +1,8132 @@ +/** @file + * IPRT - Assembly Functions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_h +#define IPRT_INCLUDED_asm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +/** @def RT_INLINE_ASM_USES_INTRIN + * Defined as 1 if we're using a _MSC_VER 1400. + * Otherwise defined as 0. + */ + +/* Solaris 10 header ugliness */ +#ifdef u +# undef u +#endif + +#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN +/* Emit the intrinsics at all optimization levels. */ +# include +# pragma intrinsic(_ReadWriteBarrier) +# pragma intrinsic(__cpuid) +# pragma intrinsic(__stosd) +# pragma intrinsic(__stosw) +# pragma intrinsic(__stosb) +# pragma intrinsic(_BitScanForward) +# pragma intrinsic(_BitScanReverse) +# pragma intrinsic(_bittest) +# pragma intrinsic(_bittestandset) +# pragma intrinsic(_bittestandreset) +# pragma intrinsic(_bittestandcomplement) +# pragma intrinsic(_byteswap_ushort) +# pragma intrinsic(_byteswap_ulong) +# pragma intrinsic(_interlockedbittestandset) +# pragma intrinsic(_interlockedbittestandreset) +# pragma intrinsic(_InterlockedAnd) +# pragma intrinsic(_InterlockedOr) +# pragma intrinsic(_InterlockedXor) +# pragma intrinsic(_InterlockedIncrement) +# pragma intrinsic(_InterlockedDecrement) +# pragma intrinsic(_InterlockedExchange) +# pragma intrinsic(_InterlockedExchangeAdd) +# pragma intrinsic(_InterlockedCompareExchange) +# pragma intrinsic(_InterlockedCompareExchange8) +# pragma intrinsic(_InterlockedCompareExchange16) +# pragma intrinsic(_InterlockedCompareExchange64) +# pragma intrinsic(_rotl) +# pragma intrinsic(_rotr) +# pragma intrinsic(_rotl64) +# pragma intrinsic(_rotr64) +# ifdef RT_ARCH_AMD64 +# pragma intrinsic(__stosq) +# pragma intrinsic(_byteswap_uint64) +# pragma intrinsic(_InterlockedCompareExchange128) +# pragma intrinsic(_InterlockedExchange64) +# pragma intrinsic(_InterlockedExchangeAdd64) +# pragma intrinsic(_InterlockedAnd64) +# pragma intrinsic(_InterlockedOr64) +# pragma intrinsic(_InterlockedIncrement64) +# pragma intrinsic(_InterlockedDecrement64) +# endif +#endif + +/* + * Undefine all symbols we have Watcom C/C++ #pragma aux'es for. + */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 && defined(RT_ARCH_X86) +# include "asm-watcom-x86-16.h" +#elif defined(__WATCOMC__) && ARCH_BITS == 32 && defined(RT_ARCH_X86) +# include "asm-watcom-x86-32.h" +#endif + + +/** @defgroup grp_rt_asm ASM - Assembly Routines + * @ingroup grp_rt + * + * @remarks The difference between ordered and unordered atomic operations are + * that the former will complete outstanding reads and writes before + * continuing while the latter doesn't make any promises about the + * order. Ordered operations doesn't, it seems, make any 100% promise + * wrt to whether the operation will complete before any subsequent + * memory access. (please, correct if wrong.) + * + * ASMAtomicSomething operations are all ordered, while + * ASMAtomicUoSomething are unordered (note the Uo). + * + * Please note that ordered operations does not necessarily imply a + * compiler (memory) barrier. The user has to use the + * ASMCompilerBarrier() macro when that is deemed necessary. + * + * @remarks Some remarks about __volatile__: Without this keyword gcc is allowed + * to reorder or even optimize assembler instructions away. For + * instance, in the following code the second rdmsr instruction is + * optimized away because gcc treats that instruction as deterministic: + * + * @code + * static inline uint64_t rdmsr_low(int idx) + * { + * uint32_t low; + * __asm__ ("rdmsr" : "=a"(low) : "c"(idx) : "edx"); + * } + * ... + * uint32_t msr1 = rdmsr_low(1); + * foo(msr1); + * msr1 = rdmsr_low(1); + * bar(msr1); + * @endcode + * + * The input parameter of rdmsr_low is the same for both calls and + * therefore gcc will use the result of the first call as input + * parameter for bar() as well. For rdmsr this is not acceptable as + * this instruction is _not_ deterministic. This applies to reading + * machine status information in general. + * + * @{ + */ + + +/** @def RT_INLINE_ASM_GCC_4_3_X_X86 + * Used to work around some 4.3.x register allocation issues in this version of + * the compiler. So far this workaround is still required for 4.4 and 4.5 but + * definitely not for 5.x */ +#if (RT_GNUC_PREREQ(4, 3) && !RT_GNUC_PREREQ(5, 0) && defined(__i386__)) +# define RT_INLINE_ASM_GCC_4_3_X_X86 1 +#else +# define RT_INLINE_ASM_GCC_4_3_X_X86 0 +#endif + +/** @def RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC + * i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5493) screws up + * RTSemRWRequestWrite semsemrw-lockless-generic.cpp in release builds. PIC + * mode, x86. + * + * Some gcc 4.3.x versions may have register allocation issues with cmpxchg8b + * when in PIC mode on x86. + */ +#ifndef RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +# if defined(DOXYGEN_RUNNING) || defined(__WATCOMC__) /* Watcom has trouble with the expression below */ +# define RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC 1 +# elif defined(_MSC_VER) /* Visual C++ has trouble too, but it'll only tell us when C4688 is enabled. */ +# define RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC 0 +# elif ( (defined(PIC) || defined(__PIC__)) \ + && defined(RT_ARCH_X86) \ + && ( RT_INLINE_ASM_GCC_4_3_X_X86 \ + || defined(RT_OS_DARWIN)) ) +# define RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC 1 +# else +# define RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC 0 +# endif +#endif + + +/** @def RT_INLINE_ASM_EXTERNAL_TMP_ARM + * Temporary version of RT_INLINE_ASM_EXTERNAL that excludes ARM. */ +#if RT_INLINE_ASM_EXTERNAL && !(defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)) +# define RT_INLINE_ASM_EXTERNAL_TMP_ARM 1 +#else +# define RT_INLINE_ASM_EXTERNAL_TMP_ARM 0 +#endif + +/* + * ARM is great fun. + */ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + +# define RTASM_ARM_NO_BARRIER +# ifdef RT_ARCH_ARM64 +# define RTASM_ARM_NO_BARRIER_IN_REG +# define RTASM_ARM_NO_BARRIER_COMMA_IN_REG +# define RTASM_ARM_DSB_SY "dsb sy\n\t" +# define RTASM_ARM_DSB_SY_IN_REG +# define RTASM_ARM_DSB_SY_COMMA_IN_REG +# define RTASM_ARM_DMB_SY "dmb sy\n\t" +# define RTASM_ARM_DMB_SY_IN_REG +# define RTASM_ARM_DMB_SY_COMMA_IN_REG +# define RTASM_ARM_DMB_ST "dmb st\n\t" +# define RTASM_ARM_DMB_ST_IN_REG +# define RTASM_ARM_DMB_ST_COMMA_IN_REG +# define RTASM_ARM_DMB_LD "dmb ld\n\t" +# define RTASM_ARM_DMB_LD_IN_REG +# define RTASM_ARM_DMB_LD_COMMA_IN_REG +# define RTASM_ARM_PICK_6432(expr64, expr32) expr64 +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(name, a_pu32Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint32_t u32NewRet; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RTASM_ARM_##barrier_type /* before lable? */ \ + "ldaxr %w[uNew], %[pMem]\n\t" \ + modify64 \ + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" \ + "cbnz %w[rc], .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+Q" (*a_pu32Mem) \ + , [uNew] "=&r" (u32NewRet) \ + , [rc] "=&r" (rcSpill) \ + : in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(name, a_pu32Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint32_t u32OldRet; \ + uint32_t u32NewSpill; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RTASM_ARM_##barrier_type /* before lable? */ \ + "ldaxr %w[uOld], %[pMem]\n\t" \ + modify64 \ + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" \ + "cbnz %w[rc], .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+Q" (*a_pu32Mem) \ + , [uOld] "=&r" (u32OldRet) \ + , [uNew] "=&r" (u32NewSpill) \ + , [rc] "=&r" (rcSpill) \ + : in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(name, a_pu64Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint64_t u64NewRet; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RTASM_ARM_##barrier_type /* before lable? */ \ + "ldaxr %[uNew], %[pMem]\n\t" \ + modify64 \ + "stlxr %w[rc], %[uNew], %[pMem]\n\t" \ + "cbnz %w[rc], .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+Q" (*a_pu64Mem) \ + , [uNew] "=&r" (u64NewRet) \ + , [rc] "=&r" (rcSpill) \ + : in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_64(name, a_pu64Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint64_t u64OldRet; \ + uint64_t u64NewSpill; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RTASM_ARM_##barrier_type /* before lable? */ \ + "ldaxr %[uOld], %[pMem]\n\t" \ + modify64 \ + "stlxr %w[rc], %[uNew], %[pMem]\n\t" \ + "cbnz %w[rc], .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+Q" (*a_pu64Mem) \ + , [uOld] "=&r" (u64OldRet) \ + , [uNew] "=&r" (u64NewSpill) \ + , [rc] "=&r" (rcSpill) \ + : in_reg \ + : "cc") + +# else /* RT_ARCH_ARM32 */ +# define RTASM_ARM_PICK_6432(expr64, expr32) expr32 +# if RT_ARCH_ARM32 >= 7 +# warning armv7 +# define RTASM_ARM_NO_BARRIER_IN_REG +# define RTASM_ARM_NO_BARRIER_COMMA_IN_REG +# define RTASM_ARM_DSB_SY "dsb sy\n\t" +# define RTASM_ARM_DSB_SY_IN_REG "X" (0xfade) +# define RTASM_ARM_DMB_SY "dmb sy\n\t" +# define RTASM_ARM_DMB_SY_IN_REG "X" (0xfade) +# define RTASM_ARM_DMB_ST "dmb st\n\t" +# define RTASM_ARM_DMB_ST_IN_REG "X" (0xfade) +# define RTASM_ARM_DMB_LD "dmb ld\n\t" +# define RTASM_ARM_DMB_LD_IN_REG "X" (0xfade) + +# elif RT_ARCH_ARM32 >= 6 +# warning armv6 +# define RTASM_ARM_DSB_SY "mcr p15, 0, %[uZero], c7, c10, 4\n\t" +# define RTASM_ARM_DSB_SY_IN_REG [uZero] "r" (0) +# define RTASM_ARM_DMB_SY "mcr p15, 0, %[uZero], c7, c10, 5\n\t" +# define RTASM_ARM_DMB_SY_IN_REG [uZero] "r" (0) +# define RTASM_ARM_DMB_ST RTASM_ARM_DMB_SY +# define RTASM_ARM_DMB_ST_IN_REG RTASM_ARM_DMB_SY_IN_REG +# define RTASM_ARM_DMB_LD RTASM_ARM_DMB_SY +# define RTASM_ARM_DMB_LD_IN_REG RTASM_ARM_DMB_SY_IN_REG +# elif RT_ARCH_ARM32 >= 4 +# warning armv5 or older +# define RTASM_ARM_DSB_SY "mcr p15, 0, %[uZero], c7, c10, 4\n\t" +# define RTASM_ARM_DSB_SY_IN_REG [uZero] "r" (0) +# define RTASM_ARM_DMB_SY RTASM_ARM_DSB_SY +# define RTASM_ARM_DMB_SY_IN_REG RTASM_ARM_DSB_SY_IN_REG +# define RTASM_ARM_DMB_ST RTASM_ARM_DSB_SY +# define RTASM_ARM_DMB_ST_IN_REG RTASM_ARM_DSB_SY_IN_REG +# define RTASM_ARM_DMB_LD RTASM_ARM_DSB_SY +# define RTASM_ARM_DMB_LD_IN_REG RTASM_ARM_DSB_SY_IN_REG +# else +# error "huh? Odd RT_ARCH_ARM32 value!" +# endif +# define RTASM_ARM_DSB_SY_COMMA_IN_REG , RTASM_ARM_DSB_SY_IN_REG +# define RTASM_ARM_DMB_SY_COMMA_IN_REG , RTASM_ARM_DMB_SY_IN_REG +# define RTASM_ARM_DMB_ST_COMMA_IN_REG , RTASM_ARM_DMB_ST_IN_REG +# define RTASM_ARM_DMB_LD_COMMA_IN_REG , RTASM_ARM_DMB_LD_IN_REG +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(name, a_pu32Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint32_t u32NewRet; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RT_CONCAT(RTASM_ARM_,barrier_type) /* before lable? */ \ + "ldrex %[uNew], %[pMem]\n\t" \ + modify32 \ + "strex %[rc], %[uNew], %[pMem]\n\t" \ + "cmp %[rc], #0\n\t" \ + "bne .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+m" (*a_pu32Mem) \ + , [uNew] "=&r" (u32NewRet) \ + , [rc] "=&r" (rcSpill) \ + : RT_CONCAT3(RTASM_ARM_,barrier_type,_IN_REG) \ + , in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(name, a_pu32Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint32_t u32OldRet; \ + uint32_t u32NewSpill; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RT_CONCAT(RTASM_ARM_,barrier_type) /* before lable? */ \ + "ldrex %[uOld], %[pMem]\n\t" \ + modify32 \ + "strex %[rc], %[uNew], %[pMem]\n\t" \ + "cmp %[rc], #0\n\t" \ + "bne .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+m" (*a_pu32Mem) \ + , [uOld] "=&r" (u32OldRet) \ + , [uNew] "=&r" (u32NewSpill) \ + , [rc] "=&r" (rcSpill) \ + : RT_CONCAT3(RTASM_ARM_,barrier_type,_IN_REG) \ + , in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(name, a_pu64Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint64_t u64NewRet; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RT_CONCAT(RTASM_ARM_,barrier_type) /* before lable? */ \ + "ldrexd %[uNew], %H[uNew], %[pMem]\n\t" \ + modify32 \ + "strexd %[rc], %[uNew], %H[uNew], %[pMem]\n\t" \ + "cmp %[rc], #0\n\t" \ + "bne .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+m" (*a_pu64Mem), \ + [uNew] "=&r" (u64NewRet), \ + [rc] "=&r" (rcSpill) \ + : RT_CONCAT3(RTASM_ARM_,barrier_type,_IN_REG) \ + , in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_64(name, a_pu64Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint64_t u64OldRet; \ + uint64_t u64NewSpill; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RT_CONCAT(RTASM_ARM_,barrier_type) /* before lable? */ \ + "ldrexd %[uOld], %H[uOld], %[pMem]\n\t" \ + modify32 \ + "strexd %[rc], %[uNew], %H[uNew], %[pMem]\n\t" \ + "cmp %[rc], #0\n\t" \ + "bne .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+m" (*a_pu64Mem), \ + [uOld] "=&r" (u64OldRet), \ + [uNew] "=&r" (u64NewSpill), \ + [rc] "=&r" (rcSpill) \ + : RT_CONCAT3(RTASM_ARM_,barrier_type,_IN_REG) \ + , in_reg \ + : "cc") +# endif /* RT_ARCH_ARM32 */ +#endif + + +/** @def ASMReturnAddress + * Gets the return address of the current (or calling if you like) function or method. + */ +#ifdef _MSC_VER +# ifdef __cplusplus +extern "C" +# endif +void * _ReturnAddress(void); +# pragma intrinsic(_ReturnAddress) +# define ASMReturnAddress() _ReturnAddress() +#elif defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define ASMReturnAddress() __builtin_return_address(0) +#elif defined(__WATCOMC__) +# define ASMReturnAddress() Watcom_does_not_appear_to_have_intrinsic_return_address_function() +#else +# error "Unsupported compiler." +#endif + + +/** + * Compiler memory barrier. + * + * Ensure that the compiler does not use any cached (register/tmp stack) memory + * values or any outstanding writes when returning from this function. + * + * This function must be used if non-volatile data is modified by a + * device or the VMM. Typical cases are port access, MMIO access, + * trapping instruction, etc. + */ +#if RT_INLINE_ASM_GNU_STYLE +# define ASMCompilerBarrier() do { __asm__ __volatile__("" : : : "memory"); } while (0) +#elif RT_INLINE_ASM_USES_INTRIN +# define ASMCompilerBarrier() do { _ReadWriteBarrier(); } while (0) +#elif defined(__WATCOMC__) +void ASMCompilerBarrier(void); +#else /* 2003 should have _ReadWriteBarrier() but I guess we're at 2002 level then... */ +DECLINLINE(void) ASMCompilerBarrier(void) RT_NOTHROW_DEF +{ + __asm + { + } +} +#endif + + +/** @def ASMBreakpoint + * Debugger Breakpoint. + * @deprecated Use RT_BREAKPOINT instead. + * @internal + */ +#define ASMBreakpoint() RT_BREAKPOINT() + + +/** + * Spinloop hint for platforms that have these, empty function on the other + * platforms. + * + * x86 & AMD64: The PAUSE variant of NOP for helping hyperthreaded CPUs detecting + * spin locks. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMNopPause(void) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMNopPause(void) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__(".byte 0xf3,0x90\n\t"); +# else + __asm { + _emit 0f3h + _emit 090h + } +# endif + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + __asm__ __volatile__("yield\n\t"); /* ARMv6K+ */ + +# else + /* dummy */ +# endif +} +#endif + + +/** + * Atomically Exchange an unsigned 8-bit value, ordered. + * + * @returns Current *pu8 value + * @param pu8 Pointer to the 8-bit variable to update. + * @param u8 The 8-bit value to assign to *pu8. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMAtomicXchgU8(volatile uint8_t RT_FAR *pu8, uint8_t u8) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint8_t) ASMAtomicXchgU8(volatile uint8_t RT_FAR *pu8, uint8_t u8) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xchgb %0, %1\n\t" + : "=m" (*pu8) + , "=q" (u8) /* =r - busted on g++ (GCC) 3.4.4 20050721 (Red Hat 3.4.4-2) */ + : "1" (u8) + , "m" (*pu8)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu8] + mov al, [u8] + xchg [rdx], al + mov [u8], al +# else + mov edx, [pu8] + mov al, [u8] + xchg [edx], al + mov [u8], al +# endif + } +# endif + return u8; + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + uint32_t uOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicXchgU8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrb %w[uOld], %[pMem]\n\t" + "stlxrb %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicXchgU8_%=\n\t" +# else + "ldrexb %[uOld], %[pMem]\n\t" /* ARMv6+ */ + "strexb %[rc], %[uNew], %[pMem]\n\t" + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicXchgU8_%=\n\t" +# endif + : [pMem] "+Q" (*pu8) + , [uOld] "=&r" (uOld) + , [rc] "=&r" (rcSpill) + : [uNew] "r" ((uint32_t)u8) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return (uint8_t)uOld; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Exchange a signed 8-bit value, ordered. + * + * @returns Current *pu8 value + * @param pi8 Pointer to the 8-bit variable to update. + * @param i8 The 8-bit value to assign to *pi8. + */ +DECLINLINE(int8_t) ASMAtomicXchgS8(volatile int8_t RT_FAR *pi8, int8_t i8) RT_NOTHROW_DEF +{ + return (int8_t)ASMAtomicXchgU8((volatile uint8_t RT_FAR *)pi8, (uint8_t)i8); +} + + +/** + * Atomically Exchange a bool value, ordered. + * + * @returns Current *pf value + * @param pf Pointer to the 8-bit variable to update. + * @param f The 8-bit value to assign to *pi8. + */ +DECLINLINE(bool) ASMAtomicXchgBool(volatile bool RT_FAR *pf, bool f) RT_NOTHROW_DEF +{ +#ifdef _MSC_VER + return !!ASMAtomicXchgU8((volatile uint8_t RT_FAR *)pf, (uint8_t)f); +#else + return (bool)ASMAtomicXchgU8((volatile uint8_t RT_FAR *)pf, (uint8_t)f); +#endif +} + + +/** + * Atomically Exchange an unsigned 16-bit value, ordered. + * + * @returns Current *pu16 value + * @param pu16 Pointer to the 16-bit variable to update. + * @param u16 The 16-bit value to assign to *pu16. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMAtomicXchgU16(volatile uint16_t RT_FAR *pu16, uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint16_t) ASMAtomicXchgU16(volatile uint16_t RT_FAR *pu16, uint16_t u16) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xchgw %0, %1\n\t" + : "=m" (*pu16) + , "=r" (u16) + : "1" (u16) + , "m" (*pu16)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu16] + mov ax, [u16] + xchg [rdx], ax + mov [u16], ax +# else + mov edx, [pu16] + mov ax, [u16] + xchg [edx], ax + mov [u16], ax +# endif + } +# endif + return u16; + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + uint32_t uOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicXchgU16_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrh %w[uOld], %[pMem]\n\t" + "stlxrh %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicXchgU16_%=\n\t" +# else + "ldrexh %[uOld], %[pMem]\n\t" /* ARMv6+ */ + "strexh %[rc], %[uNew], %[pMem]\n\t" + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicXchgU16_%=\n\t" +# endif + : [pMem] "+Q" (*pu16) + , [uOld] "=&r" (uOld) + , [rc] "=&r" (rcSpill) + : [uNew] "r" ((uint32_t)u16) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return (uint16_t)uOld; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Exchange a signed 16-bit value, ordered. + * + * @returns Current *pu16 value + * @param pi16 Pointer to the 16-bit variable to update. + * @param i16 The 16-bit value to assign to *pi16. + */ +DECLINLINE(int16_t) ASMAtomicXchgS16(volatile int16_t RT_FAR *pi16, int16_t i16) RT_NOTHROW_DEF +{ + return (int16_t)ASMAtomicXchgU16((volatile uint16_t RT_FAR *)pi16, (uint16_t)i16); +} + + +/** + * Atomically Exchange an unsigned 32-bit value, ordered. + * + * @returns Current *pu32 value + * @param pu32 Pointer to the 32-bit variable to update. + * @param u32 The 32-bit value to assign to *pu32. + * + * @remarks Does not work on 286 and earlier. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicXchgU32(volatile uint32_t RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicXchgU32(volatile uint32_t RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xchgl %0, %1\n\t" + : "=m" (*pu32) /** @todo r=bird: +m rather than =m here? */ + , "=r" (u32) + : "1" (u32) + , "m" (*pu32)); + +# elif RT_INLINE_ASM_USES_INTRIN + u32 = _InterlockedExchange((long RT_FAR *)pu32, u32); + +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + mov eax, u32 + xchg [rdx], eax + mov [u32], eax +# else + mov edx, [pu32] + mov eax, u32 + xchg [edx], eax + mov [u32], eax +# endif + } +# endif + return u32; + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + uint32_t uOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicXchgU32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %w[uOld], %[pMem]\n\t" + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicXchgU32_%=\n\t" +# else + "ldrex %[uOld], %[pMem]\n\t" /* ARMv6+ */ + "strex %[rc], %[uNew], %[pMem]\n\t" + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicXchgU32_%=\n\t" +# endif + : [pMem] "+Q" (*pu32) + , [uOld] "=&r" (uOld) + , [rc] "=&r" (rcSpill) + : [uNew] "r" (u32) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return uOld; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Exchange a signed 32-bit value, ordered. + * + * @returns Current *pu32 value + * @param pi32 Pointer to the 32-bit variable to update. + * @param i32 The 32-bit value to assign to *pi32. + */ +DECLINLINE(int32_t) ASMAtomicXchgS32(volatile int32_t RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicXchgU32((volatile uint32_t RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically Exchange an unsigned 64-bit value, ordered. + * + * @returns Current *pu64 value + * @param pu64 Pointer to the 64-bit variable to update. + * @param u64 The 64-bit value to assign to *pu64. + * + * @remarks Works on 32-bit x86 CPUs starting with Pentium. + */ +#if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMAtomicXchgU64(volatile uint64_t RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicXchgU64(volatile uint64_t RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_USES_INTRIN + return _InterlockedExchange64((__int64 *)pu64, u64); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xchgq %0, %1\n\t" + : "=m" (*pu64) + , "=r" (u64) + : "1" (u64) + , "m" (*pu64)); + return u64; +# else + __asm + { + mov rdx, [pu64] + mov rax, [u64] + xchg [rdx], rax + mov [u64], rax + } + return u64; +# endif + +# elif defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE +# if defined(PIC) || defined(__PIC__) + uint32_t u32EBX = (uint32_t)u64; + __asm__ __volatile__(/*"xchgl %%esi, %5\n\t"*/ + "xchgl %%ebx, %3\n\t" + "1:\n\t" + "lock; cmpxchg8b (%5)\n\t" + "jnz 1b\n\t" + "movl %3, %%ebx\n\t" + /*"xchgl %%esi, %5\n\t"*/ + : "=A" (u64) + , "=m" (*pu64) + : "0" (*pu64) + , "m" ( u32EBX ) + , "c" ( (uint32_t)(u64 >> 32) ) + , "S" (pu64) + : "cc"); +# else /* !PIC */ + __asm__ __volatile__("1:\n\t" + "lock; cmpxchg8b %1\n\t" + "jnz 1b\n\t" + : "=A" (u64) + , "=m" (*pu64) + : "0" (*pu64) + , "b" ( (uint32_t)u64 ) + , "c" ( (uint32_t)(u64 >> 32) ) + : "cc"); +# endif +# else + __asm + { + mov ebx, dword ptr [u64] + mov ecx, dword ptr [u64 + 4] + mov edi, pu64 + mov eax, dword ptr [edi] + mov edx, dword ptr [edi + 4] + retry: + lock cmpxchg8b [edi] + jnz retry + mov dword ptr [u64], eax + mov dword ptr [u64 + 4], edx + } +# endif + return u64; + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + uint32_t rcSpill; + uint64_t uOld; + __asm__ __volatile__(".Ltry_again_ASMAtomicXchgU64_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %[uOld], %[pMem]\n\t" + "stlxr %w[rc], %[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicXchgU64_%=\n\t" +# else + "ldrexd %[uOld], %H[uOld], %[pMem]\n\t" /* ARMv6+ */ + "strexd %[rc], %[uNew], %H[uNew], %[pMem]\n\t" + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicXchgU64_%=\n\t" +# endif + : [pMem] "+Q" (*pu64) + , [uOld] "=&r" (uOld) + , [rc] "=&r" (rcSpill) + : [uNew] "r" (u64) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return uOld; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Exchange an signed 64-bit value, ordered. + * + * @returns Current *pi64 value + * @param pi64 Pointer to the 64-bit variable to update. + * @param i64 The 64-bit value to assign to *pi64. + */ +DECLINLINE(int64_t) ASMAtomicXchgS64(volatile int64_t RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicXchgU64((volatile uint64_t RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically Exchange a size_t value, ordered. + * + * @returns Current *ppv value + * @param puDst Pointer to the size_t variable to update. + * @param uNew The new value to assign to *puDst. + */ +DECLINLINE(size_t) ASMAtomicXchgZ(size_t volatile RT_FAR *puDst, const size_t uNew) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 16 + AssertCompile(sizeof(size_t) == 2); + return ASMAtomicXchgU16((volatile uint16_t RT_FAR *)puDst, uNew); +#elif ARCH_BITS == 32 + return ASMAtomicXchgU32((volatile uint32_t RT_FAR *)puDst, uNew); +#elif ARCH_BITS == 64 + return ASMAtomicXchgU64((volatile uint64_t RT_FAR *)puDst, uNew); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically Exchange a pointer value, ordered. + * + * @returns Current *ppv value + * @param ppv Pointer to the pointer variable to update. + * @param pv The pointer value to assign to *ppv. + */ +DECLINLINE(void RT_FAR *) ASMAtomicXchgPtr(void RT_FAR * volatile RT_FAR *ppv, const void RT_FAR *pv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return (void RT_FAR *)ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pv); +#elif ARCH_BITS == 64 + return (void RT_FAR *)ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pv); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Convenience macro for avoiding the annoying casting with ASMAtomicXchgPtr. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to update. + * @param pv The pointer value to assign to *ppv. + * @param Type The type of *ppv, sans volatile. + */ +#ifdef __GNUC__ /* 8.2.0 requires -Wno-ignored-qualifiers */ +# define ASMAtomicXchgPtrT(ppv, pv, Type) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + Type const pvTypeChecked = (pv); \ + Type pvTypeCheckedRet = (__typeof__(*(ppv))) ASMAtomicXchgPtr((void * volatile *)ppvTypeChecked, (void *)pvTypeChecked); \ + pvTypeCheckedRet; \ + }) +#else +# define ASMAtomicXchgPtrT(ppv, pv, Type) \ + (Type)ASMAtomicXchgPtr((void RT_FAR * volatile RT_FAR *)(ppv), (void RT_FAR *)(pv)) +#endif + + +/** + * Atomically Exchange a raw-mode context pointer value, ordered. + * + * @returns Current *ppv value + * @param ppvRC Pointer to the pointer variable to update. + * @param pvRC The pointer value to assign to *ppv. + */ +DECLINLINE(RTRCPTR) ASMAtomicXchgRCPtr(RTRCPTR volatile RT_FAR *ppvRC, RTRCPTR pvRC) RT_NOTHROW_DEF +{ + return (RTRCPTR)ASMAtomicXchgU32((uint32_t volatile RT_FAR *)(void RT_FAR *)ppvRC, (uint32_t)pvRC); +} + + +/** + * Atomically Exchange a ring-0 pointer value, ordered. + * + * @returns Current *ppv value + * @param ppvR0 Pointer to the pointer variable to update. + * @param pvR0 The pointer value to assign to *ppv. + */ +DECLINLINE(RTR0PTR) ASMAtomicXchgR0Ptr(RTR0PTR volatile RT_FAR *ppvR0, RTR0PTR pvR0) RT_NOTHROW_DEF +{ +#if R0_ARCH_BITS == 32 || ARCH_BITS == 16 + return (RTR0PTR)ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppvR0, (uint32_t)pvR0); +#elif R0_ARCH_BITS == 64 + return (RTR0PTR)ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppvR0, (uint64_t)pvR0); +#else +# error "R0_ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically Exchange a ring-3 pointer value, ordered. + * + * @returns Current *ppv value + * @param ppvR3 Pointer to the pointer variable to update. + * @param pvR3 The pointer value to assign to *ppv. + */ +DECLINLINE(RTR3PTR) ASMAtomicXchgR3Ptr(RTR3PTR volatile RT_FAR *ppvR3, RTR3PTR pvR3) RT_NOTHROW_DEF +{ +#if R3_ARCH_BITS == 32 || ARCH_BITS == 16 + return (RTR3PTR)ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppvR3, (uint32_t)pvR3); +#elif R3_ARCH_BITS == 64 + return (RTR3PTR)ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppvR3, (uint64_t)pvR3); +#else +# error "R3_ARCH_BITS is bogus" +#endif +} + + +/** @def ASMAtomicXchgHandle + * Atomically Exchange a typical IPRT handle value, ordered. + * + * @param ph Pointer to the value to update. + * @param hNew The new value to assigned to *pu. + * @param phRes Where to store the current *ph value. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicXchgHandle(ph, hNew, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint32_t)); \ + *(uint32_t RT_FAR *)(phRes) = ASMAtomicXchgU32((uint32_t volatile RT_FAR *)(ph), (const uint32_t)(hNew)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicXchgHandle(ph, hNew, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint64_t)); \ + *(uint64_t RT_FAR *)(phRes) = ASMAtomicXchgU64((uint64_t volatile RT_FAR *)(ph), (const uint64_t)(hNew)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically Exchange a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to assign to *pu. + * @todo This is busted as its missing the result argument. + */ +#define ASMAtomicXchgSize(pu, uNew) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: ASMAtomicXchgU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu), (uint8_t)(uNew)); break; \ + case 2: ASMAtomicXchgU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu), (uint16_t)(uNew)); break; \ + case 4: ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicXchgSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + +/** + * Atomically Exchange a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to assign to *pu. + * @param puRes Where to store the current *pu value. + */ +#define ASMAtomicXchgSizeCorrect(pu, uNew, puRes) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: *(uint8_t RT_FAR *)(puRes) = ASMAtomicXchgU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu), (uint8_t)(uNew)); break; \ + case 2: *(uint16_t RT_FAR *)(puRes) = ASMAtomicXchgU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu), (uint16_t)(uNew)); break; \ + case 4: *(uint32_t RT_FAR *)(puRes) = ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: *(uint64_t RT_FAR *)(puRes) = ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicXchgSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + + +/** + * Atomically Compare and Exchange an unsigned 8-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu8 Pointer to the value to update. + * @param u8New The new value to assigned to *pu8. + * @param u8Old The old value to *pu8 compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteU8 + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM || !RT_INLINE_ASM_GNU_STYLE +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgU8(volatile uint8_t RT_FAR *pu8, const uint8_t u8New, const uint8_t u8Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgU8(volatile uint8_t RT_FAR *pu8, const uint8_t u8New, uint8_t u8Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgb %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu8) + , "=qm" (u8Ret) + , "=a" (u8Old) + : "q" (u8New) + , "2" (u8Old) + , "m" (*pu8) + : "cc"); + return (bool)u8Ret; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint32_t u32Spill; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgU8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrb %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxrb %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgU8_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexb %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexbeq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgU8_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu8) + , [uOld] "=&r" (u32Spill) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" ((uint32_t)u8Old) + , [uNew] "r" ((uint32_t)u8New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 8-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi8 Pointer to the value to update. + * @param i8New The new value to assigned to *pi8. + * @param i8Old The old value to *pi8 compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteS8 + */ +DECLINLINE(bool) ASMAtomicCmpXchgS8(volatile int8_t RT_FAR *pi8, const int8_t i8New, const int8_t i8Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgU8((volatile uint8_t RT_FAR *)pi8, (uint8_t)i8New, (uint8_t)i8Old); +} + + +/** + * Atomically Compare and Exchange a bool value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pf Pointer to the value to update. + * @param fNew The new value to assigned to *pf. + * @param fOld The old value to *pf compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteBool + */ +DECLINLINE(bool) ASMAtomicCmpXchgBool(volatile bool RT_FAR *pf, const bool fNew, const bool fOld) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgU8((volatile uint8_t RT_FAR *)pf, (uint8_t)fNew, (uint8_t)fOld); +} + + +/** + * Atomically Compare and Exchange an unsigned 32-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu32 Pointer to the value to update. + * @param u32New The new value to assigned to *pu32. + * @param u32Old The old value to *pu32 compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteU32 + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgU32(volatile uint32_t RT_FAR *pu32, const uint32_t u32New, const uint32_t u32Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgU32(volatile uint32_t RT_FAR *pu32, const uint32_t u32New, uint32_t u32Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgl %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu32) + , "=qm" (u8Ret) + , "=a" (u32Old) + : "r" (u32New) + , "2" (u32Old) + , "m" (*pu32) + : "cc"); + return (bool)u8Ret; + +# elif RT_INLINE_ASM_USES_INTRIN + return (uint32_t)_InterlockedCompareExchange((long RT_FAR *)pu32, u32New, u32Old) == u32Old; + +# else + uint32_t u32Ret; + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] +# else + mov edx, [pu32] +# endif + mov eax, [u32Old] + mov ecx, [u32New] +# ifdef RT_ARCH_AMD64 + lock cmpxchg [rdx], ecx +# else + lock cmpxchg [edx], ecx +# endif + setz al + movzx eax, al + mov [u32Ret], eax + } + return !!u32Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint32_t u32Spill; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgU32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgU32_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrex %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexeq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgU32_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu32) + , [uOld] "=&r" (u32Spill) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u32Old) + , [uNew] "r" (u32New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 32-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi32 Pointer to the value to update. + * @param i32New The new value to assigned to *pi32. + * @param i32Old The old value to *pi32 compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteS32 + */ +DECLINLINE(bool) ASMAtomicCmpXchgS32(volatile int32_t RT_FAR *pi32, const int32_t i32New, const int32_t i32Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgU32((volatile uint32_t RT_FAR *)pi32, (uint32_t)i32New, (uint32_t)i32Old); +} + + +/** + * Atomically Compare and exchange an unsigned 64-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu64 Pointer to the 64-bit variable to update. + * @param u64New The 64-bit value to assign to *pu64. + * @param u64Old The value to compare with. + * + * @remarks x86: Requires a Pentium or later. + * @todo Rename ASMAtomicCmpWriteU64 + */ +#if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgU64(volatile uint64_t RT_FAR *pu64, const uint64_t u64New, const uint64_t u64Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgU64(volatile uint64_t RT_FAR *pu64, uint64_t u64New, uint64_t u64Old) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return (uint64_t)_InterlockedCompareExchange64((__int64 RT_FAR *)pu64, u64New, u64Old) == u64Old; + +# elif defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgq %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu64) + , "=qm" (u8Ret) + , "=a" (u64Old) + : "r" (u64New) + , "2" (u64Old) + , "m" (*pu64) + : "cc"); + return (bool)u8Ret; +# else + bool fRet; + __asm + { + mov rdx, [pu32] + mov rax, [u64Old] + mov rcx, [u64New] + lock cmpxchg [rdx], rcx + setz al + mov [fRet], al + } + return fRet; +# endif + +# elif defined(RT_ARCH_X86) + uint32_t u32Ret; +# if RT_INLINE_ASM_GNU_STYLE +# if defined(PIC) || defined(__PIC__) + uint32_t u32EBX = (uint32_t)u64New; + uint32_t u32Spill; + __asm__ __volatile__("xchgl %%ebx, %4\n\t" + "lock; cmpxchg8b (%6)\n\t" + "setz %%al\n\t" + "movl %4, %%ebx\n\t" + "movzbl %%al, %%eax\n\t" + : "=a" (u32Ret) + , "=d" (u32Spill) +# if RT_GNUC_PREREQ(4, 3) + , "+m" (*pu64) +# else + , "=m" (*pu64) +# endif + : "A" (u64Old) + , "m" ( u32EBX ) + , "c" ( (uint32_t)(u64New >> 32) ) + , "S" (pu64) + : "cc"); +# else /* !PIC */ + uint32_t u32Spill; + __asm__ __volatile__("lock; cmpxchg8b %2\n\t" + "setz %%al\n\t" + "movzbl %%al, %%eax\n\t" + : "=a" (u32Ret) + , "=d" (u32Spill) + , "+m" (*pu64) + : "A" (u64Old) + , "b" ( (uint32_t)u64New ) + , "c" ( (uint32_t)(u64New >> 32) ) + : "cc"); +# endif + return (bool)u32Ret; +# else + __asm + { + mov ebx, dword ptr [u64New] + mov ecx, dword ptr [u64New + 4] + mov edi, [pu64] + mov eax, dword ptr [u64Old] + mov edx, dword ptr [u64Old + 4] + lock cmpxchg8b [edi] + setz al + movzx eax, al + mov dword ptr [u32Ret], eax + } + return !!u32Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint64_t u64Spill; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgU64_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %[uOld], %[pMem]\n\t" + "cmp %[uOld], %[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxr %w[rc], %[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgU64_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexd %[uOld], %H[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "teqeq %H[uOld], %H[uCmp]\n\t" + "strexdeq %[rc], %[uNew], %H[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgU64_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu64) + , [uOld] "=&r" (u64Spill) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u64Old) + , [uNew] "r" (u64New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and exchange a signed 64-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi64 Pointer to the 64-bit variable to update. + * @param i64 The 64-bit value to assign to *pu64. + * @param i64Old The value to compare with. + * + * @remarks x86: Requires a Pentium or later. + * @todo Rename ASMAtomicCmpWriteS64 + */ +DECLINLINE(bool) ASMAtomicCmpXchgS64(volatile int64_t RT_FAR *pi64, const int64_t i64, const int64_t i64Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgU64((volatile uint64_t RT_FAR *)pi64, (uint64_t)i64, (uint64_t)i64Old); +} + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING) + +/** @def RTASM_HAVE_CMP_WRITE_U128 + * Indicates that we've got ASMAtomicCmpWriteU128(), ASMAtomicCmpWriteU128v2() + * and ASMAtomicCmpWriteExU128() available. */ +# define RTASM_HAVE_CMP_WRITE_U128 1 + + +/** + * Atomically compare and write an unsigned 128-bit value, ordered. + * + * @returns true if write was done. + * @returns false if write wasn't done. + * + * @param pu128 Pointer to the 128-bit variable to update. + * @param u64NewHi The high 64 bits of the value to assign to *pu128. + * @param u64NewLo The low 64 bits of the value to assign to *pu128. + * @param u64OldHi The high 64-bit of the value to compare with. + * @param u64OldLo The low 64-bit of the value to compare with. + * + * @remarks AMD64: Not present in the earliest CPUs, so check CPUID. + */ +# if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) +DECLASM(bool) ASMAtomicCmpWriteU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo, + const uint64_t u64OldHi, const uint64_t u64OldLo) RT_NOTHROW_PROTO; +# else +DECLINLINE(bool) ASMAtomicCmpWriteU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo, + const uint64_t u64OldHi, const uint64_t u64OldLo) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + __int64 ai64Cmp[2]; + ai64Cmp[0] = u64OldLo; + ai64Cmp[1] = u64OldHi; + return _InterlockedCompareExchange128((__int64 volatile *)pu128, u64NewHi, u64NewLo, ai64Cmp) != 0; + +# elif (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + return __sync_bool_compare_and_swap(pu128, ((uint128_t)u64OldHi << 64) | u64OldLo, ((uint128_t)u64NewHi << 64) | u64NewLo); + +# elif defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint64_t u64Ret; + uint64_t u64Spill; + __asm__ __volatile__("lock; cmpxchg16b %2\n\t" + "setz %%al\n\t" + "movzbl %%al, %%eax\n\t" + : "=a" (u64Ret) + , "=d" (u64Spill) + , "+m" (*pu128) + : "a" (u64OldLo) + , "d" (u64OldHi) + , "b" (u64NewLo) + , "c" (u64NewHi) + : "cc"); + + return (bool)u64Ret; +# else +# error "Port me" +# endif +# else +# error "Port me" +# endif +} +# endif + + +/** + * Atomically compare and write an unsigned 128-bit value, ordered. + * + * @returns true if write was done. + * @returns false if write wasn't done. + * + * @param pu128 Pointer to the 128-bit variable to update. + * @param u128New The 128-bit value to assign to *pu128. + * @param u128Old The value to compare with. + * + * @remarks AMD64: Not present in the earliest CPUs, so check CPUID. + */ +DECLINLINE(bool) ASMAtomicCmpWriteU128(volatile uint128_t *pu128, const uint128_t u128New, const uint128_t u128Old) RT_NOTHROW_DEF +{ +# ifdef RT_COMPILER_WITH_128BIT_INT_TYPES +# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + return __sync_bool_compare_and_swap(pu128, u128Old, u128New); +# else + return ASMAtomicCmpWriteU128v2(pu128, (uint64_t)(u128New >> 64), (uint64_t)u128New, + (uint64_t)(u128Old >> 64), (uint64_t)u128Old); +# endif +# else + return ASMAtomicCmpWriteU128v2(pu128, u128New.Hi, u128New.Lo, u128Old.Hi, u128Old.Lo); +# endif +} + + +/** + * RTUINT128U wrapper for ASMAtomicCmpWriteU128. + */ +DECLINLINE(bool) ASMAtomicCmpWriteU128U(volatile RTUINT128U *pu128, const RTUINT128U u128New, + const RTUINT128U u128Old) RT_NOTHROW_DEF +{ +# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + return ASMAtomicCmpWriteU128(&pu128->u, u128New.u, u128Old.u); +# else + return ASMAtomicCmpWriteU128v2(&pu128->u, u128New.s.Hi, u128New.s.Lo, u128Old.s.Hi, u128Old.s.Lo); +# endif +} + +#endif /* RT_ARCH_AMD64 || RT_ARCH_ARM64 */ + +/** + * Atomically Compare and Exchange a pointer value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param ppv Pointer to the value to update. + * @param pvNew The new value to assigned to *ppv. + * @param pvOld The old value to *ppv compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWritePtrVoid + */ +DECLINLINE(bool) ASMAtomicCmpXchgPtrVoid(void RT_FAR * volatile RT_FAR *ppv, const void RT_FAR *pvNew, const void RT_FAR *pvOld) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return ASMAtomicCmpXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pvNew, (uint32_t)pvOld); +#elif ARCH_BITS == 64 + return ASMAtomicCmpXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pvNew, (uint64_t)pvOld); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically Compare and Exchange a pointer value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param ppv Pointer to the value to update. + * @param pvNew The new value to assigned to *ppv. + * @param pvOld The old value to *ppv compare with. + * + * @remarks This is relatively type safe on GCC platforms. + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWritePtr + */ +#ifdef __GNUC__ +# define ASMAtomicCmpXchgPtr(ppv, pvNew, pvOld) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + __typeof__(*(ppv)) const pvNewTypeChecked = (pvNew); \ + __typeof__(*(ppv)) const pvOldTypeChecked = (pvOld); \ + bool fMacroRet = ASMAtomicCmpXchgPtrVoid((void * volatile *)ppvTypeChecked, \ + (void *)pvNewTypeChecked, (void *)pvOldTypeChecked); \ + fMacroRet; \ + }) +#else +# define ASMAtomicCmpXchgPtr(ppv, pvNew, pvOld) \ + ASMAtomicCmpXchgPtrVoid((void RT_FAR * volatile RT_FAR *)(ppv), (void RT_FAR *)(pvNew), (void RT_FAR *)(pvOld)) +#endif + + +/** @def ASMAtomicCmpXchgHandle + * Atomically Compare and Exchange a typical IPRT handle value, ordered. + * + * @param ph Pointer to the value to update. + * @param hNew The new value to assigned to *pu. + * @param hOld The old value to *pu compare with. + * @param fRc Where to store the result. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteHandle + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicCmpXchgHandle(ph, hNew, hOld, fRc) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + (fRc) = ASMAtomicCmpXchgU32((uint32_t volatile RT_FAR *)(ph), (const uint32_t)(hNew), (const uint32_t)(hOld)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicCmpXchgHandle(ph, hNew, hOld, fRc) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + (fRc) = ASMAtomicCmpXchgU64((uint64_t volatile RT_FAR *)(ph), (const uint64_t)(hNew), (const uint64_t)(hOld)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** @def ASMAtomicCmpXchgSize + * Atomically Compare and Exchange a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the value to update. + * @param uNew The new value to assigned to *pu. + * @param uOld The old value to *pu compare with. + * @param fRc Where to store the result. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteSize + */ +#define ASMAtomicCmpXchgSize(pu, uNew, uOld, fRc) \ + do { \ + switch (sizeof(*(pu))) { \ + case 4: (fRc) = ASMAtomicCmpXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew), (uint32_t)(uOld)); \ + break; \ + case 8: (fRc) = ASMAtomicCmpXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew), (uint64_t)(uOld)); \ + break; \ + default: AssertMsgFailed(("ASMAtomicCmpXchgSize: size %d is not supported\n", sizeof(*(pu)))); \ + (fRc) = false; \ + break; \ + } \ + } while (0) + + +/** + * Atomically Compare and Exchange an unsigned 8-bit value, additionally passes + * back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu8 Pointer to the value to update. + * @param u8New The new value to assigned to *pu32. + * @param u8Old The old value to *pu8 compare with. + * @param pu8Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgExU8(volatile uint8_t RT_FAR *pu8, const uint8_t u8New, const uint8_t u8Old, uint8_t RT_FAR *pu8Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgExU8(volatile uint8_t RT_FAR *pu8, const uint8_t u8New, const uint8_t u8Old, uint8_t RT_FAR *pu8Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgb %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu8) + , "=qm" (u8Ret) + , "=a" (*pu8Old) +# if defined(RT_ARCH_X86) + : "q" (u8New) +# else + : "r" (u8New) +# endif + , "a" (u8Old) + , "m" (*pu8) + : "cc"); + return (bool)u8Ret; + +# elif RT_INLINE_ASM_USES_INTRIN + return (*pu8Old = _InterlockedCompareExchange8((char RT_FAR *)pu8, u8New, u8Old)) == u8Old; + +# else + uint8_t u8Ret; + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu8] +# else + mov edx, [pu8] +# endif + mov eax, [u8Old] + mov ecx, [u8New] +# ifdef RT_ARCH_AMD64 + lock cmpxchg [rdx], ecx + mov rdx, [pu8Old] + mov [rdx], eax +# else + lock cmpxchg [edx], ecx + mov edx, [pu8Old] + mov [edx], eax +# endif + setz al + movzx eax, al + mov [u8Ret], eax + } + return !!u8Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint8_t u; bool f; } fXchg; + uint8_t u8ActualOld; + uint8_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgExU8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrb %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxrb %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgExU8_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexb %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexbeq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgExU8_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu8) + , [uOld] "=&r" (u8ActualOld) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u8Old) + , [uNew] "r" (u8New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + *pu8Old = u8ActualOld; + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 8-bit value, additionally + * passes back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi8 Pointer to the value to update. + * @param i8New The new value to assigned to *pi8. + * @param i8Old The old value to *pi8 compare with. + * @param pi8Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExS8(volatile int8_t RT_FAR *pi8, const int8_t i8New, const int8_t i8Old, int8_t RT_FAR *pi8Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgExU8((volatile uint8_t RT_FAR *)pi8, (uint8_t)i8New, (uint8_t)i8Old, (uint8_t RT_FAR *)pi8Old); +} + + +/** + * Atomically Compare and Exchange an unsigned 16-bit value, additionally passes + * back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu16 Pointer to the value to update. + * @param u16New The new value to assigned to *pu16. + * @param u16Old The old value to *pu32 compare with. + * @param pu16Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgExU16(volatile uint16_t RT_FAR *pu16, const uint16_t u16New, const uint16_t u16Old, uint16_t RT_FAR *pu16Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgExU16(volatile uint16_t RT_FAR *pu16, const uint16_t u16New, const uint16_t u16Old, uint16_t RT_FAR *pu16Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgw %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu16) + , "=qm" (u8Ret) + , "=a" (*pu16Old) + : "r" (u16New) + , "a" (u16Old) + , "m" (*pu16) + : "cc"); + return (bool)u8Ret; + +# elif RT_INLINE_ASM_USES_INTRIN + return (*pu16Old = _InterlockedCompareExchange16((short RT_FAR *)pu16, u16New, u16Old)) == u16Old; + +# else + uint16_t u16Ret; + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu16] +# else + mov edx, [pu16] +# endif + mov eax, [u16Old] + mov ecx, [u16New] +# ifdef RT_ARCH_AMD64 + lock cmpxchg [rdx], ecx + mov rdx, [pu16Old] + mov [rdx], eax +# else + lock cmpxchg [edx], ecx + mov edx, [pu16Old] + mov [edx], eax +# endif + setz al + movzx eax, al + mov [u16Ret], eax + } + return !!u16Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint16_t u; bool f; } fXchg; + uint16_t u16ActualOld; + uint16_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgExU16_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrh %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxrh %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgExU16_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexh %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexheq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgExU16_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu16) + , [uOld] "=&r" (u16ActualOld) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u16Old) + , [uNew] "r" (u16New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + *pu16Old = u16ActualOld; + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 16-bit value, additionally + * passes back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi16 Pointer to the value to update. + * @param i16New The new value to assigned to *pi16. + * @param i16Old The old value to *pi16 compare with. + * @param pi16Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExS16(volatile int16_t RT_FAR *pi16, const int16_t i16New, const int16_t i16Old, int16_t RT_FAR *pi16Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgExU16((volatile uint16_t RT_FAR *)pi16, (uint16_t)i16New, (uint16_t)i16Old, (uint16_t RT_FAR *)pi16Old); +} + + +/** + * Atomically Compare and Exchange an unsigned 32-bit value, additionally + * passes back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu32 Pointer to the value to update. + * @param u32New The new value to assigned to *pu32. + * @param u32Old The old value to *pu32 compare with. + * @param pu32Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgExU32(volatile uint32_t RT_FAR *pu32, const uint32_t u32New, const uint32_t u32Old, uint32_t RT_FAR *pu32Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgExU32(volatile uint32_t RT_FAR *pu32, const uint32_t u32New, const uint32_t u32Old, uint32_t RT_FAR *pu32Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgl %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu32) + , "=qm" (u8Ret) + , "=a" (*pu32Old) + : "r" (u32New) + , "a" (u32Old) + , "m" (*pu32) + : "cc"); + return (bool)u8Ret; + +# elif RT_INLINE_ASM_USES_INTRIN + return (*pu32Old = _InterlockedCompareExchange((long RT_FAR *)pu32, u32New, u32Old)) == u32Old; + +# else + uint32_t u32Ret; + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] +# else + mov edx, [pu32] +# endif + mov eax, [u32Old] + mov ecx, [u32New] +# ifdef RT_ARCH_AMD64 + lock cmpxchg [rdx], ecx + mov rdx, [pu32Old] + mov [rdx], eax +# else + lock cmpxchg [edx], ecx + mov edx, [pu32Old] + mov [edx], eax +# endif + setz al + movzx eax, al + mov [u32Ret], eax + } + return !!u32Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint32_t u32ActualOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgExU32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgExU32_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrex %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexeq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgExU32_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu32) + , [uOld] "=&r" (u32ActualOld) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u32Old) + , [uNew] "r" (u32New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + *pu32Old = u32ActualOld; + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 32-bit value, additionally + * passes back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi32 Pointer to the value to update. + * @param i32New The new value to assigned to *pi32. + * @param i32Old The old value to *pi32 compare with. + * @param pi32Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExS32(volatile int32_t RT_FAR *pi32, const int32_t i32New, const int32_t i32Old, int32_t RT_FAR *pi32Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgExU32((volatile uint32_t RT_FAR *)pi32, (uint32_t)i32New, (uint32_t)i32Old, (uint32_t RT_FAR *)pi32Old); +} + + +/** + * Atomically Compare and exchange an unsigned 64-bit value, additionally + * passing back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu64 Pointer to the 64-bit variable to update. + * @param u64New The 64-bit value to assign to *pu64. + * @param u64Old The value to compare with. + * @param pu64Old Pointer store the old value at. + * + * @remarks x86: Requires a Pentium or later. + */ +#if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgExU64(volatile uint64_t RT_FAR *pu64, const uint64_t u64New, const uint64_t u64Old, uint64_t RT_FAR *pu64Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgExU64(volatile uint64_t RT_FAR *pu64, const uint64_t u64New, const uint64_t u64Old, uint64_t RT_FAR *pu64Old) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return (*pu64Old =_InterlockedCompareExchange64((__int64 RT_FAR *)pu64, u64New, u64Old)) == u64Old; + +# elif defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgq %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu64) + , "=qm" (u8Ret) + , "=a" (*pu64Old) + : "r" (u64New) + , "a" (u64Old) + , "m" (*pu64) + : "cc"); + return (bool)u8Ret; +# else + bool fRet; + __asm + { + mov rdx, [pu32] + mov rax, [u64Old] + mov rcx, [u64New] + lock cmpxchg [rdx], rcx + mov rdx, [pu64Old] + mov [rdx], rax + setz al + mov [fRet], al + } + return fRet; +# endif + +# elif defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint64_t u64Ret; +# if defined(PIC) || defined(__PIC__) + /* Note #1: This code uses a memory clobber description, because the clean + solution with an output value for *pu64 makes gcc run out of + registers. This will cause suboptimal code, and anyone with a + better solution is welcome to improve this. + + Note #2: We must prevent gcc from encoding the memory access, as it + may go via the GOT if we're working on a global variable (like + in the testcase). Thus we request a register (%3) and + dereference it ourselves. */ + __asm__ __volatile__("xchgl %%ebx, %1\n\t" + "lock; cmpxchg8b (%3)\n\t" + "xchgl %%ebx, %1\n\t" + : "=A" (u64Ret) + : "DS" ((uint32_t)u64New) + , "c" ((uint32_t)(u64New >> 32)) + , "r" (pu64) /* Do not use "m" here*/ + , "0" (u64Old) + : "memory" + , "cc" ); +# else /* !PIC */ + __asm__ __volatile__("lock; cmpxchg8b %4\n\t" + : "=A" (u64Ret) + , "=m" (*pu64) + : "b" ((uint32_t)u64New) + , "c" ((uint32_t)(u64New >> 32)) + , "m" (*pu64) + , "0" (u64Old) + : "cc"); +# endif + *pu64Old = u64Ret; + return u64Ret == u64Old; +# else + uint32_t u32Ret; + __asm + { + mov ebx, dword ptr [u64New] + mov ecx, dword ptr [u64New + 4] + mov edi, [pu64] + mov eax, dword ptr [u64Old] + mov edx, dword ptr [u64Old + 4] + lock cmpxchg8b [edi] + mov ebx, [pu64Old] + mov [ebx], eax + setz al + movzx eax, al + add ebx, 4 + mov [ebx], edx + mov dword ptr [u32Ret], eax + } + return !!u32Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint64_t u64ActualOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgU64_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %[uOld], %[pMem]\n\t" + "cmp %[uOld], %[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxr %w[rc], %[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgU64_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexd %[uOld], %H[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "teqeq %H[uOld], %H[uCmp]\n\t" + "strexdeq %[rc], %[uNew], %H[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgU64_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu64) + , [uOld] "=&r" (u64ActualOld) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u64Old) + , [uNew] "r" (u64New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + *pu64Old = u64ActualOld; + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and exchange a signed 64-bit value, additionally + * passing back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi64 Pointer to the 64-bit variable to update. + * @param i64 The 64-bit value to assign to *pu64. + * @param i64Old The value to compare with. + * @param pi64Old Pointer store the old value at. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExS64(volatile int64_t RT_FAR *pi64, const int64_t i64, const int64_t i64Old, int64_t RT_FAR *pi64Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgExU64((volatile uint64_t RT_FAR *)pi64, (uint64_t)i64, (uint64_t)i64Old, (uint64_t RT_FAR *)pi64Old); +} + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING) + +/** @def RTASM_HAVE_CMP_XCHG_U128 + * Indicates that we've got ASMAtomicCmpSwapU128(), ASMAtomicCmpSwapU128v2() + * and ASMAtomicCmpSwapExU128() available. */ +# define RTASM_HAVE_CMP_XCHG_U128 1 + + +/** + * Atomically compare and exchange an unsigned 128-bit value, ordered. + * + * @returns true if exchange was done. + * @returns false if exchange wasn't done. + * + * @param pu128 Pointer to the 128-bit variable to update. + * @param u64NewHi The high 64 bits of the value to assign to *pu128. + * @param u64NewLo The low 64 bits of the value to assign to *pu128. + * @param u64OldHi The high 64-bit of the value to compare with. + * @param u64OldLo The low 64-bit of the value to compare with. + * @param pu128Old Where to return the old value. + * + * @remarks AMD64: Not present in the earliest CPUs, so check CPUID. + */ +# if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) +DECLASM(bool) ASMAtomicCmpXchgU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo, + const uint64_t u64OldHi, const uint64_t u64OldLo, uint128_t *pu128Old) RT_NOTHROW_PROTO; +# else +DECLINLINE(bool) ASMAtomicCmpXchgU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo, + const uint64_t u64OldHi, const uint64_t u64OldLo, uint128_t *pu128Old) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + pu128Old->Hi = u64OldHi; + pu128Old->Lo = u64OldLo; + AssertCompileMemberOffset(uint128_t, Lo, 0); + return _InterlockedCompareExchange128((__int64 volatile *)pu128, u64NewHi, u64NewLo, (__int64 *)&pu128Old->Lo) != 0; + +# elif (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + uint128_t const uCmp = ((uint128_t)u64OldHi << 64) | u64OldLo; + uint128_t const uOld = __sync_val_compare_and_swap(pu128, uCmp, ((uint128_t)u64NewHi << 64) | u64NewLo); + *pu128Old = uOld; + return uCmp == uOld; + +# elif defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t bRet; + uint64_t u64RetHi, u64RetLo; + __asm__ __volatile__("lock; cmpxchg16b %3\n\t" + "setz %b0\n\t" + : "=r" (bRet) + , "=a" (u64RetLo) + , "=d" (u64RetHi) + , "+m" (*pu128) + : "a" (u64OldLo) + , "d" (u64OldHi) + , "b" (u64NewLo) + , "c" (u64NewHi) + : "cc"); + *pu128Old = ((uint128_t)u64RetHi << 64) | u64RetLo; + return (bool)bRet; +# else +# error "Port me" +# endif +# else +# error "Port me" +# endif +} +# endif + + +/** + * Atomically compare and exchange an unsigned 128-bit value, ordered. + * + * @returns true if exchange was done. + * @returns false if exchange wasn't done. + * + * @param pu128 Pointer to the 128-bit variable to update. + * @param u128New The 128-bit value to assign to *pu128. + * @param u128Old The value to compare with. + * @param pu128Old Where to return the old value. + * + * @remarks AMD64: Not present in the earliest CPUs, so check CPUID. + */ +DECLINLINE(bool) ASMAtomicCmpXchgU128(volatile uint128_t *pu128, const uint128_t u128New, + const uint128_t u128Old, uint128_t *pu128Old) RT_NOTHROW_DEF +{ +# ifdef RT_COMPILER_WITH_128BIT_INT_TYPES +# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + uint128_t const uSwapped = __sync_val_compare_and_swap(pu128, u128Old, u128New); + *pu128Old = uSwapped; + return uSwapped == u128Old; +# else + return ASMAtomicCmpXchgU128v2(pu128, (uint64_t)(u128New >> 64), (uint64_t)u128New, + (uint64_t)(u128Old >> 64), (uint64_t)u128Old, pu128Old); +# endif +# else + return ASMAtomicCmpXchgU128v2(pu128, u128New.Hi, u128New.Lo, u128Old.Hi, u128Old.Lo, pu128Old); +# endif +} + + +/** + * RTUINT128U wrapper for ASMAtomicCmpXchgU128. + */ +DECLINLINE(bool) ASMAtomicCmpXchgU128U(volatile RTUINT128U *pu128, const RTUINT128U u128New, + const RTUINT128U u128Old, PRTUINT128U pu128Old) RT_NOTHROW_DEF +{ +# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + return ASMAtomicCmpXchgU128(&pu128->u, u128New.u, u128Old.u, &pu128Old->u); +# else + return ASMAtomicCmpXchgU128v2(&pu128->u, u128New.s.Hi, u128New.s.Lo, u128Old.s.Hi, u128Old.s.Lo, &pu128Old->u); +# endif +} + +#endif /* RT_ARCH_AMD64 || RT_ARCH_ARM64 */ + + + +/** @def ASMAtomicCmpXchgExHandle + * Atomically Compare and Exchange a typical IPRT handle value, ordered. + * + * @param ph Pointer to the value to update. + * @param hNew The new value to assigned to *pu. + * @param hOld The old value to *pu compare with. + * @param fRc Where to store the result. + * @param phOldVal Pointer to where to store the old value. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicCmpXchgExHandle(ph, hNew, hOld, fRc, phOldVal) \ + do { \ + AssertCompile(sizeof(*ph) == sizeof(uint32_t)); \ + AssertCompile(sizeof(*phOldVal) == sizeof(uint32_t)); \ + (fRc) = ASMAtomicCmpXchgExU32((volatile uint32_t RT_FAR *)(ph), (uint32_t)(hNew), (uint32_t)(hOld), (uint32_t RT_FAR *)(phOldVal)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicCmpXchgExHandle(ph, hNew, hOld, fRc, phOldVal) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + AssertCompile(sizeof(*(phOldVal)) == sizeof(uint64_t)); \ + (fRc) = ASMAtomicCmpXchgExU64((volatile uint64_t RT_FAR *)(ph), (uint64_t)(hNew), (uint64_t)(hOld), (uint64_t RT_FAR *)(phOldVal)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** @def ASMAtomicCmpXchgExSize + * Atomically Compare and Exchange a value which size might differ + * between platforms or compilers. Additionally passes back old value. + * + * @param pu Pointer to the value to update. + * @param uNew The new value to assigned to *pu. + * @param uOld The old value to *pu compare with. + * @param fRc Where to store the result. + * @param puOldVal Pointer to where to store the old value. + * + * @remarks x86: Requires a 486 or later. + */ +#define ASMAtomicCmpXchgExSize(pu, uNew, uOld, fRc, puOldVal) \ + do { \ + switch (sizeof(*(pu))) { \ + case 4: (fRc) = ASMAtomicCmpXchgExU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew), (uint32_t)(uOld), (uint32_t RT_FAR *)(uOldVal)); \ + break; \ + case 8: (fRc) = ASMAtomicCmpXchgExU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew), (uint64_t)(uOld), (uint64_t RT_FAR *)(uOldVal)); \ + break; \ + default: AssertMsgFailed(("ASMAtomicCmpXchgSize: size %d is not supported\n", sizeof(*(pu)))); \ + (fRc) = false; \ + (uOldVal) = 0; \ + break; \ + } \ + } while (0) + + +/** + * Atomically Compare and Exchange a pointer value, additionally + * passing back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param ppv Pointer to the value to update. + * @param pvNew The new value to assigned to *ppv. + * @param pvOld The old value to *ppv compare with. + * @param ppvOld Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExPtrVoid(void RT_FAR * volatile RT_FAR *ppv, const void RT_FAR *pvNew, const void RT_FAR *pvOld, + void RT_FAR * RT_FAR *ppvOld) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return ASMAtomicCmpXchgExU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pvNew, (uint32_t)pvOld, (uint32_t RT_FAR *)ppvOld); +#elif ARCH_BITS == 64 + return ASMAtomicCmpXchgExU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pvNew, (uint64_t)pvOld, (uint64_t RT_FAR *)ppvOld); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically Compare and Exchange a pointer value, additionally + * passing back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param ppv Pointer to the value to update. + * @param pvNew The new value to assigned to *ppv. + * @param pvOld The old value to *ppv compare with. + * @param ppvOld Pointer store the old value at. + * + * @remarks This is relatively type safe on GCC platforms. + * @remarks x86: Requires a 486 or later. + */ +#ifdef __GNUC__ +# define ASMAtomicCmpXchgExPtr(ppv, pvNew, pvOld, ppvOld) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + __typeof__(*(ppv)) const pvNewTypeChecked = (pvNew); \ + __typeof__(*(ppv)) const pvOldTypeChecked = (pvOld); \ + __typeof__(*(ppv)) * const ppvOldTypeChecked = (ppvOld); \ + bool fMacroRet = ASMAtomicCmpXchgExPtrVoid((void * volatile *)ppvTypeChecked, \ + (void *)pvNewTypeChecked, (void *)pvOldTypeChecked, \ + (void **)ppvOldTypeChecked); \ + fMacroRet; \ + }) +#else +# define ASMAtomicCmpXchgExPtr(ppv, pvNew, pvOld, ppvOld) \ + ASMAtomicCmpXchgExPtrVoid((void RT_FAR * volatile RT_FAR *)(ppv), (void RT_FAR *)(pvNew), (void RT_FAR *)(pvOld), (void RT_FAR * RT_FAR *)(ppvOld)) +#endif + + +/** + * Virtualization unfriendly serializing instruction, always exits. + */ +#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSerializeInstructionCpuId(void) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMSerializeInstructionCpuId(void) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG xAX = 0; +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__ ("cpuid" + : "=a" (xAX) + : "0" (xAX) + : "rbx", "rcx", "rdx", "memory"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ __volatile__ ("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx\n\t" + : "=a" (xAX) + : "0" (xAX) + : "ecx", "edx", "memory"); +# else + __asm__ __volatile__ ("cpuid" + : "=a" (xAX) + : "0" (xAX) + : "ebx", "ecx", "edx", "memory"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + _ReadWriteBarrier(); + __cpuid(aInfo, 0); + +# else + __asm + { + push ebx + xor eax, eax + cpuid + pop ebx + } +# endif +} +#endif + +/** + * Virtualization friendly serializing instruction, though more expensive. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSerializeInstructionIRet(void) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMSerializeInstructionIRet(void) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__ ("movq %%rsp,%%r10\n\t" + "subq $128, %%rsp\n\t" /*redzone*/ + "mov %%ss, %%eax\n\t" + "pushq %%rax\n\t" + "pushq %%r10\n\t" + "pushfq\n\t" + "movl %%cs, %%eax\n\t" + "pushq %%rax\n\t" + "leaq 1f(%%rip), %%rax\n\t" + "pushq %%rax\n\t" + "iretq\n\t" + "1:\n\t" + ::: "rax", "r10", "memory", "cc"); +# else + __asm__ __volatile__ ("pushfl\n\t" + "pushl %%cs\n\t" + "pushl $1f\n\t" + "iretl\n\t" + "1:\n\t" + ::: "memory"); +# endif + +# else + __asm + { + pushfd + push cs + push la_ret + iretd + la_ret: + } +# endif +} +#endif + +/** + * Virtualization friendlier serializing instruction, may still cause exits. + */ +#if (RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2008) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSerializeInstructionRdTscp(void) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMSerializeInstructionRdTscp(void) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE + /* rdtscp is not supported by ancient linux build VM of course :-( */ +# ifdef RT_ARCH_AMD64 + /*__asm__ __volatile__("rdtscp\n\t" ::: "rax", "rdx, "rcx"); */ + __asm__ __volatile__(".byte 0x0f,0x01,0xf9\n\t" ::: "rax", "rdx", "rcx", "memory"); +# else + /*__asm__ __volatile__("rdtscp\n\t" ::: "eax", "edx, "ecx"); */ + __asm__ __volatile__(".byte 0x0f,0x01,0xf9\n\t" ::: "eax", "edx", "ecx", "memory"); +# endif +# else +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + uint32_t uIgnore; + _ReadWriteBarrier(); + (void)__rdtscp(&uIgnore); + (void)uIgnore; +# else + __asm + { + rdtscp + } +# endif +# endif +} +#endif + + +/** + * Serialize Instruction (both data store and instruction flush). + */ +#if (defined(RT_ARCH_X86) && ARCH_BITS == 16) || defined(IN_GUEST) +# define ASMSerializeInstruction() ASMSerializeInstructionIRet() +#elif defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +# define ASMSerializeInstruction() ASMSerializeInstructionCpuId() +#elif defined(RT_ARCH_SPARC64) +RTDECL(void) ASMSerializeInstruction(void) RT_NOTHROW_PROTO; +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) +DECLINLINE(void) ASMSerializeInstruction(void) RT_NOTHROW_DEF +{ + __asm__ __volatile__ (RTASM_ARM_DSB_SY :: RTASM_ARM_DSB_SY_IN_REG :); +} +#else +# error "Port me" +#endif + + +/** + * Memory fence, waits for any pending writes and reads to complete. + * @note No implicit compiler barrier (which is probably stupid). + */ +DECLINLINE(void) ASMMemoryFence(void) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_AMD64) || (defined(RT_ARCH_X86) && !defined(RT_WITH_OLD_CPU_SUPPORT)) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xf0\n\t"); +# elif RT_INLINE_ASM_USES_INTRIN + _mm_mfence(); +# else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xf0 + } +# endif +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__ (RTASM_ARM_DMB_SY :: RTASM_ARM_DMB_SY_IN_REG :); +#elif ARCH_BITS == 16 + uint16_t volatile u16; + ASMAtomicXchgU16(&u16, 0); +#else + uint32_t volatile u32; + ASMAtomicXchgU32(&u32, 0); +#endif +} + + +/** + * Write fence, waits for any pending writes to complete. + * @note No implicit compiler barrier (which is probably stupid). + */ +DECLINLINE(void) ASMWriteFence(void) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_AMD64) || (defined(RT_ARCH_X86) && !defined(RT_WITH_OLD_CPU_SUPPORT)) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xf8\n\t"); +# elif RT_INLINE_ASM_USES_INTRIN + _mm_sfence(); +# else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xf8 + } +# endif +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__ (RTASM_ARM_DMB_ST :: RTASM_ARM_DMB_ST_IN_REG :); +#else + ASMMemoryFence(); +#endif +} + + +/** + * Read fence, waits for any pending reads to complete. + * @note No implicit compiler barrier (which is probably stupid). + */ +DECLINLINE(void) ASMReadFence(void) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_AMD64) || (defined(RT_ARCH_X86) && !defined(RT_WITH_OLD_CPU_SUPPORT)) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xe8\n\t"); +# elif RT_INLINE_ASM_USES_INTRIN + _mm_lfence(); +# else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xe8 + } +# endif +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__ (RTASM_ARM_DMB_LD :: RTASM_ARM_DMB_LD_IN_REG :); +#else + ASMMemoryFence(); +#endif +} + + +/** + * Atomically reads an unsigned 8-bit value, ordered. + * + * @returns Current *pu8 value + * @param pu8 Pointer to the 8-bit variable to read. + */ +DECLINLINE(uint8_t) ASMAtomicReadU8(volatile uint8_t RT_FAR *pu8) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicReadU8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxrb %w[uDst], %[pMem]\n\t" +# else + "ldrexb %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu8) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return (uint8_t)u32; +#else + ASMMemoryFence(); + return *pu8; /* byte reads are atomic on x86 */ +#endif +} + + +/** + * Atomically reads an unsigned 8-bit value, unordered. + * + * @returns Current *pu8 value + * @param pu8 Pointer to the 8-bit variable to read. + */ +DECLINLINE(uint8_t) ASMAtomicUoReadU8(volatile uint8_t RT_FAR *pu8) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadU8_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrb %w[uDst], %[pMem]\n\t" +# else + "ldrexb %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu8)); + return (uint8_t)u32; +#else + return *pu8; /* byte reads are atomic on x86 */ +#endif +} + + +/** + * Atomically reads a signed 8-bit value, ordered. + * + * @returns Current *pi8 value + * @param pi8 Pointer to the 8-bit variable to read. + */ +DECLINLINE(int8_t) ASMAtomicReadS8(volatile int8_t RT_FAR *pi8) RT_NOTHROW_DEF +{ + ASMMemoryFence(); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicReadS8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxrb %w[iDst], %[pMem]\n\t" +# else + "ldrexb %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi8) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return (int8_t)i32; +#else + return *pi8; /* byte reads are atomic on x86 */ +#endif +} + + +/** + * Atomically reads a signed 8-bit value, unordered. + * + * @returns Current *pi8 value + * @param pi8 Pointer to the 8-bit variable to read. + */ +DECLINLINE(int8_t) ASMAtomicUoReadS8(volatile int8_t RT_FAR *pi8) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadS8_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrb %w[iDst], %[pMem]\n\t" +# else + "ldrexb %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi8)); + return (int8_t)i32; +#else + return *pi8; /* byte reads are atomic on x86 */ +#endif +} + + +/** + * Atomically reads an unsigned 16-bit value, ordered. + * + * @returns Current *pu16 value + * @param pu16 Pointer to the 16-bit variable to read. + */ +DECLINLINE(uint16_t) ASMAtomicReadU16(volatile uint16_t RT_FAR *pu16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu16 & 1)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicReadU16_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxrh %w[uDst], %[pMem]\n\t" +# else + "ldrexh %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu16) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return (uint16_t)u32; +#else + ASMMemoryFence(); + return *pu16; +#endif +} + + +/** + * Atomically reads an unsigned 16-bit value, unordered. + * + * @returns Current *pu16 value + * @param pu16 Pointer to the 16-bit variable to read. + */ +DECLINLINE(uint16_t) ASMAtomicUoReadU16(volatile uint16_t RT_FAR *pu16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu16 & 1)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadU16_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrh %w[uDst], %[pMem]\n\t" +# else + "ldrexh %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu16)); + return (uint16_t)u32; +#else + return *pu16; +#endif +} + + +/** + * Atomically reads a signed 16-bit value, ordered. + * + * @returns Current *pi16 value + * @param pi16 Pointer to the 16-bit variable to read. + */ +DECLINLINE(int16_t) ASMAtomicReadS16(volatile int16_t RT_FAR *pi16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi16 & 1)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicReadS16_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxrh %w[iDst], %[pMem]\n\t" +# else + "ldrexh %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi16) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return (int16_t)i32; +#else + ASMMemoryFence(); + return *pi16; +#endif +} + + +/** + * Atomically reads a signed 16-bit value, unordered. + * + * @returns Current *pi16 value + * @param pi16 Pointer to the 16-bit variable to read. + */ +DECLINLINE(int16_t) ASMAtomicUoReadS16(volatile int16_t RT_FAR *pi16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi16 & 1)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadS16_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrh %w[iDst], %[pMem]\n\t" +# else + "ldrexh %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi16)); + return (int16_t)i32; +#else + return *pi16; +#endif +} + + +/** + * Atomically reads an unsigned 32-bit value, ordered. + * + * @returns Current *pu32 value + * @param pu32 Pointer to the 32-bit variable to read. + */ +DECLINLINE(uint32_t) ASMAtomicReadU32(volatile uint32_t RT_FAR *pu32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu32 & 3)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicReadU32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxr %w[uDst], %[pMem]\n\t" +# else + "ldrex %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu32) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return u32; +#else + ASMMemoryFence(); +# if ARCH_BITS == 16 + AssertFailed(); /** @todo 16-bit */ +# endif + return *pu32; +#endif +} + + +/** + * Atomically reads an unsigned 32-bit value, unordered. + * + * @returns Current *pu32 value + * @param pu32 Pointer to the 32-bit variable to read. + */ +DECLINLINE(uint32_t) ASMAtomicUoReadU32(volatile uint32_t RT_FAR *pu32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu32 & 3)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadU32_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxr %w[uDst], %[pMem]\n\t" +# else + "ldrex %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu32)); + return u32; +#else +# if ARCH_BITS == 16 + AssertFailed(); /** @todo 16-bit */ +# endif + return *pu32; +#endif +} + + +/** + * Atomically reads a signed 32-bit value, ordered. + * + * @returns Current *pi32 value + * @param pi32 Pointer to the 32-bit variable to read. + */ +DECLINLINE(int32_t) ASMAtomicReadS32(volatile int32_t RT_FAR *pi32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi32 & 3)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicReadS32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxr %w[iDst], %[pMem]\n\t" +# else + "ldrex %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi32) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return i32; +#else + ASMMemoryFence(); +# if ARCH_BITS == 16 + AssertFailed(); /** @todo 16-bit */ +# endif + return *pi32; +#endif +} + + +/** + * Atomically reads a signed 32-bit value, unordered. + * + * @returns Current *pi32 value + * @param pi32 Pointer to the 32-bit variable to read. + */ +DECLINLINE(int32_t) ASMAtomicUoReadS32(volatile int32_t RT_FAR *pi32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi32 & 3)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadS32_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxr %w[iDst], %[pMem]\n\t" +# else + "ldrex %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi32)); + return i32; + +#else +# if ARCH_BITS == 16 + AssertFailed(); /** @todo 16-bit */ +# endif + return *pi32; +#endif +} + + +/** + * Atomically reads an unsigned 64-bit value, ordered. + * + * @returns Current *pu64 value + * @param pu64 Pointer to the 64-bit variable to read. + * The memory pointed to must be writable. + * + * @remarks This may fault if the memory is read-only! + * @remarks x86: Requires a Pentium or later. + */ +#if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !defined(RT_ARCH_AMD64)) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMAtomicReadU64(volatile uint64_t RT_FAR *pu64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicReadU64(volatile uint64_t RT_FAR *pu64) RT_NOTHROW_DEF +{ + uint64_t u64; +# ifdef RT_ARCH_AMD64 + Assert(!((uintptr_t)pu64 & 7)); +/*# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__( "mfence\n\t" + "movq %1, %0\n\t" + : "=r" (u64) + : "m" (*pu64)); +# else + __asm + { + mfence + mov rdx, [pu64] + mov rax, [rdx] + mov [u64], rax + } +# endif*/ + ASMMemoryFence(); + u64 = *pu64; + +# elif defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE +# if defined(PIC) || defined(__PIC__) + uint32_t u32EBX = 0; + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__("xchgl %%ebx, %3\n\t" + "lock; cmpxchg8b (%5)\n\t" + "movl %3, %%ebx\n\t" + : "=A" (u64) +# if RT_GNUC_PREREQ(4, 3) + , "+m" (*pu64) +# else + , "=m" (*pu64) +# endif + : "0" (0ULL) + , "m" (u32EBX) + , "c" (0) + , "S" (pu64) + : "cc"); +# else /* !PIC */ + __asm__ __volatile__("lock; cmpxchg8b %1\n\t" + : "=A" (u64) + , "+m" (*pu64) + : "0" (0ULL) + , "b" (0) + , "c" (0) + : "cc"); +# endif +# else + Assert(!((uintptr_t)pu64 & 7)); + __asm + { + xor eax, eax + xor edx, edx + mov edi, pu64 + xor ecx, ecx + xor ebx, ebx + lock cmpxchg8b [edi] + mov dword ptr [u64], eax + mov dword ptr [u64 + 4], edx + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__(".Lstart_ASMAtomicReadU64_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxr %[uDst], %[pMem]\n\t" +# else + "ldrexd %[uDst], %H[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u64) + : [pMem] "Q" (*pu64) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + +# else +# error "Port me" +# endif + return u64; +} +#endif + + +/** + * Atomically reads an unsigned 64-bit value, unordered. + * + * @returns Current *pu64 value + * @param pu64 Pointer to the 64-bit variable to read. + * The memory pointed to must be writable. + * + * @remarks This may fault if the memory is read-only! + * @remarks x86: Requires a Pentium or later. + */ +#if !defined(RT_ARCH_AMD64) \ + && ( (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC) +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMAtomicUoReadU64(volatile uint64_t RT_FAR *pu64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicUoReadU64(volatile uint64_t RT_FAR *pu64) RT_NOTHROW_DEF +{ + uint64_t u64; +# ifdef RT_ARCH_AMD64 + Assert(!((uintptr_t)pu64 & 7)); +/*# if RT_INLINE_ASM_GNU_STYLE + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__("movq %1, %0\n\t" + : "=r" (u64) + : "m" (*pu64)); +# else + __asm + { + mov rdx, [pu64] + mov rax, [rdx] + mov [u64], rax + } +# endif */ + u64 = *pu64; + +# elif defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE +# if defined(PIC) || defined(__PIC__) + uint32_t u32EBX = 0; + uint32_t u32Spill; + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__("xor %%eax,%%eax\n\t" + "xor %%ecx,%%ecx\n\t" + "xor %%edx,%%edx\n\t" + "xchgl %%ebx, %3\n\t" + "lock; cmpxchg8b (%4)\n\t" + "movl %3, %%ebx\n\t" + : "=A" (u64) +# if RT_GNUC_PREREQ(4, 3) + , "+m" (*pu64) +# else + , "=m" (*pu64) +# endif + , "=c" (u32Spill) + : "m" (u32EBX) + , "S" (pu64) + : "cc"); +# else /* !PIC */ + __asm__ __volatile__("lock; cmpxchg8b %1\n\t" + : "=A" (u64) + , "+m" (*pu64) + : "0" (0ULL) + , "b" (0) + , "c" (0) + : "cc"); +# endif +# else + Assert(!((uintptr_t)pu64 & 7)); + __asm + { + xor eax, eax + xor edx, edx + mov edi, pu64 + xor ecx, ecx + xor ebx, ebx + lock cmpxchg8b [edi] + mov dword ptr [u64], eax + mov dword ptr [u64 + 4], edx + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__(".Lstart_ASMAtomicUoReadU64_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxr %[uDst], %[pMem]\n\t" +# else + "ldrexd %[uDst], %H[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u64) + : [pMem] "Q" (*pu64)); + +# else +# error "Port me" +# endif + return u64; +} +#endif + + +/** + * Atomically reads a signed 64-bit value, ordered. + * + * @returns Current *pi64 value + * @param pi64 Pointer to the 64-bit variable to read. + * The memory pointed to must be writable. + * + * @remarks This may fault if the memory is read-only! + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicReadS64(volatile int64_t RT_FAR *pi64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicReadU64((volatile uint64_t RT_FAR *)pi64); +} + + +/** + * Atomically reads a signed 64-bit value, unordered. + * + * @returns Current *pi64 value + * @param pi64 Pointer to the 64-bit variable to read. + * The memory pointed to must be writable. + * + * @remarks This will fault if the memory is read-only! + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicUoReadS64(volatile int64_t RT_FAR *pi64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicUoReadU64((volatile uint64_t RT_FAR *)pi64); +} + + +/** + * Atomically reads a size_t value, ordered. + * + * @returns Current *pcb value + * @param pcb Pointer to the size_t variable to read. + */ +DECLINLINE(size_t) ASMAtomicReadZ(size_t volatile RT_FAR *pcb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + return ASMAtomicReadU64((uint64_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 32 + return ASMAtomicReadU32((uint32_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + return ASMAtomicReadU16((uint16_t volatile RT_FAR *)pcb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically reads a size_t value, unordered. + * + * @returns Current *pcb value + * @param pcb Pointer to the size_t variable to read. + */ +DECLINLINE(size_t) ASMAtomicUoReadZ(size_t volatile RT_FAR *pcb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 || ARCH_BITS == 16 + return ASMAtomicUoReadU64((uint64_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 32 + return ASMAtomicUoReadU32((uint32_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + return ASMAtomicUoReadU16((uint16_t volatile RT_FAR *)pcb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically reads a pointer value, ordered. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to read. + * + * @remarks Please use ASMAtomicReadPtrT, it provides better type safety and + * requires less typing (no casts). + */ +DECLINLINE(void RT_FAR *) ASMAtomicReadPtr(void RT_FAR * volatile RT_FAR *ppv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return (void RT_FAR *)ASMAtomicReadU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv); +#elif ARCH_BITS == 64 + return (void RT_FAR *)ASMAtomicReadU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv); +#else +# error "ARCH_BITS is bogus" +#endif +} + +/** + * Convenience macro for avoiding the annoying casting with ASMAtomicReadPtr. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to read. + * @param Type The type of *ppv, sans volatile. + */ +#ifdef __GNUC__ /* 8.2.0 requires -Wno-ignored-qualifiers */ +# define ASMAtomicReadPtrT(ppv, Type) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile *ppvTypeChecked = (ppv); \ + Type pvTypeChecked = (__typeof__(*(ppv))) ASMAtomicReadPtr((void * volatile *)ppvTypeChecked); \ + pvTypeChecked; \ + }) +#else +# define ASMAtomicReadPtrT(ppv, Type) \ + (Type)ASMAtomicReadPtr((void RT_FAR * volatile RT_FAR *)(ppv)) +#endif + + +/** + * Atomically reads a pointer value, unordered. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to read. + * + * @remarks Please use ASMAtomicUoReadPtrT, it provides better type safety and + * requires less typing (no casts). + */ +DECLINLINE(void RT_FAR *) ASMAtomicUoReadPtr(void RT_FAR * volatile RT_FAR *ppv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return (void RT_FAR *)ASMAtomicUoReadU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv); +#elif ARCH_BITS == 64 + return (void RT_FAR *)ASMAtomicUoReadU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Convenience macro for avoiding the annoying casting with ASMAtomicUoReadPtr. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to read. + * @param Type The type of *ppv, sans volatile. + */ +#ifdef __GNUC__ /* 8.2.0 requires -Wno-ignored-qualifiers */ +# define ASMAtomicUoReadPtrT(ppv, Type) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + Type pvTypeChecked = (__typeof__(*(ppv))) ASMAtomicUoReadPtr((void * volatile *)ppvTypeChecked); \ + pvTypeChecked; \ + }) +#else +# define ASMAtomicUoReadPtrT(ppv, Type) \ + (Type)ASMAtomicUoReadPtr((void RT_FAR * volatile RT_FAR *)(ppv)) +#endif + + +/** + * Atomically reads a boolean value, ordered. + * + * @returns Current *pf value + * @param pf Pointer to the boolean variable to read. + */ +DECLINLINE(bool) ASMAtomicReadBool(volatile bool RT_FAR *pf) RT_NOTHROW_DEF +{ + ASMMemoryFence(); + return *pf; /* byte reads are atomic on x86 */ +} + + +/** + * Atomically reads a boolean value, unordered. + * + * @returns Current *pf value + * @param pf Pointer to the boolean variable to read. + */ +DECLINLINE(bool) ASMAtomicUoReadBool(volatile bool RT_FAR *pf) RT_NOTHROW_DEF +{ + return *pf; /* byte reads are atomic on x86 */ +} + + +/** + * Atomically read a typical IPRT handle value, ordered. + * + * @param ph Pointer to the handle variable to read. + * @param phRes Where to store the result. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicReadHandle(ph, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint32_t)); \ + *(uint32_t RT_FAR *)(phRes) = ASMAtomicReadU32((uint32_t volatile RT_FAR *)(ph)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicReadHandle(ph, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint64_t)); \ + *(uint64_t RT_FAR *)(phRes) = ASMAtomicReadU64((uint64_t volatile RT_FAR *)(ph)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically read a typical IPRT handle value, unordered. + * + * @param ph Pointer to the handle variable to read. + * @param phRes Where to store the result. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicUoReadHandle(ph, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint32_t)); \ + *(uint32_t RT_FAR *)(phRes) = ASMAtomicUoReadU32((uint32_t volatile RT_FAR *)(ph)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicUoReadHandle(ph, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint64_t)); \ + *(uint64_t RT_FAR *)(phRes) = ASMAtomicUoReadU64((uint64_t volatile RT_FAR *)(ph)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically read a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the variable to read. + * @param puRes Where to store the result. + */ +#define ASMAtomicReadSize(pu, puRes) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: *(uint8_t RT_FAR *)(puRes) = ASMAtomicReadU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 2: *(uint16_t RT_FAR *)(puRes) = ASMAtomicReadU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 4: *(uint32_t RT_FAR *)(puRes) = ASMAtomicReadU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 8: *(uint64_t RT_FAR *)(puRes) = ASMAtomicReadU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + default: AssertMsgFailed(("ASMAtomicReadSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + +/** + * Atomically read a value which size might differ + * between platforms or compilers, unordered. + * + * @param pu Pointer to the variable to read. + * @param puRes Where to store the result. + */ +#define ASMAtomicUoReadSize(pu, puRes) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: *(uint8_t RT_FAR *)(puRes) = ASMAtomicUoReadU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 2: *(uint16_t RT_FAR *)(puRes) = ASMAtomicUoReadU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 4: *(uint32_t RT_FAR *)(puRes) = ASMAtomicUoReadU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 8: *(uint64_t RT_FAR *)(puRes) = ASMAtomicUoReadU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + default: AssertMsgFailed(("ASMAtomicReadSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + +/** + * Atomically writes an unsigned 8-bit value, ordered. + * + * @param pu8 Pointer to the 8-bit variable. + * @param u8 The 8-bit value to assign to *pu8. + */ +DECLINLINE(void) ASMAtomicWriteU8(volatile uint8_t RT_FAR *pu8, uint8_t u8) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgU8(pu8, u8); +} + + +/** + * Atomically writes an unsigned 8-bit value, unordered. + * + * @param pu8 Pointer to the 8-bit variable. + * @param u8 The 8-bit value to assign to *pu8. + */ +DECLINLINE(void) ASMAtomicUoWriteU8(volatile uint8_t RT_FAR *pu8, uint8_t u8) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 improvements here? */ + *pu8 = u8; /* byte writes are atomic on x86 */ +} + + +/** + * Atomically writes a signed 8-bit value, ordered. + * + * @param pi8 Pointer to the 8-bit variable to read. + * @param i8 The 8-bit value to assign to *pi8. + */ +DECLINLINE(void) ASMAtomicWriteS8(volatile int8_t RT_FAR *pi8, int8_t i8) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgS8(pi8, i8); +} + + +/** + * Atomically writes a signed 8-bit value, unordered. + * + * @param pi8 Pointer to the 8-bit variable to write. + * @param i8 The 8-bit value to assign to *pi8. + */ +DECLINLINE(void) ASMAtomicUoWriteS8(volatile int8_t RT_FAR *pi8, int8_t i8) RT_NOTHROW_DEF +{ + *pi8 = i8; /* byte writes are atomic on x86 */ +} + + +/** + * Atomically writes an unsigned 16-bit value, ordered. + * + * @param pu16 Pointer to the 16-bit variable to write. + * @param u16 The 16-bit value to assign to *pu16. + */ +DECLINLINE(void) ASMAtomicWriteU16(volatile uint16_t RT_FAR *pu16, uint16_t u16) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgU16(pu16, u16); +} + + +/** + * Atomically writes an unsigned 16-bit value, unordered. + * + * @param pu16 Pointer to the 16-bit variable to write. + * @param u16 The 16-bit value to assign to *pu16. + */ +DECLINLINE(void) ASMAtomicUoWriteU16(volatile uint16_t RT_FAR *pu16, uint16_t u16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu16 & 1)); + *pu16 = u16; +} + + +/** + * Atomically writes a signed 16-bit value, ordered. + * + * @param pi16 Pointer to the 16-bit variable to write. + * @param i16 The 16-bit value to assign to *pi16. + */ +DECLINLINE(void) ASMAtomicWriteS16(volatile int16_t RT_FAR *pi16, int16_t i16) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgS16(pi16, i16); +} + + +/** + * Atomically writes a signed 16-bit value, unordered. + * + * @param pi16 Pointer to the 16-bit variable to write. + * @param i16 The 16-bit value to assign to *pi16. + */ +DECLINLINE(void) ASMAtomicUoWriteS16(volatile int16_t RT_FAR *pi16, int16_t i16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi16 & 1)); + *pi16 = i16; +} + + +/** + * Atomically writes an unsigned 32-bit value, ordered. + * + * @param pu32 Pointer to the 32-bit variable to write. + * @param u32 The 32-bit value to assign to *pu32. + */ +DECLINLINE(void) ASMAtomicWriteU32(volatile uint32_t RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgU32(pu32, u32); +} + + +/** + * Atomically writes an unsigned 32-bit value, unordered. + * + * @param pu32 Pointer to the 32-bit variable to write. + * @param u32 The 32-bit value to assign to *pu32. + */ +DECLINLINE(void) ASMAtomicUoWriteU32(volatile uint32_t RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu32 & 3)); +#if ARCH_BITS >= 32 + *pu32 = u32; +#else + ASMAtomicXchgU32(pu32, u32); +#endif +} + + +/** + * Atomically writes a signed 32-bit value, ordered. + * + * @param pi32 Pointer to the 32-bit variable to write. + * @param i32 The 32-bit value to assign to *pi32. + */ +DECLINLINE(void) ASMAtomicWriteS32(volatile int32_t RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicXchgS32(pi32, i32); +} + + +/** + * Atomically writes a signed 32-bit value, unordered. + * + * @param pi32 Pointer to the 32-bit variable to write. + * @param i32 The 32-bit value to assign to *pi32. + */ +DECLINLINE(void) ASMAtomicUoWriteS32(volatile int32_t RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi32 & 3)); +#if ARCH_BITS >= 32 + *pi32 = i32; +#else + ASMAtomicXchgS32(pi32, i32); +#endif +} + + +/** + * Atomically writes an unsigned 64-bit value, ordered. + * + * @param pu64 Pointer to the 64-bit variable to write. + * @param u64 The 64-bit value to assign to *pu64. + */ +DECLINLINE(void) ASMAtomicWriteU64(volatile uint64_t RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgU64(pu64, u64); +} + + +/** + * Atomically writes an unsigned 64-bit value, unordered. + * + * @param pu64 Pointer to the 64-bit variable to write. + * @param u64 The 64-bit value to assign to *pu64. + */ +DECLINLINE(void) ASMAtomicUoWriteU64(volatile uint64_t RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu64 & 7)); +#if ARCH_BITS == 64 + *pu64 = u64; +#else + ASMAtomicXchgU64(pu64, u64); +#endif +} + + +/** + * Atomically writes a signed 64-bit value, ordered. + * + * @param pi64 Pointer to the 64-bit variable to write. + * @param i64 The 64-bit value to assign to *pi64. + */ +DECLINLINE(void) ASMAtomicWriteS64(volatile int64_t RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgS64(pi64, i64); +} + + +/** + * Atomically writes a signed 64-bit value, unordered. + * + * @param pi64 Pointer to the 64-bit variable to write. + * @param i64 The 64-bit value to assign to *pi64. + */ +DECLINLINE(void) ASMAtomicUoWriteS64(volatile int64_t RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi64 & 7)); +#if ARCH_BITS == 64 + *pi64 = i64; +#else + ASMAtomicXchgS64(pi64, i64); +#endif +} + + +/** + * Atomically writes a size_t value, ordered. + * + * @returns nothing. + * @param pcb Pointer to the size_t variable to write. + * @param cb The value to assign to *pcb. + */ +DECLINLINE(void) ASMAtomicWriteZ(volatile size_t RT_FAR *pcb, size_t cb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + ASMAtomicWriteU64((uint64_t volatile *)pcb, cb); +#elif ARCH_BITS == 32 + ASMAtomicWriteU32((uint32_t volatile *)pcb, cb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + ASMAtomicWriteU16((uint16_t volatile *)pcb, cb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically writes a size_t value, unordered. + * + * @returns nothing. + * @param pcb Pointer to the size_t variable to write. + * @param cb The value to assign to *pcb. + */ +DECLINLINE(void) ASMAtomicUoWriteZ(volatile size_t RT_FAR *pcb, size_t cb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + ASMAtomicUoWriteU64((uint64_t volatile *)pcb, cb); +#elif ARCH_BITS == 32 + ASMAtomicUoWriteU32((uint32_t volatile *)pcb, cb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + ASMAtomicUoWriteU16((uint16_t volatile *)pcb, cb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically writes a boolean value, unordered. + * + * @param pf Pointer to the boolean variable to write. + * @param f The boolean value to assign to *pf. + */ +DECLINLINE(void) ASMAtomicWriteBool(volatile bool RT_FAR *pf, bool f) RT_NOTHROW_DEF +{ + ASMAtomicWriteU8((uint8_t volatile RT_FAR *)pf, f); +} + + +/** + * Atomically writes a boolean value, unordered. + * + * @param pf Pointer to the boolean variable to write. + * @param f The boolean value to assign to *pf. + */ +DECLINLINE(void) ASMAtomicUoWriteBool(volatile bool RT_FAR *pf, bool f) RT_NOTHROW_DEF +{ + *pf = f; /* byte writes are atomic on x86 */ +} + + +/** + * Atomically writes a pointer value, ordered. + * + * @param ppv Pointer to the pointer variable to write. + * @param pv The pointer value to assign to *ppv. + */ +DECLINLINE(void) ASMAtomicWritePtrVoid(void RT_FAR * volatile RT_FAR *ppv, const void *pv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + ASMAtomicWriteU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pv); +#elif ARCH_BITS == 64 + ASMAtomicWriteU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pv); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically writes a pointer value, unordered. + * + * @param ppv Pointer to the pointer variable to write. + * @param pv The pointer value to assign to *ppv. + */ +DECLINLINE(void) ASMAtomicUoWritePtrVoid(void RT_FAR * volatile RT_FAR *ppv, const void *pv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + ASMAtomicUoWriteU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pv); +#elif ARCH_BITS == 64 + ASMAtomicUoWriteU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pv); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically writes a pointer value, ordered. + * + * @param ppv Pointer to the pointer variable to write. + * @param pv The pointer value to assign to *ppv. If NULL use + * ASMAtomicWriteNullPtr or you'll land in trouble. + * + * @remarks This is relatively type safe on GCC platforms when @a pv isn't + * NULL. + */ +#ifdef __GNUC__ +# define ASMAtomicWritePtr(ppv, pv) \ + do \ + { \ + __typeof__(*(ppv)) volatile RT_FAR * const ppvTypeChecked = (ppv); \ + __typeof__(*(ppv)) const pvTypeChecked = (pv); \ + \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + AssertCompile(sizeof(pv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + \ + ASMAtomicWritePtrVoid((void RT_FAR * volatile RT_FAR *)(ppvTypeChecked), (void RT_FAR *)(pvTypeChecked)); \ + } while (0) +#else +# define ASMAtomicWritePtr(ppv, pv) \ + do \ + { \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + AssertCompile(sizeof(pv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + \ + ASMAtomicWritePtrVoid((void RT_FAR * volatile RT_FAR *)(ppv), (void RT_FAR *)(pv)); \ + } while (0) +#endif + + +/** + * Atomically sets a pointer to NULL, ordered. + * + * @param ppv Pointer to the pointer variable that should be set to NULL. + * + * @remarks This is relatively type safe on GCC platforms. + */ +#if RT_GNUC_PREREQ(4, 2) +# define ASMAtomicWriteNullPtr(ppv) \ + do \ + { \ + __typeof__(*(ppv)) * const ppvTypeChecked = (ppv); \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + ASMAtomicWritePtrVoid((void RT_FAR * volatile RT_FAR *)(ppvTypeChecked), NULL); \ + } while (0) +#else +# define ASMAtomicWriteNullPtr(ppv) \ + do \ + { \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + ASMAtomicWritePtrVoid((void RT_FAR * volatile RT_FAR *)(ppv), NULL); \ + } while (0) +#endif + + +/** + * Atomically writes a pointer value, unordered. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable. + * @param pv The pointer value to assign to *ppv. If NULL use + * ASMAtomicUoWriteNullPtr or you'll land in trouble. + * + * @remarks This is relatively type safe on GCC platforms when @a pv isn't + * NULL. + */ +#if RT_GNUC_PREREQ(4, 2) +# define ASMAtomicUoWritePtr(ppv, pv) \ + do \ + { \ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + __typeof__(*(ppv)) const pvTypeChecked = (pv); \ + \ + AssertCompile(sizeof(*ppv) == sizeof(void *)); \ + AssertCompile(sizeof(pv) == sizeof(void *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + \ + *(ppvTypeChecked) = pvTypeChecked; \ + } while (0) +#else +# define ASMAtomicUoWritePtr(ppv, pv) \ + do \ + { \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + AssertCompile(sizeof(pv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + *(ppv) = pv; \ + } while (0) +#endif + + +/** + * Atomically sets a pointer to NULL, unordered. + * + * @param ppv Pointer to the pointer variable that should be set to NULL. + * + * @remarks This is relatively type safe on GCC platforms. + */ +#ifdef __GNUC__ +# define ASMAtomicUoWriteNullPtr(ppv) \ + do \ + { \ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + AssertCompile(sizeof(*ppv) == sizeof(void *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + *(ppvTypeChecked) = NULL; \ + } while (0) +#else +# define ASMAtomicUoWriteNullPtr(ppv) \ + do \ + { \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + *(ppv) = NULL; \ + } while (0) +#endif + + +/** + * Atomically write a typical IPRT handle value, ordered. + * + * @param ph Pointer to the variable to update. + * @param hNew The value to assign to *ph. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicWriteHandle(ph, hNew) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + ASMAtomicWriteU32((uint32_t volatile RT_FAR *)(ph), (const uint32_t)(hNew)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicWriteHandle(ph, hNew) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + ASMAtomicWriteU64((uint64_t volatile RT_FAR *)(ph), (const uint64_t)(hNew)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically write a typical IPRT handle value, unordered. + * + * @param ph Pointer to the variable to update. + * @param hNew The value to assign to *ph. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicUoWriteHandle(ph, hNew) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + ASMAtomicUoWriteU32((uint32_t volatile RT_FAR *)(ph), (const uint32_t)hNew); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicUoWriteHandle(ph, hNew) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + ASMAtomicUoWriteU64((uint64_t volatile RT_FAR *)(ph), (const uint64_t)hNew); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically write a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to assign to *pu. + */ +#define ASMAtomicWriteSize(pu, uNew) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: ASMAtomicWriteU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu), (uint8_t )(uNew)); break; \ + case 2: ASMAtomicWriteU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu), (uint16_t)(uNew)); break; \ + case 4: ASMAtomicWriteU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: ASMAtomicWriteU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicWriteSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + +/** + * Atomically write a value which size might differ + * between platforms or compilers, unordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to assign to *pu. + */ +#define ASMAtomicUoWriteSize(pu, uNew) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: ASMAtomicUoWriteU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu), (uint8_t )(uNew)); break; \ + case 2: ASMAtomicUoWriteU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu), (uint16_t)(uNew)); break; \ + case 4: ASMAtomicUoWriteU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: ASMAtomicUoWriteU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicWriteSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + + +/** + * Atomically exchanges and adds to a 16-bit value, ordered. + * + * @returns The old value. + * @param pu16 Pointer to the value. + * @param u16 Number to add. + * + * @remarks Currently not implemented, just to make 16-bit code happy. + * @remarks x86: Requires a 486 or later. + */ +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMAtomicAddU16(uint16_t volatile RT_FAR *pu16, uint32_t u16) RT_NOTHROW_PROTO; + + +/** + * Atomically exchanges and adds to a 32-bit value, ordered. + * + * @returns The old value. + * @param pu32 Pointer to the value. + * @param u32 Number to add. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicAddU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicAddU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + u32 = _InterlockedExchangeAdd((long RT_FAR *)pu32, u32); + return u32; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (u32) + , "m" (*pu32) + : "memory" + , "cc"); + return u32; +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock xadd [rdx], eax +# else + mov edx, [pu32] + lock xadd [edx], eax +# endif + mov [u32], eax + } + return u32; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicAddU32, pu32, DMB_SY, + "add %w[uNew], %w[uOld], %w[uVal]\n\t", + "add %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically exchanges and adds to a signed 32-bit value, ordered. + * + * @returns The old value. + * @param pi32 Pointer to the value. + * @param i32 Number to add. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int32_t) ASMAtomicAddS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicAddU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically exchanges and adds to a 64-bit value, ordered. + * + * @returns The old value. + * @param pu64 Pointer to the value. + * @param u64 Number to add. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +DECLASM(uint64_t) ASMAtomicAddU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicAddU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + u64 = _InterlockedExchangeAdd64((__int64 RT_FAR *)pu64, u64); + return u64; + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("lock; xaddq %0, %1\n\t" + : "=r" (u64) + , "=m" (*pu64) + : "0" (u64) + , "m" (*pu64) + : "memory" + , "cc"); + return u64; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_64(ASMAtomicAddU64, pu64, DMB_SY, + "add %[uNew], %[uOld], %[uVal]\n\t" + , + "add %[uNew], %[uOld], %[uVal]\n\t" + "adc %H[uNew], %H[uOld], %H[uVal]\n\t", + [uVal] "r" (u64)); + return u64OldRet; + +# else + uint64_t u64Old; + for (;;) + { + uint64_t u64New; + u64Old = ASMAtomicUoReadU64(pu64); + u64New = u64Old + u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } + return u64Old; +# endif +} +#endif + + +/** + * Atomically exchanges and adds to a signed 64-bit value, ordered. + * + * @returns The old value. + * @param pi64 Pointer to the value. + * @param i64 Number to add. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicAddS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicAddU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically exchanges and adds to a size_t value, ordered. + * + * @returns The old value. + * @param pcb Pointer to the size_t value. + * @param cb Number to add. + */ +DECLINLINE(size_t) ASMAtomicAddZ(size_t volatile RT_FAR *pcb, size_t cb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + AssertCompileSize(size_t, 8); + return ASMAtomicAddU64((uint64_t volatile RT_FAR *)pcb, cb); +#elif ARCH_BITS == 32 + AssertCompileSize(size_t, 4); + return ASMAtomicAddU32((uint32_t volatile RT_FAR *)pcb, cb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + return ASMAtomicAddU16((uint16_t volatile RT_FAR *)pcb, cb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically exchanges and adds a value which size might differ between + * platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to add to *pu. + * @param puOld Where to store the old value. + */ +#define ASMAtomicAddSize(pu, uNew, puOld) \ + do { \ + switch (sizeof(*(pu))) { \ + case 4: *(uint32_t *)(puOld) = ASMAtomicAddU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: *(uint64_t *)(puOld) = ASMAtomicAddU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicAddSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + + +/** + * Atomically exchanges and subtracts to an unsigned 16-bit value, ordered. + * + * @returns The old value. + * @param pu16 Pointer to the value. + * @param u16 Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(uint16_t) ASMAtomicSubU16(uint16_t volatile RT_FAR *pu16, uint32_t u16) RT_NOTHROW_DEF +{ + return ASMAtomicAddU16(pu16, (uint16_t)-(int16_t)u16); +} + + +/** + * Atomically exchanges and subtracts to a signed 16-bit value, ordered. + * + * @returns The old value. + * @param pi16 Pointer to the value. + * @param i16 Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int16_t) ASMAtomicSubS16(int16_t volatile RT_FAR *pi16, int16_t i16) RT_NOTHROW_DEF +{ + return (int16_t)ASMAtomicAddU16((uint16_t volatile RT_FAR *)pi16, (uint16_t)-i16); +} + + +/** + * Atomically exchanges and subtracts to an unsigned 32-bit value, ordered. + * + * @returns The old value. + * @param pu32 Pointer to the value. + * @param u32 Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(uint32_t) ASMAtomicSubU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ + return ASMAtomicAddU32(pu32, (uint32_t)-(int32_t)u32); +} + + +/** + * Atomically exchanges and subtracts to a signed 32-bit value, ordered. + * + * @returns The old value. + * @param pi32 Pointer to the value. + * @param i32 Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int32_t) ASMAtomicSubS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicAddU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)-i32); +} + + +/** + * Atomically exchanges and subtracts to an unsigned 64-bit value, ordered. + * + * @returns The old value. + * @param pu64 Pointer to the value. + * @param u64 Number to subtract. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(uint64_t) ASMAtomicSubU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ + return ASMAtomicAddU64(pu64, (uint64_t)-(int64_t)u64); +} + + +/** + * Atomically exchanges and subtracts to a signed 64-bit value, ordered. + * + * @returns The old value. + * @param pi64 Pointer to the value. + * @param i64 Number to subtract. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicSubS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicAddU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)-i64); +} + + +/** + * Atomically exchanges and subtracts to a size_t value, ordered. + * + * @returns The old value. + * @param pcb Pointer to the size_t value. + * @param cb Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(size_t) ASMAtomicSubZ(size_t volatile RT_FAR *pcb, size_t cb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + return ASMAtomicSubU64((uint64_t volatile RT_FAR *)pcb, cb); +#elif ARCH_BITS == 32 + return ASMAtomicSubU32((uint32_t volatile RT_FAR *)pcb, cb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + return ASMAtomicSubU16((uint16_t volatile RT_FAR *)pcb, cb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically exchanges and subtracts a value which size might differ between + * platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to subtract to *pu. + * @param puOld Where to store the old value. + * + * @remarks x86: Requires a 486 or later. + */ +#define ASMAtomicSubSize(pu, uNew, puOld) \ + do { \ + switch (sizeof(*(pu))) { \ + case 4: *(uint32_t RT_FAR *)(puOld) = ASMAtomicSubU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: *(uint64_t RT_FAR *)(puOld) = ASMAtomicSubU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicSubSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + + +/** + * Atomically increment a 16-bit value, ordered. + * + * @returns The new value. + * @param pu16 Pointer to the value to increment. + * @remarks Not implemented. Just to make 16-bit code happy. + * + * @remarks x86: Requires a 486 or later. + */ +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMAtomicIncU16(uint16_t volatile RT_FAR *pu16) RT_NOTHROW_PROTO; + + +/** + * Atomically increment a 32-bit value, ordered. + * + * @returns The new value. + * @param pu32 Pointer to the value to increment. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicIncU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicIncU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return (uint32_t)_InterlockedIncrement((long RT_FAR *)pu32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint32_t u32; + __asm__ __volatile__("lock; xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (1) + , "m" (*pu32) + : "memory" + , "cc"); + return u32+1; +# else + __asm + { + mov eax, 1 +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock xadd [rdx], eax +# else + mov edx, [pu32] + lock xadd [edx], eax +# endif + mov u32, eax + } + return u32+1; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicIncU32, pu32, DMB_SY, + "add %w[uNew], %w[uNew], #1\n\t", + "add %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */, + "X" (0) /* dummy */); + return u32NewRet; + +# else + return ASMAtomicAddU32(pu32, 1) + 1; +# endif +} +#endif + + +/** + * Atomically increment a signed 32-bit value, ordered. + * + * @returns The new value. + * @param pi32 Pointer to the value to increment. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int32_t) ASMAtomicIncS32(int32_t volatile RT_FAR *pi32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicIncU32((uint32_t volatile RT_FAR *)pi32); +} + + +/** + * Atomically increment a 64-bit value, ordered. + * + * @returns The new value. + * @param pu64 Pointer to the value to increment. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +DECLASM(uint64_t) ASMAtomicIncU64(uint64_t volatile RT_FAR *pu64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicIncU64(uint64_t volatile RT_FAR *pu64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + return (uint64_t)_InterlockedIncrement64((__int64 RT_FAR *)pu64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t u64; + __asm__ __volatile__("lock; xaddq %0, %1\n\t" + : "=r" (u64) + , "=m" (*pu64) + : "0" (1) + , "m" (*pu64) + : "memory" + , "cc"); + return u64 + 1; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicIncU64, pu64, DMB_SY, + "add %[uNew], %[uNew], #1\n\t" + , + "add %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */ + "adc %H[uNew], %H[uNew], %[uZeroVal]\n\t", + RTASM_ARM_PICK_6432("X" (0) /* dummy */, [uZeroVal] "r" (0)) ); + return u64NewRet; + +# else + return ASMAtomicAddU64(pu64, 1) + 1; +# endif +} +#endif + + +/** + * Atomically increment a signed 64-bit value, ordered. + * + * @returns The new value. + * @param pi64 Pointer to the value to increment. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicIncS64(int64_t volatile RT_FAR *pi64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicIncU64((uint64_t volatile RT_FAR *)pi64); +} + + +/** + * Atomically increment a size_t value, ordered. + * + * @returns The new value. + * @param pcb Pointer to the value to increment. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(size_t) ASMAtomicIncZ(size_t volatile RT_FAR *pcb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + return ASMAtomicIncU64((uint64_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 32 + return ASMAtomicIncU32((uint32_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 16 + return ASMAtomicIncU16((uint16_t volatile RT_FAR *)pcb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + + +/** + * Atomically decrement an unsigned 32-bit value, ordered. + * + * @returns The new value. + * @param pu16 Pointer to the value to decrement. + * @remarks Not implemented. Just to make 16-bit code happy. + * + * @remarks x86: Requires a 486 or later. + */ +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicDecU16(uint16_t volatile RT_FAR *pu16) RT_NOTHROW_PROTO; + + +/** + * Atomically decrement an unsigned 32-bit value, ordered. + * + * @returns The new value. + * @param pu32 Pointer to the value to decrement. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicDecU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicDecU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return (uint32_t)_InterlockedDecrement((long RT_FAR *)pu32); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint32_t u32; + __asm__ __volatile__("lock; xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (-1) + , "m" (*pu32) + : "memory" + , "cc"); + return u32-1; +# else + uint32_t u32; + __asm + { + mov eax, -1 +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock xadd [rdx], eax +# else + mov edx, [pu32] + lock xadd [edx], eax +# endif + mov u32, eax + } + return u32-1; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicDecU32, pu32, DMB_SY, + "sub %w[uNew], %w[uNew], #1\n\t", + "sub %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */, + "X" (0) /* dummy */); + return u32NewRet; + +# else + return ASMAtomicSubU32(pu32, 1) - (uint32_t)1; +# endif +} +#endif + + +/** + * Atomically decrement a signed 32-bit value, ordered. + * + * @returns The new value. + * @param pi32 Pointer to the value to decrement. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int32_t) ASMAtomicDecS32(int32_t volatile RT_FAR *pi32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicDecU32((uint32_t volatile RT_FAR *)pi32); +} + + +/** + * Atomically decrement an unsigned 64-bit value, ordered. + * + * @returns The new value. + * @param pu64 Pointer to the value to decrement. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMAtomicDecU64(uint64_t volatile RT_FAR *pu64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicDecU64(uint64_t volatile RT_FAR *pu64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + return (uint64_t)_InterlockedDecrement64((__int64 volatile RT_FAR *)pu64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t u64; + __asm__ __volatile__("lock; xaddq %q0, %1\n\t" + : "=r" (u64) + , "=m" (*pu64) + : "0" (~(uint64_t)0) + , "m" (*pu64) + : "memory" + , "cc"); + return u64-1; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicDecU64, pu64, DMB_SY, + "sub %[uNew], %[uNew], #1\n\t" + , + "sub %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */ + "sbc %H[uNew], %H[uNew], %[uZeroVal]\n\t", + RTASM_ARM_PICK_6432("X" (0) /* dummy */, [uZeroVal] "r" (0)) ); + return u64NewRet; + +# else + return ASMAtomicAddU64(pu64, UINT64_MAX) - 1; +# endif +} +#endif + + +/** + * Atomically decrement a signed 64-bit value, ordered. + * + * @returns The new value. + * @param pi64 Pointer to the value to decrement. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicDecS64(int64_t volatile RT_FAR *pi64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicDecU64((uint64_t volatile RT_FAR *)pi64); +} + + +/** + * Atomically decrement a size_t value, ordered. + * + * @returns The new value. + * @param pcb Pointer to the value to decrement. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(size_t) ASMAtomicDecZ(size_t volatile RT_FAR *pcb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + return ASMAtomicDecU64((uint64_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 32 + return ASMAtomicDecU32((uint32_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 16 + return ASMAtomicDecU16((uint16_t volatile RT_FAR *)pcb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically Or an unsigned 32-bit value, ordered. + * + * @param pu32 Pointer to the pointer variable to OR u32 with. + * @param u32 The value to OR *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicOrU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicOrU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _InterlockedOr((long volatile RT_FAR *)pu32, (long)u32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; orl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock or [rdx], eax +# else + mov edx, [pu32] + lock or [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + /* For more on Orr see https://en.wikipedia.org/wiki/Orr_(Catch-22) ;-) */ + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicOr32, pu32, DMB_SY, + "orr %w[uNew], %w[uNew], %w[uVal]\n\t", + "orr %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically OR an unsigned 32-bit value, ordered, extended version (for bitmap + * fallback). + * + * @returns Old value. + * @param pu32 Pointer to the variable to OR @a u32 with. + * @param u32 The value to OR @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicOrExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicOrEx32, pu32, DMB_SY, + "orr %w[uNew], %w[uOld], %w[uVal]\n\t", + "orr %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + uint32_t u32RetOld = ASMAtomicUoReadU32(pu32); + uint32_t u32New; + do + u32New = u32RetOld | u32; + while (!ASMAtomicCmpXchgExU32(pu32, u32New, u32RetOld, &u32RetOld)); + return u32RetOld; +#endif +} + + +/** + * Atomically Or a signed 32-bit value, ordered. + * + * @param pi32 Pointer to the pointer variable to OR u32 with. + * @param i32 The value to OR *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicOrS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicOrU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically Or an unsigned 64-bit value, ordered. + * + * @param pu64 Pointer to the pointer variable to OR u64 with. + * @param u64 The value to OR *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +DECLASM(void) ASMAtomicOrU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicOrU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + _InterlockedOr64((__int64 volatile RT_FAR *)pu64, (__int64)u64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("lock; orq %1, %q0\n\t" + : "=m" (*pu64) + : "r" (u64) + , "m" (*pu64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicOrU64, pu64, DMB_SY, + "orr %[uNew], %[uNew], %[uVal]\n\t" + , + "orr %[uNew], %[uNew], %[uVal]\n\t" + "orr %H[uNew], %H[uNew], %H[uVal]\n\t", + [uVal] "r" (u64)); + +# else + for (;;) + { + uint64_t u64Old = ASMAtomicUoReadU64(pu64); + uint64_t u64New = u64Old | u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } +# endif +} +#endif + + +/** + * Atomically Or a signed 64-bit value, ordered. + * + * @param pi64 Pointer to the pointer variable to OR u64 with. + * @param i64 The value to OR *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(void) ASMAtomicOrS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + ASMAtomicOrU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically And an unsigned 32-bit value, ordered. + * + * @param pu32 Pointer to the pointer variable to AND u32 with. + * @param u32 The value to AND *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicAndU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicAndU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _InterlockedAnd((long volatile RT_FAR *)pu32, u32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; andl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock and [rdx], eax +# else + mov edx, [pu32] + lock and [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicAnd32, pu32, DMB_SY, + "and %w[uNew], %w[uNew], %w[uVal]\n\t", + "and %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically AND an unsigned 32-bit value, ordered, extended version. + * + * @returns Old value. + * @param pu32 Pointer to the variable to AND @a u32 with. + * @param u32 The value to AND @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicAndExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicAndEx32, pu32, DMB_SY, + "and %w[uNew], %w[uOld], %w[uVal]\n\t", + "and %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + uint32_t u32RetOld = ASMAtomicUoReadU32(pu32); + uint32_t u32New; + do + u32New = u32RetOld & u32; + while (!ASMAtomicCmpXchgExU32(pu32, u32New, u32RetOld, &u32RetOld)); + return u32RetOld; +#endif +} + + +/** + * Atomically And a signed 32-bit value, ordered. + * + * @param pi32 Pointer to the pointer variable to AND i32 with. + * @param i32 The value to AND *pi32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicAndS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicAndU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically And an unsigned 64-bit value, ordered. + * + * @param pu64 Pointer to the pointer variable to AND u64 with. + * @param u64 The value to AND *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +DECLASM(void) ASMAtomicAndU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicAndU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + _InterlockedAnd64((__int64 volatile RT_FAR *)pu64, u64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("lock; andq %1, %0\n\t" + : "=m" (*pu64) + : "r" (u64) + , "m" (*pu64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicAndU64, pu64, DMB_SY, + "and %[uNew], %[uNew], %[uVal]\n\t" + , + "and %[uNew], %[uNew], %[uVal]\n\t" + "and %H[uNew], %H[uNew], %H[uVal]\n\t", + [uVal] "r" (u64)); + +# else + for (;;) + { + uint64_t u64Old = ASMAtomicUoReadU64(pu64); + uint64_t u64New = u64Old & u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } +# endif +} +#endif + + +/** + * Atomically And a signed 64-bit value, ordered. + * + * @param pi64 Pointer to the pointer variable to AND i64 with. + * @param i64 The value to AND *pi64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(void) ASMAtomicAndS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + ASMAtomicAndU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically XOR an unsigned 32-bit value and a memory location, ordered. + * + * @param pu32 Pointer to the variable to XOR @a u32 with. + * @param u32 The value to XOR @a *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicXorU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicXorU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _InterlockedXor((long volatile RT_FAR *)pu32, u32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; xorl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock xor [rdx], eax +# else + mov edx, [pu32] + lock xor [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicXor32, pu32, DMB_SY, + "eor %w[uNew], %w[uNew], %w[uVal]\n\t", + "eor %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically XOR an unsigned 32-bit value and a memory location, ordered, + * extended version (for bitmaps). + * + * @returns Old value. + * @param pu32 Pointer to the variable to XOR @a u32 with. + * @param u32 The value to XOR @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicXorExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicXorEx32, pu32, DMB_SY, + "eor %w[uNew], %w[uOld], %w[uVal]\n\t", + "eor %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + uint32_t u32RetOld = ASMAtomicUoReadU32(pu32); + uint32_t u32New; + do + u32New = u32RetOld ^ u32; + while (!ASMAtomicCmpXchgExU32(pu32, u32New, u32RetOld, &u32RetOld)); + return u32RetOld; +#endif +} + + +/** + * Atomically XOR a signed 32-bit value, ordered. + * + * @param pi32 Pointer to the variable to XOR i32 with. + * @param i32 The value to XOR *pi32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicXorS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicXorU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically OR an unsigned 32-bit value, unordered but interrupt safe. + * + * @param pu32 Pointer to the pointer variable to OR u32 with. + * @param u32 The value to OR *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicUoOrU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoOrU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("orl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + or [rdx], eax +# else + mov edx, [pu32] + or [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoOrU32, pu32, NO_BARRIER, + "orr %w[uNew], %w[uNew], %w[uVal]\n\t", + "orr %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically OR an unsigned 32-bit value, unordered but interrupt safe, + * extended version (for bitmap fallback). + * + * @returns Old value. + * @param pu32 Pointer to the variable to OR @a u32 with. + * @param u32 The value to OR @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicUoOrExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicUoOrExU32, pu32, NO_BARRIER, + "orr %w[uNew], %w[uOld], %w[uVal]\n\t", + "orr %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + return ASMAtomicOrExU32(pu32, u32); /* (we have no unordered cmpxchg primitive atm.) */ +#endif +} + + +/** + * Atomically OR a signed 32-bit value, unordered. + * + * @param pi32 Pointer to the pointer variable to OR u32 with. + * @param i32 The value to OR *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicUoOrS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicUoOrU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically OR an unsigned 64-bit value, unordered. + * + * @param pu64 Pointer to the pointer variable to OR u64 with. + * @param u64 The value to OR *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +DECLASM(void) ASMAtomicUoOrU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoOrU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("orq %1, %q0\n\t" + : "=m" (*pu64) + : "r" (u64) + , "m" (*pu64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicUoOrU64, pu64, NO_BARRIER, + "orr %[uNew], %[uNew], %[uVal]\n\t" + , + "orr %[uNew], %[uNew], %[uVal]\n\t" + "orr %H[uNew], %H[uNew], %H[uVal]\n\t", + [uVal] "r" (u64)); + +# else + for (;;) + { + uint64_t u64Old = ASMAtomicUoReadU64(pu64); + uint64_t u64New = u64Old | u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } +# endif +} +#endif + + +/** + * Atomically Or a signed 64-bit value, unordered. + * + * @param pi64 Pointer to the pointer variable to OR u64 with. + * @param i64 The value to OR *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(void) ASMAtomicUoOrS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + ASMAtomicUoOrU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically And an unsigned 32-bit value, unordered. + * + * @param pu32 Pointer to the pointer variable to AND u32 with. + * @param u32 The value to AND *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicUoAndU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoAndU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("andl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + and [rdx], eax +# else + mov edx, [pu32] + and [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoAnd32, pu32, NO_BARRIER, + "and %w[uNew], %w[uNew], %w[uVal]\n\t", + "and %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically AND an unsigned 32-bit value, unordered, extended version (for + * bitmap fallback). + * + * @returns Old value. + * @param pu32 Pointer to the pointer to AND @a u32 with. + * @param u32 The value to AND @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicUoAndExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicUoAndEx32, pu32, NO_BARRIER, + "and %w[uNew], %w[uOld], %w[uVal]\n\t", + "and %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + return ASMAtomicAndExU32(pu32, u32); /* (we have no unordered cmpxchg primitive atm.) */ +#endif +} + + +/** + * Atomically And a signed 32-bit value, unordered. + * + * @param pi32 Pointer to the pointer variable to AND i32 with. + * @param i32 The value to AND *pi32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicUoAndS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicUoAndU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically And an unsigned 64-bit value, unordered. + * + * @param pu64 Pointer to the pointer variable to AND u64 with. + * @param u64 The value to AND *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +DECLASM(void) ASMAtomicUoAndU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoAndU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("andq %1, %0\n\t" + : "=m" (*pu64) + : "r" (u64) + , "m" (*pu64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicUoAndU64, pu64, NO_BARRIER, + "and %[uNew], %[uNew], %[uVal]\n\t" + , + "and %[uNew], %[uNew], %[uVal]\n\t" + "and %H[uNew], %H[uNew], %H[uVal]\n\t", + [uVal] "r" (u64)); + +# else + for (;;) + { + uint64_t u64Old = ASMAtomicUoReadU64(pu64); + uint64_t u64New = u64Old & u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } +# endif +} +#endif + + +/** + * Atomically And a signed 64-bit value, unordered. + * + * @param pi64 Pointer to the pointer variable to AND i64 with. + * @param i64 The value to AND *pi64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(void) ASMAtomicUoAndS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + ASMAtomicUoAndU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically XOR an unsigned 32-bit value, unordered but interrupt safe. + * + * @param pu32 Pointer to the variable to XOR @a u32 with. + * @param u32 The value to OR @a *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicUoXorU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoXorU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xorl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + xor [rdx], eax +# else + mov edx, [pu32] + xor [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoXorU32, pu32, NO_BARRIER, + "eor %w[uNew], %w[uNew], %w[uVal]\n\t", + "eor %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically XOR an unsigned 32-bit value, unordered but interrupt safe, + * extended version (for bitmap fallback). + * + * @returns Old value. + * @param pu32 Pointer to the variable to XOR @a u32 with. + * @param u32 The value to OR @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicUoXorExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicUoXorExU32, pu32, NO_BARRIER, + "eor %w[uNew], %w[uOld], %w[uVal]\n\t", + "eor %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + return ASMAtomicXorExU32(pu32, u32); /* (we have no unordered cmpxchg primitive atm.) */ +#endif +} + + +/** + * Atomically XOR a signed 32-bit value, unordered. + * + * @param pi32 Pointer to the variable to XOR @a u32 with. + * @param i32 The value to XOR @a *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicUoXorS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicUoXorU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically increment an unsigned 32-bit value, unordered. + * + * @returns the new value. + * @param pu32 Pointer to the variable to increment. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicUoIncU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicUoIncU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (1) + , "m" (*pu32) + : "memory" /** @todo why 'memory'? */ + , "cc"); + return u32 + 1; +# else + __asm + { + mov eax, 1 +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + xadd [rdx], eax +# else + mov edx, [pu32] + xadd [edx], eax +# endif + mov u32, eax + } + return u32 + 1; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoIncU32, pu32, NO_BARRIER, + "add %w[uNew], %w[uNew], #1\n\t", + "add %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */, + "X" (0) /* dummy */); + return u32NewRet; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically decrement an unsigned 32-bit value, unordered. + * + * @returns the new value. + * @param pu32 Pointer to the variable to decrement. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicUoDecU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicUoDecU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (-1) + , "m" (*pu32) + : "memory" + , "cc"); + return u32 - 1; +# else + __asm + { + mov eax, -1 +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + xadd [rdx], eax +# else + mov edx, [pu32] + xadd [edx], eax +# endif + mov u32, eax + } + return u32 - 1; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoDecU32, pu32, NO_BARRIER, + "sub %w[uNew], %w[uNew], #1\n\t", + "sub %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */, + "X" (0) /* dummy */); + return u32NewRet; + +# else +# error "Port me" +# endif +} +#endif + + +/** @def RT_ASM_PAGE_SIZE + * We try avoid dragging in iprt/param.h here. + * @internal + */ +#if defined(RT_ARCH_SPARC64) +# define RT_ASM_PAGE_SIZE 0x2000 +# if defined(PAGE_SIZE) && !defined(NT_INCLUDED) +# if PAGE_SIZE != 0x2000 +# error "PAGE_SIZE is not 0x2000!" +# endif +# endif +#elif defined(RT_ARCH_ARM64) +# define RT_ASM_PAGE_SIZE 0x4000 +# if defined(PAGE_SIZE) && !defined(NT_INCLUDED) && !defined(_MACH_ARM_VM_PARAM_H_) +# if PAGE_SIZE != 0x4000 +# error "PAGE_SIZE is not 0x4000!" +# endif +# endif +#else +# define RT_ASM_PAGE_SIZE 0x1000 +# if defined(PAGE_SIZE) && !defined(NT_INCLUDED) +# if PAGE_SIZE != 0x1000 +# error "PAGE_SIZE is not 0x1000!" +# endif +# endif +#endif + +/** + * Zeros a 4K memory page. + * + * @param pv Pointer to the memory block. This must be page aligned. + */ +#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMMemZeroPage(volatile void RT_FAR *pv) RT_NOTHROW_PROTO; +# else +DECLINLINE(void) ASMMemZeroPage(volatile void RT_FAR *pv) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN +# ifdef RT_ARCH_AMD64 + __stosq((unsigned __int64 *)pv, 0, RT_ASM_PAGE_SIZE / 8); +# else + __stosd((unsigned long *)pv, 0, RT_ASM_PAGE_SIZE / 4); +# endif + +# elif RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uDummy; +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("rep stosq" + : "=D" (pv), + "=c" (uDummy) + : "0" (pv), + "c" (RT_ASM_PAGE_SIZE >> 3), + "a" (0) + : "memory"); +# else + __asm__ __volatile__("rep stosl" + : "=D" (pv), + "=c" (uDummy) + : "0" (pv), + "c" (RT_ASM_PAGE_SIZE >> 2), + "a" (0) + : "memory"); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + xor rax, rax + mov ecx, 0200h + mov rdi, [pv] + rep stosq +# else + xor eax, eax + mov ecx, 0400h + mov edi, [pv] + rep stosd +# endif + } +# endif +} +# endif + + +/** + * Zeros a memory block with a 32-bit aligned size. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. This MUST be aligned on 32-bit! + */ +#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMMemZero32(volatile void RT_FAR *pv, size_t cb) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMMemZero32(volatile void RT_FAR *pv, size_t cb) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN +# ifdef RT_ARCH_AMD64 + if (!(cb & 7)) + __stosq((unsigned __int64 RT_FAR *)pv, 0, cb / 8); + else +# endif + __stosd((unsigned long RT_FAR *)pv, 0, cb / 4); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep stosl" + : "=D" (pv), + "=c" (cb) + : "0" (pv), + "1" (cb >> 2), + "a" (0) + : "memory"); +# else + __asm + { + xor eax, eax +# ifdef RT_ARCH_AMD64 + mov rcx, [cb] + shr rcx, 2 + mov rdi, [pv] +# else + mov ecx, [cb] + shr ecx, 2 + mov edi, [pv] +# endif + rep stosd + } +# endif +} +#endif + + +/** + * Fills a memory block with a 32-bit aligned size. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. This MUST be aligned on 32-bit! + * @param u32 The value to fill with. + */ +#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMMemFill32(volatile void RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMMemFill32(volatile void RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN +# ifdef RT_ARCH_AMD64 + if (!(cb & 7)) + __stosq((unsigned __int64 RT_FAR *)pv, RT_MAKE_U64(u32, u32), cb / 8); + else +# endif + __stosd((unsigned long RT_FAR *)pv, u32, cb / 4); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep stosl" + : "=D" (pv), + "=c" (cb) + : "0" (pv), + "1" (cb >> 2), + "a" (u32) + : "memory"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rcx, [cb] + shr rcx, 2 + mov rdi, [pv] +# else + mov ecx, [cb] + shr ecx, 2 + mov edi, [pv] +# endif + mov eax, [u32] + rep stosd + } +# endif +} +#endif + + +/** + * Checks if a memory block is all zeros. + * + * @returns Pointer to the first non-zero byte. + * @returns NULL if all zero. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. + */ +#if !defined(RDESKTOP) && (!defined(RT_OS_LINUX) || !defined(__KERNEL__)) +DECLASM(void RT_FAR *) ASMMemFirstNonZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_PROTO; +#else +DECLINLINE(void RT_FAR *) ASMMemFirstNonZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_DEF +{ +/** @todo replace with ASMMemFirstNonZero-generic.cpp in kernel modules. */ + uint8_t const *pb = (uint8_t const RT_FAR *)pv; + for (; cb; cb--, pb++) + if (RT_LIKELY(*pb == 0)) + { /* likely */ } + else + return (void RT_FAR *)pb; + return NULL; +} +#endif + + +/** + * Checks if a memory block is all zeros. + * + * @returns true if zero, false if not. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. + * + * @sa ASMMemFirstNonZero + */ +DECLINLINE(bool) ASMMemIsZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_DEF +{ + return ASMMemFirstNonZero(pv, cb) == NULL; +} + + +/** + * Checks if a memory page is all zeros. + * + * @returns true / false. + * + * @param pvPage Pointer to the page. Must be aligned on 16 byte + * boundary + */ +DECLINLINE(bool) ASMMemIsZeroPage(void const RT_FAR *pvPage) RT_NOTHROW_DEF +{ +# if 0 /*RT_INLINE_ASM_GNU_STYLE - this is actually slower... */ + union { RTCCUINTREG r; bool f; } uAX; + RTCCUINTREG xCX, xDI; + Assert(!((uintptr_t)pvPage & 15)); + __asm__ __volatile__("repe; " +# ifdef RT_ARCH_AMD64 + "scasq\n\t" +# else + "scasl\n\t" +# endif + "setnc %%al\n\t" + : "=&c" (xCX) + , "=&D" (xDI) + , "=&a" (uAX.r) + : "mr" (pvPage) +# ifdef RT_ARCH_AMD64 + , "0" (RT_ASM_PAGE_SIZE/8) +# else + , "0" (RT_ASM_PAGE_SIZE/4) +# endif + , "1" (pvPage) + , "2" (0) + : "cc"); + return uAX.f; +# else + uintptr_t const RT_FAR *puPtr = (uintptr_t const RT_FAR *)pvPage; + size_t cLeft = RT_ASM_PAGE_SIZE / sizeof(uintptr_t) / 8; + Assert(!((uintptr_t)pvPage & 15)); + for (;;) + { + if (puPtr[0]) return false; + if (puPtr[4]) return false; + + if (puPtr[2]) return false; + if (puPtr[6]) return false; + + if (puPtr[1]) return false; + if (puPtr[5]) return false; + + if (puPtr[3]) return false; + if (puPtr[7]) return false; + + if (!--cLeft) + return true; + puPtr += 8; + } +# endif +} + + +/** + * Checks if a memory block is filled with the specified byte, returning the + * first mismatch. + * + * This is sort of an inverted memchr. + * + * @returns Pointer to the byte which doesn't equal u8. + * @returns NULL if all equal to u8. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. + * @param u8 The value it's supposed to be filled with. + * + * @remarks No alignment requirements. + */ +#if (!defined(RT_OS_LINUX) || !defined(__KERNEL__)) \ + && (!defined(RT_OS_FREEBSD) || !defined(_KERNEL)) +DECLASM(void *) ASMMemFirstMismatchingU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_PROTO; +#else +DECLINLINE(void *) ASMMemFirstMismatchingU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_DEF +{ +/** @todo replace with ASMMemFirstMismatchingU8-generic.cpp in kernel modules. */ + uint8_t const *pb = (uint8_t const RT_FAR *)pv; + for (; cb; cb--, pb++) + if (RT_LIKELY(*pb == u8)) + { /* likely */ } + else + return (void *)pb; + return NULL; +} +#endif + + +/** + * Checks if a memory block is filled with the specified byte. + * + * @returns true if all matching, false if not. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. + * @param u8 The value it's supposed to be filled with. + * + * @remarks No alignment requirements. + */ +DECLINLINE(bool) ASMMemIsAllU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_DEF +{ + return ASMMemFirstMismatchingU8(pv, cb, u8) == NULL; +} + + +/** + * Checks if a memory block is filled with the specified 32-bit value. + * + * This is a sort of inverted memchr. + * + * @returns Pointer to the first value which doesn't equal u32. + * @returns NULL if all equal to u32. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. This MUST be aligned on 32-bit! + * @param u32 The value it's supposed to be filled with. + */ +DECLINLINE(uint32_t RT_FAR *) ASMMemFirstMismatchingU32(void const RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_DEF +{ +/** @todo rewrite this in inline assembly? */ + uint32_t const RT_FAR *pu32 = (uint32_t const RT_FAR *)pv; + for (; cb; cb -= 4, pu32++) + if (RT_LIKELY(*pu32 == u32)) + { /* likely */ } + else + return (uint32_t RT_FAR *)pu32; + return NULL; +} + + +/** + * Probes a byte pointer for read access. + * + * While the function will not fault if the byte is not read accessible, + * the idea is to do this in a safe place like before acquiring locks + * and such like. + * + * Also, this functions guarantees that an eager compiler is not going + * to optimize the probing away. + * + * @param pvByte Pointer to the byte. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMProbeReadByte(const void RT_FAR *pvByte) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint8_t) ASMProbeReadByte(const void RT_FAR *pvByte) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint8_t u8; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movb %1, %0\n\t" + : "=q" (u8) + : "m" (*(const uint8_t *)pvByte)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvByte] + mov al, [rax] +# else + mov eax, [pvByte] + mov al, [eax] +# endif + mov [u8], al + } +# endif + return u8; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMProbeReadByte_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrb %w[uDst], %[pMem]\n\t" +# else + "ldrexb %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*(uint8_t const *)pvByte)); + return (uint8_t)u32; + +# else +# error "Port me" +# endif +} +#endif + +/** + * Probes a buffer for read access page by page. + * + * While the function will fault if the buffer is not fully read + * accessible, the idea is to do this in a safe place like before + * acquiring locks and such like. + * + * Also, this functions guarantees that an eager compiler is not going + * to optimize the probing away. + * + * @param pvBuf Pointer to the buffer. + * @param cbBuf The size of the buffer in bytes. Must be >= 1. + */ +DECLINLINE(void) ASMProbeReadBuffer(const void RT_FAR *pvBuf, size_t cbBuf) RT_NOTHROW_DEF +{ + /** @todo verify that the compiler actually doesn't optimize this away. (intel & gcc) */ + /* the first byte */ + const uint8_t RT_FAR *pu8 = (const uint8_t RT_FAR *)pvBuf; + ASMProbeReadByte(pu8); + + /* the pages in between pages. */ + while (cbBuf > RT_ASM_PAGE_SIZE) + { + ASMProbeReadByte(pu8); + cbBuf -= RT_ASM_PAGE_SIZE; + pu8 += RT_ASM_PAGE_SIZE; + } + + /* the last byte */ + ASMProbeReadByte(pu8 + cbBuf - 1); +} + + +/** + * Reverse the byte order of the given 16-bit integer. + * + * @returns Revert + * @param u16 16-bit integer value. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMByteSwapU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint16_t) ASMByteSwapU16(uint16_t u16) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return _byteswap_ushort(u16); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ ("rorw $8, %0" : "=r" (u16) : "0" (u16) : "cc"); +# else + _asm + { + mov ax, [u16] + ror ax, 8 + mov [u16], ax + } +# endif + return u16; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32Ret; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "rev16 %w[uRet], %w[uVal]\n\t" +# else + "rev16 %[uRet], %[uVal]\n\t" +# endif + : [uRet] "=r" (u32Ret) + : [uVal] "r" (u16)); + return (uint16_t)u32Ret; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Reverse the byte order of the given 32-bit integer. + * + * @returns Revert + * @param u32 32-bit integer value. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMByteSwapU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMByteSwapU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return _byteswap_ulong(u32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ ("bswapl %0" : "=r" (u32) : "0" (u32)); +# else + _asm + { + mov eax, [u32] + bswap eax + mov [u32], eax + } +# endif + return u32; + +# elif defined(RT_ARCH_ARM64) + uint64_t u64Ret; + __asm__ __volatile__("rev32 %[uRet], %[uVal]\n\t" + : [uRet] "=r" (u64Ret) + : [uVal] "r" ((uint64_t)u32)); + return (uint32_t)u64Ret; + +# elif defined(RT_ARCH_ARM32) + __asm__ __volatile__("rev %[uRet], %[uVal]\n\t" + : [uRet] "=r" (u32) + : [uVal] "[uRet]" (u32)); + return u32; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Reverse the byte order of the given 64-bit integer. + * + * @returns Revert + * @param u64 64-bit integer value. + */ +DECLINLINE(uint64_t) ASMByteSwapU64(uint64_t u64) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_AMD64) && RT_INLINE_ASM_USES_INTRIN + return _byteswap_uint64(u64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ ("bswapq %0" : "=r" (u64) : "0" (u64)); + return u64; + +# elif defined(RT_ARCH_ARM64) + __asm__ __volatile__("rev %[uRet], %[uVal]\n\t" + : [uRet] "=r" (u64) + : [uVal] "[uRet]" (u64)); + return u64; + +#else + return (uint64_t)ASMByteSwapU32((uint32_t)u64) << 32 + | (uint64_t)ASMByteSwapU32((uint32_t)(u64 >> 32)); +#endif +} + + + +/** @defgroup grp_inline_bits Bit Operations + * @{ + */ + + +/** + * Sets a bit in a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). This should be + * 32-bit aligned. + * @param iBit The bit to set. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMBitSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMBitSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _bittestandset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btsl %1, %0" + : "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + bts [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + bts [eax], edx +# endif + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + ASMAtomicUoOrU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Atomically sets a bit in a bitmap, ordered. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to set. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicBitSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicBitSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if RT_INLINE_ASM_USES_INTRIN + _interlockedbittestandset((long RT_FAR *)pvBitmap, iBit); +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btsl %1, %0" + : "=m" (*(volatile long *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + lock bts [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + lock bts [eax], edx +# endif + } +# endif + +# else + ASMAtomicOrU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Clears a bit in a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to clear. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMBitClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMBitClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _bittestandreset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btrl %1, %0" + : "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + btr [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + btr [eax], edx +# endif + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + ASMAtomicUoAndU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(~RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Atomically clears a bit in a bitmap, ordered. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to toggle set. + * + * @remarks No memory barrier, take care on smp. + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicBitClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicBitClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btrl %1, %0" + : "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + lock btr [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + lock btr [eax], edx +# endif + } +# endif +# else + ASMAtomicAndU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(~RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Toggles a bit in a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to toggle. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMBitToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMBitToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _bittestandcomplement((long RT_FAR *)pvBitmap, iBit); +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btcl %1, %0" + : "=m" (*(volatile long *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + btc [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + btc [eax], edx +# endif + } +# endif +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + ASMAtomicUoXorU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Atomically toggles a bit in a bitmap, ordered. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to test and set. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicBitToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicBitToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btcl %1, %0" + : "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + lock btc [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + lock btc [eax], edx +# endif + } +# endif +# else + ASMAtomicXorU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Tests and sets a bit in a bitmap. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to test and set. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMBitTestAndSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMBitTestAndSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _bittestandset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btsl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + bts [rax], edx +# else + mov eax, [pvBitmap] + bts [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + rc.u32 = RT_LE2H_U32(ASMAtomicUoOrExU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Atomically tests and sets a bit in a bitmap, ordered. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to set. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicBitTestAndSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicBitTestAndSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _interlockedbittestandset((long RT_FAR *)pvBitmap, iBit); +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btsl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + lock bts [rax], edx +# else + mov eax, [pvBitmap] + lock bts [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + rc.u32 = RT_LE2H_U32(ASMAtomicOrExU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Tests and clears a bit in a bitmap. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to test and clear. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMBitTestAndClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMBitTestAndClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _bittestandreset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btrl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + btr [rax], edx +# else + mov eax, [pvBitmap] + btr [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + rc.u32 = RT_LE2H_U32(ASMAtomicUoAndExU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(~RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Atomically tests and clears a bit in a bitmap, ordered. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to test and clear. + * + * @remarks No memory barrier, take care on smp. + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicBitTestAndClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicBitTestAndClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _interlockedbittestandreset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btrl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + lock btr [rax], edx +# else + mov eax, [pvBitmap] + lock btr [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + rc.u32 = RT_LE2H_U32(ASMAtomicAndExU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(~RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Tests and toggles a bit in a bitmap. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to test and toggle. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMBitTestAndToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMBitTestAndToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _bittestandcomplement((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btcl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + btc [rax], edx +# else + mov eax, [pvBitmap] + btc [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + rc.u32 = RT_LE2H_U32(ASMAtomicUoXorExU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Atomically tests and toggles a bit in a bitmap, ordered. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to test and toggle. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicBitTestAndToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicBitTestAndToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btcl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + lock btc [rax], edx +# else + mov eax, [pvBitmap] + lock btc [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + rc.u32 = RT_H2LE_U32(ASMAtomicXorExU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_LE2H_U32(RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Tests if a bit in a bitmap is set. + * + * @returns true if the bit is set. + * @returns false if the bit is clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to test. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMBitTest(const volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMBitTest(const volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; +# if RT_INLINE_ASM_USES_INTRIN + rc.u32 = _bittest((long *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + + __asm__ __volatile__("btl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + : "m" (*(const volatile long RT_FAR *)pvBitmap) + , "Ir" (iBit) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + bt [rax], edx +# else + mov eax, [pvBitmap] + bt [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + rc.u32 = RT_LE2H_U32(ASMAtomicUoReadU32(&((uint32_t volatile *)pvBitmap)[offBitmap])) >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Clears a bit range within a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBitStart The First bit to clear. + * @param iBitEnd The first bit not to clear. + */ +DECLINLINE(void) ASMBitClearRange(volatile void RT_FAR *pvBitmap, size_t iBitStart, size_t iBitEnd) RT_NOTHROW_DEF +{ + if (iBitStart < iBitEnd) + { + uint32_t volatile RT_FAR *pu32 = (volatile uint32_t RT_FAR *)pvBitmap + (iBitStart >> 5); + size_t iStart = iBitStart & ~(size_t)31; + size_t iEnd = iBitEnd & ~(size_t)31; + if (iStart == iEnd) + *pu32 &= RT_H2LE_U32(((UINT32_C(1) << (iBitStart & 31)) - 1) | ~((UINT32_C(1) << (iBitEnd & 31)) - 1)); + else + { + /* bits in first dword. */ + if (iBitStart & 31) + { + *pu32 &= RT_H2LE_U32((UINT32_C(1) << (iBitStart & 31)) - 1); + pu32++; + iBitStart = iStart + 32; + } + + /* whole dwords. */ + if (iBitStart != iEnd) + ASMMemZero32(pu32, (iEnd - iBitStart) >> 3); + + /* bits in last dword. */ + if (iBitEnd & 31) + { + pu32 = (volatile uint32_t RT_FAR *)pvBitmap + (iBitEnd >> 5); + *pu32 &= RT_H2LE_U32(~((UINT32_C(1) << (iBitEnd & 31)) - 1)); + } + } + } +} + + +/** + * Sets a bit range within a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBitStart The First bit to set. + * @param iBitEnd The first bit not to set. + */ +DECLINLINE(void) ASMBitSetRange(volatile void RT_FAR *pvBitmap, size_t iBitStart, size_t iBitEnd) RT_NOTHROW_DEF +{ + if (iBitStart < iBitEnd) + { + uint32_t volatile RT_FAR *pu32 = (volatile uint32_t RT_FAR *)pvBitmap + (iBitStart >> 5); + size_t iStart = iBitStart & ~(size_t)31; + size_t iEnd = iBitEnd & ~(size_t)31; + if (iStart == iEnd) + *pu32 |= RT_H2LE_U32(((UINT32_C(1) << (iBitEnd - iBitStart)) - 1) << (iBitStart & 31)); + else + { + /* bits in first dword. */ + if (iBitStart & 31) + { + *pu32 |= RT_H2LE_U32(~((UINT32_C(1) << (iBitStart & 31)) - 1)); + pu32++; + iBitStart = iStart + 32; + } + + /* whole dword. */ + if (iBitStart != iEnd) + ASMMemFill32(pu32, (iEnd - iBitStart) >> 3, ~UINT32_C(0)); + + /* bits in last dword. */ + if (iBitEnd & 31) + { + pu32 = (volatile uint32_t RT_FAR *)pvBitmap + (iBitEnd >> 5); + *pu32 |= RT_H2LE_U32((UINT32_C(1) << (iBitEnd & 31)) - 1); + } + } + } +} + + +/** + * Finds the first clear bit in a bitmap. + * + * @returns Index of the first zero bit. + * @returns -1 if no clear bit was found. + * @param pvBitmap Pointer to the bitmap (little endian). + * @param cBits The number of bits in the bitmap. Multiple of 32. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(int32_t) ASMBitFirstClear(const volatile void RT_FAR *pvBitmap, uint32_t cBits) RT_NOTHROW_PROTO; +#else +DECLINLINE(int32_t) ASMBitFirstClear(const volatile void RT_FAR *pvBitmap, uint32_t cBits) RT_NOTHROW_DEF +{ + if (cBits) + { + int32_t iBit; +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uEAX, uECX, uEDI; + cBits = RT_ALIGN_32(cBits, 32); + __asm__ __volatile__("repe; scasl\n\t" + "je 1f\n\t" +# ifdef RT_ARCH_AMD64 + "lea -4(%%rdi), %%rdi\n\t" + "xorl (%%rdi), %%eax\n\t" + "subq %5, %%rdi\n\t" +# else + "lea -4(%%edi), %%edi\n\t" + "xorl (%%edi), %%eax\n\t" + "subl %5, %%edi\n\t" +# endif + "shll $3, %%edi\n\t" + "bsfl %%eax, %%edx\n\t" + "addl %%edi, %%edx\n\t" + "1:\t\n" + : "=d" (iBit) + , "=&c" (uECX) + , "=&D" (uEDI) + , "=&a" (uEAX) + : "0" (0xffffffff) + , "mr" (pvBitmap) + , "1" (cBits >> 5) + , "2" (pvBitmap) + , "3" (0xffffffff) + : "cc"); +# else + cBits = RT_ALIGN_32(cBits, 32); + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdi, [pvBitmap] + mov rbx, rdi +# else + mov edi, [pvBitmap] + mov ebx, edi +# endif + mov edx, 0ffffffffh + mov eax, edx + mov ecx, [cBits] + shr ecx, 5 + repe scasd + je done + +# ifdef RT_ARCH_AMD64 + lea rdi, [rdi - 4] + xor eax, [rdi] + sub rdi, rbx +# else + lea edi, [edi - 4] + xor eax, [edi] + sub edi, ebx +# endif + shl edi, 3 + bsf edx, eax + add edx, edi + done: + mov [iBit], edx + } +# endif + return iBit; + } + return -1; +} +#endif + + +/** + * Finds the next clear bit in a bitmap. + * + * @returns Index of the first zero bit. + * @returns -1 if no clear bit was found. + * @param pvBitmap Pointer to the bitmap (little endian). + * @param cBits The number of bits in the bitmap. Multiple of 32. + * @param iBitPrev The bit returned from the last search. + * The search will start at iBitPrev + 1. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(int) ASMBitNextClear(const volatile void RT_FAR *pvBitmap, uint32_t cBits, uint32_t iBitPrev) RT_NOTHROW_PROTO; +#else +DECLINLINE(int) ASMBitNextClear(const volatile void RT_FAR *pvBitmap, uint32_t cBits, uint32_t iBitPrev) RT_NOTHROW_DEF +{ + const volatile uint32_t RT_FAR *pau32Bitmap = (const volatile uint32_t RT_FAR *)pvBitmap; + int iBit = ++iBitPrev & 31; + if (iBit) + { + /* + * Inspect the 32-bit word containing the unaligned bit. + */ + uint32_t u32 = ~pau32Bitmap[iBitPrev / 32] >> iBit; + +# if RT_INLINE_ASM_USES_INTRIN + unsigned long ulBit = 0; + if (_BitScanForward(&ulBit, u32)) + return ulBit + iBitPrev; +# else +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("bsf %1, %0\n\t" + "jnz 1f\n\t" + "movl $-1, %0\n\t" /** @todo use conditional move for 64-bit? */ + "1:\n\t" + : "=r" (iBit) + : "r" (u32) + : "cc"); +# else + __asm + { + mov edx, [u32] + bsf eax, edx + jnz done + mov eax, 0ffffffffh + done: + mov [iBit], eax + } +# endif + if (iBit >= 0) + return iBit + (int)iBitPrev; +# endif + + /* + * Skip ahead and see if there is anything left to search. + */ + iBitPrev |= 31; + iBitPrev++; + if (cBits <= (uint32_t)iBitPrev) + return -1; + } + + /* + * 32-bit aligned search, let ASMBitFirstClear do the dirty work. + */ + iBit = ASMBitFirstClear(&pau32Bitmap[iBitPrev / 32], cBits - iBitPrev); + if (iBit >= 0) + iBit += iBitPrev; + return iBit; +} +#endif + + +/** + * Finds the first set bit in a bitmap. + * + * @returns Index of the first set bit. + * @returns -1 if no clear bit was found. + * @param pvBitmap Pointer to the bitmap (little endian). + * @param cBits The number of bits in the bitmap. Multiple of 32. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(int32_t) ASMBitFirstSet(const volatile void RT_FAR *pvBitmap, uint32_t cBits) RT_NOTHROW_PROTO; +#else +DECLINLINE(int32_t) ASMBitFirstSet(const volatile void RT_FAR *pvBitmap, uint32_t cBits) RT_NOTHROW_DEF +{ + if (cBits) + { + int32_t iBit; +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uEAX, uECX, uEDI; + cBits = RT_ALIGN_32(cBits, 32); + __asm__ __volatile__("repe; scasl\n\t" + "je 1f\n\t" +# ifdef RT_ARCH_AMD64 + "lea -4(%%rdi), %%rdi\n\t" + "movl (%%rdi), %%eax\n\t" + "subq %5, %%rdi\n\t" +# else + "lea -4(%%edi), %%edi\n\t" + "movl (%%edi), %%eax\n\t" + "subl %5, %%edi\n\t" +# endif + "shll $3, %%edi\n\t" + "bsfl %%eax, %%edx\n\t" + "addl %%edi, %%edx\n\t" + "1:\t\n" + : "=d" (iBit) + , "=&c" (uECX) + , "=&D" (uEDI) + , "=&a" (uEAX) + : "0" (0xffffffff) + , "mr" (pvBitmap) + , "1" (cBits >> 5) + , "2" (pvBitmap) + , "3" (0) + : "cc"); +# else + cBits = RT_ALIGN_32(cBits, 32); + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdi, [pvBitmap] + mov rbx, rdi +# else + mov edi, [pvBitmap] + mov ebx, edi +# endif + mov edx, 0ffffffffh + xor eax, eax + mov ecx, [cBits] + shr ecx, 5 + repe scasd + je done +# ifdef RT_ARCH_AMD64 + lea rdi, [rdi - 4] + mov eax, [rdi] + sub rdi, rbx +# else + lea edi, [edi - 4] + mov eax, [edi] + sub edi, ebx +# endif + shl edi, 3 + bsf edx, eax + add edx, edi + done: + mov [iBit], edx + } +# endif + return iBit; + } + return -1; +} +#endif + + +/** + * Finds the next set bit in a bitmap. + * + * @returns Index of the next set bit. + * @returns -1 if no set bit was found. + * @param pvBitmap Pointer to the bitmap (little endian). + * @param cBits The number of bits in the bitmap. Multiple of 32. + * @param iBitPrev The bit returned from the last search. + * The search will start at iBitPrev + 1. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(int) ASMBitNextSet(const volatile void RT_FAR *pvBitmap, uint32_t cBits, uint32_t iBitPrev) RT_NOTHROW_PROTO; +#else +DECLINLINE(int) ASMBitNextSet(const volatile void RT_FAR *pvBitmap, uint32_t cBits, uint32_t iBitPrev) RT_NOTHROW_DEF +{ + const volatile uint32_t RT_FAR *pau32Bitmap = (const volatile uint32_t RT_FAR *)pvBitmap; + int iBit = ++iBitPrev & 31; + if (iBit) + { + /* + * Inspect the 32-bit word containing the unaligned bit. + */ + uint32_t u32 = pau32Bitmap[iBitPrev / 32] >> iBit; + +# if RT_INLINE_ASM_USES_INTRIN + unsigned long ulBit = 0; + if (_BitScanForward(&ulBit, u32)) + return ulBit + iBitPrev; +# else +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("bsf %1, %0\n\t" + "jnz 1f\n\t" /** @todo use conditional move for 64-bit? */ + "movl $-1, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "r" (u32) + : "cc"); +# else + __asm + { + mov edx, [u32] + bsf eax, edx + jnz done + mov eax, 0ffffffffh + done: + mov [iBit], eax + } +# endif + if (iBit >= 0) + return iBit + (int)iBitPrev; +# endif + + /* + * Skip ahead and see if there is anything left to search. + */ + iBitPrev |= 31; + iBitPrev++; + if (cBits <= (uint32_t)iBitPrev) + return -1; + } + + /* + * 32-bit aligned search, let ASMBitFirstClear do the dirty work. + */ + iBit = ASMBitFirstSet(&pau32Bitmap[iBitPrev / 32], cBits - iBitPrev); + if (iBit >= 0) + iBit += iBitPrev; + return iBit; +} +#endif + + +/** + * Finds the first bit which is set in the given 32-bit integer. + * Bits are numbered from 1 (least significant) to 32. + * + * @returns index [1..32] of the first set bit. + * @returns 0 if all bits are cleared. + * @param u32 Integer to search for set bits. + * @remarks Similar to ffs() in BSD. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitFirstSetU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitFirstSetU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; + if (_BitScanForward(&iBit, u32)) + iBit++; + else + iBit = 0; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint32_t iBit; + __asm__ __volatile__("bsf %1, %0\n\t" + "jnz 1f\n\t" + "xorl %0, %0\n\t" + "jmp 2f\n" + "1:\n\t" + "incl %0\n" + "2:\n\t" + : "=r" (iBit) + : "rm" (u32) + : "cc"); +# else + uint32_t iBit; + _asm + { + bsf eax, [u32] + jnz found + xor eax, eax + jmp done + found: + inc eax + done: + mov [iBit], eax + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + /* + * Using the "count leading zeros (clz)" instruction here because there + * is no dedicated instruction to get the first set bit. + * Need to reverse the bits in the value with "rbit" first because + * "clz" starts counting from the most significant bit. + */ + uint32_t iBit; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "rbit %w[uVal], %w[uVal]\n\t" + "clz %w[iBit], %w[uVal]\n\t" +# else + "rbit %[uVal], %[uVal]\n\t" + "clz %[iBit], %[uVal]\n\t" +# endif + : [uVal] "=r" (u32) + , [iBit] "=r" (iBit) + : "[uVal]" (u32)); + if (iBit != 32) + iBit++; + else + iBit = 0; /* No bit set. */ + +# else +# error "Port me" +# endif + return iBit; +} +#endif + + +/** + * Finds the first bit which is set in the given 32-bit integer. + * Bits are numbered from 1 (least significant) to 32. + * + * @returns index [1..32] of the first set bit. + * @returns 0 if all bits are cleared. + * @param i32 Integer to search for set bits. + * @remark Similar to ffs() in BSD. + */ +DECLINLINE(unsigned) ASMBitFirstSetS32(int32_t i32) RT_NOTHROW_DEF +{ + return ASMBitFirstSetU32((uint32_t)i32); +} + + +/** + * Finds the first bit which is set in the given 64-bit integer. + * + * Bits are numbered from 1 (least significant) to 64. + * + * @returns index [1..64] of the first set bit. + * @returns 0 if all bits are cleared. + * @param u64 Integer to search for set bits. + * @remarks Similar to ffs() in BSD. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitFirstSetU64(uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitFirstSetU64(uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; +# if ARCH_BITS == 64 + if (_BitScanForward64(&iBit, u64)) + iBit++; + else + iBit = 0; +# else + if (_BitScanForward(&iBit, (uint32_t)u64)) + iBit++; + else if (_BitScanForward(&iBit, (uint32_t)(u64 >> 32))) + iBit += 33; + else + iBit = 0; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t iBit; + __asm__ __volatile__("bsfq %1, %0\n\t" + "jnz 1f\n\t" + "xorl %k0, %k0\n\t" + "jmp 2f\n" + "1:\n\t" + "incl %k0\n" + "2:\n\t" + : "=r" (iBit) + : "rm" (u64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) + uint64_t iBit; + __asm__ __volatile__("rbit %[uVal], %[uVal]\n\t" + "clz %[iBit], %[uVal]\n\t" + : [uVal] "=r" (u64) + , [iBit] "=r" (iBit) + : "[uVal]" (u64)); + if (iBit != 64) + iBit++; + else + iBit = 0; /* No bit set. */ + +# else + unsigned iBit = ASMBitFirstSetU32((uint32_t)u64); + if (!iBit) + { + iBit = ASMBitFirstSetU32((uint32_t)(u64 >> 32)); + if (iBit) + iBit += 32; + } +# endif + return (unsigned)iBit; +} +#endif + + +/** + * Finds the first bit which is set in the given 16-bit integer. + * + * Bits are numbered from 1 (least significant) to 16. + * + * @returns index [1..16] of the first set bit. + * @returns 0 if all bits are cleared. + * @param u16 Integer to search for set bits. + * @remarks For 16-bit bs3kit code. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitFirstSetU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitFirstSetU16(uint16_t u16) RT_NOTHROW_DEF +{ + return ASMBitFirstSetU32((uint32_t)u16); +} +#endif + + +/** + * Finds the last bit which is set in the given 32-bit integer. + * Bits are numbered from 1 (least significant) to 32. + * + * @returns index [1..32] of the last set bit. + * @returns 0 if all bits are cleared. + * @param u32 Integer to search for set bits. + * @remark Similar to fls() in BSD. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitLastSetU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitLastSetU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; + if (_BitScanReverse(&iBit, u32)) + iBit++; + else + iBit = 0; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint32_t iBit; + __asm__ __volatile__("bsrl %1, %0\n\t" + "jnz 1f\n\t" + "xorl %0, %0\n\t" + "jmp 2f\n" + "1:\n\t" + "incl %0\n" + "2:\n\t" + : "=r" (iBit) + : "rm" (u32) + : "cc"); +# else + uint32_t iBit; + _asm + { + bsr eax, [u32] + jnz found + xor eax, eax + jmp done + found: + inc eax + done: + mov [iBit], eax + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t iBit; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "clz %w[iBit], %w[uVal]\n\t" +# else + "clz %[iBit], %[uVal]\n\t" +# endif + : [iBit] "=r" (iBit) + : [uVal] "r" (u32)); + iBit = 32 - iBit; + +# else +# error "Port me" +# endif + return iBit; +} +#endif + + +/** + * Finds the last bit which is set in the given 32-bit integer. + * Bits are numbered from 1 (least significant) to 32. + * + * @returns index [1..32] of the last set bit. + * @returns 0 if all bits are cleared. + * @param i32 Integer to search for set bits. + * @remark Similar to fls() in BSD. + */ +DECLINLINE(unsigned) ASMBitLastSetS32(int32_t i32) RT_NOTHROW_DEF +{ + return ASMBitLastSetU32((uint32_t)i32); +} + + +/** + * Finds the last bit which is set in the given 64-bit integer. + * + * Bits are numbered from 1 (least significant) to 64. + * + * @returns index [1..64] of the last set bit. + * @returns 0 if all bits are cleared. + * @param u64 Integer to search for set bits. + * @remark Similar to fls() in BSD. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitLastSetU64(uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitLastSetU64(uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; +# if ARCH_BITS == 64 + if (_BitScanReverse64(&iBit, u64)) + iBit++; + else + iBit = 0; +# else + if (_BitScanReverse(&iBit, (uint32_t)(u64 >> 32))) + iBit += 33; + else if (_BitScanReverse(&iBit, (uint32_t)u64)) + iBit++; + else + iBit = 0; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t iBit; + __asm__ __volatile__("bsrq %1, %0\n\t" + "jnz 1f\n\t" + "xorl %k0, %k0\n\t" + "jmp 2f\n" + "1:\n\t" + "incl %k0\n" + "2:\n\t" + : "=r" (iBit) + : "rm" (u64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) + uint64_t iBit; + __asm__ __volatile__("clz %[iBit], %[uVal]\n\t" + : [iBit] "=r" (iBit) + : [uVal] "r" (u64)); + iBit = 64 - iBit; + +# else + unsigned iBit = ASMBitLastSetU32((uint32_t)(u64 >> 32)); + if (iBit) + iBit += 32; + else + iBit = ASMBitLastSetU32((uint32_t)u64); +# endif + return (unsigned)iBit; +} +#endif + + +/** + * Finds the last bit which is set in the given 16-bit integer. + * + * Bits are numbered from 1 (least significant) to 16. + * + * @returns index [1..16] of the last set bit. + * @returns 0 if all bits are cleared. + * @param u16 Integer to search for set bits. + * @remarks For 16-bit bs3kit code. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitLastSetU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitLastSetU16(uint16_t u16) RT_NOTHROW_DEF +{ + return ASMBitLastSetU32((uint32_t)u16); +} +#endif + + +/** + * Count the number of leading zero bits in the given 32-bit integer. + * + * The counting starts with the most significate bit. + * + * @returns Number of most significant zero bits. + * @returns 32 if all bits are cleared. + * @param u32 Integer to consider. + * @remarks Similar to __builtin_clz() in gcc, except defined zero input result. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountLeadingZerosU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountLeadingZerosU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; + if (!_BitScanReverse(&iBit, u32)) + return 32; + return 31 - (unsigned)iBit; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint32_t iBit; +# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) && 0 /* significantly slower on 10980xe; 929 vs 237 ps/call */ + __asm__ __volatile__("bsrl %1, %0\n\t" + "cmovzl %2, %0\n\t" + : "=&r" (iBit) + : "rm" (u32) + , "rm" ((int32_t)-1) + : "cc"); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("bsr %1, %0\n\t" + "jnz 1f\n\t" + "mov $-1, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "rm" (u32) + : "cc"); +# else + _asm + { + bsr eax, [u32] + jnz found + mov eax, -1 + found: + mov [iBit], eax + } +# endif + return 31 - iBit; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t iBit; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "clz %w[iBit], %w[uVal]\n\t" +# else + "clz %[iBit], %[uVal]\n\t" +# endif + : [uVal] "=r" (u32) + , [iBit] "=r" (iBit) + : "[uVal]" (u32)); + return iBit; + +# elif defined(__GNUC__) + AssertCompile(sizeof(u32) == sizeof(unsigned int)); + return u32 ? __builtin_clz(u32) : 32; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Count the number of leading zero bits in the given 64-bit integer. + * + * The counting starts with the most significate bit. + * + * @returns Number of most significant zero bits. + * @returns 64 if all bits are cleared. + * @param u64 Integer to consider. + * @remarks Similar to __builtin_clzl() in gcc, except defined zero input + * result. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountLeadingZerosU64(uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountLeadingZerosU64(uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; +# if ARCH_BITS == 64 + if (_BitScanReverse64(&iBit, u64)) + return 63 - (unsigned)iBit; +# else + if (_BitScanReverse(&iBit, (uint32_t)(u64 >> 32))) + return 31 - (unsigned)iBit; + if (_BitScanReverse(&iBit, (uint32_t)u64)) + return 63 - (unsigned)iBit; +# endif + return 64; + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t iBit; +# if 0 /* 10980xe benchmark: 932 ps/call - the slower variant */ + __asm__ __volatile__("bsrq %1, %0\n\t" + "cmovzq %2, %0\n\t" + : "=&r" (iBit) + : "rm" (u64) + , "rm" ((int64_t)-1) + : "cc"); +# else /* 10980xe benchmark: 262 ps/call */ + __asm__ __volatile__("bsrq %1, %0\n\t" + "jnz 1f\n\t" + "mov $-1, %0\n\t" + "1:\n\t" + : "=&r" (iBit) + : "rm" (u64) + : "cc"); +# endif + return 63 - (unsigned)iBit; + +# elif defined(RT_ARCH_ARM64) + uint64_t iBit; + __asm__ __volatile__("clz %[iBit], %[uVal]\n\t" + : [uVal] "=r" (u64) + , [iBit] "=r" (iBit) + : "[uVal]" (u64)); + return (unsigned)iBit; + +# elif defined(__GNUC__) && ARCH_BITS == 64 + AssertCompile(sizeof(u64) == sizeof(unsigned long)); + return u64 ? __builtin_clzl(u64) : 64; + +# else + unsigned iBit = ASMCountLeadingZerosU32((uint32_t)(u64 >> 32)); + if (iBit == 32) + iBit = ASMCountLeadingZerosU32((uint32_t)u64) + 32; + return iBit; +# endif +} +#endif + + +/** + * Count the number of leading zero bits in the given 16-bit integer. + * + * The counting starts with the most significate bit. + * + * @returns Number of most significant zero bits. + * @returns 16 if all bits are cleared. + * @param u16 Integer to consider. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountLeadingZerosU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountLeadingZerosU16(uint16_t u16) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && 0 /* slower (10980xe: 987 vs 292 ps/call) */ + uint16_t iBit; + __asm__ __volatile__("bsrw %1, %0\n\t" + "jnz 1f\n\t" + "mov $-1, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "rm" (u16) + : "cc"); + return 15 - (int16_t)iBit; +# else + return ASMCountLeadingZerosU32((uint32_t)u16) - 16; +# endif +} +#endif + + +/** + * Count the number of trailing zero bits in the given 32-bit integer. + * + * The counting starts with the least significate bit, i.e. the zero bit. + * + * @returns Number of lest significant zero bits. + * @returns 32 if all bits are cleared. + * @param u32 Integer to consider. + * @remarks Similar to __builtin_ctz() in gcc, except defined zero input result. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountTrailingZerosU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountTrailingZerosU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; + if (!_BitScanForward(&iBit, u32)) + return 32; + return (unsigned)iBit; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint32_t iBit; +# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) && 0 /* significantly slower on 10980xe; 932 vs 240 ps/call */ + __asm__ __volatile__("bsfl %1, %0\n\t" + "cmovzl %2, %0\n\t" + : "=&r" (iBit) + : "rm" (u32) + , "rm" ((int32_t)32) + : "cc"); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("bsfl %1, %0\n\t" + "jnz 1f\n\t" + "mov $32, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "rm" (u32) + : "cc"); +# else + _asm + { + bsf eax, [u32] + jnz found + mov eax, 32 + found: + mov [iBit], eax + } +# endif + return iBit; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + /* Invert the bits and use clz. */ + uint32_t iBit; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "rbit %w[uVal], %w[uVal]\n\t" + "clz %w[iBit], %w[uVal]\n\t" +# else + "rbit %[uVal], %[uVal]\n\t" + "clz %[iBit], %[uVal]\n\t" +# endif + : [uVal] "=r" (u32) + , [iBit] "=r" (iBit) + : "[uVal]" (u32)); + return iBit; + +# elif defined(__GNUC__) + AssertCompile(sizeof(u32) == sizeof(unsigned int)); + return u32 ? __builtin_ctz(u32) : 32; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Count the number of trailing zero bits in the given 64-bit integer. + * + * The counting starts with the least significate bit. + * + * @returns Number of least significant zero bits. + * @returns 64 if all bits are cleared. + * @param u64 Integer to consider. + * @remarks Similar to __builtin_ctzl() in gcc, except defined zero input + * result. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountTrailingZerosU64(uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountTrailingZerosU64(uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; +# if ARCH_BITS == 64 + if (_BitScanForward64(&iBit, u64)) + return (unsigned)iBit; +# else + if (_BitScanForward(&iBit, (uint32_t)u64)) + return (unsigned)iBit; + if (_BitScanForward(&iBit, (uint32_t)(u64 >> 32))) + return (unsigned)iBit + 32; +# endif + return 64; + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t iBit; +# if 0 /* 10980xe benchmark: 932 ps/call - the slower variant */ + __asm__ __volatile__("bsfq %1, %0\n\t" + "cmovzq %2, %0\n\t" + : "=&r" (iBit) + : "rm" (u64) + , "rm" ((int64_t)64) + : "cc"); +# else /* 10980xe benchmark: 262 ps/call */ + __asm__ __volatile__("bsfq %1, %0\n\t" + "jnz 1f\n\t" + "mov $64, %0\n\t" + "1:\n\t" + : "=&r" (iBit) + : "rm" (u64) + : "cc"); +# endif + return (unsigned)iBit; + +# elif defined(RT_ARCH_ARM64) + /* Invert the bits and use clz. */ + uint64_t iBit; + __asm__ __volatile__("rbit %[uVal], %[uVal]\n\t" + "clz %[iBit], %[uVal]\n\t" + : [uVal] "=r" (u64) + , [iBit] "=r" (iBit) + : "[uVal]" (u64)); + return (unsigned)iBit; + +# elif defined(__GNUC__) && ARCH_BITS == 64 + AssertCompile(sizeof(u64) == sizeof(unsigned long)); + return u64 ? __builtin_ctzl(u64) : 64; + +# else + unsigned iBit = ASMCountTrailingZerosU32((uint32_t)u64); + if (iBit == 32) + iBit = ASMCountTrailingZerosU32((uint32_t)(u64 >> 32)) + 32; + return iBit; +# endif +} +#endif + + +/** + * Count the number of trailing zero bits in the given 16-bit integer. + * + * The counting starts with the most significate bit. + * + * @returns Number of most significant zero bits. + * @returns 16 if all bits are cleared. + * @param u16 Integer to consider. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountTrailingZerosU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountTrailingZerosU16(uint16_t u16) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && 0 /* slower (10980xe: 992 vs 349 ps/call) */ + uint16_t iBit; + __asm__ __volatile__("bsfw %1, %0\n\t" + "jnz 1f\n\t" + "mov $16, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "rm" (u16) + : "cc"); + return iBit; +# else + return ASMCountTrailingZerosU32((uint32_t)u16 | UINT32_C(0x10000)); +#endif +} +#endif + + +/** + * Rotate 32-bit unsigned value to the left by @a cShift. + * + * @returns Rotated value. + * @param u32 The value to rotate. + * @param cShift How many bits to rotate by. + */ +#ifdef __WATCOMC__ +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRotateLeftU32(uint32_t u32, unsigned cShift) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMRotateLeftU32(uint32_t u32, uint32_t cShift) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return _rotl(u32, cShift); + +# elif RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) + __asm__ __volatile__("roll %b1, %0" : "=g" (u32) : "Ic" (cShift), "0" (u32) : "cc"); + return u32; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "ror %w[uRet], %w[uVal], %w[cShift]\n\t" +# else + "ror %[uRet], %[uVal], %[cShift]\n\t" +# endif + : [uRet] "=r" (u32) + : [uVal] "[uRet]" (u32) + , [cShift] "r" (32 - (cShift & 31))); /** @todo there is an immediate form here */ + return u32; + +# else + cShift &= 31; + return (u32 << cShift) | (u32 >> (32 - cShift)); +# endif +} +#endif + + +/** + * Rotate 32-bit unsigned value to the right by @a cShift. + * + * @returns Rotated value. + * @param u32 The value to rotate. + * @param cShift How many bits to rotate by. + */ +#ifdef __WATCOMC__ +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRotateRightU32(uint32_t u32, unsigned cShift) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMRotateRightU32(uint32_t u32, uint32_t cShift) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return _rotr(u32, cShift); + +# elif RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) + __asm__ __volatile__("rorl %b1, %0" : "=g" (u32) : "Ic" (cShift), "0" (u32) : "cc"); + return u32; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "ror %w[uRet], %w[uVal], %w[cShift]\n\t" +# else + "ror %[uRet], %[uVal], %[cShift]\n\t" +# endif + : [uRet] "=r" (u32) + : [uVal] "[uRet]" (u32) + , [cShift] "r" (cShift & 31)); /** @todo there is an immediate form here */ + return u32; + +# else + cShift &= 31; + return (u32 >> cShift) | (u32 << (32 - cShift)); +# endif +} +#endif + + +/** + * Rotate 64-bit unsigned value to the left by @a cShift. + * + * @returns Rotated value. + * @param u64 The value to rotate. + * @param cShift How many bits to rotate by. + */ +DECLINLINE(uint64_t) ASMRotateLeftU64(uint64_t u64, uint32_t cShift) RT_NOTHROW_DEF +{ +#if RT_INLINE_ASM_USES_INTRIN + return _rotl64(u64, cShift); + +#elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("rolq %b1, %0" : "=g" (u64) : "Jc" (cShift), "0" (u64) : "cc"); + return u64; + +#elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_X86) + uint32_t uSpill; + __asm__ __volatile__("testb $0x20, %%cl\n\t" /* if (cShift >= 0x20) { swap(u64.hi, u64lo); cShift -= 0x20; } */ + "jz 1f\n\t" + "xchgl %%eax, %%edx\n\t" + "1:\n\t" + "andb $0x1f, %%cl\n\t" /* if (cShift & 0x1f) { */ + "jz 2f\n\t" + "movl %%edx, %2\n\t" /* save the hi value in %3. */ + "shldl %%cl,%%eax,%%edx\n\t" /* shift the hi value left, feeding MSBits from the low value. */ + "shldl %%cl,%2,%%eax\n\t" /* shift the lo value left, feeding MSBits from the saved hi value. */ + "2:\n\t" /* } */ + : "=A" (u64) + , "=c" (cShift) + , "=r" (uSpill) + : "0" (u64) + , "1" (cShift) + : "cc"); + return u64; + +# elif defined(RT_ARCH_ARM64) + __asm__ __volatile__("ror %[uRet], %[uVal], %[cShift]\n\t" + : [uRet] "=r" (u64) + : [uVal] "[uRet]" (u64) + , [cShift] "r" ((uint64_t)(64 - (cShift & 63)))); /** @todo there is an immediate form here */ + return u64; + +#else + cShift &= 63; + return (u64 << cShift) | (u64 >> (64 - cShift)); +#endif +} + + +/** + * Rotate 64-bit unsigned value to the right by @a cShift. + * + * @returns Rotated value. + * @param u64 The value to rotate. + * @param cShift How many bits to rotate by. + */ +DECLINLINE(uint64_t) ASMRotateRightU64(uint64_t u64, uint32_t cShift) RT_NOTHROW_DEF +{ +#if RT_INLINE_ASM_USES_INTRIN + return _rotr64(u64, cShift); + +#elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("rorq %b1, %0" : "=g" (u64) : "Jc" (cShift), "0" (u64) : "cc"); + return u64; + +#elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_X86) + uint32_t uSpill; + __asm__ __volatile__("testb $0x20, %%cl\n\t" /* if (cShift >= 0x20) { swap(u64.hi, u64lo); cShift -= 0x20; } */ + "jz 1f\n\t" + "xchgl %%eax, %%edx\n\t" + "1:\n\t" + "andb $0x1f, %%cl\n\t" /* if (cShift & 0x1f) { */ + "jz 2f\n\t" + "movl %%edx, %2\n\t" /* save the hi value in %3. */ + "shrdl %%cl,%%eax,%%edx\n\t" /* shift the hi value right, feeding LSBits from the low value. */ + "shrdl %%cl,%2,%%eax\n\t" /* shift the lo value right, feeding LSBits from the saved hi value. */ + "2:\n\t" /* } */ + : "=A" (u64) + , "=c" (cShift) + , "=r" (uSpill) + : "0" (u64) + , "1" (cShift) + : "cc"); + return u64; + +# elif defined(RT_ARCH_ARM64) + __asm__ __volatile__("ror %[uRet], %[uVal], %[cShift]\n\t" + : [uRet] "=r" (u64) + : [uVal] "[uRet]" (u64) + , [cShift] "r" ((uint64_t)(cShift & 63))); /** @todo there is an immediate form here */ + return u64; + +#else + cShift &= 63; + return (u64 >> cShift) | (u64 << (64 - cShift)); +#endif +} + +/** @} */ + + +/** @} */ + +/* + * Include #pragma aux definitions for Watcom C/C++. + */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 && defined(RT_ARCH_X86) +# define IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# undef IPRT_INCLUDED_asm_watcom_x86_16_h +# include "asm-watcom-x86-16.h" +#elif defined(__WATCOMC__) && ARCH_BITS == 32 && defined(RT_ARCH_X86) +# define IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +# undef IPRT_INCLUDED_asm_watcom_x86_32_h +# include "asm-watcom-x86-32.h" +#endif + +#endif /* !IPRT_INCLUDED_asm_h */ + diff --git a/include/iprt/asmdefs.mac b/include/iprt/asmdefs.mac new file mode 100644 index 00000000..d798a0c0 --- /dev/null +++ b/include/iprt/asmdefs.mac @@ -0,0 +1,1379 @@ +;; @file +; IPRT - Global YASM/NASM macros +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +; Special hack for bs3kit. +%ifdef RT_ASMDEFS_INC_FIRST_FILE + %include "asmdefs-first.mac" +%endif + +%ifndef ___iprt_asmdefs_mac +%define ___iprt_asmdefs_mac + + +;; @defgroup grp_rt_cdefs_size Size Constants +; (Of course, these are binary computer terms, not SI.) +; @{ +;; 1 K (Kilo) (1 024). +%define _1K 000000400h +;; 4 K (Kilo) (4 096). +%define _4K 000001000h +;; 8 K (Kilo) (8 192). +%define _8K 000002000h +;; 16 K (Kilo) (16 384). +%define _16K 000004000h +;; 32 K (Kilo) (32 768). +%define _32K 000008000h +;; 64 K (Kilo) (65 536). +%define _64K 000010000h +;; 128 K (Kilo) (131 072). +%define _128K 000020000h +;; 256 K (Kilo) (262 144). +%define _256K 000040000h +;; 512 K (Kilo) (524 288). +%define _512K 000080000h +;; 1 M (Mega) (1 048 576). +%define _1M 000100000h +;; 2 M (Mega) (2 097 152). +%define _2M 000200000h +;; 4 M (Mega) (4 194 304). +%define _4M 000400000h +;; 1 G (Giga) (1 073 741 824). +%define _1G 040000000h +;; 2 G (Giga) (2 147 483 648). +%define _2G 00000000080000000h +;; 4 G (Giga) (4 294 967 296). +%define _4G 00000000100000000h +;; 1 T (Tera) (1 099 511 627 776). +%define _1T 00000010000000000h +;; 1 P (Peta) (1 125 899 906 842 624). +%define _1P 00004000000000000h +;; 1 E (Exa) (1 152 921 504 606 846 976). +%define _1E 01000000000000000h +;; 2 E (Exa) (2 305 843 009 213 693 952). +%define _2E 02000000000000000h +;; @} + + +;; +; Define RT_STRICT for debug builds like iprt/cdefs.h does. +%ifndef RT_STRICT + %ifdef DEBUG + %define RT_STRICT + %endif +%endif +%ifdef RT_NO_STRICT + %undef RT_STRICT +%endif + +;; +; Make the mask for the given bit. +%define RT_BIT(bit) (1 << bit) + +;; +; Make the mask for the given bit. +%define RT_BIT_32(bit) (1 << bit) +;; +; Make the mask for the given bit. +%define RT_BIT_64(bit) (1 << bit) + +;; +; Makes a 32-bit unsigned (not type safe, but whatever) out of four byte values. +%define RT_MAKE_U32_FROM_U8(b0, b1, b2, b3) ( (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 ) + +;; Preprocessor concatenation macro. +%define RT_CONCAT(a_1,a_2) a_1 %+ a_2 + +;; Preprocessor concatenation macro, three arguments. +%define RT_CONCAT3(a_1,a_2,a_3) a_1 %+ a_2 %+ a_3 + +;; Preprocessor concatenation macro, four arguments. +%define RT_CONCAT4(a_1,a_2,a_3,a_4) a_1 %+ a_2 %+ a_3 %+ a_4 + +;; +; Trick for using RT_CONCAT and the like on %define names. +; @param 1 The name (expression. +; @param 2 The value. +%macro RT_DEFINE_EX 2 + %error 1=%1 2=%2 + %define %1 %2 +%endmacro + +;; +; Trick for using RT_CONCAT and the like on %xdefine names. +; @param 1 The name (expression. +; @param 2 The value. +%macro RT_XDEFINE_EX 2 + %xdefine %1 %2 +%endmacro + +;; +; Trick for using RT_CONCAT and the like on %undef names. +; @param 1 The name (expression. +%macro RT_UNDEF_EX 1 + %error 1=%1 + %undef %1 +%endmacro + +;; +; Empty define +%define RT_NOTHING + +;; Define ASM_FORMAT_PE64 if applicable. +%ifdef ASM_FORMAT_PE + %ifdef RT_ARCH_AMD64 + %define ASM_FORMAT_PE64 1 + %endif +%endif + +;; +; SEH64 macros. +%ifdef RT_ASM_WITH_SEH64 + %ifndef ASM_FORMAT_PE64 + %undef RT_ASM_WITH_SEH64 + %endif +%endif + +%ifdef RT_ASM_WITH_SEH64_ALT + %ifdef ASM_FORMAT_PE64 + ;; @name Register numbers. Used with RT_CONCAT to convert macro inputs to numbers. + ;; @{ + %define SEH64_PE_GREG_rax 0 + %define SEH64_PE_GREG_xAX 0 + %define SEH64_PE_GREG_rcx 1 + %define SEH64_PE_GREG_xCX 1 + %define SEH64_PE_GREG_rdx 2 + %define SEH64_PE_GREG_xDX 2 + %define SEH64_PE_GREG_rbx 3 + %define SEH64_PE_GREG_xBX 3 + %define SEH64_PE_GREG_rsp 4 + %define SEH64_PE_GREG_xSP 4 + %define SEH64_PE_GREG_rbp 5 + %define SEH64_PE_GREG_xBP 5 + %define SEH64_PE_GREG_rsi 6 + %define SEH64_PE_GREG_xSI 6 + %define SEH64_PE_GREG_rdi 7 + %define SEH64_PE_GREG_xDI 7 + %define SEH64_PE_GREG_r8 8 + %define SEH64_PE_GREG_r9 9 + %define SEH64_PE_GREG_r10 10 + %define SEH64_PE_GREG_r11 11 + %define SEH64_PE_GREG_r12 12 + %define SEH64_PE_GREG_r13 13 + %define SEH64_PE_GREG_r14 14 + %define SEH64_PE_GREG_r15 15 + ;; @} + + ;; @name PE unwind operations. + ;; @{ + %define SEH64_PE_PUSH_NONVOL 0 + %define SEH64_PE_ALLOC_LARGE 1 + %define SEH64_PE_ALLOC_SMALL 2 + %define SEH64_PE_SET_FPREG 3 + %define SEH64_PE_SAVE_NONVOL 4 + %define SEH64_PE_SAVE_NONVOL_FAR 5 + %define SEH64_PE_SAVE_XMM128 8 + %define SEH64_PE_SAVE_XMM128_FAR 9 + ;; @} + + ;; + ; Starts the unwind info for the manual SEH64 info generation. + ; @param 1 Function name. + %macro SEH64_ALT_START_UNWIND_INFO 1 + %assign seh64_idxOps 0 + %assign seh64_FrameReg SEH64_PE_GREG_rsp + %assign seh64_offFrame 0 + %define asm_seh64_proc %1 + %undef seh64_slot_bytes + %endmacro + + ;; We keep the unwind bytes in the seh64_slot_bytes (x)define, in reverse order as per spec. + %macro SEH64_APPEND_SLOT_PAIR 2 + %ifdef seh64_slot_bytes + %xdefine seh64_slot_bytes %1, %2, seh64_slot_bytes + %else + %xdefine seh64_slot_bytes %1, %2 + %endif + %endmacro + + ;; For multi-slot unwind info. + %macro SEH64_APPEND_SLOT_BYTES 2+ + %rep %0 + %rotate -1 + %ifdef seh64_slot_bytes + %xdefine seh64_slot_bytes %1, seh64_slot_bytes + %else + %xdefine seh64_slot_bytes %1 + %endif + %endrep + %endmacro + + %else + %undef RT_ASM_WITH_SEH64_ALT + %endif +%endif + +;; +; Records a xBP push. +%macro SEH64_PUSH_xBP 0 + %ifdef RT_ASM_WITH_SEH64 + [pushreg rbp] + + %elifdef RT_ASM_WITH_SEH64_ALT +RT_CONCAT(.seh64_op_label_,seh64_idxOps): + %ifdef ASM_FORMAT_PE64 + SEH64_APPEND_SLOT_PAIR RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_PUSH_NONVOL | (SEH64_PE_GREG_rbp << 4) + %endif + %assign seh64_idxOps seh64_idxOps + 1 + %endif +%endmacro + +;; +; Records a general register push. +; @param 1 Register name. +%macro SEH64_PUSH_GREG 1 + %ifdef RT_ASM_WITH_SEH64 + [pushreg %1] + + %elifdef RT_ASM_WITH_SEH64_ALT +RT_CONCAT(.seh64_op_label_,seh64_idxOps): + %ifdef ASM_FORMAT_PE64 + SEH64_APPEND_SLOT_PAIR RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_PUSH_NONVOL | (RT_CONCAT(SEH64_PE_GREG_,%1) << 4) + %endif + %assign seh64_idxOps seh64_idxOps + 1 + %endif +%endmacro + +;; +; Sets xBP as frame pointer that's pointing to a stack position %1 relative to xBP. +%macro SEH64_SET_FRAME_xBP 1 + %ifdef RT_ASM_WITH_SEH64 + [setframe rbp, %1] + + %elifdef RT_ASM_WITH_SEH64_ALT +RT_CONCAT(.seh64_op_label_,seh64_idxOps): + %ifdef ASM_FORMAT_PE64 + SEH64_APPEND_SLOT_PAIR RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_SET_FPREG | 0 ; vs2019 seems to put the offset in the info field + %assign seh64_FrameReg SEH64_PE_GREG_rbp + %assign seh64_offFrame %1 + %endif + %assign seh64_idxOps seh64_idxOps + 1 + %endif +%endmacro + +;; +; Records an ADD xSP, %1. +%macro SEH64_ALLOCATE_STACK 1 + %ifdef RT_ASM_WITH_SEH64 + [allocstack %1] + + %elifdef RT_ASM_WITH_SEH64_ALT +RT_CONCAT(.seh64_op_label_,seh64_idxOps): + %ifdef ASM_FORMAT_PE64 + %if (%1) & 7 + %error "SEH64_ALLOCATE_STACK must be a multiple of 8" + %endif + %if (%1) < 8 + %error "SEH64_ALLOCATE_STACK must have an argument that's 8 or higher." + %elif (%1) <= 128 + SEH64_APPEND_SLOT_PAIR RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_ALLOC_SMALL | ((((%1) / 8) - 1) << 4) + %elif (%1) < 512 + SEH64_APPEND_SLOT_BYTES RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_ALLOC_LARGE | 0, \ + ((%1) / 8) & 0xff, ((%1) / 8) >> 8 + %else + SEH64_APPEND_SLOT_BYTES RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_ALLOC_LARGE | 1, \ + (%1) & 0xff, ((%1) >> 8) & 0xff, ((%1) >> 16) & 0xff, ((%1) >> 24) & 0xff + %endif + %endif + %assign seh64_idxOps seh64_idxOps + 1 + %endif +%endmacro + +%macro SEH64_INFO_HELPER 1 +%if defined(%1) + dw %1 +%endif +%endmacro + +;; +; Ends the prologue. +%macro SEH64_END_PROLOGUE 0 +.end_of_prologue: + %ifdef RT_ASM_WITH_SEH64 + [endprolog] + + %elifdef RT_ASM_WITH_SEH64_ALT + %ifdef ASM_FORMAT_PE + ; Emit the unwind info now. + %ifndef ASM_DEFINED_XDATA_SECTION + %define ASM_DEFINED_XDATA_SECTION + section .xdata rdata align=4 + %else + section .xdata + align 4, db 0 + %endif +.unwind_info: + db 1 ; version 1 (3 bit), no flags (5 bits) + db .end_of_prologue - .start_of_prologue + + db (.unwind_info_array_end - .unwind_info_array) / 2 + db seh64_FrameReg | (seh64_offFrame & 0xf0) ; framereg and offset/16. +.unwind_info_array: + %ifdef seh64_slot_bytes + db seh64_slot_bytes + %undef seh64_slot_bytes + %endif +.unwind_info_array_end: + + ; Reset the segment + BEGINCODE + %endif + %endif +%endmacro + + +;; +; Align code, pad with INT3. +%define ALIGNCODE(alignment) align alignment, db 0cch + +;; +; Align data, pad with ZEROs. +%define ALIGNDATA(alignment) align alignment, db 0 + +;; +; Align BSS, pad with ZEROs. +%define ALIGNBSS(alignment) align alignment, resb 1 + +;; +; NAME_OVERLOAD can be defined by a .asm module to modify all the +; names created using the name macros in this files. +; This is handy when you've got some kind of template code. +%ifndef NAME_OVERLOAD + %ifdef RT_MANGLER_PREFIX + %define NAME_OVERLOAD(name) RT_MANGLER_PREFIX %+ name + %else + %define NAME_OVERLOAD(name) name + %endif +%endif + +;; +; Mangles the given name so it can be referenced using DECLASM() in the +; C/C++ world. +%ifndef ASM_FORMAT_BIN + %ifdef RT_ARCH_X86 + %ifdef RT_OS_OS2 + %define NAME(name) _ %+ NAME_OVERLOAD(name) + %endif + %ifdef RT_OS_WINDOWS + %define NAME(name) _ %+ NAME_OVERLOAD(name) + %endif + %endif + %ifdef RT_OS_DARWIN + %define NAME(name) _ %+ NAME_OVERLOAD(name) + %endif +%endif +%ifndef NAME + %define NAME(name) NAME_OVERLOAD(name) +%endif + +;; +; Mangles the given C name so it will _import_ the right symbol. +%ifdef ASM_FORMAT_PE + %define IMPNAME(name) __imp_ %+ NAME(name) +%else + %define IMPNAME(name) NAME(name) +%endif + +;; +; Gets the pointer to an imported object. +%ifdef ASM_FORMAT_PE + %ifdef RT_ARCH_AMD64 + %define IMP(name) qword [IMPNAME(name) wrt rip] + %else + %define IMP(name) dword [IMPNAME(name)] + %endif +%else + %define IMP(name) IMPNAME(name) +%endif + +;; +; Gets the pointer to an imported object. +%ifdef ASM_FORMAT_PE + %ifdef RT_ARCH_AMD64 + %define IMP_SEG(SegOverride, name) qword [SegOverride:IMPNAME(name) wrt rip] + %else + %define IMP_SEG(SegOverride, name) dword [SegOverride:IMPNAME(name)] + %endif +%else + %define IMP_SEG(SegOverride, name) IMPNAME(name) +%endif + +;; +; Declares an imported object for use with IMP2. +; @note May change the current section! +%macro EXTERN_IMP2 1 + extern IMPNAME(%1) + BEGINDATA + %ifdef ASM_FORMAT_MACHO + g_Imp2_ %+ %1: RTCCPTR_DEF IMPNAME(%1) + %endif +%endmacro + +;; +; Gets the pointer to an imported object, version 2. +%ifdef ASM_FORMAT_PE + %ifdef RT_ARCH_AMD64 + %define IMP2(name) qword [IMPNAME(name) wrt rip] + %else + %define IMP2(name) dword [IMPNAME(name)] + %endif +%elifdef ASM_FORMAT_ELF + %ifdef PIC + %ifdef RT_ARCH_AMD64 + %define IMP2(name) qword [rel IMPNAME(name) wrt ..got] + %else + %define IMP2(name) IMPNAME(name) wrt ..plt + %endif + %endif +%elifdef ASM_FORMAT_MACHO + %define IMP2(name) RTCCPTR_PRE [g_Imp2_ %+ name xWrtRIP] +%endif +%ifndef IMP2 + %define IMP2(name) IMPNAME(name) +%endif + + +;; +; Define a label as given, with a '$' prepended to permit using instruction +; names like fdiv as labels. +%macro SAFE_LABEL 1 +$%1: +%endmacro + +;; +; Global marker which is DECLASM() compatible. +%macro GLOBALNAME 1 +%ifndef ASM_FORMAT_BIN +global NAME(%1) +%endif +SAFE_LABEL NAME(%1) +%endmacro + +;; +; Global exported marker which is DECLASM() compatible. +%macro EXPORTEDNAME 1 + %ifdef ASM_FORMAT_PE + export %1=NAME(%1) + %endif + %ifdef __NASM__ + %ifdef ASM_FORMAT_OMF + export NAME(%1) NAME(%1) + %endif +%endif +GLOBALNAME %1 +%endmacro + +;; +; Same as GLOBALNAME_EX, but without the name mangling. +; +; @param %1 The symbol name - subjected to NAME(). +; @param %2 ELF and PE attributes: 'function', 'object', 'data', 'notype'. +; PE ignores all but 'function' (yasm only). Other formats ignores +; this completely. +; @param %3 Symbol visibility: 'hidden', 'protected', 'internal', and +; RT_NOTHING (for 'default' visibility). +; These are ELF attributes, but 'hidden' is translated to +; 'private_extern' for the Macho-O format. +; Ignored by other formats. +; +%macro GLOBALNAME_RAW 3 +%ifdef ASM_FORMAT_ELF +global %1:%2 %3 + +%elifdef ASM_FORMAT_PE + %ifidn %2,function + %ifdef __YASM__ ; nasm does not support any attributes, it errors out. So, nasm is no good with control flow guard atm. +global %1:function + %else +global %1 + %endif + %else +global %1 + %endif + +%elifdef ASM_FORMAT_MACHO + %ifidn %3,hidden +global %1:private_extern + %else +global %1 + %endif + +%elifndef ASM_FORMAT_BIN +global %1 + +%endif + +%1: +%endmacro + +;; +; Global marker which is DECLASM() compatible. +; +; @param %1 The symbol name - subjected to NAME(). +; @param %2 ELF and PE attributes: 'function', 'object', 'data', 'notype'. +; PE ignores all but 'function' (yasm only). Other formats ignores +; this completely. +; @param %3 Symbol visibility: 'hidden', 'protected', 'internal', and +; RT_NOTHING (for 'default' visibility). +; These are ELF attributes, but 'hidden' is translated to +; 'private_extern' for the Macho-O format. +; Ignored by other formats. +; +%macro GLOBALNAME_EX 3 +GLOBALNAME_RAW NAME(%1), %2, %3 +%endmacro + + +;; +; Global exported marker, raw version w/o automatic name mangling. +; +; @param %1 The internal symbol name. +; @param %2 The external symbol name. +; @param %3 ELF and PE attributes: 'function', 'object', 'data', 'notype'. +; PE ignores all but 'function' (yasm only). Other formats ignores +; this completely. +; +%macro EXPORTEDNAME_RAW 3 + %ifdef ASM_FORMAT_PE + export %2=%1 + %endif + %ifdef __NASM__ + %ifdef ASM_FORMAT_OMF + export %1 %2 + %endif +%endif +GLOBALNAME_RAW %1, %3, RT_NOTHING +%endmacro + +;; +; Global exported marker which is DECLASM() compatible. +; +; @param %1 The symbol name - subjected to NAME(). +; @param %2 ELF and PE attributes: 'function', 'object', 'data', 'notype'. +; PE ignores all but 'function' (yasm only). Other formats ignores +; this completely. +; +%macro EXPORTEDNAME_EX 2 +EXPORTEDNAME_RAW NAME(%1), %1, %2 +%endmacro + + +;; +; Begins a procedure, raw version w/o automatic name mangling. +%macro BEGINPROC_RAW 1 + %ifdef RT_ASM_WITH_SEH64_ALT + SEH64_ALT_START_UNWIND_INFO %1 + %endif + %ifdef RT_ASM_WITH_SEH64 +global %1:function +proc_frame %1 + %else +GLOBALNAME_RAW %1, function, hidden + %endif +.start_of_prologue: +%endmacro + +;; +; Begins a C callable (DECLASM) procedure. +%macro BEGINPROC 1 +BEGINPROC_RAW NAME(%1) +%endmacro + + +;; +; Begins a exported procedure, raw version w/o automatic name mangling. +; @param 1 Internal name. +; @param 2 Exported name. +%macro BEGINPROC_EXPORTED_RAW 2 + %ifdef RT_ASM_WITH_SEH64_ALT + SEH64_ALT_START_UNWIND_INFO %1 + %endif + %ifdef RT_ASM_WITH_SEH64 + %ifdef ASM_FORMAT_PE +export %2=%1 + %endif +global %1:function +proc_frame %1 + %else +EXPORTEDNAME_RAW %1, %2, function + %endif +.start_of_prologue: +%endmacro + +;; +; Begins a C callable (DECLASM) exported procedure. +%macro BEGINPROC_EXPORTED 1 +BEGINPROC_EXPORTED_RAW NAME(%1), %1 +%endmacro + + +;; +; Ends a procedure, raw version w/o automatic name mangling. +%macro ENDPROC_RAW 1 + %ifdef RT_ASM_WITH_SEH64 +endproc_frame + %endif +GLOBALNAME_RAW %1 %+ _EndProc, , hidden ; no function here, this isn't a valid code flow target. +%ifdef ASM_FORMAT_ELF + %ifndef __NASM__ ; nasm does this in the global directive. +size %1 %1 %+ _EndProc - %1 +size %1 %+ _EndProc 4 ; make it non-zero to shut up warnigns from Linux's objtool. + %endif +%endif + db 0xCC, 0xCC, 0xCC, 0xCC + + %ifdef RT_ASM_WITH_SEH64_ALT + %ifdef ASM_FORMAT_PE + ; Emit the RUNTIME_FUNCTION entry. The linker is picky here, no label. + %ifndef ASM_DEFINED_PDATA_SECTION + %define ASM_DEFINED_PDATA_SECTION + section .pdata rdata align=4 + %else + section .pdata + %endif + dd %1 wrt ..imagebase + dd %1 %+ _EndProc wrt ..imagebase + dd %1 %+ .unwind_info wrt ..imagebase + + ; Restore code section. + BEGINCODE + %endif + %endif +%endmacro + +;; +; Ends a C callable procedure. +%macro ENDPROC 1 +ENDPROC_RAW NAME(%1) +%endmacro + + +; +; Do OMF and Mach-O/Yasm segment definitions +; +; Both format requires this to get the segment order right, in the Mach-O/Yasm case +; it's only to make sure the .bss section ends up last (it's not declared here). +; +%ifdef ASM_FORMAT_OMF + %ifndef RT_NOINC_SEGMENTS + + ; 16-bit segments first (OMF / OS/2 specific). + %ifdef RT_INCL_16BIT_SEGMENTS + segment DATA16 public CLASS=FAR_DATA align=16 use16 + segment DATA16_INIT public CLASS=FAR_DATA align=16 use16 + group DGROUP16 DATA16 DATA16_INIT + + ;; + ; Begins 16-bit data + %macro BEGINDATA16 0 + segment DATA16 + %endmacro + + ;; + ; Begins 16-bit init data + %macro BEGINDATA16INIT 0 + segment DATA16_INIT + %endmacro + + segment CODE16 public CLASS=FAR_CODE align=16 use16 + segment CODE16_INIT public CLASS=FAR_CODE align=16 use16 + group CGROUP16 CODE16 CODE16_INIT + + ;; + ; Begins 16-bit code + %macro BEGINCODE16 0 + segment CODE16 + %endmacro + + ;; + ; Begins 16-bit init code + %macro BEGINCODE16INIT 0 + segment CODE16_INIT + %endmacro + + %endif + + ; 32-bit segments. + segment TEXT32 public CLASS=CODE align=16 use32 flat + segment DATA32 public CLASS=DATA align=16 use32 flat + segment BSS32 public CLASS=BSS align=16 use32 flat + + ; Make the TEXT32 segment default. + segment TEXT32 + %endif ; RT_NOINC_SEGMENTS +%endif + +%ifdef ASM_FORMAT_MACHO + %ifdef __YASM__ + section .text + section .data + %endif +%endif + + +;; +; Begins code +%ifdef ASM_FORMAT_OMF + %macro BEGINCODE 0 + segment TEXT32 + %endmacro +%else +%macro BEGINCODE 0 + section .text +%endmacro +%endif + +;; +; Begins constant (read-only) data +; +; @remarks This is mapped to the CODE section/segment when there isn't +; any dedicated const section/segment. (There is code that +; assumes this, so don't try change it.) +%ifdef ASM_FORMAT_OMF + %macro BEGINCONST 0 + segment TEXT32 + %endmacro +%else + %macro BEGINCONST 0 + %ifdef ASM_FORMAT_MACHO ;; @todo check the other guys too. + section .rodata + %else + section .text + %endif + %endmacro +%endif + +;; +; Begins initialized data +%ifdef ASM_FORMAT_OMF + %macro BEGINDATA 0 + segment DATA32 + %endmacro +%else +%macro BEGINDATA 0 + section .data +%endmacro +%endif + +;; +; Begins uninitialized data +%ifdef ASM_FORMAT_OMF + %macro BEGINBSS 0 + segment BSS32 + %endmacro +%else +%macro BEGINBSS 0 + section .bss +%endmacro +%endif + + + +;; @def ARCH_BITS +; Defines the bit count of the current context. +%ifndef ARCH_BITS + %ifdef RT_ARCH_AMD64 + %define ARCH_BITS 64 + %else + %define ARCH_BITS 32 + %endif +%endif + +;; @def HC_ARCH_BITS +; Defines the host architechture bit count. +%ifndef HC_ARCH_BITS + %ifndef IN_RC + %define HC_ARCH_BITS ARCH_BITS + %else + %define HC_ARCH_BITS 32 + %endif +%endif + +;; @def R3_ARCH_BITS +; Defines the host ring-3 architechture bit count. +%ifndef R3_ARCH_BITS + %ifdef IN_RING3 + %define R3_ARCH_BITS ARCH_BITS + %else + %define R3_ARCH_BITS HC_ARCH_BITS + %endif +%endif + +;; @def R0_ARCH_BITS +; Defines the host ring-0 architechture bit count. +%ifndef R0_ARCH_BITS + %ifdef IN_RING0 + %define R0_ARCH_BITS ARCH_BITS + %else + %define R0_ARCH_BITS HC_ARCH_BITS + %endif +%endif + +;; @def GC_ARCH_BITS +; Defines the guest architechture bit count. +%ifndef GC_ARCH_BITS + %ifdef IN_RC + %define GC_ARCH_BITS ARCH_BITS + %else + %define GC_ARCH_BITS 32 + %endif +%endif + + + +;; @def RTHCPTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the host context. +%if HC_ARCH_BITS == 64 + %define RTHCPTR_DEF dq +%else + %define RTHCPTR_DEF dd +%endif + +;; @def RTHCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the host context. +%if HC_ARCH_BITS == 64 + %define RTHCPTR_RES resq +%else + %define RTHCPTR_RES resd +%endif + +;; @def RTHCPTR_PRE +; The memory operand prefix used for a pointer in the host context. +%if HC_ARCH_BITS == 64 + %define RTHCPTR_PRE qword +%else + %define RTHCPTR_PRE dword +%endif + +;; @def RTHCPTR_CB +; The size in bytes of a pointer in the host context. +%if HC_ARCH_BITS == 64 + %define RTHCPTR_CB 8 +%else + %define RTHCPTR_CB 4 +%endif + + + +;; @def RTR0PTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the ring-0 host context. +%if R0_ARCH_BITS == 64 + %define RTR0PTR_DEF dq +%else + %define RTR0PTR_DEF dd +%endif + +;; @def RTR0PTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the ring-0 host context. +%if R0_ARCH_BITS == 64 + %define RTR0PTR_RES resq +%else + %define RTR0PTR_RES resd +%endif + +;; @def RTR0PTR_PRE +; The memory operand prefix used for a pointer in the ring-0 host context. +%if R0_ARCH_BITS == 64 + %define RTR0PTR_PRE qword +%else + %define RTR0PTR_PRE dword +%endif + +;; @def RTR0PTR_CB +; The size in bytes of a pointer in the ring-0 host context. +%if R0_ARCH_BITS == 64 + %define RTR0PTR_CB 8 +%else + %define RTR0PTR_CB 4 +%endif + + + +;; @def RTR3PTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the ring-3 host context. +%if R3_ARCH_BITS == 64 + %define RTR3PTR_DEF dq +%else + %define RTR3PTR_DEF dd +%endif + +;; @def RTR3PTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the ring-3 host context. +%if R3_ARCH_BITS == 64 + %define RTR3PTR_RES resq +%else + %define RTR3PTR_RES resd +%endif + +;; @def RTR3PTR_PRE +; The memory operand prefix used for a pointer in the ring-3 host context. +%if R3_ARCH_BITS == 64 + %define RTR3PTR_PRE qword +%else + %define RTR3PTR_PRE dword +%endif + +;; @def RTR3PTR_CB +; The size in bytes of a pointer in the ring-3 host context. +%if R3_ARCH_BITS == 64 + %define RTR3PTR_CB 8 +%else + %define RTR3PTR_CB 4 +%endif + + + +;; @def RTGCPTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the guest context. +%if GC_ARCH_BITS == 64 + %define RTGCPTR_DEF dq +%else + %define RTGCPTR_DEF dd +%endif + +;; @def RTGCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the guest context. +%if GC_ARCH_BITS == 64 + %define RTGCPTR_RES resq +%else + %define RTGCPTR_RES resd +%endif + +%define RTGCPTR32_RES resd +%define RTGCPTR64_RES resq + +;; @def RTGCPTR_PRE +; The memory operand prefix used for a pointer in the guest context. +%if GC_ARCH_BITS == 64 + %define RTGCPTR_PRE qword +%else + %define RTGCPTR_PRE dword +%endif + +;; @def RTGCPTR_CB +; The size in bytes of a pointer in the guest context. +%if GC_ARCH_BITS == 64 + %define RTGCPTR_CB 8 +%else + %define RTGCPTR_CB 4 +%endif + + +;; @def RTRCPTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the raw mode context. +%define RTRCPTR_DEF dd + +;; @def RTRCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the raw mode context. +%define RTRCPTR_RES resd + +;; @def RTRCPTR_PRE +; The memory operand prefix used for a pointer in the raw mode context. +%define RTRCPTR_PRE dword + +;; @def RTRCPTR_CB +; The size in bytes of a pointer in the raw mode context. +%define RTRCPTR_CB 4 + + +;; @def RT_CCPTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the current context. + +;; @def RT_CCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the current context. + +;; @def RT_CCPTR_PRE +; The memory operand prefix used for a pointer in the current context. + +;; @def RT_CCPTR_CB +; The size in bytes of a pointer in the current context. + +%ifdef IN_RC + %define RTCCPTR_DEF RTRCPTR_DEF + %define RTCCPTR_RES RTRCPTR_RES + %define RTCCPTR_PRE RTRCPTR_PRE + %define RTCCPTR_CB RTRCPTR_CB +%else + %ifdef IN_RING0 + %define RTCCPTR_DEF RTR0PTR_DEF + %define RTCCPTR_RES RTR0PTR_RES + %define RTCCPTR_PRE RTR0PTR_PRE + %define RTCCPTR_CB RTR0PTR_CB + %else + %define RTCCPTR_DEF RTR3PTR_DEF + %define RTCCPTR_RES RTR3PTR_RES + %define RTCCPTR_PRE RTR3PTR_PRE + %define RTCCPTR_CB RTR3PTR_CB + %endif +%endif + + + +;; @def RTHCPHYS_DEF +; The pesudo-instruction used to declare an initialized host physical address. +%define RTHCPHYS_DEF dq + +;; @def RTHCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized +; host physical address variable +%define RTHCPHYS_RES resq + +;; @def RTHCPTR_PRE +; The memory operand prefix used for a host physical address. +%define RTHCPHYS_PRE qword + +;; @def RTHCPHYS_CB +; The size in bytes of a host physical address. +%define RTHCPHYS_CB 8 + + + +;; @def RTGCPHYS_DEF +; The pesudo-instruction used to declare an initialized guest physical address. +%define RTGCPHYS_DEF dq + +;; @def RTGCPHYS_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized +; guest physical address variable +%define RTGCPHYS_RES resq + +;; @def RTGCPTR_PRE +; The memory operand prefix used for a guest physical address. +%define RTGCPHYS_PRE qword + +;; @def RTGCPHYS_CB +; The size in bytes of a guest physical address. +%define RTGCPHYS_CB 8 + + + +;; +; The size of the long double C/C++ type. +; On 32-bit Darwin this is 16 bytes, on L4, Linux, OS/2 and Windows +; it's 12 bytes. +; @todo figure out what 64-bit Windows does (I don't recall right now). +%ifdef RT_ARCH_X86 + %ifdef RT_OS_DARWIN + %define RTLRD_CB 16 + %else + %define RTLRD_CB 12 + %endif +%else + %define RTLRD_CB 16 +%endif + +;; @name Floating point constants along the lines of the iprt/types.h types. +; @note YASM does support special the __Infinity__ and __NaN__ nasm tokens. +; @{ +%define RTFLOAT32U_QNAN_PLUS 0x7fc00000 +%define RTFLOAT32U_QNAN_MINUS 0xffc00000 +%define RTFLOAT32U_INF_PLUS 0x7f800000 +%define RTFLOAT32U_INF_MINUS 0xff800000 + +%define RTFLOAT64U_QNAN_PLUS 0x7ff8000000000000 +%define RTFLOAT64U_QNAN_MINUS 0xfff8000000000000 +%define RTFLOAT64U_INF_PLUS 0x7ff0000000000000 +%define RTFLOAT64U_INF_MINUS 0xfff0000000000000 +; @} + + + +;; @def ASM_CALL64_GCC +; Indicates that we're using the GCC 64-bit calling convention. +; @see @ref sec_vboxrem_amd64_compare (in VBoxREMWrapper.cpp) for an ABI description. + +;; @def ASM_CALL64_MSC +; Indicates that we're using the Microsoft 64-bit calling convention (fastcall on steroids). +; @see @ref sec_vboxrem_amd64_compare (in VBoxREMWrapper.cpp) for an ABI description. + +; Note: On X86 we're using cdecl unconditionally. There is not yet any common +; calling convention on AMD64, that's why we need to support two different ones.) + +%ifdef RT_ARCH_AMD64 + %ifndef ASM_CALL64_GCC + %ifndef ASM_CALL64_MSC + ; define it based on the object format. + %ifdef ASM_FORMAT_PE + %define ASM_CALL64_MSC + %else + %define ASM_CALL64_GCC + %endif + %endif + %else + ; sanity check. + %ifdef ASM_CALL64_MSC + %error "Only one of the ASM_CALL64_* defines should be defined!" + %endif + %endif +%else + ;later; %ifdef ASM_CALL64_GCC + ;later; %error "ASM_CALL64_GCC is defined without RT_ARCH_AMD64!" ASM_CALL64_GCC + ;later; %endif + ;later; %ifdef ASM_CALL64_MSC + ;later; %error "ASM_CALL64_MSC is defined without RT_ARCH_AMD64!" ASM_CALL64_MSC + ;later; %endif +%endif + + +;; @def RT_BEGINPROC +; Starts an IPRT procedure that should be exported unless IN_RT_STATIC is defined. +; +; @param 1 The function name. Will apply NAME macro to it. +%macro RT_BEGINPROC 1 + %ifdef IN_RT_STATIC +BEGINPROC %1 + %else +BEGINPROC_EXPORTED %1 + %endif +%endmacro ; RT_BEGINPROC + + +;; @def RT_NOCRT +; Symbol name wrapper for the No-CRT bits. +; +; In order to coexist in the same process as other CRTs, we need to +; decorate the symbols such that they don't conflict the ones in the +; other CRTs. The result of such conflicts / duplicate symbols can +; confuse the dynamic loader on unix like systems. +; +; @remark Always feed the name to this macro first and then pass the result +; on to the next *NAME* macro. +; +%ifndef RT_WITHOUT_NOCRT_WRAPPERS + %define RT_NOCRT(name) nocrt_ %+ name +%else + %define RT_NOCRT(name) name +%endif + +;; @def RT_NOCRT_BEGINPROC +; Starts a NOCRT procedure, taking care of name wrapping and aliasing. +; +; Weak aliases for regular crt (%1) names to the nocrt_ prefixed ones will be +; added when RT_WITH_NOCRT_ALIASES is defined and the output is ELF. If +; RT_WITH_GENALIAS_NOCRT_ALIASES is undefined, strong aliases will be added for +; for non-ELF targets, otherwise it's assumed the genalias build tool will do +; the weak aliasing for us. +; +%macro RT_NOCRT_BEGINPROC 1 + %ifdef RT_WITH_NOCRT_ALIASES +BEGINPROC_EXPORTED RT_NOCRT(%1) + %ifdef ASM_FORMAT_ELF + ; ELF + %ifdef RT_WITH_NOCRT_UNDERSCORE_ALIASES +global NAME(_ %+ %1):function +weak NAME(_ %+ %1) +SAFE_LABEL NAME(_ %+ %1) + %endif +global NAME(%1):function +weak NAME(%1) +SAFE_LABEL NAME(%1) + + %elifndef RT_WITH_GENALIAS_NOCRT_ALIASES + ; non-ELF when not using genalias. + %ifdef RT_WITH_NOCRT_UNDERSCORE_ALIASES +GLOBALNAME _%1 + %endif +GLOBALNAME %1 + %endif + %else ; !RT_WITH_NOCRT_ALIASES +BEGINPROC_EXPORTED RT_NOCRT(%1) + %endif ; !RT_WITH_NOCRT_ALIASES +%endmacro ; RT_NOCRT_BEGINPROC + + + +;; @def xCB +; The stack unit size / The register unit size. + +;; @def xSP +; The stack pointer register (RSP or ESP). + +;; @def xBP +; The base pointer register (RBP or ESP). + +;; @def xAX +; RAX or EAX depending on context. + +;; @def xBX +; RBX or EBX depending on context. + +;; @def xCX +; RCX or ECX depending on context. + +;; @def xDX +; RDX or EDX depending on context. + +;; @def xDI +; RDI or EDI depending on context. + +;; @def xSI +; RSI or ESI depending on context. + +;; @def xWrtRIP +; 'wrt rip' for AMD64 targets, nothing for x86 ones. + +%ifdef RT_ARCH_AMD64 + %define xCB 8 + %define xSP rsp + %define xBP rbp + %define xAX rax + %define xBX rbx + %define xCX rcx + %define xDX rdx + %define xDI rdi + %define xSI rsi + %define xWrtRIP wrt rip +%else + %define xCB 4 + %define xSP esp + %define xBP ebp + %define xAX eax + %define xBX ebx + %define xCX ecx + %define xDX edx + %define xDI edi + %define xSI esi + %define xWrtRIP +%endif + + +; +; NASM sets __PASS__ to 0 in preprocess-only mode, and to 3 when only generating dependencies. +; YASM has no such setting which is why we must rely on kBuild to tell us what we're doing. +; For simplicity, we'll set the kBuild macro when using NASM. +; +%ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %ifdef __NASM__ + %if __PASS__ == 0 || __PASS__ == 3 + %define KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %endif + %endif +%endif + + +; +; Some simple compile time assertions. +; +; Note! Requires new kBuild to work with YASM (see above). +; + +;; +; Structure size assertion macro. +%define AssertCompileSize(a_Type, a_Size) AssertCompileSizeML a_Type, a_Size +%macro AssertCompileSizeML 2 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %assign AssertVar_cbActual %1 %+ _size + %assign AssertVar_cbExpected %2 + %if AssertVar_cbActual != AssertVar_cbExpected + %error %1 is AssertVar_cbActual bytes instead of AssertVar_cbExpected + %endif + %endif +%endmacro + +;; +; Structure size alignment assertion macro. + +%define AssertCompileSizeAlignment(a_Type, a_Align) AssertCompileSizeAlignmentML a_Type, a_Align +%macro AssertCompileSizeAlignmentML 2 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %assign AssertVar_cbActual %1 %+ _size + %assign AssertVar_cbAlignment %2 + %if (AssertVar_cbActual & (AssertVar_cbAlignment - 1)) != 0 + %error %1 is AssertVar_cbActual bytes, expected size with AssertVar_cbAlignment bytes alignment. + %endif + %endif +%endmacro + +;; +; Structure member offset assertion macro. +%define AssertCompileMemberOffset(a_Type, a_Member, a_off) AssertCompileMemberOffsetML a_Type, a_Member, a_off +%macro AssertCompileMemberOffsetML 3 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %assign AssertVar_offActual %1 %+ . %+ %2 + %assign AssertVar_offExpected %3 + %if AssertVar_offActual != AssertVar_offExpected + %error %1 %+ . %+ %2 is at AssertVar_offActual instead of AssertVar_offExpected + %endif + %endif +%endmacro + +;; +; Structure member alignment assertion macro. +%define AssertCompileMemberAlignment(a_Type, a_Member, a_cbAlign) AssertCompileMemberAlignmentML a_Type, a_Member, a_cbAlign +%macro AssertCompileMemberAlignmentML 3 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %assign AssertVar_offActual %1 %+ . %+ %2 + %assign AssertVar_cbAlign %3 + %if AssertVar_offActual & (AssertVar_cbAlign - 1) + %error %1 %+ . %+ %2 is at AssertVar_offActual, expected AssertVar_cbAlign alignment + %endif + %endif +%endmacro + +;; +; Generic compile time expression assertion. +%define AssertCompile(a_Expr) AssertCompileML { a_Expr } +%macro AssertCompileML 1 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %if (%1) != 1 + %assign AssertVar_uResult %1 + %error %1 => AssertVar_uResult + %endif + %endif +%endmacro + +%endif + diff --git a/include/iprt/asn1-generator-asn1-decoder.h b/include/iprt/asn1-generator-asn1-decoder.h new file mode 100644 index 00000000..bf0d762c --- /dev/null +++ b/include/iprt/asn1-generator-asn1-decoder.h @@ -0,0 +1,40 @@ +/** @file + * IPRT - ASN.1 Code Generator, the ASN1 Decoder Passes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_DECODE +#include + diff --git a/include/iprt/asn1-generator-core.h b/include/iprt/asn1-generator-core.h new file mode 100644 index 00000000..50dbb700 --- /dev/null +++ b/include/iprt/asn1-generator-core.h @@ -0,0 +1,50 @@ +/** @file + * IPRT - ASN.1 Code Generator, the ASN.1 Core Code (VTable, Compare, ..). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include +#include +#include + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_XTAG +#include +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_VTABLE +#include +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_DELETE +#include +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_ENUM +#include +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_COMPARE +#include + diff --git a/include/iprt/asn1-generator-init.h b/include/iprt/asn1-generator-init.h new file mode 100644 index 00000000..74665a8a --- /dev/null +++ b/include/iprt/asn1-generator-init.h @@ -0,0 +1,48 @@ +/** @file + * IPRT - ASN.1 Code Generator, the ASN1 Init, Clone and Modifier Passes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_INIT +#include +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_CLONE +#include +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_SETTERS_1 +#include +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_SETTERS_2 +#include +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_ARRAY +#include + diff --git a/include/iprt/asn1-generator-internal-header.h b/include/iprt/asn1-generator-internal-header.h new file mode 100644 index 00000000..9ec72f52 --- /dev/null +++ b/include/iprt/asn1-generator-internal-header.h @@ -0,0 +1,39 @@ +/** @file + * IPRT - ASN.1 Code Generator, the Internal Header File. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_INTERNAL_HEADER +#include + diff --git a/include/iprt/asn1-generator-pass.h b/include/iprt/asn1-generator-pass.h new file mode 100644 index 00000000..86cfd3ef --- /dev/null +++ b/include/iprt/asn1-generator-pass.h @@ -0,0 +1,1757 @@ +/** @file + * IPRT - ASN.1 Code Generator, One Pass. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef ___iprt_asn1_generator_pass_h /* (special, only part of the file) */ +#define ___iprt_asn1_generator_pass_h + +#include +#include + + +/** @def RTASN1TMPL_MEMBER_OPT_ANY + * Used for optional entries without any specific type at the end of a + * structure. + * + * For example PolicyQualifierInfo's qualifier member which is defined as: + * ANY DEFINED BY policyQualifierId + * + * Defaults to RTASN1TMPL_MEMBER_EX. + */ + +/** @def RTASN1TMPL_MEMBER_OPT_ITAG_EX + * Optional member with implict tag, extended version. + * + * This is what all the other RTASN1TMPL_MEMBER_OPT_ITAG* macros defere to. + */ +/** @def RTASN1TMPL_MEMBER_OPT_ITAG_CP + * Optional member of a typical primitive type with an implicit context tag. + * + * Examples of this can be found in AuthorityKeyIdentifier where the first and + * last member are primitive types (normally anyways).: + * keyIdentifier [1] OCTET STRING OPTIONAL, + * authorityCertSerialNumber [3] INTEGER OPTIONAL + */ +/** @def RTASN1TMPL_MEMBER_OPT_ITAG_UC + * Optional member of a constructed type from the universal tag class. + */ +/** @def RTASN1TMPL_MEMBER_OPT_ITAG_UP + * Optional member of a primitive type from the universal tag class. + */ + + +/** @name Expansion Passes (RTASN1TMPL_PASS values) + * @{ */ +#define RTASN1TMPL_PASS_INTERNAL_HEADER 1 + +#define RTASN1TMPL_PASS_XTAG 2 +#define RTASN1TMPL_PASS_VTABLE 3 +#define RTASN1TMPL_PASS_ENUM 4 +#define RTASN1TMPL_PASS_DELETE 5 +#define RTASN1TMPL_PASS_COMPARE 6 + +#define RTASN1TMPL_PASS_CHECK_SANITY 8 + +#define RTASN1TMPL_PASS_INIT 16 +#define RTASN1TMPL_PASS_CLONE 17 +#define RTASN1TMPL_PASS_SETTERS_1 18 +#define RTASN1TMPL_PASS_SETTERS_2 19 +#define RTASN1TMPL_PASS_ARRAY 20 + +#define RTASN1TMPL_PASS_DECODE 24 +/** @} */ + +/** @name ITAG clues + * @{ */ +#define RTASN1TMPL_ITAG_F_CC 1 /**< context, constructed. */ +#define RTASN1TMPL_ITAG_F_CP 2 /**< context, probably primary. (w/ numeric value) */ +#define RTASN1TMPL_ITAG_F_UP 3 /**< universal, probably primary. (w/ ASN1_TAG_XXX value) */ +#define RTASN1TMPL_ITAG_F_UC 4 /**< universal, constructed. (w/ ASN1_TAG_XXX value) */ +/** @} */ +/** Expands the ITAG clues into tag flag and tag class. */ +#define RTASN1TMPL_ITAG_F_EXPAND(a_fClue) \ + ( a_fClue == RTASN1TMPL_ITAG_F_CC ? (ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED ) \ + : a_fClue == RTASN1TMPL_ITAG_F_CP ? (ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_PRIMITIVE) \ + : a_fClue == RTASN1TMPL_ITAG_F_UP ? (ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE) \ + : a_fClue == RTASN1TMPL_ITAG_F_UC ? (ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) \ + : 0 ) + +#define RTASN1TMPL_SEMICOLON_DUMMY() typedef unsigned RTASN1TMPLSEMICOLONDUMMY + +#endif /* !___iprt_asn1_generator_pass_h */ + + +#if RTASN1TMPL_PASS == RTASN1TMPL_PASS_INTERNAL_HEADER +/* + * + * Internal header file. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() extern DECL_HIDDEN_DATA(RTASN1COREVTABLE const) RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable) + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + extern "C" DECL_HIDDEN_DATA(RTASN1COREVTABLE const) RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Vtable) + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + extern "C" DECL_HIDDEN_DATA(RTASN1COREVTABLE const) RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_PCHOICE_XTAG_,a_Name,_Vtable) + +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_BEGIN_COMMON() + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_XTAG +/* + * + * Generate a vtable and associated methods for explicitly tagged items (XTAG). + * + * These turned out to be a little problematic during encoding since there are + * two tags, the first encapsulating the second, thus the enumeration has to be + * nested or we cannot calculate the size of the first tag. + * + * + */ +# define RTASN1TMPL_BEGIN_COMMON() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + /* This is the method we need to make it work. */ \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Enum)(PRTASN1CORE pThisCore, \ + PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser) \ + { \ + RTASN1TMPL_TYPE *pThis = RT_FROM_MEMBER(pThisCore, RTASN1TMPL_TYPE, a_TnNm.a_CtxTagN); \ + if (RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core)) \ + return pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_TnNm.a_Name), #a_TnNm "." #a_Name, uDepth + 1, pvUser); \ + return VINF_SUCCESS; \ + } \ + /* The reminder of the methods shouldn't normally be needed, just stub them. */ \ + static DECLCALLBACK(void) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Delete)(PRTASN1CORE pThisCore) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Clone)(PRTASN1CORE pThisCore, PCRTASN1CORE pSrcCore, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); RT_NOREF_PV(pSrcCore); RT_NOREF_PV(pAllocator); return VERR_INTERNAL_ERROR_2; } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Compare)(PCRTASN1CORE pLeftCore, \ + PCRTASN1CORE pRightCore) \ + { AssertFailed(); RT_NOREF_PV(pLeftCore); RT_NOREF_PV(pRightCore); return VERR_INTERNAL_ERROR_2; } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_CheckSanity)(PCRTASN1CORE pThisCore, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); RT_NOREF_PV(fFlags); RT_NOREF_PV(pErrInfo); RT_NOREF_PV(pszErrorTag); \ + return VERR_INTERNAL_ERROR_2; } \ + DECL_HIDDEN_CONST(RTASN1COREVTABLE const) RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Vtable) = \ + { \ + /* When the Asn1Core is at the start of the structure, we can reuse the _Delete and _Enum APIs here. */ \ + /* .pszName = */ RT_XSTR(RTASN1TMPL_INT_NAME) "_XTAG_" RT_XSTR(a_Name), \ + /* .cb = */ RT_SIZEOFMEMB(RTASN1TMPL_TYPE, a_TnNm), \ + /* .uDefaultTag = */ a_uTag, \ + /* .fDefaultClass = */ ASN1_TAGCLASS_CONTEXT, \ + /* .uReserved = */ 0, \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Delete), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Enum), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Clone), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Compare), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_CheckSanity), \ + /*.pfnEncodePrep */ NULL, \ + /*.pfnEncodeWrite */ NULL \ + } + + +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + /* This is the method we need to make it work. */ \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Enum)(PRTASN1CORE pThisCore, \ + PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser) \ + { \ + if (RTASN1CORE_IS_PRESENT(pThisCore)) \ + { \ + /** @todo optimize this one day, possibly change the PCHOICE+XTAG representation. */ \ + RTASN1TMPL_TYPE Tmp; \ + *(PRTASN1CORE *)&Tmp.a_PtrTnNm = pThisCore; \ + Assert(&Tmp.a_PtrTnNm->a_CtxTagN.Asn1Core == pThisCore); \ + return pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(&Tmp.a_PtrTnNm->a_Name), "T" #a_uTag "." #a_Name, uDepth + 1, pvUser); \ + } \ + return VINF_SUCCESS; \ + } \ + /* The reminder of the methods shouldn't normally be needed, just stub them. */ \ + static DECLCALLBACK(void) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Delete)(PRTASN1CORE pThisCore) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Clone)(PRTASN1CORE pThisCore, PCRTASN1CORE pSrcCore, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); RT_NOREF_PV(pSrcCore); RT_NOREF_PV(pAllocator); return VERR_INTERNAL_ERROR_3; } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Compare)(PCRTASN1CORE pLeftCore, \ + PCRTASN1CORE pRightCore) \ + { AssertFailed(); RT_NOREF_PV(pLeftCore); RT_NOREF_PV(pRightCore); return VERR_INTERNAL_ERROR_3; } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_CheckSanity)(PCRTASN1CORE pThisCore, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); RT_NOREF_PV(fFlags); RT_NOREF_PV(pErrInfo); RT_NOREF_PV(pszErrorTag); \ + return VERR_INTERNAL_ERROR_3; } \ + DECL_HIDDEN_CONST(RTASN1COREVTABLE const) RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_PCHOICE_XTAG_,a_Name,_Vtable) = \ + { \ + /* When the Asn1Core is at the start of the structure, we can reuse the _Delete and _Enum APIs here. */ \ + /* .pszName = */ RT_XSTR(RTASN1TMPL_INT_NAME) "_PCHOICE_XTAG_" RT_XSTR(a_Name), \ + /* .cb = */ sizeof(*((RTASN1TMPL_TYPE *)(void *)0)->a_PtrTnNm), \ + /* .uDefaultTag = */ a_uTag, \ + /* .fDefaultClass = */ ASN1_TAGCLASS_CONTEXT, \ + /* .uReserved = */ 0, \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Delete), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Enum), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Clone), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Compare), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_CheckSanity), \ + /*.pfnEncodePrep */ NULL, \ + /*.pfnEncodeWrite */ NULL \ + } + + + +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_VTABLE +/* + * + * Internal header file. + * + */ +# ifndef RTASN1TMPL_VTABLE_FN_ENCODE_PREP +# define RTASN1TMPL_VTABLE_FN_ENCODE_PREP NULL +# endif +# ifndef RTASN1TMPL_VTABLE_FN_ENCODE_WRITE +# define RTASN1TMPL_VTABLE_FN_ENCODE_WRITE NULL +# endif +# define RTASN1TMPL_BEGIN_COMMON(a_uDefaultTag, a_fDefaultClass) \ + DECL_HIDDEN_CONST(RTASN1COREVTABLE const) RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable) = \ + { \ + /* When the Asn1Core is at the start of the structure, we can reuse the _Delete and _Enum APIs here. */ \ + /* .pszName = */ RT_XSTR(RTASN1TMPL_EXT_NAME), \ + /* .cb = */ sizeof(RTASN1TMPL_TYPE), \ + /* .uDefaultTag = */ a_uDefaultTag, \ + /* .fDefaultClass = */ a_fDefaultClass, \ + /* .uReserved = */ 0, \ + (PFNRTASN1COREVTDTOR)RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete), \ + (PFNRTASN1COREVTENUM)RT_CONCAT(RTASN1TMPL_EXT_NAME,_Enum), \ + (PFNRTASN1COREVTCLONE)RT_CONCAT(RTASN1TMPL_EXT_NAME,_Clone), \ + (PFNRTASN1COREVTCOMPARE)RT_CONCAT(RTASN1TMPL_EXT_NAME,_Compare), \ + (PFNRTASN1COREVTCHECKSANITY)RT_CONCAT(RTASN1TMPL_EXT_NAME,_CheckSanity), \ + RTASN1TMPL_VTABLE_FN_ENCODE_PREP, \ + RTASN1TMPL_VTABLE_FN_ENCODE_WRITE \ + } + +# define RTASN1TMPL_BEGIN_SEQCORE() \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, SeqCore, 0); \ + RTASN1TMPL_BEGIN_COMMON(ASN1_TAG_SEQUENCE, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) +# define RTASN1TMPL_BEGIN_SETCORE() \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, SetCore, 0); \ + RTASN1TMPL_BEGIN_COMMON(ASN1_TAG_SET, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, Dummy, 0); \ + RTASN1TMPL_BEGIN_COMMON(UINT8_MAX, UINT8_MAX) +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, SeqCore, 0); \ + RTASN1TMPL_BEGIN_COMMON(ASN1_TAG_SEQUENCE, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, SetCore, 0); \ + RTASN1TMPL_BEGIN_COMMON(ASN1_TAG_SET, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_INIT +/* + * + * Initialization to standard / default values. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Init)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + RT_NOREF_PV(pAllocator); \ + RT_ZERO(*pThis) +# define RTASN1TMPL_END_COMMON() \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RTAsn1SequenceCore_Init(&pThis->SeqCore, &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable)) +# define RTASN1TMPL_BEGIN_SETCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RTAsn1SetCore_Init(&pThis->SetCore, &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable)) +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Init)(&pThis->a_Name, pAllocator) + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + pThis->a_enmMembNm = RT_CONCAT(a_enmType,_NOT_PRESENT) +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + do { } while (0) +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) do { } while (0) + +# define RTASN1TMPL_MEMBER_DEF_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_DefVal, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT(a_Api,_InitDefault)(&pThis->a_Name, a_DefVal, pAllocator); \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1Core_SetTagAndFlags(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), \ + a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)); \ + } +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) do { } while (0) /* All optional members are left as not-present. */ +# define RTASN1TMPL_END_SEQCORE() \ + if (RT_FAILURE(rc)) \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_SEQCORE() + +/* No choice, just an empty, non-present structure. */ +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + int rc = VINF_SUCCESS +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + do { } while (0) +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + do { } while (0) +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, a_OfApi, a_OfMember) \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTAsn1MemInitArrayAllocation(&pThis->Allocation, pAllocator, sizeof(a_ItemType)); \ + int rc = RT_CONCAT(a_OfApi,_Init)(&pThis->a_OfMember, &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable)); \ + if (RT_FAILURE(rc)) \ + RT_ZERO(*pThis); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SeqOfCore, SeqCore) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SetOfCore, SetCore) + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_DECODE +/* + * + * Decode ASN.1. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_DecodeAsn1)(PRTASN1CURSOR pCursor, uint32_t fFlags, \ + RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, const char *pszErrorTag) \ +{ \ + RT_ZERO(*pThis); + +# define RTASN1TMPL_END_COMMON() \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_BEGIN_SEQCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTASN1CURSOR ThisCursor; \ + int rc = RTAsn1CursorGetSequenceCursor(pCursor, fFlags, &pThis->SeqCore, &ThisCursor, pszErrorTag); \ + if (RT_FAILURE(rc)) \ + return rc; \ + pCursor = &ThisCursor; \ + pThis->SeqCore.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable) +# define RTASN1TMPL_BEGIN_SETCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTASN1CURSOR ThisCursor; \ + int rc = RTAsn1CursorGetSetCursor(pCursor, fFlags, &pThis->SetCore, &ThisCursor, pszErrorTag); \ + if (RT_FAILURE(rc)) \ + return rc; \ + pCursor = &ThisCursor; \ + pThis->SetCore.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable) + +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, 0, &pThis->a_Name, #a_Name) + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (RT_SUCCESS(rc)) \ + { \ + int rc2; /* not initialized! */ \ + RTAsn1CursorInitAllocation(pCursor, &pThis->a_Allocation); \ + pThis->a_enmMembNm = RT_CONCAT(a_enmType, _INVALID); \ + if (false) do { /*nothing*/ } while (0) +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + else a_IfStmt \ + do { \ + rc2 = RTAsn1MemAllocZ(&pThis->a_Allocation, (void **)&pThis->a_UnionNm.a_PtrName, \ + sizeof(*pThis->a_UnionNm.a_PtrName)); \ + if (RT_SUCCESS(rc2)) \ + { \ + pThis->a_enmMembNm = a_enmValue; \ + rc2 = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, 0, pThis->a_UnionNm.a_PtrName, #a_UnionNm "." #a_PtrName); \ + } \ + } while (0) +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + rc = rc2; /* Should trigger warning if a _DEFAULT is missing. */ \ + } + +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) \ + Error_Missing_Specific_Macro_In_Decode_Pass() + +# define RTASN1TMPL_MEMBER_DEF_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_DefVal, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + { \ + if (RTAsn1CursorIsNextEx(pCursor, a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue))) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, 0, &pThis->a_Name, #a_Name); \ + else \ + rc = RT_CONCAT(a_Api,_InitDefault)(&pThis->a_Name, a_DefVal, pCursor->pPrimary->pAllocator); \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1Core_SetTagAndFlags(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), \ + a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)); \ + } do {} while (0) + +# define RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX(a_Name, a_Constraints) \ + if (RT_SUCCESS(rc) && RTAsn1CursorIsNextEx(pCursor, ASN1_TAG_UTF8_STRING, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_PRIMITIVE)) \ + rc = RTAsn1CursorGetUtf8String(pCursor, 0, &pThis->a_Name, #a_Name) + +# define RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_Constraints) \ + if (RT_SUCCESS(rc) && RTAsn1CursorIsNextEx(pCursor, a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)) /** @todo || CER */) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, RTASN1CURSOR_GET_F_IMPLICIT, &pThis->a_Name, #a_Name) + +# define RTASN1TMPL_MEMBER_OPT_ITAG_BITSTRING(a_Name, a_cMaxBits, a_uTag) \ + if (RT_SUCCESS(rc) && RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED)) \ + rc = RTAsn1CursorGetBitStringEx(pCursor, RTASN1CURSOR_GET_F_IMPLICIT, a_cMaxBits, &pThis->a_Name, #a_Name) + +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (RT_SUCCESS(rc) && RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED)) \ + { \ + RTASN1CURSOR CtxCursor; \ + rc = RT_CONCAT3(RTAsn1CursorGetContextTag,a_uTag,Cursor)(pCursor, 0, \ + &RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Vtable), \ + &pThis->a_TnNm.a_CtxTagN, &CtxCursor, #a_TnNm); \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(&CtxCursor, 0, &pThis->a_TnNm.a_Name, #a_Name); \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1CursorCheckEnd(&CtxCursor); \ + } \ + } do { } while (0) + +# define RTASN1TMPL_MEMBER_OPT_ANY(a_Name, a_Type, a_Api) \ + if (RT_SUCCESS(rc) && pCursor->cbLeft > 0) \ + RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, RT_NOTHING) + +# define RTASN1TMPL_END_SEQCORE() \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1CursorCheckSeqEnd(&ThisCursor, &pThis->SeqCore); \ + if (RT_SUCCESS(rc)) \ + return VINF_SUCCESS; \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1CursorCheckSetEnd(&ThisCursor, &pThis->SetCore); \ + if (RT_SUCCESS(rc)) \ + return VINF_SUCCESS; \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RT_NOREF_PV(fFlags); \ + RTAsn1Dummy_InitEx(&pThis->Dummy); \ + pThis->Dummy.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1CursorInitAllocation(pCursor, &pThis->Allocation); \ + RTASN1CORE Asn1Peek; \ + int rc = RTAsn1CursorPeek(pCursor, &Asn1Peek); \ + if (RT_SUCCESS(rc)) \ + { \ + if (false) do {} while (0) +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + else if ( Asn1Peek.uTag == (a_uTag) \ + && (Asn1Peek.fClass == RTASN1TMPL_ITAG_F_EXPAND(a_fClue) /** @todo || CER */ ) ) \ + do { \ + pThis->enmChoice = a_enmChoice; \ + rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrName, sizeof(*pThis->a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, RTASN1CURSOR_GET_F_IMPLICIT, pThis->a_PtrName, #a_PtrName); \ + } while (0) +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + else if (Asn1Peek.uTag == (a_uTag) && Asn1Peek.fClass == (ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED)) \ + do { \ + pThis->enmChoice = a_enmChoice; \ + rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrTnNm, sizeof(*pThis->a_PtrTnNm)); \ + if (RT_SUCCESS(rc)) \ + { \ + RTASN1CURSOR CtxCursor; \ + rc = RT_CONCAT3(RTAsn1CursorGetContextTag,a_uTag,Cursor)(pCursor, 0, \ + &RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_PCHOICE_XTAG_,a_Name,_Vtable), \ + &pThis->a_PtrTnNm->a_CtxTagN, &CtxCursor, "T" #a_uTag); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(&CtxCursor, RTASN1CURSOR_GET_F_IMPLICIT, \ + &pThis->a_PtrTnNm->a_Name, #a_Name); \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1CursorCheckEnd(&CtxCursor); \ + } \ + } while (0) +#define RTASN1TMPL_END_PCHOICE() \ + else \ + rc = RTAsn1CursorSetInfo(pCursor, VERR_GENERAL_FAILURE, "%s: Unknown choice: tag=%#x fClass=%#x", \ + pszErrorTag, Asn1Peek.uTag, Asn1Peek.fClass); \ + if (RT_SUCCESS(rc)) \ + return VINF_SUCCESS; \ + } \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, a_OfApi, a_OfMember, a_fnGetCursor) \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTASN1CURSOR ThisCursor; \ + int rc = a_fnGetCursor(pCursor, fFlags, &pThis->a_OfMember, &ThisCursor, pszErrorTag); \ + if (RT_SUCCESS(rc)) \ + { \ + pCursor = &ThisCursor; \ + pThis->a_OfMember.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1CursorInitArrayAllocation(pCursor, &pThis->Allocation, sizeof(a_ItemType)); \ + \ + uint32_t i = 0; \ + while ( pCursor->cbLeft > 0 \ + && RT_SUCCESS(rc)) \ + { \ + rc = RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, i, i + 1); \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT(a_ItemApi,_DecodeAsn1)(pCursor, 0, pThis->papItems[i], "papItems[#]"); \ + if (RT_SUCCESS(rc)) \ + { \ + i++; \ + pThis->cItems = i; \ + continue; \ + } \ + } \ + break; \ + } \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RTAsn1CursorCheckEnd(pCursor); \ + if (RT_SUCCESS(rc)) \ + return VINF_SUCCESS; \ + } \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + } \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) \ + RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SeqOfCore, SeqCore, RTAsn1CursorGetSequenceCursor) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) \ + RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SetOfCore, SetCore, RTAsn1CursorGetSetCursor) + + +# define RTASN1TMPL_EXEC_DECODE(a_Expr) if (RT_SUCCESS(rc)) { a_Expr; } + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_ENUM +/* + * + * Enumeration. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Enum)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser) \ +{ \ + if (!RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pThis)) \ + return VINF_SUCCESS; \ + uDepth++; \ + int rc = VINF_SUCCESS + +# define RTASN1TMPL_END_COMMON() \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (rc == VINF_SUCCESS) \ + rc = pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), #a_Name, uDepth, pvUser) +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (rc == VINF_SUCCESS) \ + switch (pThis->a_enmMembNm) \ + { \ + default: rc = VERR_INTERNAL_ERROR_3; break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: \ + rc = pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_UnionNm.a_PtrName), #a_UnionNm "." #a_PtrName, \ + uDepth, pvUser); \ + break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + case RT_CONCAT(a_enmType,_NOT_PRESENT): break; \ + } +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (rc == VINF_SUCCESS && RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name)) \ + rc = pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), #a_Name, uDepth, pvUser) +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (rc == VINF_SUCCESS && RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core)) \ + { \ + rc = pfnCallback(&pThis->a_TnNm.a_CtxTagN.Asn1Core, #a_Name, uDepth, pvUser); \ + } do {} while (0) +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + switch (pThis->enmChoice) \ + { \ + default: rc = VERR_INTERNAL_ERROR_3; break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: rc = pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_PtrName), #a_PtrName, uDepth, pvUser); break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: rc = pfnCallback(&pThis->a_PtrTnNm->a_CtxTagN.Asn1Core, "T" #a_uTag "." #a_CtxTagN, uDepth, pvUser); break +#define RTASN1TMPL_END_PCHOICE() \ + } \ + RTASN1TMPL_END_COMMON() + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_BEGIN_COMMON(); \ + for (uint32_t i = 0; i < pThis->cItems && rc == VINF_SUCCESS; i++) \ + rc = pfnCallback(RT_CONCAT(a_ItemApi,_GetAsn1Core)(pThis->papItems[i]), "papItems[#]", uDepth, pvUser); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_CLONE +/* + * + * Clone another instance of the type. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Clone)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,RTASN1TMPL_TYPE) pSrc, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + RT_ZERO(*pThis); \ + if (!RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pSrc)) \ + return VINF_SUCCESS; \ + +# define RTASN1TMPL_END_COMMON() \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RTAsn1SequenceCore_Clone(&pThis->SeqCore, &RT_CONCAT3(g_, RTASN1TMPL_INT_NAME, _Vtable), &pSrc->SeqCore) +# define RTASN1TMPL_BEGIN_SETCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RTAsn1SetCore_Clone(&pThis->SetCore, &RT_CONCAT3(g_, RTASN1TMPL_INT_NAME, _Vtable), &pSrc->SetCore) + +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_Name, &pSrc->a_Name, pAllocator); \ + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (RT_SUCCESS(rc)) \ + { \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + pThis->a_enmMembNm = pSrc->a_enmMembNm; \ + switch (pSrc->a_enmMembNm) \ + { \ + default: rc = VERR_INTERNAL_ERROR_3; break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: \ + rc = RTAsn1MemAllocZ(&pThis->a_Allocation, (void **)&pThis->a_UnionNm.a_PtrName, \ + sizeof(*pThis->a_UnionNm.a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Clone)(pThis->a_UnionNm.a_PtrName, pSrc->a_UnionNm.a_PtrName, pAllocator); \ + break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + case RT_CONCAT(a_enmType,_NOT_PRESENT): break; \ + } \ + } + +/* Optional members and members with defaults are the same as a normal member when cloning. */ +# define RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX(a_Name, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, RTASN1STRING, RTAsn1Utf8String, a_Constraints RT_NOTHING) +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (RTASN1CORE_IS_PRESENT(&pSrc->a_TnNm.a_CtxTagN.Asn1Core) && RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Clone)(&pThis->a_TnNm.a_CtxTagN, &pSrc->a_TnNm.a_CtxTagN); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_TnNm.a_Name, &pSrc->a_TnNm.a_Name, pAllocator); \ + } do { } while (0) + +# define RTASN1TMPL_END_SEQCORE() \ + if (RT_FAILURE(rc)) \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_SEQCORE() + + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTAsn1Dummy_InitEx(&pThis->Dummy); \ + pThis->Dummy.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + int rc; \ + pThis->enmChoice = pSrc->enmChoice; \ + switch (pSrc->enmChoice) \ + { \ + default: rc = VERR_INTERNAL_ERROR_3; break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: \ + rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrName, sizeof(*pThis->a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Clone)(pThis->a_PtrName, pSrc->a_PtrName, pAllocator); \ + break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: /* A bit of presence paranoia here, but better safe than sorry... */ \ + rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrTnNm, sizeof(*pThis->a_PtrTnNm)); \ + if (RT_SUCCESS(rc) && RTASN1CORE_IS_PRESENT(&pSrc->a_PtrTnNm->a_CtxTagN.Asn1Core)) \ + { \ + RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Clone)(&pThis->a_PtrTnNm->a_CtxTagN, &pSrc->a_PtrTnNm->a_CtxTagN); \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_PtrTnNm->a_Name, &pSrc->a_PtrTnNm->a_Name, pAllocator); \ + } \ + break +#define RTASN1TMPL_END_PCHOICE() \ + } \ + if (RT_FAILURE(rc)) \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, a_OfApi, a_OfMember) \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RT_CONCAT(a_OfApi,_Clone)(&pThis->a_OfMember, &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable), &pSrc->a_OfMember); \ + if (RT_SUCCESS(rc)) \ + { \ + RTAsn1MemInitArrayAllocation(&pThis->Allocation, pAllocator, sizeof(a_ItemType)); \ + uint32_t const cItems = pSrc->cItems; \ + if (cItems > 0) \ + { \ + rc = RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, 0, cItems); \ + if (RT_SUCCESS(rc)) \ + { \ + uint32_t i = 0; \ + while (i < cItems) \ + { \ + rc = RT_CONCAT(a_ItemApi,_Clone)(pThis->papItems[i], pSrc->papItems[i], pAllocator); \ + if (RT_SUCCESS(rc)) \ + pThis->cItems = ++i; \ + else \ + { \ + pThis->cItems = i; \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + return rc; \ + } \ + } \ + } \ + else \ + RT_ZERO(*pThis); \ + } \ + } \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SeqOfCore, SeqCore) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SetOfCore, SetCore) + +# define RTASN1TMPL_EXEC_CLONE(a_Expr) if (RT_SUCCESS(rc)) { a_Expr; } + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_SETTERS_1 +/* + * + * Member setter helpers. + * + */ +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +#if 1 /** @todo later */ +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +#else +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + RTDECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RTASN1TMPL_TYPE *pThis, a_Type const *pValue, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ + { \ + if (RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name)) \ + RT_CONCAT(a_Api,_Delete)(&pThis->a_Name); \ + return RT_CONCAT(a_Api,_Clone)(&pThis->a_Name, pValue, pAllocator, true /* fResetImplicit */); \ + } RTASN1TMPL_SEMICOLON_DUMMY() +#endif + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_SETTERS_2 +/* + * + * Member setters. + * + */ +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_MEMBER_DYN(a_UnionNm, a_PtrName, a_Name, a_Type, a_Api, a_Allocation, a_ObjIdMembNm, a_enmMembNm, a_enmValue, a_szObjId) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtr(pThis); AssertPtrNull(pToClone); Assert(!pToClone || RT_CONCAT(a_Api,_IsPresent)(pToClone)); \ + AssertReturn(pThis->a_UnionNm.a_PtrName == NULL, VERR_INVALID_STATE); /* for now */ \ + /* Set the type */ \ + if (RTAsn1ObjId_IsPresent(&pThis->a_ObjIdMembNm)) \ + RTAsn1ObjId_Delete(&pThis->a_ObjIdMembNm); \ + int rc = RTAsn1ObjId_InitFromString(&pThis->a_ObjIdMembNm, a_szObjId, pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + pThis->a_enmMembNm = a_enmValue; \ + \ + /* Allocate memory for the structure we're targeting. */ \ + rc = RTAsn1MemAllocZ(&pThis->a_Allocation, (void **)&pThis->a_UnionNm.a_PtrName, sizeof(*pThis->a_UnionNm.a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) /* If nothing to clone, just initialize the structure. */ \ + rc = RT_CONCAT(a_Api,_Clone)(pThis->a_UnionNm.a_PtrName, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(pThis->a_UnionNm.a_PtrName, pAllocator); \ + } \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + + + +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_Constraints) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtr(pThis); AssertPtrNull(pToClone); Assert(!pToClone || RT_CONCAT(a_Api,_IsPresent)(pToClone)); \ + if (RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name)) \ + RT_CONCAT(a_Api,_Delete)(&pThis->a_Name); \ + \ + int rc; \ + if (pToClone) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_Name, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(&pThis->a_Name, pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + RTAsn1Core_ResetImplict(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name)); /* probably not needed */ \ + rc = RTAsn1Core_SetTagAndFlags(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), \ + a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)); \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtr(pThis); AssertPtrNull(pToClone); Assert(!pToClone || RT_CONCAT(a_Api,_IsPresent)(pToClone)); \ + if (RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core)) \ + RT_CONCAT(a_Api,_Delete)(&pThis->a_TnNm.a_Name); \ + \ + int rc = RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Init)(&pThis->a_TnNm.a_CtxTagN, \ + &RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Vtable), \ + pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_TnNm.a_Name, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(&pThis->a_TnNm.a_Name, pAllocator); \ + if (RT_SUCCESS(rc) && pToClone) \ + RTAsn1Core_ResetImplict(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_TnNm.a_Name)); \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtrNull(pToClone); AssertPtr(pThis); \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); /* See _Init. */ \ + RTAsn1Dummy_InitEx(&pThis->Dummy); \ + pThis->Dummy.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + pThis->enmChoice = a_enmChoice; \ + int rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrName, sizeof(*pThis->a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) \ + rc = RT_CONCAT(a_Api,_Clone)(pThis->a_PtrName, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(pThis->a_PtrName, pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) \ + RTAsn1Core_ResetImplict(RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_PtrName)); \ + rc = RTAsn1Core_SetTagAndFlags(RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_PtrName), \ + a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)); \ + } \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtr(pThis); AssertPtrNull(pToClone); Assert(!pToClone || RT_CONCAT(a_Api,_IsPresent)(pToClone)); \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); /* See _Init. */ \ + RTAsn1Dummy_InitEx(&pThis->Dummy); \ + pThis->Dummy.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + pThis->enmChoice = a_enmChoice; \ + int rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrTnNm, sizeof(*pThis->a_PtrTnNm)); \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Init)(&pThis->a_PtrTnNm->a_CtxTagN, \ + &RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_PCHOICE_XTAG_,a_Name,_Vtable), \ + pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_PtrTnNm->a_Name, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(&pThis->a_PtrTnNm->a_Name, pAllocator); \ + if (RT_SUCCESS(rc) && pToClone) \ + RTAsn1Core_ResetImplict(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_PtrTnNm->a_Name)); \ + } \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_ARRAY +/* + * + * Array operations. + * + */ +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Erase)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, uint32_t iPosition) \ + { \ + /* Check and adjust iPosition. */ \ + uint32_t const cItems = pThis->cItems; \ + if (iPosition < cItems) \ + { /* likely */ } \ + else \ + { \ + AssertReturn(iPosition == UINT32_MAX, VERR_OUT_OF_RANGE); \ + AssertReturn(cItems > 0, VERR_OUT_OF_RANGE); \ + iPosition = cItems - 1; \ + } \ + \ + /* Delete the entry instance. */ \ + RT_CONCAT(P, a_ItemType) pErased = pThis->papItems[iPosition]; \ + if (RT_CONCAT(a_ItemApi,_IsPresent)(pErased)) \ + RT_CONCAT(a_ItemApi,_Delete)(pErased); \ + \ + /* If not the final entry, shift the other entries up and place the erased on at the end. */ \ + if (iPosition < cItems - 1) \ + { \ + memmove(&pThis->papItems[iPosition], &pThis->papItems[iPosition + 1], (cItems - iPosition - 1) * sizeof(void *)); \ + pThis->papItems[cItems - 1] = pErased; \ + } \ + /* Commit the new array size. */ \ + pThis->cItems = cItems - 1; \ + \ + /* Call the allocator to resize the array (ignore return). */ \ + RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, cItems - 1, cItems); \ + return VINF_SUCCESS; \ + } \ + \ + RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_InsertEx)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, uint32_t iPosition, \ + RT_CONCAT(PC, a_ItemType) pToClone, \ + PCRTASN1ALLOCATORVTABLE pAllocator, uint32_t *piActualPos) \ + { \ + /* Check and adjust iPosition. */ \ + uint32_t const cItems = pThis->cItems; \ + if (iPosition <= cItems) \ + { /* likely */ } \ + else \ + { \ + AssertReturn(iPosition == UINT32_MAX, VERR_OUT_OF_RANGE); \ + iPosition = cItems; \ + } \ + \ + /* Ensure we've got space in the array. */ \ + int rc = RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, cItems, cItems + 1); \ + if (RT_SUCCESS(rc)) \ + { \ + /* Initialize the new entry (which is currently at the end of the array) either with defaults or as a clone. */ \ + RT_CONCAT(P,a_ItemType) pInserted = pThis->papItems[cItems]; \ + if (RT_CONCAT(a_ItemApi,_IsPresent)(pToClone)) \ + rc = RT_CONCAT(a_ItemApi,_Clone)(pInserted, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_ItemApi,_Init)(pInserted, pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + pThis->cItems = cItems + 1; \ + \ + /* If not inserting at the end of the array, shift existing items out of the way and insert the new as req. */ \ + if (iPosition != cItems) \ + { \ + memmove(&pThis->papItems[iPosition + 1], &pThis->papItems[iPosition], (cItems - iPosition) * sizeof(void *)); \ + pThis->papItems[iPosition] = pInserted; \ + } \ + \ + /* Done! */ \ + if (piActualPos) \ + *piActualPos = iPosition; \ + return VINF_SUCCESS; \ + } \ + RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, cItems + 1, cItems); \ + } \ + return rc; \ + } RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_COMPARE +/* + * + * Compare two instances of the type. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Compare)(RT_CONCAT(PC,RTASN1TMPL_TYPE) pLeft, \ + RT_CONCAT(PC,RTASN1TMPL_TYPE) pRight) \ +{ \ + if (!RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pLeft)) \ + return 0 - (int)RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pRight); \ + if (!RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pRight)) \ + return -1; \ + int iDiff = 0 + +# define RTASN1TMPL_END_COMMON() \ + return iDiff; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (!iDiff) \ + iDiff = RT_CONCAT(a_Api,_Compare)(&pLeft->a_Name, &pRight->a_Name) +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (!iDiff && pLeft->a_enmMembNm != pRight->a_enmMembNm) \ + iDiff = pLeft->a_enmMembNm < pRight->a_enmMembNm ? -1 : 1; \ + else if (!iDiff) \ + switch (pLeft->a_enmMembNm) \ + { \ + default: break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: iDiff = RT_CONCAT(a_Api,_Compare)(pLeft->a_UnionNm.a_PtrName, pRight->a_UnionNm.a_PtrName); break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + case RT_CONCAT(a_enmType,_NOT_PRESENT): break; \ + } +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (!iDiff) \ + { \ + if (RTASN1CORE_IS_PRESENT(&pLeft->a_TnNm.a_CtxTagN.Asn1Core)) \ + { \ + if (RTASN1CORE_IS_PRESENT(&pRight->a_TnNm.a_CtxTagN.Asn1Core)) \ + iDiff = RT_CONCAT(a_Api,_Compare)(&pLeft->a_TnNm.a_Name, &pRight->a_TnNm.a_Name); \ + else \ + iDiff = -1; \ + } \ + else \ + iDiff = 0 - (int)RTASN1CORE_IS_PRESENT(&pRight->a_TnNm.a_CtxTagN.Asn1Core); \ + } do { } while (0) +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_COMMON() + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + if (pLeft->enmChoice != pRight->enmChoice) \ + return pLeft->enmChoice < pRight->enmChoice ? -1 : 1; \ + switch (pLeft->enmChoice) \ + { \ + default: break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: iDiff = RT_CONCAT(a_Api,_Compare)(pLeft->a_PtrName, pRight->a_PtrName); break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: iDiff = RT_CONCAT(a_Api,_Compare)(&pLeft->a_PtrTnNm->a_Name, &pRight->a_PtrTnNm->a_Name); break +#define RTASN1TMPL_END_PCHOICE() \ + } \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_BEGIN_COMMON(); \ + uint32_t cItems = pLeft->cItems; \ + if (cItems == pRight->cItems) \ + for (uint32_t i = 0; iDiff == 0 && i < cItems; i++) \ + iDiff = RT_CONCAT(a_ItemApi,_Compare)(pLeft->papItems[i], pRight->papItems[i]); \ + else \ + iDiff = cItems < pRight->cItems ? -1 : 1; \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_CHECK_SANITY +/* + * + * Checks the sanity of the type. + * + */ +# ifndef RTASN1TMPL_SANITY_CHECK_EXPR +# define RTASN1TMPL_SANITY_CHECK_EXPR() VINF_SUCCESS +# endif +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_CheckSanity)(RT_CONCAT(PC,RTASN1TMPL_TYPE) pThis, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) \ +{ \ + if (RT_LIKELY(RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pThis))) \ + { /* likely */ } \ + else \ + return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s: Missing (%s).", pszErrorTag, RT_XSTR(RTASN1TMPL_TYPE)); \ + int rc = VINF_SUCCESS + +# define RTASN1TMPL_END_COMMON() \ + if (RT_SUCCESS(rc)) \ + rc = (RTASN1TMPL_SANITY_CHECK_EXPR()); \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + { \ + if (RT_LIKELY(RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name))) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(&pThis->a_Name, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s: Missing member %s (%s).", \ + pszErrorTag, #a_Name, RT_XSTR(RTASN1TMPL_TYPE)); \ + } do {} while (0) +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (RT_SUCCESS(rc)) \ + switch (pThis->a_enmMembNm) \ + { \ + default: \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s: Invalid " #a_enmMembNm " value: %d", pszErrorTag, pThis->a_enmMembNm); \ + break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: \ + rc = RT_CONCAT(a_Api,_CheckSanity)(pThis->a_UnionNm.a_PtrName, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_UnionNm "." #a_PtrName); \ + break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + case RT_CONCAT(a_enmType,_NOT_PRESENT): \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s: Invalid " #a_enmMembNm " value: " #a_enmType "_NOT_PRESENT", pszErrorTag); \ + break; \ + } +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc) && RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name)) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(&pThis->a_Name, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + { \ + bool const fOuterPresent = RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core); \ + bool const fInnerPresent = RT_CONCAT(a_Api,_IsPresent)(&pThis->a_TnNm.a_Name); \ + if (fOuterPresent && fInnerPresent) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(&pThis->a_TnNm.a_Name, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } \ + else if (RT_LIKELY(RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core) == fInnerPresent)) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_TnNm "." #a_Name ": Explict tag precense mixup; " #a_CtxTagN "=%d " #a_Name "=%d.", \ + pszErrorTag, fOuterPresent, fInnerPresent); \ + } do { } while (0) +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + switch (pThis->enmChoice) \ + { \ + default: \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s: Invalid enmChoice value: %d", pszErrorTag, pThis->enmChoice); \ + break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: \ + if (pThis->a_PtrName && RT_CONCAT(a_Api,_IsPresent)(pThis->a_PtrName)) \ + { \ + PCRTASN1CORE pCore = RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_PtrName); \ + if (pCore->uTag == a_uTag && pCore->fClass == RTASN1TMPL_ITAG_F_EXPAND(a_fClue)) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(pThis->a_PtrName, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_Name ": Tag/class mismatch: expected %#x/%#x, actual %#x/%x.", \ + pszErrorTag, a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue), pCore->uTag, pCore->fClass); \ + } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s::" #a_Name ": Not present.", pszErrorTag); \ + break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: \ + if ( pThis->a_PtrTnNm \ + && RTASN1CORE_IS_PRESENT(&(pThis->a_PtrTnNm->a_CtxTagN.Asn1Core)) \ + && RT_CONCAT(a_Api,_IsPresent)(&pThis->a_PtrTnNm->a_Name) ) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(&pThis->a_PtrTnNm->a_Name, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s::" #a_Name ": Not present.", pszErrorTag); \ + break +#define RTASN1TMPL_END_PCHOICE() \ + } \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_BEGIN_COMMON(); \ + for (uint32_t i = 0; RT_SUCCESS(rc) && i < pThis->cItems; i++) \ + rc = RT_CONCAT(a_ItemApi,_CheckSanity)(pThis->papItems[i], fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::papItems[#]"); \ + if (RT_SUCCESS(rc)) { RTASN1TMPL_SET_SEQ_EXEC_CHECK_SANITY(); } \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + +/* The constraints. */ +# define RTASN1TMPL_MEMBER_CONSTR_MIN_MAX(a_Name, a_Type, a_Api, cbMin, cbMax, a_MoreConstraints) \ + if (RT_SUCCESS(rc) && ((cbMin) != 0 || (cbMax) != UINT32_MAX)) \ + { \ + PCRTASN1CORE pCore = RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name); \ + if (RT_LIKELY(pCore->cb >= (cbMin) && pCore->cb <= (cbMax))) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_Name ": Content size is out of range: %#x not in {%#x..%#x}", \ + pszErrorTag, pCore->cb, cbMin, cbMax); \ + } \ + { a_MoreConstraints } + +# define RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX(a_Name, cMinBits, cMaxBits, a_MoreConstraints) \ + if (RT_SUCCESS(rc) && ((cMinBits) != 0 || (cMaxBits) != UINT32_MAX)) \ + { \ + if (RT_LIKELY( ((cMinBits) == 0 ? true : pThis->a_Name.cBits + 1U >= (cMinBits) + 1U /* warning avoiding */) \ + && ((cMaxBits) == UINT32_MAX ? true : pThis->a_Name.cBits + 1U <= (cMaxBits) + 1U /* ditto */) ) ) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_Name ": Bit size is out of range: %#x not in {%#x..%#x}", \ + pszErrorTag, pThis->a_Name.cBits, cMinBits, cMaxBits); \ + } \ + { a_MoreConstraints } + +# define RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX(a_Name, uMin, uMax, a_MoreConstraints) \ + if (RT_SUCCESS(rc)) \ + { \ + if (RT_LIKELY( RTAsn1Integer_UnsignedCompareWithU64(&pThis->a_Name, uMin) >= 0 \ + && RTAsn1Integer_UnsignedCompareWithU64(&pThis->a_Name, uMax) <= 0) ) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_Name ": Out of range: %#x not in {%#llx..%#llx}", \ + pszErrorTag, pThis->a_Name.Asn1Core.cb > 8 ? UINT64_MAX : pThis->a_Name.uValue.u, \ + (uint64_t)(uMin), (uint64_t)(uMax)); \ + } \ + { a_MoreConstraints } + +# define RTASN1TMPL_MEMBER_CONSTR_PRESENT(a_Name, a_Api, a_MoreConstraints) \ + if (RT_SUCCESS(rc)) \ + { \ + if (RT_LIKELY(RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name))) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s::" #a_Name ": Missing.", pszErrorTag); \ + } \ + { a_MoreConstraints } + + + +# define RTASN1TMPL_EXEC_CHECK_SANITY(a_Expr) if (RT_SUCCESS(rc)) { a_Expr; } + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_DELETE +/* + * + * Delete wrappers. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(void) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis) \ +{ \ + if (RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pThis)) \ + { do { } while (0) + +# define RTASN1TMPL_END_COMMON() \ + } \ + RT_ZERO(*pThis); \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RT_CONCAT(a_Api,_Delete)(&pThis->a_Name) +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + switch (pThis->a_enmMembNm) \ + { \ + default: break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: \ + if (pThis->a_UnionNm.a_PtrName) \ + { \ + RT_CONCAT(a_Api,_Delete)(pThis->a_UnionNm.a_PtrName); \ + RTAsn1MemFree(&pThis->Allocation, pThis->a_UnionNm.a_PtrName); \ + pThis->a_UnionNm.a_PtrName = NULL; \ + } \ + break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + } +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + switch (pThis->enmChoice) \ + { \ + default: break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: \ + if (pThis->a_PtrName) \ + { \ + RT_CONCAT(a_Api,_Delete)(pThis->a_PtrName); \ + RTAsn1MemFree(&pThis->Allocation, pThis->a_PtrName); \ + pThis->a_PtrName = NULL; \ + } \ + break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: \ + if (pThis->a_PtrTnNm) \ + { \ + RT_CONCAT(a_Api,_Delete)(&pThis->a_PtrTnNm->a_Name); \ + RTAsn1MemFree(&pThis->Allocation, pThis->a_PtrTnNm); \ + pThis->a_PtrTnNm = NULL; \ + } \ + break +# define RTASN1TMPL_END_PCHOICE() \ + } \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_BEGIN_COMMON(); \ + uint32_t i = pThis->cItems; \ + while (i-- > 0) \ + RT_CONCAT(a_ItemApi,_Delete)(pThis->papItems[i]); \ + RTAsn1MemFreeArray(&pThis->Allocation, (void **)pThis->papItems); \ + pThis->papItems = NULL; \ + pThis->cItems = 0; \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + + +#else +# error "Invalid/missing RTASN1TMPL_PASS value." +#endif + + + +/* + * Default aliases for simplified versions of macros if no specialization + * was required above. + */ +/* Non-optional members. */ +#ifndef RTASN1TMPL_MEMBER +# define RTASN1TMPL_MEMBER(a_Name, a_Type, a_Api) \ + RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_UTF8_STRING_MIN_MAX +# define RTASN1TMPL_MEMBER_UTF8_STRING_MIN_MAX(a_Name) \ + RTASN1TMPL_MEMBER(a_Name, RTASN1STRING, RTAsn1String) +#endif +#ifndef RTASN1TMPL_MEMBER_UTF8_STRING +# define RTASN1TMPL_MEMBER_UTF8_STRING(a_Name) \ + RTASN1TMPL_MEMBER_UTF8_STRING_MIN_MAX(a_Name, 0, UINT32_MAX) +#endif + +#ifndef RTASN1TMPL_MEMBER_STRING_MIN_MAX +# define RTASN1TMPL_MEMBER_STRING_MIN_MAX(a_Name, a_cbMin, a_cbMax) \ + RTASN1TMPL_MEMBER(a_Name, RTASN1STRING, RTAsn1String) +#endif +#ifndef RTASN1TMPL_MEMBER_STRING +# define RTASN1TMPL_MEMBER_STRING(a_Name) \ + RTASN1TMPL_MEMBER_STRING_MIN_MAX(a_Name, 0, UINT32_MAX) +#endif +#ifndef RTASN1TMPL_MEMBER_XTAG_EX +# define RTASN1TMPL_MEMBER_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + RTASN1TMPL_MEMBER_EX(a_TnNm.a_Name, a_Type, a_Api, a_Constraints RT_NOTHING) +#endif + +/* Any/dynamic members. */ +#ifndef RTASN1TMPL_MEMBER_DYN_BEGIN +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) do { } while (0) +#endif +#ifndef RTASN1TMPL_MEMBER_DYN_END +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) do { } while (0) +#endif +#ifndef RTASN1TMPL_MEMBER_DYN_COMMON +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + RTASN1TMPL_MEMBER(a_UnionNm.a_PtrName, a_Type, a_Api) +#endif +#ifndef RTASN1TMPL_MEMBER_DYN +# define RTASN1TMPL_MEMBER_DYN(a_UnionNm, a_PtrName, a_Name, a_Type, a_Api, a_Allocation, a_ObjIdMembNm, a_enmMembNm, a_enmValue, a_szObjId) \ + RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, if (RTAsn1ObjId_CompareWithString(&pThis->a_ObjIdMembNm, a_szObjId) == 0)) +#endif +#ifndef RTASN1TMPL_MEMBER_DYN_DEFAULT +# define RTASN1TMPL_MEMBER_DYN_DEFAULT(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_ObjIdMembNm, a_enmMembNm, a_enmValue) \ + RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, RT_NOTHING) +#endif + +/* Optional members. */ +#ifndef RTASN1TMPL_MEMBER_OPT_EX +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) \ + RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT +# define RTASN1TMPL_MEMBER_OPT(a_Name, a_Type, a_Api) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_XTAG_EX +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_TnNm.a_Name, a_Type, a_Api, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_XTAG +# define RTASN1TMPL_MEMBER_OPT_XTAG(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_EX +# define RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_UP +# define RTASN1TMPL_MEMBER_OPT_ITAG_UP(a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_UP, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_UC +# define RTASN1TMPL_MEMBER_OPT_ITAG_UC(a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_UC, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_CP +# define RTASN1TMPL_MEMBER_OPT_ITAG_CP(a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_CP, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG +# define RTASN1TMPL_MEMBER_OPT_ITAG(a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_CC, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ANY +# define RTASN1TMPL_MEMBER_OPT_ANY(a_Name, a_Type, a_Api) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_DEF_ITAG_EX +# define RTASN1TMPL_MEMBER_DEF_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_DefVal, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_DEF_ITAG_UP +# define RTASN1TMPL_MEMBER_DEF_ITAG_UP(a_Name, a_Type, a_Api, a_uTag, a_DefVal) \ + RTASN1TMPL_MEMBER_DEF_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_UP, a_DefVal, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_BITSTRING +# define RTASN1TMPL_MEMBER_OPT_ITAG_BITSTRING(a_Name, a_cMaxBits, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, RTASN1BITSTRING, RTAsn1BitString, a_uTag, RTASN1TMPL_ITAG_F_CP, \ + RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX(a_Name, 0, a_cMaxBits, RT_NOTHING)) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX +# define RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX(a_Name, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, RTASN1STRING, RTAsn1String, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_UTF8_STRING +# define RTASN1TMPL_MEMBER_OPT_UTF8_STRING(a_Name) \ + RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX(a_Name, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_STRING_EX +# define RTASN1TMPL_MEMBER_OPT_STRING_EX(a_Name, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, RTASN1STRING, RTAsn1String, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_STRING +# define RTASN1TMPL_MEMBER_OPT_STRING(a_Name) \ + RTASN1TMPL_MEMBER_OPT_STRING_EX(a_Name, RT_NOTHING) +#endif + +/* Pointer choices. */ +#ifndef RTASN1TMPL_PCHOICE_ITAG_UP +# define RTASN1TMPL_PCHOICE_ITAG_UP(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, RTASN1TMPL_ITAG_F_UP, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_PCHOICE_ITAG_UC +# define RTASN1TMPL_PCHOICE_ITAG_UC(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, RTASN1TMPL_ITAG_F_UC, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_PCHOICE_ITAG_CP +# define RTASN1TMPL_PCHOICE_ITAG_CP(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, RTASN1TMPL_ITAG_F_CP, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_PCHOICE_ITAG +# define RTASN1TMPL_PCHOICE_ITAG(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, RTASN1TMPL_ITAG_F_CC, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_PCHOICE_XTAG +# define RTASN1TMPL_PCHOICE_XTAG(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, RT_NOTHING) +#endif + + +/* + * Constraints are only used in the sanity check pass, so provide subs for the + * others passes. + */ +#ifndef RTASN1TMPL_MEMBER_CONSTR_MIN_MAX +# define RTASN1TMPL_MEMBER_CONSTR_MIN_MAX(a_Name, a_Type, a_Api, cbMin, cbMax, a_MoreConstraints) +#endif +#ifndef RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX +# define RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX(a_Name, cMinBits, cMaxBits, a_MoreConstraints) +#endif +#ifndef RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX +# define RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX(a_Name, uMin, uMax, a_MoreConstraints) +#endif +#ifndef RTASN1TMPL_MEMBER_CONSTR_PRESENT +# define RTASN1TMPL_MEMBER_CONSTR_PRESENT(a_Name, a_Api, a_MoreConstraints) +#endif + + +/* + * Stub exec hacks. + */ +#ifndef RTASN1TMPL_EXEC_DECODE +# define RTASN1TMPL_EXEC_DECODE(a_Expr) /* no semi colon allowed after this */ +#endif +#ifndef RTASN1TMPL_EXEC_CLONE +# define RTASN1TMPL_EXEC_CLONE(a_Expr) /* no semi colon allowed after this */ +#endif +#ifndef RTASN1TMPL_EXEC_CHECK_SANITY +# define RTASN1TMPL_EXEC_CHECK_SANITY(a_Expr) /* no semi colon allowed after this */ +#endif + +#define RTASN1TMPL_SET_SEQ_EXEC_CHECK_SANITY() do { } while (0) + + +/* + * Generate the requested code. + */ +#ifndef RTASN1TMPL_TEMPLATE_FILE +# error "No template file (RTASN1TMPL_TEMPLATE_FILE) is specified." +#endif +#include RTASN1TMPL_TEMPLATE_FILE + + + +/* + * Undo all the macros. + */ +#undef RTASN1TMPL_DECL +#undef RTASN1TMPL_TYPE +#undef RTASN1TMPL_EXT_NAME +#undef RTASN1TMPL_INT_NAME + +#undef RTASN1TMPL_PASS + +#undef RTASN1TMPL_BEGIN_COMMON +#undef RTASN1TMPL_END_COMMON +#undef RTASN1TMPL_BEGIN_SEQCORE +#undef RTASN1TMPL_BEGIN_SETCORE +#undef RTASN1TMPL_MEMBER +#undef RTASN1TMPL_MEMBER_EX +#undef RTASN1TMPL_MEMBER_DYN_BEGIN +#undef RTASN1TMPL_MEMBER_DYN +#undef RTASN1TMPL_MEMBER_DYN_DEFAULT +#undef RTASN1TMPL_MEMBER_DYN_COMMON +#undef RTASN1TMPL_MEMBER_DYN_END +#undef RTASN1TMPL_MEMBER_OPT +#undef RTASN1TMPL_MEMBER_OPT_EX +#undef RTASN1TMPL_MEMBER_OPT_ITAG +#undef RTASN1TMPL_MEMBER_OPT_ITAG_EX +#undef RTASN1TMPL_MEMBER_OPT_ITAG_CP +#undef RTASN1TMPL_MEMBER_OPT_ITAG_UC +#undef RTASN1TMPL_MEMBER_OPT_ITAG_UP +#undef RTASN1TMPL_MEMBER_OPT_ITAG_BITSTRING +#undef RTASN1TMPL_MEMBER_OPT_UTF8_STRING +#undef RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX +#undef RTASN1TMPL_MEMBER_OPT_XTAG +#undef RTASN1TMPL_MEMBER_OPT_XTAG_EX +#undef RTASN1TMPL_MEMBER_OPT_ANY +#undef RTASN1TMPL_MEMBER_DEF_ITAG_UP +#undef RTASN1TMPL_MEMBER_DEF_ITAG_EX +#undef RTASN1TMPL_END_SEQCORE +#undef RTASN1TMPL_END_SETCORE + +#undef RTASN1TMPL_BEGIN_PCHOICE +#undef RTASN1TMPL_PCHOICE_ITAG +#undef RTASN1TMPL_PCHOICE_ITAG_UP +#undef RTASN1TMPL_PCHOICE_ITAG_CP +#undef RTASN1TMPL_PCHOICE_ITAG_EX +#undef RTASN1TMPL_PCHOICE_XTAG +#undef RTASN1TMPL_PCHOICE_XTAG_EX +#undef RTASN1TMPL_END_PCHOICE + +#undef RTASN1TMPL_SET_SEQ_OF_COMMON +#undef RTASN1TMPL_SEQ_OF +#undef RTASN1TMPL_SET_OF + +#undef RTASN1TMPL_VTABLE_FN_ENCODE_PREP +#undef RTASN1TMPL_VTABLE_FN_ENCODE_WRITE + +#undef RTASN1TMPL_MEMBER_CONSTR_MIN_MAX +#undef RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX +#undef RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX +#undef RTASN1TMPL_MEMBER_CONSTR_PRESENT + +#undef RTASN1TMPL_SANITY_CHECK_EXPR + +#undef RTASN1TMPL_EXEC_DECODE +#undef RTASN1TMPL_EXEC_CLONE +#undef RTASN1TMPL_EXEC_CHECK_SANITY + +#undef RTASN1TMPL_SET_SEQ_EXEC_CHECK_SANITY + diff --git a/include/iprt/asn1-generator-sanity.h b/include/iprt/asn1-generator-sanity.h new file mode 100644 index 00000000..93ad5036 --- /dev/null +++ b/include/iprt/asn1-generator-sanity.h @@ -0,0 +1,38 @@ +/** @file + * IPRT - ASN.1 Code Generator, the Sanity Checking. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_CHECK_SANITY +#include + diff --git a/include/iprt/asn1.h b/include/iprt/asn1.h new file mode 100644 index 00000000..19f200a6 --- /dev/null +++ b/include/iprt/asn1.h @@ -0,0 +1,2368 @@ +/** @file + * IPRT - Abstract Syntax Notation One (ASN.1). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asn1_h +#define IPRT_INCLUDED_asn1_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_asn1 RTAsn1 - Abstract Syntax Notation One + * @ingroup grp_rt + * @{ + */ + + +/** Pointer to ASN.1 allocation information. */ +typedef struct RTASN1ALLOCATION *PRTASN1ALLOCATION; +/** Pointer to ASN.1 array allocation information. */ +typedef struct RTASN1ARRAYALLOCATION *PRTASN1ARRAYALLOCATION; +/** Pointer to a ASN.1 byte decoder cursor. */ +typedef struct RTASN1CURSOR *PRTASN1CURSOR; + + +/** + * Sketch of a custom ASN.1 allocator virtual method table. + * + * Any information required by the allocator should be associated with this + * structure, i.e. use this as a kind of parent class. This saves storage in + * RTASN1ALLOCATORINFO and possibly reduces the number of parameters by one. + */ +typedef struct RTASN1ALLOCATORVTABLE +{ + /** + * Free a chunk of memory allocated by this allocator. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param pv Pointer to the memory that shall be freed. Not NULL. + */ + DECLCALLBACKMEMBER(void, pfnFree,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ALLOCATION pAllocation, + void *pv)); + /** + * Allocates a chunk of memory, all initialized to zero. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param ppv Where to store the pointer on success. + * @param cb The minimum number of bytes to allocate. The actual + * number of bytes allocated shall be stored in + * pInfo->cbAllocated on success. + */ + DECLCALLBACKMEMBER(int, pfnAlloc,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ALLOCATION pAllocation, + void **ppv, size_t cb)); + /** + * Reallocates a memory allocation. + * + * New memory does not need to be initialized, the caller takes care of that. + * + * This will not need to deal with free (@a cbNew == 0) or the initial + * allocation (@a pvOld == NULL), those calls will be directed to pfnFree and + * pfnAlloc respectively. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param pvOld Pointer to the current allocation. Shall remain + * valid on failure, but may be invalid on success. + * @param ppvNew Where to store the pointer on success. Shall not be + * touched, except on successful returns. + * @param cbNew The new minimum allocation size. The actual number + * of bytes allocated shall be stored in + * pInfo->cbAllocated on success. + */ + DECLCALLBACKMEMBER(int, pfnRealloc,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ALLOCATION pAllocation, + void *pvOld, void **ppvNew, size_t cbNew)); + + /** + * Frees an array allocation (the array an all instances in it). + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param papvArray Pointer to the pointer array to be freed. Not NULL. + */ + DECLCALLBACKMEMBER(void, pfnFreeArray,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ARRAYALLOCATION pAllocation, + void **papvArray)); + /** + * Grows the array to at least @a cMinEntries. + * + * The entries are initalized with ZEROs. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param ppapvArray Pointer to the pointer to the array to be grown (or + * allocated). + * @param cMinEntries The minimum number of entries (array size and + * instantiated entries) that must be available + * on successful return. + */ + DECLCALLBACKMEMBER(int, pfnGrowArray,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ARRAYALLOCATION pAllocation, + void ***ppapvArray, uint32_t cMinEntries)); + /** + * Shrinks the array (depends on allocator policy). + * + * If memory isn't freed, the implementation must fill the entries being + * shredded with ZEROs so the growth optimizations in RTAsn1MemResizeArray + * returns ZEROed entries. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param ppapvArray Pointer to the pointer to the array to shrunk. + * @param cNew The new entry count. + * @param cCurrent The new entry count. + */ + DECLCALLBACKMEMBER(void, pfnShrinkArray,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ARRAYALLOCATION pAllocation, + void ***ppapvArray, uint32_t cNew, uint32_t cCurrent)); +} RTASN1ALLOCATORVTABLE; +/** Pointer to an ASN.1 allocator vtable. */ +typedef RTASN1ALLOCATORVTABLE *PRTASN1ALLOCATORVTABLE; +/** Pointer to a const ASN.1 allocator vtable. */ +typedef RTASN1ALLOCATORVTABLE const *PCRTASN1ALLOCATORVTABLE; + +/** The default ASN.1 allocator. */ +extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1DefaultAllocator; + +/** The Electric Fence ASN.1 allocator. */ +extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1EFenceAllocator; + +/** The safer ASN.1 allocator for sensitive data. */ +extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1SaferAllocator; + + +/** + * Allocation information. + */ +typedef struct RTASN1ALLOCATION +{ + /** The number of bytes currently allocated. */ + uint32_t cbAllocated; + /** Number of realloc calls. */ + uint16_t cReallocs; + /** Reserved / padding. */ + uint16_t uReserved0; + /** Allocator vtable, NULL for the default allocator. */ + PCRTASN1ALLOCATORVTABLE pAllocator; +} RTASN1ALLOCATION; + + +/** + * Pointer array allocation information. + * + * Used by SET OF and SEQUENCE OF structures (typically automatically + * generated). + */ +typedef struct RTASN1ARRAYALLOCATION +{ + /** The size of the array entry. */ + uint32_t cbEntry; + /** The size of the pointer array allocation. */ + uint32_t cPointersAllocated; + /** Number of entry instances allocated. This can be greater than the + * official array size. */ + uint32_t cEntriesAllocated; + /** Number of array resizing calls (for increasing growth rate). + * Maintained by RTAsn1MemResizeArray(). */ + uint16_t cResizeCalls; + /** Reserved / padding. */ + uint16_t uReserved0; + /** Allocator vtable, NULL for the default allocator. */ + PCRTASN1ALLOCATORVTABLE pAllocator; +} RTASN1ARRAYALLOCATION; + + +/** + * Allocate a block of zero initialized memory. + * + * @returns IPRT status code. + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param ppvMem Where to return the pointer to the block. + * @param cbMem The minimum number of bytes to allocate. + */ +RTDECL(int) RTAsn1MemAllocZ(PRTASN1ALLOCATION pAllocation, void **ppvMem, size_t cbMem); + +/** + * Allocates a block of memory initialized to the content of @a pvSrc. + * + * @returns IPRT status code. + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param ppvMem Where to return the pointer to the block. + * @param pvSrc The source memory. + * @param cbMem The minimum number of bytes to allocate. + */ +RTDECL(int) RTAsn1MemDup(PRTASN1ALLOCATION pAllocation, void **ppvMem, void const *pvSrc, size_t cbMem); + +/** + * Free a memory block. + * + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param pv The memory block to free. NULL will be ignored. + */ +RTDECL(void) RTAsn1MemFree(PRTASN1ALLOCATION pAllocation, void *pv); + +/** + * Initalize an allocation. + * + * @returns pAllocation + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param pAllocator The allocator + */ +RTDECL(PRTASN1ALLOCATION) RTAsn1MemInitAllocation(PRTASN1ALLOCATION pAllocation, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Initalize an array allocation. + * + * @returns pAllocation + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param pAllocator The allocator + * @param cbEntry The entry size. + */ +RTDECL(PRTASN1ARRAYALLOCATION) RTAsn1MemInitArrayAllocation(PRTASN1ARRAYALLOCATION pAllocation, + PCRTASN1ALLOCATORVTABLE pAllocator, size_t cbEntry); + +/** + * Resize an array with zero initialized memory. + * + * @returns IPRT status code. + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param ppapvArray Pointer to the variable pointing to the array. This is + * both input and output. Remains valid on failure. + * @param cCurrent The current entry count. (Relevant for zero + * initialization of the new entries.) + * @param cNew The new entry count. + */ +RTDECL(int) RTAsn1MemResizeArray(PRTASN1ARRAYALLOCATION pAllocation, void ***ppapvArray, uint32_t cCurrent, uint32_t cNew); + +/** + * Frees an array and all its entries. + * + * @param pAllocation The array allocation record (initialized by + * RTAsn1CursorInitArrayAllocation or similar). + * @param papvArray The array to free. NULL is ignored. + */ +RTDECL(void) RTAsn1MemFreeArray(PRTASN1ARRAYALLOCATION pAllocation, void **papvArray); + + +/** Pointer to a core ASN.1 encoding info structure. */ +typedef struct RTASN1CORE *PRTASN1CORE; +/** Pointer to a const core ASN.1 encoding info structure. */ +typedef struct RTASN1CORE const *PCRTASN1CORE; + +RTDECL(int) RTAsn1ContentAllocZ(struct RTASN1CORE *pAsn1Core, size_t cb, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1ContentDup(struct RTASN1CORE *pAsn1Core, void const *pvSrc, size_t cbSrc, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1ContentReallocZ(struct RTASN1CORE *pAsn1Core, size_t cb, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(void) RTAsn1ContentFree(struct RTASN1CORE *pAsn1Core); + + + +/** + * ASN.1 object enumeration callback. + * + * @returns IPRT status code. VINF_SUCCESS continues the enumberation, all + * others quit it and is returned to the caller's caller. + * @param pAsn1Core The ASN.1 object we're called back about. + * @param pszName The member name. Array member names ends with + * '[#]'. + * @param uDepth The current depth. + * @param pvUser Callback user parameter. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1ENUMCALLBACK,(struct RTASN1CORE *pAsn1Core, const char *pszName, uint32_t uDepth, + void *pvUser)); +/** Pointer to an ASN.1 object enumeration callback. */ +typedef FNRTASN1ENUMCALLBACK *PFNRTASN1ENUMCALLBACK; + +/** + * ASN.1 object encoding writer callback. + * + * @returns IPRT status code. + * @param pvBuf Pointer to the bytes to output. + * @param cbToWrite The number of bytes to write. + * @param pvUser Callback user parameter. + * @param pErrInfo Where to store extended error info. Optional. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1ENCODEWRITER,(const void *pvBuf, size_t cbToWrite, void *pvUser, PRTERRINFO pErrInfo)); +/** Pointer to an ASN.1 encoding writer callback. */ +typedef FNRTASN1ENCODEWRITER *PFNRTASN1ENCODEWRITER; + +/** @name ASN.1 Vtable Method Types + * @{ */ + +/** + * Destructor. + * + * RTAsn1Destroy will first destroy all children by recursive calls to pfnEnum, + * afterwards it will call this method to release any memory or other resources + * associated with this object. The memory backing the object structure shall + * not be freed by this method. + * + * @param pThisCore Pointer to the ASN.1 core to destroy. + */ +typedef DECLCALLBACKTYPE(void, FNRTASN1COREVTDTOR,(PRTASN1CORE pThisCore)); +/** Pointer to a FNRTASN1COREVTDTOR method. */ +typedef FNRTASN1COREVTDTOR *PFNRTASN1COREVTDTOR; + +/** + * Enumerate members (not necessary for primitive objects). + * + * @returns IPRT status code, any non VINF_SUCCESS value stems from pfnCallback. + * @param pThisCore Pointer to the ASN.1 core to enumerate members of. + * @param pfnCallback The callback. + * @param uDepth The depth of this object. Children are at +1. + * @param pvUser Callback user argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTENUM,(PRTASN1CORE pThisCore, PFNRTASN1ENUMCALLBACK pfnCallback, + uint32_t uDepth, void *pvUser)); +/** Pointer to a FNRTASN1COREVTENUM method. */ +typedef FNRTASN1COREVTENUM *PFNRTASN1COREVTENUM; + +/** + * Clone method. + * + * @param pThisCore Pointer to the ASN.1 core to initialize as a clone + * of pSrcClone. (The caller is responsible for making + * sure there is sufficent space and such.) + * @param pSrcCore The object to clone. + * @param pAllocator The allocator to use. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTCLONE,(PRTASN1CORE pThisCore, PCRTASN1CORE pSrcCore, + PCRTASN1ALLOCATORVTABLE pAllocator)); +/** Pointer to a FNRTASN1COREVTCLONE method. */ +typedef FNRTASN1COREVTCLONE *PFNRTASN1COREVTCLONE; + +/** + * Compare method. + * + * The caller makes sure both cores are present and have the same Vtable. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeftCore Pointer to the ASN.1 core of the left side object. + * @param pRightCore Pointer to the ASN.1 core of the right side object. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTCOMPARE,(PCRTASN1CORE pLeftCore, PCRTASN1CORE pRightCore)); +/** Pointer to a FNRTASN1COREVTCOMPARE method. */ +typedef FNRTASN1COREVTCOMPARE *PFNRTASN1COREVTCOMPARE; + +/** + * Check sanity method. + * + * @returns IPRT status code. + * @param pThisCore Pointer to the ASN.1 core of the object to check out. + * @param fFlags See RTASN1_CHECK_SANITY_F_XXX. + * @param pErrInfo Where to return additional error details. Optional. + * @param pszErrorTag Tag for the additional error details. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTCHECKSANITY,(PCRTASN1CORE pThisCore, uint32_t fFlags, + PRTERRINFO pErrInfo, const char *pszErrorTag)); +/** Pointer to a FNRTASN1COREVTCHECKSANITY method. */ +typedef FNRTASN1COREVTCHECKSANITY *PFNRTASN1COREVTCHECKSANITY; + +/** + * Optional encoding preparations. + * + * On successful return, the pThisCore->cb value shall be valid and up to date. + * Will be called for any present object, including ones with default values and + * similar. + * + * @returns IPRT status code + * @param pThisCore Pointer to the ASN.1 core to enumerate members of. + * @param fFlags Encoding flags, RTASN1ENCODE_F_XXX. + * @param pErrInfo Where to return extra error information. Optional. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTENCODEPREP,(PRTASN1CORE pThisCore, uint32_t fFlags, PRTERRINFO pErrInfo)); +/** Pointer to a FNRTASN1COREVTENCODEWRITE method. */ +typedef FNRTASN1COREVTENCODEPREP *PFNRTASN1COREVTENCODEPREP; + +/** + * Optional encoder writer. + * + * This writes the header as well as all the content. Will be called for any + * present object, including ones with default values and similar. + * + * @returns IPRT status code. + * @param pThisCore Pointer to the ASN.1 core to enumerate members of. + * @param fFlags Encoding flags, RTASN1ENCODE_F_XXX. + * @param pfnWriter The output writer function. + * @param pvUser The user context for the writer function. + * @param pErrInfo Where to return extra error information. Optional. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTENCODEWRITE,(PRTASN1CORE pThisCore, uint32_t fFlags, PFNRTASN1ENCODEWRITER pfnWriter, + void *pvUser, PRTERRINFO pErrInfo)); +/** Pointer to a FNRTASN1COREVTENCODEWRITE method. */ +typedef FNRTASN1COREVTENCODEWRITE *PFNRTASN1COREVTENCODEWRITE; +/** @} */ + +/** Mask of common flags. These will be propagated during sanity checking. + * Bits not in this mask are type specfic. */ +#define RTASN1_CHECK_SANITY_F_COMMON_MASK UINT32_C(0xffff0000) + +/** + * ASN.1 core vtable. + */ +typedef struct RTASN1COREVTABLE +{ + /** The name. */ + const char *pszName; + /** Size of the structure. */ + uint32_t cbStruct; + /** The default tag, UINT8_MAX if not applicable. */ + uint8_t uDefaultTag; + /** The default class and flags. */ + uint8_t fDefaultClass; + /** Reserved for later / alignment. */ + uint16_t uReserved; + /** @copydoc FNRTASN1COREVTDTOR */ + PFNRTASN1COREVTDTOR pfnDtor; + /** @copydoc FNRTASN1COREVTENUM */ + PFNRTASN1COREVTENUM pfnEnum; + /** @copydoc FNRTASN1COREVTCLONE */ + PFNRTASN1COREVTCLONE pfnClone; + /** @copydoc FNRTASN1COREVTCOMPARE */ + PFNRTASN1COREVTCOMPARE pfnCompare; + /** @copydoc FNRTASN1COREVTCHECKSANITY */ + PFNRTASN1COREVTCHECKSANITY pfnCheckSanity; + /** @copydoc FNRTASN1COREVTENCODEPREP */ + PFNRTASN1COREVTENCODEPREP pfnEncodePrep; + /** @copydoc FNRTASN1COREVTENUM */ + PFNRTASN1COREVTENCODEWRITE pfnEncodeWrite; +} RTASN1COREVTABLE; +/** Pointer to an ASN.1 allocator vtable. */ +typedef struct RTASN1COREVTABLE *PRTASN1COREVTABLE; +/** Pointer to a const ASN.1 allocator vtable. */ +typedef RTASN1COREVTABLE const *PCRTASN1COREVTABLE; + + +/** @name Helper macros for prototyping standard functions for an ASN.1 type. + * @{ */ + +#define RTASN1TYPE_STANDARD_PROTOTYPES_NO_GET_CORE(a_TypeNm, a_DeclMacro, a_ImplExtNm) \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Init)(RT_CONCAT(P,a_TypeNm) pThis, PCRTASN1ALLOCATORVTABLE pAllocator); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Clone)(RT_CONCAT(P,a_TypeNm) pThis, RT_CONCAT(PC,a_TypeNm) pSrc, \ + PCRTASN1ALLOCATORVTABLE pAllocator); \ + a_DeclMacro(void) RT_CONCAT(a_ImplExtNm,_Delete)(RT_CONCAT(P,a_TypeNm) pThis); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Enum)(RT_CONCAT(P,a_TypeNm) pThis, PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Compare)(RT_CONCAT(PC,a_TypeNm) pLeft, RT_CONCAT(PC,a_TypeNm) pRight); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_DecodeAsn1)(PRTASN1CURSOR pCursor, uint32_t fFlags, RT_CONCAT(P,a_TypeNm) pThis,\ + const char *pszErrorTag); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_CheckSanity)(RT_CONCAT(PC,a_TypeNm) pThis, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) + + +#define RTASN1TYPE_STANDARD_PROTOTYPES(a_TypeNm, a_DeclMacro, a_ImplExtNm, a_Asn1CoreNm) \ + DECL_FORCE_INLINE(PRTASN1CORE) RT_CONCAT(a_ImplExtNm,_GetAsn1Core)(RT_CONCAT(PC,a_TypeNm) pThis) \ + { return (PRTASN1CORE)&pThis->a_Asn1CoreNm; } \ + DECLINLINE(bool) RT_CONCAT(a_ImplExtNm,_IsPresent)(RT_CONCAT(PC,a_TypeNm) pThis) \ + { return pThis && RTASN1CORE_IS_PRESENT(&pThis->a_Asn1CoreNm); } \ + RTASN1TYPE_STANDARD_PROTOTYPES_NO_GET_CORE(a_TypeNm, a_DeclMacro, a_ImplExtNm) + + +/** Aliases two ASN.1 types, no method aliases. */ +#define RTASN1TYPE_ALIAS_TYPE_ONLY(a_TypeNm, a_AliasType) \ + typedef a_AliasType a_TypeNm; \ + typedef a_TypeNm *RT_CONCAT(P,a_TypeNm); \ + typedef a_TypeNm const *RT_CONCAT(PC,a_TypeNm) + +/** Aliases two ASN.1 types and methods. */ +#define RTASN1TYPE_ALIAS(a_TypeNm, a_AliasType, a_ImplExtNm, a_AliasExtNm) \ + typedef a_AliasType a_TypeNm; \ + typedef a_TypeNm *RT_CONCAT(P,a_TypeNm); \ + \ + DECLINLINE(PRTASN1CORE) RT_CONCAT(a_ImplExtNm,_GetAsn1Core)(a_TypeNm const *pThis) \ + { return RT_CONCAT(a_AliasExtNm,_GetAsn1Core)(pThis); } \ + DECLINLINE(bool) RT_CONCAT(a_ImplExtNm,_IsPresent)(a_TypeNm const *pThis) \ + { return RT_CONCAT(a_AliasExtNm,_IsPresent)(pThis); } \ + \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_Init)(RT_CONCAT(P,a_TypeNm) pThis, PCRTASN1ALLOCATORVTABLE pAllocator) \ + { return RT_CONCAT(a_AliasExtNm,_Init)(pThis, pAllocator); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_Clone)(RT_CONCAT(P,a_TypeNm) pThis, a_TypeNm const *pSrc, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ + { return RT_CONCAT(a_AliasExtNm,_Clone)(pThis, pSrc, pAllocator); } \ + DECLINLINE(void) RT_CONCAT(a_ImplExtNm,_Delete)(RT_CONCAT(P,a_TypeNm) pThis) \ + { RT_CONCAT(a_AliasExtNm,_Delete)(pThis); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_Enum)(a_TypeNm *pThis, PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser) \ + { return RT_CONCAT(a_AliasExtNm,_Enum)(pThis, pfnCallback, uDepth, pvUser); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_Compare)(a_TypeNm const *pLeft, a_TypeNm const *pRight) \ + { return RT_CONCAT(a_AliasExtNm,_Compare)(pLeft, pRight); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_DecodeAsn1)(PRTASN1CURSOR pCursor, uint32_t fFlags, RT_CONCAT(P,a_TypeNm) pThis,\ + const char *pszErrorTag) \ + { return RT_CONCAT(a_AliasExtNm,_DecodeAsn1)(pCursor, fFlags, pThis, pszErrorTag); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_CheckSanity)(a_TypeNm const *pThis, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) \ + { return RT_CONCAT(a_AliasExtNm,_CheckSanity)(pThis, fFlags, pErrInfo, pszErrorTag); } \ + \ + typedef a_TypeNm const *RT_CONCAT(PC,a_TypeNm) + +/** @} */ + + +/** + * Core ASN.1 structure for storing encoding details and data location. + * + * This is used as a 'parent' for all other decoded ASN.1 based structures. + */ +typedef struct RTASN1CORE +{ + /** The tag. + * @remarks 32-bit should be enough for everyone... We don't currently + * implement decoding tags larger than 30 anyway. :-) */ + uint32_t uTag; + /** Tag class and flags (ASN1_TAGCLASS_XXX and ASN1_TAGFLAG_XXX). */ + uint8_t fClass; + /** The real tag value for IMPLICT tag overrides. */ + uint8_t uRealTag; + /** The real class value for IMPLICT tag overrides. */ + uint8_t fRealClass; + /** The size of the tag and length ASN.1 header. */ + uint8_t cbHdr; + /** Length. */ + uint32_t cb; + /** IPRT flags (RTASN1CORE_F_XXX). */ + uint32_t fFlags; + /** Pointer to the data. + * After decoding this generally points to the encoded data content. When + * preparting something for encoding or otherwise constructing things in memory, + * this generally points heap memory or read-only constants. + * @sa RTAsn1ContentAllocZ, RTAsn1ContentReallocZ, RTAsn1ContentDup, + * RTAsn1ContentFree. */ + RTCPTRUNION uData; + /** Pointer to the virtual method table for this object. Optional. */ + PCRTASN1COREVTABLE pOps; +} RTASN1CORE; +/** The Vtable for a RTASN1CORE structure when not in some way use used as a + * parent type/class. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Core_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES_NO_GET_CORE(RTASN1CORE, RTDECL, RTAsn1Core); + +/** @name RTASN1CORE_F_XXX - Flags for RTASN1CORE::fFlags + * @{ */ +/** Present/valid. */ +#define RTASN1CORE_F_PRESENT RT_BIT_32(0) +/** Not present in stream, using default value. */ +#define RTASN1CORE_F_DEFAULT RT_BIT_32(1) +/** The tag was overriden by an implict context tag or some such thing, + * RTASN1CORE::uImplicitTag hold the universal tag value if one exists. */ +#define RTASN1CORE_F_TAG_IMPLICIT RT_BIT_32(2) +/** Primitive tag with the corresponding RTASN1XXX struct. */ +#define RTASN1CORE_F_PRIMITE_TAG_STRUCT RT_BIT_32(3) +/** Dummy node typically used with choices, has children, not encoded, must be + * ignored. */ +#define RTASN1CORE_F_DUMMY RT_BIT_32(4) +/** Allocated content (pointed to by uData). + * The content should is still be considered 104% read-only by anyone other + * than then type methods (pOps and associates). */ +#define RTASN1CORE_F_ALLOCATED_CONTENT RT_BIT_32(5) +/** Decoded content (pointed to by uData). + * Mutually exclusive with RTASN1CORE_F_ALLOCATED_CONTENT. If neither is + * set, uData might be NULL or point to some shared static memory for + * frequently used values. */ +#define RTASN1CORE_F_DECODED_CONTENT RT_BIT_32(6) +/** Indefinite length, still pending. */ +#define RTASN1CORE_F_INDEFINITE_LENGTH RT_BIT_32(7) +/** @} */ + + +/** Checks whether an ASN.1 core object present in some way (default data, + * decoded data, ...). */ +#define RTASN1CORE_IS_PRESENT(a_pAsn1Core) ( RT_BOOL((a_pAsn1Core)->fFlags) ) + +/** Checks whether an ASN.1 core object is a dummy object (and is present). */ +#define RTASN1CORE_IS_DUMMY(a_pAsn1Core) ( RT_BOOL((a_pAsn1Core)->fFlags & RTASN1CORE_F_DUMMY) ) + +/** + * Calculates pointer to the raw ASN.1 record. + * + * ASSUMES that it's decoded content and that cbHdr and uData are both valid. + * + * @returns Byte pointer to the first tag byte. + * @param a_pAsn1Core The ASN.1 core. + */ +#define RTASN1CORE_GET_RAW_ASN1_PTR(a_pAsn1Core) ( (a_pAsn1Core)->uData.pu8 - (a_pAsn1Core)->cbHdr ) + +/** + * Calculates the length of the raw ASN.1 record to go with the + * RTASN1CORE_GET_RAW_ASN1_PTR() result. + * + * ASSUMES that it's decoded content and that cbHdr and uData are both valid. + * + * @returns Size in bytes (uint32_t). + * @param a_pAsn1Core The ASN.1 core. + */ +#define RTASN1CORE_GET_RAW_ASN1_SIZE(a_pAsn1Core) ( (a_pAsn1Core)->cbHdr + (a_pAsn1Core)->cb ) + +/** + * Retrievs the tag or implicit tag depending on the RTASN1CORE_F_TAG_IMPLICIT + * flag. + * + * @returns The ASN.1 tag of the object. + * @param a_pAsn1Core The ASN.1 core. + */ +#define RTASN1CORE_GET_TAG(a_pAsn1Core) ( !((a_pAsn1Core)->fFlags & RTASN1CORE_F_TAG_IMPLICIT) ? (a_pAsn1Core)->uTag : (a_pAsn1Core)->uRealTag ) + + +DECL_FORCE_INLINE(PRTASN1CORE) RTAsn1Core_GetAsn1Core(PCRTASN1CORE pThis) +{ + return (PRTASN1CORE)pThis; +} + + +DECL_FORCE_INLINE(bool) RTAsn1Core_IsPresent(PCRTASN1CORE pThis) +{ + return pThis && RTASN1CORE_IS_PRESENT(pThis); +} + + +RTDECL(int) RTAsn1Core_InitEx(PRTASN1CORE pAsn1Core, uint32_t uTag, uint8_t fClass, PCRTASN1COREVTABLE pOps, uint32_t fFlags); +/** + * Initialize the ASN.1 core object representation to a default value. + * + * @returns VINF_SUCCESS + * @param pAsn1Core The ASN.1 core. + * @param uTag The tag number. + * @param fClass The tag class and flags. + */ +RTDECL(int) RTAsn1Core_InitDefault(PRTASN1CORE pAsn1Core, uint32_t uTag, uint8_t fClass); +RTDECL(int) RTAsn1Core_CloneContent(PRTASN1CORE pThis, PCRTASN1CORE pSrc, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1Core_CloneNoContent(PRTASN1CORE pThis, PCRTASN1CORE pSrc); +RTDECL(int) RTAsn1Core_SetTagAndFlags(PRTASN1CORE pAsn1Core, uint32_t uTag, uint8_t fClass); +RTDECL(int) RTAsn1Core_ChangeTag(PRTASN1CORE pAsn1Core, uint32_t uTag); +RTDECL(void) RTAsn1Core_ResetImplict(PRTASN1CORE pThis); +RTDECL(int) RTAsn1Core_CompareEx(PCRTASN1CORE pLeft, PCRTASN1CORE pRight, bool fIgnoreTagAndClass); + + +/** + * Dummy ASN.1 object for use in choices and similar non-sequence structures. + * + * This allows hooking up destructors, enumerators and such, as well as not + * needing custom code for sequence-of / set-of collections. + */ +typedef struct RTASN1DUMMY +{ + /** Core ASN.1. */ + RTASN1CORE Asn1Core; +} RTASN1DUMMY; +/** Pointer to a dummy record. */ +typedef RTASN1DUMMY *PRTASN1DUMMY; + + +/** + * Initalizes a dummy ASN.1 object. + * + * @returns VINF_SUCCESS. + * @param pThis The dummy object. + */ +RTDECL(int) RTAsn1Dummy_InitEx(PRTASN1DUMMY pThis); + +/** + * Standard compliant initalizer. + * + * @returns VINF_SUCCESS. + * @param pThis The dummy object. + * @param pAllocator Ignored. + */ +DECLINLINE(int) RTAsn1Dummy_Init(PRTASN1DUMMY pThis, PCRTASN1ALLOCATORVTABLE pAllocator) +{ + NOREF(pAllocator); + return RTAsn1Dummy_InitEx(pThis); +} + + +/** + * ASN.1 sequence core (IPRT representation). + */ +typedef struct RTASN1SEQUENCECORE +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1SEQUENCECORE; +/** Pointer to an ASN.1 sequence core (IPRT representation). */ +typedef RTASN1SEQUENCECORE *PRTASN1SEQUENCECORE; +/** Pointer to a const ASN.1 sequence core (IPRT representation). */ +typedef RTASN1SEQUENCECORE const *PCRTASN1SEQUENCECORE; + +RTDECL(int) RTAsn1SequenceCore_Init(PRTASN1SEQUENCECORE pSeqCore, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1SequenceCore_Clone(PRTASN1SEQUENCECORE pSeqCore, PCRTASN1COREVTABLE pVtable, PCRTASN1SEQUENCECORE pSrc); + +/** + * ASN.1 sequence-of core (IPRT representation). + */ +#if 0 +typedef struct RTASN1SEQOFCORE +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1SEQUENCECORE; +/** Pointer to an ASN.1 sequence-of core (IPRT representation). */ +typedef RTASN1SEQUENCECORE *PRTASN1SEQUENCECORE; +/** Pointer to a const ASN.1 sequence-of core (IPRT representation). */ +typedef RTASN1SEQUENCECORE const *PCRTASN1SEQUENCECORE; +#else +# define RTASN1SEQOFCORE RTASN1SEQUENCECORE +# define PRTASN1SEQOFCORE PRTASN1SEQUENCECORE +# define PCRTASN1SEQOFCORE PCRTASN1SEQUENCECORE +#endif +RTDECL(int) RTAsn1SeqOfCore_Init(PRTASN1SEQOFCORE pThis, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1SeqOfCore_Clone(PRTASN1SEQOFCORE pThis, PCRTASN1COREVTABLE pVtable, PCRTASN1SEQOFCORE pSrc); + + +/** Defines the typedefs and prototypes for a generic sequence-of/set-of type. */ +#define RTASN1_IMPL_GEN_SEQ_OR_SET_OF_TYPEDEFS_AND_PROTOS(a_CoreType, a_CoreMember, \ + a_ThisType, a_ItemType, a_DeclMacro, a_ImplExtNm) \ + typedef struct a_ThisType \ + { \ + /** Sequence/set core. */ \ + a_CoreType a_CoreMember; \ + /** The array allocation tracker. */ \ + RTASN1ARRAYALLOCATION Allocation; \ + /** Items in the array. */ \ + uint32_t cItems; \ + /** Array. */ \ + RT_CONCAT(P,a_ItemType) *papItems; \ + } a_ThisType; \ + typedef a_ThisType *RT_CONCAT(P,a_ThisType); \ + typedef a_ThisType const *RT_CONCAT(PC,a_ThisType); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Erase)(RT_CONCAT(P,a_ThisType) pThis, uint32_t iPosition); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_InsertEx)(RT_CONCAT(P,a_ThisType) pThis, uint32_t iPosition, \ + RT_CONCAT(PC,a_ItemType) pToClone, \ + PCRTASN1ALLOCATORVTABLE pAllocator, uint32_t *piActualPos); \ + /** Appends entry with default content, returns index or negative error code. */ \ + DECLINLINE(int32_t) RT_CONCAT(a_ImplExtNm,_Append)(RT_CONCAT(P,a_ThisType) pThis) \ + { \ + uint32_t uPos = pThis->cItems; \ + int rc = RT_CONCAT(a_ImplExtNm,_InsertEx)(pThis, uPos, NULL /*pToClone*/, pThis->Allocation.pAllocator, &uPos); \ + if (RT_SUCCESS(rc)) \ + return (int32_t)uPos; \ + return rc; \ + } \ + RTASN1TYPE_STANDARD_PROTOTYPES(a_ThisType, a_DeclMacro, a_ImplExtNm, a_CoreMember.Asn1Core) + +/** Defines the typedefs and prototypes for a generic sequence-of type. */ +#define RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(a_SeqOfType, a_ItemType, a_DeclMacro, a_ImplExtNm) \ + RTASN1_IMPL_GEN_SEQ_OR_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQUENCECORE, SeqCore, a_SeqOfType, a_ItemType, a_DeclMacro, a_ImplExtNm) + + +/** + * ASN.1 set core (IPRT representation). + */ +typedef struct RTASN1SETCORE +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1SETCORE; +/** Pointer to an ASN.1 set core (IPRT representation). */ +typedef RTASN1SETCORE *PRTASN1SETCORE; +/** Pointer to a const ASN.1 set core (IPRT representation). */ +typedef RTASN1SETCORE const *PCRTASN1SETCORE; + +RTDECL(int) RTAsn1SetCore_Init(PRTASN1SETCORE pThis, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1SetCore_Clone(PRTASN1SETCORE pThis, PCRTASN1COREVTABLE pVtable, PCRTASN1SETCORE pSrc); + +/** + * ASN.1 set-of core (IPRT representation). + */ +#if 0 +typedef struct RTASN1SETOFCORE +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1SETUENCECORE; +/** Pointer to an ASN.1 set-of core (IPRT representation). */ +typedef RTASN1SETUENCECORE *PRTASN1SETUENCECORE; +/** Pointer to a const ASN.1 set-of core (IPRT representation). */ +typedef RTASN1SETUENCECORE const *PCRTASN1SETUENCECORE; +#else +# define RTASN1SETOFCORE RTASN1SETCORE +# define PRTASN1SETOFCORE PRTASN1SETCORE +# define PCRTASN1SETOFCORE PCRTASN1SETCORE +#endif +RTDECL(int) RTAsn1SetOfCore_Init(PRTASN1SETOFCORE pThis, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1SetOfCore_Clone(PRTASN1SETOFCORE pThis, PCRTASN1COREVTABLE pVtable, PCRTASN1SETOFCORE pSrc); + + +/** Defines the typedefs and prototypes for a generic set-of type. */ +#define RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(a_SetOfType, a_ItemType, a_DeclMacro, a_ImplExtNm) \ + RTASN1_IMPL_GEN_SEQ_OR_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETCORE, SetCore, a_SetOfType, a_ItemType, a_DeclMacro, a_ImplExtNm) + + +/* + * Declare sets and sequences of the core structure. + */ +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFCORES, RTASN1CORE, RTDECL, RTAsn1SeqOfCores); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFCORES, RTASN1CORE, RTDECL, RTAsn1SetOfCores); + + +/** + * ASN.1 null (IPRT representation). + */ +typedef struct RTASN1NULL +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1NULL; +/** Pointer to an ASN.1 null (IPRT representation). */ +typedef RTASN1NULL *PRTASN1NULL; +/** Pointer to a const ASN.1 null (IPRT representation). */ +typedef RTASN1NULL const *PCRTASN1NULL; +/** The Vtable for a RTASN1NULL structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Null_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1NULL, RTDECL, RTAsn1Null, Asn1Core); + + +/** + * ASN.1 integer (IPRT representation). + */ +typedef struct RTASN1INTEGER +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** The unsigned C representation of the 64 least significant bits. + * @note A ASN.1 integer doesn't define signed/unsigned and can have any + * length you like. Thus, the user needs to check the size and + * preferably use the access APIs for signed numbers. */ + RTUINT64U uValue; +} RTASN1INTEGER; +/** Pointer to an ASN.1 integer (IPRT representation). */ +typedef RTASN1INTEGER *PRTASN1INTEGER; +/** Pointer to a const ASN.1 integer (IPRT representation). */ +typedef RTASN1INTEGER const *PCRTASN1INTEGER; +/** The Vtable for a RTASN1INTEGER structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Integer_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1INTEGER, RTDECL, RTAsn1Integer, Asn1Core); + +/** + * Initializes an interger object to a default value. + * @returns VINF_SUCCESS. + * @param pInteger The integer object representation. + * @param uValue The default value (unsigned 64-bit). + * @param pAllocator The allocator (pro forma). + */ +RTDECL(int) RTAsn1Integer_InitDefault(PRTASN1INTEGER pInteger, uint64_t uValue, PCRTASN1ALLOCATORVTABLE pAllocator); + +RTDECL(int) RTAsn1Integer_InitU64(PRTASN1INTEGER pThis, uint64_t uValue, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Get the most significat bit that's set (1). + * + * @returns 0-base bit number, -1 if all clear. + * @param pInteger The integer to check. + */ +RTDECL(int32_t) RTAsn1Integer_UnsignedLastBit(PCRTASN1INTEGER pInteger); + +/** + * Compares two ASN.1 unsigned integers. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeft The first ASN.1 integer. + * @param pRight The second ASN.1 integer. + */ +RTDECL(int) RTAsn1Integer_UnsignedCompare(PCRTASN1INTEGER pLeft, PCRTASN1INTEGER pRight); + +/** + * Compares an ASN.1 unsigned integer with a uint64_t. + * + * @returns 0 if equal, -1 if @a pInteger is smaller, 1 if @a pInteger is + * larger. + * @param pInteger The ASN.1 integer to treat as unsigned. + * @param u64Const The uint64_t constant to compare with. + */ +RTDECL(int) RTAsn1Integer_UnsignedCompareWithU64(PCRTASN1INTEGER pInteger, uint64_t u64Const); + +/** + * Compares an ASN.1 unsigned integer with a uint32_t. + * + * @returns 0 if equal, -1 if @a pInteger is smaller, 1 if @a pInteger is + * larger. + * @param pInteger The ASN.1 integer to treat as unsigned. + * @param u32Const The uint32_t constant to compare with. + * @remarks We don't bother with U16 and U8 variants, just use this instead. + */ +RTDECL(int) RTAsn1Integer_UnsignedCompareWithU32(PCRTASN1INTEGER pInteger, uint32_t u32Const); + + +/** + * Initializes a big integer number from an ASN.1 integer. + * + * @returns IPRT status code. + * @param pInteger The ASN.1 integer. + * @param pBigNum The big integer number structure to initialize. + * @param fBigNumInit Subset of RTBIGNUMINIT_F_XXX that concerns + * senitivity, signedness and endianness. + */ +RTDECL(int) RTAsn1Integer_ToBigNum(PCRTASN1INTEGER pInteger, PRTBIGNUM pBigNum, uint32_t fBigNumInit); +RTDECL(int) RTAsn1Integer_FromBigNum(PRTASN1INTEGER pThis, PCRTBIGNUM pBigNum, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Converts the integer to a string. + * + * This will produce a hex represenation of the number. If it fits in 64-bit, a + * C style hex number will be produced. If larger than 64-bit, it will be + * printed as a space separated string of hex bytes. + * + * @returns IPRT status code. + * @param pThis The ASN.1 integer. + * @param pszBuf The output buffer. + * @param cbBuf The buffer size. + * @param fFlags Flags reserved for future exploits. MBZ. + * @param pcbActual Where to return the amount of buffer space used + * (i.e. including terminator). Optional. + * + * @remarks Currently assume unsigned number. + */ +RTDECL(int) RTAsn1Integer_ToString(PCRTASN1INTEGER pThis, char *pszBuf, size_t cbBuf, uint32_t fFlags, size_t *pcbActual); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFINTEGERS, RTASN1INTEGER, RTDECL, RTAsn1SeqOfIntegers); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFINTEGERS, RTASN1INTEGER, RTDECL, RTAsn1SetOfIntegers); + + + +/** + * ASN.1 boolean (IPRT representation). + */ +typedef struct RTASN1BOOLEAN +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** The boolean value. */ + bool fValue; +} RTASN1BOOLEAN; +/** Pointer to the IPRT representation of an ASN.1 boolean. */ +typedef RTASN1BOOLEAN *PRTASN1BOOLEAN; +/** Pointer to the const IPRT representation of an ASN.1 boolean. */ +typedef RTASN1BOOLEAN const *PCRTASN1BOOLEAN; +/** The Vtable for a RTASN1BOOLEAN structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Boolean_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1BOOLEAN, RTDECL, RTAsn1Boolean, Asn1Core); + +/** + * Initializes a boolean object to a default value. + * @returns VINF_SUCCESS + * @param pBoolean The boolean object representation. + * @param fValue The default value. + * @param pAllocator The allocator (pro forma). + */ +RTDECL(int) RTAsn1Boolean_InitDefault(PRTASN1BOOLEAN pBoolean, bool fValue, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1Boolean_Set(PRTASN1BOOLEAN pThis, bool fValue); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFBOOLEANS, RTASN1BOOLEAN, RTDECL, RTAsn1SeqOfBooleans); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFBOOLEANS, RTASN1BOOLEAN, RTDECL, RTAsn1SetOfBooleans); + + + +/** + * ASN.1 UTC and Generalized Time (IPRT representation). + * + * The two time types only differs in the precision the render (UTC time being + * the one for which you go "WTF were they thinking?!!" for in 2014). + */ +typedef struct RTASN1TIME +{ + /** The core structure, either ASN1_TAG_UTC_TIME or + * ASN1_TAG_GENERALIZED_TIME. */ + RTASN1CORE Asn1Core; + /** The exploded time. */ + RTTIME Time; +} RTASN1TIME; +/** Pointer to an IPRT representation of ASN.1 UTC/Generalized time. */ +typedef RTASN1TIME *PRTASN1TIME; +/** Pointer to a const IPRT representation of ASN.1 UTC/Generalized time. */ +typedef RTASN1TIME const *PCRTASN1TIME; +/** The Vtable for a RTASN1TIME structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Time_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1TIME, RTDECL, RTAsn1Time, Asn1Core); + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1TIME, RTDECL, RTAsn1UtcTime, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1TIME, RTDECL, RTAsn1GeneralizedTime, Asn1Core); + +/** + * Compares two ASN.1 time values. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeft The first ASN.1 time object. + * @param pTsRight The second time to compare. + */ +RTDECL(int) RTAsn1Time_CompareWithTimeSpec(PCRTASN1TIME pLeft, PCRTTIMESPEC pTsRight); + +/** + * Extended init function that lets you select the kind of time object (UTC or + * generalized). + */ +RTDECL(int) RTAsn1Time_InitEx(PRTASN1TIME pThis, uint32_t uTag, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Combines RTAsn1Time_InitEx() and RTAsn1Time_SetTime(). + */ +RTDECL(int) RTAsn1Time_InitWithTime(PRTASN1TIME pThis, uint32_t uTag, PCRTASN1ALLOCATORVTABLE pAllocator, PCRTTIME pTime); + +/** + * Sets the ASN.1 time value to @a pTime. + * + * @returns IPRT status code. + * @param pThis The ASN.1 time object to modify. + * @param pAllocator The allocator to use. + * @param pTime The time to set. + */ +RTDECL(int) RTAsn1Time_SetTime(PRTASN1TIME pThis, PCRTASN1ALLOCATORVTABLE pAllocator, PCRTTIME pTime); + +/** + * Sets the ASN.1 time value to @a pTimeSpec. + * + * @returns IPRT status code. + * @param pThis The ASN.1 time object to modify. + * @param pAllocator The allocator to use. + * @param pTimeSpec The time to set. + */ +RTDECL(int) RTAsn1Time_SetTimeSpec(PRTASN1TIME pThis, PCRTASN1ALLOCATORVTABLE pAllocator, PCRTTIMESPEC pTimeSpec); + +/** @name Predicate macros for determing the exact type of RTASN1TIME. + * @{ */ +/** True if UTC time. */ +#define RTASN1TIME_IS_UTC_TIME(a_pAsn1Time) ((a_pAsn1Time)->Asn1Core.uTag == ASN1_TAG_UTC_TIME) +/** True if generalized time. */ +#define RTASN1TIME_IS_GENERALIZED_TIME(a_pAsn1Time) ((a_pAsn1Time)->Asn1Core.uTag == ASN1_TAG_GENERALIZED_TIME) +/** @} */ + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFTIMES, RTASN1TIME, RTDECL, RTAsn1SeqOfTimes); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFTIMES, RTASN1TIME, RTDECL, RTAsn1SetOfTimes); + + + +/** + * ASN.1 object identifier (IPRT representation). + */ +typedef struct RTASN1OBJID +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** Coverning the paComponents memory allocation if there isn't enough room in + * szObjId for both the dottet string and the component values. */ + RTASN1ALLOCATION Allocation; + /** Pointer to an array with the component values. + * This may point within szObjId if there is enough space for both there. */ + uint32_t const *pauComponents; + /** The number of components in the object identifier. + * This ASSUMES that nobody will be ever needing more than 255 components. */ + uint8_t cComponents; + /** The dotted string representation of the object identifier. + * If there is sufficient space after the string, we will place the array that + * paComponents points to here and/or the raw content bytes (Asn1Core.uData). + * + * An analysis of dumpasn1.cfg, hl7.org and our own _OID defines indicates + * that we need space for at least 10 components and 30-something chars. We've + * allocated 87 bytes, which we ASSUME should be enough for everyone. */ + char szObjId[87]; +} RTASN1OBJID; +/** Pointer to an ASN.1 object identifier representation. */ +typedef RTASN1OBJID *PRTASN1OBJID; +/** Pointer to a const ASN.1 object identifier representation. */ +typedef RTASN1OBJID const *PCRTASN1OBJID; +/** The Vtable for a RTASN1OBJID structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1ObjId_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1OBJID, RTDECL, RTAsn1ObjId, Asn1Core); + +RTDECL(int) RTAsn1ObjId_InitFromString(PRTASN1OBJID pThis, const char *pszObjId, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1ObjId_SetFromString(PRTASN1OBJID pThis, const char *pszObjId, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Compares an ASN.1 object identifier with a dotted object identifier string. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pThis The ASN.1 object identifier. + * @param pszRight The dotted object identifier string. + */ +RTDECL(int) RTAsn1ObjId_CompareWithString(PCRTASN1OBJID pThis, const char *pszRight); + +/** + * Checks if an ASN.1 object identifier starts with the given dotted object + * identifier string. + * + * The matching is only successful if the given string matches matches the last + * component completely. + * + * @returns true / false. + * @param pThis The ASN.1 object identifier. + * @param pszStartsWith The dotted object identifier string. + */ +RTDECL(bool) RTAsn1ObjId_StartsWith(PCRTASN1OBJID pThis, const char *pszStartsWith); + +RTDECL(uint8_t) RTAsn1ObjIdCountComponents(PCRTASN1OBJID pThis); +RTDECL(uint32_t) RTAsn1ObjIdGetComponentsAsUInt32(PCRTASN1OBJID pThis, uint8_t iComponent); +RTDECL(uint32_t) RTAsn1ObjIdGetLastComponentsAsUInt32(PCRTASN1OBJID pThis); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFOBJIDS, RTASN1OBJID, RTDECL, RTAsn1SeqOfObjIds); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFOBJIDS, RTASN1OBJID, RTDECL, RTAsn1SetOfObjIds); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFOBJIDSEQS, RTASN1SEQOFOBJIDS, RTDECL, RTAsn1SetOfObjIdSeqs); + + +/** + * ASN.1 bit string (IPRT representation). + */ +typedef struct RTASN1BITSTRING +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** The number of bits. */ + uint32_t cBits; + /** The max number of bits (given at decoding / construction). */ + uint32_t cMaxBits; + /** Pointer to the bits. */ + RTCPTRUNION uBits; + /** Pointer to user structure encapsulated in this string, if dynamically + * allocated the EncapsulatedAllocation member can be used to track it and + * trigger automatic cleanup on object destruction. If EncapsulatedAllocation + * is zero, any object pointed to will only be deleted. */ + PRTASN1CORE pEncapsulated; + /** Allocation tracking structure for pEncapsulated. */ + RTASN1ALLOCATION EncapsulatedAllocation; +} RTASN1BITSTRING; +/** Pointer to the IPRT representation of an ASN.1 bit string. */ +typedef RTASN1BITSTRING *PRTASN1BITSTRING; +/** Pointer to the const IPRT representation of an ASN.1 bit string. */ +typedef RTASN1BITSTRING const *PCRTASN1BITSTRING; +/** The Vtable for a RTASN1BITSTRING structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1BitString_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1BITSTRING, RTDECL, RTAsn1BitString, Asn1Core); + +/** + * Calculates pointer to the first bit. + * + * @returns Byte pointer to the first bit. + * @param a_pBitString The ASN.1 bit string. + */ +#define RTASN1BITSTRING_GET_BIT0_PTR(a_pBitString) ( &(a_pBitString)->Asn1Core.uData.pu8[1] ) + +/** + * Calculates the size in bytes. + * + * @returns Rounded up size in bytes. + * @param a_pBitString The ASN.1 bit string. + */ +#define RTASN1BITSTRING_GET_BYTE_SIZE(a_pBitString) ( ((a_pBitString)->cBits + 7U) >> 3 ) + +RTDECL(int) RTAsn1BitString_InitWithData(PRTASN1BITSTRING pThis, void const *pvSrc, uint32_t cSrcBits, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1BitString_DecodeAsn1Ex(PRTASN1CURSOR pCursor, uint32_t fFlags, uint32_t cMaxBits, PRTASN1BITSTRING pThis, + const char *pszErrorTag); +RTDECL(uint64_t) RTAsn1BitString_GetAsUInt64(PCRTASN1BITSTRING pThis); +RTDECL(int) RTAsn1BitString_RefreshContent(PRTASN1BITSTRING pThis, uint32_t fFlags, + PCRTASN1ALLOCATORVTABLE pAllocator, PRTERRINFO pErrInfo); +RTDECL(bool) RTAsn1BitString_AreContentBitsValid(PCRTASN1BITSTRING pThis, uint32_t fFlags); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFBITSTRINGS, RTASN1BITSTRING, RTDECL, RTAsn1SeqOfBitStrings); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFBITSTRINGS, RTASN1BITSTRING, RTDECL, RTAsn1SetOfBitStrings); + + +/** + * ASN.1 octet string (IPRT representation). + */ +typedef struct RTASN1OCTETSTRING +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** Pointer to user structure encapsulated in this string. + * + * If dynamically allocated the EncapsulatedAllocation member can be used to + * track it and trigger automatic cleanup on object destruction. If + * EncapsulatedAllocation is zero, any object pointed to will only be + * deleted. */ + PRTASN1CORE pEncapsulated; + /** Allocation tracking structure for pEncapsulated. */ + RTASN1ALLOCATION EncapsulatedAllocation; +} RTASN1OCTETSTRING; +/** Pointer to the IPRT representation of an ASN.1 octet string. */ +typedef RTASN1OCTETSTRING *PRTASN1OCTETSTRING; +/** Pointer to the const IPRT representation of an ASN.1 octet string. */ +typedef RTASN1OCTETSTRING const *PCRTASN1OCTETSTRING; +/** The Vtable for a RTASN1OCTETSTRING structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1OctetString_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1OCTETSTRING, RTDECL, RTAsn1OctetString, Asn1Core); + +RTDECL(int) RTAsn1OctetString_AllocContent(PRTASN1OCTETSTRING pThis, void const *pvSrc, size_t cb, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1OctetString_SetContent(PRTASN1OCTETSTRING pThis, void const *pvSrc, size_t cbSrc, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(bool) RTAsn1OctetString_AreContentBytesValid(PCRTASN1OCTETSTRING pThis, uint32_t fFlags); +RTDECL(int) RTAsn1OctetString_RefreshContent(PRTASN1OCTETSTRING pThis, uint32_t fFlags, + PCRTASN1ALLOCATORVTABLE pAllocator, PRTERRINFO pErrInfo); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFOCTETSTRINGS, RTASN1OCTETSTRING, RTDECL, RTAsn1SeqOfOctetStrings); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFOCTETSTRINGS, RTASN1OCTETSTRING, RTDECL, RTAsn1SetOfOctetStrings); + + +/** + * ASN.1 string (IPRT representation). + * All char string types except 'character string (29)'. + */ +typedef struct RTASN1STRING +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** Allocation tracking for pszUtf8. */ + RTASN1ALLOCATION Allocation; + /** If conversion to UTF-8 was requested, we cache that here. */ + char const *pszUtf8; + /** The length (chars, not code points) of the above UTF-8 string if + * present. */ + uint32_t cchUtf8; +} RTASN1STRING; +/** Pointer to the IPRT representation of an ASN.1 string. */ +typedef RTASN1STRING *PRTASN1STRING; +/** Pointer to the const IPRT representation of an ASN.1 string. */ +typedef RTASN1STRING const *PCRTASN1STRING; +/** The Vtable for a RTASN1STRING structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1String_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1String, Asn1Core); + +/** @name String type predicate macros. + * @{ */ +#define RTASN1STRING_IS_NUMERIC(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_NUMERIC_STRING ) +#define RTASN1STRING_IS_PRINTABLE(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_PRINTABLE_STRING ) +#define RTASN1STRING_IS_T61(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_T61_STRING ) +#define RTASN1STRING_IS_VIDEOTEX(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_VIDEOTEX_STRING ) +#define RTASN1STRING_IS_VISIBLE(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_VISIBLE_STRING ) +#define RTASN1STRING_IS_IA5(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_IA5_STRING ) +#define RTASN1STRING_IS_GRAPHIC(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_GRAPHIC_STRING ) +#define RTASN1STRING_IS_GENERAL(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_GENERAL_STRING ) +/** UTF-8. */ +#define RTASN1STRING_IS_UTF8(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_UTF8_STRING ) +/** UCS-2. */ +#define RTASN1STRING_IS_BMP(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_BMP_STRING ) +/** UCS-4. */ +#define RTASN1STRING_IS_UNIVERSAL(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_UNIVERSAL_STRING ) +/** @} */ + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1NumericString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1PrintableString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1T61String, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1VideoTexString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1VisibleString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1Ia5String, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1GraphicString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1GeneralString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1Utf8String, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1BmpString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1UniversalString, Asn1Core); + +RTDECL(int) RTAsn1String_InitWithValue(PRTASN1STRING pThis, const char *pszUtf8Value, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1String_InitEx(PRTASN1STRING pThis, uint32_t uTag, void const *pvValue, size_t cbValue, + PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Compares two strings values, extended version. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeft The first string. + * @param pRight The second string. + * @param fTypeToo Set if the string types must match, false if + * not. + */ +RTDECL(int) RTAsn1String_CompareEx(PCRTASN1STRING pLeft, PCRTASN1STRING pRight, bool fTypeToo); +RTDECL(int) RTAsn1String_CompareValues(PCRTASN1STRING pLeft, PCRTASN1STRING pRight); + +/** + * Compares a ASN.1 string object with an UTF-8 string. + * + * @returns 0 if equal, -1 if @a pThis is smaller, 1 if @a pThis is larger. + * @param pThis The ASN.1 string object. + * @param pszString The UTF-8 string. + * @param cchString The length of @a pszString, or RTSTR_MAX. + */ +RTDECL(int) RTAsn1String_CompareWithString(PCRTASN1STRING pThis, const char *pszString, size_t cchString); + +/** + * Queries the UTF-8 length of an ASN.1 string object. + * + * This differs from RTAsn1String_QueryUtf8 in that it won't need to allocate + * memory for the converted string, but just calculates the length. + * + * @returns IPRT status code. + * @param pThis The ASN.1 string object. + * @param pcch Where to return the string length. + */ +RTDECL(int) RTAsn1String_QueryUtf8Len(PCRTASN1STRING pThis, size_t *pcch); + +/** + * Queries the UTF-8 string for an ASN.1 string object. + * + * This may fail as it may require memory to be allocated for storing the + * string. + * + * @returns IPRT status code. + * @param pString The ASN.1 string object. This is a const + * parameter for making life easier on the caller, + * however be aware that the object may be modified + * by this call! + * @param ppsz Where to return the pointer to the UTF-8 string. + * Optional. + * @param pcch Where to return the length (in 8-bit chars) to + * of the UTF-8 string. Optional. + */ +RTDECL(int) RTAsn1String_QueryUtf8(PCRTASN1STRING pString, const char **ppsz, size_t *pcch); +RTDECL(int) RTAsn1String_RecodeAsUtf8(PRTASN1STRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFSTRINGS, RTASN1STRING, RTDECL, RTAsn1SeqOfStrings); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFSTRINGS, RTASN1STRING, RTDECL, RTAsn1SetOfStrings); + + + +/** + * ASN.1 generic context specific tag (IPRT representation). + * + * Normally used to tag something that's optional, version specific or such. + * + * For the purpose of documenting the format with typedefs as well as possibly + * making it a little more type safe, there's a set of typedefs for the most + * commonly used tag values defined. These typedefs have are identical to + * RTASN1CONTEXTTAG, except from the C++ type system point of view. + */ +typedef struct RTASN1CONTEXTTAG +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1CONTEXTTAG; +/** Pointer to an ASN.1 context tag (IPRT thing). */ +typedef RTASN1CONTEXTTAG *PRTASN1CONTEXTTAG; +/** Pointer to a const ASN.1 context tag (IPRT thing). */ +typedef RTASN1CONTEXTTAG const *PCRTASN1CONTEXTTAG; + +RTDECL(int) RTAsn1ContextTagN_Init(PRTASN1CONTEXTTAG pThis, uint32_t uTag, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1ContextTagN_Clone(PRTASN1CONTEXTTAG pThis, PCRTASN1CONTEXTTAG pSrc, uint32_t uTag); + + +/** @internal */ +#define RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(a_uTag) \ + typedef struct RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) { RTASN1CORE Asn1Core; } RT_CONCAT(RTASN1CONTEXTTAG,a_uTag); \ + typedef RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) *RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag); \ + DECLINLINE(int) RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Init)(RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pThis, \ + PCRTASN1COREVTABLE pVtable, PCRTASN1ALLOCATORVTABLE pAllocator) \ + { \ + NOREF(pAllocator); \ + return RTAsn1ContextTagN_Init((PRTASN1CONTEXTTAG)pThis, a_uTag, pVtable); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Clone)(RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pThis, \ + RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) const *pSrc) \ + { return RTAsn1ContextTagN_Clone((PRTASN1CONTEXTTAG)pThis, (PCRTASN1CONTEXTTAG)pSrc, a_uTag); } \ + typedef RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) const *RT_CONCAT(PCRTASN1CONTEXTTAG,a_uTag) +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(0); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(1); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(2); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(3); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(4); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(5); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(6); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(7); +#undef RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE + +/** Helper for comparing optional context tags. + * This will return if both are not present or if their precense differs. + * @internal */ +#define RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, a_uTag) \ + do { \ + /* type checks */ \ + RT_CONCAT(PCRTASN1CONTEXTTAG,a_uTag) const pMyLeftInternal = (a_pLeft); \ + RT_CONCAT(PCRTASN1CONTEXTTAG,a_uTag) const pMyRightInternal = (a_pRight); \ + (a_iDiff) = (int)RTASN1CORE_IS_PRESENT(&pMyLeftInternal->Asn1Core) \ + - (int)RTASN1CORE_IS_PRESENT(&pMyRightInternal->Asn1Core); \ + if ((a_iDiff) || !RTASN1CORE_IS_PRESENT(&pMyLeftInternal->Asn1Core)) return iDiff; \ + } while (0) + +/** @name Helpers for comparing optional context tags. + * This will return if both are not present or if their precense differs. + * @{ */ +#define RTASN1CONTEXTTAG0_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 0) +#define RTASN1CONTEXTTAG1_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 1) +#define RTASN1CONTEXTTAG2_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 2) +#define RTASN1CONTEXTTAG3_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 3) +#define RTASN1CONTEXTTAG4_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 4) +#define RTASN1CONTEXTTAG5_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 5) +#define RTASN1CONTEXTTAG6_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 6) +#define RTASN1CONTEXTTAG7_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 7) +/** @} */ + + +/** + * Type information for dynamically bits (see RTASN1DYNTYPE). + */ +typedef enum RTASN1TYPE +{ + /** Not present. */ + RTASN1TYPE_NOT_PRESENT = 0, + /** Generic ASN.1 for unknown tag/class. */ + RTASN1TYPE_CORE, + /** ASN.1 NULL. */ + RTASN1TYPE_NULL, + /** ASN.1 integer. */ + RTASN1TYPE_INTEGER, + /** ASN.1 boolean. */ + RTASN1TYPE_BOOLEAN, + /** ASN.1 character string. */ + RTASN1TYPE_STRING, + /** ASN.1 octet string. */ + RTASN1TYPE_OCTET_STRING, + /** ASN.1 bite string. */ + RTASN1TYPE_BIT_STRING, + /** ASN.1 UTC or Generalize time. */ + RTASN1TYPE_TIME, +#if 0 + /** ASN.1 sequence core. */ + RTASN1TYPE_SEQUENCE_CORE, + /** ASN.1 set core. */ + RTASN1TYPE_SET_CORE, +#endif + /** ASN.1 object identifier. */ + RTASN1TYPE_OBJID, + /** End of valid types. */ + RTASN1TYPE_END, + /** Type size hack. */ + RTASN1TYPE_32BIT_HACK = 0x7fffffff +} RTASN1TYPE; + + +/** + * ASN.1 dynamic type record. + */ +typedef struct RTASN1DYNTYPE +{ + /** Alternative interpretation provided by a user. + * Before destroying this object, the user must explicitly free this and set + * it to NULL, otherwise there will be memory leaks. */ + PRTASN1CORE pUser; + /** The type of data we've got here. */ + RTASN1TYPE enmType; + /** Union with data of the type dictated by enmType. */ + union + { + /** RTASN1TYPE_CORE. */ + RTASN1CORE Core; + /** RTASN1TYPE_NULL. */ + RTASN1NULL Asn1Null; + /** RTASN1TYPE_INTEGER. */ + RTASN1INTEGER Integer; + /** RTASN1TYPE_BOOLEAN. */ + RTASN1BOOLEAN Boolean; + /** RTASN1TYPE_STRING. */ + RTASN1STRING String; + /** RTASN1TYPE_OCTET_STRING. */ + RTASN1OCTETSTRING OctetString; + /** RTASN1TYPE_BIT_STRING. */ + RTASN1BITSTRING BitString; + /** RTASN1TYPE_TIME. */ + RTASN1TIME Time; +#if 0 + /** RTASN1TYPE_SEQUENCE_CORE. */ + RTASN1SEQUENCECORE SeqCore; + /** RTASN1TYPE_SET_CORE. */ + RTASN1SETCORE SetCore; +#endif + /** RTASN1TYPE_OBJID. */ + RTASN1OBJID ObjId; + } u; +} RTASN1DYNTYPE; +/** Pointer to an ASN.1 dynamic type record. */ +typedef RTASN1DYNTYPE *PRTASN1DYNTYPE; +/** Pointer to a const ASN.1 dynamic type record. */ +typedef RTASN1DYNTYPE const *PCRTASN1DYNTYPE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1DYNTYPE, RTDECL, RTAsn1DynType, u.Core); +RTDECL(int) RTAsn1DynType_SetToNull(PRTASN1DYNTYPE pThis); + + +/** @name Virtual Method Table Based API + * @{ */ +/** + * Calls the destructor of the ASN.1 object. + * + * @param pThisCore The IPRT representation of an ASN.1 object. + */ +RTDECL(void) RTAsn1VtDelete(PRTASN1CORE pThisCore); + +/** + * Deep enumeration of all descendants. + * + * @returns IPRT status code, any non VINF_SUCCESS value stems from pfnCallback. + * @param pThisCore Pointer to the ASN.1 core to enumerate members of. + * @param pfnCallback The callback. + * @param uDepth The depth of this object. Children are at +1. + * @param pvUser Callback user argument. + * @param fDepthFirst When set, recurse into child objects before calling + * pfnCallback on then. When clear, the child object + * is first + */ +RTDECL(int) RTAsn1VtDeepEnum(PRTASN1CORE pThisCore, bool fDepthFirst, uint32_t uDepth, + PFNRTASN1ENUMCALLBACK pfnCallback, void *pvUser); + +/** + * Clones @a pSrcCore onto @a pThisCore. + * + * The caller must be sure that @a pSrcCore and @a pThisCore are of the same + * types. + * + * @returns IPRT status code. + * @param pThisCore Pointer to the ASN.1 core to clone onto. This shall + * be uninitialized. + * @param pSrcCore Pointer to the ASN.1 core to clone. + * @param pAllocator The allocator to use. + */ +RTDECL(int) RTAsn1VtClone(PRTASN1CORE pThisCore, PRTASN1CORE pSrcCore, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Compares two objects. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeftCore Pointer to the ASN.1 core of the left side object. + * @param pRightCore Pointer to the ASN.1 core of the right side object. + */ +RTDECL(int) RTAsn1VtCompare(PCRTASN1CORE pLeftCore, PCRTASN1CORE pRightCore); + +/** + * Check sanity. + * + * A primary criteria is that the object is present and initialized. + * + * @returns IPRT status code. + * @param pThisCore Pointer to the ASN.1 core of the object to check out. + * @param fFlags See RTASN1_CHECK_SANITY_F_XXX. + * @param pErrInfo Where to return additional error details. Optional. + * @param pszErrorTag Tag for the additional error details. + */ +RTDECL(int) RTAsn1VtCheckSanity(PCRTASN1CORE pThisCore, uint32_t fFlags, + PRTERRINFO pErrInfo, const char *pszErrorTag); +/** @} */ + + +/** @defgroup rp_asn1_encode RTAsn1Encode - ASN.1 Encoding + * @{ */ + +/** @name RTASN1ENCODE_F_XXX + * @{ */ +/** Use distinguished encoding rules (DER) to encode the object. */ +#define RTASN1ENCODE_F_DER UINT32_C(0x00000001) +/** Use base encoding rules (BER) to encode the object. + * This is currently the same as DER for practical reasons. */ +#define RTASN1ENCODE_F_BER RTASN1ENCODE_F_DER +/** Mask of valid encoding rules. */ +#define RTASN1ENCODE_F_RULE_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * Recalculates cbHdr of and ASN.1 object. + * + * @returns IPRT status code. + * @retval VINF_ASN1_NOT_ENCODED if the header size is zero (default value, + * whatever). + * @param pAsn1Core The object in question. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pErrInfo Extended error info. Optional. + */ +RTDECL(int) RTAsn1EncodeRecalcHdrSize(PRTASN1CORE pAsn1Core, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Prepares the ASN.1 structure for encoding. + * + * The preparations is mainly calculating accurate object size, but may also + * involve operations like recoding internal UTF-8 strings to the actual ASN.1 + * format and other things that may require memory to allocated/reallocated. + * + * @returns IPRT status code + * @param pRoot The root of the ASN.1 object tree to encode. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pcbEncoded Where to return the encoded size. Optional. + * @param pErrInfo Where to store extended error information. + * Optional. + */ +RTDECL(int) RTAsn1EncodePrepare(PRTASN1CORE pRoot, uint32_t fFlags, uint32_t *pcbEncoded, PRTERRINFO pErrInfo); + +/** + * Encodes and writes the header of an ASN.1 object. + * + * @returns IPRT status code. + * @retval VINF_ASN1_NOT_ENCODED if nothing was written (default value, + * whatever). + * @param pAsn1Core The object in question. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pfnWriter The output writer callback. + * @param pvUser The user argument to pass to @a pfnWriter. + * @param pErrInfo Where to store extended error information. + * Optional. + */ +RTDECL(int) RTAsn1EncodeWriteHeader(PCRTASN1CORE pAsn1Core, uint32_t fFlags, FNRTASN1ENCODEWRITER pfnWriter, void *pvUser, + PRTERRINFO pErrInfo); + +/** + * Encodes and writes an ASN.1 object. + * + * @returns IPRT status code + * @param pRoot The root of the ASN.1 object tree to encode. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pfnWriter The output writer callback. + * @param pvUser The user argument to pass to @a pfnWriter. + * @param pErrInfo Where to store extended error information. + * Optional. + */ +RTDECL(int) RTAsn1EncodeWrite(PCRTASN1CORE pRoot, uint32_t fFlags, FNRTASN1ENCODEWRITER pfnWriter, void *pvUser, + PRTERRINFO pErrInfo); + +/** + * Encodes and writes an ASN.1 object into a caller allocated memory buffer. + * + * @returns IPRT status code + * @param pRoot The root of the ASN.1 object tree to encode. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pvBuf The output buffer. + * @param cbBuf The buffer size. This should have the size + * returned by RTAsn1EncodePrepare(). + * @param pErrInfo Where to store extended error information. + * Optional. + */ +RTDECL(int) RTAsn1EncodeToBuffer(PCRTASN1CORE pRoot, uint32_t fFlags, void *pvBuf, size_t cbBuf, PRTERRINFO pErrInfo); + +/** + * Helper for when DER encoded ASN.1 is needed for something. + * + * Handy when interfacing with OpenSSL and the many d2i_Xxxxx OpenSSL functions, + * but also handy when structures needs to be digested or similar during signing + * or verification. + * + * We sometimes can use the data we've decoded directly, but often we have + * encode it into a temporary heap buffer. + * + * @returns IPRT status code, details in @a pErrInfo if present. + * @param pRoot The ASN.1 root of the structure to be passed to OpenSSL. + * @param ppbRaw Where to return the pointer to raw encoded data. + * @param pcbRaw Where to return the size of the raw encoded data. + * @param ppvFree Where to return what to pass to RTMemTmpFree, i.e. NULL + * if we use the previously decoded data directly and + * non-NULL if we had to allocate heap and encode it. + * @param pErrInfo Where to return details about encoding issues. Optional. + */ +RTDECL(int) RTAsn1EncodeQueryRawBits(PRTASN1CORE pRoot, const uint8_t **ppbRaw, uint32_t *pcbRaw, + void **ppvFree, PRTERRINFO pErrInfo); + +/** @} */ + + + +/** @defgroup rp_asn1_cursor RTAsn1Cursor - BER, DER, and CER cursor + * @{ */ + +/** + * ASN.1 decoder byte cursor. + */ +typedef struct RTASN1CURSOR +{ + /** Pointer to the current (next) byte. */ + uint8_t const *pbCur; + /** Number of bytes left to decode. */ + uint32_t cbLeft; + /** RTASN1CURSOR_FLAGS_XXX. */ + uint8_t fFlags; + /** The cursor depth. */ + uint8_t cDepth; + /** Two bytes reserved for future tricks. */ + uint8_t abReserved[2]; + /** Pointer to the primary cursor. */ + struct RTASN1CURSORPRIMARY *pPrimary; + /** Pointer to the parent cursor. */ + struct RTASN1CURSOR *pUp; + /** The error tag for this cursor level. */ + const char *pszErrorTag; +} RTASN1CURSOR; + +/** @name RTASN1CURSOR_FLAGS_XXX - Cursor flags. + * @{ */ +/** Enforce DER rules. */ +#define RTASN1CURSOR_FLAGS_DER RT_BIT(1) +/** Enforce CER rules. */ +#define RTASN1CURSOR_FLAGS_CER RT_BIT(2) +/** Pending indefinite length encoding. */ +#define RTASN1CURSOR_FLAGS_INDEFINITE_LENGTH RT_BIT(3) +/** @} */ + + +typedef struct RTASN1CURSORPRIMARY +{ + /** The normal cursor bits. */ + RTASN1CURSOR Cursor; + /** For error reporting. */ + PRTERRINFO pErrInfo; + /** The allocator virtual method table. */ + PCRTASN1ALLOCATORVTABLE pAllocator; + /** Pointer to the first byte. Useful for calculating offsets. */ + uint8_t const *pbFirst; +} RTASN1CURSORPRIMARY; +typedef RTASN1CURSORPRIMARY *PRTASN1CURSORPRIMARY; + + +/** + * Initializes a primary cursor. + * + * The primary cursor is special in that it stores information shared with the + * sub-cursors created by methods like RTAsn1CursorGetContextTagNCursor and + * RTAsn1CursorGetSequenceCursor. Even if just sharing a few items at present, + * it still important to save every possible byte since stack space is scarce in + * some of the execution environments. + * + * @returns Pointer to pCursor->Cursor. + * @param pPrimaryCursor The primary cursor structure to initialize. + * @param pvFirst The first byte to decode. + * @param cb The number of bytes to decode. + * @param pErrInfo Where to store error information. + * @param pAllocator The allocator to use. + * @param fFlags RTASN1CURSOR_FLAGS_XXX. + * @param pszErrorTag The primary error tag. + */ +RTDECL(PRTASN1CURSOR) RTAsn1CursorInitPrimary(PRTASN1CURSORPRIMARY pPrimaryCursor, void const *pvFirst, uint32_t cb, + PRTERRINFO pErrInfo, PCRTASN1ALLOCATORVTABLE pAllocator, uint32_t fFlags, + const char *pszErrorTag); + +RTDECL(int) RTAsn1CursorInitSub(PRTASN1CURSOR pParent, uint32_t cb, PRTASN1CURSOR pChild, const char *pszErrorTag); + +/** + * Initialize a sub-cursor for traversing the content of an ASN.1 object. + * + * @returns IPRT status code. + * @param pParent The parent cursor. + * @param pAsn1Core The ASN.1 object which content we should + * traverse with the sub-cursor. + * @param pChild The sub-cursor to initialize. + * @param pszErrorTag The error tag of the sub-cursor. + */ +RTDECL(int) RTAsn1CursorInitSubFromCore(PRTASN1CURSOR pParent, PRTASN1CORE pAsn1Core, + PRTASN1CURSOR pChild, const char *pszErrorTag); + +/** + * Initalizes the an allocation structure prior to making an allocation. + * + * To try unify and optimize memory managment for decoding and in-memory + * construction of ASN.1 objects, each allocation has an allocation structure + * associated with it. This stores the allocator and keep statistics for + * optimizing resizable allocations. + * + * @returns Pointer to the allocator info (for call in alloc parameter). + * @param pCursor The cursor. + * @param pAllocation The allocation structure to initialize. + */ +RTDECL(PRTASN1ALLOCATION) RTAsn1CursorInitAllocation(PRTASN1CURSOR pCursor, PRTASN1ALLOCATION pAllocation); + +/** + * Initalizes the an array allocation structure prior to making an allocation. + * + * This is a special case of RTAsn1CursorInitAllocation. We store a little bit + * more detail here in order to optimize growing and shrinking of arrays. + * + * @returns Pointer to the allocator info (for call in alloc parameter). + * @param pCursor The cursor. + * @param pAllocation The allocation structure to initialize. + * @param cbEntry The array entry size. + */ +RTDECL(PRTASN1ARRAYALLOCATION) RTAsn1CursorInitArrayAllocation(PRTASN1CURSOR pCursor, PRTASN1ARRAYALLOCATION pAllocation, + size_t cbEntry); + +/** + * Wrapper around RTErrInfoSetV. + * + * @returns @a rc + * @param pCursor The cursor. + * @param rc The return code to return. + * @param pszMsg Message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTAsn1CursorSetInfo(PRTASN1CURSOR pCursor, int rc, const char *pszMsg, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Wrapper around RTErrInfoSetV. + * + * @returns @a rc + * @param pCursor The cursor. + * @param rc The return code to return. + * @param pszMsg Message format string. + * @param va Format arguments. + */ +RTDECL(int) RTAsn1CursorSetInfoV(PRTASN1CURSOR pCursor, int rc, const char *pszMsg, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Checks that we've reached the end of the data for the cursor. + * + * This differs from RTAsn1CursorCheckEnd in that it does not consider the end + * an error and therefore leaves the error buffer alone. + * + * @returns True if end, otherwise false. + * @param pCursor The cursor we're decoding from. + */ +RTDECL(bool) RTAsn1CursorIsEnd(PRTASN1CURSOR pCursor); + +/** + * Checks that we've reached the end of the data for the cursor. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + */ +RTDECL(int) RTAsn1CursorCheckEnd(PRTASN1CURSOR pCursor); + +/** + * Specialization of RTAsn1CursorCheckEnd for handling indefinite length sequences. + * + * Makes sure we've reached the end of the data for the cursor, and in case of a + * an indefinite length sequence it may adjust sequence length and the parent + * cursor. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param pSeqCore The sequence core record. + * @sa RTAsn1CursorCheckSetEnd, RTAsn1CursorCheckOctStrEnd, + * RTAsn1CursorCheckEnd + */ +RTDECL(int) RTAsn1CursorCheckSeqEnd(PRTASN1CURSOR pCursor, PRTASN1SEQUENCECORE pSeqCore); + +/** + * Specialization of RTAsn1CursorCheckEnd for handling indefinite length sets. + * + * Makes sure we've reached the end of the data for the cursor, and in case of a + * an indefinite length sets it may adjust set length and the parent cursor. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param pSetCore The set core record. + * @sa RTAsn1CursorCheckSeqEnd, RTAsn1CursorCheckOctStrEnd, + * RTAsn1CursorCheckEnd + */ +RTDECL(int) RTAsn1CursorCheckSetEnd(PRTASN1CURSOR pCursor, PRTASN1SETCORE pSetCore); + +/** + * Specialization of RTAsn1CursorCheckEnd for handling indefinite length + * constructed octet strings. + * + * This function must used when parsing the content of an octet string, like + * for example the Content of a PKCS\#7 ContentInfo structure. It makes sure + * we've reached the end of the data for the cursor, and in case of a an + * indefinite length sets it may adjust set length and the parent cursor. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param pOctetString The octet string. + * @sa RTAsn1CursorCheckSeqEnd, RTAsn1CursorCheckSetEnd, + * RTAsn1CursorCheckEnd + */ +RTDECL(int) RTAsn1CursorCheckOctStrEnd(PRTASN1CURSOR pCursor, PRTASN1OCTETSTRING pOctetString); + + +/** + * Skips a given number of bytes. + * + * @returns @a pCursor + * @param pCursor The cursor. + * @param cb The number of bytes to skip. + * @internal + */ +DECLINLINE(PRTASN1CURSOR) RTAsn1CursorSkip(PRTASN1CURSOR pCursor, uint32_t cb) +{ + if (cb <= pCursor->cbLeft) + { + pCursor->cbLeft -= cb; + pCursor->pbCur += cb; + } + else + { + pCursor->pbCur += pCursor->cbLeft; + pCursor->cbLeft = 0; + } + + return pCursor; +} + +/** + * Low-level function for reading an ASN.1 header. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param pAsn1Core The output object core. + * @param pszErrorTag Error tag. + * @internal + */ +RTDECL(int) RTAsn1CursorReadHdr(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core, const char *pszErrorTag); + +/** + * Common helper for simple tag matching. + * + * @returns IPRT status code. + * @param pCursor The cursor (for error reporting). + * @param pAsn1Core The ASN.1 core structure. + * @param uTag The expected tag. + * @param fClass The expected class. + * @param fString Set if it's a string type that shall follow + * special CER and DER rules wrt to constructed and + * primitive encoding. + * @param fFlags The RTASN1CURSOR_GET_F_XXX flags. + * @param pszErrorTag The error tag. + * @param pszWhat The type/whatever name. + */ +RTDECL(int) RTAsn1CursorMatchTagClassFlagsEx(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core, uint32_t uTag, uint32_t fClass, + bool fString, uint32_t fFlags, const char *pszErrorTag, const char *pszWhat); + +/** + * Common helper for simple tag matching. + * + * @returns IPRT status code. + * @param pCursor The cursor (for error reporting). + * @param pAsn1Core The ASN.1 core structure. + * @param uTag The expected tag. + * @param fClass The expected class. + * @param fFlags The RTASN1CURSOR_GET_F_XXX flags. + * @param pszErrorTag The error tag. + * @param pszWhat The type/whatever name. + * @internal + */ +DECLINLINE(int) RTAsn1CursorMatchTagClassFlags(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core, uint32_t uTag, uint32_t fClass, + uint32_t fFlags, const char *pszErrorTag, const char *pszWhat) +{ + if (pAsn1Core->uTag == uTag && pAsn1Core->fClass == fClass) + return VINF_SUCCESS; + return RTAsn1CursorMatchTagClassFlagsEx(pCursor, pAsn1Core, uTag, fClass, false /*fString*/, fFlags, pszErrorTag, pszWhat); +} + + +/** + * Common helper for simple tag matching for strings. + * + * Check string encoding considerations. + * + * @returns IPRT status code. + * @param pCursor The cursor (for error reporting). + * @param pAsn1Core The ASN.1 core structure. + * @param uTag The expected tag. + * @param fClass The expected class. + * @param fFlags The RTASN1CURSOR_GET_F_XXX flags. + * @param pszErrorTag The error tag. + * @param pszWhat The type/whatever name. + * @internal + */ +DECLINLINE(int) RTAsn1CursorMatchTagClassFlagsString(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core, uint32_t uTag, uint32_t fClass, + uint32_t fFlags, const char *pszErrorTag, const char *pszWhat) +{ + if (pAsn1Core->uTag == uTag && pAsn1Core->fClass == fClass) + return VINF_SUCCESS; + return RTAsn1CursorMatchTagClassFlagsEx(pCursor, pAsn1Core, uTag, fClass, true /*fString*/, fFlags, pszErrorTag, pszWhat); +} + + + +/** @name RTASN1CURSOR_GET_F_XXX - Common flags for all the getters. + * @{ */ +/** Used for decoding objects with implicit tags assigned to them. This only + * works when calling getters with a unambigious types. */ +#define RTASN1CURSOR_GET_F_IMPLICIT RT_BIT_32(0) +/** @} */ + +/** + * Read ANY object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pAsn1Core The output object core. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetCore(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1CORE pAsn1Core, const char *pszErrorTag); + +/** + * Read a NULL object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pNull The output NULL object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetNull(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1NULL pNull, const char *pszErrorTag); + +/** + * Read an INTEGER object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pInteger The output integer object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetInteger(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1INTEGER pInteger, const char *pszErrorTag); + +/** + * Read an BOOLEAN object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pBoolean The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetBoolean(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1BOOLEAN pBoolean, const char *pszErrorTag); + +/** + * Retrives an object identifier (aka ObjId or OID) item from the ASN.1 stream. + * + * @returns IPRT status code. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pObjId The output ODI object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetObjId(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1OBJID pObjId, const char *pszErrorTag); + +/** + * Retrives and verifies an object identifier. + * + * @returns IPRT status code. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pObjId Where to return the parsed object ID, optional. + * @param pszExpectedObjId The expected object identifier (dotted). + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetAndCheckObjId(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1OBJID pObjId, + const char *pszExpectedObjId, const char *pszErrorTag); + +/** + * Read an UTC TIME or GENERALIZED TIME object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pTime The output time object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetTime(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1TIME pTime, const char *pszErrorTag); + +/** + * Read an BIT STRING object (skips past the content). + * + * @returns IPRT status ocde. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pBitString The output bit string object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetBitString(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1BITSTRING pBitString, + const char *pszErrorTag); + +/** + * Read an BIT STRING object (skips past the content), extended version with + * cMaxBits. + * + * @returns IPRT status ocde. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param cMaxBits The max length of the bit string in bits. Pass + * UINT32_MAX if variable size. + * @param pBitString The output bit string object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetBitStringEx(PRTASN1CURSOR pCursor, uint32_t fFlags, uint32_t cMaxBits, PRTASN1BITSTRING pBitString, + const char *pszErrorTag); + +/** + * Read an OCTET STRING object (skips past the content). + * + * @returns IPRT status ocde. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pOctetString The output octet string object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetOctetString(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1OCTETSTRING pOctetString, + const char *pszErrorTag); + +/** + * Read any kind of string object, except 'character string (29)'. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pString The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetString(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1STRING pString, const char *pszErrorTag); + +/** + * Read a IA5 STRING object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pString The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetIa5String(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1STRING pString, const char *pszErrorTag); + +/** + * Read a UTF8 STRING object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pString The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetUtf8String(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1STRING pString, const char *pszErrorTag); + +/** + * Read a BMP STRING (UCS-2) object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pString The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetBmpString(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1STRING pString, const char *pszErrorTag); + +/** + * Read a SEQUENCE object and create a cursor for its content. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pSeqCore The output sequence core object. + * @param pSeqCursor The output cursor for the sequence content. + * @param pszErrorTag Error tag, this will be associated with the + * returned cursor. + */ +RTDECL(int) RTAsn1CursorGetSequenceCursor(PRTASN1CURSOR pCursor, uint32_t fFlags, + PRTASN1SEQUENCECORE pSeqCore, PRTASN1CURSOR pSeqCursor, const char *pszErrorTag); + +/** + * Read a SET object and create a cursor for its content. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pSetCore The output set core object. + * @param pSetCursor The output cursor for the set content. + * @param pszErrorTag Error tag, this will be associated with the + * returned cursor. + */ +RTDECL(int) RTAsn1CursorGetSetCursor(PRTASN1CURSOR pCursor, uint32_t fFlags, + PRTASN1SETCORE pSetCore, PRTASN1CURSOR pSetCursor, const char *pszErrorTag); + +/** + * Read a given constructed context tag and create a cursor for its content. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param uExpectedTag The expected tag. + * @param pVtable The vtable for the context tag node (see + * RTASN1TMPL_PASS_XTAG). + * @param pCtxTag The output context tag object. + * @param pCtxTagCursor The output cursor for the context tag content. + * @param pszErrorTag Error tag, this will be associated with the + * returned cursor. + * + * @remarks There are specialized version of this function for each of the + * numbered context tag structures, like for RTASN1CONTEXTTAG0 there is + * RTAsn1CursorGetContextTag0Cursor. + */ +RTDECL(int) RTAsn1CursorGetContextTagNCursor(PRTASN1CURSOR pCursor, uint32_t fFlags, uint32_t uExpectedTag, + PCRTASN1COREVTABLE pVtable, PRTASN1CONTEXTTAG pCtxTag, PRTASN1CURSOR pCtxTagCursor, + const char *pszErrorTag); + +/** + * Read a dynamic ASN.1 type. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pDynType The output context tag object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetDynType(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1DYNTYPE pDynType, const char *pszErrorTag); + +/** + * Peeks at the next ASN.1 object. + * + * @returns IPRT status code. + * @param pCursor The cursore we're decoding from. + * @param pAsn1Core Where to store the output of the peek. + */ +RTDECL(int) RTAsn1CursorPeek(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core); + +/** + * Checks if the next ASN.1 object matches the given tag and class/flags. + * + * @returns @c true on match, @c false on mismatch. + * @param pCursor The cursore we're decoding from. + * @param uTag The tag number to match against. + * @param fClass The tag class and flags to match against. + */ +RTDECL(bool) RTAsn1CursorIsNextEx(PRTASN1CURSOR pCursor, uint32_t uTag, uint8_t fClass); + + + +/** @internal */ +#define RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(a_uTag) \ + DECLINLINE(int) RT_CONCAT3(RTAsn1CursorGetContextTag,a_uTag,Cursor)(PRTASN1CURSOR pCursor, uint32_t fFlags, \ + PCRTASN1COREVTABLE pVtable, \ + RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pCtxTag, \ + PRTASN1CURSOR pCtxTagCursor, const char *pszErrorTag) \ + { /* Constructed is automatically implied if you need a cursor to it. */ \ + return RTAsn1CursorGetContextTagNCursor(pCursor, fFlags, a_uTag, pVtable, (PRTASN1CONTEXTTAG)pCtxTag, pCtxTagCursor, pszErrorTag); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1ContextTag,a_uTag,InitDefault)(RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pCtxTag) \ + { /* Constructed is automatically implied if you need to init it with a default value. */ \ + return RTAsn1Core_InitDefault(&pCtxTag->Asn1Core, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1CursorIsConstructedContextTag,a_uTag,Next)(PRTASN1CURSOR pCursor) \ + { \ + return RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1CursorIsPrimitiveContextTag,a_uTag,Next)(PRTASN1CURSOR pCursor) \ + { \ + return RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_PRIMITIVE); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1CursorIsAnyContextTag,a_uTag,Next)(PRTASN1CURSOR pCursor) \ + { \ + return RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED) \ + || RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_PRIMITIVE);\ + } \ + +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(0) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(1) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(2) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(3) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(4) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(5) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(6) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(7) +#undef RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES + + +/** + * Checks if the next object is a boolean. + * + * @returns true / false + * @param pCursor The cursor we're decoding from. + * @remarks May produce error info output on mismatch. + */ +DECLINLINE(bool) RTAsn1CursorIsBooleanNext(PRTASN1CURSOR pCursor) +{ + return RTAsn1CursorIsNextEx(pCursor, ASN1_TAG_BOOLEAN, ASN1_TAGFLAG_PRIMITIVE | ASN1_TAGCLASS_UNIVERSAL); +} + + +/** + * Checks if the next object is a set. + * + * @returns true / false + * @param pCursor The cursor we're decoding from. + * @remarks May produce error info output on mismatch. + */ +DECLINLINE(bool) RTAsn1CursorIsSetNext(PRTASN1CURSOR pCursor) +{ + return RTAsn1CursorIsNextEx(pCursor, ASN1_TAG_SET, ASN1_TAGFLAG_CONSTRUCTED | ASN1_TAGCLASS_UNIVERSAL); +} + + +/** @} */ + + +/** @name ASN.1 Utility APIs + * @{ */ + +/** + * Dumps an IPRT representation of a ASN.1 object tree. + * + * @returns IPRT status code. + * @param pAsn1Core The ASN.1 object which members should be dumped. + * @param fFlags RTASN1DUMP_F_XXX. + * @param uLevel The indentation level to start at. + * @param pfnPrintfV The output function. + * @param pvUser Argument to the output function. + */ +RTDECL(int) RTAsn1Dump(PCRTASN1CORE pAsn1Core, uint32_t fFlags, uint32_t uLevel, PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser); + +/** + * Queries the name for an object identifier. + * + * This API is very simple due to how we store the data. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if not found. + * @retval VERR_BUFFER_OVERFLOW if more buffer space is required. + * + * @param pObjId The object ID to name. + * @param pszDst Where to store the name if found. + * @param cbDst The size of the destination buffer. + */ +RTDECL(int) RTAsn1QueryObjIdName(PCRTASN1OBJID pObjId, char *pszDst, size_t cbDst); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_asn1_h */ + diff --git a/include/iprt/assert.h b/include/iprt/assert.h new file mode 100644 index 00000000..6d0087ee --- /dev/null +++ b/include/iprt/assert.h @@ -0,0 +1,2893 @@ +/** @file + * IPRT - Assertions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_assert_h +#define IPRT_INCLUDED_assert_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +/** @defgroup grp_rt_assert Assert - Assertions + * @ingroup grp_rt + * + * Assertions are generally used to check preconditions and other + * assumptions. Sometimes it is also used to catch odd errors or errors + * that one would like to inspect in the debugger. They should not be + * used for errors that happen frequently. + * + * IPRT provides a host of assertion macros, so many that it can be a bit + * overwhelming at first. Don't despair, there is a system (surprise). + * + * First there are four families of assertions: + * - Assert - The normal strict build only assertions. + * - AssertLogRel - Calls LogRel() in non-strict builds, otherwise like Assert. + * - AssertRelease - Triggers in all builds. + * - AssertFatal - Triggers in all builds and cannot be continued. + * + * Then there are variations wrt to argument list and behavior on failure: + * - Msg - Custom RTStrPrintf-like message with the assertion message. + * - Return - Return the specific rc on failure. + * - ReturnVoid - Return (void) on failure. + * - Break - Break (out of switch/loop) on failure. + * - Stmt - Execute the specified statement(s) on failure. + * - RC - Assert RT_SUCCESS. + * - RCSuccess - Assert VINF_SUCCESS. + * + * @remarks As you might have noticed, the macros don't follow the + * coding guidelines wrt to macros supposedly being all uppercase + * and underscored. For various reasons they don't, and nobody + * has complained yet. Wonder why... :-) + * + * @remarks Each project has its own specific guidelines on how to use + * assertions, so the above is just trying to give you the general idea + * from the IPRT point of view. + * + * @{ + */ + +RT_C_DECLS_BEGIN + +#if !defined(IPRT_WITHOUT_ASSERT_STACK) \ + && defined(IN_RING3) \ + && !defined(IN_RT_STATIC) /* try keep static binaries small */ \ + && (defined(RT_ARCH_AMD64) /*|| defined(RT_ARCH_X86)*/) +/** @def IPRT_WITH_ASSERT_STACK + * Indicates that we collect a callstack stack on assertion. */ +# define IPRT_WITH_ASSERT_STACK +#endif + +/** + * The 1st part of an assert message. + * + * @param pszExpr Expression. Can be NULL. + * @param uLine Location line number. + * @param pszFile Location file name. + * @param pszFunction Location function name. + */ +RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction); +/** + * Weak version of RTAssertMsg1 that can be overridden locally in a module to + * modify, redirect or otherwise mess with the assertion output. + * + * @copydoc RTAssertMsg1 + */ +RTDECL(void) RTAssertMsg1Weak(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction); + +/** + * The 2nd (optional) part of an assert message. + * + * @param pszFormat Printf like format string. + * @param ... Arguments to that string. + */ +RTDECL(void) RTAssertMsg2(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); +/** + * Weak version of RTAssertMsg2 that forwards to RTAssertMsg2WeakV. + * + * There is not need to override this, check out RTAssertMsg2WeakV instead! + * + * @copydoc RTAssertMsg2 + */ +RTDECL(void) RTAssertMsg2Weak(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * The 2nd (optional) part of an assert message. + * + * @param pszFormat Printf like format string. + * @param va Arguments to that string. + */ +RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); +/** + * Weak version of RTAssertMsg2V that can be overridden locally in a module to + * modify, redirect or otherwise mess with the assertion output. + * + * @copydoc RTAssertMsg2V + */ +RTDECL(void) RTAssertMsg2WeakV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Additional information which should be appended to the 2nd part of an + * assertion message. + * + * @param pszFormat Printf like format string. + * @param ... Arguments to that string. + */ +RTDECL(void) RTAssertMsg2Add(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); +/** + * Weak version of RTAssertMsg2Add that forwards to RTAssertMsg2AddWeakV. + * + * There is not need to override this, check out RTAssertMsg2AddWeakV instead! + * + * @copydoc RTAssertMsg2Add + */ +RTDECL(void) RTAssertMsg2AddWeak(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Additional information which should be appended to the 2nd part of an + * assertion message. + * + * @param pszFormat Printf like format string. + * @param va Arguments to that string. + */ +RTDECL(void) RTAssertMsg2AddV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); +/** + * Weak version of RTAssertMsg2AddV that can be overridden locally in a module + * to modify, redirect or otherwise mess with the assertion output. + * + * @copydoc RTAssertMsg2AddV + */ +RTDECL(void) RTAssertMsg2AddWeakV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +#ifdef IN_RING0 +/** + * Panics the system as the result of a fail assertion. + */ +RTR0DECL(void) RTR0AssertPanicSystem(void); +#endif /* IN_RING0 */ + +/** + * Overridable function that decides whether assertions executes the panic + * (breakpoint) or not. + * + * The generic implementation will return true. + * + * @returns true if the breakpoint should be hit, false if it should be ignored. + * + * @remark The RTDECL() makes this a bit difficult to override on Windows. So, + * you'll have to use RTASSERT_HAVE_SHOULD_PANIC or + * RTASSERT_HAVE_SHOULD_PANIC_PRIVATE there to control the kind of + * prototype. + */ +#if !defined(RTASSERT_HAVE_SHOULD_PANIC) && !defined(RTASSERT_HAVE_SHOULD_PANIC_PRIVATE) +RTDECL(bool) RTAssertShouldPanic(void); +#elif defined(RTASSERT_HAVE_SHOULD_PANIC_PRIVATE) +bool RTAssertShouldPanic(void); +#else +DECLEXPORT(bool) RTCALL RTAssertShouldPanic(void); +#endif + +/** + * Controls whether the assertions should be quiet or noisy (default). + * + * @returns The old setting. + * @param fQuiet The new setting. + */ +RTDECL(bool) RTAssertSetQuiet(bool fQuiet); + +/** + * Are assertions quiet or noisy? + * + * @returns True if they are quiet, false if noisy. + */ +RTDECL(bool) RTAssertAreQuiet(void); + +/** + * Makes the assertions panic (default) or not. + * + * @returns The old setting. + * @param fPanic The new setting. + */ +RTDECL(bool) RTAssertSetMayPanic(bool fPanic); + +/** + * Can assertion panic. + * + * @returns True if they can, false if not. + */ +RTDECL(bool) RTAssertMayPanic(void); + + +/** @name Globals for crash analysis + * @remarks This is the full potential set, it + * @{ + */ +/** The last assertion message, 1st part. */ +extern RTDATADECL(char) g_szRTAssertMsg1[1024]; +/** The last assertion message, 2nd part. */ +extern RTDATADECL(char) g_szRTAssertMsg2[4096]; +#ifdef IPRT_WITH_ASSERT_STACK +/** The last assertion message, stack part. */ +extern RTDATADECL(char) g_szRTAssertStack[4096]; +#endif +/** The last assertion message, expression. */ +extern RTDATADECL(const char * volatile) g_pszRTAssertExpr; +/** The last assertion message, file name. */ +extern RTDATADECL(const char * volatile) g_pszRTAssertFile; +/** The last assertion message, line number. */ +extern RTDATADECL(uint32_t volatile) g_u32RTAssertLine; +/** The last assertion message, function name. */ +extern RTDATADECL(const char * volatile) g_pszRTAssertFunction; +/** @} */ + +RT_C_DECLS_END + +/** @def RTAssertDebugBreak() + * Debugger breakpoint instruction. + * + * @remarks This macro does not depend on RT_STRICT. + */ +#define RTAssertDebugBreak() do { RT_BREAKPOINT(); } while (0) + + + +/** @name Assertions + * + * These assertions will only trigger when RT_STRICT is defined. When it is + * undefined they will all be no-ops and generate no code. + * + * @{ + */ + + +/** @def RTASSERT_QUIET + * This can be defined to shut up the messages for a file where this would be + * problematic because the message printing code path passes thru it. + * @internal */ +#ifdef DOXYGEN_RUNNING +# define RTASSERT_QUIET +#endif +#if defined(RTASSERT_QUIET) && !defined(DOXYGEN_RUNNING) +# define RTAssertMsg1Weak(pszExpr, uLine, pszfile, pszFunction) \ + do { } while (0) +# ifdef RT_COMPILER_SUPPORTS_VA_ARGS +# define RTAssertMsg2Weak(...) do { } while (0) +# else +# define RTAssertMsg2Weak if (1) {} else RTAssertMsg2Weak +# endif +#endif + +/** @def RTAssertDoPanic + * Raises an assertion panic appropriate to the current context. + * @remarks This macro does not depend on RT_STRICT. + */ +#if defined(IN_RING0) \ + && (defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU) || defined(RT_OS_SOLARIS)) +# define RTAssertDoPanic() RTR0AssertPanicSystem() +#else +# define RTAssertDoPanic() RTAssertDebugBreak() +#endif + +/** @def AssertBreakpoint() + * Assertion Breakpoint. + * @deprecated Use RTAssertPanic or RTAssertDebugBreak instead. + */ +#ifdef RT_STRICT +# define AssertBreakpoint() RTAssertDebugBreak() +#else +# define AssertBreakpoint() do { } while (0) +#endif + +/** @def RTAssertPanic() + * If RT_STRICT is defined this macro will invoke RTAssertDoPanic if + * RTAssertShouldPanic returns true. If RT_STRICT isn't defined it won't do any + * thing. + */ +#if defined(RT_STRICT) && !defined(RTASSERT_DONT_PANIC) +# define RTAssertPanic() do { if (RTAssertShouldPanic()) RTAssertDoPanic(); } while (0) +#else +# define RTAssertPanic() do { } while (0) +#endif + +/** @def Assert + * Assert that an expression is true. If false, hit breakpoint. + * @param expr Expression which should be true. + */ +#ifdef RT_STRICT +# define Assert(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + } \ + } while (0) +#else +# define Assert(expr) do { } while (0) +#endif + + +/** @def AssertStmt + * Assert that an expression is true. If false, hit breakpoint and execute the + * statement. + * @param expr Expression which should be true. + * @param stmt Statement to execute on failure. + */ +#ifdef RT_STRICT +# define AssertStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + } \ + } while (0) +#else +# define AssertStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + } \ + } while (0) +#endif + + +/** @def AssertReturn + * Assert that an expression is true and returns if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return (rc); \ + } \ + } while (0) +#else +# define AssertReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return (rc); \ + } while (0) +#endif + +/** @def AssertReturnStmt + * Assert that an expression is true, if it isn't execute the given statement + * and return rc. + * + * In RT_STRICT mode it will hit a breakpoint before executing the statement and + * returning. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before returning on failure. + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertReturnStmt(expr, stmt, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + return (rc); \ + } \ + } while (0) +#else +# define AssertReturnStmt(expr, stmt, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + return (rc); \ + } \ + } while (0) +#endif + +/** @def AssertReturnVoid + * Assert that an expression is true and returns if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + */ +#ifdef RT_STRICT +# define AssertReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return; \ + } \ + } while (0) +#else +# define AssertReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + +/** @def AssertReturnVoidStmt + * Assert that an expression is true, if it isn't execute the given statement + * and return. + * + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before returning on failure. + */ +#ifdef RT_STRICT +# define AssertReturnVoidStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + return; \ + } \ + } while (0) +#else +# define AssertReturnVoidStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + return; \ + } \ + } while (0) +#endif + + +/** @def AssertBreak + * Assert that an expression is true and breaks if it isn't. + * In RT_STRICT mode it will hit a breakpoint before breaking. + * + * @param expr Expression which should be true. + */ +#ifdef RT_STRICT +# define AssertBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + break; \ + } else \ + break +#else +# define AssertBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def AssertContinue + * Assert that an expression is true and continue if it isn't. + * In RT_STRICT mode it will hit a breakpoint before continuing. + * + * @param expr Expression which should be true. + */ +#ifdef RT_STRICT +# define AssertContinue(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + continue; \ + } else do {} while (0) +#else +# define AssertContinue(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + continue +#endif + +/** @def AssertBreakStmt + * Assert that an expression is true and breaks if it isn't. + * In RT_STRICT mode it will hit a breakpoint before doing break. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#ifdef RT_STRICT +# define AssertBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else do {} while (0) +#else +# define AssertBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + stmt; \ + break; \ + } else do {} while (0) +#endif + + +/** @def AssertMsg + * Assert that an expression is true. If it's not print message and hit breakpoint. + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsg(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + } \ + } while (0) +#else +# define AssertMsg(expr, a) do { } while (0) +#endif + +/** @def AssertMsgStmt + * Assert that an expression is true. If it's not print message and hit + * breakpoint and execute the statement. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute in case of a failed assertion. + * + * @remarks The expression and statement will be evaluated in all build types. + */ +#ifdef RT_STRICT +# define AssertMsgStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + } \ + } while (0) +#else +# define AssertMsgStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + } \ + } while (0) +#endif + +/** @def AssertMsgReturn + * Assert that an expression is true and returns if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + return (rc); \ + } \ + } while (0) +#else +# define AssertMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return (rc); \ + } while (0) +#endif + +/** @def AssertMsgReturnStmt + * Assert that an expression is true, if it isn't execute the statement and + * return. + * + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertMsgReturnStmt(expr, a, stmt, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + return (rc); \ + } \ + } while (0) +#else +# define AssertMsgReturnStmt(expr, a, stmt, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + return (rc); \ + } \ + } while (0) +#endif + +/** @def AssertMsgReturnVoid + * Assert that an expression is true and returns if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + return; \ + } \ + } while (0) +#else +# define AssertMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + +/** @def AssertMsgReturnVoidStmt + * Assert that an expression is true, if it isn't execute the statement and + * return. + * + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before return in case of a failed assertion. + */ +#ifdef RT_STRICT +# define AssertMsgReturnVoidStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + return; \ + } \ + } while (0) +#else +# define AssertMsgReturnVoidStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + return; \ + } \ + } while (0) +#endif + + +/** @def AssertMsgBreak + * Assert that an expression is true and breaks if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + break; \ + } else \ + break +#else +# define AssertMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def AssertMsgBreakStmt + * Assert that an expression is true and breaks if it isn't. + * In RT_STRICT mode it will hit a breakpoint before doing break. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#ifdef RT_STRICT +# define AssertMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + stmt; \ + break; \ + } else \ + break +#endif + +/** @def AssertFailed + * An assertion failed, hit breakpoint. + */ +#ifdef RT_STRICT +# define AssertFailed() \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + } while (0) +#else +# define AssertFailed() do { } while (0) +#endif + +/** @def AssertFailedStmt + * An assertion failed, hit breakpoint and execute statement. + */ +#ifdef RT_STRICT +# define AssertFailedStmt(stmt) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + } while (0) +#else +# define AssertFailedStmt(stmt) do { stmt; } while (0) +#endif + +/** @def AssertFailedReturn + * An assertion failed, hit breakpoint (RT_STRICT mode only) and return. + * + * @param rc The rc to return. + */ +#ifdef RT_STRICT +# define AssertFailedReturn(rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return (rc); \ + } while (0) +#else +# define AssertFailedReturn(rc) \ + do { \ + return (rc); \ + } while (0) +#endif + +/** @def AssertFailedReturnStmt + * An assertion failed, hit breakpoint (RT_STRICT mode only), execute a + * statement and return a value. + * + * @param stmt The statement to execute before returning. + * @param rc The value to return. + */ +#ifdef RT_STRICT +# define AssertFailedReturnStmt(stmt, rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + return (rc); \ + } while (0) +#else +# define AssertFailedReturnStmt(stmt, rc) \ + do { \ + stmt; \ + return (rc); \ + } while (0) +#endif + +/** @def AssertFailedReturnVoid + * An assertion failed, hit breakpoint (RT_STRICT mode only) and return. + */ +#ifdef RT_STRICT +# define AssertFailedReturnVoid() \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return; \ + } while (0) +#else +# define AssertFailedReturnVoid() \ + do { \ + return; \ + } while (0) +#endif + +/** @def AssertFailedReturnVoidStmt + * An assertion failed, hit breakpoint (RT_STRICT mode only), execute a + * statement and return. + * + * @param stmt The statement to execute before returning. + */ +#ifdef RT_STRICT +# define AssertFailedReturnVoidStmt(stmt) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + return; \ + } while (0) +#else +# define AssertFailedReturnVoidStmt(stmt) \ + do { \ + stmt; \ + return; \ + } while (0) +#endif + + +/** @def AssertFailedBreak + * An assertion failed, hit breakpoint (RT_STRICT mode only) and break. + */ +#ifdef RT_STRICT +# define AssertFailedBreak() \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + break; \ + } else \ + break +#else +# define AssertFailedBreak() \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertFailedBreakStmt + * An assertion failed, hit breakpoint (RT_STRICT mode only), execute + * the given statement and break. + * + * @param stmt Statement to execute before break. + */ +#ifdef RT_STRICT +# define AssertFailedBreakStmt(stmt) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertFailedBreakStmt(stmt) \ + if (1) { \ + stmt; \ + break; \ + } else \ + break +#endif + + +/** @def AssertMsgFailed + * An assertion failed print a message and a hit breakpoint. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgFailed(a) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + } while (0) +#else +# define AssertMsgFailed(a) do { } while (0) +#endif + +/** @def AssertMsgFailedReturn + * An assertion failed, hit breakpoint with message (RT_STRICT mode only) and return. + * + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertMsgFailedReturn(a, rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + return (rc); \ + } while (0) +#else +# define AssertMsgFailedReturn(a, rc) \ + do { \ + return (rc); \ + } while (0) +#endif + +/** @def AssertMsgFailedReturnVoid + * An assertion failed, hit breakpoint with message (RT_STRICT mode only) and return. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgFailedReturnVoid(a) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + return; \ + } while (0) +#else +# define AssertMsgFailedReturnVoid(a) \ + do { \ + return; \ + } while (0) +#endif + + +/** @def AssertMsgFailedBreak + * An assertion failed, hit breakpoint with message (RT_STRICT mode only) and break. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgFailedBreak(a) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + break; \ + } else \ + break +#else +# define AssertMsgFailedBreak(a) \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertMsgFailedBreakStmt + * An assertion failed, hit breakpoint (RT_STRICT mode only), execute + * the given statement and break. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break. + */ +#ifdef RT_STRICT +# define AssertMsgFailedBreakStmt(a, stmt) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertMsgFailedBreakStmt(a, stmt) \ + if (1) { \ + stmt; \ + break; \ + } else \ + break +#endif + +/** @} */ + + + +/** @name Release Log Assertions + * + * These assertions will work like normal strict assertion when RT_STRICT is + * defined and LogRel statements when RT_STRICT is undefined. Typically used for + * things which shouldn't go wrong, but when it does you'd like to know one way + * or the other. + * + * @{ + */ + +/** @def RTAssertLogRelMsg1 + * RTAssertMsg1Weak (strict builds) / LogRel wrapper (non-strict). + */ +#ifdef RT_STRICT +# define RTAssertLogRelMsg1(pszExpr, iLine, pszFile, pszFunction) \ + RTAssertMsg1Weak(pszExpr, iLine, pszFile, pszFunction) +#else +# define RTAssertLogRelMsg1(pszExpr, iLine, pszFile, pszFunction) \ + LogRel(("AssertLogRel %s(%d) %s: %s\n",\ + (pszFile), (iLine), (pszFunction), (pszExpr) )) +#endif + +/** @def RTAssertLogRelMsg2 + * RTAssertMsg2Weak (strict builds) / LogRel wrapper (non-strict). + */ +#ifdef RT_STRICT +# define RTAssertLogRelMsg2(a) RTAssertMsg2Weak a +#else +# define RTAssertLogRelMsg2(a) LogRel(a) +#endif + +/** @def AssertLogRel + * Assert that an expression is true. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + */ +#define AssertLogRel(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + } \ + } while (0) + +/** @def AssertLogRelReturn + * Assert that an expression is true, return \a rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param rc What is to be presented to return. + */ +#define AssertLogRelReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return (rc); \ + } \ + } while (0) + +/** @def AssertLogRelReturnVoid + * Assert that an expression is true, return void if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + */ +#define AssertLogRelReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return; \ + } \ + } while (0) + +/** @def AssertLogRelBreak + * Assert that an expression is true, break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + */ +#define AssertLogRelBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + break; \ + } \ + else \ + break + +/** @def AssertLogRelBreakStmt + * Assert that an expression is true, execute \a stmt and break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#define AssertLogRelBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break + +/** @def AssertLogRelStmt + * Assert that an expression is true, return \a rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute in case of a failed assertion. + */ +#define AssertLogRelStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + } \ + } while (0) + +/** @def AssertLogRelMsg + * Assert that an expression is true. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsg(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + } \ + } while (0) + +/** @def AssertLogRelMsgStmt + * Assert that an expression is true, execute \a stmt and break if it isn't + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute in case of a failed assertion. + */ +#define AssertLogRelMsgStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + } \ + } while (0) + +/** @def AssertLogRelMsgReturn + * Assert that an expression is true, return \a rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#define AssertLogRelMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + return (rc); \ + } \ + } while (0) + +/** @def AssertLogRelMsgReturnStmt + * Assert that an expression is true, execute @a stmt and return @a rcRet if it + * isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + */ +#define AssertLogRelMsgReturnStmt(expr, a, stmt, rcRet) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + return (rcRet); \ + } \ + } while (0) + +/** @def AssertLogRelMsgReturnVoid + * Assert that an expression is true, return (void) if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + return; \ + } \ + } while (0) + +/** @def AssertLogRelMsgBreak + * Assert that an expression is true, break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + break; \ + } \ + else \ + break + +/** @def AssertLogRelMsgBreakStmt + * Assert that an expression is true, execute \a stmt and break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#define AssertLogRelMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break + +/** @def AssertLogRelFailed + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define AssertLogRelFailed() \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + } while (0) + +/** @def AssertLogRelFailedReturn + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param rc What is to be presented to return. + */ +#define AssertLogRelFailedReturn(rc) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return (rc); \ + } while (0) + +/** @def AssertLogRelFailedReturnVoid + * An assertion failed, hit a breakpoint and return. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define AssertLogRelFailedReturnVoid() \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return; \ + } while (0) + +/** @def AssertLogRelFailedBreak + * An assertion failed, break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define AssertLogRelFailedBreak() \ + if (1) \ + { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + break; \ + } else \ + break + +/** @def AssertLogRelFailedBreakStmt + * An assertion failed, execute \a stmt and break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param stmt Statement to execute before break. + */ +#define AssertLogRelFailedBreakStmt(stmt) \ + if (1) \ + { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break + +/** @def AssertLogRelMsgFailed + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgFailed(a) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + } while (0) + +/** @def AssertLogRelMsgFailedStmt + * An assertion failed, execute @a stmt. + * + * Strict builds will hit a breakpoint, non-strict will only do LogRel. The + * statement will be executed in regardless of build type. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute after raising/logging the assertion. + */ +#define AssertLogRelMsgFailedStmt(a, stmt) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + } while (0) + +/** @def AssertLogRelMsgFailedReturn + * An assertion failed, return \a rc. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#define AssertLogRelMsgFailedReturn(a, rc) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + return (rc); \ + } while (0) + +/** @def AssertLogRelMsgFailedReturnStmt + * An assertion failed, execute @a stmt and return @a rc. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rc What is to be presented to return. + */ +#define AssertLogRelMsgFailedReturnStmt(a, stmt, rc) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + return (rc); \ + } while (0) + +/** @def AssertLogRelMsgFailedReturnVoid + * An assertion failed, return void. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgFailedReturnVoid(a) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + return; \ + } while (0) + +/** @def AssertLogRelMsgFailedReturnVoidStmt + * An assertion failed, execute @a stmt and return void. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + */ +#define AssertLogRelMsgFailedReturnVoidStmt(a, stmt) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + return; \ + } while (0) + +/** @def AssertLogRelMsgFailedBreak + * An assertion failed, break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgFailedBreak(a) \ + if (1)\ + { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + break; \ + } else \ + break + +/** @def AssertLogRelMsgFailedBreakStmt + * An assertion failed, execute \a stmt and break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break. + */ +#define AssertLogRelMsgFailedBreakStmt(a, stmt) \ + if (1) \ + { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break + +/** @} */ + + + +/** @name Release Assertions + * + * These assertions are always enabled. + * @{ + */ + +/** @def RTAssertReleasePanic() + * Invokes RTAssertShouldPanic and RTAssertDoPanic. + * + * It might seem odd that RTAssertShouldPanic is necessary when its result isn't + * checked, but it's done since RTAssertShouldPanic is overrideable and might be + * used to bail out before taking down the system (the VMMR0 case). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define RTAssertReleasePanic() do { RTAssertShouldPanic(); RTAssertDoPanic(); } while (0) +#else +# define RTAssertReleasePanic() do { } while (0) +#endif + + +/** @def AssertRelease + * Assert that an expression is true. If it's not hit a breakpoint. + * + * @param expr Expression which should be true. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertRelease(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + } \ + } while (0) +#else +# define AssertRelease(expr) do { } while (0) +#endif + + +/** @def AssertReleaseReturn + * Assert that an expression is true, hit a breakpoint and return if it isn't. + * + * @param expr Expression which should be true. + * @param rc What is to be presented to return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + return (rc); \ + } \ + } while (0) +#else +# define AssertReleaseReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return (rc); \ + } while (0) +#endif + +/** @def AssertReleaseReturnVoid + * Assert that an expression is true, hit a breakpoint and return if it isn't. + * + * @param expr Expression which should be true. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + return; \ + } \ + } while (0) +#else +# define AssertReleaseReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + + +/** @def AssertReleaseBreak + * Assert that an expression is true, hit a breakpoint and break if it isn't. + * + * @param expr Expression which should be true. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + break; \ + } else \ + break +#else +# define AssertReleaseBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def AssertReleaseBreakStmt + * Assert that an expression is true, hit a breakpoint and break if it isn't. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertReleaseBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + stmt; \ + break; \ + } else \ + break +#endif + + +/** @def AssertReleaseMsg + * Assert that an expression is true, print the message and hit a breakpoint if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsg(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + } \ + } while (0) +#else +# define AssertReleaseMsg(expr, a) do { } while (0) +#endif + +/** @def AssertReleaseMsgReturn + * Assert that an expression is true, print the message and hit a breakpoint and return if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + return (rc); \ + } \ + } while (0) +#else +# define AssertReleaseMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return (rc); \ + } while (0) +#endif + +/** @def AssertReleaseMsgReturnVoid + * Assert that an expression is true, print the message and hit a breakpoint and return if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + return; \ + } \ + } while (0) +#else +# define AssertReleaseMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + + +/** @def AssertReleaseMsgBreak + * Assert that an expression is true, print the message and hit a breakpoint and break if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + break; \ + } else \ + break +#else +# define AssertReleaseMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertReleaseMsgBreakStmt + * Assert that an expression is true, print the message and hit a breakpoint and break if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertReleaseMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + stmt; \ + break; \ + } else \ + break +#endif + + +/** @def AssertReleaseFailed + * An assertion failed, hit a breakpoint. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailed() \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + } while (0) +#else +# define AssertReleaseFailed() do { } while (0) +#endif + +/** @def AssertReleaseFailedReturn + * An assertion failed, hit a breakpoint and return. + * + * @param rc What is to be presented to return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailedReturn(rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + return (rc); \ + } while (0) +#else +# define AssertReleaseFailedReturn(rc) \ + do { return (rc); } while (0) +#endif + +/** @def AssertReleaseFailedReturnVoid + * An assertion failed, hit a breakpoint and return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailedReturnVoid() \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + return; \ + } while (0) +#else +# define AssertReleaseFailedReturnVoid() \ + do { return; } while (0) +#endif + +/** @def AssertReleaseFailedBreak + * An assertion failed, hit a breakpoint and break. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailedBreak() \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + break; \ + } else \ + break +#else +# define AssertReleaseFailedBreak() \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertReleaseFailedBreakStmt + * An assertion failed, hit a breakpoint and break. + * + * @param stmt Statement to execute before break. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailedBreakStmt(stmt) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertReleaseFailedBreakStmt(stmt) \ + if (1) { \ + stmt; \ + break; \ + } else \ + break +#endif + +/** @def AssertReleaseMsgFailed + * An assertion failed, print a message and hit a breakpoint. + * + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailed(a) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + } while (0) +#else +# define AssertReleaseMsgFailed(a) do { } while (0) +#endif + +/** @def AssertReleaseMsgFailedReturn + * An assertion failed, print a message, hit a breakpoint and return. + * + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailedReturn(a, rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + return (rc); \ + } while (0) +#else +# define AssertReleaseMsgFailedReturn(a, rc) \ + do { return (rc); } while (0) +#endif + +/** @def AssertReleaseMsgFailedReturnVoid + * An assertion failed, print a message, hit a breakpoint and return. + * + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailedReturnVoid(a) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + return; \ + } while (0) +#else +# define AssertReleaseMsgFailedReturnVoid(a) \ + do { return; } while (0) +#endif + + +/** @def AssertReleaseMsgFailedBreak + * An assertion failed, print a message, hit a breakpoint and break. + * + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailedBreak(a) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + break; \ + } else \ + break +#else +# define AssertReleaseMsgFailedBreak(a) \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertReleaseMsgFailedBreakStmt + * An assertion failed, print a message, hit a breakpoint and break. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailedBreakStmt(a, stmt) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertReleaseMsgFailedBreakStmt(a, stmt) \ + if (1) { \ + stmt; \ + break; \ + } else \ + break +#endif +/** @} */ + + + +/** @name Fatal Assertions + * These are similar to release assertions except that you cannot ignore them in + * any way, they will loop for ever if RTAssertDoPanic returns. + * + * @{ + */ + +/** @def AssertFatal + * Assert that an expression is true. If it's not hit a breakpoint (for ever). + * + * @param expr Expression which should be true. + */ +#define AssertFatal(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + for (;;) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + } \ + } while (0) + +/** @def AssertFatalMsg + * Assert that an expression is true, print the message and hit a breakpoint (for ever) if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define AssertFatalMsg(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + for (;;) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + } \ + } while (0) + +/** @def AssertFatalFailed + * An assertion failed, hit a breakpoint (for ever). + */ +#define AssertFatalFailed() \ + do { \ + for (;;) \ + { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + } \ + } while (0) + +/** @def AssertFatalMsgFailed + * An assertion failed, print a message and hit a breakpoint (for ever). + * + * @param a printf argument list (in parenthesis). + */ +#define AssertFatalMsgFailed(a) \ + do { \ + for (;;) \ + { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + } \ + } while (0) + +/** @} */ + + + +/** @name Convenience Assertions Macros + * @{ + */ + +/** @def AssertRC + * Asserts a iprt status code successful. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRC(rc) AssertMsgRC(rc, ("%Rra\n", (rc))) + +/** @def AssertRCStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and execute + * @a stmt if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCStmt(rc, stmt) AssertMsgRCStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertRCReturn + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCReturn(rc, rcRet) AssertMsgRCReturn(rc, ("%Rra\n", (rc)), rcRet) + +/** @def AssertRCReturnStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and returns @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCReturnStmt(rc, stmt, rcRet) AssertMsgRCReturnStmt(rc, ("%Rra\n", (rc)), stmt, rcRet) + +/** @def AssertRCReturnVoid + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCReturnVoid(rc) AssertMsgRCReturnVoid(rc, ("%Rra\n", (rc))) + +/** @def AssertRCReturnVoidStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), and + * execute the given statement/return if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning on failure. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCReturnVoidStmt(rc, stmt) AssertMsgRCReturnVoidStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertRCBreak + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCBreak(rc) AssertMsgRCBreak(rc, ("%Rra\n", (rc))) + +/** @def AssertRCBreakStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCBreakStmt(rc, stmt) AssertMsgRCBreakStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertMsgRC + * Asserts a iprt status code successful. + * + * It prints a custom message and hits a breakpoint on FAILURE. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRC(rc, msg) \ + do { AssertMsg(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def AssertMsgRCStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and + * execute @a stmt if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCStmt(rc, msg, stmt) \ + do { AssertMsgStmt(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def AssertMsgRCReturn + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCReturn(rc, msg, rcRet) \ + do { AssertMsgReturn(RT_SUCCESS_NP(rc), msg, rcRet); NOREF(rc); } while (0) + +/** @def AssertMsgRCReturnStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCReturnStmt(rc, msg, stmt, rcRet) \ + do { AssertMsgReturnStmt(RT_SUCCESS_NP(rc), msg, stmt, rcRet); NOREF(rc); } while (0) + +/** @def AssertMsgRCReturnVoid + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCReturnVoid(rc, msg) \ + do { AssertMsgReturnVoid(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def AssertMsgRCReturnVoidStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCReturnVoidStmt(rc, msg, stmt) \ + do { AssertMsgReturnVoidStmt(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def AssertMsgRCBreak + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break + * if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCBreak(rc, msg) \ + if (1) { AssertMsgBreak(RT_SUCCESS(rc), msg); NOREF(rc); } else do {} while (0) + +/** @def AssertMsgRCBreakStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and break if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCBreakStmt(rc, msg, stmt) \ + if (1) { AssertMsgBreakStmt(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } else do {} while (0) + +/** @def AssertRCSuccess + * Asserts an iprt status code equals VINF_SUCCESS. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccess(rc) do { AssertMsg((rc) == VINF_SUCCESS, ("%Rra\n", (rc))); NOREF(rc); } while (0) + +/** @def AssertRCSuccessReturn + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccessReturn(rc, rcRet) AssertMsgReturn((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def AssertRCSuccessReturnVoid + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccessReturnVoid(rc) AssertMsgReturnVoid((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertRCSuccessBreak + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccessBreak(rc) AssertMsgBreak((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertRCSuccessBreakStmt + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccessBreakStmt(rc, stmt) AssertMsgBreakStmt((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + + +/** @def AssertLogRelRC + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRC(rc) AssertLogRelMsgRC(rc, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCReturn + * Asserts a iprt status code successful, returning \a rc if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCReturn(rc, rcRet) AssertLogRelMsgRCReturn(rc, ("%Rra\n", (rc)), rcRet) + +/** @def AssertLogRelRCReturnStmt + * Asserts a iprt status code successful, executing \a stmt and returning \a rc + * if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCReturnStmt(rc, stmt, rcRet) AssertLogRelMsgRCReturnStmt(rc, ("%Rra\n", (rc)), stmt, rcRet) + +/** @def AssertLogRelRCReturnVoid + * Asserts a iprt status code successful, returning (void) if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCReturnVoid(rc) AssertLogRelMsgRCReturnVoid(rc, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCBreak + * Asserts a iprt status code successful, breaking if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCBreak(rc) AssertLogRelMsgRCBreak(rc, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCBreakStmt + * Asserts a iprt status code successful, execute \a statement and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCBreakStmt(rc, stmt) AssertLogRelMsgRCBreakStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertLogRelMsgRC + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRC(rc, msg) AssertLogRelMsg(RT_SUCCESS_NP(rc), msg) + +/** @def AssertLogRelMsgRCReturn + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCReturn(rc, msg, rcRet) AssertLogRelMsgReturn(RT_SUCCESS_NP(rc), msg, rcRet) + +/** @def AssertLogRelMsgRCReturnStmt + * Asserts a iprt status code successful, execute \a stmt and return on + * failure. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCReturnStmt(rc, msg, stmt, rcRet) AssertLogRelMsgReturnStmt(RT_SUCCESS_NP(rc), msg, stmt, rcRet) + +/** @def AssertLogRelMsgRCReturnVoid + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCReturnVoid(rc, msg) AssertLogRelMsgReturnVoid(RT_SUCCESS_NP(rc), msg) + +/** @def AssertLogRelMsgRCBreak + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCBreak(rc, msg) AssertLogRelMsgBreak(RT_SUCCESS(rc), msg) + +/** @def AssertLogRelMsgRCBreakStmt + * Asserts a iprt status code successful, execute \a stmt and break if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCBreakStmt(rc, msg, stmt) AssertLogRelMsgBreakStmt(RT_SUCCESS_NP(rc), msg, stmt) + +/** @def AssertLogRelRCSuccess + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccess(rc) AssertLogRelMsg((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCSuccessReturn + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccessReturn(rc, rcRet) AssertLogRelMsgReturn((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def AssertLogRelRCSuccessReturnVoid + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccessReturnVoid(rc) AssertLogRelMsgReturnVoid((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCSuccessBreak + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccessBreak(rc) AssertLogRelMsgBreak((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCSuccessBreakStmt + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccessBreakStmt(rc, stmt) AssertLogRelMsgBreakStmt((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + + +/** @def AssertReleaseRC + * Asserts a iprt status code successful. + * + * On failure information about the error will be printed and a breakpoint hit. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRC(rc) AssertReleaseMsgRC(rc, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCReturn + * Asserts a iprt status code successful, returning if it isn't. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCReturn(rc, rcRet) AssertReleaseMsgRCReturn(rc, ("%Rra\n", (rc)), rcRet) + +/** @def AssertReleaseRCReturnVoid + * Asserts a iprt status code successful, returning if it isn't. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCReturnVoid(rc) AssertReleaseMsgRCReturnVoid(rc, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCBreak + * Asserts a iprt status code successful, breaking if it isn't. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally breaking the current statement if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCBreak(rc) AssertReleaseMsgRCBreak(rc, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCBreakStmt + * Asserts a iprt status code successful, break if it isn't. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally the break statement will be issued if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCBreakStmt(rc, stmt) AssertReleaseMsgRCBreakStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertReleaseMsgRC + * Asserts a iprt status code successful. + * + * On failure a custom message is printed and a breakpoint is hit. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRC(rc, msg) AssertReleaseMsg(RT_SUCCESS_NP(rc), msg) + +/** @def AssertReleaseMsgRCReturn + * Asserts a iprt status code successful. + * + * On failure a custom message is printed, a breakpoint is hit, and finally + * returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRCReturn(rc, msg, rcRet) AssertReleaseMsgReturn(RT_SUCCESS_NP(rc), msg, rcRet) + +/** @def AssertReleaseMsgRCReturnVoid + * Asserts a iprt status code successful. + * + * On failure a custom message is printed, a breakpoint is hit, and finally + * returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRCReturnVoid(rc, msg) AssertReleaseMsgReturnVoid(RT_SUCCESS_NP(rc), msg) + +/** @def AssertReleaseMsgRCBreak + * Asserts a iprt status code successful. + * + * On failure a custom message is printed, a breakpoint is hit, and finally + * breaking the current status if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRCBreak(rc, msg) AssertReleaseMsgBreak(RT_SUCCESS(rc), msg) + +/** @def AssertReleaseMsgRCBreakStmt + * Asserts a iprt status code successful. + * + * On failure a custom message is printed, a breakpoint is hit, and finally + * the break statement is issued if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRCBreakStmt(rc, msg, stmt) AssertReleaseMsgBreakStmt(RT_SUCCESS_NP(rc), msg, stmt) + +/** @def AssertReleaseRCSuccess + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed and a breakpoint hit. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccess(rc) AssertReleaseMsg((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCSuccessReturn + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccessReturn(rc, rcRet) AssertReleaseMsgReturn((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def AssertReleaseRCSuccessReturnVoid + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccessReturnVoid(rc) AssertReleaseMsgReturnVoid((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCSuccessBreak + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally breaking the current statement if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccessBreak(rc) AssertReleaseMsgBreak((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCSuccessBreakStmt + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally the break statement will be issued if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccessBreakStmt(rc, stmt) AssertReleaseMsgBreakStmt((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + + +/** @def AssertFatalRC + * Asserts a iprt status code successful. + * + * On failure information about the error will be printed and a breakpoint hit. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertFatalRC(rc) AssertFatalMsgRC(rc, ("%Rra\n", (rc))) + +/** @def AssertReleaseMsgRC + * Asserts a iprt status code successful. + * + * On failure a custom message is printed and a breakpoint is hit. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertFatalMsgRC(rc, msg) AssertFatalMsg(RT_SUCCESS_NP(rc), msg) + +/** @def AssertFatalRCSuccess + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed and a breakpoint hit. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertFatalRCSuccess(rc) AssertFatalMsg((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + + +/** @def AssertPtr + * Asserts that a pointer is valid. + * + * @param pv The pointer. + */ +#define AssertPtr(pv) AssertMsg(RT_VALID_PTR(pv), ("%p\n", (pv))) + +/** @def AssertPtrReturn + * Asserts that a pointer is valid. + * + * @param pv The pointer. + * @param rcRet What is to be presented to return. + */ +#define AssertPtrReturn(pv, rcRet) AssertMsgReturn(RT_VALID_PTR(pv), ("%p\n", (pv)), rcRet) + +/** @def AssertPtrReturnVoid + * Asserts that a pointer is valid. + * + * @param pv The pointer. + */ +#define AssertPtrReturnVoid(pv) AssertMsgReturnVoid(RT_VALID_PTR(pv), ("%p\n", (pv))) + +/** @def AssertPtrReturnStmt + * Asserts that a pointer is valid. + * + * @param pv The pointer. + * @param stmt Statement to execute before returninig in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + */ +#define AssertPtrReturnStmt(pv, stmt, rcRet) AssertMsgReturnStmt(RT_VALID_PTR(pv), ("%p\n", (pv)), stmt, rcRet) + +/** @def AssertPtrReturnVoidStmt + * Asserts that a pointer is valid. + * + * @param pv The pointer. + * @param stmt Statement to execute before returninig in case of a failed + * assertion. + */ +#define AssertPtrReturnVoidStmt(pv, stmt) AssertMsgReturnVoid(RT_VALID_PTR(pv), ("%p\n", (pv)), stmt) + +/** @def AssertPtrBreak + * Asserts that a pointer is valid. + * + * @param pv The pointer. + */ +#define AssertPtrBreak(pv) AssertMsgBreak(RT_VALID_PTR(pv), ("%p\n", (pv))) + +/** @def AssertPtrBreakStmt + * Asserts that a pointer is valid. + * + * @param pv The pointer. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#define AssertPtrBreakStmt(pv, stmt) AssertMsgBreakStmt(RT_VALID_PTR(pv), ("%p\n", (pv)), stmt) + +/** @def AssertPtrNull + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + */ +#define AssertPtrNull(pv) AssertMsg(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv))) + +/** @def AssertPtrNullReturn + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + * @param rcRet What is to be presented to return. + */ +#define AssertPtrNullReturn(pv, rcRet) AssertMsgReturn(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv)), rcRet) + +/** @def AssertPtrNullReturnVoid + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + */ +#define AssertPtrNullReturnVoid(pv) AssertMsgReturnVoid(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv))) + +/** @def AssertPtrNullBreak + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + */ +#define AssertPtrNullBreak(pv) AssertMsgBreak(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv))) + +/** @def AssertPtrNullBreakStmt + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#define AssertPtrNullBreakStmt(pv, stmt) AssertMsgBreakStmt(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv)), stmt) + +/** @def AssertGCPhys32 + * Asserts that the high dword of a physical address is zero + * + * @param GCPhys The address (RTGCPHYS). + */ +#define AssertGCPhys32(GCPhys) AssertMsg(VALID_PHYS32(GCPhys), ("%RGp\n", (RTGCPHYS)(GCPhys))) + +/** @def AssertGCPtr32 + * Asserts that the high dword of a physical address is zero + * + * @param GCPtr The address (RTGCPTR). + */ +#if GC_ARCH_BITS == 32 +# define AssertGCPtr32(GCPtr) do { } while (0) +#else +# define AssertGCPtr32(GCPtr) AssertMsg(!((GCPtr) & UINT64_C(0xffffffff00000000)), ("%RGv\n", GCPtr)) +#endif + +/** @def AssertForEach + * Equivalent to Assert for each value of the variable from the starting + * value to the finishing one. + * + * @param var Name of the counter variable. + * @param vartype Type of the counter variable. + * @param first Lowest inclusive value of the counter variable. + * This must be free from side effects. + * @param end Highest exclusive value of the counter variable. + * This must be free from side effects. + * @param expr Expression which should be true for each value of @a var. + */ +#define AssertForEach(var, vartype, first, end, expr) \ + do { \ + vartype var; \ + Assert((first) == (first) && (end) == (end)); /* partial check for side effects */ \ + for (var = (first); var < (end); var++) \ + AssertMsg(expr, ("%s = %#RX64 (%RI64)", #var, (uint64_t)var, (int64_t)var)); \ + } while (0) + +#ifdef RT_OS_WINDOWS + +/** @def AssertNtStatus + * Asserts that the NT_SUCCESS() returns true for the given NTSTATUS value. + * + * @param a_rcNt The NTSTATUS to check. Will be evaluated twice and + * subjected to NOREF(). + * @sa AssertRC() + */ +# define AssertNtStatus(a_rcNt) \ + do { AssertMsg(NT_SUCCESS(a_rcNt), ("%#x\n", (a_rcNt))); NOREF(a_rcNt); } while (0) + +/** @def AssertNtStatusSuccess + * Asserts that the given NTSTATUS value equals STATUS_SUCCESS. + * + * @param a_rcNt The NTSTATUS to check. Will be evaluated twice and + * subjected to NOREF(). + * @sa AssertRCSuccess() + */ +# define AssertNtStatusSuccess(a_rcNt) \ + do { AssertMsg((a_rcNt) == STATUS_SUCCESS, ("%#x\n", (a_rcNt))); NOREF(a_rcNt); } while (0) + +#endif /* RT_OS_WINDOWS */ + +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_assert_h */ + diff --git a/include/iprt/assertcompile.h b/include/iprt/assertcompile.h new file mode 100644 index 00000000..dae0840d --- /dev/null +++ b/include/iprt/assertcompile.h @@ -0,0 +1,263 @@ +/** @file + * IPRT - Compile Time Assertions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_assertcompile_h +#define IPRT_INCLUDED_assertcompile_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_assert_compile Compile time assertions + * @ingroup grp_rt + * + * These assertions are used to check structure sizes, member/size alignments + * and similar compile time expressions. + * + * @remarks As you might have noticed, the AssertCompile macros don't follow the + * coding guidelines wrt to macros supposedly being all uppercase and + * underscored. For various reasons they don't, and nobody has + * complained yet. + * + * @{ + */ + +/** + * RTASSERTTYPE is the type the AssertCompile() macro redefines. + * It has no other function and shouldn't be used. + * Visual C++ uses this. + */ +typedef int RTASSERTTYPE[1]; + +/** + * RTASSERTVAR is the type the AssertCompile() macro redefines. + * It has no other function and shouldn't be used. + * + * GCC and IBM VisualAge C/C++ uses this. GCC doesn't technicaly need this + * global scope one as it declares it for each use, however things get + * complicated in C++ code where most GCC and clang versions gets upset by mixed + * "C" and "C++" versions of the symbol when using inside and outside + * RT_C_DECLS_BEGIN/END. The GCC 3.3.x and 3.4.x versions we use, OTOH will + * always complain about unused RTASSERTVAR for each AssertCompileNS use in a + * function if we declare it globally, so we don't do it for those, but we do + * for 4.x+ to prevent linkage confusion. + */ +#if !defined(__cplusplus) || !defined(__GNUC__) +extern int RTASSERTVAR[1]; +#elif RT_GNUC_PREREQ(4, 0) || defined(__clang_major__) /* Not sure when they fixed the global scoping __unused__/whatever problem. */ +RT_C_DECLS_BEGIN +extern int RTASSERTVAR[1]; +RT_C_DECLS_END +#endif + +/** @def RTASSERT_HAVE_STATIC_ASSERT + * Indicates that the compiler implements static_assert(expr, msg). + */ +#ifdef _MSC_VER +# if _MSC_VER >= 1600 && defined(__cplusplus) +# define RTASSERT_HAVE_STATIC_ASSERT +# endif +#endif +#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define RTASSERT_HAVE_STATIC_ASSERT +#endif +#if RT_CLANG_PREREQ(6, 0) +# if __has_feature(cxx_static_assert) || __has_feature(c_static_assert) +# define RTASSERT_HAVE_STATIC_ASSERT +# endif +#endif +#ifdef DOXYGEN_RUNNING +# define RTASSERT_HAVE_STATIC_ASSERT +#endif + +/** @def AssertCompileNS + * Asserts that a compile-time expression is true. If it's not break the build. + * + * This differs from AssertCompile in that it accepts some more expressions + * than what C++0x allows - NS = Non-standard. + * + * @param expr Expression which should be true. + */ +#ifdef __GNUC__ +# define AssertCompileNS(expr) AssertCompileNS2(expr,RTASSERTVAR) +# define AssertCompileNS2(expr,a_VarName) extern int a_VarName[ 1 ] __attribute__((__unused__)), \ + a_VarName[(expr) ? 1 : 0] __attribute__((__unused__)) +#elif defined(__IBMC__) || defined(__IBMCPP__) +# define AssertCompileNS(expr) extern int RTASSERTVAR[(expr) ? 1 : 0] +#else +# define AssertCompileNS(expr) typedef int RTASSERTTYPE[(expr) ? 1 : 0] +#endif + +/** @def AssertCompile + * Asserts that a C++0x compile-time expression is true. If it's not break the + * build. + * @param expr Expression which should be true. + */ +#ifdef RTASSERT_HAVE_STATIC_ASSERT +# ifdef __cplusplus +# define AssertCompile(expr) static_assert(!!(expr), #expr) +# else +# define AssertCompile(expr) _Static_assert(!!(expr), #expr) +# endif +#else +# define AssertCompile(expr) AssertCompileNS(expr) +#endif + +/** @def RTASSERT_OFFSET_OF() + * A offsetof() macro suitable for compile time assertions. + * Both GCC v4 and VisualAge for C++ v3.08 has trouble using RT_OFFSETOF. + */ +#if defined(__GNUC__) +# if __GNUC__ >= 4 +# define RTASSERT_OFFSET_OF(a_Type, a_Member) __builtin_offsetof(a_Type, a_Member) +# else +# define RTASSERT_OFFSET_OF(a_Type, a_Member) RT_OFFSETOF(a_Type, a_Member) +# endif +#elif (defined(__IBMC__) || defined(__IBMCPP__)) && defined(RT_OS_OS2) +# define RTASSERT_OFFSET_OF(a_Type, a_Member) __offsetof(a_Type, a_Member) +#elif (defined(__WATCOMC__) && defined(__cplusplus)) +# define RTASSERT_OFFSET_OF(a_Type, a_Member) __offsetof(a_Type, a_Member) +#else +# define RTASSERT_OFFSET_OF(a_Type, a_Member) RT_OFFSETOF(a_Type, a_Member) +#endif + + +/** @def AssertCompileSize + * Asserts a size at compile. + * @param type The type. + * @param size The expected type size. + */ +#define AssertCompileSize(type, size) \ + AssertCompile(sizeof(type) == (size)) + +/** @def AssertCompileSizeAlignment + * Asserts a size alignment at compile. + * @param type The type. + * @param align The size alignment to assert. + */ +#define AssertCompileSizeAlignment(type, align) \ + AssertCompile(!(sizeof(type) & ((align) - 1))) + +/** @def AssertCompileMemberSize + * Asserts a member offset alignment at compile. + * @param type The type. + * @param member The member. + * @param size The member size to assert. + */ +#define AssertCompileMemberSize(type, member, size) \ + AssertCompile(RT_SIZEOFMEMB(type, member) == (size)) + +/** @def AssertCompileMemberSizeAlignment + * Asserts a member size alignment at compile. + * @param type The type. + * @param member The member. + * @param align The member size alignment to assert. + */ +#define AssertCompileMemberSizeAlignment(type, member, align) \ + AssertCompile(!(RT_SIZEOFMEMB(type, member) & ((align) - 1))) + +/** @def AssertCompileMemberAlignment + * Asserts a member offset alignment at compile. + * @param type The type. + * @param member The member. + * @param align The member offset alignment to assert. + */ +#define AssertCompileMemberAlignment(type, member, align) \ + AssertCompile(!(RTASSERT_OFFSET_OF(type, member) & ((align) - 1))) + +/** @def AssertCompileMemberOffset + * Asserts an offset of a structure member at compile. + * @param type The type. + * @param member The member. + * @param off The expected offset. + */ +#define AssertCompileMemberOffset(type, member, off) \ + AssertCompile(RTASSERT_OFFSET_OF(type, member) == (off)) + +/** @def AssertCompile2MemberOffsets + * Asserts that two (sub-structure) members in union have the same offset. + * @param type The type. + * @param member1 The first member. + * @param member2 The second member. + */ +#define AssertCompile2MemberOffsets(type, member1, member2) \ + AssertCompile(RTASSERT_OFFSET_OF(type, member1) == RTASSERT_OFFSET_OF(type, member2)) + +/** @def AssertCompileAdjacentMembers + * Asserts that two structure members are adjacent. + * @param type The type. + * @param member1 The first member. + * @param member2 The second member. + */ +#define AssertCompileAdjacentMembers(type, member1, member2) \ + AssertCompile(RTASSERT_OFFSET_OF(type, member1) + RT_SIZEOFMEMB(type, member1) == RTASSERT_OFFSET_OF(type, member2)) + +/** @def AssertCompileMembersAtSameOffset + * Asserts that members of two different structures are at the same offset. + * @param type1 The first type. + * @param member1 The first member. + * @param type2 The second type. + * @param member2 The second member. + */ +#define AssertCompileMembersAtSameOffset(type1, member1, type2, member2) \ + AssertCompile(RTASSERT_OFFSET_OF(type1, member1) == RTASSERT_OFFSET_OF(type2, member2)) + +/** @def AssertCompileMembersSameSize + * Asserts that members of two different structures have the same size. + * @param type1 The first type. + * @param member1 The first member. + * @param type2 The second type. + * @param member2 The second member. + */ +#define AssertCompileMembersSameSize(type1, member1, type2, member2) \ + AssertCompile(RT_SIZEOFMEMB(type1, member1) == RT_SIZEOFMEMB(type2, member2)) + +/** @def AssertCompileMembersSameSizeAndOffset + * Asserts that members of two different structures have the same size and are + * at the same offset. + * @param type1 The first type. + * @param member1 The first member. + * @param type2 The second type. + * @param member2 The second member. + */ +#define AssertCompileMembersSameSizeAndOffset(type1, member1, type2, member2) \ + AssertCompile( RTASSERT_OFFSET_OF(type1, member1) == RTASSERT_OFFSET_OF(type2, member2) \ + && RT_SIZEOFMEMB(type1, member1) == RT_SIZEOFMEMB(type2, member2)) + +/** @} */ + +#endif /* !IPRT_INCLUDED_assertcompile_h */ + diff --git a/include/iprt/avl.h b/include/iprt/avl.h new file mode 100644 index 00000000..af51d0e6 --- /dev/null +++ b/include/iprt/avl.h @@ -0,0 +1,1195 @@ +/** @file + * IPRT - AVL Trees. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_avl_h +#define IPRT_INCLUDED_avl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_avl RTAvl - AVL Trees + * @ingroup grp_rt + * @{ + */ + + +/** @name AVL tree of void pointers. + * @{ + */ + +/** + * AVL key type + */ +typedef void * AVLPVKEY; + +/** + * AVL Core node. + */ +typedef struct _AVLPVNodeCore +{ + AVLPVKEY Key; /** Key value. */ + struct _AVLPVNodeCore *pLeft; /** Pointer to left leaf node. */ + struct _AVLPVNodeCore *pRight; /** Pointer to right leaf node. */ + unsigned char uchHeight; /** Height of this tree: max(height(left), height(right)) + 1 */ +} AVLPVNODECORE, *PAVLPVNODECORE, **PPAVLPVNODECORE; + +/** A tree with void pointer keys. */ +typedef PAVLPVNODECORE AVLPVTREE; +/** Pointer to a tree with void pointer keys. */ +typedef PPAVLPVNODECORE PAVLPVTREE; + +/** Callback function for AVLPVDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLPVCALLBACK,(PAVLPVNODECORE, void *)); +/** Pointer to callback function for AVLPVDoWithAll(). */ +typedef AVLPVCALLBACK *PAVLPVCALLBACK; + +/* + * Functions. + */ +RTDECL(bool) RTAvlPVInsert(PAVLPVTREE ppTree, PAVLPVNODECORE pNode); +RTDECL(PAVLPVNODECORE) RTAvlPVRemove(PAVLPVTREE ppTree, AVLPVKEY Key); +RTDECL(PAVLPVNODECORE) RTAvlPVGet(PAVLPVTREE ppTree, AVLPVKEY Key); +RTDECL(PAVLPVNODECORE) RTAvlPVGetBestFit(PAVLPVTREE ppTree, AVLPVKEY Key, bool fAbove); +RTDECL(PAVLPVNODECORE) RTAvlPVRemoveBestFit(PAVLPVTREE ppTree, AVLPVKEY Key, bool fAbove); +RTDECL(int) RTAvlPVDoWithAll(PAVLPVTREE ppTree, int fFromLeft, PAVLPVCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlPVDestroy(PAVLPVTREE ppTree, PAVLPVCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of unsigned long. + * @{ + */ + +/** + * AVL key type + */ +typedef unsigned long AVLULKEY; + +/** + * AVL Core node. + */ +typedef struct _AVLULNodeCore +{ + AVLULKEY Key; /** Key value. */ + struct _AVLULNodeCore *pLeft; /** Pointer to left leaf node. */ + struct _AVLULNodeCore *pRight; /** Pointer to right leaf node. */ + unsigned char uchHeight; /** Height of this tree: max(height(left), height(right)) + 1 */ +} AVLULNODECORE, *PAVLULNODECORE, **PPAVLULNODECORE; + + +/** Callback function for AVLULDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLULCALLBACK,(PAVLULNODECORE, void*)); +/** Pointer to callback function for AVLULDoWithAll(). */ +typedef AVLULCALLBACK *PAVLULCALLBACK; + + +/* + * Functions. + */ +RTDECL(bool) RTAvlULInsert(PPAVLULNODECORE ppTree, PAVLULNODECORE pNode); +RTDECL(PAVLULNODECORE) RTAvlULRemove(PPAVLULNODECORE ppTree, AVLULKEY Key); +RTDECL(PAVLULNODECORE) RTAvlULGet(PPAVLULNODECORE ppTree, AVLULKEY Key); +RTDECL(PAVLULNODECORE) RTAvlULGetBestFit(PPAVLULNODECORE ppTree, AVLULKEY Key, bool fAbove); +RTDECL(PAVLULNODECORE) RTAvlULRemoveBestFit(PPAVLULNODECORE ppTree, AVLULKEY Key, bool fAbove); +RTDECL(int) RTAvlULDoWithAll(PPAVLULNODECORE ppTree, int fFromLeft, PAVLULCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlULDestroy(PPAVLULNODECORE pTree, PAVLULCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + + +/** @name AVL tree of void pointer ranges. + * @{ + */ + +/** + * AVL key type + */ +typedef void *AVLRPVKEY; + +/** + * AVL Core node. + */ +typedef struct AVLRPVNodeCore +{ + AVLRPVKEY Key; /**< First key value in the range (inclusive). */ + AVLRPVKEY KeyLast; /**< Last key value in the range (inclusive). */ + struct AVLRPVNodeCore *pLeft; /**< Pointer to left leaf node. */ + struct AVLRPVNodeCore *pRight; /**< Pointer to right leaf node. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ +} AVLRPVNODECORE, *PAVLRPVNODECORE, **PPAVLRPVNODECORE; + +/** A tree with void pointer keys. */ +typedef PAVLRPVNODECORE AVLRPVTREE; +/** Pointer to a tree with void pointer keys. */ +typedef PPAVLRPVNODECORE PAVLRPVTREE; + +/** Callback function for AVLPVDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRPVCALLBACK,(PAVLRPVNODECORE, void *)); +/** Pointer to callback function for AVLPVDoWithAll(). */ +typedef AVLRPVCALLBACK *PAVLRPVCALLBACK; + +/* + * Functions. + */ +RTDECL(bool) RTAvlrPVInsert(PAVLRPVTREE ppTree, PAVLRPVNODECORE pNode); +RTDECL(PAVLRPVNODECORE) RTAvlrPVRemove(PAVLRPVTREE ppTree, AVLRPVKEY Key); +RTDECL(PAVLRPVNODECORE) RTAvlrPVGet(PAVLRPVTREE ppTree, AVLRPVKEY Key); +RTDECL(PAVLRPVNODECORE) RTAvlrPVRangeGet(PAVLRPVTREE ppTree, AVLRPVKEY Key); +RTDECL(PAVLRPVNODECORE) RTAvlrPVRangeRemove(PAVLRPVTREE ppTree, AVLRPVKEY Key); +RTDECL(PAVLRPVNODECORE) RTAvlrPVGetBestFit(PAVLRPVTREE ppTree, AVLRPVKEY Key, bool fAbove); +RTDECL(PAVLRPVNODECORE) RTAvlrPVRemoveBestFit(PAVLRPVTREE ppTree, AVLRPVKEY Key, bool fAbove); +RTDECL(int) RTAvlrPVDoWithAll(PAVLRPVTREE ppTree, int fFromLeft, PAVLRPVCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrPVDestroy(PAVLRPVTREE ppTree, PAVLRPVCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + + +/** @name AVL tree of uint32_t + * @{ + */ + +/** AVL key type. */ +typedef uint32_t AVLU32KEY; + +/** AVL Core node. */ +typedef struct _AVLU32NodeCore +{ + struct _AVLU32NodeCore *pLeft; /**< Pointer to left leaf node. */ + struct _AVLU32NodeCore *pRight; /**< Pointer to right leaf node. */ + AVLU32KEY Key; /**< Key value. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ +} AVLU32NODECORE, *PAVLU32NODECORE, **PPAVLU32NODECORE; + +/** A tree with uint32_t keys. */ +typedef PAVLU32NODECORE AVLU32TREE; +/** Pointer to a tree with uint32_t keys. */ +typedef PPAVLU32NODECORE PAVLU32TREE; + +/** Callback function for AVLU32DoWithAll() & AVLU32Destroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLU32CALLBACK,(PAVLU32NODECORE, void*)); +/** Pointer to callback function for AVLU32DoWithAll() & AVLU32Destroy(). */ +typedef AVLU32CALLBACK *PAVLU32CALLBACK; + + +/* + * Functions. + */ +RTDECL(bool) RTAvlU32Insert(PAVLU32TREE pTree, PAVLU32NODECORE pNode); +RTDECL(PAVLU32NODECORE) RTAvlU32Remove(PAVLU32TREE pTree, AVLU32KEY Key); +RTDECL(PAVLU32NODECORE) RTAvlU32Get(PAVLU32TREE pTree, AVLU32KEY Key); +RTDECL(PAVLU32NODECORE) RTAvlU32GetBestFit(PAVLU32TREE pTree, AVLU32KEY Key, bool fAbove); +RTDECL(PAVLU32NODECORE) RTAvlU32RemoveBestFit(PAVLU32TREE pTree, AVLU32KEY Key, bool fAbove); +RTDECL(int) RTAvlU32DoWithAll(PAVLU32TREE pTree, int fFromLeft, PAVLU32CALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlU32Destroy(PAVLU32TREE pTree, PAVLU32CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + +/** @name AVL tree of uint32_t, offset based + * @{ + */ + +/** + * AVL uint32_t type for the relative offset pointer scheme. + */ +typedef int32_t AVLOU32; + +typedef uint32_t AVLOU32KEY; + +/** + * AVL Core node. + */ +typedef struct _AVLOU32NodeCore +{ + /** Key value. */ + AVLOU32KEY Key; + /** Offset to the left leaf node, relative to this field. */ + AVLOU32 pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOU32 pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLOU32NODECORE, *PAVLOU32NODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOU32 AVLOU32TREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOU32TREE *PAVLOU32TREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOU32TREE *PPAVLOU32NODECORE; + +/** Callback function for RTAvloU32DoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOU32CALLBACK,(PAVLOU32NODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloU32DoWithAll(). */ +typedef AVLOU32CALLBACK *PAVLOU32CALLBACK; + +RTDECL(bool) RTAvloU32Insert(PAVLOU32TREE pTree, PAVLOU32NODECORE pNode); +RTDECL(PAVLOU32NODECORE) RTAvloU32Remove(PAVLOU32TREE pTree, AVLOU32KEY Key); +RTDECL(PAVLOU32NODECORE) RTAvloU32Get(PAVLOU32TREE pTree, AVLOU32KEY Key); +RTDECL(int) RTAvloU32DoWithAll(PAVLOU32TREE pTree, int fFromLeft, PAVLOU32CALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOU32NODECORE) RTAvloU32GetBestFit(PAVLOU32TREE ppTree, AVLOU32KEY Key, bool fAbove); +RTDECL(PAVLOU32NODECORE) RTAvloU32RemoveBestFit(PAVLOU32TREE ppTree, AVLOU32KEY Key, bool fAbove); +RTDECL(int) RTAvloU32Destroy(PAVLOU32TREE pTree, PAVLOU32CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of uint32_t, list duplicates. + * @{ + */ + +/** AVL key type. */ +typedef uint32_t AVLLU32KEY; + +/** AVL Core node. */ +typedef struct _AVLLU32NodeCore +{ + AVLLU32KEY Key; /**< Key value. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ + struct _AVLLU32NodeCore *pLeft; /**< Pointer to left leaf node. */ + struct _AVLLU32NodeCore *pRight; /**< Pointer to right leaf node. */ + struct _AVLLU32NodeCore *pList; /**< Pointer to next node with the same key. */ +} AVLLU32NODECORE, *PAVLLU32NODECORE, **PPAVLLU32NODECORE; + +/** Callback function for RTAvllU32DoWithAll() & RTAvllU32Destroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLLU32CALLBACK,(PAVLLU32NODECORE, void*)); +/** Pointer to callback function for RTAvllU32DoWithAll() & RTAvllU32Destroy(). */ +typedef AVLLU32CALLBACK *PAVLLU32CALLBACK; + + +/* + * Functions. + */ +RTDECL(bool) RTAvllU32Insert(PPAVLLU32NODECORE ppTree, PAVLLU32NODECORE pNode); +RTDECL(PAVLLU32NODECORE) RTAvllU32Remove(PPAVLLU32NODECORE ppTree, AVLLU32KEY Key); +RTDECL(PAVLLU32NODECORE) RTAvllU32RemoveNode(PPAVLLU32NODECORE ppTree, PAVLLU32NODECORE pNode); +RTDECL(PAVLLU32NODECORE) RTAvllU32Get(PPAVLLU32NODECORE ppTree, AVLLU32KEY Key); +RTDECL(PAVLLU32NODECORE) RTAvllU32GetBestFit(PPAVLLU32NODECORE ppTree, AVLLU32KEY Key, bool fAbove); +RTDECL(PAVLLU32NODECORE) RTAvllU32RemoveBestFit(PPAVLLU32NODECORE ppTree, AVLLU32KEY Key, bool fAbove); +RTDECL(int) RTAvllU32DoWithAll(PPAVLLU32NODECORE ppTree, int fFromLeft, PAVLLU32CALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvllU32Destroy(PPAVLLU32NODECORE pTree, PAVLLU32CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of uint64_t + * @{ + */ + +/** AVL key type. */ +typedef uint64_t AVLU64KEY; + +/** AVL Core node. */ +typedef struct _AVLU64NodeCore +{ + struct _AVLU64NodeCore *pLeft; /**< Pointer to left leaf node. */ + struct _AVLU64NodeCore *pRight; /**< Pointer to right leaf node. */ + AVLU64KEY Key; /**< Key value. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ +} AVLU64NODECORE, *PAVLU64NODECORE, **PPAVLU64NODECORE; + +/** A tree with uint64_t keys. */ +typedef PAVLU64NODECORE AVLU64TREE; +/** Pointer to a tree with uint64_t keys. */ +typedef PPAVLU64NODECORE PAVLU64TREE; + +/** Callback function for AVLU64DoWithAll() & AVLU64Destroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLU64CALLBACK,(PAVLU64NODECORE, void*)); +/** Pointer to callback function for AVLU64DoWithAll() & AVLU64Destroy(). */ +typedef AVLU64CALLBACK *PAVLU64CALLBACK; + + +/* + * Functions. + */ +RTDECL(bool) RTAvlU64Insert(PAVLU64TREE pTree, PAVLU64NODECORE pNode); +RTDECL(PAVLU64NODECORE) RTAvlU64Remove(PAVLU64TREE pTree, AVLU64KEY Key); +RTDECL(PAVLU64NODECORE) RTAvlU64Get(PAVLU64TREE pTree, AVLU64KEY Key); +RTDECL(PAVLU64NODECORE) RTAvlU64GetBestFit(PAVLU64TREE pTree, AVLU64KEY Key, bool fAbove); +RTDECL(PAVLU64NODECORE) RTAvlU64RemoveBestFit(PAVLU64TREE pTree, AVLU64KEY Key, bool fAbove); +RTDECL(int) RTAvlU64DoWithAll(PAVLU64TREE pTree, int fFromLeft, PAVLU64CALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlU64Destroy(PAVLU64TREE pTree, PAVLU64CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of uint64_t ranges. + * @{ + */ + +/** + * AVL key type + */ +typedef uint64_t AVLRU64KEY; + +/** + * AVL Core node. + */ +typedef struct AVLRU64NodeCore +{ + AVLRU64KEY Key; /**< First key value in the range (inclusive). */ + AVLRU64KEY KeyLast; /**< Last key value in the range (inclusive). */ + struct AVLRU64NodeCore *pLeft; /**< Pointer to left leaf node. */ + struct AVLRU64NodeCore *pRight; /**< Pointer to right leaf node. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ +} AVLRU64NODECORE, *PAVLRU64NODECORE, **PPAVLRU64NODECORE; + +/** A tree with uint64_t keys. */ +typedef PAVLRU64NODECORE AVLRU64TREE; +/** Pointer to a tree with uint64_t keys. */ +typedef PPAVLRU64NODECORE PAVLRU64TREE; + +/** Callback function for AVLRU64DoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRU64CALLBACK,(PAVLRU64NODECORE, void *)); +/** Pointer to callback function for AVLU64DoWithAll(). */ +typedef AVLRU64CALLBACK *PAVLRU64CALLBACK; + +/* + * Functions. + */ +RTDECL(bool) RTAvlrU64Insert(PAVLRU64TREE ppTree, PAVLRU64NODECORE pNode); +RTDECL(PAVLRU64NODECORE) RTAvlrU64Remove(PAVLRU64TREE ppTree, AVLRU64KEY Key); +RTDECL(PAVLRU64NODECORE) RTAvlrU64Get(PAVLRU64TREE ppTree, AVLRU64KEY Key); +RTDECL(PAVLRU64NODECORE) RTAvlrU64RangeGet(PAVLRU64TREE ppTree, AVLRU64KEY Key); +RTDECL(PAVLRU64NODECORE) RTAvlrU64RangeRemove(PAVLRU64TREE ppTree, AVLRU64KEY Key); +RTDECL(PAVLRU64NODECORE) RTAvlrU64GetBestFit(PAVLRU64TREE ppTree, AVLRU64KEY Key, bool fAbove); +RTDECL(PAVLRU64NODECORE) RTAvlrU64RemoveBestFit(PAVLRU64TREE ppTree, AVLRU64KEY Key, bool fAbove); +RTDECL(int) RTAvlrU64DoWithAll(PAVLRU64TREE ppTree, int fFromLeft, PAVLRU64CALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrU64Destroy(PAVLRU64TREE ppTree, PAVLRU64CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + + +/** @name AVL tree of RTGCPHYSes - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLOGCPHYS; + +/** + * AVL Core node. + */ +typedef struct _AVLOGCPhysNodeCore +{ + /** Key value. */ + RTGCPHYS Key; + /** Offset to the left leaf node, relative to this field. */ + AVLOGCPHYS pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOGCPHYS pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; + /** Padding */ + unsigned char Padding[7]; +} AVLOGCPHYSNODECORE, *PAVLOGCPHYSNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOGCPHYS AVLOGCPHYSTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOGCPHYSTREE *PAVLOGCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOGCPHYSTREE *PPAVLOGCPHYSNODECORE; + +/** Callback function for RTAvloGCPhysDoWithAll() and RTAvloGCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOGCPHYSCALLBACK,(PAVLOGCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloGCPhysDoWithAll() and RTAvloGCPhysDestroy(). */ +typedef AVLOGCPHYSCALLBACK *PAVLOGCPHYSCALLBACK; + +RTDECL(bool) RTAvloGCPhysInsert(PAVLOGCPHYSTREE pTree, PAVLOGCPHYSNODECORE pNode); +RTDECL(PAVLOGCPHYSNODECORE) RTAvloGCPhysRemove(PAVLOGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLOGCPHYSNODECORE) RTAvloGCPhysGet(PAVLOGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(int) RTAvloGCPhysDoWithAll(PAVLOGCPHYSTREE pTree, int fFromLeft, PAVLOGCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOGCPHYSNODECORE) RTAvloGCPhysGetBestFit(PAVLOGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(PAVLOGCPHYSNODECORE) RTAvloGCPhysRemoveBestFit(PAVLOGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(int) RTAvloGCPhysDestroy(PAVLOGCPHYSTREE pTree, PAVLOGCPHYSCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTGCPHYS ranges - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLROGCPHYS; + +/** + * AVL Core node. + */ +typedef struct _AVLROGCPhysNodeCore +{ + /** First key value in the range (inclusive). */ + RTGCPHYS Key; + /** Last key value in the range (inclusive). */ + RTGCPHYS KeyLast; + /** Offset to the left leaf node, relative to this field. */ + AVLROGCPHYS pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLROGCPHYS pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; + /** Padding */ + unsigned char Padding[7]; +} AVLROGCPHYSNODECORE, *PAVLROGCPHYSNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLROGCPHYS AVLROGCPHYSTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLROGCPHYSTREE *PAVLROGCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLROGCPHYSTREE *PPAVLROGCPHYSNODECORE; + +/** Callback function for RTAvlroGCPhysDoWithAll() and RTAvlroGCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLROGCPHYSCALLBACK,(PAVLROGCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlroGCPhysDoWithAll() and RTAvlroGCPhysDestroy(). */ +typedef AVLROGCPHYSCALLBACK *PAVLROGCPHYSCALLBACK; + +RTDECL(bool) RTAvlroGCPhysInsert(PAVLROGCPHYSTREE pTree, PAVLROGCPHYSNODECORE pNode); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysRemove(PAVLROGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGet(PAVLROGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysRangeGet(PAVLROGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysRangeRemove(PAVLROGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGetBestFit(PAVLROGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(int) RTAvlroGCPhysDoWithAll(PAVLROGCPHYSTREE pTree, int fFromLeft, PAVLROGCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlroGCPhysDestroy(PAVLROGCPHYSTREE pTree, PAVLROGCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGetRoot(PAVLROGCPHYSTREE pTree); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGetLeft(PAVLROGCPHYSNODECORE pNode); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGetRight(PAVLROGCPHYSNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTGCPTRs. + * @{ + */ + +/** + * AVL Core node. + */ +typedef struct _AVLGCPtrNodeCore +{ + /** Key value. */ + RTGCPTR Key; + /** Pointer to the left node. */ + struct _AVLGCPtrNodeCore *pLeft; + /** Pointer to the right node. */ + struct _AVLGCPtrNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLGCPTRNODECORE, *PAVLGCPTRNODECORE, **PPAVLGCPTRNODECORE; + +/** A tree of RTGCPTR keys. */ +typedef PAVLGCPTRNODECORE AVLGCPTRTREE; +/** Pointer to a tree of RTGCPTR keys. */ +typedef PPAVLGCPTRNODECORE PAVLGCPTRTREE; + +/** Callback function for RTAvlGCPtrDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLGCPTRCALLBACK,(PAVLGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlGCPtrDoWithAll(). */ +typedef AVLGCPTRCALLBACK *PAVLGCPTRCALLBACK; + +RTDECL(bool) RTAvlGCPtrInsert(PAVLGCPTRTREE pTree, PAVLGCPTRNODECORE pNode); +RTDECL(PAVLGCPTRNODECORE) RTAvlGCPtrRemove(PAVLGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLGCPTRNODECORE) RTAvlGCPtrGet(PAVLGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvlGCPtrDoWithAll(PAVLGCPTRTREE pTree, int fFromLeft, PAVLGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLGCPTRNODECORE) RTAvlGCPtrGetBestFit(PAVLGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLGCPTRNODECORE) RTAvlGCPtrRemoveBestFit(PAVLGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(int) RTAvlGCPtrDestroy(PAVLGCPTRTREE pTree, PAVLGCPTRCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTGCPTRs - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLOGCPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLOGCPtrNodeCore +{ + /** Key value. */ + RTGCPTR Key; + /** Offset to the left leaf node, relative to this field. */ + AVLOGCPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOGCPTR pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; + unsigned char padding[GC_ARCH_BITS == 64 ? 7 : 3]; +} AVLOGCPTRNODECORE, *PAVLOGCPTRNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOGCPTR AVLOGCPTRTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOGCPTRTREE *PAVLOGCPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOGCPTRTREE *PPAVLOGCPTRNODECORE; + +/** Callback function for RTAvloGCPtrDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOGCPTRCALLBACK,(PAVLOGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloGCPtrDoWithAll(). */ +typedef AVLOGCPTRCALLBACK *PAVLOGCPTRCALLBACK; + +RTDECL(bool) RTAvloGCPtrInsert(PAVLOGCPTRTREE pTree, PAVLOGCPTRNODECORE pNode); +RTDECL(PAVLOGCPTRNODECORE) RTAvloGCPtrRemove(PAVLOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLOGCPTRNODECORE) RTAvloGCPtrGet(PAVLOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvloGCPtrDoWithAll(PAVLOGCPTRTREE pTree, int fFromLeft, PAVLOGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOGCPTRNODECORE) RTAvloGCPtrGetBestFit(PAVLOGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLOGCPTRNODECORE) RTAvloGCPtrRemoveBestFit(PAVLOGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(int) RTAvloGCPtrDestroy(PAVLOGCPTRTREE pTree, PAVLOGCPTRCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTGCPTR ranges. + * @{ + */ + +/** + * AVL Core node. + */ +typedef struct _AVLRGCPtrNodeCore +{ + /** First key value in the range (inclusive). */ + RTGCPTR Key; + /** Last key value in the range (inclusive). */ + RTGCPTR KeyLast; + /** Offset to the left leaf node, relative to this field. */ + struct _AVLRGCPtrNodeCore *pLeft; + /** Offset to the right leaf node, relative to this field. */ + struct _AVLRGCPtrNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLRGCPTRNODECORE, *PAVLRGCPTRNODECORE; + +/** A offset base tree with RTGCPTR keys. */ +typedef PAVLRGCPTRNODECORE AVLRGCPTRTREE; +/** Pointer to an offset base tree with RTGCPTR keys. */ +typedef AVLRGCPTRTREE *PAVLRGCPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLRGCPTRTREE *PPAVLRGCPTRNODECORE; + +/** Callback function for RTAvlrGCPtrDoWithAll() and RTAvlrGCPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRGCPTRCALLBACK,(PAVLRGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlrGCPtrDoWithAll() and RTAvlrGCPtrDestroy(). */ +typedef AVLRGCPTRCALLBACK *PAVLRGCPTRCALLBACK; + +RTDECL(bool) RTAvlrGCPtrInsert( PAVLRGCPTRTREE pTree, PAVLRGCPTRNODECORE pNode); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrRemove( PAVLRGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGet( PAVLRGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGetBestFit( PAVLRGCPTRTREE pTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrRangeGet( PAVLRGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrRangeRemove( PAVLRGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvlrGCPtrDoWithAll( PAVLRGCPTRTREE pTree, int fFromLeft, PAVLRGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrGCPtrDestroy( PAVLRGCPTRTREE pTree, PAVLRGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGetRoot( PAVLRGCPTRTREE pTree); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGetLeft( PAVLRGCPTRNODECORE pNode); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGetRight( PAVLRGCPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTGCPTR ranges - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLROGCPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLROGCPtrNodeCore +{ + /** First key value in the range (inclusive). */ + RTGCPTR Key; + /** Last key value in the range (inclusive). */ + RTGCPTR KeyLast; + /** Offset to the left leaf node, relative to this field. */ + AVLROGCPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLROGCPTR pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; + unsigned char padding[GC_ARCH_BITS == 64 ? 7 : 7]; +} AVLROGCPTRNODECORE, *PAVLROGCPTRNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLROGCPTR AVLROGCPTRTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLROGCPTRTREE *PAVLROGCPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLROGCPTRTREE *PPAVLROGCPTRNODECORE; + +/** Callback function for RTAvlroGCPtrDoWithAll() and RTAvlroGCPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLROGCPTRCALLBACK,(PAVLROGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlroGCPtrDoWithAll() and RTAvlroGCPtrDestroy(). */ +typedef AVLROGCPTRCALLBACK *PAVLROGCPTRCALLBACK; + +RTDECL(bool) RTAvlroGCPtrInsert(PAVLROGCPTRTREE pTree, PAVLROGCPTRNODECORE pNode); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrRemove(PAVLROGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGet(PAVLROGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGetBestFit(PAVLROGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrRangeGet(PAVLROGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrRangeRemove(PAVLROGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvlroGCPtrDoWithAll(PAVLROGCPTRTREE pTree, int fFromLeft, PAVLROGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlroGCPtrDestroy(PAVLROGCPTRTREE pTree, PAVLROGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGetRoot(PAVLROGCPTRTREE pTree); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGetLeft(PAVLROGCPTRNODECORE pNode); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGetRight(PAVLROGCPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTGCPTR ranges (overlapping supported) - using relative + * offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLROOGCPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLROOGCPtrNodeCore +{ + /** First key value in the range (inclusive). */ + RTGCPTR Key; + /** Last key value in the range (inclusive). */ + RTGCPTR KeyLast; + /** Offset to the left leaf node, relative to this field. */ + AVLROOGCPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLROOGCPTR pRight; + /** Pointer to the list of string with the same key. Don't touch. */ + AVLROOGCPTR pList; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLROOGCPTRNODECORE, *PAVLROOGCPTRNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLROOGCPTR AVLROOGCPTRTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLROOGCPTRTREE *PAVLROOGCPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLROOGCPTRTREE *PPAVLROOGCPTRNODECORE; + +/** Callback function for RTAvlrooGCPtrDoWithAll() and RTAvlrooGCPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLROOGCPTRCALLBACK,(PAVLROOGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlrooGCPtrDoWithAll() and RTAvlrooGCPtrDestroy(). */ +typedef AVLROOGCPTRCALLBACK *PAVLROOGCPTRCALLBACK; + +RTDECL(bool) RTAvlrooGCPtrInsert(PAVLROOGCPTRTREE pTree, PAVLROOGCPTRNODECORE pNode); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrRemove(PAVLROOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGet(PAVLROOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetBestFit(PAVLROOGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrRangeGet(PAVLROOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrRangeRemove(PAVLROOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvlrooGCPtrDoWithAll(PAVLROOGCPTRTREE pTree, int fFromLeft, PAVLROOGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrooGCPtrDestroy(PAVLROOGCPTRTREE pTree, PAVLROOGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetRoot(PAVLROOGCPTRTREE pTree); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetLeft(PAVLROOGCPTRNODECORE pNode); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetRight(PAVLROOGCPTRNODECORE pNode); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetNextEqual(PAVLROOGCPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTUINTPTR. + * @{ + */ + +/** + * AVL RTUINTPTR node core. + */ +typedef struct _AVLUIntPtrNodeCore +{ + /** Key value. */ + RTUINTPTR Key; + /** Offset to the left leaf node, relative to this field. */ + struct _AVLUIntPtrNodeCore *pLeft; + /** Offset to the right leaf node, relative to this field. */ + struct _AVLUIntPtrNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLUINTPTRNODECORE; +/** Pointer to a RTUINTPTR AVL node core.*/ +typedef AVLUINTPTRNODECORE *PAVLUINTPTRNODECORE; + +/** A pointer based tree with RTUINTPTR keys. */ +typedef PAVLUINTPTRNODECORE AVLUINTPTRTREE; +/** Pointer to an offset base tree with RTUINTPTR keys. */ +typedef AVLUINTPTRTREE *PAVLUINTPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a pointer. */ +typedef AVLUINTPTRTREE *PPAVLUINTPTRNODECORE; + +/** Callback function for RTAvlUIntPtrDoWithAll() and RTAvlUIntPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLUINTPTRCALLBACK,(PAVLUINTPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlUIntPtrDoWithAll() and RTAvlUIntPtrDestroy(). */ +typedef AVLUINTPTRCALLBACK *PAVLUINTPTRCALLBACK; + +RTDECL(bool) RTAvlUIntPtrInsert( PAVLUINTPTRTREE pTree, PAVLUINTPTRNODECORE pNode); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrRemove( PAVLUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGet( PAVLUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGetBestFit(PAVLUINTPTRTREE pTree, RTUINTPTR Key, bool fAbove); +RTDECL(int) RTAvlUIntPtrDoWithAll( PAVLUINTPTRTREE pTree, int fFromLeft, PAVLUINTPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlUIntPtrDestroy( PAVLUINTPTRTREE pTree, PAVLUINTPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGetRoot( PAVLUINTPTRTREE pTree); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGetLeft( PAVLUINTPTRNODECORE pNode); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGetRight( PAVLUINTPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTUINTPTR ranges. + * @{ + */ + +/** + * AVL RTUINTPTR range node core. + */ +typedef struct _AVLRUIntPtrNodeCore +{ + /** First key value in the range (inclusive). */ + RTUINTPTR Key; + /** Last key value in the range (inclusive). */ + RTUINTPTR KeyLast; + /** Offset to the left leaf node, relative to this field. */ + struct _AVLRUIntPtrNodeCore *pLeft; + /** Offset to the right leaf node, relative to this field. */ + struct _AVLRUIntPtrNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLRUINTPTRNODECORE; +/** Pointer to an AVL RTUINTPTR range node code. */ +typedef AVLRUINTPTRNODECORE *PAVLRUINTPTRNODECORE; + +/** A pointer based tree with RTUINTPTR ranges. */ +typedef PAVLRUINTPTRNODECORE AVLRUINTPTRTREE; +/** Pointer to a pointer based tree with RTUINTPTR ranges. */ +typedef AVLRUINTPTRTREE *PAVLRUINTPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a pointer. */ +typedef AVLRUINTPTRTREE *PPAVLRUINTPTRNODECORE; + +/** Callback function for RTAvlrUIntPtrDoWithAll() and RTAvlrUIntPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRUINTPTRCALLBACK,(PAVLRUINTPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlrUIntPtrDoWithAll() and RTAvlrUIntPtrDestroy(). */ +typedef AVLRUINTPTRCALLBACK *PAVLRUINTPTRCALLBACK; + +RTDECL(bool) RTAvlrUIntPtrInsert( PAVLRUINTPTRTREE pTree, PAVLRUINTPTRNODECORE pNode); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrRemove( PAVLRUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGet( PAVLRUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGetBestFit( PAVLRUINTPTRTREE pTree, RTUINTPTR Key, bool fAbove); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrRangeGet( PAVLRUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrRangeRemove(PAVLRUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(int) RTAvlrUIntPtrDoWithAll( PAVLRUINTPTRTREE pTree, int fFromLeft, PAVLRUINTPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrUIntPtrDestroy( PAVLRUINTPTRTREE pTree, PAVLRUINTPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGetRoot( PAVLRUINTPTRTREE pTree); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGetLeft( PAVLRUINTPTRNODECORE pNode); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGetRight( PAVLRUINTPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTHCPHYSes - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLOHCPHYS; + +/** + * AVL Core node. + */ +typedef struct _AVLOHCPhysNodeCore +{ + /** Key value. */ + RTHCPHYS Key; + /** Offset to the left leaf node, relative to this field. */ + AVLOHCPHYS pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOHCPHYS pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64 + unsigned char Padding[7]; /**< Alignment padding. */ +#endif +} AVLOHCPHYSNODECORE, *PAVLOHCPHYSNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOHCPHYS AVLOHCPHYSTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOHCPHYSTREE *PAVLOHCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOHCPHYSTREE *PPAVLOHCPHYSNODECORE; + +/** Callback function for RTAvloHCPhysDoWithAll() and RTAvloHCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOHCPHYSCALLBACK,(PAVLOHCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloHCPhysDoWithAll() and RTAvloHCPhysDestroy(). */ +typedef AVLOHCPHYSCALLBACK *PAVLOHCPHYSCALLBACK; + +RTDECL(bool) RTAvloHCPhysInsert(PAVLOHCPHYSTREE pTree, PAVLOHCPHYSNODECORE pNode); +RTDECL(PAVLOHCPHYSNODECORE) RTAvloHCPhysRemove(PAVLOHCPHYSTREE pTree, RTHCPHYS Key); +RTDECL(PAVLOHCPHYSNODECORE) RTAvloHCPhysGet(PAVLOHCPHYSTREE pTree, RTHCPHYS Key); +RTDECL(int) RTAvloHCPhysDoWithAll(PAVLOHCPHYSTREE pTree, int fFromLeft, PAVLOHCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOHCPHYSNODECORE) RTAvloHCPhysGetBestFit(PAVLOHCPHYSTREE ppTree, RTHCPHYS Key, bool fAbove); +RTDECL(PAVLOHCPHYSNODECORE) RTAvloHCPhysRemoveBestFit(PAVLOHCPHYSTREE ppTree, RTHCPHYS Key, bool fAbove); +RTDECL(int) RTAvloHCPhysDestroy(PAVLOHCPHYSTREE pTree, PAVLOHCPHYSCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + + +/** @name AVL tree of RTIOPORTs - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLOIOPORTPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLOIOPortNodeCore +{ + /** Offset to the left leaf node, relative to this field. */ + AVLOIOPORTPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOIOPORTPTR pRight; + /** Key value. */ + RTIOPORT Key; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLOIOPORTNODECORE, *PAVLOIOPORTNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOIOPORTPTR AVLOIOPORTTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOIOPORTTREE *PAVLOIOPORTTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOIOPORTTREE *PPAVLOIOPORTNODECORE; + +/** Callback function for RTAvloIOPortDoWithAll() and RTAvloIOPortDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOIOPORTCALLBACK,(PAVLOIOPORTNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloIOPortDoWithAll() and RTAvloIOPortDestroy(). */ +typedef AVLOIOPORTCALLBACK *PAVLOIOPORTCALLBACK; + +RTDECL(bool) RTAvloIOPortInsert(PAVLOIOPORTTREE pTree, PAVLOIOPORTNODECORE pNode); +RTDECL(PAVLOIOPORTNODECORE) RTAvloIOPortRemove(PAVLOIOPORTTREE pTree, RTIOPORT Key); +RTDECL(PAVLOIOPORTNODECORE) RTAvloIOPortGet(PAVLOIOPORTTREE pTree, RTIOPORT Key); +RTDECL(int) RTAvloIOPortDoWithAll(PAVLOIOPORTTREE pTree, int fFromLeft, PAVLOIOPORTCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOIOPORTNODECORE) RTAvloIOPortGetBestFit(PAVLOIOPORTTREE ppTree, RTIOPORT Key, bool fAbove); +RTDECL(PAVLOIOPORTNODECORE) RTAvloIOPortRemoveBestFit(PAVLOIOPORTTREE ppTree, RTIOPORT Key, bool fAbove); +RTDECL(int) RTAvloIOPortDestroy(PAVLOIOPORTTREE pTree, PAVLOIOPORTCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTIOPORT ranges - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLROIOPORTPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLROIOPortNodeCore +{ + /** First key value in the range (inclusive). */ + RTIOPORT Key; + /** Last key value in the range (inclusive). */ + RTIOPORT KeyLast; + /** Offset to the left leaf node, relative to this field. */ + AVLROIOPORTPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLROIOPORTPTR pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLROIOPORTNODECORE, *PAVLROIOPORTNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLROIOPORTPTR AVLROIOPORTTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLROIOPORTTREE *PAVLROIOPORTTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLROIOPORTTREE *PPAVLROIOPORTNODECORE; + +/** Callback function for RTAvlroIOPortDoWithAll() and RTAvlroIOPortDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLROIOPORTCALLBACK,(PAVLROIOPORTNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlroIOPortDoWithAll() and RTAvlroIOPortDestroy(). */ +typedef AVLROIOPORTCALLBACK *PAVLROIOPORTCALLBACK; + +RTDECL(bool) RTAvlroIOPortInsert(PAVLROIOPORTTREE pTree, PAVLROIOPORTNODECORE pNode); +RTDECL(PAVLROIOPORTNODECORE) RTAvlroIOPortRemove(PAVLROIOPORTTREE pTree, RTIOPORT Key); +RTDECL(PAVLROIOPORTNODECORE) RTAvlroIOPortGet(PAVLROIOPORTTREE pTree, RTIOPORT Key); +RTDECL(PAVLROIOPORTNODECORE) RTAvlroIOPortRangeGet(PAVLROIOPORTTREE pTree, RTIOPORT Key); +RTDECL(PAVLROIOPORTNODECORE) RTAvlroIOPortRangeRemove(PAVLROIOPORTTREE pTree, RTIOPORT Key); +RTDECL(int) RTAvlroIOPortDoWithAll(PAVLROIOPORTTREE pTree, int fFromLeft, PAVLROIOPORTCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlroIOPortDestroy(PAVLROIOPORTTREE pTree, PAVLROIOPORTCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTHCPHYSes. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef struct _AVLHCPhysNodeCore *AVLHCPHYSPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLHCPhysNodeCore +{ + /** Offset to the left leaf node, relative to this field. */ + AVLHCPHYSPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLHCPHYSPTR pRight; + /** Key value. */ + RTHCPHYS Key; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLHCPHYSNODECORE, *PAVLHCPHYSNODECORE; + +/** A offset base tree with RTHCPHYS keys. */ +typedef AVLHCPHYSPTR AVLHCPHYSTREE; +/** Pointer to an offset base tree with RTHCPHYS keys. */ +typedef AVLHCPHYSTREE *PAVLHCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLHCPHYSTREE *PPAVLHCPHYSNODECORE; + +/** Callback function for RTAvlHCPhysDoWithAll() and RTAvlHCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLHCPHYSCALLBACK,(PAVLHCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlHCPhysDoWithAll() and RTAvlHCPhysDestroy(). */ +typedef AVLHCPHYSCALLBACK *PAVLHCPHYSCALLBACK; + +RTDECL(bool) RTAvlHCPhysInsert(PAVLHCPHYSTREE pTree, PAVLHCPHYSNODECORE pNode); +RTDECL(PAVLHCPHYSNODECORE) RTAvlHCPhysRemove(PAVLHCPHYSTREE pTree, RTHCPHYS Key); +RTDECL(PAVLHCPHYSNODECORE) RTAvlHCPhysGet(PAVLHCPHYSTREE pTree, RTHCPHYS Key); +RTDECL(int) RTAvlHCPhysDoWithAll(PAVLHCPHYSTREE pTree, int fFromLeft, PAVLHCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLHCPHYSNODECORE) RTAvlHCPhysGetBestFit(PAVLHCPHYSTREE ppTree, RTHCPHYS Key, bool fAbove); +RTDECL(PAVLHCPHYSNODECORE) RTAvlHCPhysRemoveBestFit(PAVLHCPHYSTREE ppTree, RTHCPHYS Key, bool fAbove); +RTDECL(int) RTAvlHCPhysDestroy(PAVLHCPHYSTREE pTree, PAVLHCPHYSCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + +/** @name AVL tree of RTGCPHYSes. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef struct _AVLGCPhysNodeCore *AVLGCPHYSPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLGCPhysNodeCore +{ + /** Offset to the left leaf node, relative to this field. */ + AVLGCPHYSPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLGCPHYSPTR pRight; + /** Key value. */ + RTGCPHYS Key; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLGCPHYSNODECORE, *PAVLGCPHYSNODECORE; + +/** A offset base tree with RTGCPHYS keys. */ +typedef AVLGCPHYSPTR AVLGCPHYSTREE; +/** Pointer to an offset base tree with RTGCPHYS keys. */ +typedef AVLGCPHYSTREE *PAVLGCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLGCPHYSTREE *PPAVLGCPHYSNODECORE; + +/** Callback function for RTAvlGCPhysDoWithAll() and RTAvlGCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLGCPHYSCALLBACK,(PAVLGCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlGCPhysDoWithAll() and RTAvlGCPhysDestroy(). */ +typedef AVLGCPHYSCALLBACK *PAVLGCPHYSCALLBACK; + +RTDECL(bool) RTAvlGCPhysInsert(PAVLGCPHYSTREE pTree, PAVLGCPHYSNODECORE pNode); +RTDECL(PAVLGCPHYSNODECORE) RTAvlGCPhysRemove(PAVLGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLGCPHYSNODECORE) RTAvlGCPhysGet(PAVLGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(int) RTAvlGCPhysDoWithAll(PAVLGCPHYSTREE pTree, int fFromLeft, PAVLGCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLGCPHYSNODECORE) RTAvlGCPhysGetBestFit(PAVLGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(PAVLGCPHYSNODECORE) RTAvlGCPhysRemoveBestFit(PAVLGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(int) RTAvlGCPhysDestroy(PAVLGCPHYSTREE pTree, PAVLGCPHYSCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTFOFF ranges. + * @{ + */ + +/** + * AVL Core node. + */ +typedef struct _AVLRFOFFNodeCore +{ + /** First key value in the range (inclusive). */ + RTFOFF Key; + /** Last key value in the range (inclusive). */ + RTFOFF KeyLast; + /** Offset to the left leaf node, relative to this field. */ + struct _AVLRFOFFNodeCore *pLeft; + /** Offset to the right leaf node, relative to this field. */ + struct _AVLRFOFFNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLRFOFFNODECORE, *PAVLRFOFFNODECORE; + +/** A pointer based tree with RTFOFF ranges. */ +typedef PAVLRFOFFNODECORE AVLRFOFFTREE; +/** Pointer to a pointer based tree with RTFOFF ranges. */ +typedef AVLRFOFFTREE *PAVLRFOFFTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLRFOFFTREE *PPAVLRFOFFNODECORE; + +/** Callback function for RTAvlrGCPtrDoWithAll() and RTAvlrGCPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRFOFFCALLBACK,(PAVLRFOFFNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlrGCPtrDoWithAll() and RTAvlrGCPtrDestroy(). */ +typedef AVLRFOFFCALLBACK *PAVLRFOFFCALLBACK; + +RTDECL(bool) RTAvlrFileOffsetInsert( PAVLRFOFFTREE pTree, PAVLRFOFFNODECORE pNode); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetRemove( PAVLRFOFFTREE pTree, RTFOFF Key); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGet( PAVLRFOFFTREE pTree, RTFOFF Key); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGetBestFit( PAVLRFOFFTREE pTree, RTFOFF Key, bool fAbove); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetRangeGet( PAVLRFOFFTREE pTree, RTFOFF Key); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetRangeRemove( PAVLRFOFFTREE pTree, RTFOFF Key); +RTDECL(int) RTAvlrFileOffsetDoWithAll( PAVLRFOFFTREE pTree, int fFromLeft, PAVLRFOFFCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrFileOffsetDestroy( PAVLRFOFFTREE pTree, PAVLRFOFFCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGetRoot( PAVLRFOFFTREE pTree); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGetLeft( PAVLRFOFFNODECORE pNode); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGetRight( PAVLRFOFFNODECORE pNode); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_avl_h */ + diff --git a/include/iprt/base64.h b/include/iprt/base64.h new file mode 100644 index 00000000..441f6e5e --- /dev/null +++ b/include/iprt/base64.h @@ -0,0 +1,353 @@ +/** @file + * IPRT - Base64, MIME content transfer encoding. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_base64_h +#define IPRT_INCLUDED_base64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_base64 RTBase64 - Base64, MIME content transfer encoding. + * @ingroup grp_rt + * @{ + */ + +/** @def RTBASE64_EOL_SIZE + * The size of the end-of-line marker. */ +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# define RTBASE64_EOL_SIZE (sizeof("\r\n") - 1) +#else +# define RTBASE64_EOL_SIZE (sizeof("\n") - 1) +#endif + + +/** @name Flags for RTBase64EncodeEx() and RTBase64EncodedLengthEx(). + * @{ */ +/** Insert line breaks into encoded string. + * The size of the end-of-line marker is that that of the host platform. + */ +#define RTBASE64_FLAGS_EOL_NATIVE UINT32_C(0) /**< Use native newlines. */ +#define RTBASE64_FLAGS_NO_LINE_BREAKS UINT32_C(1) /**< No newlines. */ +#define RTBASE64_FLAGS_EOL_LF UINT32_C(2) /**< Use UNIX-style newlines. */ +#define RTBASE64_FLAGS_EOL_CRLF UINT32_C(3) /**< Use DOS-style newlines. */ +#define RTBASE64_FLAGS_EOL_STYLE_MASK UINT32_C(3) /**< End-of-line style mask. */ +/** @} */ + + +/** + * Calculates the decoded data size for a Base64 encoded string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param pszString The Base64 encoded string. + * @param ppszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + */ +RTDECL(ssize_t) RTBase64DecodedSize(const char *pszString, char **ppszEnd); + +/** + * Calculates the decoded data size for a Base64 encoded UTF-16 string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param pwszString The Base64 encoded UTF-16 string. + * @param ppwszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + */ +RTDECL(ssize_t) RTBase64DecodedUtf16Size(PCRTUTF16 pwszString, PRTUTF16 *ppwszEnd); + +/** + * Calculates the decoded data size for a Base64 encoded string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param pszString The Base64 encoded string. + * @param cchStringMax The max length to decode, use RTSTR_MAX if the + * length of @a pszString is not known and it is + * really zero terminated. + * @param ppszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + */ +RTDECL(ssize_t) RTBase64DecodedSizeEx(const char *pszString, size_t cchStringMax, char **ppszEnd); + +/** + * Calculates the decoded data size for a Base64 encoded UTF-16 string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param pwszString The Base64 encoded UTF-16 string. + * @param cwcStringMax The max length to decode in RTUTF16 units, use + * RTSTR_MAX if the length of @a pwszString is not + * known and it is really zero terminated. + * @param ppwszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + */ +RTDECL(ssize_t) RTBase64DecodedUtf16SizeEx(PCRTUTF16 pwszString, size_t cwcStringMax, PRTUTF16 *ppwszEnd); + +/** + * Decodes a Base64 encoded string into the buffer supplied by the caller. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not + * be set, nor will ppszEnd. + * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong. + * + * @param pszString The Base64 string. Whether the entire string or + * just the start of the string is in Base64 depends + * on whether ppszEnd is specified or not. + * @param pvData Where to store the decoded data. + * @param cbData The size of the output buffer that pvData points to. + * @param pcbActual Where to store the actual number of bytes returned. + * Optional. + * @param ppszEnd Indicates that the string may contain other stuff + * after the Base64 encoded data when not NULL. Will + * be set to point to the first char that's not part of + * the encoding. If NULL the entire string must be part + * of the Base64 encoded data. + */ +RTDECL(int) RTBase64Decode(const char *pszString, void *pvData, size_t cbData, size_t *pcbActual, char **ppszEnd); + +/** + * Decodes a Base64 encoded UTF-16 string into the buffer supplied by the + * caller. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not + * be set, nor will ppszEnd. + * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong. + * + * @param pwszString The Base64 UTF-16 string. Whether the entire string + * or just the start of the string is in Base64 depends + * on whether ppwszEnd is specified or not. + * @param pvData Where to store the decoded data. + * @param cbData The size of the output buffer that pvData points to. + * @param pcbActual Where to store the actual number of bytes returned. + * Optional. + * @param ppwszEnd Indicates that the string may contain other stuff + * after the Base64 encoded data when not NULL. Will + * be set to point to the first char that's not part of + * the encoding. If NULL the entire string must be part + * of the Base64 encoded data. + */ +RTDECL(int) RTBase64DecodeUtf16(PCRTUTF16 pwszString, void *pvData, size_t cbData, size_t *pcbActual, PRTUTF16 *ppwszEnd); + +/** + * Decodes a Base64 encoded string into the buffer supplied by the caller. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not + * be set, nor will ppszEnd. + * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong. + * + * @param pszString The Base64 string. Whether the entire string or + * just the start of the string is in Base64 depends + * on whether ppszEnd is specified or not. + * @param cchStringMax The max length to decode, use RTSTR_MAX if the + * length of @a pszString is not known and it is + * really zero terminated. + * @param pvData Where to store the decoded data. + * @param cbData The size of the output buffer that pvData points to. + * @param pcbActual Where to store the actual number of bytes returned. + * Optional. + * @param ppszEnd Indicates that the string may contain other stuff + * after the Base64 encoded data when not NULL. Will + * be set to point to the first char that's not part of + * the encoding. If NULL the entire string must be part + * of the Base64 encoded data. + */ +RTDECL(int) RTBase64DecodeEx(const char *pszString, size_t cchStringMax, void *pvData, size_t cbData, + size_t *pcbActual, char **ppszEnd); + +/** + * Decodes a Base64 encoded UTF-16 string into the buffer supplied by the + * caller. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not + * be set, nor will ppszEnd. + * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong. + * + * @param pwszString The Base64 UTF-16 string. Whether the entire string + * or just the start of the string is in Base64 depends + * on whether ppszEnd is specified or not. + * @param cwcStringMax The max length to decode in RTUTF16 units, use + * RTSTR_MAX if the length of @a pwszString is not + * known and it is really zero terminated. + * @param pvData Where to store the decoded data. + * @param cbData The size of the output buffer that pvData points to. + * @param pcbActual Where to store the actual number of bytes returned. + * Optional. + * @param ppwszEnd Indicates that the string may contain other stuff + * after the Base64 encoded data when not NULL. Will + * be set to point to the first char that's not part of + * the encoding. If NULL the entire string must be part + * of the Base64 encoded data. + */ +RTDECL(int) RTBase64DecodeUtf16Ex(PCRTUTF16 pwszString, size_t cwcStringMax, void *pvData, size_t cbData, + size_t *pcbActual, PRTUTF16 *ppwszEnd); + + +/** + * Calculates the length of the Base64 encoding of a given number of bytes of + * data produced by RTBase64Encode(). + * + * @returns The Base64 string length, excluding the terminator. + * @param cbData The number of bytes to encode. + */ +RTDECL(size_t) RTBase64EncodedLength(size_t cbData); + +/** + * Calculates the UTF-16 length of the Base64 encoding of a given number of + * bytes of data produced by RTBase64EncodeUtf16(). + * + * @returns The Base64 UTF-16 string length (in RTUTF16 units), excluding the + * terminator. + * @param cbData The number of bytes to encode. + */ +RTDECL(size_t) RTBase64EncodedUtf16Length(size_t cbData); + +/** + * Calculates the length of the Base64 encoding of a given number of bytes of + * data produced by RTBase64EncodeEx() with the same @a fFlags. + * + * @returns The Base64 string length, excluding the terminator. + * @param cbData The number of bytes to encode. + * @param fFlags Flags, any combination of the RTBASE64_FLAGS \#defines. + */ +RTDECL(size_t) RTBase64EncodedLengthEx(size_t cbData, uint32_t fFlags); + +/** + * Calculates the UTF-16 length of the Base64 encoding of a given number of + * bytes of data produced by RTBase64EncodeUtf16Ex() with the same @a fFlags. + * + * @returns The Base64 UTF-16 string length (in RTUTF16 units), excluding the + * terminator. + * @param cbData The number of bytes to encode. + * @param fFlags Flags, any combination of the RTBASE64_FLAGS \#defines. + */ +RTDECL(size_t) RTBase64EncodedUtf16LengthEx(size_t cbData, uint32_t fFlags); + +/** + * Encodes the specifed data into a Base64 string, the caller supplies the + * output buffer. + * + * This is equivalent to calling RTBase64EncodeEx() with no flags. + * + * @returns IRPT status code. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small. The buffer + * may contain an invalid Base64 string. + * + * @param pvData The data to encode. + * @param cbData The number of bytes to encode. + * @param pszBuf Where to put the Base64 string. + * @param cbBuf The size of the output buffer, including the terminator. + * @param pcchActual The actual number of characters returned. + */ +RTDECL(int) RTBase64Encode(const void *pvData, size_t cbData, char *pszBuf, size_t cbBuf, size_t *pcchActual); + +/** + * Encodes the specifed data into a Base64 UTF-16 string, the caller supplies + * the output buffer. + * + * This is equivalent to calling RTBase64EncodeUtf16Ex() with no flags. + * + * @returns IRPT status code. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small. The buffer + * may contain an invalid Base64 string. + * + * @param pvData The data to encode. + * @param cbData The number of bytes to encode. + * @param pwszBuf Where to put the Base64 UTF-16 string. + * @param cwcBuf The size of the output buffer in RTUTF16 units, + * including the terminator. + * @param pcwcActual The actual number of characters returned (excluding the + * terminator). Optional. + */ +RTDECL(int) RTBase64EncodeUtf16(const void *pvData, size_t cbData, PRTUTF16 pwszBuf, size_t cwcBuf, size_t *pcwcActual); + +/** + * Encodes the specifed data into a Base64 string, the caller supplies the + * output buffer. + * + * @returns IRPT status code. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small. The buffer + * may contain an invalid Base64 string. + * + * @param pvData The data to encode. + * @param cbData The number of bytes to encode. + * @param fFlags Flags, any combination of the RTBASE64_FLAGS \#defines. + * @param pszBuf Where to put the Base64 string. + * @param cbBuf The size of the output buffer, including the terminator. + * @param pcchActual The actual number of characters returned (excluding the + * terminator). Optional. + */ +RTDECL(int) RTBase64EncodeEx(const void *pvData, size_t cbData, uint32_t fFlags, + char *pszBuf, size_t cbBuf, size_t *pcchActual); + +/** + * Encodes the specifed data into a Base64 UTF-16 string, the caller supplies + * the output buffer. + * + * @returns IRPT status code. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small. The buffer + * may contain an invalid Base64 string. + * + * @param pvData The data to encode. + * @param cbData The number of bytes to encode. + * @param fFlags Flags, any combination of the RTBASE64_FLAGS \#defines. + * @param pwszBuf Where to put the Base64 UTF-16 string. + * @param cwcBuf The size of the output buffer in RTUTF16 units, + * including the terminator. + * @param pcwcActual The actual number of characters returned (excluding the + * terminator). Optional. + */ +RTDECL(int) RTBase64EncodeUtf16Ex(const void *pvData, size_t cbData, uint32_t fFlags, + PRTUTF16 pwszBuf, size_t cwcBuf, size_t *pcwcActual); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_base64_h */ + diff --git a/include/iprt/bignum.h b/include/iprt/bignum.h new file mode 100644 index 00000000..ff1b8c48 --- /dev/null +++ b/include/iprt/bignum.h @@ -0,0 +1,197 @@ +/** @file + * IPRT - Big Integer Numbers. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_bignum_h +#define IPRT_INCLUDED_bignum_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rtbignum RTBigNum - Big Integer Numbers + * @ingroup grp_rt + * @{ + */ + +/** The big integer number element type. */ +#if ARCH_BITS == 64 +typedef uint64_t RTBIGNUMELEMENT; +#else +typedef uint32_t RTBIGNUMELEMENT; +#endif +/** Pointer to a big integer number element. */ +typedef RTBIGNUMELEMENT *PRTBIGNUMELEMENT; +/** Pointer to a const big integer number element. */ +typedef RTBIGNUMELEMENT const *PCRTBIGNUMELEMENT; + +/** The size (in bytes) of one array element. */ +#if ARCH_BITS == 64 +# define RTBIGNUM_ELEMENT_SIZE 8 +#else +# define RTBIGNUM_ELEMENT_SIZE 4 +#endif +/** The number of bits in one array element. */ +#define RTBIGNUM_ELEMENT_BITS (RTBIGNUM_ELEMENT_SIZE * 8) +/** Returns the bitmask corrsponding to given bit number. */ +#if ARCH_BITS == 64 +# define RTBIGNUM_ELEMENT_BIT(iBit) RT_BIT_64(iBit) +#else +# define RTBIGNUM_ELEMENT_BIT(iBit) RT_BIT_32(iBit) +#endif +/** The maximum value one element can hold. */ +#if ARCH_BITS == 64 +# define RTBIGNUM_ELEMENT_MAX UINT64_MAX +#else +# define RTBIGNUM_ELEMENT_MAX UINT32_MAX +#endif +/** Mask including all the element bits set to 1. */ +#define RTBIGNUM_ELEMENT_MASK RTBIGNUM_ELEMENT_MAX + + +/** + * IPRT big integer number. + */ +typedef struct RTBIGNUM +{ + /** Elements array where the magnitue of the value is stored. */ + RTBIGNUMELEMENT *pauElements; + /** The current number of elements we're using in the pauElements array. */ + uint32_t cUsed; + /** The current allocation size of pauElements. */ + uint32_t cAllocated; + /** Reserved for future use. */ + uint32_t uReserved; + + /** Set if it's a negative number, clear if positive or zero. */ + uint32_t fNegative : 1; + + /** Whether to use a the data is sensitive (RTBIGNUMINIT_F_SENSITIVE). */ + uint32_t fSensitive : 1; + /** The number is currently scrambled */ + uint32_t fCurScrambled : 1; + + /** Bits reserved for future use. */ + uint32_t fReserved : 30; +} RTBIGNUM; + + +RTDECL(int) RTBigNumInit(PRTBIGNUM pBigNum, uint32_t fFlags, void const *pvRaw, size_t cbRaw); +RTDECL(int) RTBigNumInitZero(PRTBIGNUM pBigNum, uint32_t fFlags); + +/** @name RTBIGNUMINIT_F_XXX - RTBigNumInit flags. + * @{ */ +/** The number is sensitive so use a safer allocator, scramble it when not + * in use, and apply RTMemWipeThoroughly before freeing. The RTMemSafer API + * takes care of these things. + * @note When using this flag, concurrent access is not possible! */ +#define RTBIGNUMINIT_F_SENSITIVE RT_BIT(0) +/** Big endian number. */ +#define RTBIGNUMINIT_F_ENDIAN_BIG RT_BIT(1) +/** Little endian number. */ +#define RTBIGNUMINIT_F_ENDIAN_LITTLE RT_BIT(2) +/** The raw number is unsigned. */ +#define RTBIGNUMINIT_F_UNSIGNED RT_BIT(3) +/** The raw number is signed. */ +#define RTBIGNUMINIT_F_SIGNED RT_BIT(4) +/** @} */ + +RTDECL(int) RTBigNumClone(PRTBIGNUM pBigNum, PCRTBIGNUM pSrc); + +RTDECL(int) RTBigNumDestroy(PRTBIGNUM pBigNum); + + +/** + * The minimum number of bits require store the two's complement representation + * of the number. + * + * @returns Width in number of bits. + * @param pBigNum The big number. + */ +RTDECL(uint32_t) RTBigNumBitWidth(PCRTBIGNUM pBigNum); +RTDECL(uint32_t) RTBigNumByteWidth(PCRTBIGNUM pBigNum); + + +/** + * Converts the big number to a sign-extended big endian byte sequence. + * + * @returns IPRT status code + * @retval VERR_BUFFER_OVERFLOW if the specified buffer is too small. + * @param pBigNum The big number. + * @param pvBuf The output buffer (size is at least cbWanted). + * @param cbWanted The number of bytes wanted. + */ +RTDECL(int) RTBigNumToBytesBigEndian(PCRTBIGNUM pBigNum, void *pvBuf, size_t cbWanted); + +/** + * Compares two numbers. + * + * @retval -1 if pLeft < pRight. + * @retval 0 if pLeft == pRight. + * @retval 1 if pLeft > pRight. + * + * @param pLeft The left side number. + * @param pRight The right side number. + */ +RTDECL(int) RTBigNumCompare(PRTBIGNUM pLeft, PRTBIGNUM pRight); +RTDECL(int) RTBigNumCompareWithU64(PRTBIGNUM pLeft, uint64_t uRight); +RTDECL(int) RTBigNumCompareWithS64(PRTBIGNUM pLeft, int64_t iRight); + +RTDECL(int) RTBigNumAssign(PRTBIGNUM pDst, PCRTBIGNUM pSrc); +RTDECL(int) RTBigNumNegate(PRTBIGNUM pResult, PCRTBIGNUM pBigNum); +RTDECL(int) RTBigNumNegateThis(PRTBIGNUM pThis); + +RTDECL(int) RTBigNumAdd(PRTBIGNUM pResult, PCRTBIGNUM pAugend, PCRTBIGNUM pAddend); +RTDECL(int) RTBigNumSubtract(PRTBIGNUM pResult, PCRTBIGNUM pMinuend, PCRTBIGNUM pSubtrahend); +RTDECL(int) RTBigNumMultiply(PRTBIGNUM pResult, PCRTBIGNUM pMultiplicand, PCRTBIGNUM pMultiplier); +RTDECL(int) RTBigNumDivide(PRTBIGNUM pQuotient, PRTBIGNUM pRemainder, PCRTBIGNUM pDividend, PCRTBIGNUM pDivisor); +RTDECL(int) RTBigNumDivideKnuth(PRTBIGNUM pQuotient, PRTBIGNUM pRemainder, PCRTBIGNUM pDividend, PCRTBIGNUM pDivisor); +RTDECL(int) RTBigNumDivideLong(PRTBIGNUM pQuotient, PRTBIGNUM pRemainder, PCRTBIGNUM pDividend, PCRTBIGNUM pDivisor); +RTDECL(int) RTBigNumModulo(PRTBIGNUM pRemainder, PCRTBIGNUM pDividend, PCRTBIGNUM pDivisor); +RTDECL(int) RTBigNumExponentiate(PRTBIGNUM pResult, PCRTBIGNUM pBase, PCRTBIGNUM pExponent); +RTDECL(int) RTBigNumShiftLeft(PRTBIGNUM pResult, PCRTBIGNUM pValue, uint32_t cBits); +RTDECL(int) RTBigNumShiftRight(PRTBIGNUM pResult, PCRTBIGNUM pValue, uint32_t cBits); + +RTDECL(int) RTBigNumModExp(PRTBIGNUM pResult, PRTBIGNUM pBase, PRTBIGNUM pExponent, PRTBIGNUM pModulus); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_bignum_h */ + diff --git a/include/iprt/bldprog-strtab-template.cpp.h b/include/iprt/bldprog-strtab-template.cpp.h new file mode 100644 index 00000000..c4d63f4d --- /dev/null +++ b/include/iprt/bldprog-strtab-template.cpp.h @@ -0,0 +1,1335 @@ +/* $Id: bldprog-strtab-template.cpp.h $ */ +/** @file + * IPRT - Build Program - String Table Generator. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/* + * (Avoid include sanity checks as this is ring-3 only, C++ code.) + */ +#if defined(__cplusplus) && defined(IN_RING3) + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** @def BLDPROG_STRTAB_MAX_STRLEN + * The max length of strings in the table. */ +#if !defined(BLDPROG_STRTAB_MAX_STRLEN) || defined(DOXYGEN_RUNNING) +# define BLDPROG_STRTAB_MAX_STRLEN 256 +#endif + +/** @def BLDPROG_STRTAB_WITH_COMPRESSION + * Enables very simple string compression. + */ +#if defined(DOXYGEN_RUNNING) +# define BLDPROG_STRTAB_WITH_COMPRESSION +#endif + +/** @def BLDPROG_STRTAB_WITH_CAMEL_WORDS + * Modifies the string compression to look for camel case words. + */ +#if defined(DOXYGEN_RUNNING) +# define BLDPROG_STRTAB_WITH_CAMEL_WORDS +#endif + +/** @def BLDPROG_STRTAB_PURE_ASCII + * String compression assumes pure 7-bit ASCII and will fail on UTF-8 when this + * is defined. Otherwise, the compression code will require IPRT to link. + */ +#if defined(DOXYGEN_RUNNING) +# define BLDPROG_STRTAB_PURE_ASCII +#endif + + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include +#include +#include + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION +# include +# include + +# define BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE +typedef struct BLDPROGWORDFREQSTATS +{ + uint32_t cWithoutSep; /**< Number of occurances without a separator. */ +# ifdef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE + uint32_t cWithSep; /**< Number of occurance with a separator. */ + char chSep; /**< The separator. First come basis. */ +# endif +} BLDPROGWORDFREQSTATS; + +typedef std::map BLDPROGWORDFREQMAP; + +#endif + +#include "../../src/VBox/Runtime/include/internal/strhash.h" /** @todo make this one public */ + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** + * Build table string. + */ +typedef struct BLDPROGSTRING +{ + /** The string. + * @note This may be modified or replaced (allocated from heap) when + * compressing the string table. */ + char *pszString; + /** The string hash value. */ + uint32_t uHash; + /** The strint table offset. */ + uint32_t offStrTab; + /** The string length. */ + size_t cchString; + /** Pointer to the next string reference (same string table entry). */ + struct BLDPROGSTRING *pNextRef; + /** Pointer to the next string with the same hash value (collision). */ + struct BLDPROGSTRING *pNextCollision; + +} BLDPROGSTRING; +/** Pointer to a string table string. */ +typedef BLDPROGSTRING *PBLDPROGSTRING; + + +/** String table data. */ +typedef struct BLDPROGSTRTAB +{ + /** The size of g_papStrHash. */ + size_t cStrHash; + /** String hash table. */ + PBLDPROGSTRING *papStrHash; + /** Duplicate strings found by AddString. */ + size_t cDuplicateStrings; + /** Total length of the unique strings (no terminators). */ + size_t cchUniqueStrings; + /** Number of unique strings after AddString. */ + size_t cUniqueStrings; + /** Number of collisions. */ + size_t cCollisions; + + /** Number of entries in apSortedStrings. */ + size_t cSortedStrings; + /** The sorted string table. */ + PBLDPROGSTRING *papSortedStrings; + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + /** The 256 words we've picked to be indexed by reference. */ + BLDPROGSTRING aCompDict[256]; + /** The frequency of the 256 dictionary entries. */ + size_t auCompDictFreq[256]; + /** Incoming strings pending compression. */ + PBLDPROGSTRING *papPendingStrings; + /** Current number of entries in papStrPending. */ + size_t cPendingStrings; + /** The allocated size of papPendingStrings. */ + size_t cMaxPendingStrings; + /** Work frequency map. + * @todo rewrite in plain C. */ + BLDPROGWORDFREQMAP Frequencies; + /** Map of characters used by input strings. */ + uint64_t bmUsedChars[256/64]; +#endif + + /** The string table. */ + char *pachStrTab; + /** The actual string table size. */ + size_t cchStrTab; +} BLDPROGSTRTAB; +typedef BLDPROGSTRTAB *PBLDPROGSTRTAB; + +#if RT_CLANG_PREREQ(4, 0) || RT_GNUC_PREREQ(4, 6) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + +/** + * Same as ASMBitTest. + * + * We cannot safely use ASMBitTest here because it must be inline, as this code + * is used to build RuntimeBldProg. */ +DECLINLINE(bool) BldProgBitIsSet(uint64_t const *pbmBitmap, size_t iBit) +{ + return RT_BOOL(pbmBitmap[iBit / 64] & RT_BIT_64(iBit % 64)); +} + + +/** + * Same as ASMBitSet. + * + * We cannot safely use ASMBitSet here because it must be inline, as this code + * is used to build RuntimeBldProg. + */ +DECLINLINE(void) BldProgBitSet(uint64_t *pbmBitmap, size_t iBit) +{ + pbmBitmap[iBit / 64] |= RT_BIT_64(iBit % 64); +} + +#endif + + +/** + * Initializes the strint table compiler. + * + * @returns success indicator (out of memory if false). + * @param pThis The strint table compiler instance. + * @param cMaxStrings The max number of strings we'll be adding. + */ +static bool BldProgStrTab_Init(PBLDPROGSTRTAB pThis, size_t cMaxStrings) +{ + pThis->cStrHash = 0; + pThis->papStrHash = NULL; + pThis->cDuplicateStrings = 0; + pThis->cchUniqueStrings = 0; + pThis->cUniqueStrings = 0; + pThis->cCollisions = 0; + pThis->cSortedStrings = 0; + pThis->papSortedStrings = NULL; + pThis->pachStrTab = NULL; + pThis->cchStrTab = 0; +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + memset(pThis->aCompDict, 0, sizeof(pThis->aCompDict)); + pThis->papPendingStrings = NULL; + pThis->cPendingStrings = 0; + pThis->cMaxPendingStrings = cMaxStrings; + memset(pThis->bmUsedChars, 0, sizeof(pThis->bmUsedChars)); + BldProgBitSet(pThis->bmUsedChars, 0); /* Some parts of the code still thinks zero is a terminator, so don't use it for now. */ +# ifndef BLDPROG_STRTAB_PURE_ASCII + BldProgBitSet(pThis->bmUsedChars, 0xff); /* Reserve escape byte for codepoints above 127. */ +# endif +#endif + + /* + * Allocate a hash table double the size of all strings (to avoid too + * many collisions). Add all strings to it, finding duplicates in the + * process. + */ +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + cMaxStrings += RT_ELEMENTS(pThis->aCompDict); +#endif + cMaxStrings *= 2; + pThis->papStrHash = (PBLDPROGSTRING *)calloc(sizeof(pThis->papStrHash[0]), cMaxStrings); + if (pThis->papStrHash) + { + pThis->cStrHash = cMaxStrings; +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + pThis->papPendingStrings = (PBLDPROGSTRING *)calloc(sizeof(pThis->papPendingStrings[0]), pThis->cMaxPendingStrings); + if (pThis->papPendingStrings) +#endif + return true; + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + free(pThis->papStrHash); + pThis->papStrHash = NULL; +#endif + } + return false; +} + + +#if 0 /* unused */ +static void BldProgStrTab_Delete(PBLDPROGSTRTAB pThis) +{ + free(pThis->papStrHash); + free(pThis->papSortedStrings); + free(pThis->pachStrTab); +# ifdef BLDPROG_STRTAB_WITH_COMPRESSION + free(pThis->papPendingStrings); +# endif + memset(pThis, 0, sizeof(*pThis)); +} +#endif + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + +DECLINLINE(size_t) bldProgStrTab_compressorFindNextWord(const char *pszSrc, char ch, const char **ppszSrc) +{ + /* + * Skip leading word separators. + */ +# ifdef BLDPROG_STRTAB_WITH_CAMEL_WORDS + while ( ch == ' ' + || ch == '-' + || ch == '+' + || ch == '_') +# else + while (ch == ' ') +# endif + ch = *++pszSrc; + if (ch) + { + /* + * Find end of word. + */ + size_t cchWord = 1; +# ifdef BLDPROG_STRTAB_WITH_CAMEL_WORDS + char chPrev = ch; + while ( (ch = pszSrc[cchWord]) != ' ' + && ch != '\0' + && ch != '-' + && ch != '+' + && ch != '_' + && ( ch == chPrev + || !RT_C_IS_UPPER(ch) + || RT_C_IS_UPPER(chPrev)) ) + { + chPrev = ch; + cchWord++; + } +# else + while ((ch = pszSrc[cchWord]) != ' ' && ch != '\0') + cchWord++; +# endif + *ppszSrc = pszSrc; + return cchWord; + } + + *ppszSrc = pszSrc; + return 0; +} + + +/** + * Analyzes a string. + * + * @param pThis The strint table compiler instance. + * @param pStr The string to analyze. + */ +static void bldProgStrTab_compressorAnalyzeString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + /* + * Mark all the string characters as used. + */ + const char *psz = pStr->pszString; + char ch; + while ((ch = *psz++) != '\0') + BldProgBitSet(pThis->bmUsedChars, (uint8_t)ch); + + /* + * For now we just consider words. + */ + psz = pStr->pszString; + while ((ch = *psz) != '\0') + { + size_t cchWord = bldProgStrTab_compressorFindNextWord(psz, ch, &psz); + if (cchWord > 1) + { + std::string strWord(psz, cchWord); + BLDPROGWORDFREQMAP::iterator it = pThis->Frequencies.find(strWord); + if (it != pThis->Frequencies.end()) + { +# ifdef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE + char const chSep = psz[cchWord]; + if (chSep != '\0' && (it->second.chSep == chSep || it->second.chSep == '\0')) + { + it->second.chSep = chSep; + it->second.cWithSep++; + } + else +# endif + it->second.cWithoutSep++; + } + else + { +# ifdef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE + char const chSep = psz[cchWord]; + if (chSep != '\0') + { + BLDPROGWORDFREQSTATS const NewWord = { 0, 0, chSep }; + pThis->Frequencies[strWord] = NewWord; + } + else + { + static BLDPROGWORDFREQSTATS const s_NewWord = { 0, 0, 0 }; + pThis->Frequencies[strWord] = s_NewWord; + } +# else + pThis->Frequencies[strWord].cWithoutSep = 0; +# endif + } + +# if 0 /** @todo need better accounting for overlapping alternatives before this can be enabled. */ + /* Two words - immediate yields calc may lie when this enabled and we may pick the wrong words. */ + if (ch == ' ') + { + ch = psz[++cchWord]; + if (ch != ' ' && ch != '\0') + { + size_t const cchSaved = cchWord; + + do + cchWord++; + while ((ch = psz[cchWord]) != ' ' && ch != '\0'); + + strWord = std::string(psz, cchWord); + BLDPROGWORDFREQMAP::iterator it = pThis->Frequencies.find(strWord); + if (it != pThis->Frequencies.end()) + it->second += cchWord - 1; + else + pThis->Frequencies[strWord] = 0; + + cchWord = cchSaved; + } + } +# endif + } + else if (!cchWord) + break; + + /* Advance. */ + psz += cchWord; + } + pStr->cchString = psz - pStr->pszString; + if (pStr->cchString > BLDPROG_STRTAB_MAX_STRLEN) + { + fprintf(stderr, "error: String to long (%u)\n", (unsigned)pStr->cchString); + abort(); + } +} + +#endif /* BLDPROG_STRTAB_WITH_COMPRESSION */ + +/** + * Adds a string to the hash table. + * @param pThis The strint table compiler instance. + * @param pStr The string. + */ +static void bldProgStrTab_AddStringToHashTab(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + pStr->pNextRef = NULL; + pStr->pNextCollision = NULL; + pStr->offStrTab = 0; + pStr->uHash = sdbm(pStr->pszString, &pStr->cchString); + if (pStr->cchString > BLDPROG_STRTAB_MAX_STRLEN) + { + fprintf(stderr, "error: String to long (%u)\n", (unsigned)pStr->cchString); + exit(RTEXITCODE_FAILURE); + } + + size_t idxHash = pStr->uHash % pThis->cStrHash; + PBLDPROGSTRING pCur = pThis->papStrHash[idxHash]; + if (!pCur) + pThis->papStrHash[idxHash] = pStr; + else + { + /* Look for matching string. */ + do + { + if ( pCur->uHash == pStr->uHash + && pCur->cchString == pStr->cchString + && memcmp(pCur->pszString, pStr->pszString, pStr->cchString) == 0) + { + pStr->pNextRef = pCur->pNextRef; + pCur->pNextRef = pStr; + pThis->cDuplicateStrings++; + return; + } + pCur = pCur->pNextCollision; + } while (pCur != NULL); + + /* No matching string, insert. */ + pThis->cCollisions++; + pStr->pNextCollision = pThis->papStrHash[idxHash]; + pThis->papStrHash[idxHash] = pStr; + } + + pThis->cUniqueStrings++; + pThis->cchUniqueStrings += pStr->cchString; +} + + +/** + * Adds a string to the string table. + * + * @param pThis The strint table compiler instance. + * @param pStr The string. + */ +static void BldProgStrTab_AddString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + bldProgStrTab_compressorAnalyzeString(pThis, pStr); + if (pThis->cPendingStrings < pThis->cMaxPendingStrings) + pThis->papPendingStrings[pThis->cPendingStrings++] = pStr; + else + abort(); +#else + bldProgStrTab_AddStringToHashTab(pThis, pStr); +#endif +} + + +/** + * Adds a string to the string table. + * + * @param pThis The strint table compiler instance. + * @param pStr The string entry (uninitialized). + * @param psz The string, will be duplicated if compression is enabled. + */ +DECLINLINE(void) BldProgStrTab_AddStringDup(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr, const char *psz) +{ +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + pStr->pszString = strdup(psz); + if (!pStr->pszString) + abort(); +#else + pStr->pszString = (char *)psz; +#endif + BldProgStrTab_AddString(pThis, pStr); +} + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + +/** + * Copies @a cchSrc chars from @a pchSrc to @a pszDst, escaping special + * sequences. + * + * @returns New @a pszDst position, NULL if invalid source encoding. + * @param pszDst The destination buffer. + * @param pszSrc The source buffer. + * @param cchSrc How much to copy. + */ +static char *bldProgStrTab_compressorCopyAndEscape(char *pszDst, const char *pszSrc, size_t cchSrc) +{ + while (cchSrc-- > 0) + { + char ch = *pszSrc; + if (!((unsigned char)ch & 0x80)) + { + *pszDst++ = ch; + pszSrc++; + } + else + { +# ifdef BLDPROG_STRTAB_PURE_ASCII + fprintf(stderr, "error: unexpected char value %#x\n", ch); + return NULL; +# else + RTUNICP uc; + int rc = RTStrGetCpEx(&pszSrc, &uc); + if (RT_SUCCESS(rc)) + { + *pszDst++ = (unsigned char)0xff; /* escape single code point. */ + pszDst = RTStrPutCp(pszDst, uc); + } + else + { + fprintf(stderr, "Error: RTStrGetCpEx failed with rc=%d\n", rc); + return NULL; + } +# endif + } + } + return pszDst; +} + + +/** + * Replaces the dictionary words and escapes non-ascii chars in a string. + * + * @param pThis The strint table compiler instance. + * @param pString The string to fixup. + */ +static bool bldProgStrTab_compressorFixupString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + char szNew[BLDPROG_STRTAB_MAX_STRLEN * 2]; + char *pszDst = szNew; + const char *pszSrc = pStr->pszString; + const char *pszSrcEnd = pszSrc + pStr->cchString; + + char ch; + while ((ch = *pszSrc) != '\0') + { + const char * const pszSrcUncompressed = pszSrc; + size_t cchWord = bldProgStrTab_compressorFindNextWord(pszSrc, ch, &pszSrc); + size_t cchSrcUncompressed = pszSrc - pszSrcUncompressed; + if (cchSrcUncompressed > 0) + { + pszDst = bldProgStrTab_compressorCopyAndEscape(pszDst, pszSrcUncompressed, cchSrcUncompressed); + if (!pszDst) + return false; + } + if (!cchWord) + break; + + /* Check for g_aWord matches. */ + if (cchWord > 1) + { + size_t cchMax = pszSrcEnd - pszSrc; + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + { + size_t cchLen = pThis->aCompDict[i].cchString; + if ( cchLen >= cchWord + && cchLen <= cchMax + && memcmp(pThis->aCompDict[i].pszString, pszSrc, cchLen) == 0) + { + *pszDst++ = (unsigned char)i; + pszSrc += cchLen; + cchWord = 0; + break; + } + } + } + + if (cchWord > 0) + { + /* Copy the current word. */ + pszDst = bldProgStrTab_compressorCopyAndEscape(pszDst, pszSrc, cchWord); + if (!pszDst) + return false; + pszSrc += cchWord; + } + } + + /* Just terminate it now. */ + *pszDst = '\0'; + + /* + * Update the string. + */ + size_t cchNew = pszDst - &szNew[0]; + if (cchNew > pStr->cchString) + { + pStr->pszString = (char *)malloc(cchNew + 1); + if (!pStr->pszString) + { + fprintf(stderr, "Out of memory!\n"); + return false; + } + } + memcpy(pStr->pszString, szNew, cchNew + 1); + pStr->cchString = cchNew; + + return true; +} + + +/** + * Entry in SortedDictionary. + * + * Uses variable length string member, so not class and allocated via malloc. + */ +struct SortedDictionaryEntry +{ + size_t m_cchGain; + size_t m_cchString; + RT_FLEXIBLE_ARRAY_EXTENSION + char m_szString[RT_FLEXIBLE_ARRAY]; + + /** Allocates and initializes a new entry. */ + static SortedDictionaryEntry *allocate(const char *a_pch, size_t a_cch, size_t a_cchGain, char a_chSep) + { + size_t cbString = a_cch + !!a_chSep + 1; + SortedDictionaryEntry *pNew = (SortedDictionaryEntry *)malloc(RT_UOFFSETOF(SortedDictionaryEntry, m_szString) + cbString); + if (pNew) + { + pNew->m_cchGain = a_cchGain; + memcpy(pNew->m_szString, a_pch, a_cch); + if (a_chSep) + pNew->m_szString[a_cch++] = a_chSep; + pNew->m_szString[a_cch] = '\0'; + pNew->m_cchString = a_cch; + } + return pNew; + } + + + /** Compares this dictionary entry with an incoming one. + * @retval -1 if this entry is of less worth than the new one. + * @retval 0 if this entry is of equal worth to the new one. + * @retval +1 if this entry is of more worth than the new one. + */ + int compare(size_t a_cchGain, size_t a_cchString) + { + /* Higher gain is preferred of course: */ + if (m_cchGain < a_cchGain) + return -1; + if (m_cchGain > a_cchGain) + return 1; + + /* Gain is the same. Prefer the shorter string, as it will result in a shorter string table: */ + if (m_cchString > a_cchString) + return -1; + if (m_cchString < a_cchString) + return 1; + return 0; + } +}; + + +/** + * Insertion sort dictionary that keeps the 256 best words. + * + * Used by bldProgStrTab_compressorDoStringCompression to pick the dictionary + * words. + */ +class SortedDictionary +{ +public: + size_t m_cEntries; + SortedDictionaryEntry *m_apEntries[256]; + + SortedDictionary() + : m_cEntries(0) + { + for (size_t i = 0; i < RT_ELEMENTS(m_apEntries); i++) + m_apEntries[i] = NULL; + } + + ~SortedDictionary() + { + while (m_cEntries > 0) + { + free(m_apEntries[--m_cEntries]); + m_apEntries[m_cEntries] = NULL; + } + } + + + /** + * Inserts a new entry, if it's worth it. + * @returns true on succes, false if out of memory. + */ + bool insert(const char *a_pchString, size_t a_cchStringBase, size_t a_cchGain, char a_chSep = 0) + { + size_t const cchString = a_cchStringBase + (a_chSep + 1); + + /* + * Drop the insert if the symbol table is full and the insert is less worth the last entry: + */ + if ( m_cEntries >= RT_ELEMENTS(m_apEntries) + && m_apEntries[RT_ELEMENTS(m_apEntries) - 1]->compare(a_cchGain, cchString) >= 0) + return true; + + /* + * Create a new entry to insert. + */ + SortedDictionaryEntry *pNewEntry = SortedDictionaryEntry::allocate(a_pchString, a_cchStringBase, a_cchGain, a_chSep); + if (!pNewEntry) + return false; + + /* + * Find the insert point. + */ + if (m_cEntries == 0) + { + m_apEntries[0] = pNewEntry; + m_cEntries = 1; + } + else + { + /* If table is full, drop the last entry before we start (already made + sure the incoming entry is preferable to the one were dropping): */ + if (m_cEntries >= RT_ELEMENTS(m_apEntries)) + { + free(m_apEntries[RT_ELEMENTS(m_apEntries) - 1]); + m_apEntries[RT_ELEMENTS(m_apEntries) - 1] = NULL; + m_cEntries = RT_ELEMENTS(m_apEntries) - 1; + } + + /* Find where to insert the new entry: */ + /** @todo use binary search. */ + size_t i = m_cEntries; + while (i > 0 && m_apEntries[i - 1]->compare(a_cchGain, cchString) < 0) + i--; + + /* Shift entries to make room and insert the new entry. */ + if (i < m_cEntries) + memmove(&m_apEntries[i + 1], &m_apEntries[i], (m_cEntries - i) * sizeof(m_apEntries[0])); + m_apEntries[i] = pNewEntry; + m_cEntries++; + } + return true; + } +}; + + +/** + * Compresses the vendor and product strings. + * + * This is very very simple (a lot less work than the string table for + * instance). + */ +static bool bldProgStrTab_compressorDoStringCompression(PBLDPROGSTRTAB pThis, bool fVerbose) +{ + /* + * Sort the frequency analyzis result and pick the top entries for any + * available dictionary slots. + */ + SortedDictionary SortedDict; + for (BLDPROGWORDFREQMAP::iterator it = pThis->Frequencies.begin(); it != pThis->Frequencies.end(); ++it) + { + bool fInsert; + size_t const cchString = it->first.length(); +# ifndef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE + size_t const cchGainWithout = it->second.cWithoutSep * cchString; +# else + size_t const cchGainWithout = (it->second.cWithoutSep + it->second.cWithSep) * cchString; + size_t const cchGainWith = it->second.cWithSep * (cchString + 1); + if (cchGainWith > cchGainWithout) + fInsert = SortedDict.insert(it->first.c_str(), cchString, cchGainWith, it->second.chSep); + else +# endif + fInsert = SortedDict.insert(it->first.c_str(), cchString, cchGainWithout); + if (!fInsert) + return false; + } + + size_t cb = 0; + size_t cWords = 0; + size_t iDict = 0; + for (size_t i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + { + char szTmp[2] = { (char)i, '\0' }; + const char *psz = szTmp; + if ( BldProgBitIsSet(pThis->bmUsedChars, i) + || iDict >= SortedDict.m_cEntries) + { + /* character entry */ + pThis->auCompDictFreq[i] = 0; + pThis->aCompDict[i].cchString = 1; + } + else + { + /* word entry */ + cb += SortedDict.m_apEntries[iDict]->m_cchGain; + pThis->auCompDictFreq[i] = SortedDict.m_apEntries[iDict]->m_cchGain; + pThis->aCompDict[i].cchString = SortedDict.m_apEntries[iDict]->m_cchString; + psz = SortedDict.m_apEntries[iDict]->m_szString; + cWords++; + iDict++; + } + pThis->aCompDict[i].pszString = (char *)malloc(pThis->aCompDict[i].cchString + 1); + if (pThis->aCompDict[i].pszString) + memcpy(pThis->aCompDict[i].pszString, psz, pThis->aCompDict[i].cchString + 1); + else + return false; + } + + if (fVerbose) + printf("debug: Estimated string compression saving: %u bytes\n" + "debug: %u words, %u characters\n" + , (unsigned)cb, (unsigned)cWords, (unsigned)(RT_ELEMENTS(pThis->aCompDict) - cWords)); + + /* + * Rework the strings. + */ + size_t cchOld = 0; + size_t cchOldMax = 0; + size_t cchOldMin = BLDPROG_STRTAB_MAX_STRLEN; + size_t cchNew = 0; + size_t cchNewMax = 0; + size_t cchNewMin = BLDPROG_STRTAB_MAX_STRLEN; + size_t i = pThis->cPendingStrings; + while (i-- > 0) + { + PBLDPROGSTRING pCurStr = pThis->papPendingStrings[i]; + cchOld += pCurStr->cchString; + if (pCurStr->cchString > cchOldMax) + cchOldMax = pCurStr->cchString; + if (pCurStr->cchString < cchOldMin) + cchOldMin = pCurStr->cchString; + + if (!bldProgStrTab_compressorFixupString(pThis, pCurStr)) + return false; + + cchNew += pCurStr->cchString; + if (pCurStr->cchString > cchNewMax) + cchNewMax = pCurStr->cchString; + if (pCurStr->cchString < cchNewMin) + cchNewMin = pCurStr->cchString; + + bldProgStrTab_AddStringToHashTab(pThis, pCurStr); + } + + /* + * Do debug stats. + */ + if (fVerbose) + { + for (i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + cchNew += pThis->aCompDict[i].cchString + 1; + + printf("debug: Strings: original: %u bytes; compressed: %u bytes;", (unsigned)cchOld, (unsigned)cchNew); + if (cchNew < cchOld) + printf(" saving %u bytes (%u%%)\n", (unsigned)(cchOld - cchNew), (unsigned)((cchOld - cchNew) * 100 / cchOld)); + else + printf(" wasting %u bytes!\n", (unsigned)(cchOld - cchNew)); + printf("debug: Original string lengths: average %u; min %u; max %u\n", + (unsigned)(cchOld / pThis->cPendingStrings), (unsigned)cchOldMin, (unsigned)cchOldMax); + printf("debug: Compressed string lengths: average %u; min %u; max %u\n", + (unsigned)(cchNew / pThis->cPendingStrings), (unsigned)cchNewMin, (unsigned)cchNewMax); + } + + return true; +} + +#endif /* BLDPROG_STRTAB_WITH_COMPRESSION */ + +/** + * Inserts a string into g_apUniqueStrings. + * @param pThis The strint table compiler instance. + * @param pStr The string. + */ +static void bldProgStrTab_InsertUniqueString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + size_t iIdx; + size_t iEnd = pThis->cSortedStrings; + if (iEnd) + { + size_t iStart = 0; + for (;;) + { + iIdx = iStart + (iEnd - iStart) / 2; + if (pThis->papSortedStrings[iIdx]->cchString < pStr->cchString) + { + if (iIdx <= iStart) + break; + iEnd = iIdx; + } + else if (pThis->papSortedStrings[iIdx]->cchString > pStr->cchString) + { + if (++iIdx >= iEnd) + break; + iStart = iIdx; + } + else + break; + } + + if (iIdx != pThis->cSortedStrings) + memmove(&pThis->papSortedStrings[iIdx + 1], &pThis->papSortedStrings[iIdx], + (pThis->cSortedStrings - iIdx) * sizeof(pThis->papSortedStrings[iIdx])); + } + else + iIdx = 0; + + pThis->papSortedStrings[iIdx] = pStr; + pThis->cSortedStrings++; +} + + +/** + * Compiles the string table after the string has been added. + * + * This will save space by dropping string terminators, eliminating duplicates + * and try find strings that are sub-strings of others. + * + * Will initialize the StrRef of all StrTabString instances. + * + * @returns success indicator (error flagged). + * @param pThis The strint table compiler instance. + */ +static bool BldProgStrTab_CompileIt(PBLDPROGSTRTAB pThis, bool fVerbose) +{ +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + /* + * Do the compression and add all the compressed strings to the table. + */ + if (!bldProgStrTab_compressorDoStringCompression(pThis, fVerbose)) + return false; + + /* + * Add the dictionary strings. + */ + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + if (pThis->aCompDict[i].cchString > 1) + bldProgStrTab_AddStringToHashTab(pThis, &pThis->aCompDict[i]); +# ifdef RT_STRICT + else if (pThis->aCompDict[i].cchString != 1) + abort(); +# endif +#endif + if (fVerbose) + printf("debug: %u unique strings (%u bytes), %u duplicates, %u collisions\n", + (unsigned)pThis->cUniqueStrings, (unsigned)pThis->cchUniqueStrings, + (unsigned)pThis->cDuplicateStrings, (unsigned)pThis->cCollisions); + + /* + * Create papSortedStrings from the hash table. The table is sorted by + * string length, with the longer strings first, so that we increase our + * chances of locating duplicate substrings. + */ + pThis->papSortedStrings = (PBLDPROGSTRING *)malloc(sizeof(pThis->papSortedStrings[0]) * pThis->cUniqueStrings); + if (!pThis->papSortedStrings) + return false; + pThis->cSortedStrings = 0; + size_t idxHash = pThis->cStrHash; + while (idxHash-- > 0) + { + PBLDPROGSTRING pCur = pThis->papStrHash[idxHash]; + if (pCur) + { + do + { + bldProgStrTab_InsertUniqueString(pThis, pCur); + pCur = pCur->pNextCollision; + } while (pCur); + } + } + + /* + * Create the actual string table. + */ + pThis->pachStrTab = (char *)malloc(pThis->cchUniqueStrings + 1); + if (!pThis->pachStrTab) + return false; + pThis->cchStrTab = 0; + for (size_t i = 0; i < pThis->cSortedStrings; i++) + { + PBLDPROGSTRING pCur = pThis->papSortedStrings[i]; + const char * const pszCur = pCur->pszString; + size_t const cchCur = pCur->cchString; + size_t offStrTab = pThis->cchStrTab; + + /* + * See if the string is a substring already found in the string table. + * Excluding the zero terminator increases the chances for this. + */ + size_t cchLeft = pThis->cchStrTab >= cchCur ? pThis->cchStrTab - cchCur : 0; + const char *pchLeft = pThis->pachStrTab; + char const chFirst = *pszCur; + while (cchLeft > 0) + { + const char *pchCandidate = (const char *)memchr(pchLeft, chFirst, cchLeft); + if (!pchCandidate) + break; + if (memcmp(pchCandidate, pszCur, cchCur) == 0) + { + offStrTab = pchCandidate - pThis->pachStrTab; + break; + } + + cchLeft -= pchCandidate + 1 - pchLeft; + pchLeft = pchCandidate + 1; + } + + if (offStrTab == pThis->cchStrTab) + { + /* + * See if the start of the string overlaps the end of the string table. + */ + if (pThis->cchStrTab && cchCur > 1) + { + cchLeft = RT_MIN(pThis->cchStrTab, cchCur - 1); + pchLeft = &pThis->pachStrTab[pThis->cchStrTab - cchLeft]; + while (cchLeft > 0) + { + const char *pchCandidate = (const char *)memchr(pchLeft, chFirst, cchLeft); + if (!pchCandidate) + break; + cchLeft -= pchCandidate - pchLeft; + pchLeft = pchCandidate; + if (memcmp(pchLeft, pszCur, cchLeft) == 0) + { + size_t cchToCopy = cchCur - cchLeft; + memcpy(&pThis->pachStrTab[offStrTab], &pszCur[cchLeft], cchToCopy); + pThis->cchStrTab += cchToCopy; + offStrTab = pchCandidate - pThis->pachStrTab; + break; + } + cchLeft--; + pchLeft++; + } + } + + /* + * If we didn't have any luck above, just append the string. + */ + if (offStrTab == pThis->cchStrTab) + { + memcpy(&pThis->pachStrTab[offStrTab], pszCur, cchCur); + pThis->cchStrTab += cchCur; + } + } + + /* + * Set the string table offset for all the references to this string. + */ + do + { + pCur->offStrTab = (uint32_t)offStrTab; + pCur = pCur->pNextRef; + } while (pCur != NULL); + } + + if (fVerbose) + printf("debug: String table: %u bytes\n", (unsigned)pThis->cchStrTab); + return true; +} + + +#ifdef RT_STRICT +/** + * Sanity checks a string table string. + * @param pThis The strint table compiler instance. + * @param pStr The string to check. + */ +static void BldProgStrTab_CheckStrTabString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + if (pStr->cchString != strlen(pStr->pszString)) + abort(); + if (pStr->offStrTab >= pThis->cchStrTab) + abort(); + if (pStr->offStrTab + pStr->cchString > pThis->cchStrTab) + abort(); + if (memcmp(pStr->pszString, &pThis->pachStrTab[pStr->offStrTab], pStr->cchString) != 0) + abort(); +} +#endif + + +/** + * Output the string table string in C string litteral fashion. + * + * @param pThis The strint table instance. + * @param pString The string to print. + * @param pOut The output stream. + */ +static void BldProgStrTab_PrintCStringLitteral(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pString, FILE *pOut) +{ + const unsigned char *psz = (const unsigned char *)pString->pszString; + unsigned char uch; + while ((uch = *psz++) != '\0') + { +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + if (pThis->aCompDict[uch].cchString == 1) +#else + if (!(uch & 0x80)) +#endif + { + if (uch != '\'' && uch != '\\') + fputc((char)uch, pOut); + else + { + fputc('\\', pOut); + fputc((char)uch, pOut); + } + } +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION +# ifndef BLDPROG_STRTAB_PURE_ASCII + else if (uch == 0xff) + { + RTUNICP uc = RTStrGetCp((const char *)psz); + psz += RTStrCpSize(uc); + fprintf(pOut, "\\u%04x", uc); + } +# else + else + fputs(pThis->aCompDict[uch].pszString, pOut); +# endif +#else + else + fprintf(pOut, "\\x%02x", (unsigned)uch); + NOREF(pThis); +#endif + } +} + + +/** + * Writes the string table code to the output stream. + * + * @param pThis The strint table compiler instance. + * @param pOut The output stream. + * @param pszScope The scoping ("static " or empty string), + * including trailing space. + * @param pszPrefix The variable prefix. Typically "g_" for C programs, + * whereas C++ classes normally use "class::s_g". + * @param pszBaseName The base name for the variables. The user + * accessible variable will end up as just the + * prefix and basename concatenated. + */ +static void BldProgStrTab_WriteStringTable(PBLDPROGSTRTAB pThis, FILE *pOut, + const char *pszScope, const char *pszPrefix, const char *pszBaseName) +{ +#ifdef RT_STRICT + /* + * Do some quick sanity checks while we're here. + */ +# ifdef BLDPROG_STRTAB_WITH_COMPRESSION + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + { + if (BldProgBitIsSet(pThis->bmUsedChars, i) + ? pThis->aCompDict[i].cchString != 1 : pThis->aCompDict[i].cchString < 1) + abort(); + if (pThis->aCompDict[i].cchString > 1) + BldProgStrTab_CheckStrTabString(pThis, &pThis->aCompDict[i]); + } +# endif +#endif + + /* + * Create a table for speeding up the character categorization. + */ + uint8_t abCharCat[256]; + memset(abCharCat, 0, sizeof(abCharCat)); + abCharCat[(unsigned char)'\\'] = 1; + abCharCat[(unsigned char)'\''] = 1; + for (unsigned i = 0; i < 0x20; i++) + abCharCat[i] = 2; + for (unsigned i = 0x7f; i < 0x100; i++) + abCharCat[i] = 2; +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + for (unsigned i = 0; i < 0x100; i++) + if (!BldProgBitIsSet(pThis->bmUsedChars, i)) /* Encode table references using '\xYY'. */ + abCharCat[i] = 2; +#endif + + /* + * We follow the sorted string table, one string per line. + */ + fprintf(pOut, + "#include \n" + "\n" + "static const char g_achStrTab%s[] =\n" + "{\n", + pszBaseName); + + uint32_t off = 0; + for (uint32_t i = 0; i < pThis->cSortedStrings; i++) + { + PBLDPROGSTRING pCur = pThis->papSortedStrings[i]; + uint32_t offEnd = pCur->offStrTab + (uint32_t)pCur->cchString; + if (offEnd > off) + { + /* Comment with an uncompressed and more readable version of the string. */ + if (off == pCur->offStrTab) + fprintf(pOut, "/* 0x%05x = \"", off); + else + fprintf(pOut, "/* 0X%05x = \"", off); + BldProgStrTab_PrintCStringLitteral(pThis, pCur, pOut); + fputs("\" */\n", pOut); + + /* Must use char by char here or we may trigger the max string + length limit in the compiler, */ + fputs(" ", pOut); + for (; off < offEnd; off++) + { + unsigned char uch = pThis->pachStrTab[off]; + fputc('\'', pOut); + if (abCharCat[uch] == 0) + fputc(uch, pOut); + else if (abCharCat[uch] != 1) + fprintf(pOut, "\\x%02x", (unsigned)uch); + else + { + fputc('\\', pOut); + fputc(uch, pOut); + } + fputc('\'', pOut); + fputc(',', pOut); + } + fputc('\n', pOut); + } + } + + fprintf(pOut, + "};\n" + "AssertCompile(sizeof(g_achStrTab%s) == %#x);\n\n", + pszBaseName, (unsigned)pThis->cchStrTab); + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + /* + * Write the compression dictionary. + */ + fprintf(pOut, + "static const RTBLDPROGSTRREF g_aCompDict%s[%u] = \n" + "{\n", + pszBaseName, (unsigned)RT_ELEMENTS(pThis->aCompDict)); + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + if (pThis->aCompDict[i].cchString > 1) + fprintf(pOut, " /*[%3u]=*/ { %#08x, %#04x }, // %6lu - %s\n", i, + pThis->aCompDict[i].offStrTab, (unsigned)pThis->aCompDict[i].cchString, + (unsigned long)pThis->auCompDictFreq[i], pThis->aCompDict[i].pszString); +# ifndef BLDPROG_STRTAB_PURE_ASCII + else if (i == 0xff) + fprintf(pOut, " /*[%3u]=*/ { 0x000000, 0x00 }, // UTF-8 escape\n", i); +# endif + else if (i == 0) + fprintf(pOut, " /*[%3u]=*/ { 0x000000, 0x00 }, // unused, because zero terminator\n", i); + else if (i < 0x20) + fprintf(pOut, " /*[%3u]=*/ { 0x000000, 0x00 }, // %02x\n", i, i); + else + fprintf(pOut, " /*[%3u]=*/ { 0x000000, 0x00 }, // '%c'\n", i, (char)i); + fprintf(pOut, "};\n\n"); +#endif + + + /* + * Write the string table data structure. + */ + fprintf(pOut, + "%sconst RTBLDPROGSTRTAB %s%s = \n" + "{\n" + " /*.pchStrTab = */ &g_achStrTab%s[0],\n" + " /*.cchStrTab = */ sizeof(g_achStrTab%s),\n" + , + pszScope, pszPrefix, pszBaseName, pszBaseName, pszBaseName); +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + fprintf(pOut, + " /*.cCompDict = */ %u,\n" + " /*.paCompDict = */ &g_aCompDict%s[0]\n" + "};\n" +# ifndef BLDPROG_STRTAB_PURE_ASCII /* 255 or 256 entries is how the decoder knows */ + , (unsigned)RT_ELEMENTS(pThis->aCompDict) - 1, +# else + , (unsigned)RT_ELEMENTS(pThis->aCompDict), +# endif + pszBaseName); +#else + fprintf(pOut, + " /*.cCompDict = */ 0,\n" + " /*.paCompDict = */ NULL\n" + "};\n"); +#endif +} + +#if RT_CLANG_PREREQ(4, 0) || RT_GNUC_PREREQ(4, 6) +# pragma GCC diagnostic pop +#endif + +#endif /* __cplusplus && IN_RING3 */ + diff --git a/include/iprt/bldprog-strtab.h b/include/iprt/bldprog-strtab.h new file mode 100644 index 00000000..9a40d24a --- /dev/null +++ b/include/iprt/bldprog-strtab.h @@ -0,0 +1,259 @@ +/** @file + * IPRT - Build Program - String Table Generator, Accessors. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_bldprog_strtab_h +#define IPRT_INCLUDED_bldprog_strtab_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** + * The default build program string table reference. + */ +typedef struct RTBLDPROGSTRREF +{ + /** Offset of the string in the string table. */ + uint32_t off : 22; + /** The length of the string. */ + uint32_t cch : 10; +} RTBLDPROGSTRREF; +AssertCompileSize(RTBLDPROGSTRREF, sizeof(uint32_t)); +/** Pointer to a build program string table reference. */ +typedef RTBLDPROGSTRREF const *PCRTBLDPROGSTRREF; + + +typedef struct RTBLDPROGSTRTAB +{ + const char *pchStrTab; + uint32_t cchStrTab; + uint32_t cCompDict; + PCRTBLDPROGSTRREF paCompDict; +} RTBLDPROGSTRTAB; +typedef const RTBLDPROGSTRTAB *PCRTBLDPROGSTRTAB; + + +/** + * Tries to ensure the buffer is terminated when failing. + */ +DECLINLINE(ssize_t) RTBldProgStrTabQueryStringFail(int rc, char *pszDstStart, char *pszDst, size_t cbDst) +{ + if (cbDst) + *pszDst = '\0'; + else if (pszDstStart != pszDst) + pszDst[-1] = '\0'; + return rc; +} + + +/** + * Retrieves the decompressed string. + * + * @returns The string size on success, IPRT status code on failure. + * @param pStrTab The string table. + * @param offString The offset of the string. + * @param cchString The length of the string. + * @param pszDst The return buffer. + * @param cbDst The size of the return buffer. + */ +DECLINLINE(ssize_t) RTBldProgStrTabQueryString(PCRTBLDPROGSTRTAB pStrTab, uint32_t offString, size_t cchString, + char *pszDst, size_t cbDst) +{ + AssertReturn(offString < pStrTab->cchStrTab, VERR_OUT_OF_RANGE); + AssertReturn(offString + cchString <= pStrTab->cchStrTab, VERR_OUT_OF_RANGE); + + if (pStrTab->cCompDict) + { + Assert(pStrTab->cCompDict == 256 || pStrTab->cCompDict == 255); + + /* + * Is compressed, decompress it. + */ + char * const pchDstStart = pszDst; + const char *pchSrc = &pStrTab->pchStrTab[offString]; + while (cchString-- > 0) + { + unsigned char uch = *(unsigned char *)pchSrc++; + if (uch != 0xff || pStrTab->cCompDict > 0xff) + { + /* + * Look it up in the dictionary, either a single 7-bit character or a word. + * Either way, no UTF-8 unescaping necessary. + */ + PCRTBLDPROGSTRREF pWord = &pStrTab->paCompDict[uch]; + size_t const cchWord = pWord->cch; + if (cchWord <= 1) + { + Assert(uch != 0); + Assert(uch <= 127); + AssertReturn(cbDst > 1, RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst)); + cbDst -= 1; + *pszDst++ = (char)uch; + } + else + { + Assert(cchWord > 1); + AssertReturn((size_t)pWord->off + cchWord <= pStrTab->cchStrTab, + RTBldProgStrTabQueryStringFail(VERR_INVALID_PARAMETER, pchDstStart, pszDst, cbDst)); + AssertReturn(cbDst > cchWord, + RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst)); + memcpy(pszDst, &pStrTab->pchStrTab[pWord->off], cchWord); + pszDst += cchWord; + cbDst -= cchWord; + } + } + else + { + /* + * UTF-8 encoded unicode codepoint. + */ + size_t cchCp; + RTUNICP uc = ' '; + int rc = RTStrGetCpNEx(&pchSrc, &cchString, &uc); + AssertStmt(RT_SUCCESS(rc), (uc = '?', pchSrc++, cchString--)); + + cchCp = RTStrCpSize(uc); + AssertReturn(cbDst > cchCp, + RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst)); + + RTStrPutCp(pszDst, uc); + pszDst += cchCp; + cbDst -= cchCp; + } + } + AssertReturn(cbDst > 0, RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst)); + *pszDst = '\0'; + return pszDst - pchDstStart; + } + + /* + * Not compressed. + */ + if (cbDst > cchString) + { + memcpy(pszDst, &pStrTab->pchStrTab[offString], cchString); + pszDst[cchString] = '\0'; + return (ssize_t)cchString; + } + if (cbDst > 0) + { + memcpy(pszDst, &pStrTab->pchStrTab[offString], cbDst - 1); + pszDst[cbDst - 1] = '\0'; + } + return VERR_BUFFER_OVERFLOW; +} + + +/** + * Outputs the decompressed string. + * + * @returns The sum of the pfnOutput return values. + * @param pStrTab The string table. + * @param offString The offset of the string. + * @param cchString The length of the string. + * @param pfnOutput The output function. + * @param pvArgOutput The argument to pass to the output function. + * + */ +DECLINLINE(size_t) RTBldProgStrTabQueryOutput(PCRTBLDPROGSTRTAB pStrTab, uint32_t offString, size_t cchString, + PFNRTSTROUTPUT pfnOutput, void *pvArgOutput) +{ + AssertReturn(offString < pStrTab->cchStrTab, 0); + AssertReturn(offString + cchString <= pStrTab->cchStrTab, 0); + + if (pStrTab->cCompDict) + { + Assert(pStrTab->cCompDict == 256 || pStrTab->cCompDict == 255); + + /* + * Could be compressed, decompress it. + */ + size_t cchRet = 0; + const char *pchSrc = &pStrTab->pchStrTab[offString]; + while (cchString-- > 0) + { + unsigned char uch = *(unsigned char *)pchSrc++; + if (uch != 0xff || pStrTab->cCompDict > 0xff) + { + /* + * Look it up in the dictionary, either a single 7-bit character or a word. + * Either way, no UTF-8 unescaping necessary. + */ + PCRTBLDPROGSTRREF pWord = &pStrTab->paCompDict[uch]; + size_t const cchWord = pWord->cch; + if (cchWord <= 1) + { + Assert(uch != 0); + Assert(uch <= 127); + cchRet += pfnOutput(pvArgOutput, (const char *)&uch, 1); + } + else + { + Assert(cchWord > 1); + AssertReturn((size_t)pWord->off + cchWord <= pStrTab->cchStrTab, cchRet); + + cchRet += pfnOutput(pvArgOutput, &pStrTab->pchStrTab[pWord->off], cchWord); + } + } + else + { + /* + * UTF-8 encoded unicode codepoint. + */ + const char * const pchUtf8Seq = pchSrc; + RTUNICP uc = ' '; + int rc = RTStrGetCpNEx(&pchSrc, &cchString, &uc); + if (RT_SUCCESS(rc)) + cchRet += pfnOutput(pvArgOutput, pchUtf8Seq, (size_t)(pchSrc - pchUtf8Seq)); + else + cchRet += pfnOutput(pvArgOutput, "?", 1); + } + } + return cchRet; + } + + /* + * Not compressed. + */ + return pfnOutput(pvArgOutput, &pStrTab->pchStrTab[offString], cchString); +} + + +#endif /* !IPRT_INCLUDED_bldprog_strtab_h */ + diff --git a/include/iprt/buildconfig.h b/include/iprt/buildconfig.h new file mode 100644 index 00000000..b5292d0c --- /dev/null +++ b/include/iprt/buildconfig.h @@ -0,0 +1,138 @@ +/** @file + * IPRT - Build Configuration Information + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_buildconfig_h +#define IPRT_INCLUDED_buildconfig_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_buildconfig RTBldCfg - Build Configuration Information + * @ingroup grp_rt + * @{ + */ + +/** + * Gets the source code management revision of the IPRT build. + * @returns Source code management revision number. + */ +RTDECL(uint32_t) RTBldCfgRevision(void); + +/** + * Gets the source code management revision of the IPRT build. + * @returns Read only string containing the revision number. + */ +RTDECL(const char *) RTBldCfgRevisionStr(void); + +/** + * Gets the product version string. + * + * This will be a string on the form "x.y.z[_string]". + * + * @returns Read only version string. + * + * @remarks This is a build time configuration thing that the product using IPRT + * will set. It is therefore not any IPRT version, but rather the + * version of that product. + */ +RTDECL(const char *) RTBldCfgVersion(void); + +/** + * Gets the major product version number. + * @returns Major product version number. + * @remarks See RTBldCfgVersion. + */ +RTDECL(uint32_t) RTBldCfgVersionMajor(void); + +/** + * Gets the minor product version number. + * @returns Minor product version number. + * @remarks See RTBldCfgVersion. + */ +RTDECL(uint32_t) RTBldCfgVersionMinor(void); + +/** + * Gets the product build number. + * @returns Product build number. + * @remarks See RTBldCfgVersion. + */ +RTDECL(uint32_t) RTBldCfgVersionBuild(void); + +/** + * Gets the build target name. + * + * @returns Read only build target string. + */ +RTDECL(const char *) RTBldCfgTarget(void); + +/** + * Gets the build target architecture name. + * + * @returns Read only build target architecture string. + */ +RTDECL(const char *) RTBldCfgTargetArch(void); + +/** + * Gets the build target-dot-architecture name. + * + * @returns Read only build target-dot-architecture string. + */ +RTDECL(const char *) RTBldCfgTargetDotArch(void); + +/** + * Gets the build type name. + * + * @returns Read only build type string. + */ +RTDECL(const char *) RTBldCfgType(void); + +/** + * Gets the name of the compiler used for building IPRT. + * + * @returns Read only compiler name. + */ +RTDECL(const char *) RTBldCfgCompiler(void); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_buildconfig_h */ + diff --git a/include/iprt/cdefs.h b/include/iprt/cdefs.h new file mode 100644 index 00000000..8fe26f69 --- /dev/null +++ b/include/iprt/cdefs.h @@ -0,0 +1,4901 @@ +/** @file + * IPRT - Common C and C++ definitions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cdefs_h +#define IPRT_INCLUDED_cdefs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/** @defgroup grp_rt_cdefs IPRT Common Definitions and Macros + * @{ + */ + +/** @def RT_C_DECLS_BEGIN + * Used to start a block of function declarations which are shared + * between C and C++ program. + */ + +/** @def RT_C_DECLS_END + * Used to end a block of function declarations which are shared + * between C and C++ program. + */ + +#if defined(__cplusplus) +# define RT_C_DECLS_BEGIN extern "C" { +# define RT_C_DECLS_END } +#else +# define RT_C_DECLS_BEGIN +# define RT_C_DECLS_END +#endif + + +/* + * Shut up DOXYGEN warnings and guide it properly thru the code. + */ +#ifdef DOXYGEN_RUNNING +# define __AMD64__ +# define __X86__ +# define RT_ARCH_AMD64 +# define RT_ARCH_X86 +# define RT_ARCH_SPARC +# define RT_ARCH_SPARC64 +# define RT_ARCH_ARM32 +# define RT_ARCH_ARM64 +# define IN_RING0 +# define IN_RING3 +# define IN_RC +# define IN_RT_RC +# define IN_RT_R0 +# define IN_RT_R3 +# define IN_RT_STATIC +# define RT_STRICT +# define RT_NO_STRICT +# define RT_LOCK_STRICT +# define RT_LOCK_NO_STRICT +# define RT_LOCK_STRICT_ORDER +# define RT_LOCK_NO_STRICT_ORDER +# define RT_BREAKPOINT +# define RT_NO_DEPRECATED_MACROS +# define RT_EXCEPTIONS_ENABLED +# define RT_BIG_ENDIAN +# define RT_LITTLE_ENDIAN +# define RT_COMPILER_GROKS_64BIT_BITFIELDS +# define RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_128BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_128BIT_INT_TYPES +# define RT_NO_VISIBILITY_HIDDEN +# define RT_GCC_SUPPORTS_VISIBILITY_HIDDEN +# define RT_COMPILER_SUPPORTS_VA_ARGS +# define RT_COMPILER_SUPPORTS_LAMBDA +#endif /* DOXYGEN_RUNNING */ + +/** @def RT_ARCH_X86 + * Indicates that we're compiling for the X86 architecture. + */ + +/** @def RT_ARCH_AMD64 + * Indicates that we're compiling for the AMD64 architecture. + */ + +/** @def RT_ARCH_SPARC + * Indicates that we're compiling for the SPARC V8 architecture (32-bit). + */ + +/** @def RT_ARCH_SPARC64 + * Indicates that we're compiling for the SPARC V9 architecture (64-bit). + */ + +/** @def RT_ARCH_ARM32 + * Indicates that we're compiling for the 32-bit ARM architecture, the value + * is the version (i.e. 6 for ARMv6). + */ + +/** @def RT_ARCH_ARM64 + * Indicates that we're compiling for the 64-bit ARM architecture. + */ + +#if !defined(RT_ARCH_X86) \ + && !defined(RT_ARCH_AMD64) \ + && !defined(RT_ARCH_SPARC) \ + && !defined(RT_ARCH_SPARC64) \ + && !defined(RT_ARCH_ARM32) \ + && !defined(RT_ARCH_ARM64) +# if defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) || defined(__AMD64__) +# define RT_ARCH_AMD64 +# elif defined(__i386__) || defined(_M_IX86) || defined(__X86__) +# define RT_ARCH_X86 +# elif defined(__sparcv9) +# define RT_ARCH_SPARC64 +# elif defined(__sparc__) +# define RT_ARCH_SPARC +# elif defined(__arm64__) || defined(__aarch64__) +# define RT_ARCH_ARM64 __ARM_ARCH +# elif defined(__arm__) +# define RT_ARCH_ARM32 __ARM_ARCH +# elif defined(__arm32__) +# define RT_ARCH_ARM32 __ARM_ARCH +# else /* PORTME: append test for new archs. */ +# error "Check what predefined macros your compiler uses to indicate architecture." +# endif +/* PORTME: append new archs checks. */ +#elif defined(RT_ARCH_X86) && defined(RT_ARCH_AMD64) +# error "Both RT_ARCH_X86 and RT_ARCH_AMD64 cannot be defined at the same time!" +#elif defined(RT_ARCH_X86) && defined(RT_ARCH_SPARC) +# error "Both RT_ARCH_X86 and RT_ARCH_SPARC cannot be defined at the same time!" +#elif defined(RT_ARCH_X86) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_X86 and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_AMD64) && defined(RT_ARCH_SPARC) +# error "Both RT_ARCH_AMD64 and RT_ARCH_SPARC cannot be defined at the same time!" +#elif defined(RT_ARCH_AMD64) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_AMD64 and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_SPARC) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_SPARC and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM32) && defined(RT_ARCH_AMD64) +# error "Both RT_ARCH_ARM32 and RT_ARCH_AMD64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM32) && defined(RT_ARCH_X86) +# error "Both RT_ARCH_ARM32 and RT_ARCH_X86 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM32) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_ARM32 and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM32) && defined(RT_ARCH_SPARC) +# error "Both RT_ARCH_ARM32 and RT_ARCH_SPARC cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_AMD64) +# error "Both RT_ARCH_ARM64 and RT_ARCH_AMD64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_X86) +# error "Both RT_ARCH_ARM64 and RT_ARCH_X86 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_ARM64 and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_SPARC) +# error "Both RT_ARCH_ARM64 and RT_ARCH_SPARC cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_ARM32) +# error "Both RT_ARCH_ARM64 and RT_ARCH_ARM32 cannot be defined at the same time!" +#endif +#ifdef RT_ARCH_ARM +# error "RT_ARCH_ARM is now RT_ARCH_ARM32!" +#endif + +/* Final check (PORTME). */ +#if (defined(RT_ARCH_X86) != 0) \ + + (defined(RT_ARCH_AMD64) != 0) \ + + (defined(RT_ARCH_SPARC) != 0) \ + + (defined(RT_ARCH_SPARC64) != 0) \ + + (defined(RT_ARCH_ARM32) != 0) \ + + (defined(RT_ARCH_ARM64) != 0) \ + != 1 +# error "Exactly one RT_ARCH_XXX macro shall be defined" +#endif + +/** @def RT_CPLUSPLUS_PREREQ + * Require a minimum __cplusplus value, simplifying dealing with non-C++ code. + * + * @param a_Min The minimum version, e.g. 201100. + */ +#ifdef __cplusplus +# define RT_CPLUSPLUS_PREREQ(a_Min) (__cplusplus >= (a_Min)) +#else +# define RT_CPLUSPLUS_PREREQ(a_Min) (0) +#endif + +/** @def RT_GNUC_PREREQ + * Shorter than fiddling with __GNUC__ and __GNUC_MINOR__. + * + * @param a_MinMajor Minimum major version + * @param a_MinMinor The minor version number part. + */ +#define RT_GNUC_PREREQ(a_MinMajor, a_MinMinor) RT_GNUC_PREREQ_EX(a_MinMajor, a_MinMinor, 0) +/** @def RT_GNUC_PREREQ_EX + * Simplified way of checking __GNUC__ and __GNUC_MINOR__ regardless of actual + * compiler used, returns @a a_OtherRet for other compilers. + * + * @param a_MinMajor Minimum major version + * @param a_MinMinor The minor version number part. + * @param a_OtherRet What to return for non-GCC compilers. + */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define RT_GNUC_PREREQ_EX(a_MinMajor, a_MinMinor, a_OtherRet) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((a_MinMajor) << 16) + (a_MinMinor)) +#else +# define RT_GNUC_PREREQ_EX(a_MinMajor, a_MinMinor, a_OtherRet) (a_OtherRet) +#endif + +/** @def RT_MSC_PREREQ + * Convenient way of checking _MSC_VER regardless of actual compiler used + * (returns false if not MSC). + * + * @param a_MinVer Preferably a RT_MSC_VER_XXX value. + */ +#define RT_MSC_PREREQ(a_MinVer) RT_MSC_PREREQ_EX(a_MinVer, 0) +/** @def RT_MSC_PREREQ_EX + * Convenient way of checking _MSC_VER regardless of actual compiler used, + * returns @a a_OtherRet for other compilers. + * + * @param a_MinVer Preferably a RT_MSC_VER_XXX value. + * @param a_OtherRet What to return for non-MSC compilers. + */ +#if defined(_MSC_VER) +# define RT_MSC_PREREQ_EX(a_MinVer, a_OtherRet) ( (_MSC_VER) >= (a_MinVer) ) +#else +# define RT_MSC_PREREQ_EX(a_MinVer, a_OtherRet) (a_OtherRet) +#endif +/** @name RT_MSC_VER_XXX - _MSC_VER values to use with RT_MSC_PREREQ. + * @remarks The VCxxx values are derived from the CRT DLLs shipping with the + * compilers. + * @{ */ +#define RT_MSC_VER_VC50 (1100) /**< Visual C++ 5.0. */ +#define RT_MSC_VER_VC60 (1200) /**< Visual C++ 6.0. */ +#define RT_MSC_VER_VC70 (1300) /**< Visual C++ 7.0. */ +#define RT_MSC_VER_VC70 (1300) /**< Visual C++ 7.0. */ +#define RT_MSC_VER_VS2003 (1310) /**< Visual Studio 2003, aka Visual C++ 7.1. */ +#define RT_MSC_VER_VC71 RT_MSC_VER_VS2003 /**< Visual C++ 7.1, aka Visual Studio 2003. */ +#define RT_MSC_VER_VS2005 (1400) /**< Visual Studio 2005. */ +#define RT_MSC_VER_VC80 RT_MSC_VER_VS2005 /**< Visual C++ 8.0, aka Visual Studio 2008. */ +#define RT_MSC_VER_VS2008 (1500) /**< Visual Studio 2008. */ +#define RT_MSC_VER_VC90 RT_MSC_VER_VS2008 /**< Visual C++ 9.0, aka Visual Studio 2008. */ +#define RT_MSC_VER_VS2010 (1600) /**< Visual Studio 2010. */ +#define RT_MSC_VER_VC100 RT_MSC_VER_VS2010 /**< Visual C++ 10.0, aka Visual Studio 2010. */ +#define RT_MSC_VER_VS2012 (1700) /**< Visual Studio 2012. */ +#define RT_MSC_VER_VC110 RT_MSC_VER_VS2012 /**< Visual C++ 11.0, aka Visual Studio 2012. */ +#define RT_MSC_VER_VS2013 (1800) /**< Visual Studio 2013. */ +#define RT_MSC_VER_VC120 RT_MSC_VER_VS2013 /**< Visual C++ 12.0, aka Visual Studio 2013. */ +#define RT_MSC_VER_VS2015 (1900) /**< Visual Studio 2015. */ +#define RT_MSC_VER_VC140 RT_MSC_VER_VS2015 /**< Visual C++ 14.0, aka Visual Studio 2015. */ +#define RT_MSC_VER_VS2017 (1910) /**< Visual Studio 2017. */ +#define RT_MSC_VER_VC141 RT_MSC_VER_VS2017 /**< Visual C++ 14.1, aka Visual Studio 2017. */ +#define RT_MSC_VER_VS2019 (1920) /**< Visual Studio 2019. */ +#define RT_MSC_VER_VC142 RT_MSC_VER_VS2019 /**< Visual C++ 14.2, aka Visual Studio 2019. */ +#define RT_MSC_VER_VS2019_U6 (1926) /**< Visual Studio 2019, update 6. */ +#define RT_MSC_VER_VC142_U6 RT_MSC_VER_VS2019_U6 /**< Visual C++ 14.2 update 6. */ +#define RT_MSC_VER_VS2019_U8 (1928) /**< Visual Studio 2019, update 8. */ +#define RT_MSC_VER_VC142_U8 RT_MSC_VER_VS2019_U8 /**< Visual C++ 14.2 update 8. */ +#define RT_MSC_VER_VS2019_U11 (1929) /**< Visual Studio 2019, update 11. */ +#define RT_MSC_VER_VC142_U11 RT_MSC_VER_VS2019_U11 /**< Visual C++ 14.2 update 11. */ +/** @} */ + +/** @def RT_CLANG_PREREQ + * Shorter than fiddling with __clang_major__ and __clang_minor__. + * + * @param a_MinMajor Minimum major version + * @param a_MinMinor The minor version number part. + */ +#define RT_CLANG_PREREQ(a_MinMajor, a_MinMinor) RT_CLANG_PREREQ_EX(a_MinMajor, a_MinMinor, 0) +/** @def RT_CLANG_PREREQ_EX + * Simplified way of checking __clang_major__ and __clang_minor__ regardless of + * actual compiler used, returns @a a_OtherRet for other compilers. + * + * @param a_MinMajor Minimum major version + * @param a_MinMinor The minor version number part. + * @param a_OtherRet What to return for non-GCC compilers. + */ +#if defined(__clang_major__) && defined(__clang_minor__) +# define RT_CLANG_PREREQ_EX(a_MinMajor, a_MinMinor, a_OtherRet) \ + ((__clang_major__ << 16) + __clang_minor__ >= ((a_MinMajor) << 16) + (a_MinMinor)) +#else +# define RT_CLANG_PREREQ_EX(a_MinMajor, a_MinMinor, a_OtherRet) (a_OtherRet) +#endif +/** @def RT_CLANG_HAS_FEATURE + * Wrapper around clang's __has_feature(). + * + * @param a_Feature The feature to check for. + */ +#if defined(__clang_major__) && defined(__clang_minor__) && defined(__has_feature) +# define RT_CLANG_HAS_FEATURE(a_Feature) (__has_feature(a_Feature)) +#else +# define RT_CLANG_HAS_FEATURE(a_Feature) (0) +#endif + + +#if !defined(__X86__) && !defined(__AMD64__) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) +# if defined(RT_ARCH_AMD64) +/** Indicates that we're compiling for the AMD64 architecture. + * @deprecated + */ +# define __AMD64__ +# elif defined(RT_ARCH_X86) +/** Indicates that we're compiling for the X86 architecture. + * @deprecated + */ +# define __X86__ +# else +# error "Check what predefined macros your compiler uses to indicate architecture." +# endif +#elif defined(__X86__) && defined(__AMD64__) +# error "Both __X86__ and __AMD64__ cannot be defined at the same time!" +#elif defined(__X86__) && !defined(RT_ARCH_X86) +# error "__X86__ without RT_ARCH_X86!" +#elif defined(__AMD64__) && !defined(RT_ARCH_AMD64) +# error "__AMD64__ without RT_ARCH_AMD64!" +#endif + +/** @def RT_BIG_ENDIAN + * Defined if the architecture is big endian. */ +/** @def RT_LITTLE_ENDIAN + * Defined if the architecture is little endian. */ +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) || defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) +# define RT_LITTLE_ENDIAN +#elif defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) +# define RT_BIG_ENDIAN +#else +# error "PORTME: architecture endianess" +#endif +#if defined(RT_BIG_ENDIAN) && defined(RT_LITTLE_ENDIAN) +# error "Both RT_BIG_ENDIAN and RT_LITTLE_ENDIAN are defined" +#endif + + +/** @def IN_RING0 + * Used to indicate that we're compiling code which is running + * in Ring-0 Host Context. + */ + +/** @def IN_RING3 + * Used to indicate that we're compiling code which is running + * in Ring-3 Host Context. + */ + +/** @def IN_RC + * Used to indicate that we're compiling code which is running + * in the Raw-mode Context (implies R0). + */ +#if !defined(IN_RING3) && !defined(IN_RING0) && !defined(IN_RC) +# error "You must define which context the compiled code should run in; IN_RING3, IN_RING0 or IN_RC" +#endif +#if (defined(IN_RING3) && (defined(IN_RING0) || defined(IN_RC)) ) \ + || (defined(IN_RING0) && (defined(IN_RING3) || defined(IN_RC)) ) \ + || (defined(IN_RC) && (defined(IN_RING3) || defined(IN_RING0)) ) +# error "Only one of the IN_RING3, IN_RING0, IN_RC defines should be defined." +#endif + + +/** @def ARCH_BITS + * Defines the bit count of the current context. + */ +#if !defined(ARCH_BITS) || defined(DOXYGEN_RUNNING) +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_SPARC64) || defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING) +# define ARCH_BITS 64 +# elif !defined(__I86__) || !defined(__WATCOMC__) +# define ARCH_BITS 32 +# else +# define ARCH_BITS 16 +# endif +#endif + +/* ARCH_BITS validation (PORTME). */ +#if ARCH_BITS == 64 + #if defined(RT_ARCH_X86) || defined(RT_ARCH_SPARC) || defined(RT_ARCH_ARM32) + # error "ARCH_BITS=64 but non-64-bit RT_ARCH_XXX defined." + #endif + #if !defined(RT_ARCH_AMD64) && !defined(RT_ARCH_SPARC64) && !defined(RT_ARCH_ARM64) + # error "ARCH_BITS=64 but no 64-bit RT_ARCH_XXX defined." + #endif + +#elif ARCH_BITS == 32 + #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_SPARC64) || defined(RT_ARCH_ARM64) + # error "ARCH_BITS=32 but non-32-bit RT_ARCH_XXX defined." + #endif + #if !defined(RT_ARCH_X86) && !defined(RT_ARCH_SPARC) && !defined(RT_ARCH_ARM32) + # error "ARCH_BITS=32 but no 32-bit RT_ARCH_XXX defined." + #endif + +#elif ARCH_BITS == 16 + #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) || defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + # error "ARCH_BITS=16 but non-16-bit RT_ARCH_XX defined." + #endif + #if !defined(RT_ARCH_X86) + # error "ARCH_BITS=16 but RT_ARCH_X86 isn't defined." + #endif + +#else +# error "Unsupported ARCH_BITS value!" +#endif + +/** @def HC_ARCH_BITS + * Defines the host architecture bit count. + */ +#if !defined(HC_ARCH_BITS) || defined(DOXYGEN_RUNNING) +# if !defined(IN_RC) || defined(DOXYGEN_RUNNING) +# define HC_ARCH_BITS ARCH_BITS +# else +# define HC_ARCH_BITS 32 +# endif +#endif + +/** @def GC_ARCH_BITS + * Defines the guest architecture bit count. + */ +#if !defined(GC_ARCH_BITS) || defined(DOXYGEN_RUNNING) +# if defined(VBOX_WITH_64_BITS_GUESTS) || defined(DOXYGEN_RUNNING) +# define GC_ARCH_BITS 64 +# else +# define GC_ARCH_BITS 32 +# endif +#endif + +/** @def R3_ARCH_BITS + * Defines the host ring-3 architecture bit count. + */ +#if !defined(R3_ARCH_BITS) || defined(DOXYGEN_RUNNING) +# ifdef IN_RING3 +# define R3_ARCH_BITS ARCH_BITS +# else +# define R3_ARCH_BITS HC_ARCH_BITS +# endif +#endif + +/** @def R0_ARCH_BITS + * Defines the host ring-0 architecture bit count. + */ +#if !defined(R0_ARCH_BITS) || defined(DOXYGEN_RUNNING) +# ifdef IN_RING0 +# define R0_ARCH_BITS ARCH_BITS +# else +# define R0_ARCH_BITS HC_ARCH_BITS +# endif +#endif + + + +/** @name RT_OPSYS_XXX - Operative System Identifiers. + * These are the value that the RT_OPSYS \#define can take. @{ + */ +/** Unknown OS. */ +#define RT_OPSYS_UNKNOWN 0 +/** OS Agnostic. */ +#define RT_OPSYS_AGNOSTIC 1 +/** Darwin - aka Mac OS X. */ +#define RT_OPSYS_DARWIN 2 +/** DragonFly BSD. */ +#define RT_OPSYS_DRAGONFLY 3 +/** DOS. */ +#define RT_OPSYS_DOS 4 +/** FreeBSD. */ +#define RT_OPSYS_FREEBSD 5 +/** Haiku. */ +#define RT_OPSYS_HAIKU 6 +/** Linux. */ +#define RT_OPSYS_LINUX 7 +/** L4. */ +#define RT_OPSYS_L4 8 +/** Minix. */ +#define RT_OPSYS_MINIX 9 +/** NetBSD. */ +#define RT_OPSYS_NETBSD 11 +/** Netware. */ +#define RT_OPSYS_NETWARE 12 +/** NT (native). */ +#define RT_OPSYS_NT 13 +/** OpenBSD. */ +#define RT_OPSYS_OPENBSD 14 +/** OS/2. */ +#define RT_OPSYS_OS2 15 +/** Plan 9. */ +#define RT_OPSYS_PLAN9 16 +/** QNX. */ +#define RT_OPSYS_QNX 17 +/** Solaris. */ +#define RT_OPSYS_SOLARIS 18 +/** UEFI. */ +#define RT_OPSYS_UEFI 19 +/** Windows. */ +#define RT_OPSYS_WINDOWS 20 +/** The max RT_OPSYS_XXX value (exclusive). */ +#define RT_OPSYS_MAX 21 +/** @} */ + +/** @def RT_OPSYS + * Indicates which OS we're targeting. It's a \#define with is + * assigned one of the RT_OPSYS_XXX defines above. + * + * So to test if we're on FreeBSD do the following: + * @code + * #if RT_OPSYS == RT_OPSYS_FREEBSD + * some_funky_freebsd_specific_stuff(); + * #endif + * @endcode + */ + +/* + * Set RT_OPSYS_XXX according to RT_OS_XXX. + * + * Search: #define RT_OPSYS_([A-Z0-9]+) .* + * Replace: # elif defined(RT_OS_\1)\n# define RT_OPSYS RT_OPSYS_\1 + */ +#ifndef RT_OPSYS +# if defined(RT_OS_UNKNOWN) || defined(DOXYGEN_RUNNING) +# define RT_OPSYS RT_OPSYS_UNKNOWN +# elif defined(RT_OS_AGNOSTIC) +# define RT_OPSYS RT_OPSYS_AGNOSTIC +# elif defined(RT_OS_DARWIN) +# define RT_OPSYS RT_OPSYS_DARWIN +# elif defined(RT_OS_DRAGONFLY) +# define RT_OPSYS RT_OPSYS_DRAGONFLY +# elif defined(RT_OS_DOS) +# define RT_OPSYS RT_OPSYS_DOS +# elif defined(RT_OS_FREEBSD) +# define RT_OPSYS RT_OPSYS_FREEBSD +# elif defined(RT_OS_HAIKU) +# define RT_OPSYS RT_OPSYS_HAIKU +# elif defined(RT_OS_LINUX) +# define RT_OPSYS RT_OPSYS_LINUX +# elif defined(RT_OS_L4) +# define RT_OPSYS RT_OPSYS_L4 +# elif defined(RT_OS_MINIX) +# define RT_OPSYS RT_OPSYS_MINIX +# elif defined(RT_OS_NETBSD) +# define RT_OPSYS RT_OPSYS_NETBSD +# elif defined(RT_OS_NETWARE) +# define RT_OPSYS RT_OPSYS_NETWARE +# elif defined(RT_OS_NT) +# define RT_OPSYS RT_OPSYS_NT +# elif defined(RT_OS_OPENBSD) +# define RT_OPSYS RT_OPSYS_OPENBSD +# elif defined(RT_OS_OS2) +# define RT_OPSYS RT_OPSYS_OS2 +# elif defined(RT_OS_PLAN9) +# define RT_OPSYS RT_OPSYS_PLAN9 +# elif defined(RT_OS_QNX) +# define RT_OPSYS RT_OPSYS_QNX +# elif defined(RT_OS_SOLARIS) +# define RT_OPSYS RT_OPSYS_SOLARIS +# elif defined(RT_OS_UEFI) +# define RT_OPSYS RT_OPSYS_UEFI +# elif defined(RT_OS_WINDOWS) +# define RT_OPSYS RT_OPSYS_WINDOWS +# endif +#endif + +/* + * Guess RT_OPSYS based on compiler predefined macros. + */ +#ifndef RT_OPSYS +# if defined(__APPLE__) +# define RT_OPSYS RT_OPSYS_DARWIN +# elif defined(__DragonFly__) +# define RT_OPSYS RT_OPSYS_DRAGONFLY +# elif defined(__FreeBSD__) /*??*/ +# define RT_OPSYS RT_OPSYS_FREEBSD +# elif defined(__gnu_linux__) +# define RT_OPSYS RT_OPSYS_LINUX +# elif defined(__NetBSD__) /*??*/ +# define RT_OPSYS RT_OPSYS_NETBSD +# elif defined(__OpenBSD__) /*??*/ +# define RT_OPSYS RT_OPSYS_OPENBSD +# elif defined(__OS2__) +# define RT_OPSYS RT_OPSYS_OS2 +# elif defined(__sun__) || defined(__SunOS__) || defined(__sun) || defined(__SunOS) +# define RT_OPSYS RT_OPSYS_SOLARIS +# elif defined(_WIN32) || defined(_WIN64) +# define RT_OPSYS RT_OPSYS_WINDOWS +# elif defined(MSDOS) || defined(_MSDOS) || defined(DOS16RM) /* OW+MSC || MSC || DMC */ +# define RT_OPSYS RT_OPSYS_DOS +# else +# error "Port Me" +# endif +#endif + +#if RT_OPSYS < RT_OPSYS_UNKNOWN || RT_OPSYS >= RT_OPSYS_MAX +# error "Invalid RT_OPSYS value." +#endif + +/* + * Do some consistency checks. + * + * Search: #define RT_OPSYS_([A-Z0-9]+) .* + * Replace: #if defined(RT_OS_\1) && RT_OPSYS != RT_OPSYS_\1\n# error RT_OPSYS vs RT_OS_\1\n#endif + */ +#if defined(RT_OS_UNKNOWN) && RT_OPSYS != RT_OPSYS_UNKNOWN +# error RT_OPSYS vs RT_OS_UNKNOWN +#endif +#if defined(RT_OS_AGNOSTIC) && RT_OPSYS != RT_OPSYS_AGNOSTIC +# error RT_OPSYS vs RT_OS_AGNOSTIC +#endif +#if defined(RT_OS_DARWIN) && RT_OPSYS != RT_OPSYS_DARWIN +# error RT_OPSYS vs RT_OS_DARWIN +#endif +#if defined(RT_OS_DRAGONFLY) && RT_OPSYS != RT_OPSYS_DRAGONFLY +# error RT_OPSYS vs RT_OS_DRAGONFLY +#endif +#if defined(RT_OS_DOS) && RT_OPSYS != RT_OPSYS_DOS +# error RT_OPSYS vs RT_OS_DOS +#endif +#if defined(RT_OS_FREEBSD) && RT_OPSYS != RT_OPSYS_FREEBSD +# error RT_OPSYS vs RT_OS_FREEBSD +#endif +#if defined(RT_OS_HAIKU) && RT_OPSYS != RT_OPSYS_HAIKU +# error RT_OPSYS vs RT_OS_HAIKU +#endif +#if defined(RT_OS_LINUX) && RT_OPSYS != RT_OPSYS_LINUX +# error RT_OPSYS vs RT_OS_LINUX +#endif +#if defined(RT_OS_L4) && RT_OPSYS != RT_OPSYS_L4 +# error RT_OPSYS vs RT_OS_L4 +#endif +#if defined(RT_OS_MINIX) && RT_OPSYS != RT_OPSYS_MINIX +# error RT_OPSYS vs RT_OS_MINIX +#endif +#if defined(RT_OS_NETBSD) && RT_OPSYS != RT_OPSYS_NETBSD +# error RT_OPSYS vs RT_OS_NETBSD +#endif +#if defined(RT_OS_NETWARE) && RT_OPSYS != RT_OPSYS_NETWARE +# error RT_OPSYS vs RT_OS_NETWARE +#endif +#if defined(RT_OS_NT) && RT_OPSYS != RT_OPSYS_NT +# error RT_OPSYS vs RT_OS_NT +#endif +#if defined(RT_OS_OPENBSD) && RT_OPSYS != RT_OPSYS_OPENBSD +# error RT_OPSYS vs RT_OS_OPENBSD +#endif +#if defined(RT_OS_OS2) && RT_OPSYS != RT_OPSYS_OS2 +# error RT_OPSYS vs RT_OS_OS2 +#endif +#if defined(RT_OS_PLAN9) && RT_OPSYS != RT_OPSYS_PLAN9 +# error RT_OPSYS vs RT_OS_PLAN9 +#endif +#if defined(RT_OS_QNX) && RT_OPSYS != RT_OPSYS_QNX +# error RT_OPSYS vs RT_OS_QNX +#endif +#if defined(RT_OS_SOLARIS) && RT_OPSYS != RT_OPSYS_SOLARIS +# error RT_OPSYS vs RT_OS_SOLARIS +#endif +#if defined(RT_OS_UEFI) && RT_OPSYS != RT_OPSYS_UEFI +# error RT_OPSYS vs RT_OS_UEFI +#endif +#if defined(RT_OS_WINDOWS) && RT_OPSYS != RT_OPSYS_WINDOWS +# error RT_OPSYS vs RT_OS_WINDOWS +#endif + +/* + * Make sure the RT_OS_XXX macro is defined. + * + * Search: #define RT_OPSYS_([A-Z0-9]+) .* + * Replace: #elif RT_OPSYS == RT_OPSYS_\1\n# ifndef RT_OS_\1\n# define RT_OS_\1\n# endif + */ +#if RT_OPSYS == RT_OPSYS_UNKNOWN +# ifndef RT_OS_UNKNOWN +# define RT_OS_UNKNOWN +# endif +#elif RT_OPSYS == RT_OPSYS_AGNOSTIC +# ifndef RT_OS_AGNOSTIC +# define RT_OS_AGNOSTIC +# endif +#elif RT_OPSYS == RT_OPSYS_DARWIN +# ifndef RT_OS_DARWIN +# define RT_OS_DARWIN +# endif +#elif RT_OPSYS == RT_OPSYS_DRAGONFLY +# ifndef RT_OS_DRAGONFLY +# define RT_OS_DRAGONFLY +# endif +#elif RT_OPSYS == RT_OPSYS_DOS +# ifndef RT_OS_DOS +# define RT_OS_DOS +# endif +#elif RT_OPSYS == RT_OPSYS_FREEBSD +# ifndef RT_OS_FREEBSD +# define RT_OS_FREEBSD +# endif +#elif RT_OPSYS == RT_OPSYS_HAIKU +# ifndef RT_OS_HAIKU +# define RT_OS_HAIKU +# endif +#elif RT_OPSYS == RT_OPSYS_LINUX +# ifndef RT_OS_LINUX +# define RT_OS_LINUX +# endif +#elif RT_OPSYS == RT_OPSYS_L4 +# ifndef RT_OS_L4 +# define RT_OS_L4 +# endif +#elif RT_OPSYS == RT_OPSYS_MINIX +# ifndef RT_OS_MINIX +# define RT_OS_MINIX +# endif +#elif RT_OPSYS == RT_OPSYS_NETBSD +# ifndef RT_OS_NETBSD +# define RT_OS_NETBSD +# endif +#elif RT_OPSYS == RT_OPSYS_NETWARE +# ifndef RT_OS_NETWARE +# define RT_OS_NETWARE +# endif +#elif RT_OPSYS == RT_OPSYS_NT +# ifndef RT_OS_NT +# define RT_OS_NT +# endif +#elif RT_OPSYS == RT_OPSYS_OPENBSD +# ifndef RT_OS_OPENBSD +# define RT_OS_OPENBSD +# endif +#elif RT_OPSYS == RT_OPSYS_OS2 +# ifndef RT_OS_OS2 +# define RT_OS_OS2 +# endif +#elif RT_OPSYS == RT_OPSYS_PLAN9 +# ifndef RT_OS_PLAN9 +# define RT_OS_PLAN9 +# endif +#elif RT_OPSYS == RT_OPSYS_QNX +# ifndef RT_OS_QNX +# define RT_OS_QNX +# endif +#elif RT_OPSYS == RT_OPSYS_SOLARIS +# ifndef RT_OS_SOLARIS +# define RT_OS_SOLARIS +# endif +#elif RT_OPSYS == RT_OPSYS_UEFI +# ifndef RT_OS_UEFI +# define RT_OS_UEFI +# endif +#elif RT_OPSYS == RT_OPSYS_WINDOWS +# ifndef RT_OS_WINDOWS +# define RT_OS_WINDOWS +# endif +#else +# error "Bad RT_OPSYS value." +#endif + + +/** + * Checks whether the given OpSys uses DOS-style paths or not. + * + * By DOS-style paths we include drive lettering and UNC paths. + * + * @returns true / false + * @param a_OpSys The RT_OPSYS_XXX value to check, will be reference + * multiple times. + */ +#define RT_OPSYS_USES_DOS_PATHS(a_OpSys) \ + ( (a_OpSys) == RT_OPSYS_WINDOWS \ + || (a_OpSys) == RT_OPSYS_OS2 \ + || (a_OpSys) == RT_OPSYS_DOS ) + + + +/** @def CTXTYPE + * Declare a type differently in GC, R3 and R0. + * + * @param a_GCType The GC type. + * @param a_R3Type The R3 type. + * @param a_R0Type The R0 type. + * @remark For pointers used only in one context use RCPTRTYPE(), R3R0PTRTYPE(), R3PTRTYPE() or R0PTRTYPE(). + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXTYPE(a_GCType, a_R3Type, a_R0Type) a_GCType +#elif defined(IN_RING3) || defined(DOXYGEN_RUNNING) +# define CTXTYPE(a_GCType, a_R3Type, a_R0Type) a_R3Type +#else +# define CTXTYPE(a_GCType, a_R3Type, a_R0Type) a_R0Type +#endif + +/** @def CTX_EXPR + * Expression selector for avoiding \#ifdef's. + * + * @param a_R3Expr The R3 expression. + * @param a_R0Expr The R0 expression. + * @param a_RCExpr The RC expression. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTX_EXPR(a_R3Expr, a_R0Expr, a_RCExpr) a_RCExpr +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTX_EXPR(a_R3Expr, a_R0Expr, a_RCExpr) a_R0Expr +#else +# define CTX_EXPR(a_R3Expr, a_R0Expr, a_RCExpr) a_R3Expr +#endif + +/** @def RCPTRTYPE + * Declare a pointer which is used in the raw mode context but appears in structure(s) used by + * both HC and RC. The main purpose is to make sure structures have the same + * size when built for different architectures. + * + * @param a_RCType The RC type. + */ +#define RCPTRTYPE(a_RCType) CTXTYPE(a_RCType, RTRCPTR, RTRCPTR) + +/** @def RGPTRTYPE + * This will become RCPTRTYPE once we've converted all uses of RCPTRTYPE to this. + * + * @param a_RCType The RC type. + */ +#define RGPTRTYPE(a_RCType) CTXTYPE(a_RCType, RTGCPTR, RTGCPTR) + +/** @def R3R0PTRTYPE + * Declare a pointer which is used in HC, is explicitly valid in ring 3 and 0, + * but appears in structure(s) used by both HC and GC. The main purpose is to + * make sure structures have the same size when built for different architectures. + * + * @param a_R3R0Type The R3R0 type. + * @remarks This used to be called HCPTRTYPE. + */ +#define R3R0PTRTYPE(a_R3R0Type) CTXTYPE(RTHCPTR, a_R3R0Type, a_R3R0Type) + +/** @def R3PTRTYPE + * Declare a pointer which is used in R3 but appears in structure(s) used by + * both HC and GC. The main purpose is to make sure structures have the same + * size when built for different architectures. + * + * @param a_R3Type The R3 type. + */ +#define R3PTRTYPE(a_R3Type) CTXTYPE(RTHCUINTPTR, a_R3Type, RTHCUINTPTR) + +/** @def R0PTRTYPE + * Declare a pointer which is used in R0 but appears in structure(s) used by + * both HC and GC. The main purpose is to make sure structures have the same + * size when built for different architectures. + * + * @param a_R0Type The R0 type. + */ +#define R0PTRTYPE(a_R0Type) CTXTYPE(RTHCUINTPTR, RTHCUINTPTR, a_R0Type) + +/** @def CTXSUFF + * Adds the suffix of the current context to the passed in + * identifier name. The suffix is HC or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * @deprecated Use CTX_SUFF. Do NOT use this for new code. + */ +/** @def OTHERCTXSUFF + * Adds the suffix of the other context to the passed in + * identifier name. The suffix is HC or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * @deprecated Use CTX_SUFF. Do NOT use this for new code. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXSUFF(a_Var) a_Var##GC +# define OTHERCTXSUFF(a_Var) a_Var##HC +#else +# define CTXSUFF(a_Var) a_Var##HC +# define OTHERCTXSUFF(a_Var) a_Var##GC +#endif + +/** @def CTXALLSUFF + * Adds the suffix of the current context to the passed in + * identifier name. The suffix is R3, R0 or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * @deprecated Use CTX_SUFF. Do NOT use this for new code. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXALLSUFF(a_Var) a_Var##GC +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTXALLSUFF(a_Var) a_Var##R0 +#else +# define CTXALLSUFF(a_Var) a_Var##R3 +#endif + +/** @def CTX_SUFF + * Adds the suffix of the current context to the passed in + * identifier name. The suffix is R3, R0 or RC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * + * @remark This will replace CTXALLSUFF and CTXSUFF before long. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTX_SUFF(a_Var) a_Var##RC +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTX_SUFF(a_Var) a_Var##R0 +#else +# define CTX_SUFF(a_Var) a_Var##R3 +#endif + +/** @def CTX_SUFF_Z + * Adds the suffix of the current context to the passed in + * identifier name, combining RC and R0 into RZ. + * The suffix thus is R3 or RZ. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * + * @remark This will replace CTXALLSUFF and CTXSUFF before long. + */ +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +# define CTX_SUFF_Z(a_Var) a_Var##R3 +#else +# define CTX_SUFF_Z(a_Var) a_Var##RZ +#endif + + +/** @def CTXMID + * Adds the current context as a middle name of an identifier name + * The middle name is HC or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + */ +/** @def OTHERCTXMID + * Adds the other context as a middle name of an identifier name + * The middle name is HC or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + * @deprecated use CTX_MID or CTX_MID_Z + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXMID(a_First, a_Last) a_First##GC##a_Last +# define OTHERCTXMID(a_First, a_Last) a_First##HC##a_Last +#else +# define CTXMID(a_First, a_Last) a_First##HC##a_Last +# define OTHERCTXMID(a_First, a_Last) a_First##GC##a_Last +#endif + +/** @def CTXALLMID + * Adds the current context as a middle name of an identifier name. + * The middle name is R3, R0 or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + * @deprecated use CTX_MID or CTX_MID_Z + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXALLMID(a_First, a_Last) a_First##GC##a_Last +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTXALLMID(a_First, a_Last) a_First##R0##a_Last +#else +# define CTXALLMID(a_First, a_Last) a_First##R3##a_Last +#endif + +/** @def CTX_MID + * Adds the current context as a middle name of an identifier name. + * The middle name is R3, R0 or RC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTX_MID(a_First, a_Last) a_First##RC##a_Last +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTX_MID(a_First, a_Last) a_First##R0##a_Last +#else +# define CTX_MID(a_First, a_Last) a_First##R3##a_Last +#endif + +/** @def CTX_MID_Z + * Adds the current context as a middle name of an identifier name, combining RC + * and R0 into RZ. + * The middle name thus is either R3 or RZ. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + */ +#ifdef IN_RING3 +# define CTX_MID_Z(a_First, a_Last) a_First##R3##a_Last +#else +# define CTX_MID_Z(a_First, a_Last) a_First##RZ##a_Last +#endif + + +/** @def R3STRING + * A macro which in GC and R0 will return a dummy string while in R3 it will return + * the parameter. + * + * This is typically used to wrap description strings in structures shared + * between R3, R0 and/or GC. The intention is to avoid the \#ifdef IN_RING3 mess. + * + * @param a_pR3String The R3 string. Only referenced in R3. + * @see R0STRING and GCSTRING + */ +#ifdef IN_RING3 +# define R3STRING(a_pR3String) (a_pR3String) +#else +# define R3STRING(a_pR3String) ("") +#endif + +/** @def R0STRING + * A macro which in GC and R3 will return a dummy string while in R0 it will return + * the parameter. + * + * This is typically used to wrap description strings in structures shared + * between R3, R0 and/or GC. The intention is to avoid the \#ifdef IN_RING0 mess. + * + * @param a_pR0String The R0 string. Only referenced in R0. + * @see R3STRING and GCSTRING + */ +#ifdef IN_RING0 +# define R0STRING(a_pR0String) (a_pR0String) +#else +# define R0STRING(a_pR0String) ("") +#endif + +/** @def RCSTRING + * A macro which in R3 and R0 will return a dummy string while in RC it will return + * the parameter. + * + * This is typically used to wrap description strings in structures shared + * between R3, R0 and/or RC. The intention is to avoid the \#ifdef IN_RC mess. + * + * @param a_pRCString The RC string. Only referenced in RC. + * @see R3STRING, R0STRING + */ +#ifdef IN_RC +# define RCSTRING(a_pRCString) (a_pRCString) +#else +# define RCSTRING(a_pRCString) ("") +#endif + + +/** @def RT_NOTHING + * A macro that expands to nothing. + * This is primarily intended as a dummy argument for macros to avoid the + * undefined behavior passing empty arguments to an macro (ISO C90 and C++98, + * gcc v4.4 warns about it). + */ +#define RT_NOTHING + +/** @def RT_GCC_EXTENSION + * Macro for shutting up GCC warnings about using language extensions. */ +#ifdef __GNUC__ +# define RT_GCC_EXTENSION __extension__ +#else +# define RT_GCC_EXTENSION +#endif + +/** @def RT_GCC_NO_WARN_DEPRECATED_BEGIN + * Used to start a block of code where GCC and Clang should not warn about + * deprecated declarations. */ +/** @def RT_GCC_NO_WARN_DEPRECATED_END + * Used to end a block of code where GCC and Clang should not warn about + * deprecated declarations. */ +#if RT_CLANG_PREREQ(4, 0) +# define RT_GCC_NO_WARN_DEPRECATED_BEGIN \ + _Pragma("clang diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define RT_GCC_NO_WARN_DEPRECATED_END \ + _Pragma("clang diagnostic pop") + +#elif RT_GNUC_PREREQ(4, 6) +# define RT_GCC_NO_WARN_DEPRECATED_BEGIN \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define RT_GCC_NO_WARN_DEPRECATED_END \ + _Pragma("GCC diagnostic pop") +#else +# define RT_GCC_NO_WARN_DEPRECATED_BEGIN +# define RT_GCC_NO_WARN_DEPRECATED_END +#endif + +/** @def RT_GCC_NO_WARN_CONVERSION_BEGIN + * Used to start a block of code where GCC should not warn about implicit + * conversions that may alter a value. */ +#if RT_GNUC_PREREQ(4, 6) +# define RT_GCC_NO_WARN_CONVERSION_BEGIN \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wconversion\"") +/** @def RT_GCC_NO_WARN_CONVERSION_END + * Used to end a block of code where GCC should not warn about implicit + * conversions that may alter a value. */ +# define RT_GCC_NO_WARN_CONVERSION_END \ + _Pragma("GCC diagnostic pop") +#else +# define RT_GCC_NO_WARN_CONVERSION_BEGIN +# define RT_GCC_NO_WARN_CONVERSION_END +#endif + +/** @def RT_COMPILER_GROKS_64BIT_BITFIELDS + * Macro that is defined if the compiler understands 64-bit bitfields. */ +#if !defined(RT_OS_OS2) || (!defined(__IBMC__) && !defined(__IBMCPP__)) +# if !defined(__WATCOMC__) /* watcom compiler doesn't grok it either. */ +# define RT_COMPILER_GROKS_64BIT_BITFIELDS +# endif +#endif + +/** @def RT_COMPILER_LONG_DOUBLE_BITS + * Number of relevant bits in the long double type: 64, 80 or 128 */ +/** @def RT_COMPILER_WITH_64BIT_LONG_DOUBLE + * Macro that is defined if the compiler implements long double as the + * IEEE precision floating. */ +/** @def RT_COMPILER_WITH_80BIT_LONG_DOUBLE + * Macro that is defined if the compiler implements long double as the + * IEEE extended precision floating. */ +/** @def RT_COMPILER_WITH_128BIT_LONG_DOUBLE +* Macro that is defined if the compiler implements long double as the +* IEEE quadruple precision floating (128-bit). +* @note Currently not able to detect this, so must be explicitly defined. */ +#if defined(__LDBL_MANT_DIG__) /* GCC & clang have this defined and should be more reliable. */ +# if __LDBL_MANT_DIG__ == 53 +# define RT_COMPILER_LONG_DOUBLE_BITS 64 +# define RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_128BIT_LONG_DOUBLE +# elif __LDBL_MANT_DIG__ == 64 +# define RT_COMPILER_LONG_DOUBLE_BITS 80 +# undef RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_128BIT_LONG_DOUBLE +# elif __LDBL_MANT_DIG__ == 113 +# define RT_COMPILER_LONG_DOUBLE_BITS 128 +# undef RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_128BIT_LONG_DOUBLE +# else +# error "Port me!" +# endif +#elif defined(RT_OS_WINDOWS) || defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) /* the M1 arm64 at least */ +# define RT_COMPILER_LONG_DOUBLE_BITS 64 +# define RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_128BIT_LONG_DOUBLE +#elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# define RT_COMPILER_LONG_DOUBLE_BITS 80 +# undef RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_128BIT_LONG_DOUBLE +#elif defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) +# define RT_COMPILER_LONG_DOUBLE_BITS 128 +# undef RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_128BIT_LONG_DOUBLE +#else +# error "Port me!" +#endif + +/** @def RT_COMPILER_WITH_128BIT_INT_TYPES + * Defined when uint128_t and int128_t are native integer types. If + * undefined, they are structure with Hi & Lo members. */ +#if defined(__SIZEOF_INT128__) || (defined(__GNUC__) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64))) +# define RT_COMPILER_WITH_128BIT_INT_TYPES +#endif + +/** @def RT_EXCEPTIONS_ENABLED + * Defined when C++ exceptions are enabled. + */ +#if !defined(RT_EXCEPTIONS_ENABLED) \ + && defined(__cplusplus) \ + && ( (defined(_MSC_VER) && defined(_CPPUNWIND)) \ + || (defined(__GNUC__) && defined(__EXCEPTIONS))) +# define RT_EXCEPTIONS_ENABLED +#endif + +/** @def DECL_NOTHROW + * How to declare a function which does not throw C++ exceptions. + * + * @param a_Type The return type. + * + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECL_NOTHROW(void)) foo(void); + * @endcode + * + * @note GCC is currently restricted to 4.2+ given the ominous comments on + * RT_NOTHROW_PROTO. + */ +#ifdef __cplusplus +# if RT_MSC_PREREQ(RT_MSC_VER_VS2015) /*?*/ +# define DECL_NOTHROW(a_Type) __declspec(nothrow) a_Type +# elif RT_CLANG_PREREQ(6,0) || RT_GNUC_PREREQ(4,2) +# define DECL_NOTHROW(a_Type) __attribute__((__nothrow__)) a_Type +# else +# define DECL_NOTHROW(a_Type) a_Type +# endif +#else +# define DECL_NOTHROW(a_Type) a_Type +#endif + +/** @def RT_NOTHROW_PROTO + * Function does not throw any C++ exceptions, prototype edition. + * + * How to express that a function doesn't throw C++ exceptions and the compiler + * can thus save itself the bother of trying to catch any of them and generate + * unwind info. Put this between the closing parenthesis and the semicolon in + * function prototypes (and implementation if C++). + * + * @note This translates to 'noexcept' when compiling in newer C++ mode. + * + * @remarks The use of the nothrow attribute with GCC is because old compilers + * (4.1.1, 32-bit) leaking the nothrow into global space or something + * when used with RTDECL or similar. Using this forces us to have two + * macros, as the nothrow attribute is not for the function definition. + */ +/** @def RT_NOTHROW_DEF + * Function does not throw any C++ exceptions, definition edition. + * + * The counter part to RT_NOTHROW_PROTO that is added to the function + * definition. + */ +#ifdef RT_EXCEPTIONS_ENABLED +# if RT_MSC_PREREQ_EX(RT_MSC_VER_VS2015, 0) \ + || RT_CLANG_HAS_FEATURE(cxx_noexcept) \ + || (RT_GNUC_PREREQ(7, 0) && __cplusplus >= 201100) +# define RT_NOTHROW_PROTO noexcept +# define RT_NOTHROW_DEF noexcept +# elif defined(__GNUC__) +# if RT_GNUC_PREREQ(3, 3) +# define RT_NOTHROW_PROTO __attribute__((__nothrow__)) +# else +# define RT_NOTHROW_PROTO +# endif +# define RT_NOTHROW_DEF /* Would need a DECL_NO_THROW like __declspec(nothrow), which we wont do at this point. */ +# else +# define RT_NOTHROW_PROTO throw() +# define RT_NOTHROW_DEF throw() +# endif +#else +# define RT_NOTHROW_PROTO +# define RT_NOTHROW_DEF +#endif +/** @def RT_NOTHROW_PROTO + * @deprecated Use RT_NOTHROW_PROTO. */ +#define RT_NO_THROW_PROTO RT_NOTHROW_PROTO +/** @def RT_NOTHROW_DEF + * @deprecated Use RT_NOTHROW_DEF. */ +#define RT_NO_THROW_DEF RT_NOTHROW_DEF + +/** @def RT_THROW + * How to express that a method or function throws a type of exceptions. Some + * compilers does not want this kind of information and will warning about it. + * + * @param a_Type The type exception. + * + * @remarks If the actual throwing is done from the header, enclose it by + * \#ifdef RT_EXCEPTIONS_ENABLED ... \#else ... \#endif so the header + * compiles cleanly without exceptions enabled. + * + * Do NOT use this for the actual throwing of exceptions! + */ +#ifdef RT_EXCEPTIONS_ENABLED +# if (__cplusplus + 0) >= 201700 +# define RT_THROW(a_Type) noexcept(false) +# elif RT_MSC_PREREQ_EX(RT_MSC_VER_VC71, 0) +# define RT_THROW(a_Type) +# elif RT_GNUC_PREREQ(7, 0) +# define RT_THROW(a_Type) +# else +# define RT_THROW(a_Type) throw(a_Type) +# endif +#else +# define RT_THROW(a_Type) +#endif + + +/** @def RT_OVERRIDE + * Wrapper for the C++11 override keyword. + * + * @remarks Recognized by g++ starting 4.7, however causes pedantic warnings + * when used without officially enabling the C++11 features. + */ +#ifdef __cplusplus +# if RT_MSC_PREREQ_EX(RT_MSC_VER_VS2012, 0) +# define RT_OVERRIDE override +# elif RT_GNUC_PREREQ(4, 7) +# if __cplusplus >= 201100 +# define RT_OVERRIDE override +# else +# define RT_OVERRIDE +# endif +# else +# define RT_OVERRIDE +# endif +#else +# define RT_OVERRIDE +#endif + +/** @def RT_NOEXCEPT + * Wrapper for the C++11 noexcept keyword (only true form). + * @note use RT_NOTHROW instead. + */ +/** @def RT_NOEXCEPT_EX + * Wrapper for the C++11 noexcept keyword with expression. + * @param a_Expr The expression. + */ +#ifdef __cplusplus +# if (RT_MSC_PREREQ_EX(RT_MSC_VER_VS2015, 0) && defined(RT_EXCEPTIONS_ENABLED)) \ + || RT_CLANG_HAS_FEATURE(cxx_noexcept) \ + || (RT_GNUC_PREREQ(7, 0) && __cplusplus >= 201100) +# define RT_NOEXCEPT noexcept +# define RT_NOEXCEPT_EX(a_Expr) noexcept(a_Expr) +# else +# define RT_NOEXCEPT +# define RT_NOEXCEPT_EX(a_Expr) +# endif +#else +# define RT_NOEXCEPT +# define RT_NOEXCEPT_EX(a_Expr) +#endif + +/** @def RT_ALIGNAS_VAR + * Wrapper for the C++ alignas keyword when used on variables. + * + * This must be put before the storage class and type. + * + * @param a_cbAlign The alignment. Must be power of two. + * @note If C++11 is not enabled/detectable, alternatives will be used where + * available. */ +/** @def RT_ALIGNAS_TYPE + * Wrapper for the C++ alignas keyword when used on types. + * + * When using struct, this must follow the struct keyword. + * + * @param a_cbAlign The alignment. Must be power of two. + * @note If C++11 is not enabled/detectable, alternatives will be used where + * available. */ +/** @def RT_ALIGNAS_MEMB + * Wrapper for the C++ alignas keyword when used on structure members. + * + * This must be put before the variable type. + * + * @param a_cbAlign The alignment. Must be power of two. + * @note If C++11 is not enabled/detectable, alternatives will be used where + * available. */ +#ifdef __cplusplus +# if __cplusplus >= 201100 || defined(DOXYGEN_RUNNING) +# define RT_ALIGNAS_VAR(a_cbAlign) alignas(a_cbAlign) +# define RT_ALIGNAS_TYPE(a_cbAlign) alignas(a_cbAlign) +# define RT_ALIGNAS_MEMB(a_cbAlign) alignas(a_cbAlign) +# endif +#endif +#ifndef RT_ALIGNAS_VAR +# ifdef _MSC_VER +# define RT_ALIGNAS_VAR(a_cbAlign) __declspec(align(a_cbAlign)) +# define RT_ALIGNAS_TYPE(a_cbAlign) __declspec(align(a_cbAlign)) +# define RT_ALIGNAS_MEMB(a_cbAlign) __declspec(align(a_cbAlign)) +# elif defined(__GNUC__) +# define RT_ALIGNAS_VAR(a_cbAlign) __attribute__((__aligned__(a_cbAlign))) +# define RT_ALIGNAS_TYPE(a_cbAlign) __attribute__((__aligned__(a_cbAlign))) +# define RT_ALIGNAS_MEMB(a_cbAlign) __attribute__((__aligned__(a_cbAlign))) +# else +# define RT_ALIGNAS_VAR(a_cbAlign) +# define RT_ALIGNAS_TYPE(a_cbAlign) +# define RT_ALIGNAS_MEMB(a_cbAlign) +# endif +#endif + +/** @def RT_CACHELINE_SIZE + * The typical cache line size for the target architecture. + * @see RT_ALIGNAS_VAR, RT_ALIGNAS_TYPE, RT_ALIGNAS_MEMB + */ +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) \ + || defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) \ + || defined(RT_ARCH_SPARC32) || defined(RT_ARCH_SPARC64) \ + || defined(DOXYGEN_RUNNING) +# define RT_CACHELINE_SIZE 64 +#else +# define RT_CACHELINE_SIZE 128 /* better overdo it */ +#endif + +/** @def RT_FALL_THROUGH + * Tell the compiler that we're falling through to the next case in a switch. + * @sa RT_FALL_THRU */ +#if RT_CLANG_PREREQ(4, 0) && RT_CPLUSPLUS_PREREQ(201100) +# define RT_FALL_THROUGH() [[clang::fallthrough]] +#elif RT_CLANG_PREREQ(12, 0) || RT_GNUC_PREREQ(7, 0) +# define RT_FALL_THROUGH() __attribute__((__fallthrough__)) +#else +# define RT_FALL_THROUGH() (void)0 +#endif +/** @def RT_FALL_THRU + * Tell the compiler that we're falling thru to the next case in a switch. + * @sa RT_FALL_THROUGH */ +#define RT_FALL_THRU() RT_FALL_THROUGH() + + +/** @def RT_IPRT_FORMAT_ATTR + * Identifies a function taking an IPRT format string. + * @param a_iFmt The index (1-based) of the format string argument. + * @param a_iArgs The index (1-based) of the first format argument, use 0 for + * va_list. + */ +#if defined(__GNUC__) && defined(WITH_IPRT_FORMAT_ATTRIBUTE) +# define RT_IPRT_FORMAT_ATTR(a_iFmt, a_iArgs) __attribute__((__iprt_format__(a_iFmt, a_iArgs))) +#else +# define RT_IPRT_FORMAT_ATTR(a_iFmt, a_iArgs) +#endif + +/** @def RT_IPRT_FORMAT_ATTR_MAYBE_NULL + * Identifies a function taking an IPRT format string, NULL is allowed. + * @param a_iFmt The index (1-based) of the format string argument. + * @param a_iArgs The index (1-based) of the first format argument, use 0 for + * va_list. + */ +#if defined(__GNUC__) && defined(WITH_IPRT_FORMAT_ATTRIBUTE) +# define RT_IPRT_FORMAT_ATTR_MAYBE_NULL(a_iFmt, a_iArgs) __attribute__((__iprt_format_maybe_null__(a_iFmt, a_iArgs))) +#else +# define RT_IPRT_FORMAT_ATTR_MAYBE_NULL(a_iFmt, a_iArgs) +#endif + + +/** @def RT_GCC_SUPPORTS_VISIBILITY_HIDDEN + * Indicates that the "hidden" visibility attribute can be used (GCC) */ +#if defined(__GNUC__) +# if __GNUC__ >= 4 && !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) +# define RT_GCC_SUPPORTS_VISIBILITY_HIDDEN +# endif +#endif + +/** @def RT_COMPILER_SUPPORTS_VA_ARGS + * If the defined, the compiler supports the variadic macro feature (..., __VA_ARGS__). */ +#if defined(_MSC_VER) +# if _MSC_VER >= 1600 /* Visual C++ v10.0 / 2010 */ +# define RT_COMPILER_SUPPORTS_VA_ARGS +# endif +#elif defined(__GNUC__) +# if __GNUC__ >= 3 /* not entirely sure when this was added */ +# define RT_COMPILER_SUPPORTS_VA_ARGS +# endif +#elif defined(__WATCOMC__) +# define RT_COMPILER_SUPPORTS_VA_ARGS +#endif + +/** @def RT_CB_LOG_CAST + * Helper for logging function pointers to function may throw stuff. + * + * Not needed for function pointer types declared using our DECLCALLBACK + * macros, only external types. */ +#if defined(_MSC_VER) && defined(RT_EXCEPTIONS_ENABLED) +# define RT_CB_LOG_CAST(a_pfnCallback) ((uintptr_t)(a_pfnCallback) + 1 - 1) +#else +# define RT_CB_LOG_CAST(a_pfnCallback) (a_pfnCallback) +#endif + + + +/** @def RTCALL + * The standard calling convention for the Runtime interfaces. + * + * @remarks The regparm(0) in the X86/GNUC variant deals with -mregparm=x use in + * the linux kernel and potentially elsewhere (3rd party). + */ +#if defined(_MSC_VER) || defined(__WATCOMC__) +# define RTCALL __cdecl +#elif defined(RT_OS_OS2) +# define RTCALL __cdecl +#elif defined(__GNUC__) && defined(RT_ARCH_X86) +# define RTCALL __attribute__((__cdecl__,__regparm__(0))) +#else +# define RTCALL +#endif + +/** @def DECLEXPORT + * How to declare an exported function. + * @param a_RetType The return type of the function declaration. + */ +#if defined(_MSC_VER) || defined(RT_OS_OS2) +# define DECLEXPORT(a_RetType) __declspec(dllexport) a_RetType +#elif defined(RT_USE_VISIBILITY_DEFAULT) +# define DECLEXPORT(a_RetType) __attribute__((visibility("default"))) a_RetType +#else +# define DECLEXPORT(a_RetType) a_RetType +#endif + +/** @def DECL_EXPORT_NOTHROW + * How to declare an exported function that does not throw C++ exceptions. + * @param a_RetType The return type of the function declaration. + */ +#define DECL_EXPORT_NOTHROW(a_RetType) DECL_NOTHROW(DECLEXPORT(a_RetType)) + +/** @def DECLIMPORT + * How to declare an imported function. + * @param a_RetType The return type of the function declaration. + */ +#if defined(_MSC_VER) || (defined(RT_OS_OS2) && !defined(__IBMC__) && !defined(__IBMCPP__)) +# define DECLIMPORT(a_RetType) __declspec(dllimport) a_RetType +#else +# define DECLIMPORT(a_RetType) a_RetType +#endif + +/** @def DECL_IMPORT_NOTHROW + * How to declare an imported function that does not throw C++ exceptions. + * @param a_RetType The return type of the function declaration. + */ +#define DECL_IMPORT_NOTHROW(a_RetType) DECL_NOTHROW(DECLIMPORT(a_RetType)) + +/** @def DECL_HIDDEN_ONLY + * How to declare a non-exported function or variable. + * @param a_Type The return type of the function or the data type of the variable. + * @sa DECL_HIDDEN, DECL_HIDDEN_DATA, DECL_HIDDEN_CONST + * @internal Considered more or less internal. + */ +#if !defined(RT_GCC_SUPPORTS_VISIBILITY_HIDDEN) || defined(RT_NO_VISIBILITY_HIDDEN) +# define DECL_HIDDEN_ONLY(a_Type) a_Type +#else +# define DECL_HIDDEN_ONLY(a_Type) __attribute__((visibility("hidden"))) a_Type +#endif + +/** @def DECLHIDDEN + * How to declare a non-exported function or variable. + * @param a_Type The return type of the function or the data type of the variable. + * @sa DECL_HIDDEN_THROW, DECL_HIDDEN_DATA, DECL_HIDDEN_CONST + * @todo split up into data and non-data. + */ +#define DECLHIDDEN(a_Type) DECL_NOTHROW(DECL_HIDDEN_ONLY(a_Type)) + +/** @def DECL_HIDDEN_NOTHROW + * How to declare a non-exported function that does not throw C++ exceptions. + * @param a_RetType The return type of the function. + * @note Same as DECLHIDDEN but provided to go along with DECL_IMPORT_NOTHROW + * and DECL_EXPORT_NOTHROW. + */ +#define DECL_HIDDEN_NOTHROW(a_RetType) DECL_NOTHROW(DECL_HIDDEN_ONLY(a_RetType)) + +/** @def DECL_HIDDEN_THROW + * How to declare a non-exported function that may throw C++ exceptions. + * @param a_RetType The return type of the function. + */ +#define DECL_HIDDEN_THROW(a_RetType) DECL_HIDDEN_ONLY(a_Type) + +/** @def DECL_HIDDEN_DATA + * How to declare a non-exported variable. + * @param a_Type The data type of the variable. + * @sa DECL_HIDDEN_CONST + */ +#if !defined(RT_GCC_SUPPORTS_VISIBILITY_HIDDEN) || defined(RT_NO_VISIBILITY_HIDDEN) +# define DECL_HIDDEN_DATA(a_Type) a_Type +#else +# define DECL_HIDDEN_DATA(a_Type) __attribute__((visibility("hidden"))) a_Type +#endif + +/** @def DECL_HIDDEN_CONST + * Workaround for g++ warnings when applying the hidden attribute to a const + * definition. Use DECL_HIDDEN_DATA for the declaration. + * @param a_Type The data type of the variable. + * @sa DECL_HIDDEN_DATA + */ +#if defined(__cplusplus) && defined(__GNUC__) +# define DECL_HIDDEN_CONST(a_Type) a_Type +#else +# define DECL_HIDDEN_CONST(a_Type) DECL_HIDDEN_DATA(a_Type) +#endif + +/** @def DECL_INVALID + * How to declare a function not available for linking in the current context. + * The purpose is to create compile or like time errors when used. This isn't + * possible on all platforms. + * @param a_RetType The return type of the function. + */ +#if defined(_MSC_VER) +# define DECL_INVALID(a_RetType) __declspec(dllimport) a_RetType __stdcall +#elif defined(__GNUC__) && defined(__cplusplus) +# define DECL_INVALID(a_RetType) extern "C++" a_RetType +#else +# define DECL_INVALID(a_RetType) a_RetType +#endif + +/** @def DECLASM + * How to declare an internal assembly function. + * @param a_RetType The return type of the function declaration. + * @note DECL_NOTHROW is implied. + */ +#ifdef __cplusplus +# define DECLASM(a_RetType) extern "C" DECL_NOTHROW(a_RetType RTCALL) +#else +# define DECLASM(a_RetType) DECL_NOTHROW(a_RetType RTCALL) +#endif + +/** @def RT_ASM_DECL_PRAGMA_WATCOM + * How to declare a assembly method prototype with watcom \#pragma aux definition. */ +/** @def RT_ASM_DECL_PRAGMA_WATCOM_386 + * Same as RT_ASM_DECL_PRAGMA_WATCOM, but there is no 16-bit version when + * 8086, 80186 or 80286 is selected as the target CPU. */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 && defined(RT_ARCH_X86) +# define RT_ASM_DECL_PRAGMA_WATCOM(a_RetType) a_RetType +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# define RT_ASM_DECL_PRAGMA_WATCOM_386(a_RetType) DECLASM(a_RetType) +# else +# define RT_ASM_DECL_PRAGMA_WATCOM_386(a_RetType) a_RetType +# endif +#elif defined(__WATCOMC__) && ARCH_BITS == 32 && defined(RT_ARCH_X86) +# define RT_ASM_DECL_PRAGMA_WATCOM(a_RetType) a_RetType +# define RT_ASM_DECL_PRAGMA_WATCOM_386(a_RetType) a_RetType +#else +# define RT_ASM_DECL_PRAGMA_WATCOM(a_RetType) DECLASM(a_RetType) +# define RT_ASM_DECL_PRAGMA_WATCOM_386(a_RetType) DECLASM(a_RetType) +#endif + +/** @def DECL_NO_RETURN + * How to declare a function which does not return. + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECL_NO_RETURN(void)) foo(void); + * @endcode + */ +#ifdef _MSC_VER +# define DECL_NO_RETURN(a_RetType) __declspec(noreturn) a_RetType +#elif defined(__GNUC__) +# define DECL_NO_RETURN(a_RetType) __attribute__((noreturn)) a_RetType +#else +# define DECL_NO_RETURN(a_RetType) a_RetType +#endif + +/** @def DECL_RETURNS_TWICE + * How to declare a function which may return more than once. + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECL_RETURNS_TWICE(void)) MySetJmp(void); + * @endcode + */ +#if RT_GNUC_PREREQ(4, 1) +# define DECL_RETURNS_TWICE(a_RetType) __attribute__((returns_twice)) a_RetType +#else +# define DECL_RETURNS_TWICE(a_RetType) a_RetType +#endif + +/** @def DECL_CHECK_RETURN + * Require a return value to be checked. + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECL_CHECK_RETURN(int)) MayReturnInfoStatus(void); + * @endcode + */ +#if RT_GNUC_PREREQ(3, 4) +# define DECL_CHECK_RETURN(a_RetType) __attribute__((warn_unused_result)) a_RetType +#elif defined(_MSC_VER) +# define DECL_CHECK_RETURN(a_RetType) __declspec("SAL_checkReturn") a_RetType +#else +# define DECL_CHECK_RETURN(a_RetType) a_RetType +#endif + +/** @def DECL_CHECK_RETURN_NOT_R3 + * Variation of DECL_CHECK_RETURN that only applies the required to non-ring-3 + * code. + */ +#ifndef IN_RING3 +# define DECL_CHECK_RETURN_NOT_R3(a_RetType) DECL_CHECK_RETURN(a_RetType) +#else +# define DECL_CHECK_RETURN_NOT_R3(a_RetType) a_RetType +#endif + +/** @def DECLWEAK + * How to declare a variable which is not necessarily resolved at + * runtime. + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECLWEAK(int)) foo; + * @endcode + */ +#if defined(__GNUC__) +# define DECLWEAK(a_Type) a_Type __attribute__((weak)) +#else +# define DECLWEAK(a_Type) a_Type +#endif + +/** @def DECLCALLBACK + * How to declare an call back function. + * @param a_RetType The return type of the function declaration. + * @note DECL_NOTHROW is implied. + * @note Use DECLCALLBACKTYPE for typedefs. + */ +#define DECLCALLBACK(a_RetType) DECL_NOTHROW(a_RetType RT_FAR_CODE RTCALL) + +/** @def DECL_HIDDEN_CALLBACK + * How to declare an call back function with hidden visibility. + * @param a_RetType The return type of the function declaration. + * @note DECL_NOTHROW is implied. + * @note Use DECLCALLBACKTYPE for typedefs. + */ +#define DECL_HIDDEN_CALLBACK(a_RetType) DECL_HIDDEN_ONLY(DECLCALLBACK(a_RetType)) + +/** @def DECLCALLBACKTYPE_EX + * How to declare an call back function type. + * @param a_RetType The return type of the function declaration. + * @param a_CallConv Calling convention. + * @param a_Name The name of the typedef + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if RT_CLANG_PREREQ(6,0) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKTYPE_EX(a_RetType, a_CallConv, a_Name, a_Args) __attribute__((__nothrow__)) a_RetType a_CallConv a_Name a_Args +#elif RT_MSC_PREREQ(RT_MSC_VER_VS2015) /*?*/ && defined(__cplusplus) && defined(_MSC_EXTENSIONS) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKTYPE_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType a_CallConv a_Name a_Args throw() +#else +# define DECLCALLBACKTYPE_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType a_CallConv a_Name a_Args +#endif +/** @def DECLCALLBACKTYPE + * How to declare an call back function type. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the typedef + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#define DECLCALLBACKTYPE(a_RetType, a_Name, a_Args) DECLCALLBACKTYPE_EX(a_RetType, RT_FAR_CODE RTCALL, a_Name, a_Args) + +/** @def DECLCALLBACKPTR_EX + * How to declare an call back function pointer. + * @param a_RetType The return type of the function declaration. + * @param a_CallConv Calling convention. + * @param a_Name The name of the variable member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(__IBMC__) || defined(__IBMCPP__) +# define DECLCALLBACKPTR_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (* a_CallConv a_Name) a_Args +#elif RT_CLANG_PREREQ(6,0) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKPTR_EX(a_RetType, a_CallConv, a_Name, a_Args) __attribute__((__nothrow__)) a_RetType (a_CallConv * a_Name) a_Args +#elif RT_MSC_PREREQ(RT_MSC_VER_VS2015) /*?*/ && defined(__cplusplus) && defined(_MSC_EXTENSIONS) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKPTR_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (a_CallConv * a_Name) a_Args throw() +#else +# define DECLCALLBACKPTR_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (a_CallConv * a_Name) a_Args +#endif +/** @def DECLCALLBACKPTR + * How to declare an call back function pointer. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the variable member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#define DECLCALLBACKPTR(a_RetType, a_Name, a_Args) DECLCALLBACKPTR_EX(a_RetType, RT_FAR_CODE RTCALL, a_Name, a_Args) + +/** @def DECLCALLBACKMEMBER_EX + * How to declare an call back function pointer member. + * @param a_RetType The return type of the function declaration. + * @param a_CallConv Calling convention. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(__IBMC__) || defined(__IBMCPP__) +# define DECLCALLBACKMEMBER_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (* a_CallConv a_Name) a_Args +#elif RT_CLANG_PREREQ(6,0) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKMEMBER_EX(a_RetType, a_CallConv, a_Name, a_Args) __attribute__((__nothrow__)) a_RetType (a_CallConv *a_Name) a_Args +#elif RT_MSC_PREREQ(RT_MSC_VER_VS2015) /*?*/ && defined(__cplusplus) && defined(_MSC_EXTENSIONS) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKMEMBER_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (a_CallConv *a_Name) a_Args throw() +#else +# define DECLCALLBACKMEMBER_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (a_CallConv *a_Name) a_Args +#endif +/** @def DECLCALLBACKMEMBER + * How to declare an call back function pointer member. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#define DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER_EX(a_RetType, RT_FAR_CODE RTCALL, a_Name, a_Args) + +/** @def DECLR3CALLBACKMEMBER + * How to declare an call back function pointer member - R3 Ptr. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +# define DECLR3CALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) +#else +# define DECLR3CALLBACKMEMBER(a_RetType, a_Name, a_Args) RTR3PTR a_Name +#endif + +/** @def DECLRCCALLBACKMEMBER + * How to declare an call back function pointer member - RC Ptr. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(IN_RC) || defined(DOXYGEN_RUNNING) +# define DECLRCCALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) +#else +# define DECLRCCALLBACKMEMBER(a_RetType, a_Name, a_Args) RTRCPTR a_Name +#endif +#if defined(IN_RC) || defined(DOXYGEN_RUNNING) +# define DECLRGCALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) +#else +# define DECLRGCALLBACKMEMBER(a_RetType, a_Name, a_Args) RTRGPTR a_Name +#endif + +/** @def DECLR0CALLBACKMEMBER + * How to declare an call back function pointer member - R0 Ptr. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +# define DECLR0CALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) +#else +# define DECLR0CALLBACKMEMBER(a_RetType, a_Name, a_Args) RTR0PTR a_Name +#endif + +/** @def DECLINLINE + * How to declare a function as inline that does not throw any C++ exceptions. + * @param a_RetType The return type of the function declaration. + * @remarks Don't use this macro on C++ methods. + * @sa DECL_INLINE_THROW + */ +#if defined(__GNUC__) && !defined(DOXYGEN_RUNNING) +# define DECLINLINE(a_RetType) DECL_NOTHROW(static __inline__ a_RetType) +#elif defined(__cplusplus) || defined(DOXYGEN_RUNNING) +# define DECLINLINE(a_RetType) DECL_NOTHROW(static inline a_RetType) +#elif defined(_MSC_VER) +# define DECLINLINE(a_RetType) DECL_NOTHROW(static _inline a_RetType) +#elif defined(__IBMC__) +# define DECLINLINE(a_RetType) DECL_NOTHROW(_Inline a_RetType) +#else +# define DECLINLINE(a_RetType) DECL_NOTHROW(inline a_RetType) +#endif + +/** @def DECL_INLINE_THROW + * How to declare a function as inline that throws C++ exceptions. + * @param a_RetType The return type of the function declaration. + * @remarks Don't use this macro on C++ methods. + */ +#if defined(__GNUC__) && !defined(DOXYGEN_RUNNING) +# define DECL_INLINE_THROW(a_RetType) static __inline__ a_RetType +#elif defined(__cplusplus) || defined(DOXYGEN_RUNNING) +# define DECL_INLINE_THROW(a_RetType) static inline a_RetType +#elif defined(_MSC_VER) +# define DECL_INLINE_THROW(a_RetType) static _inline a_RetType +#elif defined(__IBMC__) +# define DECL_INLINE_THROW(a_RetType) _Inline a_RetType +#else +# define DECL_INLINE_THROW(a_RetType) inline a_RetType +#endif + +/** @def DECL_FORCE_INLINE + * How to declare a function that does not throw any C++ exceptions as inline + * and try convince the compiler to always inline it regardless of optimization + * switches. + * @param a_RetType The return type of the function declaration. + * @remarks Use sparsely and with care. Don't use this macro on C++ methods. + * @sa DECL_FORCE_INLINE_THROW + */ +#ifdef __GNUC__ +# define DECL_FORCE_INLINE(a_RetType) __attribute__((__always_inline__)) DECLINLINE(a_RetType) +#elif defined(_MSC_VER) +# define DECL_FORCE_INLINE(a_RetType) DECL_NOTHROW(__forceinline a_RetType) +#else +# define DECL_FORCE_INLINE(a_RetType) DECLINLINE(a_RetType) +#endif + +/** @def DECL_FORCE_INLINE_THROW + * How to declare a function throwing C++ exceptions as inline and try convince + * the compiler to always inline it regardless of optimization switches. + * @param a_RetType The return type of the function declaration. + * @remarks Use sparsely and with care. Don't use this macro on C++ methods. + */ +#ifdef __GNUC__ +# define DECL_FORCE_INLINE_THROW(a_RetType) __attribute__((__always_inline__)) DECL_INLINE_THROW(a_RetType) +#elif defined(_MSC_VER) +# define DECL_FORCE_INLINE_THROW(a_RetType) __forceinline a_RetType +#else +# define DECL_FORCE_INLINE_THROW(a_RetType) DECL_INLINE_THROW(a_RetType) +#endif + + +/** @def DECL_NO_INLINE + * How to declare a function telling the compiler not to inline it. + * @param scope The function scope, static or RT_NOTHING. + * @param a_RetType The return type of the function declaration. + * @remarks Don't use this macro on C++ methods. + */ +#ifdef __GNUC__ +# define DECL_NO_INLINE(scope, a_RetType) __attribute__((__noinline__)) scope a_RetType +#elif defined(_MSC_VER) +# define DECL_NO_INLINE(scope, a_RetType) __declspec(noinline) scope a_RetType +#else +# define DECL_NO_INLINE(scope,a_RetType) scope a_RetType +#endif + + +/** @def IN_RT_STATIC + * Used to indicate whether we're linking against a static IPRT + * or not. + * + * The IPRT symbols will be declared as hidden (if supported). Note that this + * define has no effect without also setting one of the IN_RT_R0, IN_RT_R3 or + * IN_RT_RC indicators. + */ + +/** @def IN_RT_R0 + * Used to indicate whether we're inside the same link module as the host + * context ring-0 Runtime Library. + */ +/** @def RTR0DECL(a_RetType) + * Runtime Library host context ring-0 export or import declaration. + * @param a_RetType The return a_RetType of the function declaration. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + * @note DECL_NOTHROW is implied. + */ +#ifdef IN_RT_R0 +# ifdef IN_RT_STATIC +# define RTR0DECL(a_RetType) DECL_HIDDEN_NOTHROW(a_RetType) RTCALL +# else +# define RTR0DECL(a_RetType) DECL_EXPORT_NOTHROW(a_RetType) RTCALL +# endif +#else +# define RTR0DECL(a_RetType) DECL_IMPORT_NOTHROW(a_RetType) RTCALL +#endif + +/** @def IN_RT_R3 + * Used to indicate whether we're inside the same link module as the host + * context ring-3 Runtime Library. + */ +/** @def RTR3DECL(a_RetType) + * Runtime Library host context ring-3 export or import declaration. + * @param a_RetType The return type of the function declaration. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + * @note DECL_NOTHROW is implied. + */ +#ifdef IN_RT_R3 +# ifdef IN_RT_STATIC +# define RTR3DECL(a_RetType) DECL_HIDDEN_NOTHROW(a_RetType) RTCALL +# else +# define RTR3DECL(a_RetType) DECL_EXPORT_NOTHROW(a_RetType) RTCALL +# endif +#else +# define RTR3DECL(a_RetType) DECL_IMPORT_NOTHROW(a_RetType) RTCALL +#endif + +/** @def IN_RT_RC + * Used to indicate whether we're inside the same link module as the raw-mode + * context (RC) runtime library. + */ +/** @def RTRCDECL(a_RetType) + * Runtime Library raw-mode context export or import declaration. + * @param a_RetType The return type of the function declaration. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + * @note DECL_NOTHROW is implied. + */ +#ifdef IN_RT_RC +# ifdef IN_RT_STATIC +# define RTRCDECL(a_RetType) DECL_HIDDEN_NOTHROW(a_RetType) RTCALL +# else +# define RTRCDECL(a_RetType) DECL_EXPORT_NOTHROW(a_RetType) RTCALL +# endif +#else +# define RTRCDECL(a_RetType) DECL_IMPORT_NOTHROW(a_RetType) RTCALL +#endif + +/** @def RTDECL(a_RetType) + * Runtime Library export or import declaration. + * Functions declared using this macro exists in all contexts. + * @param a_RetType The return type of the function declaration. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + * @note DECL_NOTHROW is implied. + */ +#if defined(IN_RT_R3) || defined(IN_RT_RC) || defined(IN_RT_R0) +# ifdef IN_RT_STATIC +# define RTDECL(a_RetType) DECL_HIDDEN_NOTHROW(a_RetType) RTCALL +# else +# define RTDECL(a_RetType) DECL_EXPORT_NOTHROW(a_RetType) RTCALL +# endif +#else +# define RTDECL(a_RetType) DECL_IMPORT_NOTHROW(a_RetType) RTCALL +#endif + +/** @def RTDATADECL(a_Type) + * Runtime Library export or import declaration. + * Data declared using this macro exists in all contexts. + * @param a_Type The data type. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + */ +/** @def RT_DECL_DATA_CONST(a_Type) + * Definition of a const variable. See DECL_HIDDEN_CONST. + * @param a_Type The const data type. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + */ +#if defined(IN_RT_R3) || defined(IN_RT_RC) || defined(IN_RT_R0) +# ifdef IN_RT_STATIC +# define RTDATADECL(a_Type) DECL_HIDDEN_DATA(a_Type) +# define RT_DECL_DATA_CONST(a_Type) DECL_HIDDEN_CONST(a_Type) +# else +# define RTDATADECL(a_Type) DECLEXPORT(a_Type) +# if defined(__cplusplus) && defined(__GNUC__) +# define RT_DECL_DATA_CONST(a_Type) a_Type +# else +# define RT_DECL_DATA_CONST(a_Type) DECLEXPORT(a_Type) +# endif +# endif +#else +# define RTDATADECL(a_Type) DECLIMPORT(a_Type) +# define RT_DECL_DATA_CONST(a_Type) DECLIMPORT(a_Type) +#endif + +/** @def RT_DECL_CLASS + * Declares an class living in the runtime. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + */ +#if defined(IN_RT_R3) || defined(IN_RT_RC) || defined(IN_RT_R0) +# ifdef IN_RT_STATIC +# define RT_DECL_CLASS +# else +# define RT_DECL_CLASS DECLEXPORT_CLASS +# endif +#else +# define RT_DECL_CLASS DECLIMPORT_CLASS +#endif + + +/** @def RT_NOCRT + * Symbol name wrapper for the No-CRT bits. + * + * In order to coexist in the same process as other CRTs, we need to + * decorate the symbols such that they don't conflict the ones in the + * other CRTs. The result of such conflicts / duplicate symbols can + * confuse the dynamic loader on Unix like systems. + * + * Define RT_WITHOUT_NOCRT_WRAPPERS to drop the wrapping. + * Define RT_WITHOUT_NOCRT_WRAPPER_ALIASES to drop the aliases to the + * wrapped names. + */ +/** @def RT_NOCRT_STR + * Same as RT_NOCRT only it'll return a double quoted string of the result. + */ +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) || defined(RT_FORCE_NOCRT_WRAPPERS) +# define RT_NOCRT(name) nocrt_ ## name +# define RT_NOCRT_STR(name) "nocrt_" # name +#else +# define RT_NOCRT(name) name +# define RT_NOCRT_STR(name) #name +#endif + + +/** @name Untrusted data classifications. + * @{ */ +/** @def RT_UNTRUSTED_USER + * For marking non-volatile (race free) data from user mode as untrusted. + * This is just for visible documentation. */ +#define RT_UNTRUSTED_USER +/** @def RT_UNTRUSTED_VOLATILE_USER + * For marking volatile data shared with user mode as untrusted. + * This is more than just documentation as it specifies the 'volatile' keyword, + * because the guest could modify the data at any time. */ +#define RT_UNTRUSTED_VOLATILE_USER volatile + +/** @def RT_UNTRUSTED_GUEST + * For marking non-volatile (race free) data from the guest as untrusted. + * This is just for visible documentation. */ +#define RT_UNTRUSTED_GUEST +/** @def RT_UNTRUSTED_VOLATILE_GUEST + * For marking volatile data shared with the guest as untrusted. + * This is more than just documentation as it specifies the 'volatile' keyword, + * because the guest could modify the data at any time. */ +#define RT_UNTRUSTED_VOLATILE_GUEST volatile + +/** @def RT_UNTRUSTED_HOST + * For marking non-volatile (race free) data from the host as untrusted. + * This is just for visible documentation. */ +#define RT_UNTRUSTED_HOST +/** @def RT_UNTRUSTED_VOLATILE_HOST + * For marking volatile data shared with the host as untrusted. + * This is more than just documentation as it specifies the 'volatile' keyword, + * because the host could modify the data at any time. */ +#define RT_UNTRUSTED_VOLATILE_HOST volatile + +/** @def RT_UNTRUSTED_HSTGST + * For marking non-volatile (race free) data from the host/gust as untrusted. + * This is just for visible documentation. */ +#define RT_UNTRUSTED_HSTGST +/** @def RT_UNTRUSTED_VOLATILE_HSTGST + * For marking volatile data shared with the host/guest as untrusted. + * This is more than just documentation as it specifies the 'volatile' keyword, + * because the host could modify the data at any time. */ +#define RT_UNTRUSTED_VOLATILE_HSTGST volatile +/** @} */ + +/** @name Fences for use when handling untrusted data. + * @{ */ +/** For use after copying untruated volatile data to a non-volatile location. + * This translates to a compiler memory barrier and will help ensure that the + * compiler uses the non-volatile copy of the data. */ +#define RT_UNTRUSTED_NONVOLATILE_COPY_FENCE() ASMCompilerBarrier() +/** For use after finished validating guest input. + * What this translates to is architecture dependent. On intel it will + * translate to a CPU load+store fence as well as a compiler memory barrier. */ +#if defined(RT_ARCH_AMD64) || (defined(RT_ARCH_X86) && !defined(RT_WITH_OLD_CPU_SUPPORT)) +# define RT_UNTRUSTED_VALIDATED_FENCE() do { ASMCompilerBarrier(); ASMReadFence(); } while (0) +#elif defined(RT_ARCH_X86) +# define RT_UNTRUSTED_VALIDATED_FENCE() do { ASMCompilerBarrier(); ASMMemoryFence(); } while (0) +#else +# define RT_UNTRUSTED_VALIDATED_FENCE() do { ASMCompilerBarrier(); } while (0) +#endif +/** @} */ + + +/** @def RT_LIKELY + * Give the compiler a hint that an expression is very likely to hold true. + * + * Some compilers support explicit branch prediction so that the CPU backend + * can hint the processor and also so that code blocks can be reordered such + * that the predicted path sees a more linear flow, thus improving cache + * behaviour, etc. + * + * IPRT provides the macros RT_LIKELY() and RT_UNLIKELY() as a way to utilize + * this compiler feature when present. + * + * A few notes about the usage: + * + * - Generally, order your code use RT_LIKELY() instead of RT_UNLIKELY(). + * + * - Generally, use RT_UNLIKELY() with error condition checks (unless you + * have some _strong_ reason to do otherwise, in which case document it), + * and/or RT_LIKELY() with success condition checks, assuming you want + * to optimize for the success path. + * + * - Other than that, if you don't know the likelihood of a test succeeding + * from empirical or other 'hard' evidence, don't make predictions unless + * you happen to be a Dirk Gently character. + * + * - These macros are meant to be used in places that get executed a lot. It + * is wasteful to make predictions in code that is executed rarely (e.g. + * at subsystem initialization time) as the basic block reordering that this + * affects can often generate larger code. + * + * - Note that RT_SUCCESS() and RT_FAILURE() already makes use of RT_LIKELY() + * and RT_UNLIKELY(). Should you wish for prediction free status checks, + * use the RT_SUCCESS_NP() and RT_FAILURE_NP() macros instead. + * + * + * @returns the boolean result of the expression. + * @param expr The expression that's very likely to be true. + * @see RT_UNLIKELY + */ +/** @def RT_UNLIKELY + * Give the compiler a hint that an expression is highly unlikely to hold true. + * + * See the usage instructions give in the RT_LIKELY() docs. + * + * @returns the boolean result of the expression. + * @param expr The expression that's very unlikely to be true. + * @see RT_LIKELY + * + * @deprecated Please use RT_LIKELY() instead wherever possible! That gives us + * a better chance of the windows compilers to generate favorable code + * too. The belief is that the compiler will by default assume the + * if-case is more likely than the else-case. + */ +#if defined(__GNUC__) +# if __GNUC__ >= 3 && !defined(FORTIFY_RUNNING) +# define RT_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define RT_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +# else +# define RT_LIKELY(expr) (expr) +# define RT_UNLIKELY(expr) (expr) +# endif +#else +# define RT_LIKELY(expr) (expr) +# define RT_UNLIKELY(expr) (expr) +#endif + +/** @def RT_EXPAND_2 + * Helper for RT_EXPAND. */ +#define RT_EXPAND_2(a_Expr) a_Expr +/** @def RT_EXPAND + * Returns the expanded expression. + * @param a_Expr The expression to expand. */ +#define RT_EXPAND(a_Expr) RT_EXPAND_2(a_Expr) + +/** @def RT_STR + * Returns the argument as a string constant. + * @param str Argument to stringify. */ +#define RT_STR(str) #str +/** @def RT_XSTR + * Returns the expanded argument as a string. + * @param str Argument to expand and stringify. */ +#define RT_XSTR(str) RT_STR(str) + +/** @def RT_LSTR_2 + * Helper for RT_WSTR that gets the expanded @a str. + * @param str String litteral to prefix with 'L'. */ +#define RT_LSTR_2(str) L##str +/** @def RT_LSTR + * Returns the expanded argument with a L string prefix. + * + * Intended for converting ASCII string \#defines into wide char string + * litterals on Windows. + * + * @param str String litteral to . */ +#define RT_LSTR(str) RT_LSTR_2(str) + +/** @def RT_UNPACK_CALL + * Unpacks the an argument list inside an extra set of parenthesis and turns it + * into a call to @a a_Fn. + * + * @param a_Fn Function/macro to call. + * @param a_Args Parameter list in parenthesis. + */ +#define RT_UNPACK_CALL(a_Fn, a_Args) a_Fn a_Args + +#if defined(RT_COMPILER_SUPPORTS_VA_ARGS) || defined(DOXYGEN_RUNNING) + +/** @def RT_UNPACK_ARGS + * Returns the arguments without parenthesis. + * + * @param ... Parameter list in parenthesis. + * @remarks Requires RT_COMPILER_SUPPORTS_VA_ARGS. + */ +# define RT_UNPACK_ARGS(...) __VA_ARGS__ + +/** @def RT_COUNT_VA_ARGS_HLP + * Helper for RT_COUNT_VA_ARGS that picks out the argument count from + * RT_COUNT_VA_ARGS_REV_SEQ. */ +# define RT_COUNT_VA_ARGS_HLP( \ + c69, c68, c67, c66, c65, c64, c63, c62, c61, c60, \ + c59, c58, c57, c56, c55, c54, c53, c52, c51, c50, \ + c49, c48, c47, c46, c45, c44, c43, c42, c41, c40, \ + c39, c38, c37, c36, c35, c34, c33, c32, c31, c30, \ + c29, c28, c27, c26, c25, c24, c23, c22, c21, c20, \ + c19, c18, c17, c16, c15, c14, c13, c12, c11, c10, \ + c9, c8, c7, c6, c5, c4, c3, c2, c1, cArgs, ...) cArgs +/** Argument count sequence. */ +# define RT_COUNT_VA_ARGS_REV_SEQ \ + 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, \ + 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ + 39, 38, 37, 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 is for zero arguments. At least Visual C++ requires it. */ +# define RT_COUNT_VA_ARGS_PREFIX_RT_NOTHING RT_COUNT_VA_ARGS_REV_SEQ +/** + * Counts the number of arguments given to the variadic macro. + * + * Max is 69. + * + * @returns Number of arguments in the ellipsis + * @param ... Arguments to count. + * @remarks Requires RT_COMPILER_SUPPORTS_VA_ARGS. + */ +# define RT_COUNT_VA_ARGS(...) \ + RT_UNPACK_CALL(RT_COUNT_VA_ARGS_HLP, (RT_COUNT_VA_ARGS_PREFIX_ ## __VA_ARGS__ ## RT_NOTHING, \ + RT_COUNT_VA_ARGS_REV_SEQ)) + +#endif /* RT_COMPILER_SUPPORTS_VA_ARGS */ + + +/** @def RT_CONCAT + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The first part. + * @param b The second part. + */ +#define RT_CONCAT(a,b) RT_CONCAT_HLP(a,b) +/** RT_CONCAT helper, don't use. */ +#define RT_CONCAT_HLP(a,b) a##b + +/** @def RT_CONCAT3 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + */ +#define RT_CONCAT3(a,b,c) RT_CONCAT3_HLP(a,b,c) +/** RT_CONCAT3 helper, don't use. */ +#define RT_CONCAT3_HLP(a,b,c) a##b##c + +/** @def RT_CONCAT4 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + */ +#define RT_CONCAT4(a,b,c,d) RT_CONCAT4_HLP(a,b,c,d) +/** RT_CONCAT4 helper, don't use. */ +#define RT_CONCAT4_HLP(a,b,c,d) a##b##c##d + +/** @def RT_CONCAT5 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + */ +#define RT_CONCAT5(a,b,c,d,e) RT_CONCAT5_HLP(a,b,c,d,e) +/** RT_CONCAT5 helper, don't use. */ +#define RT_CONCAT5_HLP(a,b,c,d,e) a##b##c##d##e + +/** @def RT_CONCAT6 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + * @param f The 6th part. + */ +#define RT_CONCAT6(a,b,c,d,e,f) RT_CONCAT6_HLP(a,b,c,d,e,f) +/** RT_CONCAT6 helper, don't use. */ +#define RT_CONCAT6_HLP(a,b,c,d,e,f) a##b##c##d##e##f + +/** @def RT_CONCAT7 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + * @param f The 6th part. + * @param g The 7th part. + */ +#define RT_CONCAT7(a,b,c,d,e,f,g) RT_CONCAT7_HLP(a,b,c,d,e,f,g) +/** RT_CONCAT7 helper, don't use. */ +#define RT_CONCAT7_HLP(a,b,c,d,e,f,g) a##b##c##d##e##f##g + +/** @def RT_CONCAT8 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + * @param f The 6th part. + * @param g The 7th part. + * @param h The 8th part. + */ +#define RT_CONCAT8(a,b,c,d,e,f,g,h) RT_CONCAT8_HLP(a,b,c,d,e,f,g,h) +/** RT_CONCAT8 helper, don't use. */ +#define RT_CONCAT8_HLP(a,b,c,d,e,f,g,h) a##b##c##d##e##f##g##h + +/** @def RT_CONCAT9 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + * @param f The 6th part. + * @param g The 7th part. + * @param h The 8th part. + * @param i The 9th part. + */ +#define RT_CONCAT9(a,b,c,d,e,f,g,h,i) RT_CONCAT9_HLP(a,b,c,d,e,f,g,h,i) +/** RT_CONCAT9 helper, don't use. */ +#define RT_CONCAT9_HLP(a,b,c,d,e,f,g,h,i) a##b##c##d##e##f##g##h##i + +/** + * String constant tuple - string constant, strlen(string constant). + * + * @param a_szConst String constant. + * @sa RTSTRTUPLE + */ +#define RT_STR_TUPLE(a_szConst) a_szConst, (sizeof(a_szConst) - 1) + + +/** + * Macro for using in switch statements that turns constants into strings. + * + * @param a_Const The constant (not string). + */ +#define RT_CASE_RET_STR(a_Const) case a_Const: return #a_Const + + +/** @def RT_BIT + * Convert a bit number into an integer bitmask (unsigned). + * @param bit The bit number. + */ +#define RT_BIT(bit) ( 1U << (bit) ) + +/** @def RT_BIT_32 + * Convert a bit number into a 32-bit bitmask (unsigned). + * @param bit The bit number. + */ +#define RT_BIT_32(bit) ( UINT32_C(1) << (bit) ) + +/** @def RT_BIT_64 + * Convert a bit number into a 64-bit bitmask (unsigned). + * @param bit The bit number. + */ +#define RT_BIT_64(bit) ( UINT64_C(1) << (bit) ) + +/** @def RT_BIT_Z + * Convert a bit number into a size_t bitmask (for avoid MSC warnings). + * @param a_iBit The bit number. + */ +#define RT_BIT_Z(a_iBit) ( (size_t)(1) << (a_iBit) ) + + +/** @def RT_BF_GET + * Gets the value of a bit field in an integer value. + * + * This requires a couple of macros to be defined for the field: + * - \_SHIFT: The shift count to get to the field. + * - \_MASK: The field mask. + * + * @returns The bit field value. + * @param a_uValue The integer value containing the field. + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @sa #RT_BF_CLEAR, #RT_BF_SET, #RT_BF_MAKE, #RT_BF_ZMASK + */ +#define RT_BF_GET(a_uValue, a_FieldNm) ( ((a_uValue) >> RT_CONCAT(a_FieldNm,_SHIFT)) & RT_BF_ZMASK(a_FieldNm) ) + +/** @def RT_BF_SET + * Sets the given bit field in the integer value. + * + * This requires a couple of macros to be defined for the field: + * - \_SHIFT: The shift count to get to the field. + * - \_MASK: The field mask. Must have the same type as the + * integer value!! + * + * @returns Integer value with bit field set to @a a_uFieldValue. + * @param a_uValue The integer value containing the field. + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @param a_uFieldValue The new field value. + * @sa #RT_BF_GET, #RT_BF_CLEAR, #RT_BF_MAKE, #RT_BF_ZMASK + */ +#define RT_BF_SET(a_uValue, a_FieldNm, a_uFieldValue) ( RT_BF_CLEAR(a_uValue, a_FieldNm) | RT_BF_MAKE(a_FieldNm, a_uFieldValue) ) + +/** @def RT_BF_CLEAR + * Clears the given bit field in the integer value. + * + * This requires a couple of macros to be defined for the field: + * - \_SHIFT: The shift count to get to the field. + * - \_MASK: The field mask. Must have the same type as the + * integer value!! + * + * @returns Integer value with bit field set to zero. + * @param a_uValue The integer value containing the field. + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @sa #RT_BF_GET, #RT_BF_SET, #RT_BF_MAKE, #RT_BF_ZMASK + */ +#define RT_BF_CLEAR(a_uValue, a_FieldNm) ( (a_uValue) & ~RT_CONCAT(a_FieldNm,_MASK) ) + +/** @def RT_BF_MAKE + * Shifts and masks a bit field value into position in the integer value. + * + * This requires a couple of macros to be defined for the field: + * - \_SHIFT: The shift count to get to the field. + * - \_MASK: The field mask. + * + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @param a_uFieldValue The field value that should be masked and shifted + * into position. + * @sa #RT_BF_GET, #RT_BF_SET, #RT_BF_CLEAR, #RT_BF_ZMASK + */ +#define RT_BF_MAKE(a_FieldNm, a_uFieldValue) ( ((a_uFieldValue) & RT_BF_ZMASK(a_FieldNm) ) << RT_CONCAT(a_FieldNm,_SHIFT) ) + +/** @def RT_BF_ZMASK + * Helper for getting the field mask shifted to bit position zero. + * + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @sa #RT_BF_GET, #RT_BF_SET, #RT_BF_CLEAR, #RT_BF_MAKE + */ +#define RT_BF_ZMASK(a_FieldNm) ( RT_CONCAT(a_FieldNm,_MASK) >> RT_CONCAT(a_FieldNm,_SHIFT) ) + +/** Bit field compile time check helper + * @internal */ +#define RT_BF_CHECK_DO_XOR_MASK(a_uLeft, a_RightPrefix, a_FieldNm) ((a_uLeft) ^ RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK)) +/** Bit field compile time check helper + * @internal */ +#define RT_BF_CHECK_DO_OR_MASK(a_uLeft, a_RightPrefix, a_FieldNm) ((a_uLeft) | RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK)) +/** Bit field compile time check helper + * @internal */ +#define RT_BF_CHECK_DO_1ST_MASK_BIT(a_uLeft, a_RightPrefix, a_FieldNm) \ + ((a_uLeft) && ( (RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK) >> RT_CONCAT3(a_RightPrefix, a_FieldNm, _SHIFT)) & 1U ) ) +/** Used to check that a bit field mask does not start too early. + * @internal */ +#define RT_BF_CHECK_DO_MASK_START(a_uLeft, a_RightPrefix, a_FieldNm) \ + ( (a_uLeft) \ + && ( RT_CONCAT3(a_RightPrefix, a_FieldNm, _SHIFT) == 0 \ + || ( ( ( ((RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK) >> RT_CONCAT3(a_RightPrefix, a_FieldNm, _SHIFT)) & 1U) \ + << RT_CONCAT3(a_RightPrefix, a_FieldNm, _SHIFT)) /* => single bit mask, correct type */ \ + - 1U) /* => mask of all bits below the field */ \ + & RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK)) == 0 ) ) +/** @name Bit field compile time check recursion workers. + * @internal + * @{ */ +#define RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix, f1) \ + a_DoThis(a_uLeft, a_RightPrefix, f1) +#define RT_BF_CHECK_DO_2(a_DoThis, a_uLeft, a_RightPrefix, f1, f2) \ + RT_BF_CHECK_DO_1(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2) +#define RT_BF_CHECK_DO_3(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3) \ + RT_BF_CHECK_DO_2(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3) +#define RT_BF_CHECK_DO_4(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4) \ + RT_BF_CHECK_DO_3(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4) +#define RT_BF_CHECK_DO_5(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5) \ + RT_BF_CHECK_DO_4(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5) +#define RT_BF_CHECK_DO_6(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6) \ + RT_BF_CHECK_DO_5(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6) +#define RT_BF_CHECK_DO_7(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7) \ + RT_BF_CHECK_DO_6(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7) +#define RT_BF_CHECK_DO_8(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8) \ + RT_BF_CHECK_DO_7(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8) +#define RT_BF_CHECK_DO_9(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + RT_BF_CHECK_DO_8(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9) +#define RT_BF_CHECK_DO_10(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) \ + RT_BF_CHECK_DO_9(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10) +#define RT_BF_CHECK_DO_11(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \ + RT_BF_CHECK_DO_10(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) +#define RT_BF_CHECK_DO_12(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12) \ + RT_BF_CHECK_DO_11(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12) +#define RT_BF_CHECK_DO_13(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13) \ + RT_BF_CHECK_DO_12(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13) +#define RT_BF_CHECK_DO_14(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14) \ + RT_BF_CHECK_DO_13(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14) +#define RT_BF_CHECK_DO_15(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15) \ + RT_BF_CHECK_DO_14(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15) +#define RT_BF_CHECK_DO_16(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16) \ + RT_BF_CHECK_DO_15(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16) +#define RT_BF_CHECK_DO_17(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17) \ + RT_BF_CHECK_DO_16(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17) +#define RT_BF_CHECK_DO_18(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18) \ + RT_BF_CHECK_DO_17(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18) +#define RT_BF_CHECK_DO_19(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19) \ + RT_BF_CHECK_DO_18(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19) +#define RT_BF_CHECK_DO_20(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20) \ + RT_BF_CHECK_DO_19(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20) +#define RT_BF_CHECK_DO_21(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21) \ + RT_BF_CHECK_DO_20(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21) +#define RT_BF_CHECK_DO_22(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22) \ + RT_BF_CHECK_DO_21(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22) +#define RT_BF_CHECK_DO_23(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23) \ + RT_BF_CHECK_DO_22(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23) +#define RT_BF_CHECK_DO_24(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24) \ + RT_BF_CHECK_DO_23(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24) +#define RT_BF_CHECK_DO_25(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25) \ + RT_BF_CHECK_DO_24(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25) +#define RT_BF_CHECK_DO_26(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26) \ + RT_BF_CHECK_DO_25(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26) +#define RT_BF_CHECK_DO_27(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27) \ + RT_BF_CHECK_DO_26(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27) +#define RT_BF_CHECK_DO_28(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28) \ + RT_BF_CHECK_DO_27(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28) +#define RT_BF_CHECK_DO_29(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29) \ + RT_BF_CHECK_DO_28(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29) +#define RT_BF_CHECK_DO_30(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30) \ + RT_BF_CHECK_DO_29(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30) +#define RT_BF_CHECK_DO_31(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31) \ + RT_BF_CHECK_DO_30(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31) +#define RT_BF_CHECK_DO_32(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32) \ + RT_BF_CHECK_DO_31(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32) +#define RT_BF_CHECK_DO_33(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33) \ + RT_BF_CHECK_DO_32(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33) +#define RT_BF_CHECK_DO_34(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34) \ + RT_BF_CHECK_DO_33(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34) +#define RT_BF_CHECK_DO_35(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35) \ + RT_BF_CHECK_DO_34(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35) +#define RT_BF_CHECK_DO_36(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36) \ + RT_BF_CHECK_DO_35(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36) +#define RT_BF_CHECK_DO_37(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37) \ + RT_BF_CHECK_DO_36(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37) +#define RT_BF_CHECK_DO_38(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38) \ + RT_BF_CHECK_DO_37(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38) +#define RT_BF_CHECK_DO_39(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39) \ + RT_BF_CHECK_DO_38(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39) +#define RT_BF_CHECK_DO_40(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40) \ + RT_BF_CHECK_DO_39(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40) +#define RT_BF_CHECK_DO_41(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41) \ + RT_BF_CHECK_DO_40(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41) +#define RT_BF_CHECK_DO_42(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42) \ + RT_BF_CHECK_DO_41(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42) +#define RT_BF_CHECK_DO_43(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43) \ + RT_BF_CHECK_DO_42(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43) +#define RT_BF_CHECK_DO_44(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44) \ + RT_BF_CHECK_DO_43(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44) +#define RT_BF_CHECK_DO_45(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45) \ + RT_BF_CHECK_DO_44(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45) +#define RT_BF_CHECK_DO_46(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46) \ + RT_BF_CHECK_DO_45(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46) +#define RT_BF_CHECK_DO_47(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47) \ + RT_BF_CHECK_DO_46(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47) +#define RT_BF_CHECK_DO_48(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48) \ + RT_BF_CHECK_DO_47(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48) +#define RT_BF_CHECK_DO_49(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49) \ + RT_BF_CHECK_DO_48(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49) +#define RT_BF_CHECK_DO_50(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50) \ + RT_BF_CHECK_DO_49(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50) +#define RT_BF_CHECK_DO_51(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51) \ + RT_BF_CHECK_DO_40(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51) +#define RT_BF_CHECK_DO_52(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52) \ + RT_BF_CHECK_DO_51(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52) +#define RT_BF_CHECK_DO_53(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53) \ + RT_BF_CHECK_DO_52(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53) +#define RT_BF_CHECK_DO_54(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54) \ + RT_BF_CHECK_DO_53(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54) +#define RT_BF_CHECK_DO_55(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55) \ + RT_BF_CHECK_DO_54(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55) +#define RT_BF_CHECK_DO_56(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56) \ + RT_BF_CHECK_DO_55(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56) +#define RT_BF_CHECK_DO_57(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57) \ + RT_BF_CHECK_DO_56(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57) +#define RT_BF_CHECK_DO_58(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58) \ + RT_BF_CHECK_DO_57(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58) +#define RT_BF_CHECK_DO_59(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59) \ + RT_BF_CHECK_DO_58(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59) +#define RT_BF_CHECK_DO_60(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60) \ + RT_BF_CHECK_DO_59(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60) +#define RT_BF_CHECK_DO_61(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61) \ + RT_BF_CHECK_DO_60(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61) +#define RT_BF_CHECK_DO_62(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62) \ + RT_BF_CHECK_DO_61(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62) +#define RT_BF_CHECK_DO_63(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62, f63) \ + RT_BF_CHECK_DO_62(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62, f63) +#define RT_BF_CHECK_DO_64(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62, f63, f64) \ + RT_BF_CHECK_DO_63(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62, f63, f64) +/** @} */ + +/** @def RT_BF_ASSERT_COMPILE_CHECKS + * Emits a series of AssertCompile statements checking that the bit-field + * declarations doesn't overlap, has holes, and generally makes some sense. + * + * This requires variadic macros because its too much to type otherwise. + */ +#if defined(RT_COMPILER_SUPPORTS_VA_ARGS) || defined(DOXYGEN_RUNNING) +# define RT_BF_ASSERT_COMPILE_CHECKS(a_Prefix, a_uZero, a_uCovered, a_Fields) \ + AssertCompile(RT_BF_CHECK_DO_N(RT_BF_CHECK_DO_OR_MASK, a_uZero, a_Prefix, RT_UNPACK_ARGS a_Fields ) == a_uCovered); \ + AssertCompile(RT_BF_CHECK_DO_N(RT_BF_CHECK_DO_XOR_MASK, a_uCovered, a_Prefix, RT_UNPACK_ARGS a_Fields ) == 0); \ + AssertCompile(RT_BF_CHECK_DO_N(RT_BF_CHECK_DO_1ST_MASK_BIT, true, a_Prefix, RT_UNPACK_ARGS a_Fields ) == true); \ + AssertCompile(RT_BF_CHECK_DO_N(RT_BF_CHECK_DO_MASK_START, true, a_Prefix, RT_UNPACK_ARGS a_Fields ) == true) +/** Bit field compile time check helper + * @internal */ +# define RT_BF_CHECK_DO_N(a_DoThis, a_uLeft, a_RightPrefix, ...) \ + RT_UNPACK_CALL(RT_CONCAT(RT_BF_CHECK_DO_, RT_EXPAND(RT_COUNT_VA_ARGS(__VA_ARGS__))), (a_DoThis, a_uLeft, a_RightPrefix, __VA_ARGS__)) +#else +# define RT_BF_ASSERT_COMPILE_CHECKS(a_Prefix, a_uZero, a_uCovered, a_Fields) AssertCompile(true) +#endif + + +/** @def RT_ALIGN + * Align macro. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * + * @remark Be extremely careful when using this macro with type which sizeof != sizeof int. + * When possible use any of the other RT_ALIGN_* macros. And when that's not + * possible, make 101% sure that uAlignment is specified with a right sized type. + * + * Specifying an unsigned 32-bit alignment constant with a 64-bit value will give + * you a 32-bit return value! + * + * In short: Don't use this macro. Use RT_ALIGN_T() instead. + */ +#define RT_ALIGN(u, uAlignment) ( ((u) + ((uAlignment) - 1)) & ~((uAlignment) - 1) ) + +/** @def RT_ALIGN_T + * Align macro. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param type Integer type to use while aligning. + * @remark This macro is the preferred alignment macro, it doesn't have any of the pitfalls RT_ALIGN has. + */ +#define RT_ALIGN_T(u, uAlignment, type) ( ((type)(u) + ((uAlignment) - 1)) & ~(type)((uAlignment) - 1) ) + +/** @def RT_ALIGN_32 + * Align macro for a 32-bit value. + * @param u32 Value to align. + * @param uAlignment The alignment. Power of two! + */ +#define RT_ALIGN_32(u32, uAlignment) RT_ALIGN_T(u32, uAlignment, uint32_t) + +/** @def RT_ALIGN_64 + * Align macro for a 64-bit value. + * @param u64 Value to align. + * @param uAlignment The alignment. Power of two! + */ +#define RT_ALIGN_64(u64, uAlignment) RT_ALIGN_T(u64, uAlignment, uint64_t) + +/** @def RT_ALIGN_Z + * Align macro for size_t. + * @param cb Value to align. + * @param uAlignment The alignment. Power of two! + */ +#define RT_ALIGN_Z(cb, uAlignment) RT_ALIGN_T(cb, uAlignment, size_t) + +/** @def RT_ALIGN_P + * Align macro for pointers. + * @param pv Value to align. + * @param uAlignment The alignment. Power of two! + */ +#define RT_ALIGN_P(pv, uAlignment) RT_ALIGN_PT(pv, uAlignment, void *) + +/** @def RT_ALIGN_PT + * Align macro for pointers with type cast. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param CastType The type to cast the result to. + */ +#define RT_ALIGN_PT(u, uAlignment, CastType) ( (CastType)RT_ALIGN_T(u, uAlignment, uintptr_t) ) + +/** @def RT_ALIGN_R3PT + * Align macro for ring-3 pointers with type cast. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param CastType The type to cast the result to. + */ +#define RT_ALIGN_R3PT(u, uAlignment, CastType) ( (CastType)RT_ALIGN_T(u, uAlignment, RTR3UINTPTR) ) + +/** @def RT_ALIGN_R0PT + * Align macro for ring-0 pointers with type cast. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param CastType The type to cast the result to. + */ +#define RT_ALIGN_R0PT(u, uAlignment, CastType) ( (CastType)RT_ALIGN_T(u, uAlignment, RTR0UINTPTR) ) + +/** @def RT_ALIGN_GCPT + * Align macro for GC pointers with type cast. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param CastType The type to cast the result to. + */ +#define RT_ALIGN_GCPT(u, uAlignment, CastType) ( (CastType)RT_ALIGN_T(u, uAlignment, RTGCUINTPTR) ) + + +/** @def RT_OFFSETOF + * Our own special offsetof() variant, returns a signed result. + * + * @returns offset into the structure of the specified member. signed. + * @param type Structure type. + * @param member Member. + * + * @remarks Only use this for static offset calculations. Please + * use RT_UOFFSETOF_DYN for dynamic ones (i.e. involves + * non-constant array indexing). + * + */ +#if RT_GNUC_PREREQ(4, 0) +# define RT_OFFSETOF(type, member) ( (int)__builtin_offsetof(type, member) ) +#else +# define RT_OFFSETOF(type, member) ( (int)(intptr_t)&( ((type *)(void *)0)->member) ) +#endif + +/** @def RT_UOFFSETOF + * Our own offsetof() variant, returns an unsigned result. + * + * @returns offset into the structure of the specified member. unsigned. + * @param type Structure type. + * @param member Member. + * + * @remarks Only use this for static offset calculations. Please + * use RT_UOFFSETOF_DYN for dynamic ones (i.e. involves + * non-constant array indexing). + */ +#if RT_GNUC_PREREQ(4, 0) +# define RT_UOFFSETOF(type, member) ( (uintptr_t)__builtin_offsetof(type, member) ) +#else +# define RT_UOFFSETOF(type, member) ( (uintptr_t)&( ((type *)(void *)0)->member) ) +#endif + +/** @def RT_OFFSETOF_ADD + * RT_OFFSETOF with an addend. + * + * @returns offset into the structure of the specified member. signed. + * @param type Structure type. + * @param member Member. + * @param addend The addend to add to the offset. + * + * @remarks Only use this for static offset calculations. + */ +#define RT_OFFSETOF_ADD(type, member, addend) ( (int)RT_UOFFSETOF_ADD(type, member, addend) ) + +/** @def RT_UOFFSETOF_ADD + * RT_UOFFSETOF with an addend. + * + * @returns offset into the structure of the specified member. signed. + * @param type Structure type. + * @param member Member. + * @param addend The addend to add to the offset. + * + * @remarks Only use this for static offset calculations. + */ +#if RT_GNUC_PREREQ(4, 0) +# define RT_UOFFSETOF_ADD(type, member, addend) ( (uintptr_t)(__builtin_offsetof(type, member) + (addend))) +#else +# define RT_UOFFSETOF_ADD(type, member, addend) ( (uintptr_t)&( ((type *)(void *)(uintptr_t)(addend))->member) ) +#endif + +/** @def RT_UOFFSETOF_DYN + * Dynamic (runtime) structure offset calculations, involving + * indexing of array members via variable. + * + * @returns offset into the structure of the specified member. signed. + * @param type Structure type. + * @param memberarray Member. + */ +#if defined(__cplusplus) && RT_GNUC_PREREQ(4, 4) +# define RT_UOFFSETOF_DYN(type, memberarray) ( (uintptr_t)&( ((type *)(void *)0x1000)->memberarray) - 0x1000 ) +#else +# define RT_UOFFSETOF_DYN(type, memberarray) ( (uintptr_t)&( ((type *)(void *)0)->memberarray) ) +#endif + + +/** @def RT_SIZEOFMEMB + * Get the size of a structure member. + * + * @returns size of the structure member. + * @param type Structure type. + * @param member Member. + */ +#define RT_SIZEOFMEMB(type, member) ( sizeof(((type *)(void *)0)->member) ) + +/** @def RT_UOFFSET_AFTER + * Returns the offset of the first byte following a structure/union member. + * + * @return byte offset into the struct. + * @param a_Type Structure type. + * @param a_Member The member name. + */ +#define RT_UOFFSET_AFTER(a_Type, a_Member) ( RT_UOFFSETOF(a_Type, a_Member) + RT_SIZEOFMEMB(a_Type, a_Member) ) + +/** @def RT_FROM_MEMBER + * Convert a pointer to a structure member into a pointer to the structure. + * + * @returns pointer to the structure. + * @param pMem Pointer to the member. + * @param Type Structure type. + * @param Member Member name. + */ +#define RT_FROM_MEMBER(pMem, Type, Member) ( (Type *) ((uint8_t *)(void *)(pMem) - RT_UOFFSETOF(Type, Member)) ) + +/** @def RT_FROM_CPP_MEMBER + * Same as RT_FROM_MEMBER except it avoids the annoying g++ warnings about + * invalid access to non-static data member of NULL object. + * + * @returns pointer to the structure. + * @param pMem Pointer to the member. + * @param Type Structure type. + * @param Member Member name. + * + * @remarks Using the __builtin_offsetof does not shut up the compiler. + */ +#if defined(__GNUC__) && defined(__cplusplus) +# define RT_FROM_CPP_MEMBER(pMem, Type, Member) \ + ( (Type *) ((uintptr_t)(pMem) - (uintptr_t)&((Type *)0x1000)->Member + 0x1000U) ) +#else +# define RT_FROM_CPP_MEMBER(pMem, Type, Member) RT_FROM_MEMBER(pMem, Type, Member) +#endif + +/** @def RT_FROM_MEMBER_DYN + * Convert a pointer to a structure member into a pointer to the structure. + * + * @returns pointer to the structure. + * @param pMem Pointer to the member. + * @param Type Structure type. + * @param Member Member name dynamic size (some array is index by + * non-constant value). + */ +#define RT_FROM_MEMBER_DYN(pMem, Type, Member) ( (Type *) ((uint8_t *)(void *)(pMem) - RT_UOFFSETOF_DYN(Type, Member)) ) + +/** @def RT_ELEMENTS + * Calculates the number of elements in a statically sized array. + * @returns Element count. + * @param aArray Array in question. + */ +#define RT_ELEMENTS(aArray) ( sizeof(aArray) / sizeof((aArray)[0]) ) + +/** @def RT_SAFE_SUBSCRIPT + * Safe array subscript using modulo and size_t cast. + * @param a_Array The array. + * @param a_idx The array index, cast to size_t to ensure unsigned. + */ +#define RT_SAFE_SUBSCRIPT(a_Array, a_idx) (a_Array)[(size_t)(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_SAFE_SUBSCRIPT32 + * Safe array subscript using modulo and uint32_t cast. + * @param a_Array The array. + * @param a_idx The array index, cast to size_t to ensure unsigned. + * @note Only consider using this if array size is not power of two. + */ +#define RT_SAFE_SUBSCRIPT32(a_Array, a_idx) (a_Array)[(uint32_t)(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_SAFE_SUBSCRIPT16 + * Safe array subscript using modulo and uint16_t cast. + * @param a_Array The array. + * @param a_idx The array index, cast to size_t to ensure unsigned. + * @note Only consider using this if array size is not power of two. + */ +#define RT_SAFE_SUBSCRIPT16(a_Array, a_idx) (a_Array)[(uint16_t)(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_SAFE_SUBSCRIPT8 + * Safe array subscript using modulo and uint8_t cast. + * @param a_Array The array. + * @param a_idx The array index, cast to size_t to ensure unsigned. + * @note Only consider using this if array size is not power of two. + */ +#define RT_SAFE_SUBSCRIPT8(a_Array, a_idx) (a_Array)[(uint8_t)(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_SAFE_SUBSCRIPT_NC + * Safe array subscript using modulo but no cast. + * @param a_Array The array. + * @param a_idx The array index - assumes unsigned type. + * @note Only consider using this if array size is not power of two. + */ +#define RT_SAFE_SUBSCRIPT_NC(a_Array, a_idx) (a_Array)[(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_FLEXIBLE_ARRAY + * What to up inside the square brackets when declaring a structure member + * with a flexible size. + * + * @note RT_FLEXIBLE_ARRAY_EXTENSION must always preceed the type, unless + * it's C-only code. + * + * @note Use RT_UOFFSETOF() to calculate the structure size. + * + * @note Never do a sizeof() on the structure or member! + * + * @note The member must be the last one. + * + * @note GCC does not permit using this in a union. So, for unions you must + * use RT_FLEXIBLE_ARRAY_IN_UNION instead. + * + * @note GCC does not permit using this in nested structures, where as MSC + * does. So, use RT_FLEXIBLE_ARRAY_NESTED for that. + * + * @sa RT_FLEXIBLE_ARRAY_NESTED, RT_FLEXIBLE_ARRAY_IN_UNION + */ +#if RT_MSC_PREREQ(RT_MSC_VER_VS2005) /** @todo Probably much much earlier. */ \ + || (defined(__cplusplus) && RT_GNUC_PREREQ(6, 1)) /* not tested 7.x, but hope it works with __extension__ too. */ \ + || defined(__WATCOMC__) /* openwatcom 1.9 supports it, we don't care about older atm. */ \ + || RT_CLANG_PREREQ_EX(3, 4, 0) /* Only tested clang v3.4, support is probably older. */ +# define RT_FLEXIBLE_ARRAY +# if defined(__cplusplus) && defined(_MSC_VER) +# pragma warning(disable:4200) /* -wd4200 does not work with VS2010 */ +# pragma warning(disable:4815) /* -wd4815 does not work with VS2019 */ +# endif +#elif defined(__STDC_VERSION__) +# if __STDC_VERSION__ >= 1999901L +# define RT_FLEXIBLE_ARRAY +# else +# define RT_FLEXIBLE_ARRAY 1 +# endif +#else +# define RT_FLEXIBLE_ARRAY 1 +#endif + +/** @def RT_FLEXIBLE_ARRAY_EXTENSION + * A trick to make GNU C++ quietly accept flexible arrays in C++ code when + * pedantic warnings are enabled. Put this on the line before the flexible + * array. */ +#if (RT_GNUC_PREREQ(7, 0) && defined(__cplusplus)) || defined(DOXGYEN_RUNNING) +# define RT_FLEXIBLE_ARRAY_EXTENSION RT_GCC_EXTENSION +#else +# define RT_FLEXIBLE_ARRAY_EXTENSION +#endif + +/** @def RT_FLEXIBLE_ARRAY_NESTED + * Variant of RT_FLEXIBLE_ARRAY for use in structures that are nested. + * + * GCC only allow the use of flexible array member in the top structure, whereas + * MSC is less strict and let you do struct { struct { char szName[]; } s; }; + * + * @note See notes for RT_FLEXIBLE_ARRAY. + * + * @note GCC does not permit using this in a union. So, for unions you must + * use RT_FLEXIBLE_ARRAY_IN_NESTED_UNION instead. + * + * @sa RT_FLEXIBLE_ARRAY, RT_FLEXIBLE_ARRAY_IN_NESTED_UNION + */ +#ifdef _MSC_VER +# define RT_FLEXIBLE_ARRAY_NESTED RT_FLEXIBLE_ARRAY +#else +# define RT_FLEXIBLE_ARRAY_NESTED 1 +#endif + +/** @def RT_FLEXIBLE_ARRAY_IN_UNION + * The union version of RT_FLEXIBLE_ARRAY. + * + * @remarks GCC does not support flexible array members in unions, 6.1.x + * actively checks for this. Visual C++ 2010 seems happy with it. + * + * @note See notes for RT_FLEXIBLE_ARRAY. + * + * @sa RT_FLEXIBLE_ARRAY, RT_FLEXIBLE_ARRAY_IN_NESTED_UNION + */ +#ifdef _MSC_VER +# define RT_FLEXIBLE_ARRAY_IN_UNION RT_FLEXIBLE_ARRAY +#else +# define RT_FLEXIBLE_ARRAY_IN_UNION 1 +#endif + +/** @def RT_FLEXIBLE_ARRAY_IN_NESTED_UNION + * The union version of RT_FLEXIBLE_ARRAY_NESTED. + * + * @note See notes for RT_FLEXIBLE_ARRAY. + * + * @sa RT_FLEXIBLE_ARRAY, RT_FLEXIBLE_ARRAY_IN_NESTED_UNION + */ +#ifdef _MSC_VER +# define RT_FLEXIBLE_ARRAY_IN_NESTED_UNION RT_FLEXIBLE_ARRAY_NESTED +#else +# define RT_FLEXIBLE_ARRAY_IN_NESTED_UNION 1 +#endif + +/** @def RT_UNION_NM + * For compilers (like DTrace) that does not grok nameless unions, we have a + * little hack to make them palatable. + */ +/** @def RT_STRUCT_NM + * For compilers (like DTrace) that does not grok nameless structs (it is + * non-standard C++), we have a little hack to make them palatable. + */ +#ifdef IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS +# define RT_UNION_NM(a_Nm) a_Nm +# define RT_STRUCT_NM(a_Nm) a_Nm +#else +# define RT_UNION_NM(a_Nm) +# define RT_STRUCT_NM(a_Nm) +#endif + +/** + * Checks if the value is a power of two. + * + * @returns true if power of two, false if not. + * @param uVal The value to test. + * @remarks 0 is a power of two. + * @see VERR_NOT_POWER_OF_TWO + */ +#define RT_IS_POWER_OF_TWO(uVal) ( ((uVal) & ((uVal) - 1)) == 0) + +#ifdef RT_OS_OS2 +/* Undefine RT_MAX since there is an unfortunate clash with the max + resource type define in os2.h. */ +# undef RT_MAX +#endif + +/** @def RT_MAX + * Finds the maximum value. + * @returns The higher of the two. + * @param Value1 Value 1 + * @param Value2 Value 2 + */ +#define RT_MAX(Value1, Value2) ( (Value1) >= (Value2) ? (Value1) : (Value2) ) + +/** @def RT_MIN + * Finds the minimum value. + * @returns The lower of the two. + * @param Value1 Value 1 + * @param Value2 Value 2 + */ +#define RT_MIN(Value1, Value2) ( (Value1) <= (Value2) ? (Value1) : (Value2) ) + +/** @def RT_CLAMP + * Clamps the value to minimum and maximum values. + * @returns The clamped value. + * @param Value The value to check. + * @param Min Minimum value. + * @param Max Maximum value. + */ +#define RT_CLAMP(Value, Min, Max) ( (Value) > (Max) ? (Max) : (Value) < (Min) ? (Min) : (Value) ) + +/** @def RT_ABS + * Get the absolute (non-negative) value. + * @returns The absolute value of Value. + * @param Value The value. + */ +#define RT_ABS(Value) ( (Value) >= 0 ? (Value) : -(Value) ) + +/** @def RT_BOOL + * Turn non-zero/zero into true/false + * @returns The resulting boolean value. + * @param Value The value. + */ +#define RT_BOOL(Value) ( !!(Value) ) + +/** @def RT_LO_U8 + * Gets the low uint8_t of a uint16_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_LO_U8(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint16_t)); (uint8_t)(a); }) +#elif defined(_MSC_VER) /* shut up cast truncates constant value warnings */ +# define RT_LO_U8(a) ( (uint8_t)(UINT8_MAX & (a)) ) +#else +# define RT_LO_U8(a) ( (uint8_t)(a) ) +#endif +/** @def RT_HI_U8 + * Gets the high uint8_t of a uint16_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_HI_U8(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint16_t)); (uint8_t)((a) >> 8); }) +#else +# define RT_HI_U8(a) ( (uint8_t)((a) >> 8) ) +#endif + +/** @def RT_LO_U16 + * Gets the low uint16_t of a uint32_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_LO_U16(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint32_t)); (uint16_t)(a); }) +#elif defined(_MSC_VER) /* shut up cast truncates constant value warnings */ +# define RT_LO_U16(a) ( (uint16_t)(UINT16_MAX & (a)) ) +#else +# define RT_LO_U16(a) ( (uint16_t)(a) ) +#endif +/** @def RT_HI_U16 + * Gets the high uint16_t of a uint32_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_HI_U16(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint32_t)); (uint16_t)((a) >> 16); }) +#else +# define RT_HI_U16(a) ( (uint16_t)((a) >> 16) ) +#endif + +/** @def RT_LO_U32 + * Gets the low uint32_t of a uint64_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_LO_U32(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint64_t)); (uint32_t)(a); }) +#elif defined(_MSC_VER) /* shut up cast truncates constant value warnings */ +# define RT_LO_U32(a) ( (uint32_t)(UINT32_MAX & (a)) ) +#else +# define RT_LO_U32(a) ( (uint32_t)(a) ) +#endif +/** @def RT_HI_U32 + * Gets the high uint32_t of a uint64_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_HI_U32(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint64_t)); (uint32_t)((a) >> 32); }) +#else +# define RT_HI_U32(a) ( (uint32_t)((a) >> 32) ) +#endif + +/** @def RT_BYTE1 + * Gets the first byte of something. */ +#define RT_BYTE1(a) ( (uint8_t)((a) & 0xff) ) +/** @def RT_BYTE2 + * Gets the second byte of something. */ +#define RT_BYTE2(a) ( (uint8_t)(((a) >> 8) & 0xff) ) +/** @def RT_BYTE3 + * Gets the second byte of something. */ +#define RT_BYTE3(a) ( (uint8_t)(((a) >> 16) & 0xff) ) +/** @def RT_BYTE4 + * Gets the fourth byte of something. */ +#define RT_BYTE4(a) ( (uint8_t)(((a) >> 24) & 0xff) ) +/** @def RT_BYTE5 + * Gets the fifth byte of something. */ +#define RT_BYTE5(a) ( (uint8_t)(((a) >> 32) & 0xff) ) +/** @def RT_BYTE6 + * Gets the sixth byte of something. */ +#define RT_BYTE6(a) ( (uint8_t)(((a) >> 40) & 0xff) ) +/** @def RT_BYTE7 + * Gets the seventh byte of something. */ +#define RT_BYTE7(a) ( (uint8_t)(((a) >> 48) & 0xff) ) +/** @def RT_BYTE8 + * Gets the eight byte of something. */ +#define RT_BYTE8(a) ( (uint8_t)(((a) >> 56) & 0xff) ) + + +/** @def RT_LODWORD + * Gets the low dword (=uint32_t) of something. + * @deprecated Use RT_LO_U32. */ +#define RT_LODWORD(a) ( (uint32_t)(a) ) +/** @def RT_HIDWORD + * Gets the high dword (=uint32_t) of a 64-bit of something. + * @deprecated Use RT_HI_U32. */ +#define RT_HIDWORD(a) ( (uint32_t)((a) >> 32) ) + +/** @def RT_LOWORD + * Gets the low word (=uint16_t) of something. + * @deprecated Use RT_LO_U16. */ +#define RT_LOWORD(a) ( (a) & 0xffff ) +/** @def RT_HIWORD + * Gets the high word (=uint16_t) of a 32-bit something. + * @deprecated Use RT_HI_U16. */ +#define RT_HIWORD(a) ( (a) >> 16 ) + +/** @def RT_LOBYTE + * Gets the low byte of something. + * @deprecated Use RT_LO_U8. */ +#define RT_LOBYTE(a) ( (a) & 0xff ) +/** @def RT_HIBYTE + * Gets the high byte of a 16-bit something. + * @deprecated Use RT_HI_U8. */ +#define RT_HIBYTE(a) ( (a) >> 8 ) + + +/** @def RT_MAKE_U64 + * Constructs a uint64_t value from two uint32_t values. + */ +#define RT_MAKE_U64(Lo, Hi) ( (uint64_t)((uint32_t)(Hi)) << 32 | (uint32_t)(Lo) ) + +/** @def RT_MAKE_U64_FROM_U16 + * Constructs a uint64_t value from four uint16_t values. + */ +#define RT_MAKE_U64_FROM_U16(w0, w1, w2, w3) \ + ((uint64_t)( (uint64_t)((uint16_t)(w3)) << 48 \ + | (uint64_t)((uint16_t)(w2)) << 32 \ + | (uint32_t)((uint16_t)(w1)) << 16 \ + | (uint16_t)(w0) )) + +/** @def RT_MAKE_U64_FROM_U8 + * Constructs a uint64_t value from eight uint8_t values. + */ +#define RT_MAKE_U64_FROM_U8(b0, b1, b2, b3, b4, b5, b6, b7) \ + ((uint64_t)( (uint64_t)((uint8_t)(b7)) << 56 \ + | (uint64_t)((uint8_t)(b6)) << 48 \ + | (uint64_t)((uint8_t)(b5)) << 40 \ + | (uint64_t)((uint8_t)(b4)) << 32 \ + | (uint64_t)((uint8_t)(b3)) << 24 \ + | (uint64_t)((uint8_t)(b2)) << 16 \ + | (uint64_t)((uint8_t)(b1)) << 8 \ + | (uint64_t) (uint8_t)(b0) )) + +/** @def RT_MAKE_U32 + * Constructs a uint32_t value from two uint16_t values. + */ +#define RT_MAKE_U32(Lo, Hi) \ + ((uint32_t)( (uint32_t)((uint16_t)(Hi)) << 16 \ + | (uint16_t)(Lo) )) + +/** @def RT_MAKE_U32_FROM_U8 + * Constructs a uint32_t value from four uint8_t values. + */ +#define RT_MAKE_U32_FROM_U8(b0, b1, b2, b3) \ + ((uint32_t)( (uint32_t)((uint8_t)(b3)) << 24 \ + | (uint32_t)((uint8_t)(b2)) << 16 \ + | (uint32_t)((uint8_t)(b1)) << 8 \ + | (uint8_t)(b0) )) + +/** @def RT_MAKE_U16 + * Constructs a uint16_t value from two uint8_t values. + */ +#define RT_MAKE_U16(Lo, Hi) \ + ((uint16_t)( (uint16_t)((uint8_t)(Hi)) << 8 \ + | (uint8_t)(Lo) )) + + +/** @def RT_BSWAP_U64 + * Reverses the byte order of an uint64_t value. */ +#if defined(__GNUC__) +# define RT_BSWAP_U64(u64) (__builtin_constant_p((u64)) ? RT_BSWAP_U64_C(u64) : ASMByteSwapU64(u64)) +#else +# define RT_BSWAP_U64(u64) ASMByteSwapU64(u64) +#endif + +/** @def RT_BSWAP_U32 + * Reverses the byte order of an uint32_t value. */ +#if defined(__GNUC__) +# define RT_BSWAP_U32(u32) (__builtin_constant_p((u32)) ? RT_BSWAP_U32_C(u32) : ASMByteSwapU32(u32)) +#else +# define RT_BSWAP_U32(u32) ASMByteSwapU32(u32) +#endif + +/** @def RT_BSWAP_U16 + * Reverses the byte order of an uint16_t value. */ +#if defined(__GNUC__) +# define RT_BSWAP_U16(u16) (__builtin_constant_p((u16)) ? RT_BSWAP_U16_C(u16) : ASMByteSwapU16(u16)) +#else +# define RT_BSWAP_U16(u16) ASMByteSwapU16(u16) +#endif + +/** @def RT_BSWAP_S64 + * Reverses the byte order of an int64_t value. */ +#define RT_BSWAP_S64(i64) ((int64_t)RT_BSWAP_U64((uint64_t)i64)) + +/** @def RT_BSWAP_S32 + * Reverses the byte order of an int32_t value. */ +#define RT_BSWAP_S32(i32) ((int32_t)RT_BSWAP_U32((uint32_t)i32)) + +/** @def RT_BSWAP_S16 + * Reverses the byte order of an int16_t value. */ +#define RT_BSWAP_S16(i16) ((int16_t)RT_BSWAP_U16((uint16_t)i16)) + + +/** @def RT_BSWAP_U64_C + * Reverses the byte order of an uint64_t constant. */ +#define RT_BSWAP_U64_C(u64) RT_MAKE_U64(RT_BSWAP_U32_C((u64) >> 32), RT_BSWAP_U32_C((u64) & 0xffffffff)) + +/** @def RT_BSWAP_U32_C + * Reverses the byte order of an uint32_t constant. */ +#define RT_BSWAP_U32_C(u32) RT_MAKE_U32_FROM_U8(RT_BYTE4(u32), RT_BYTE3(u32), RT_BYTE2(u32), RT_BYTE1(u32)) + +/** @def RT_BSWAP_U16_C + * Reverses the byte order of an uint16_t constant. */ +#define RT_BSWAP_U16_C(u16) RT_MAKE_U16(RT_HIBYTE(u16), RT_LOBYTE(u16)) + +/** @def RT_BSWAP_S64_C + * Reverses the byte order of an int64_t constant. */ +#define RT_BSWAP_S64_C(i64) ((int64_t)RT_MAKE_U64(RT_BSWAP_U32_C((uint64_t)(i64) >> 32), RT_BSWAP_U32_C((uint32_t)(i64)))) + +/** @def RT_BSWAP_S32_C + * Reverses the byte order of an int32_t constant. */ +#define RT_BSWAP_S32_C(i32) ((int32_t)RT_MAKE_U32_FROM_U8(RT_BYTE4(i32), RT_BYTE3(i32), RT_BYTE2(i32), RT_BYTE1(i))) + +/** @def RT_BSWAP_S16_C + * Reverses the byte order of an uint16_t constant. */ +#define RT_BSWAP_S16_C(i16) ((int16_t)RT_MAKE_U16(RT_HIBYTE(i16), RT_LOBYTE(i16))) + + + +/** @name Host to/from little endian. + * @note Typically requires iprt/asm.h to be included. + * @{ */ + +/** @def RT_H2LE_U64 + * Converts an uint64_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U64(u64) RT_BSWAP_U64(u64) +#else +# define RT_H2LE_U64(u64) (u64) +#endif + +/** @def RT_H2LE_U64_C + * Converts an uint64_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U64_C(u64) RT_BSWAP_U64_C(u64) +#else +# define RT_H2LE_U64_C(u64) (u64) +#endif + +/** @def RT_H2LE_U32 + * Converts an uint32_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U32(u32) RT_BSWAP_U32(u32) +#else +# define RT_H2LE_U32(u32) (u32) +#endif + +/** @def RT_H2LE_U32_C + * Converts an uint32_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U32_C(u32) RT_BSWAP_U32_C(u32) +#else +# define RT_H2LE_U32_C(u32) (u32) +#endif + +/** @def RT_H2LE_U16 + * Converts an uint16_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U16(u16) RT_BSWAP_U16(u16) +#else +# define RT_H2LE_U16(u16) (u16) +#endif + +/** @def RT_H2LE_U16_C + * Converts an uint16_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U16_C(u16) RT_BSWAP_U16_C(u16) +#else +# define RT_H2LE_U16_C(u16) (u16) +#endif + + +/** @def RT_LE2H_U64 + * Converts an uint64_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U64(u64) RT_BSWAP_U64(u64) +#else +# define RT_LE2H_U64(u64) (u64) +#endif + +/** @def RT_LE2H_U64_C + * Converts an uint64_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U64_C(u64) RT_BSWAP_U64_C(u64) +#else +# define RT_LE2H_U64_C(u64) (u64) +#endif + +/** @def RT_LE2H_U32 + * Converts an uint32_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U32(u32) RT_BSWAP_U32(u32) +#else +# define RT_LE2H_U32(u32) (u32) +#endif + +/** @def RT_LE2H_U32_C + * Converts an uint32_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U32_C(u32) RT_BSWAP_U32_C(u32) +#else +# define RT_LE2H_U32_C(u32) (u32) +#endif + +/** @def RT_LE2H_U16 + * Converts an uint16_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U16(u16) RT_BSWAP_U16(u16) +#else +# define RT_LE2H_U16(u16) (u16) +#endif + +/** @def RT_LE2H_U16_C + * Converts an uint16_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U16_C(u16) RT_BSWAP_U16_C(u16) +#else +# define RT_LE2H_U16_C(u16) (u16) +#endif + +/** @def RT_H2LE_S64 + * Converts an int64_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S64(i64) RT_BSWAP_S64(i64) +#else +# define RT_H2LE_S64(i64) (i64) +#endif + +/** @def RT_H2LE_S64_C + * Converts an int64_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S64_C(i64) RT_BSWAP_S64_C(i64) +#else +# define RT_H2LE_S64_C(i64) (i64) +#endif + +/** @def RT_H2LE_S32 + * Converts an int32_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S32(i32) RT_BSWAP_S32(i32) +#else +# define RT_H2LE_S32(i32) (i32) +#endif + +/** @def RT_H2LE_S32_C + * Converts an int32_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S32_C(i32) RT_BSWAP_S32_C(i32) +#else +# define RT_H2LE_S32_C(i32) (i32) +#endif + +/** @def RT_H2LE_S16 + * Converts an int16_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S16(i16) RT_BSWAP_S16(i16) +#else +# define RT_H2LE_S16(i16) (i16) +#endif + +/** @def RT_H2LE_S16_C + * Converts an int16_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S16_C(i16) RT_BSWAP_S16_C(i16) +#else +# define RT_H2LE_S16_C(i16) (i16) +#endif + +/** @def RT_LE2H_S64 + * Converts an int64_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S64(i64) RT_BSWAP_S64(i64) +#else +# define RT_LE2H_S64(i64) (i64) +#endif + +/** @def RT_LE2H_S64_C + * Converts an int64_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S64_C(i64) RT_BSWAP_S64_C(i64) +#else +# define RT_LE2H_S64_C(i64) (i64) +#endif + +/** @def RT_LE2H_S32 + * Converts an int32_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S32(i32) RT_BSWAP_S32(i32) +#else +# define RT_LE2H_S32(i32) (i32) +#endif + +/** @def RT_LE2H_S32_C + * Converts an int32_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S32_C(i32) RT_BSWAP_S32_C(i32) +#else +# define RT_LE2H_S32_C(i32) (i32) +#endif + +/** @def RT_LE2H_S16 + * Converts an int16_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S16(i16) RT_BSWAP_S16(i16) +#else +# define RT_LE2H_S16(i16) (i16) +#endif + +/** @def RT_LE2H_S16_C + * Converts an int16_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S16_C(i16) RT_BSWAP_S16_C(i16) +#else +# define RT_LE2H_S16_C(i16) (i16) +#endif + +/** @} */ + +/** @name Host to/from big endian. + * @note Typically requires iprt/asm.h to be included. + * @{ */ + +/** @def RT_H2BE_U64 + * Converts an uint64_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U64(u64) (u64) +#else +# define RT_H2BE_U64(u64) RT_BSWAP_U64(u64) +#endif + +/** @def RT_H2BE_U64_C + * Converts an uint64_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U64_C(u64) (u64) +#else +# define RT_H2BE_U64_C(u64) RT_BSWAP_U64_C(u64) +#endif + +/** @def RT_H2BE_U32 + * Converts an uint32_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U32(u32) (u32) +#else +# define RT_H2BE_U32(u32) RT_BSWAP_U32(u32) +#endif + +/** @def RT_H2BE_U32_C + * Converts an uint32_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U32_C(u32) (u32) +#else +# define RT_H2BE_U32_C(u32) RT_BSWAP_U32_C(u32) +#endif + +/** @def RT_H2BE_U16 + * Converts an uint16_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U16(u16) (u16) +#else +# define RT_H2BE_U16(u16) RT_BSWAP_U16(u16) +#endif + +/** @def RT_H2BE_U16_C + * Converts an uint16_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U16_C(u16) (u16) +#else +# define RT_H2BE_U16_C(u16) RT_BSWAP_U16_C(u16) +#endif + +/** @def RT_BE2H_U64 + * Converts an uint64_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U64(u64) (u64) +#else +# define RT_BE2H_U64(u64) RT_BSWAP_U64(u64) +#endif + +/** @def RT_BE2H_U64 + * Converts an uint64_t constant from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U64_C(u64) (u64) +#else +# define RT_BE2H_U64_C(u64) RT_BSWAP_U64_C(u64) +#endif + +/** @def RT_BE2H_U32 + * Converts an uint32_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U32(u32) (u32) +#else +# define RT_BE2H_U32(u32) RT_BSWAP_U32(u32) +#endif + +/** @def RT_BE2H_U32_C + * Converts an uint32_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U32_C(u32) (u32) +#else +# define RT_BE2H_U32_C(u32) RT_BSWAP_U32_C(u32) +#endif + +/** @def RT_BE2H_U16 + * Converts an uint16_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U16(u16) (u16) +#else +# define RT_BE2H_U16(u16) RT_BSWAP_U16(u16) +#endif + +/** @def RT_BE2H_U16_C + * Converts an uint16_t constant from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U16_C(u16) (u16) +#else +# define RT_BE2H_U16_C(u16) RT_BSWAP_U16_C(u16) +#endif + +/** @def RT_H2BE_S64 + * Converts an int64_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S64(i64) (i64) +#else +# define RT_H2BE_S64(i64) RT_BSWAP_S64(i64) +#endif + +/** @def RT_H2BE_S64_C + * Converts an int64_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S64_C(i64) (i64) +#else +# define RT_H2BE_S64_C(i64) RT_BSWAP_S64_C(i64) +#endif + +/** @def RT_H2BE_S32 + * Converts an int32_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S32(i32) (i32) +#else +# define RT_H2BE_S32(i32) RT_BSWAP_S32(i32) +#endif + +/** @def RT_H2BE_S32_C + * Converts an int32_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S32_C(i32) (i32) +#else +# define RT_H2BE_S32_C(i32) RT_BSWAP_S32_C(i32) +#endif + +/** @def RT_H2BE_S16 + * Converts an int16_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S16(i16) (i16) +#else +# define RT_H2BE_S16(i16) RT_BSWAP_S16(i16) +#endif + +/** @def RT_H2BE_S16_C + * Converts an int16_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S16_C(i16) (i16) +#else +# define RT_H2BE_S16_C(i16) RT_BSWAP_S16_C(i16) +#endif + +/** @def RT_BE2H_S64 + * Converts an int64_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S64(i64) (i64) +#else +# define RT_BE2H_S64(i64) RT_BSWAP_S64(i64) +#endif + +/** @def RT_BE2H_S64 + * Converts an int64_t constant from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S64_C(i64) (i64) +#else +# define RT_BE2H_S64_C(i64) RT_BSWAP_S64_C(i64) +#endif + +/** @def RT_BE2H_S32 + * Converts an int32_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S32(i32) (i32) +#else +# define RT_BE2H_S32(i32) RT_BSWAP_S32(i32) +#endif + +/** @def RT_BE2H_S32_C + * Converts an int32_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S32_C(i32) (i32) +#else +# define RT_BE2H_S32_C(i32) RT_BSWAP_S32_C(i32) +#endif + +/** @def RT_BE2H_S16 + * Converts an int16_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S16(i16) (i16) +#else +# define RT_BE2H_S16(i16) RT_BSWAP_S16(i16) +#endif + +/** @def RT_BE2H_S16_C + * Converts an int16_t constant from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S16_C(i16) (i16) +#else +# define RT_BE2H_S16_C(i16) RT_BSWAP_S16_C(i16) +#endif +/** @} */ + +/** @name Host to/from network byte order. + * @note Typically requires iprt/asm.h to be included. + * @{ */ + +/** @def RT_H2N_U64 + * Converts an uint64_t value from host to network byte order. */ +#define RT_H2N_U64(u64) RT_H2BE_U64(u64) + +/** @def RT_H2N_U64_C + * Converts an uint64_t constant from host to network byte order. */ +#define RT_H2N_U64_C(u64) RT_H2BE_U64_C(u64) + +/** @def RT_H2N_U32 + * Converts an uint32_t value from host to network byte order. */ +#define RT_H2N_U32(u32) RT_H2BE_U32(u32) + +/** @def RT_H2N_U32_C + * Converts an uint32_t constant from host to network byte order. */ +#define RT_H2N_U32_C(u32) RT_H2BE_U32_C(u32) + +/** @def RT_H2N_U16 + * Converts an uint16_t value from host to network byte order. */ +#define RT_H2N_U16(u16) RT_H2BE_U16(u16) + +/** @def RT_H2N_U16_C + * Converts an uint16_t constant from host to network byte order. */ +#define RT_H2N_U16_C(u16) RT_H2BE_U16_C(u16) + +/** @def RT_N2H_U64 + * Converts an uint64_t value from network to host byte order. */ +#define RT_N2H_U64(u64) RT_BE2H_U64(u64) + +/** @def RT_N2H_U64_C + * Converts an uint64_t constant from network to host byte order. */ +#define RT_N2H_U64_C(u64) RT_BE2H_U64_C(u64) + +/** @def RT_N2H_U32 + * Converts an uint32_t value from network to host byte order. */ +#define RT_N2H_U32(u32) RT_BE2H_U32(u32) + +/** @def RT_N2H_U32_C + * Converts an uint32_t constant from network to host byte order. */ +#define RT_N2H_U32_C(u32) RT_BE2H_U32_C(u32) + +/** @def RT_N2H_U16 + * Converts an uint16_t value from network to host byte order. */ +#define RT_N2H_U16(u16) RT_BE2H_U16(u16) + +/** @def RT_N2H_U16_C + * Converts an uint16_t value from network to host byte order. */ +#define RT_N2H_U16_C(u16) RT_BE2H_U16_C(u16) + +/** @def RT_H2N_S64 + * Converts an int64_t value from host to network byte order. */ +#define RT_H2N_S64(i64) RT_H2BE_S64(i64) + +/** @def RT_H2N_S64_C + * Converts an int64_t constant from host to network byte order. */ +#define RT_H2N_S64_C(i64) RT_H2BE_S64_C(i64) + +/** @def RT_H2N_S32 + * Converts an int32_t value from host to network byte order. */ +#define RT_H2N_S32(i32) RT_H2BE_S32(i32) + +/** @def RT_H2N_S32_C + * Converts an int32_t constant from host to network byte order. */ +#define RT_H2N_S32_C(i32) RT_H2BE_S32_C(i32) + +/** @def RT_H2N_S16 + * Converts an int16_t value from host to network byte order. */ +#define RT_H2N_S16(i16) RT_H2BE_S16(i16) + +/** @def RT_H2N_S16_C + * Converts an int16_t constant from host to network byte order. */ +#define RT_H2N_S16_C(i16) RT_H2BE_S16_C(i16) + +/** @def RT_N2H_S64 + * Converts an int64_t value from network to host byte order. */ +#define RT_N2H_S64(i64) RT_BE2H_S64(i64) + +/** @def RT_N2H_S64_C + * Converts an int64_t constant from network to host byte order. */ +#define RT_N2H_S64_C(i64) RT_BE2H_S64_C(i64) + +/** @def RT_N2H_S32 + * Converts an int32_t value from network to host byte order. */ +#define RT_N2H_S32(i32) RT_BE2H_S32(i32) + +/** @def RT_N2H_S32_C + * Converts an int32_t constant from network to host byte order. */ +#define RT_N2H_S32_C(i32) RT_BE2H_S32_C(i32) + +/** @def RT_N2H_S16 + * Converts an int16_t value from network to host byte order. */ +#define RT_N2H_S16(i16) RT_BE2H_S16(i16) + +/** @def RT_N2H_S16_C + * Converts an int16_t value from network to host byte order. */ +#define RT_N2H_S16_C(i16) RT_BE2H_S16_C(i16) + +/** @} */ + + +/* + * The BSD sys/param.h + machine/param.h file is a major source of + * namespace pollution. Kill off some of the worse ones unless we're + * compiling kernel code. + */ +#if defined(RT_OS_DARWIN) \ + && !defined(KERNEL) \ + && !defined(RT_NO_BSD_PARAM_H_UNDEFING) \ + && ( defined(_SYS_PARAM_H_) || defined(_I386_PARAM_H_) ) +/* sys/param.h: */ +# undef PSWP +# undef PVM +# undef PINOD +# undef PRIBO +# undef PVFS +# undef PZERO +# undef PSOCK +# undef PWAIT +# undef PLOCK +# undef PPAUSE +# undef PUSER +# undef PRIMASK +# undef MINBUCKET +# undef MAXALLOCSAVE +# undef FSHIFT +# undef FSCALE + +/* i386/machine.h: */ +# undef ALIGN +# undef ALIGNBYTES +# undef DELAY +# undef STATUS_WORD +# undef USERMODE +# undef BASEPRI +# undef MSIZE +# undef CLSIZE +# undef CLSIZELOG2 +#endif + +/** @def NIL_OFFSET + * NIL offset. + * Whenever we use offsets instead of pointers to save space and relocation effort + * NIL_OFFSET shall be used as the equivalent to NULL. + */ +#define NIL_OFFSET (~0U) + + +/** @def NOREF + * Keeps the compiler from bitching about an unused parameter, local variable, + * or other stuff, will never use _Pragma are is thus more flexible. + */ +#define NOREF(var) (void)(var) + +/** @def RT_NOREF_PV + * Keeps the compiler from bitching about an unused parameter or local variable. + * This one cannot be used with structure members and such, like for instance + * AssertRC may end up doing due to its generic nature. + */ +#if defined(__cplusplus) && RT_CLANG_PREREQ(6, 0) +# define RT_NOREF_PV(var) _Pragma(RT_STR(unused(var))) +#else +# define RT_NOREF_PV(var) (void)(var) +#endif + +/** @def RT_NOREF1 + * RT_NOREF_PV shorthand taking on parameter. */ +#define RT_NOREF1(var1) RT_NOREF_PV(var1) +/** @def RT_NOREF2 + * RT_NOREF_PV shorthand taking two parameters. */ +#define RT_NOREF2(var1, var2) RT_NOREF_PV(var1); RT_NOREF1(var2) +/** @def RT_NOREF3 + * RT_NOREF_PV shorthand taking three parameters. */ +#define RT_NOREF3(var1, var2, var3) RT_NOREF_PV(var1); RT_NOREF2(var2, var3) +/** @def RT_NOREF4 + * RT_NOREF_PV shorthand taking four parameters. */ +#define RT_NOREF4(var1, var2, var3, var4) RT_NOREF_PV(var1); RT_NOREF3(var2, var3, var4) +/** @def RT_NOREF5 + * RT_NOREF_PV shorthand taking five parameters. */ +#define RT_NOREF5(var1, var2, var3, var4, var5) RT_NOREF_PV(var1); RT_NOREF4(var2, var3, var4, var5) +/** @def RT_NOREF6 + * RT_NOREF_PV shorthand taking six parameters. */ +#define RT_NOREF6(var1, var2, var3, var4, var5, var6) RT_NOREF_PV(var1); RT_NOREF5(var2, var3, var4, var5, var6) +/** @def RT_NOREF7 + * RT_NOREF_PV shorthand taking seven parameters. */ +#define RT_NOREF7(var1, var2, var3, var4, var5, var6, var7) \ + RT_NOREF_PV(var1); RT_NOREF6(var2, var3, var4, var5, var6, var7) +/** @def RT_NOREF8 + * RT_NOREF_PV shorthand taking eight parameters. */ +#define RT_NOREF8(var1, var2, var3, var4, var5, var6, var7, var8) \ + RT_NOREF_PV(var1); RT_NOREF7(var2, var3, var4, var5, var6, var7, var8) +/** @def RT_NOREF9 + * RT_NOREF_PV shorthand taking nine parameters. */ +#define RT_NOREF9(var1, var2, var3, var4, var5, var6, var7, var8, var9) \ + RT_NOREF_PV(var1); RT_NOREF8(var2, var3, var4, var5, var6, var7, var8, var9) +/** @def RT_NOREF10 + * RT_NOREF_PV shorthand taking ten parameters. */ +#define RT_NOREF10(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10) \ + RT_NOREF_PV(var1); RT_NOREF_PV(var2); RT_NOREF_PV(var3); RT_NOREF_PV(var4); RT_NOREF_PV(var5); RT_NOREF_PV(var6); \ + RT_NOREF_PV(var7); RT_NOREF_PV(var8); RT_NOREF_PV(var9); RT_NOREF_PV(var10) +/** @def RT_NOREF11 + * RT_NOREF_PV shorthand taking eleven parameters. */ +#define RT_NOREF11(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11) \ + RT_NOREF_PV(var1); RT_NOREF10(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11) +/** @def RT_NOREF12 + * RT_NOREF_PV shorthand taking twelve parameters. */ +#define RT_NOREF12(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12) \ + RT_NOREF_PV(var1); RT_NOREF11(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12) +/** @def RT_NOREF13 + * RT_NOREF_PV shorthand taking thirteen parameters. */ +#define RT_NOREF13(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13) \ + RT_NOREF_PV(var1); RT_NOREF12(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13) +/** @def RT_NOREF14 + * RT_NOREF_PV shorthand taking fourteen parameters. */ +#define RT_NOREF14(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14) \ + RT_NOREF_PV(var1); RT_NOREF13(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14) +/** @def RT_NOREF15 + * RT_NOREF_PV shorthand taking fifteen parameters. */ +#define RT_NOREF15(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15) \ + RT_NOREF_PV(var1); RT_NOREF14(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15) +/** @def RT_NOREF16 + * RT_NOREF_PV shorthand taking fifteen parameters. */ +#define RT_NOREF16(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15, var16) \ + RT_NOREF_PV(var1); RT_NOREF15(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15, var16) +/** @def RT_NOREF17 + * RT_NOREF_PV shorthand taking seventeen parameters. */ +#define RT_NOREF17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) \ + RT_NOREF_PV(v1); RT_NOREF16(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +/** @def RT_NOREF18 + * RT_NOREF_PV shorthand taking eighteen parameters. */ +#define RT_NOREF18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) \ + RT_NOREF_PV(v1); RT_NOREF17(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +/** @def RT_NOREF19 + * RT_NOREF_PV shorthand taking nineteen parameters. */ +#define RT_NOREF19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) \ + RT_NOREF_PV(v1); RT_NOREF18(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +/** @def RT_NOREF20 + * RT_NOREF_PV shorthand taking twenty parameters. */ +#define RT_NOREF20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) \ + RT_NOREF_PV(v1); RT_NOREF19(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +/** @def RT_NOREF21 + * RT_NOREF_PV shorthand taking twentyone parameters. */ +#define RT_NOREF21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) \ + RT_NOREF_PV(v1); RT_NOREF20(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +/** @def RT_NOREF22 + * RT_NOREF_PV shorthand taking twentytwo parameters. */ +#define RT_NOREF22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) \ + RT_NOREF_PV(v1); RT_NOREF21(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) + +/** @def RT_NOREF + * RT_NOREF_PV variant using the variadic macro feature of C99. + * @remarks Only use this in sources */ +#ifdef RT_COMPILER_SUPPORTS_VA_ARGS +# define RT_NOREF(...) \ + RT_UNPACK_CALL(RT_CONCAT(RT_NOREF, RT_EXPAND(RT_COUNT_VA_ARGS(__VA_ARGS__))),(__VA_ARGS__)) +#endif + + +/** @def RT_BREAKPOINT + * Emit a debug breakpoint instruction. + * + * @remarks In the x86/amd64 gnu world we add a nop instruction after the int3 + * to force gdb to remain at the int3 source line. + * @remarks The L4 kernel will try make sense of the breakpoint, thus the jmp on + * x86/amd64. + */ +#ifdef __GNUC__ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if !defined(__L4ENV__) +# define RT_BREAKPOINT() __asm__ __volatile__("int $3\n\tnop\n\t") +# else +# define RT_BREAKPOINT() __asm__ __volatile__("int3; jmp 1f; 1:\n\t") +# endif +# elif defined(RT_ARCH_SPARC64) +# define RT_BREAKPOINT() __asm__ __volatile__("illtrap 0\n\t") /** @todo Sparc64: this is just a wild guess. */ +# elif defined(RT_ARCH_SPARC) +# define RT_BREAKPOINT() __asm__ __volatile__("unimp 0\n\t") /** @todo Sparc: this is just a wild guess (same as Sparc64, just different name). */ +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) +# define RT_BREAKPOINT() __asm__ __volatile__("brk #0x1\n\t") +# endif +#endif +#ifdef _MSC_VER +# define RT_BREAKPOINT() __debugbreak() +#endif +#if defined(__IBMC__) || defined(__IBMCPP__) +# define RT_BREAKPOINT() __interrupt(3) +#endif +#if defined(__WATCOMC__) +# define RT_BREAKPOINT() _asm { int 3 } +#endif +#ifndef RT_BREAKPOINT +# error "This compiler/arch is not supported!" +#endif + + +/** @defgroup grp_rt_cdefs_size Size Constants + * (Of course, these are binary computer terms, not SI.) + * @{ + */ +/** 1 K (Kilo) (1 024). */ +#define _1K 0x00000400 +/** 2 K (Kilo) (2 048). */ +#define _2K 0x00000800 +/** 4 K (Kilo) (4 096). */ +#define _4K 0x00001000 +/** 8 K (Kilo) (8 192). */ +#define _8K 0x00002000 +/** 16 K (Kilo) (16 384). */ +#define _16K 0x00004000 +/** 32 K (Kilo) (32 768). */ +#define _32K 0x00008000 +/** 64 K (Kilo) (65 536). */ +#if ARCH_BITS != 16 +# define _64K 0x00010000 +#else +# define _64K UINT32_C(0x00010000) +#endif +/** 128 K (Kilo) (131 072). */ +#if ARCH_BITS != 16 +# define _128K 0x00020000 +#else +# define _128K UINT32_C(0x00020000) +#endif +/** 256 K (Kilo) (262 144). */ +#if ARCH_BITS != 16 +# define _256K 0x00040000 +#else +# define _256K UINT32_C(0x00040000) +#endif +/** 512 K (Kilo) (524 288). */ +#if ARCH_BITS != 16 +# define _512K 0x00080000 +#else +# define _512K UINT32_C(0x00080000) +#endif +/** 1 M (Mega) (1 048 576). */ +#if ARCH_BITS != 16 +# define _1M 0x00100000 +#else +# define _1M UINT32_C(0x00100000) +#endif +/** 2 M (Mega) (2 097 152). */ +#if ARCH_BITS != 16 +# define _2M 0x00200000 +#else +# define _2M UINT32_C(0x00200000) +#endif +/** 4 M (Mega) (4 194 304). */ +#if ARCH_BITS != 16 +# define _4M 0x00400000 +#else +# define _4M UINT32_C(0x00400000) +#endif +/** 8 M (Mega) (8 388 608). */ +#define _8M UINT32_C(0x00800000) +/** 16 M (Mega) (16 777 216). */ +#define _16M UINT32_C(0x01000000) +/** 32 M (Mega) (33 554 432). */ +#define _32M UINT32_C(0x02000000) +/** 64 M (Mega) (67 108 864). */ +#define _64M UINT32_C(0x04000000) +/** 128 M (Mega) (134 217 728). */ +#define _128M UINT32_C(0x08000000) +/** 256 M (Mega) (268 435 456). */ +#define _256M UINT32_C(0x10000000) +/** 512 M (Mega) (536 870 912). */ +#define _512M UINT32_C(0x20000000) +/** 1 G (Giga) (1 073 741 824). (32-bit) */ +#if ARCH_BITS != 16 +# define _1G 0x40000000 +#else +# define _1G UINT32_C(0x40000000) +#endif +/** 1 G (Giga) (1 073 741 824). (64-bit) */ +#if ARCH_BITS != 16 +# define _1G64 0x40000000LL +#else +# define _1G64 UINT64_C(0x40000000) +#endif +/** 2 G (Giga) (2 147 483 648). (32-bit) */ +#define _2G32 UINT32_C(0x80000000) +/** 2 G (Giga) (2 147 483 648). (64-bit) */ +#if ARCH_BITS != 16 +# define _2G 0x0000000080000000LL +#else +# define _2G UINT64_C(0x0000000080000000) +#endif +/** 4 G (Giga) (4 294 967 296). */ +#if ARCH_BITS != 16 +# define _4G 0x0000000100000000LL +#else +# define _4G UINT64_C(0x0000000100000000) +#endif +/** 1 T (Tera) (1 099 511 627 776). */ +#if ARCH_BITS != 16 +# define _1T 0x0000010000000000LL +#else +# define _1T UINT64_C(0x0000010000000000) +#endif +/** 1 P (Peta) (1 125 899 906 842 624). */ +#if ARCH_BITS != 16 +# define _1P 0x0004000000000000LL +#else +# define _1P UINT64_C(0x0004000000000000) +#endif +/** 1 E (Exa) (1 152 921 504 606 846 976). */ +#if ARCH_BITS != 16 +# define _1E 0x1000000000000000LL +#else +# define _1E UINT64_C(0x1000000000000000) +#endif +/** 2 E (Exa) (2 305 843 009 213 693 952). */ +#if ARCH_BITS != 16 +# define _2E 0x2000000000000000ULL +#else +# define _2E UINT64_C(0x2000000000000000) +#endif +/** @} */ + +/** @defgroup grp_rt_cdefs_decimal_grouping Decimal Constant Grouping Macros + * @{ */ +#define RT_D1(g1) g1 +#define RT_D2(g1, g2) g1#g2 +#define RT_D3(g1, g2, g3) g1#g2#g3 +#define RT_D4(g1, g2, g3, g4) g1#g2#g3#g4 +#define RT_D5(g1, g2, g3, g4, g5) g1#g2#g3#g4#g5 +#define RT_D6(g1, g2, g3, g4, g5, g6) g1#g2#g3#g4#g5#g6 +#define RT_D7(g1, g2, g3, g4, g5, g6, g7) g1#g2#g3#g4#g5#g6#g7 + +#define RT_D1_U(g1) UINT32_C(g1) +#define RT_D2_U(g1, g2) UINT32_C(g1#g2) +#define RT_D3_U(g1, g2, g3) UINT32_C(g1#g2#g3) +#define RT_D4_U(g1, g2, g3, g4) UINT64_C(g1#g2#g3#g4) +#define RT_D5_U(g1, g2, g3, g4, g5) UINT64_C(g1#g2#g3#g4#g5) +#define RT_D6_U(g1, g2, g3, g4, g5, g6) UINT64_C(g1#g2#g3#g4#g5#g6) +#define RT_D7_U(g1, g2, g3, g4, g5, g6, g7) UINT64_C(g1#g2#g3#g4#g5#g6#g7) + +#define RT_D1_S(g1) INT32_C(g1) +#define RT_D2_S(g1, g2) INT32_C(g1#g2) +#define RT_D3_S(g1, g2, g3) INT32_C(g1#g2#g3) +#define RT_D4_S(g1, g2, g3, g4) INT64_C(g1#g2#g3#g4) +#define RT_D5_S(g1, g2, g3, g4, g5) INT64_C(g1#g2#g3#g4#g5) +#define RT_D6_S(g1, g2, g3, g4, g5, g6) INT64_C(g1#g2#g3#g4#g5#g6) +#define RT_D7_S(g1, g2, g3, g4, g5, g6, g7) INT64_C(g1#g2#g3#g4#g5#g6#g7) + +#define RT_D1_U32(g1) UINT32_C(g1) +#define RT_D2_U32(g1, g2) UINT32_C(g1#g2) +#define RT_D3_U32(g1, g2, g3) UINT32_C(g1#g2#g3) +#define RT_D4_U32(g1, g2, g3, g4) UINT32_C(g1#g2#g3#g4) + +#define RT_D1_S32(g1) INT32_C(g1) +#define RT_D2_S32(g1, g2) INT32_C(g1#g2) +#define RT_D3_S32(g1, g2, g3) INT32_C(g1#g2#g3) +#define RT_D4_S32(g1, g2, g3, g4) INT32_C(g1#g2#g3#g4) + +#define RT_D1_U64(g1) UINT64_C(g1) +#define RT_D2_U64(g1, g2) UINT64_C(g1#g2) +#define RT_D3_U64(g1, g2, g3) UINT64_C(g1#g2#g3) +#define RT_D4_U64(g1, g2, g3, g4) UINT64_C(g1#g2#g3#g4) +#define RT_D5_U64(g1, g2, g3, g4, g5) UINT64_C(g1#g2#g3#g4#g5) +#define RT_D6_U64(g1, g2, g3, g4, g5, g6) UINT64_C(g1#g2#g3#g4#g5#g6) +#define RT_D7_U64(g1, g2, g3, g4, g5, g6, g7) UINT64_C(g1#g2#g3#g4#g5#g6#g7) + +#define RT_D1_S64(g1) INT64_C(g1) +#define RT_D2_S64(g1, g2) INT64_C(g1#g2) +#define RT_D3_S64(g1, g2, g3) INT64_C(g1#g2#g3) +#define RT_D4_S64(g1, g2, g3, g4) INT64_C(g1#g2#g3#g4) +#define RT_D5_S64(g1, g2, g3, g4, g5) INT64_C(g1#g2#g3#g4#g5) +#define RT_D6_S64(g1, g2, g3, g4, g5, g6) INT64_C(g1#g2#g3#g4#g5#g6) +#define RT_D7_S64(g1, g2, g3, g4, g5, g6, g7) INT64_C(g1#g2#g3#g4#g5#g6#g7) +/** @} */ + + +/** @defgroup grp_rt_cdefs_time Time Constants + * @{ + */ +/** 1 week expressed in nanoseconds (64-bit). */ +#define RT_NS_1WEEK UINT64_C(604800000000000) +/** 1 day expressed in nanoseconds (64-bit). */ +#define RT_NS_1DAY UINT64_C(86400000000000) +/** 1 hour expressed in nanoseconds (64-bit). */ +#define RT_NS_1HOUR UINT64_C(3600000000000) +/** 30 minutes expressed in nanoseconds (64-bit). */ +#define RT_NS_30MIN UINT64_C(1800000000000) +/** 5 minutes expressed in nanoseconds (64-bit). */ +#define RT_NS_5MIN UINT64_C(300000000000) +/** 1 minute expressed in nanoseconds (64-bit). */ +#define RT_NS_1MIN UINT64_C(60000000000) +/** 45 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_45SEC UINT64_C(45000000000) +/** 30 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_30SEC UINT64_C(30000000000) +/** 20 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_20SEC UINT64_C(20000000000) +/** 15 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_15SEC UINT64_C(15000000000) +/** 10 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_10SEC UINT64_C(10000000000) +/** 1 second expressed in nanoseconds. */ +#define RT_NS_1SEC UINT32_C(1000000000) +/** 100 millsecond expressed in nanoseconds. */ +#define RT_NS_100MS UINT32_C(100000000) +/** 10 millsecond expressed in nanoseconds. */ +#define RT_NS_10MS UINT32_C(10000000) +/** 8 millsecond expressed in nanoseconds. */ +#define RT_NS_8MS UINT32_C(8000000) +/** 2 millsecond expressed in nanoseconds. */ +#define RT_NS_2MS UINT32_C(2000000) +/** 1 millsecond expressed in nanoseconds. */ +#define RT_NS_1MS UINT32_C(1000000) +/** 100 microseconds expressed in nanoseconds. */ +#define RT_NS_100US UINT32_C(100000) +/** 10 microseconds expressed in nanoseconds. */ +#define RT_NS_10US UINT32_C(10000) +/** 1 microsecond expressed in nanoseconds. */ +#define RT_NS_1US UINT32_C(1000) + +/** 1 second expressed in nanoseconds - 64-bit type. */ +#define RT_NS_1SEC_64 UINT64_C(1000000000) +/** 100 millsecond expressed in nanoseconds - 64-bit type. */ +#define RT_NS_100MS_64 UINT64_C(100000000) +/** 10 millsecond expressed in nanoseconds - 64-bit type. */ +#define RT_NS_10MS_64 UINT64_C(10000000) +/** 1 millsecond expressed in nanoseconds - 64-bit type. */ +#define RT_NS_1MS_64 UINT64_C(1000000) +/** 100 microseconds expressed in nanoseconds - 64-bit type. */ +#define RT_NS_100US_64 UINT64_C(100000) +/** 10 microseconds expressed in nanoseconds - 64-bit type. */ +#define RT_NS_10US_64 UINT64_C(10000) +/** 1 microsecond expressed in nanoseconds - 64-bit type. */ +#define RT_NS_1US_64 UINT64_C(1000) + +/** 1 week expressed in microseconds (64-bit). */ +#define RT_US_1WEEK UINT64_C(604800000000) +/** 1 day expressed in microseconds (64-bit). */ +#define RT_US_1DAY UINT64_C(86400000000) +/** 1 hour expressed in microseconds. */ +#define RT_US_1HOUR UINT32_C(3600000000) +/** 30 minutes expressed in microseconds. */ +#define RT_US_30MIN UINT32_C(1800000000) +/** 5 minutes expressed in microseconds. */ +#define RT_US_5MIN UINT32_C(300000000) +/** 1 minute expressed in microseconds. */ +#define RT_US_1MIN UINT32_C(60000000) +/** 45 seconds expressed in microseconds. */ +#define RT_US_45SEC UINT32_C(45000000) +/** 30 seconds expressed in microseconds. */ +#define RT_US_30SEC UINT32_C(30000000) +/** 20 seconds expressed in microseconds. */ +#define RT_US_20SEC UINT32_C(20000000) +/** 15 seconds expressed in microseconds. */ +#define RT_US_15SEC UINT32_C(15000000) +/** 10 seconds expressed in microseconds. */ +#define RT_US_10SEC UINT32_C(10000000) +/** 5 seconds expressed in microseconds. */ +#define RT_US_5SEC UINT32_C(5000000) +/** 1 second expressed in microseconds. */ +#define RT_US_1SEC UINT32_C(1000000) +/** 100 millsecond expressed in microseconds. */ +#define RT_US_100MS UINT32_C(100000) +/** 10 millsecond expressed in microseconds. */ +#define RT_US_10MS UINT32_C(10000) +/** 1 millsecond expressed in microseconds. */ +#define RT_US_1MS UINT32_C(1000) + +/** 1 hour expressed in microseconds - 64-bit type. */ +#define RT_US_1HOUR_64 UINT64_C(3600000000) +/** 30 minutes expressed in microseconds - 64-bit type. */ +#define RT_US_30MIN_64 UINT64_C(1800000000) +/** 5 minutes expressed in microseconds - 64-bit type. */ +#define RT_US_5MIN_64 UINT64_C(300000000) +/** 1 minute expressed in microseconds - 64-bit type. */ +#define RT_US_1MIN_64 UINT64_C(60000000) +/** 45 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_45SEC_64 UINT64_C(45000000) +/** 30 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_30SEC_64 UINT64_C(30000000) +/** 20 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_20SEC_64 UINT64_C(20000000) +/** 15 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_15SEC_64 UINT64_C(15000000) +/** 10 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_10SEC_64 UINT64_C(10000000) +/** 5 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_5SEC_64 UINT64_C(5000000) +/** 1 second expressed in microseconds - 64-bit type. */ +#define RT_US_1SEC_64 UINT64_C(1000000) +/** 100 millsecond expressed in microseconds - 64-bit type. */ +#define RT_US_100MS_64 UINT64_C(100000) +/** 10 millsecond expressed in microseconds - 64-bit type. */ +#define RT_US_10MS_64 UINT64_C(10000) +/** 1 millsecond expressed in microseconds - 64-bit type. */ +#define RT_US_1MS_64 UINT64_C(1000) + +/** 1 week expressed in milliseconds. */ +#define RT_MS_1WEEK UINT32_C(604800000) +/** 1 day expressed in milliseconds. */ +#define RT_MS_1DAY UINT32_C(86400000) +/** 1 hour expressed in milliseconds. */ +#define RT_MS_1HOUR UINT32_C(3600000) +/** 30 minutes expressed in milliseconds. */ +#define RT_MS_30MIN UINT32_C(1800000) +/** 5 minutes expressed in milliseconds. */ +#define RT_MS_5MIN UINT32_C(300000) +/** 1 minute expressed in milliseconds. */ +#define RT_MS_1MIN UINT32_C(60000) +/** 45 seconds expressed in milliseconds. */ +#define RT_MS_45SEC UINT32_C(45000) +/** 30 seconds expressed in milliseconds. */ +#define RT_MS_30SEC UINT32_C(30000) +/** 20 seconds expressed in milliseconds. */ +#define RT_MS_20SEC UINT32_C(20000) +/** 15 seconds expressed in milliseconds. */ +#define RT_MS_15SEC UINT32_C(15000) +/** 10 seconds expressed in milliseconds. */ +#define RT_MS_10SEC UINT32_C(10000) +/** 5 seconds expressed in milliseconds. */ +#define RT_MS_5SEC UINT32_C(5000) +/** 1 second expressed in milliseconds. */ +#define RT_MS_1SEC UINT32_C(1000) + +/** 1 week expressed in milliseconds - 64-bit type. */ +#define RT_MS_1WEEK_64 UINT64_C(604800000) +/** 1 day expressed in milliseconds - 64-bit type. */ +#define RT_MS_1DAY_64 UINT64_C(86400000) +/** 1 hour expressed in milliseconds - 64-bit type. */ +#define RT_MS_1HOUR_64 UINT64_C(3600000) +/** 30 minutes expressed in milliseconds - 64-bit type. */ +#define RT_MS_30MIN_64 UINT64_C(1800000) +/** 5 minutes expressed in milliseconds - 64-bit type. */ +#define RT_MS_5MIN_64 UINT64_C(300000) +/** 1 minute expressed in milliseconds - 64-bit type. */ +#define RT_MS_1MIN_64 UINT64_C(60000) +/** 45 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_45SEC_64 UINT64_C(45000) +/** 30 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_30SEC_64 UINT64_C(30000) +/** 20 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_20SEC_64 UINT64_C(20000) +/** 15 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_15SEC_64 UINT64_C(15000) +/** 10 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_10SEC_64 UINT64_C(10000) +/** 5 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_5SEC_64 UINT64_C(5000) +/** 1 second expressed in milliseconds - 64-bit type. */ +#define RT_MS_1SEC_64 UINT64_C(1000) + +/** The number of seconds per week. */ +#define RT_SEC_1WEEK UINT32_C(604800) +/** The number of seconds per day. */ +#define RT_SEC_1DAY UINT32_C(86400) +/** The number of seconds per hour. */ +#define RT_SEC_1HOUR UINT32_C(3600) + +/** The number of seconds per week - 64-bit type. */ +#define RT_SEC_1WEEK_64 UINT64_C(604800) +/** The number of seconds per day - 64-bit type. */ +#define RT_SEC_1DAY_64 UINT64_C(86400) +/** The number of seconds per hour - 64-bit type. */ +#define RT_SEC_1HOUR_64 UINT64_C(3600) +/** @} */ + + +/** @defgroup grp_rt_cdefs_dbgtype Debug Info Types + * @{ */ +/** Other format. */ +#define RT_DBGTYPE_OTHER RT_BIT_32(0) +/** Stabs. */ +#define RT_DBGTYPE_STABS RT_BIT_32(1) +/** Debug With Arbitrary Record Format (DWARF). */ +#define RT_DBGTYPE_DWARF RT_BIT_32(2) +/** Microsoft Codeview debug info. */ +#define RT_DBGTYPE_CODEVIEW RT_BIT_32(3) +/** Watcom debug info. */ +#define RT_DBGTYPE_WATCOM RT_BIT_32(4) +/** IBM High Level Language debug info. */ +#define RT_DBGTYPE_HLL RT_BIT_32(5) +/** Old OS/2 and Windows symbol file. */ +#define RT_DBGTYPE_SYM RT_BIT_32(6) +/** Map file. */ +#define RT_DBGTYPE_MAP RT_BIT_32(7) +/** @} */ + + +/** @defgroup grp_rt_cdefs_exetype Executable Image Types + * @{ */ +/** Some other format. */ +#define RT_EXETYPE_OTHER RT_BIT_32(0) +/** Portable Executable. */ +#define RT_EXETYPE_PE RT_BIT_32(1) +/** Linear eXecutable. */ +#define RT_EXETYPE_LX RT_BIT_32(2) +/** Linear Executable. */ +#define RT_EXETYPE_LE RT_BIT_32(3) +/** New Executable. */ +#define RT_EXETYPE_NE RT_BIT_32(4) +/** DOS Executable (Mark Zbikowski). */ +#define RT_EXETYPE_MZ RT_BIT_32(5) +/** COM Executable. */ +#define RT_EXETYPE_COM RT_BIT_32(6) +/** a.out Executable. */ +#define RT_EXETYPE_AOUT RT_BIT_32(7) +/** Executable and Linkable Format. */ +#define RT_EXETYPE_ELF RT_BIT_32(8) +/** Mach-O Executable (including FAT ones). */ +#define RT_EXETYPE_MACHO RT_BIT_32(9) +/** TE from UEFI. */ +#define RT_EXETYPE_TE RT_BIT_32(9) +/** @} */ + + +/** @def RT_VALID_PTR + * Pointer validation macro. + * @param ptr The pointer. + */ +#if defined(RT_ARCH_AMD64) +# ifdef IN_RING3 +# if defined(RT_OS_DARWIN) /* first 4GB is reserved for legacy kernel. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) >= _4G \ + && !((uintptr_t)(ptr) & 0xffff800000000000ULL) ) +# elif defined(RT_OS_SOLARIS) /* The kernel only used the top 2TB, but keep it simple. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U \ + && ( ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0xffff800000000000ULL \ + || ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0) ) +# elif defined(RT_OS_LINUX) /* May use 5-level paging (see Documentation/x86/x86_64/mm.rst). */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) >= 0x1000U /* one invalid page at the bottom */ \ + && !((uintptr_t)(ptr) & 0xff00000000000000ULL) ) +# else +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) >= 0x1000U \ + && !((uintptr_t)(ptr) & 0xffff800000000000ULL) ) +# endif +# else /* !IN_RING3 */ +# if defined(RT_OS_LINUX) /* May use 5-level paging (see Documentation/x86/x86_64/mm.rst). */ +# if 1 /* User address are no longer considered valid in kernel mode (SMAP, etc). */ +# define RT_VALID_PTR(ptr) ((uintptr_t)(ptr) - 0xff00000000000000ULL < 0x00ffffffffe00000ULL) /* 2MB invalid space at the top */ +# else +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x200000 >= 0x201000U /* one invalid page at the bottom and 2MB at the top */ \ + && ( ((uintptr_t)(ptr) & 0xff00000000000000ULL) == 0xff00000000000000ULL \ + || ((uintptr_t)(ptr) & 0xff00000000000000ULL) == 0) ) +# endif +# else +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U \ + && ( ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0xffff800000000000ULL \ + || ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0) ) +# endif +# endif /* !IN_RING3 */ + +#elif defined(RT_ARCH_X86) +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U ) + +#elif defined(RT_ARCH_SPARC64) +# ifdef IN_RING3 +# if defined(RT_OS_SOLARIS) +/** Sparc64 user mode: According to Figure 9.4 in solaris internals */ +/** @todo # define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x80004000U >= 0x80004000U + 0x100000000ULL ) - figure this. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x80000000U >= 0x80000000U + 0x100000000ULL ) +# else +# error "Port me" +# endif +# else /* !IN_RING3 */ +# if defined(RT_OS_SOLARIS) +/** @todo Sparc64 kernel mode: This is according to Figure 11.1 in solaris + * internals. Verify in sources. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) >= 0x01000000U ) +# else +# error "Port me" +# endif +# endif /* !IN_RING3 */ + +#elif defined(RT_ARCH_SPARC) +# ifdef IN_RING3 +# ifdef RT_OS_SOLARIS +/** Sparc user mode: According to + * http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/sun4/os/startup.c#510 */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x400000U >= 0x400000U + 0x2000U ) + +# else +# error "Port me" +# endif +# else /* !IN_RING3 */ +# ifdef RT_OS_SOLARIS +/** @todo Sparc kernel mode: Check the sources! */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U ) +# else +# error "Port me" +# endif +# endif /* !IN_RING3 */ + +#elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) +/* ASSUMES that at least the last and first 4K are out of bounds. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U ) + +#else +# error "Architecture identifier missing / not implemented." +#endif + +/** @def RT_VALID_ALIGNED_PTR + * Pointer validation macro that also checks the alignment. + * @param ptr The pointer. + * @param align The alignment, must be a power of two. + */ +#define RT_VALID_ALIGNED_PTR(ptr, align) \ + ( !((uintptr_t)(ptr) & (uintptr_t)((align) - 1)) \ + && RT_VALID_PTR(ptr) ) + + +/** @def VALID_PHYS32 + * 32 bits physical address validation macro. + * @param Phys The RTGCPHYS address. + */ +#define VALID_PHYS32(Phys) ( (uint64_t)(Phys) < (uint64_t)_4G ) + +/** @def N_ + * The \#define N_ is used to mark a string for translation. This is usable in + * any part of the code, as it is only used by the tools that create message + * catalogs. This macro is a no-op as far as the compiler and code generation + * is concerned. + * + * If you want to both mark a string for translation and translate it, use _(). + */ +#define N_(s) (s) + +/** @def _ + * The \#define _ is used to mark a string for translation and to translate it + * in one step. + * + * If you want to only mark a string for translation, use N_(). + */ +#define _(s) gettext(s) + + +#if (!defined(__GNUC__) && !defined(__PRETTY_FUNCTION__)) || defined(DOXYGEN_RUNNING) +# if defined(_MSC_VER) || defined(DOXYGEN_RUNNING) +/** With GNU C we'd like to use the builtin __PRETTY_FUNCTION__, so define that + * for the other compilers. */ +# define __PRETTY_FUNCTION__ __FUNCSIG__ +# else +# define __PRETTY_FUNCTION__ __FUNCTION__ +# endif +#endif + + +/** @def RT_STRICT + * The \#define RT_STRICT controls whether or not assertions and other runtime + * checks should be compiled in or not. This is defined when DEBUG is defined. + * If RT_NO_STRICT is defined, it will unconditionally be undefined. + * + * If you want assertions which are not subject to compile time options use + * the AssertRelease*() flavors. + */ +#if !defined(RT_STRICT) && defined(DEBUG) +# define RT_STRICT +#endif +#ifdef RT_NO_STRICT +# undef RT_STRICT +#endif + +/** @todo remove this: */ +#if !defined(RT_LOCK_STRICT) && !defined(DEBUG_bird) +# define RT_LOCK_NO_STRICT +#endif +#if !defined(RT_LOCK_STRICT_ORDER) && !defined(DEBUG_bird) +# define RT_LOCK_NO_STRICT_ORDER +#endif + +/** @def RT_LOCK_STRICT + * The \#define RT_LOCK_STRICT controls whether deadlock detection and related + * checks are done in the lock and semaphore code. It is by default enabled in + * RT_STRICT builds, but this behavior can be overridden by defining + * RT_LOCK_NO_STRICT. */ +#if !defined(RT_LOCK_STRICT) && !defined(RT_LOCK_NO_STRICT) && defined(RT_STRICT) +# define RT_LOCK_STRICT +#endif +/** @def RT_LOCK_NO_STRICT + * The \#define RT_LOCK_NO_STRICT disables RT_LOCK_STRICT. */ +#if defined(RT_LOCK_NO_STRICT) && defined(RT_LOCK_STRICT) +# undef RT_LOCK_STRICT +#endif + +/** @def RT_LOCK_STRICT_ORDER + * The \#define RT_LOCK_STRICT_ORDER controls whether locking order is checked + * by the lock and semaphore code. It is by default enabled in RT_STRICT + * builds, but this behavior can be overridden by defining + * RT_LOCK_NO_STRICT_ORDER. */ +#if !defined(RT_LOCK_STRICT_ORDER) && !defined(RT_LOCK_NO_STRICT_ORDER) && defined(RT_STRICT) +# define RT_LOCK_STRICT_ORDER +#endif +/** @def RT_LOCK_NO_STRICT_ORDER + * The \#define RT_LOCK_NO_STRICT_ORDER disables RT_LOCK_STRICT_ORDER. */ +#if defined(RT_LOCK_NO_STRICT_ORDER) && defined(RT_LOCK_STRICT_ORDER) +# undef RT_LOCK_STRICT_ORDER +#endif + + +/** Source position. */ +#define RT_SRC_POS __FILE__, __LINE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__ + +/** Source position declaration. */ +#define RT_SRC_POS_DECL const char *pszFile, unsigned iLine, const char *pszFunction + +/** Source position arguments. */ +#define RT_SRC_POS_ARGS pszFile, iLine, pszFunction + +/** Applies NOREF() to the source position arguments. */ +#define RT_SRC_POS_NOREF() do { NOREF(pszFile); NOREF(iLine); NOREF(pszFunction); } while (0) + + +/** @def RT_INLINE_ASM_EXTERNAL + * Defined as 1 if the compiler does not support inline assembly. + * The ASM* functions will then be implemented in external .asm files. + */ +#if (defined(_MSC_VER) && defined(RT_ARCH_AMD64)) \ + || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86) && !defined(RT_ARCH_ARM64) && !defined(RT_ARCH_ARM32)) \ + || defined(__WATCOMC__) +# define RT_INLINE_ASM_EXTERNAL 1 +#else +# define RT_INLINE_ASM_EXTERNAL 0 +#endif + +/** @def RT_INLINE_ASM_GNU_STYLE + * Defined as 1 if the compiler understands GNU style inline assembly. + */ +#if defined(_MSC_VER) || defined(__WATCOMC__) +# define RT_INLINE_ASM_GNU_STYLE 0 +#else +# define RT_INLINE_ASM_GNU_STYLE 1 +#endif + +/** @def RT_INLINE_ASM_USES_INTRIN + * Defined as one of the RT_MSC_VER_XXX MSC version values if the compiler have + * and uses intrin.h. Otherwise it is 0. */ +#ifdef _MSC_VER +# if _MSC_VER >= RT_MSC_VER_VS2019 /* Visual C++ v14.2 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2019 +# elif _MSC_VER >= RT_MSC_VER_VS2017 /* Visual C++ v14.1 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2017 +# elif _MSC_VER >= RT_MSC_VER_VS2015 /* Visual C++ v14.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2015 +# elif _MSC_VER >= RT_MSC_VER_VS2013 /* Visual C++ v12.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2013 +# elif _MSC_VER >= RT_MSC_VER_VS2012 /* Visual C++ v11.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2012 +# elif _MSC_VER >= RT_MSC_VER_VS2010 /* Visual C++ v10.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2010 +# elif _MSC_VER >= RT_MSC_VER_VS2008 /* Visual C++ v9.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2008 +# elif _MSC_VER >= RT_MSC_VER_VS2005 /* Visual C++ v8.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2005 +# endif +#endif +#ifndef RT_INLINE_ASM_USES_INTRIN +# define RT_INLINE_ASM_USES_INTRIN 0 +#endif + +#define RT_MSC_VER_VS2012 (1700) /**< Visual Studio 2012. */ +#define RT_MSC_VER_VC110 RT_MSC_VER_VS2012 /**< Visual C++ 11.0, aka Visual Studio 2012. */ +#define RT_MSC_VER_VS2013 (1800) /**< Visual Studio 2013. */ +#define RT_MSC_VER_VC120 RT_MSC_VER_VS2013 /**< Visual C++ 12.0, aka Visual Studio 2013. */ +#define RT_MSC_VER_VS2015 (1900) /**< Visual Studio 2015. */ +#define RT_MSC_VER_VC140 RT_MSC_VER_VS2015 /**< Visual C++ 14.0, aka Visual Studio 2015. */ +#define RT_MSC_VER_VS2017 (1910) /**< Visual Studio 2017. */ +#define RT_MSC_VER_VC141 RT_MSC_VER_VS2017 /**< Visual C++ 14.1, aka Visual Studio 2017. */ +#define RT_MSC_VER_VS2019 (1920) /**< Visual Studio 2017. */ +#define RT_MSC_VER_VC142 RT_MSC_VER_VS2019 /**< Visual C++ 14.2, aka Visual Studio 2019. */ + +/** @def RT_COMPILER_SUPPORTS_LAMBDA + * If the defined, the compiler supports lambda expressions. These expressions + * are useful for embedding assertions and type checks into macros. */ +#if defined(_MSC_VER) && defined(__cplusplus) +# if _MSC_VER >= 1600 /* Visual C++ v10.0 / 2010 */ +# define RT_COMPILER_SUPPORTS_LAMBDA +# endif +#elif defined(__GNUC__) && defined(__cplusplus) +/* 4.5 or later, I think, if in ++11 mode... */ +#endif + +/** @def RT_DATA_IS_FAR + * Set to 1 if we're in 16-bit mode and use far pointers. + */ +#if ARCH_BITS == 16 && defined(__WATCOMC__) \ + && (defined(__COMPACT__) || defined(__LARGE__)) +# define RT_DATA_IS_FAR 1 +#else +# define RT_DATA_IS_FAR 0 +#endif + +/** @def RT_FAR + * For indicating far pointers in 16-bit code. + * Does nothing in 32-bit and 64-bit code. */ +/** @def RT_NEAR + * For indicating near pointers in 16-bit code. + * Does nothing in 32-bit and 64-bit code. */ +/** @def RT_FAR_CODE + * For indicating far 16-bit functions. + * Does nothing in 32-bit and 64-bit code. */ +/** @def RT_NEAR_CODE + * For indicating near 16-bit functions. + * Does nothing in 32-bit and 64-bit code. */ +/** @def RT_FAR_DATA + * For indicating far 16-bit external data, i.e. in a segment other than DATA16. + * Does nothing in 32-bit and 64-bit code. */ +#if ARCH_BITS == 16 +# define RT_FAR __far +# define RT_NEAR __near +# define RT_FAR_CODE __far +# define RT_NEAR_CODE __near +# define RT_FAR_DATA __far +#else +# define RT_FAR +# define RT_NEAR +# define RT_FAR_CODE +# define RT_NEAR_CODE +# define RT_FAR_DATA +#endif + + +/** @} */ + + +/** @defgroup grp_rt_cdefs_cpp Special Macros for C++ + * @ingroup grp_rt_cdefs + * @{ + */ + +#ifdef __cplusplus + +/** @def DECLEXPORT_CLASS + * How to declare an exported class. Place this macro after the 'class' + * keyword in the declaration of every class you want to export. + * + * @note It is necessary to use this macro even for inner classes declared + * inside the already exported classes. This is a GCC specific requirement, + * but it seems not to harm other compilers. + */ +#if defined(_MSC_VER) || defined(RT_OS_OS2) +# define DECLEXPORT_CLASS __declspec(dllexport) +#elif defined(RT_USE_VISIBILITY_DEFAULT) +# define DECLEXPORT_CLASS __attribute__((visibility("default"))) +#else +# define DECLEXPORT_CLASS +#endif + +/** @def DECLIMPORT_CLASS + * How to declare an imported class Place this macro after the 'class' + * keyword in the declaration of every class you want to export. + * + * @note It is necessary to use this macro even for inner classes declared + * inside the already exported classes. This is a GCC specific requirement, + * but it seems not to harm other compilers. + */ +#if defined(_MSC_VER) || (defined(RT_OS_OS2) && !defined(__IBMC__) && !defined(__IBMCPP__)) +# define DECLIMPORT_CLASS __declspec(dllimport) +#elif defined(RT_USE_VISIBILITY_DEFAULT) +# define DECLIMPORT_CLASS __attribute__((visibility("default"))) +#else +# define DECLIMPORT_CLASS +#endif + +/** @def WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP + * Macro to work around error C2593 of the not-so-smart MSVC 7.x ambiguity + * resolver. The following snippet clearly demonstrates the code causing this + * error: + * @code + * class A + * { + * public: + * operator bool() const { return false; } + * operator int*() const { return NULL; } + * }; + * int main() + * { + * A a; + * if (!a); + * if (a && 0); + * return 0; + * } + * @endcode + * The code itself seems pretty valid to me and GCC thinks the same. + * + * This macro fixes the compiler error by explicitly overloading implicit + * global operators !, && and || that take the given class instance as one of + * their arguments. + * + * The best is to use this macro right after the class declaration. + * + * @note The macro expands to nothing for compilers other than MSVC. + * + * @param Cls Class to apply the workaround to + */ +#if defined(_MSC_VER) +# define WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP(Cls) \ + inline bool operator! (const Cls &that) { return !bool (that); } \ + inline bool operator&& (const Cls &that, bool b) { return bool (that) && b; } \ + inline bool operator|| (const Cls &that, bool b) { return bool (that) || b; } \ + inline bool operator&& (bool b, const Cls &that) { return b && bool (that); } \ + inline bool operator|| (bool b, const Cls &that) { return b || bool (that); } +#else +# define WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP(Cls) +#endif + +/** @def WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP_TPL + * Version of WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP for template classes. + * + * @param Tpl Name of the template class to apply the workaround to + * @param ArgsDecl arguments of the template, as declared in |<>| after the + * |template| keyword, including |<>| + * @param Args arguments of the template, as specified in |<>| after the + * template class name when using the, including |<>| + * + * Example: + * @code + * // template class declaration + * template + * class Foo { ... }; + * // applied workaround + * WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP_TPL (Foo, , ) + * @endcode + */ +#if defined(_MSC_VER) +# define WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP_TPL(Tpl, ArgsDecl, Args) \ + template ArgsDecl \ + inline bool operator! (const Tpl Args &that) { return !bool (that); } \ + template ArgsDecl \ + inline bool operator&& (const Tpl Args &that, bool b) { return bool (that) && b; } \ + template ArgsDecl \ + inline bool operator|| (const Tpl Args &that, bool b) { return bool (that) || b; } \ + template ArgsDecl \ + inline bool operator&& (bool b, const Tpl Args &that) { return b && bool (that); } \ + template ArgsDecl \ + inline bool operator|| (bool b, const Tpl Args &that) { return b || bool (that); } +#else +# define WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP_TPL(Tpl, ArgsDecl, Args) +#endif + + +/** @def DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP + * Declares the copy constructor and the assignment operation as inlined no-ops + * (non-existent functions) for the given class. Use this macro inside the + * private section if you want to effectively disable these operations for your + * class. + * + * @param Cls class name to declare for + */ +#define DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(Cls) \ + inline Cls(const Cls &); \ + inline Cls &operator= (const Cls &) + + +/** @def DECLARE_CLS_NEW_DELETE_NOOP + * Declares the new and delete operations as no-ops (non-existent functions) + * for the given class. Use this macro inside the private section if you want + * to effectively limit creating class instances on the stack only. + * + * @note The destructor of the given class must not be virtual, otherwise a + * compile time error will occur. Note that this is not a drawback: having + * the virtual destructor for a stack-based class is absolutely useless + * (the real class of the stack-based instance is always known to the compiler + * at compile time, so it will always call the correct destructor). + * + * @param Cls class name to declare for + */ +#define DECLARE_CLS_NEW_DELETE_NOOP(Cls) \ + inline static void *operator new (size_t); \ + inline static void operator delete (void *) + +#endif /* __cplusplus */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_cdefs_h */ + diff --git a/include/iprt/cdrom.h b/include/iprt/cdrom.h new file mode 100644 index 00000000..78dfecba --- /dev/null +++ b/include/iprt/cdrom.h @@ -0,0 +1,195 @@ +/** @file + * IPRT CD/DVD/BD-ROM Drive API. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cdrom_h +#define IPRT_INCLUDED_cdrom_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cdrom IPRT CD/DVD/BD-ROM Drive API + * @ingroup grp_rt + * + * The user of the API is currently resposible for serializing calls to it. + * + * @{ + */ + +/** CD-ROM drive handle. */ +typedef struct RTCDROMINT *RTCDROM; +/** Pointer to a CD-ROM handle. */ +typedef RTCDROM *PRTCDROM; +/** NIL CD-ROM handle value. */ +#define NIL_RTCDROM ((RTCDROM)0) + + +/** @name CD-ROM open flags. + * @{ */ +#define RTCDROM_O_READ RT_BIT(0) +#define RTCDROM_O_WRITE RT_BIT(1) +#define RTCDROM_O_CONTROL RT_BIT(2) +#define RTCDROM_O_QUERY RT_BIT(3) +#define RTCDROM_O_ALL_ACCESS (RTCDROM_O_READ | RTCDROM_O_WRITE | RTCDROM_O_CONTROL | RTCDROM_O_QUERY) +/** @} */ + +/** + * Opens the CD-ROM drive (by name). + * + * @returns IPRT status code. + * @param pszName The CD-ROM name (path). + * @param fFlags Open flags, see RTCDROM_O_XXX. + * @param phCdrom Where to return the CDROM handle. + */ +RTDECL(int) RTCdromOpen(const char *pszName, uint32_t fFlags, PRTCDROM phCdrom); + +/** + * Retains a reference to the CD-ROM handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * @param hCdrom The CD-ROM handle to retain. + */ +RTDECL(uint32_t) RTCdromRetain(RTCDROM hCdrom); + +/** + * Releases a reference to the CD-ROM handle. + * + * When the reference count reaches zero, the CD-ROM handle is destroy. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * @param hCdrom The CD-ROM handle to retain. + */ +RTDECL(uint32_t) RTCdromRelease(RTCDROM hCdrom); + +/** + * Query the primary mount point of the CD-ROM. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer will be + * set to an empty string if possible. + * + * @param hCdrom The CD-ROM handle. + * @param pszMountPoint Where to return the mount point. + * @param cbMountPoint The size of the mount point buffer. + */ +RTDECL(int) RTCdromQueryMountPoint(RTCDROM hCdrom, char *pszMountPoint, size_t cbMountPoint); + +/** + * Unmounts all file-system mounts related to the CD-ROM. + * + * @returns IPRT status code. + * @param hCdrom The CD-ROM handle. + */ +RTDECL(int) RTCdromUnmount(RTCDROM hCdrom); + +/** + * Ejects the CD-ROM from the drive. + * + * @returns IPRT status code. + * @param hCdrom The CD-ROM handle. + * @param fForce If set, unmount and unlock will be performed. + */ +RTDECL(int) RTCdromEject(RTCDROM hCdrom, bool fForce); + +/** + * Locks the CD-ROM so it cannot be ejected by the user or system. + * + * @returns IPRT status code. + * @param hCdrom The CD-ROM handle. + */ +RTDECL(int) RTCdromLock(RTCDROM hCdrom); + +/** + * Unlocks the CD-ROM so it can be ejected by the user or system. + * + * @returns IPRT status code. + * @param hCdrom The CD-ROM handle. + */ +RTDECL(int) RTCdromUnlock(RTCDROM hCdrom); + + +/** @name Ordinal / Enumeration + * @{ */ +/** + * Get the current number of CD-ROMs. + * + * This is handy for using RTCdromOpenByOrdinal() or RTCdromOrdinalToName() to + * perform some kind of enumeration of all drives. + * + * @returns Number of CD-ROM drivers in the system. + */ +RTDECL(unsigned) RTCdromCount(void); + +/** + * Translates an CD-ROM drive ordinal number to a path suitable for RTCdromOpen. + * + * @returns IRPT status code. + * @retval VINF_SUCCESS on success, with the name in the buffer. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer will be + * set to an empty string if possible, in order to prevent trouble. + * @retval VERR_OUT_OF_RANGE if the ordinal number is higher than the current + * number of CD-ROM drives. + * + * @param iCdrom The CD-ROM drive ordinal. Starts at 0. + * @param pszName Where to return the name (path). + * @param cbName Size of the output buffer. + * + * @remarks The ordinals are volatile. They may change as drives are attached + * or detected from the host. + */ +RTDECL(int) RTCdromOrdinalToName(unsigned iCdrom, char *pszName, size_t cbName); + +/** + * Combination of RTCdromOrdinalToName() and RTCdromOpen(). + * + * @returns IPRT status code. + * @param iCdrom The CD-ROM number. + * @param fFlags Open flags, see RTCDROM_O_XXX. + * @param phCdrom Where to return the CDROM handle . + * @remarks See remarks on RTCdromOrdinalToName(). + */ +RTDECL(int) RTCdromOpenByOrdinal(unsigned iCdrom, uint32_t fFlags, PRTCDROM phCdrom); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_cdrom_h */ + diff --git a/include/iprt/cidr.h b/include/iprt/cidr.h new file mode 100644 index 00000000..ed9d558d --- /dev/null +++ b/include/iprt/cidr.h @@ -0,0 +1,76 @@ +/** @file + * IPRT - TCP/IP. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cidr_h +#define IPRT_INCLUDED_cidr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +/** @defgroup grp_rt_cidr RTCidr - Classless Inter-Domain Routing notation + * @ingroup grp_rt + * @{ + */ +RT_C_DECLS_BEGIN + +/** + * Parse a string which contains an IP address in CIDR (Classless + * Inter-Domain Routing) notation. + * + * @warning The network address and the network mask are returned in + * @b host(!) byte order. This is different from all the other + * RTNetStrTo* functions. + * + * @deprecated This function is superseded by RTNetStrToIPv4Cidr() + * that provides a better API consistent with other functions + * from that family. It returns the prefix length, if you need a + * netmask, you can obtain it with RTNetPrefixToMaskIPv4(). + * + * @return iprt status code. + * + * @param pszAddress The IP address in CIDR specificaion. + * @param pNetwork The determined IP address / network in host byte order. + * @param pNetmask The determined netmask in host byte order. + */ +RTDECL(int) RTCidrStrToIPv4(const char *pszAddress, PRTNETADDRIPV4 pNetwork, PRTNETADDRIPV4 pNetmask); + +RT_C_DECLS_END +/** @} */ + +#endif /* !IPRT_INCLUDED_cidr_h */ diff --git a/include/iprt/circbuf.h b/include/iprt/circbuf.h new file mode 100644 index 00000000..bb107189 --- /dev/null +++ b/include/iprt/circbuf.h @@ -0,0 +1,165 @@ +/** @file + * IPRT - Lock Free Circular Buffer + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_circbuf_h +#define IPRT_INCLUDED_circbuf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_circbuf RTCircBuf - Lock Free Circular Buffer + * @ingroup grp_rt + * + * Implementation of a lock free circular buffer which could be used in a multi + * threaded environment. Note that only the acquire, release and getter + * functions are threading aware. So don't use reset if the circular buffer is + * still in use. + * + * @{ + */ + +RT_C_DECLS_BEGIN + +/** Pointer to a circular buffer (abstract). */ +typedef struct RTCIRCBUF *PRTCIRCBUF; + +/** + * Create a circular buffer. + * + * @returns IPRT status code. + * + * @param ppBuf Where to store the buffer. + * @param cbSize The size of the new buffer. + */ +RTDECL(int) RTCircBufCreate(PRTCIRCBUF *ppBuf, size_t cbSize); + +/** + * Destroy the circular buffer. + * + * @param pBuf The buffer to destroy. NULL is ignored. + */ +RTDECL(void) RTCircBufDestroy(PRTCIRCBUF pBuf); + +/** + * Reset all position information in the circular buffer. + * + * @note This function is not multi threading aware. + * + * @param pBuf The buffer to reset. + */ +RTDECL(void) RTCircBufReset(PRTCIRCBUF pBuf); + +/** + * Returns the current free space of the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufFree(PRTCIRCBUF pBuf); + +/** + * Returns the current used space of the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufUsed(PRTCIRCBUF pBuf); + +/** + * Returns the size of the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufSize(PRTCIRCBUF pBuf); + +RTDECL(bool) RTCircBufIsReading(PRTCIRCBUF pBuf); +RTDECL(bool) RTCircBufIsWriting(PRTCIRCBUF pBuf); + +/** + * Returns the current read offset (in bytes) within the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufOffsetRead(PRTCIRCBUF pBuf); + +/** + * Returns the current write offset (in bytes) within the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufOffsetWrite(PRTCIRCBUF pBuf); + +/** + * Acquire a block of the circular buffer for reading. + * + * @param pBuf The buffer to acquire from. + * @param cbReqSize The requested size of the block. + * @param ppvStart The resulting memory pointer. + * @param pcbSize The resulting size of the memory pointer. + */ +RTDECL(void) RTCircBufAcquireReadBlock(PRTCIRCBUF pBuf, size_t cbReqSize, void **ppvStart, size_t *pcbSize); + +/** + * Release a block which was acquired by RTCircBufAcquireReadBlock. + * + * @param pBuf The buffer to acquire from. + * @param cbSize The size of the block. + */ +RTDECL(void) RTCircBufReleaseReadBlock(PRTCIRCBUF pBuf, size_t cbSize); + +/** + * Acquire a block of the circular buffer for writing. + * + * @param pBuf The buffer to acquire from. + * @param cbReqSize The requested size of the block. + * @param ppvStart The resulting memory pointer. + * @param pcbSize The resulting size of the memory pointer. + */ +RTDECL(void) RTCircBufAcquireWriteBlock(PRTCIRCBUF pBuf, size_t cbReqSize, void **ppvStart, size_t *pcbSize); + +/** + * Release a block which was acquired by RTCircBufAcquireWriteBlock. + * + * @param pBuf The buffer to acquire from. + * @param cbSize The size of the block. + */ +RTDECL(void) RTCircBufReleaseWriteBlock(PRTCIRCBUF pBuf, size_t cbSize); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_circbuf_h */ + diff --git a/include/iprt/condvar.h b/include/iprt/condvar.h new file mode 100644 index 00000000..8501cb5b --- /dev/null +++ b/include/iprt/condvar.h @@ -0,0 +1,297 @@ +/** @file + * IPRT - Condition Variable. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_condvar_h +#define IPRT_INCLUDED_condvar_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) +# include +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_condvar RTCondVar - Condition Variable + * + * Condition variables combines mutex semaphore or critical sections with event + * semaphores. See @ref grp_rt_sems_mutex, @ref grp_rt_critsect, + * @ref grp_rt_sems_event and @ref grp_rt_sems_event_multi. + * + * @ingroup grp_rt + * @{ + */ + + +/** + * Create a condition variable. + * + * @returns iprt status code. + * @param phCondVar Where to store the handle to the newly created + * condition variable. + */ +RTDECL(int) RTCondVarCreate(PRTCONDVAR phCondVar); + +/** + * Create a condition variable. + * + * @returns iprt status code. + * @param phCondVar Where to store the handle to the newly created + * condition variable. + * @param fFlags Flags, any combination of the + * RTCONDVAR_FLAGS_XXX \#defines. + * @param hClass The class (no reference consumed). Since we + * don't do order checks on condition variables, + * the use of the class is limited to controlling + * the timeout threshold for deadlock detection. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTCondVarCreateEx(PRTCONDVAR phCondVar, uint32_t fFlags, RTLOCKVALCLASS hClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** @name RTCondVarCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTCONDVAR_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** @} */ + +/** + * Destroy a condition variable. + * + * @returns iprt status code. + * @param hCondVar Handle of the condition variable. NIL_RTCONDVAR + * is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTCondVarDestroy(RTCONDVAR hCondVar); + +/** + * Signal the condition variable, waking up exactly one thread. + * + * It is recommended that the caller holds the associated lock, but this is not + * strictly speaking necessary. + * + * If no threads are waiting on the condition variable, the call will have no + * effect on the variable. + * + * @returns iprt status code. + * @param hCondVar The condition variable to signal. + */ +RTDECL(int) RTCondVarSignal(RTCONDVAR hCondVar); + +/** + * Signal the condition variable, waking up all blocked threads. + * + * It is recommended that the caller holds the associated lock, but this is not + * strictly speaking necessary. + * + * If no threads are waiting on the condition variable, the call will have no + * effect on the variable. + * + * @returns iprt status code. + * @param hCondVar The condition variable to broadcast. + */ +RTDECL(int) RTCondVarBroadcast(RTCONDVAR hCondVar); + +/** + * Wait for the condition variable to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hCondVar The condition variable to wait on. + * @param hMtx The mutex to leave during the wait and which + * will be re-enter before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarMutexWait(RTCONDVAR hCondVar, RTSEMMUTEX hMtx, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hCondVar The condition variable to wait on. + * @param hMtx The mutex to leave during the wait and which + * will be re-enter before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarMutexWaitNoResume(RTCONDVAR hCondVar, RTSEMMUTEX hMtx, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hCondVar The condition variable to wait on. + * @param hRWSem The read/write semaphore to write-leave during + * the wait and which will be re-enter in write + * mode before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarRWWriteWait(RTCONDVAR hCondVar, RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hCondVar The condition variable to wait on. + * @param hRWSem The read/write semaphore to write-leave during + * the wait and which will be re-enter in write + * mode before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarRWWriteWaitNoResume(RTCONDVAR hCondVar, RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hCondVar The condition variable to wait on. + * @param hRWSem The read/write semaphore to read-leave during + * the wait and which will be re-enter in read mode + * before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarRWReadWait(RTCONDVAR hCondVar, RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hCondVar The condition variable to wait on. + * @param hRWSem The read/write semaphore to read-leave during + * the wait and which will be re-enter in read mode + * before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarRWReadWaitNoResume(RTCONDVAR hCondVar, RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hCondVar The condition variable to wait on. + * @param pCritSect The critical section to leave during the wait + * and which will be re-enter before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarCritSectWait(RTCONDVAR hCondVar, PRTCRITSECT pCritSect, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hCondVar The condition variable to wait on. + * @param pCritSect The critical section to leave during the wait + * and which will be re-enter before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarCritSectWaitNoResume(RTCONDVAR hCondVar, PRTCRITSECT pCritSect, RTMSINTERVAL cMillies); + +/** + * Sets the signaller thread to one specific thread. + * + * This is only used for validating usage and deadlock detection. When used + * after calls to RTCondVarAddSignaller, the specified thread will be the only + * signalling thread. + * + * @param hCondVar The condition variable. + * @param hThread The thread that will signal it. Pass + * NIL_RTTHREAD to indicate that there is no + * special signalling thread. + */ +RTDECL(void) RTCondVarSetSignaller(RTCONDVAR hCondVar, RTTHREAD hThread); + +/** + * To add more signalling threads. + * + * First call RTCondVarSetSignaller then add further threads with this. + * + * @param hCondVar The condition variable. + * @param hThread The thread that will signal it. NIL_RTTHREAD is + * not accepted. + */ +RTDECL(void) RTCondVarAddSignaller(RTCONDVAR hCondVar, RTTHREAD hThread); + +/** + * To remove a signalling thread. + * + * Reverts work done by RTCondVarAddSignaller and RTCondVarSetSignaller. + * + * @param hCondVar The condition variable. + * @param hThread A previously added thread. + */ +RTDECL(void) RTCondVarRemoveSignaller(RTCONDVAR hCondVar, RTTHREAD hThread); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_condvar_h */ + diff --git a/include/iprt/coredumper.h b/include/iprt/coredumper.h new file mode 100644 index 00000000..7d1f07c8 --- /dev/null +++ b/include/iprt/coredumper.h @@ -0,0 +1,105 @@ +/** @file + * IPRT - Core Dumper. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_coredumper_h +#define IPRT_INCLUDED_coredumper_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_coredumper RTCoreDumper - Core Dumper. + * @ingroup grp_rt + * @{ + */ + +/** @name RTCoreDumperSetup flags + * @{ */ +/** Override system core dumper. Registers handlers for + * SIGSEGV/SIGTRAP/SIGBUS. */ +#define RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP RT_BIT(0) +/** Allow taking live process dumps (without killing process). Registers handler + * for SIGUSR2. */ +#define RTCOREDUMPER_FLAGS_LIVE_CORE RT_BIT(1) +/** @} */ + +/** + * Take a core dump of the current process without terminating it. + * + * @returns IPRT status code. + * @param pszOutputFile Name of the core file. If NULL use the + * default naming scheme. + * @param fLiveCore When true, the process is not killed after + * taking a core. Otherwise it will be killed. This + * works in conjuction with the flags set during + * RTCoreDumperSetup(). + */ +RTDECL(int) RTCoreDumperTakeDump(const char *pszOutputFile, bool fLiveCore); + +/** + * Sets up and enables the core dumper. + * + * Installs signal / unhandled exception handlers for catching fatal errors + * that should result in a core dump. If you wish to install your own handlers + * you should do that after calling this function and make sure you pass on + * events you don't handle. + * + * This can be called multiple times to change the settings without needing to + * call RTCoreDumperDisable in between. + * + * @param pszOutputDir The directory to store the cores in. If NULL + * the current directory will be used. + * @param fFlags Setup flags, 0 in NOT a valid flag, it must be + * one or more of RTCOREDUMPER_FLAGS_*. + */ +RTDECL(int) RTCoreDumperSetup(const char *pszOutputDir, uint32_t fFlags); + +/** + * Disables the core dumper, i.e. undoes what RTCoreDumperSetup did. + * + * @returns IPRT status code. + */ +RTDECL(int) RTCoreDumperDisable(void); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_coredumper_h */ + diff --git a/include/iprt/cpp/Makefile.kup b/include/iprt/cpp/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/cpp/autores.h b/include/iprt/cpp/autores.h new file mode 100644 index 00000000..a620de7a --- /dev/null +++ b/include/iprt/cpp/autores.h @@ -0,0 +1,216 @@ +/** @file + * IPRT - C++ Resource Management. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_autores_h +#define IPRT_INCLUDED_cpp_autores_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + + +/** @defgroup grp_rt_cpp_autores C++ Resource Management + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * A callable class template which returns the correct value against which an + * IPRT type must be compared to see if it is invalid. + * + * @warning This template *must* be specialised for the types it is to work with. + */ +template +inline T RTAutoResNil(void) +{ + AssertFatalMsgFailed(("Unspecialized template!\n")); + return (T)0; +} + +/** Specialisation of RTAutoResNil for RTFILE */ +template <> +inline RTFILE RTAutoResNil(void) +{ + return NIL_RTFILE; +} + +/** + * A function template which calls the correct destructor for an IPRT type. + * + * @warning This template *must* be specialised for the types it is to work with. + */ +template +inline void RTAutoResDestruct(T a_h) +{ + AssertFatalMsgFailed(("Unspecialized template!\n")); + NOREF(a_h); +} + +/** + * An auto pointer-type class for resources which take a C-style destructor + * (RTMemFree() or equivalent). + * + * The idea of this class is to manage resources which the current code is + * responsible for freeing. By wrapping the resource in an RTCAutoRes, you + * ensure that the resource will be freed when you leave the scope in which + * the RTCAutoRes is defined, unless you explicitly release the resource. + * + * A typical use case is when a function is allocating a number of resources. + * If any single allocation fails then all other resources must be freed. If + * all allocations succeed, then the resources should be returned to the + * caller. By placing all allocated resources in RTCAutoRes containers, you + * ensure that they will be freed on failure, and only have to take care of + * releasing them when you return them. + * + * @param T The type of the resource. + * @param Destruct The function to be used to free the resource. + * This parameter must be supplied if there is no + * specialisation of RTAutoDestruct available for @a T. + * @param NilRes The function returning the NIL value for T. Required. + * This parameter must be supplied if there is no + * specialisation of RTAutoResNil available for @a T. + * + * @note The class can not be initialised directly using assignment, due + * to the lack of a copy constructor. This is intentional. + */ +template , T NilRes(void) = RTAutoResNil > +class RTCAutoRes + : public RTCNonCopyable +{ +protected: + /** The resource handle. */ + T m_hRes; + +public: + /** + * Constructor + * + * @param a_hRes The handle to resource to manage. Defaults to NIL. + */ + RTCAutoRes(T a_hRes = NilRes()) + : m_hRes(a_hRes) + { + } + + /** + * Destructor. + * + * This destroys any resource currently managed by the object. + */ + ~RTCAutoRes() + { + if (m_hRes != NilRes()) + Destruct(m_hRes); + } + + /** + * Assignment from a value. + * + * This destroys any resource currently managed by the object + * before taking on the new one. + * + * @param a_hRes The handle to the new resource. + */ + RTCAutoRes &operator=(T a_hRes) + { + if (m_hRes != NilRes()) + Destruct(m_hRes); + m_hRes = a_hRes; + return *this; + } + + /** + * Checks if the resource handle is NIL or not. + */ + bool operator!() + { + return m_hRes == NilRes(); + } + + /** + * Give up ownership the current resource, handing it to the caller. + * + * @returns The current resource handle. + * + * @note Nothing happens to the resource when the object goes out of scope. + */ + T release(void) + { + T Tmp = m_hRes; + m_hRes = NilRes(); + return Tmp; + } + + /** + * Deletes the current resources. + * + * @param a_hRes Handle to a new resource to manage. Defaults to NIL. + */ + void reset(T a_hRes = NilRes()) + { + if (a_hRes != m_hRes) + { + if (m_hRes != NilRes()) + Destruct(m_hRes); + m_hRes = a_hRes; + } + } + + /** + * Get the raw resource handle. + * + * Typically used passing the handle to some IPRT function while + * the object remains in scope. + * + * @returns The raw resource handle. + */ + T get(void) + { + return m_hRes; + } +}; + +/** @} */ + + +/* include after template definition */ +#include + +#endif /* !IPRT_INCLUDED_cpp_autores_h */ + diff --git a/include/iprt/cpp/exception.h b/include/iprt/cpp/exception.h new file mode 100644 index 00000000..0c9f09b7 --- /dev/null +++ b/include/iprt/cpp/exception.h @@ -0,0 +1,118 @@ +/** @file + * IPRT - C++ Base Exceptions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_exception_h +#define IPRT_INCLUDED_cpp_exception_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#if RT_MSC_PREREQ(RT_MSC_VER_VC140) +# pragma warning(push) +# pragma warning(disable:4275) /* non dll-interface class 'std::exception' used as base for dll-interface class 'RTCError' */ +#endif + + +/** @defgroup grp_rt_cpp_exceptions C++ Exceptions + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Base exception class for IPRT, derived from std::exception. + * The XML exceptions are based on this. + */ +class RT_DECL_CLASS RTCError + : public std::exception +{ +public: + + RTCError(const char *pszMessage) + : m_strMsg(pszMessage) + { + } + + RTCError(const RTCString &a_rstrMessage) + : m_strMsg(a_rstrMessage) + { + } + + RTCError(const RTCError &a_rSrc) + : std::exception(a_rSrc), + m_strMsg(a_rSrc.what()) + { + } + + virtual ~RTCError() throw() + { + } + + void operator=(const RTCError &a_rSrc) + { + m_strMsg = a_rSrc.what(); + } + + void setWhat(const char *a_pszMessage) + { + m_strMsg = a_pszMessage; + } + + virtual const char *what() const throw() + { + return m_strMsg.c_str(); + } + +private: + /** + * Hidden default constructor making sure that the extended one above is + * always used. + */ + RTCError(); + +protected: + /** The exception message. */ + RTCString m_strMsg; +}; + +/** @} */ + +#if RT_MSC_PREREQ(RT_MSC_VER_VC140) +# pragma warning(pop) +#endif +#endif /* !IPRT_INCLUDED_cpp_exception_h */ + diff --git a/include/iprt/cpp/hardavlrange.h b/include/iprt/cpp/hardavlrange.h new file mode 100644 index 00000000..7020968e --- /dev/null +++ b/include/iprt/cpp/hardavlrange.h @@ -0,0 +1,1284 @@ +/** @file + * IPRT - Hardened AVL tree, unique key ranges. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_hardavlrange_h +#define IPRT_INCLUDED_cpp_hardavlrange_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_cpp_hardavl Hardened AVL Trees + * @{ + */ + +/** + * Check that the tree heights make sense for the current node. + * + * This is a RT_STRICT test as it's expensive and we should have sufficient + * other checks to ensure safe AVL tree operation. + * + * @note the a_cStackEntries parameter is a hack to avoid running into gcc's + * "the address of 'AVLStack' will never be NULL" errors. + */ +#ifdef RT_STRICT +# define RTHARDAVL_STRICT_CHECK_HEIGHTS(a_pNode, a_pAvlStack, a_cStackEntries) do { \ + NodeType * const pLeftNodeX = a_pAllocator->ptrFromInt(readIdx(&(a_pNode)->idxLeft)); \ + AssertReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNodeX), m_cErrors++, a_pAllocator->ptrErrToStatus((a_pNode))); \ + NodeType * const pRightNodeX = a_pAllocator->ptrFromInt(readIdx(&(a_pNode)->idxRight)); \ + AssertReturnStmt(a_pAllocator->isPtrRetOkay(pRightNodeX), m_cErrors++, a_pAllocator->ptrErrToStatus((a_pNode))); \ + uint8_t const cLeftHeightX = pLeftNodeX ? pLeftNodeX->cHeight : 0; \ + uint8_t const cRightHeightX = pRightNodeX ? pRightNodeX->cHeight : 0; \ + if (RT_LIKELY((a_pNode)->cHeight == RT_MAX(cLeftHeightX, cRightHeightX) + 1)) { /*likely*/ } \ + else \ + { \ + RTAssertMsg2("line %u: %u l=%u r=%u\n", __LINE__, (a_pNode)->cHeight, cLeftHeightX, cRightHeightX); \ + if ((a_cStackEntries)) dumpStack(a_pAllocator, (a_pAvlStack)); \ + AssertMsgReturnStmt((a_pNode)->cHeight == RT_MAX(cLeftHeightX, cRightHeightX) + 1, \ + ("%u l=%u r=%u\n", (a_pNode)->cHeight, cLeftHeightX, cRightHeightX), \ + m_cErrors++, VERR_HARDAVL_BAD_HEIGHT); \ + } \ + AssertMsgReturnStmt(RT_ABS(cLeftHeightX - cRightHeightX) <= 1, ("l=%u r=%u\n", cLeftHeightX, cRightHeightX), \ + m_cErrors++, VERR_HARDAVL_UNBALANCED); \ + Assert(!pLeftNodeX || pLeftNodeX->Key < (a_pNode)->Key); \ + Assert(!pRightNodeX || pRightNodeX->Key > (a_pNode)->Key); \ + } while (0) +#else +# define RTHARDAVL_STRICT_CHECK_HEIGHTS(a_pNode, a_pAvlStack, a_cStackEntries) do { } while (0) +#endif + + +/** + * Hardened AVL tree for nodes with key ranges. + * + * This is very crude and therefore expects the NodeType to feature: + * - Key and KeyLast members of KeyType. + * - idxLeft and idxRight members with type uint32_t. + * - cHeight members of type uint8_t. + * + * The code is very C-ish because of it's sources and initial use (ring-0 + * without C++ exceptions enabled). + */ +template +struct RTCHardAvlRangeTree +{ + /** The root index. */ + uint32_t m_idxRoot; + /** The error count. */ + uint32_t m_cErrors; + /** @name Statistics + * @{ */ + uint64_t m_cInserts; + uint64_t m_cRemovals; + uint64_t m_cRebalancingOperations; + /** @} */ + + /** The max stack depth. */ + enum { kMaxStack = 28 }; + /** The max height value we allow. */ + enum { kMaxHeight = kMaxStack + 1 }; + + /** A stack used internally to avoid recursive calls. + * This is used with operations invoking i_rebalance(). */ + typedef struct HardAvlStack + { + /** Number of entries on the stack. */ + unsigned cEntries; + /** The stack. */ + uint32_t *apidxEntries[kMaxStack]; + } HardAvlStack; + + /** @name Key comparisons + * @{ */ + static inline int areKeyRangesIntersecting(KeyType a_Key1First, KeyType a_Key2First, + KeyType a_Key1Last, KeyType a_Key2Last) RT_NOEXCEPT + { + return a_Key1First <= a_Key2Last && a_Key1Last >= a_Key2First; + } + + static inline int isKeyInRange(KeyType a_Key, KeyType a_KeyFirst, KeyType a_KeyLast) RT_NOEXCEPT + { + return a_Key <= a_KeyLast && a_Key >= a_KeyFirst; + } + + static inline int isKeyGreater(KeyType a_Key1, KeyType a_Key2) RT_NOEXCEPT + { + return a_Key1 > a_Key2; + } + /** @} */ + + /** + * Read an index value trying to prevent the compiler from re-reading it. + */ + DECL_FORCE_INLINE(uint32_t) readIdx(uint32_t volatile *pidx) RT_NOEXCEPT + { + uint32_t idx = *pidx; + ASMCompilerBarrier(); + return idx; + } + + RTCHardAvlRangeTree() RT_NOEXCEPT + : m_idxRoot(0) + , m_cErrors(0) + { } + + RTCHardAvlRangeTree(RTCHardAvlTreeSlabAllocator *a_pAllocator) RT_NOEXCEPT + { + initWithAllocator(a_pAllocator); + } + + void initWithAllocator(RTCHardAvlTreeSlabAllocator *a_pAllocator) RT_NOEXCEPT + { + m_idxRoot = a_pAllocator->kNilIndex; + m_cErrors = 0; + } + + /** + * Inserts a node into the AVL-tree. + * + * @returns IPRT status code. + * @retval VERR_ALREADY_EXISTS if a node with overlapping key range exists. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pNode Pointer to the node which is to be added. + * + * @code + * Find the location of the node (using binary tree algorithm.): + * LOOP until KAVL_NULL leaf pointer + * BEGIN + * Add node pointer pointer to the AVL-stack. + * IF new-node-key < node key THEN + * left + * ELSE + * right + * END + * Fill in leaf node and insert it. + * Rebalance the tree. + * @endcode + */ + int insert(RTCHardAvlTreeSlabAllocator *a_pAllocator, NodeType *a_pNode) RT_NOEXCEPT + { + KeyType const Key = a_pNode->Key; + KeyType const KeyLast = a_pNode->KeyLast; + AssertMsgReturn(Key <= KeyLast, ("Key=%#RX64 KeyLast=%#RX64\n", (uint64_t)Key, (uint64_t)KeyLast), + VERR_HARDAVL_INSERT_INVALID_KEY_RANGE); + + uint32_t *pidxCurNode = &m_idxRoot; + HardAvlStack AVLStack; + AVLStack.cEntries = 0; + for (;;) + { + NodeType *pCurNode = a_pAllocator->ptrFromInt(readIdx(pidxCurNode)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pCurNode), ("*pidxCurNode=%#x pCurNode=%p\n", *pidxCurNode, pCurNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pCurNode)); + if (!pCurNode) + break; + + unsigned const cEntries = AVLStack.cEntries; + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(AVLStack.apidxEntries), + ("%p[%#x/%p] %p[%#x] %p[%#x] %p[%#x] %p[%#x] %p[%#x]\n", pidxCurNode, *pidxCurNode, pCurNode, + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + AVLStack.apidxEntries[cEntries] = pidxCurNode; + AVLStack.cEntries = cEntries + 1; + + RTHARDAVL_STRICT_CHECK_HEIGHTS(pCurNode, &AVLStack, AVLStack.cEntries); + + /* Range check: */ + if (areKeyRangesIntersecting(pCurNode->Key, Key, pCurNode->KeyLast, KeyLast)) + return VERR_ALREADY_EXISTS; + + /* Descend: */ + if (isKeyGreater(pCurNode->Key, Key)) + pidxCurNode = &pCurNode->idxLeft; + else + pidxCurNode = &pCurNode->idxRight; + } + + a_pNode->idxLeft = a_pAllocator->kNilIndex; + a_pNode->idxRight = a_pAllocator->kNilIndex; + a_pNode->cHeight = 1; + + uint32_t const idxNode = a_pAllocator->ptrToInt(a_pNode); + AssertMsgReturn(a_pAllocator->isIdxRetOkay(idxNode), ("pNode=%p idxNode=%#x\n", a_pNode, idxNode), + a_pAllocator->idxErrToStatus(idxNode)); + *pidxCurNode = idxNode; + + m_cInserts++; + return i_rebalance(a_pAllocator, &AVLStack); + } + + /** + * Removes a node from the AVL-tree by a key value. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if not found. + * @param a_pAllocator Pointer to the allocator. + * @param a_Key A key value in the range of the node to be removed. + * @param a_ppRemoved Where to return the pointer to the removed node. + * + * @code + * Find the node which is to be removed: + * LOOP until not found + * BEGIN + * Add node pointer pointer to the AVL-stack. + * IF the keys matches THEN break! + * IF remove key < node key THEN + * left + * ELSE + * right + * END + * IF found THEN + * BEGIN + * IF left node not empty THEN + * BEGIN + * Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack: + * Start at left node. + * LOOP until right node is empty + * BEGIN + * Add to stack. + * go right. + * END + * Link out the found node. + * Replace the node which is to be removed with the found node. + * Correct the stack entry for the pointer to the left tree. + * END + * ELSE + * BEGIN + * Move up right node. + * Remove last stack entry. + * END + * Balance tree using stack. + * END + * return pointer to the removed node (if found). + * @endcode + */ + int remove(RTCHardAvlTreeSlabAllocator *a_pAllocator, KeyType a_Key, NodeType **a_ppRemoved) RT_NOEXCEPT + { + *a_ppRemoved = NULL; + + /* + * Walk the tree till we locate the node that is to be deleted. + */ + uint32_t *pidxDeleteNode = &m_idxRoot; + NodeType *pDeleteNode; + HardAvlStack AVLStack; + AVLStack.cEntries = 0; + for (;;) + { + pDeleteNode = a_pAllocator->ptrFromInt(readIdx(pidxDeleteNode)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pDeleteNode), + ("*pidxCurNode=%#x pDeleteNode=%p\n", *pidxDeleteNode, pDeleteNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pDeleteNode)); + if (pDeleteNode) + { /*likely*/ } + else + return VERR_NOT_FOUND; + + unsigned const cEntries = AVLStack.cEntries; + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(AVLStack.apidxEntries), + ("%p[%#x/%p] %p[%#x] %p[%#x] %p[%#x] %p[%#x] %p[%#x]\n", + pidxDeleteNode, *pidxDeleteNode, pDeleteNode, + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + AVLStack.apidxEntries[cEntries] = pidxDeleteNode; + AVLStack.cEntries = cEntries + 1; + + RTHARDAVL_STRICT_CHECK_HEIGHTS(pDeleteNode, &AVLStack, AVLStack.cEntries); + + /* Range check: */ + if (isKeyInRange(a_Key, pDeleteNode->Key, pDeleteNode->KeyLast)) + break; + + /* Descend: */ + if (isKeyGreater(pDeleteNode->Key, a_Key)) + pidxDeleteNode = &pDeleteNode->idxLeft; + else + pidxDeleteNode = &pDeleteNode->idxRight; + } + + /* + * Do the deletion. + */ + uint32_t const idxDeleteLeftNode = readIdx(&pDeleteNode->idxLeft); + if (idxDeleteLeftNode != a_pAllocator->kNilIndex) + { + /* + * Replace the deleted node with the rightmost node in the left subtree. + */ + NodeType * const pDeleteLeftNode = a_pAllocator->ptrFromInt(idxDeleteLeftNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pDeleteLeftNode), + ("idxDeleteLeftNode=%#x pDeleteLeftNode=%p\n", idxDeleteLeftNode, pDeleteLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pDeleteLeftNode)); + + uint32_t const idxDeleteRightNode = readIdx(&pDeleteNode->idxRight); + AssertReturnStmt(a_pAllocator->isIntValid(idxDeleteRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + + const unsigned iStackEntry = AVLStack.cEntries; + + uint32_t *pidxLeftBiggest = &pDeleteNode->idxLeft; + uint32_t idxLeftBiggestNode = idxDeleteLeftNode; + NodeType *pLeftBiggestNode = pDeleteLeftNode; + RTHARDAVL_STRICT_CHECK_HEIGHTS(pLeftBiggestNode, &AVLStack, AVLStack.cEntries); + + uint32_t idxRightTmp; + while ((idxRightTmp = readIdx(&pLeftBiggestNode->idxRight)) != a_pAllocator->kNilIndex) + { + unsigned const cEntries = AVLStack.cEntries; + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(AVLStack.apidxEntries), + ("%p[%#x/%p] %p[%#x] %p[%#x] %p[%#x] %p[%#x] %p[%#x]\n", + pidxLeftBiggest, *pidxLeftBiggest, pLeftBiggestNode, + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + AVLStack.apidxEntries[cEntries] = pidxLeftBiggest; + AVLStack.cEntries = cEntries + 1; + + pidxLeftBiggest = &pLeftBiggestNode->idxRight; + idxLeftBiggestNode = idxRightTmp; + pLeftBiggestNode = a_pAllocator->ptrFromInt(idxRightTmp); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftBiggestNode), + ("idxLeftBiggestNode=%#x pLeftBiggestNode=%p\n", idxLeftBiggestNode, pLeftBiggestNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftBiggestNode)); + RTHARDAVL_STRICT_CHECK_HEIGHTS(pLeftBiggestNode, &AVLStack, AVLStack.cEntries); + } + + uint32_t const idxLeftBiggestLeftNode = readIdx(&pLeftBiggestNode->idxLeft); + AssertReturnStmt(a_pAllocator->isIntValid(idxLeftBiggestLeftNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + + /* link out pLeftBiggestNode */ + *pidxLeftBiggest = idxLeftBiggestLeftNode; + + /* link it in place of the deleted node. */ + if (idxDeleteLeftNode != idxLeftBiggestNode) + pLeftBiggestNode->idxLeft = idxDeleteLeftNode; + pLeftBiggestNode->idxRight = idxDeleteRightNode; + pLeftBiggestNode->cHeight = AVLStack.cEntries > iStackEntry ? pDeleteNode->cHeight : 0; + + *pidxDeleteNode = idxLeftBiggestNode; + + if (AVLStack.cEntries > iStackEntry) + AVLStack.apidxEntries[iStackEntry] = &pLeftBiggestNode->idxLeft; + } + else + { + /* No left node, just pull up the right one. */ + uint32_t const idxDeleteRightNode = readIdx(&pDeleteNode->idxRight); + AssertReturnStmt(a_pAllocator->isIntValid(idxDeleteRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + *pidxDeleteNode = idxDeleteRightNode; + AVLStack.cEntries--; + } + *a_ppRemoved = pDeleteNode; + + m_cRemovals++; + return i_rebalance(a_pAllocator, &AVLStack); + } + + /** + * Looks up a node from the tree. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if not found. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_Key A key value in the range of the desired node. + * @param a_ppFound Where to return the pointer to the node. + */ + int lookup(RTCHardAvlTreeSlabAllocator *a_pAllocator, KeyType a_Key, NodeType **a_ppFound) RT_NOEXCEPT + { + *a_ppFound = NULL; + + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); +#ifdef RT_STRICT + HardAvlStack AVLStack; + AVLStack.apidxEntries[0] = &m_idxRoot; + AVLStack.cEntries = 1; +#endif + unsigned cDepth = 0; + while (pNode) + { + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, &AVLStack, AVLStack.cEntries); + AssertReturn(cDepth <= kMaxHeight, VERR_HARDAVL_LOOKUP_TOO_DEEP); + cDepth++; + + if (isKeyInRange(a_Key, pNode->Key, pNode->KeyLast)) + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + if (isKeyGreater(pNode->Key, a_Key)) + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxLeft; +#endif + uint32_t const idxLeft = readIdx(&pNode->idxLeft); + pNode = a_pAllocator->ptrFromInt(idxLeft); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("idxLeft=%#x pNode=%p\n", idxLeft, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + } + else + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxRight; +#endif + uint32_t const idxRight = readIdx(&pNode->idxRight); + pNode = a_pAllocator->ptrFromInt(idxRight); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("idxRight=%#x pNode=%p\n", idxRight, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + } + } + + return VERR_NOT_FOUND; + } + + /** + * Looks up node matching @a a_Key or if no exact match the closest smaller than it. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if not found. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_Key A key value in the range of the desired node. + * @param a_ppFound Where to return the pointer to the node. + */ + int lookupMatchingOrBelow(RTCHardAvlTreeSlabAllocator *a_pAllocator, KeyType a_Key, + NodeType **a_ppFound) RT_NOEXCEPT + { + *a_ppFound = NULL; + + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); +#ifdef RT_STRICT + HardAvlStack AVLStack; + AVLStack.apidxEntries[0] = &m_idxRoot; + AVLStack.cEntries = 1; +#endif + unsigned cDepth = 0; + NodeType *pNodeLast = NULL; + while (pNode) + { + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, &AVLStack, AVLStack.cEntries); + AssertReturn(cDepth <= kMaxHeight, VERR_HARDAVL_LOOKUP_TOO_DEEP); + cDepth++; + + if (isKeyInRange(a_Key, pNode->Key, pNode->KeyLast)) + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + if (isKeyGreater(pNode->Key, a_Key)) + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxLeft; +#endif + uint32_t const idxLeft = readIdx(&pNode->idxLeft); + NodeType *pLeftNode = a_pAllocator->ptrFromInt(idxLeft); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), ("idxLeft=%#x pLeftNode=%p\n", idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + pNode = pLeftNode; + else if (!pNodeLast) + break; + else + { + *a_ppFound = pNodeLast; + return VINF_SUCCESS; + } + } + else + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxRight; +#endif + uint32_t const idxRight = readIdx(&pNode->idxRight); + NodeType *pRightNode = a_pAllocator->ptrFromInt(idxRight); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), ("idxRight=%#x pRightNode=%p\n", idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + { + pNodeLast = pNode; + pNode = pRightNode; + } + else + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + } + } + + return VERR_NOT_FOUND; + } + + /** + * Looks up node matching @a a_Key or if no exact match the closest larger than it. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if not found. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_Key A key value in the range of the desired node. + * @param a_ppFound Where to return the pointer to the node. + */ + int lookupMatchingOrAbove(RTCHardAvlTreeSlabAllocator *a_pAllocator, KeyType a_Key, + NodeType **a_ppFound) RT_NOEXCEPT + { + *a_ppFound = NULL; + + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); +#ifdef RT_STRICT + HardAvlStack AVLStack; + AVLStack.apidxEntries[0] = &m_idxRoot; + AVLStack.cEntries = 1; +#endif + unsigned cDepth = 0; + NodeType *pNodeLast = NULL; + while (pNode) + { + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, &AVLStack, AVLStack.cEntries); + AssertReturn(cDepth <= kMaxHeight, VERR_HARDAVL_LOOKUP_TOO_DEEP); + cDepth++; + + if (isKeyInRange(a_Key, pNode->Key, pNode->KeyLast)) + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + if (isKeyGreater(pNode->Key, a_Key)) + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxLeft; +#endif + uint32_t const idxLeft = readIdx(&pNode->idxLeft); + NodeType *pLeftNode = a_pAllocator->ptrFromInt(idxLeft); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), ("idxLeft=%#x pLeftNode=%p\n", idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + { + pNodeLast = pNode; + pNode = pLeftNode; + } + else + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + } + else + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxRight; +#endif + uint32_t const idxRight = readIdx(&pNode->idxRight); + NodeType *pRightNode = a_pAllocator->ptrFromInt(idxRight); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), ("idxRight=%#x pRightNode=%p\n", idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + pNode = pRightNode; + else if (!pNodeLast) + break; + else + { + *a_ppFound = pNodeLast; + return VINF_SUCCESS; + } + } + } + + return VERR_NOT_FOUND; + } + + /** + * A callback for doWithAllFromLeft and doWithAllFromRight. + * + * @returns IPRT status code. Any non-zero status causes immediate return from + * the enumeration function. + * @param pNode The current node. + * @param pvUser The user argument. + */ + typedef DECLCALLBACKTYPE(int, FNCALLBACK,(NodeType *pNode, void *pvUser)); + /** Pointer to a callback for doWithAllFromLeft and doWithAllFromRight. */ + typedef FNCALLBACK *PFNCALLBACK; + + /** + * Iterates thru all nodes in the tree from left (smaller) to right. + * + * @returns IPRT status code. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pfnCallBack Pointer to callback function. + * @param a_pvUser Callback user argument. + * + * @note This is very similar code to doWithAllFromRight() and destroy(). + */ + int doWithAllFromLeft(RTCHardAvlTreeSlabAllocator *a_pAllocator, + PFNCALLBACK a_pfnCallBack, void *a_pvUser) RT_NOEXCEPT + { + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + if (!pNode) + return VINF_SUCCESS; + + /* + * We simulate recursive calling here. For safety reasons, we do not + * pop before going down the right tree like the original code did. + */ + uint32_t cNodesLeft = a_pAllocator->m_cNodes; + NodeType *apEntries[kMaxStack]; + uint8_t abState[kMaxStack]; + unsigned cEntries = 1; + abState[0] = 0; + apEntries[0] = pNode; + while (cEntries > 0) + { + pNode = apEntries[cEntries - 1]; + switch (abState[cEntries - 1]) + { + /* Go left. */ + case 0: + { + abState[cEntries - 1] = 1; + + NodeType * const pLeftNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxLeft)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), + ("idxLeft=%#x pLeftNode=%p\n", pNode->idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pLeftNode, pNode->idxLeft, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pLeftNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + /* center then right. */ + case 1: + { + abState[cEntries - 1] = 2; + + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); + + int rc = a_pfnCallBack(pNode, a_pvUser); + if (rc != VINF_SUCCESS) + return rc; + + NodeType * const pRightNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxRight)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), + ("idxRight=%#x pRightNode=%p\n", pNode->idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pRightNode, pNode->idxRight, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pRightNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + default: + /* pop it. */ + cEntries -= 1; + break; + } + } + return VINF_SUCCESS; + } + + /** + * Iterates thru all nodes in the tree from right (larger) to left (smaller). + * + * @returns IPRT status code. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pfnCallBack Pointer to callback function. + * @param a_pvUser Callback user argument. + * + * @note This is very similar code to doWithAllFromLeft() and destroy(). + */ + int doWithAllFromRight(RTCHardAvlTreeSlabAllocator *a_pAllocator, + PFNCALLBACK a_pfnCallBack, void *a_pvUser) RT_NOEXCEPT + { + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + if (!pNode) + return VINF_SUCCESS; + + /* + * We simulate recursive calling here. For safety reasons, we do not + * pop before going down the right tree like the original code did. + */ + uint32_t cNodesLeft = a_pAllocator->m_cNodes; + NodeType *apEntries[kMaxStack]; + uint8_t abState[kMaxStack]; + unsigned cEntries = 1; + abState[0] = 0; + apEntries[0] = pNode; + while (cEntries > 0) + { + pNode = apEntries[cEntries - 1]; + switch (abState[cEntries - 1]) + { + /* Go right. */ + case 0: + { + abState[cEntries - 1] = 1; + + NodeType * const pRightNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxRight)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), + ("idxRight=%#x pRightNode=%p\n", pNode->idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pRightNode, pNode->idxRight, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pRightNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + /* center then left. */ + case 1: + { + abState[cEntries - 1] = 2; + + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); + + int rc = a_pfnCallBack(pNode, a_pvUser); + if (rc != VINF_SUCCESS) + return rc; + + NodeType * const pLeftNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxLeft)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), + ("idxLeft=%#x pLeftNode=%p\n", pNode->idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pLeftNode, pNode->idxLeft, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pLeftNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + default: + /* pop it. */ + cEntries -= 1; + break; + } + } + return VINF_SUCCESS; + } + + /** + * A callback for destroy to do additional cleanups before the node is freed. + * + * @param pNode The current node. + * @param pvUser The user argument. + */ + typedef DECLCALLBACKTYPE(void, FNDESTROYCALLBACK,(NodeType *pNode, void *pvUser)); + /** Pointer to a callback for destroy. */ + typedef FNDESTROYCALLBACK *PFNDESTROYCALLBACK; + + /** + * Destroys the tree, starting with the root node. + * + * This will invoke the freeNode() method on the allocate for every node after + * first doing the callback to let the caller free additional resources + * referenced by the node. + * + * @returns IPRT status code. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pfnCallBack Pointer to callback function. Optional. + * @param a_pvUser Callback user argument. + * + * @note This is mostly the same code as the doWithAllFromLeft(). + */ + int destroy(RTCHardAvlTreeSlabAllocator *a_pAllocator, + PFNDESTROYCALLBACK a_pfnCallBack = NULL, void *a_pvUser = NULL) RT_NOEXCEPT + { + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + if (!pNode) + return VINF_SUCCESS; + + /* + * We simulate recursive calling here. For safety reasons, we do not + * pop before going down the right tree like the original code did. + */ + uint32_t cNodesLeft = a_pAllocator->m_cNodes; + NodeType *apEntries[kMaxStack]; + uint8_t abState[kMaxStack]; + unsigned cEntries = 1; + abState[0] = 0; + apEntries[0] = pNode; + while (cEntries > 0) + { + pNode = apEntries[cEntries - 1]; + switch (abState[cEntries - 1]) + { + /* Go left. */ + case 0: + { + abState[cEntries - 1] = 1; + + NodeType * const pLeftNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxLeft)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), + ("idxLeft=%#x pLeftNode=%p\n", pNode->idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pLeftNode, pNode->idxLeft, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pLeftNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + /* right. */ + case 1: + { + abState[cEntries - 1] = 2; + + NodeType * const pRightNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxRight)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), + ("idxRight=%#x pRightNode=%p\n", pNode->idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pRightNode, pNode->idxRight, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pRightNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + default: + { + /* pop it and destroy it. */ + if (a_pfnCallBack) + a_pfnCallBack(pNode, a_pvUser); + + int rc = a_pAllocator->freeNode(pNode); + AssertRCReturnStmt(rc, m_cErrors++, rc); + + cEntries -= 1; + break; + } + } + } + + Assert(m_idxRoot == a_pAllocator->kNilIndex); + return VINF_SUCCESS; + } + + + /** + * Gets the tree height value (reads cHeigh from the root node). + * + * @retval UINT8_MAX if bogus tree. + */ + uint8_t getHeight(RTCHardAvlTreeSlabAllocator *a_pAllocator) RT_NOEXCEPT + { + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, UINT8_MAX); + if (pNode) + return pNode->cHeight; + return 0; + } + +#ifdef RT_STRICT + + static void dumpStack(RTCHardAvlTreeSlabAllocator *a_pAllocator, HardAvlStack const *pStack) RT_NOEXCEPT + { + uint32_t const * const *paidx = pStack->apidxEntries; + RTAssertMsg2("stack: %u:\n", pStack->cEntries); + for (unsigned i = 0; i < pStack->cEntries; i++) + { + uint32_t idx = *paidx[i]; + uint32_t idxNext = i + 1 < pStack->cEntries ? *paidx[i + 1] : UINT32_MAX; + NodeType const *pNode = a_pAllocator->ptrFromInt(idx); + RTAssertMsg2(" #%02u: %p[%#06x] pNode=%p h=%02d l=%#06x%c r=%#06x%c\n", i, paidx[i], idx, pNode, pNode->cHeight, + pNode->idxLeft, pNode->idxLeft == idxNext ? '*' : ' ', + pNode->idxRight, pNode->idxRight == idxNext ? '*' : ' '); + } + } + + static void printTree(RTCHardAvlTreeSlabAllocator *a_pAllocator, uint32_t a_idxRoot, + unsigned a_uLevel = 0, unsigned a_uMaxLevel = 8, const char *a_pszDir = "") RT_NOEXCEPT + { + if (a_idxRoot == a_pAllocator->kNilIndex) + RTAssertMsg2("%*snil\n", a_uLevel * 6, a_pszDir); + else if (a_uLevel < a_uMaxLevel) + { + NodeType *pNode = a_pAllocator->ptrFromInt(a_idxRoot); + printTree(a_pAllocator, readIdx(&pNode->idxRight), a_uLevel + 1, a_uMaxLevel, "/ "); + RTAssertMsg2("%*s%#x/%u\n", a_uLevel * 6, a_pszDir, a_idxRoot, pNode->cHeight); + printTree(a_pAllocator, readIdx(&pNode->idxLeft), a_uLevel + 1, a_uMaxLevel, "\\ "); + } + else + RTAssertMsg2("%*stoo deep\n", a_uLevel * 6, a_pszDir); + } + +#endif + +private: + /** + * Rewinds a stack of pointers to pointers to nodes, rebalancing the tree. + * + * @returns IPRT status code. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pStack Pointer to stack to rewind. + * @param a_fLog Log is done (DEBUG builds only). + * + * @code + * LOOP thru all stack entries + * BEGIN + * Get pointer to pointer to node (and pointer to node) from the stack. + * IF 2 higher left subtree than in right subtree THEN + * BEGIN + * IF higher (or equal) left-sub-subtree than right-sub-subtree THEN + * * n+2|n+3 + * / \ / \ + * n+2 n ==> n+1 n+1|n+2 + * / \ / \ + * n+1 n|n+1 n|n+1 n + * + * Or with keys: + * + * 4 2 + * / \ / \ + * 2 5 ==> 1 4 + * / \ / \ + * 1 3 3 5 + * + * ELSE + * * n+2 + * / \ / \ + * n+2 n n+1 n+1 + * / \ ==> / \ / \ + * n n+1 n L R n + * / \ + * L R + * + * Or with keys: + * 6 4 + * / \ / \ + * 2 7 ==> 2 6 + * / \ / \ / \ + * 1 4 1 3 5 7 + * / \ + * 3 5 + * END + * ELSE IF 2 higher in right subtree than in left subtree THEN + * BEGIN + * Same as above but left <==> right. (invert the picture) + * ELSE + * IF correct height THEN break + * ELSE correct height. + * END + * @endcode + * @internal + */ + int i_rebalance(RTCHardAvlTreeSlabAllocator *a_pAllocator, HardAvlStack *a_pStack, bool a_fLog = false) RT_NOEXCEPT + { + RT_NOREF(a_fLog); + + while (a_pStack->cEntries > 0) + { + /* pop */ + uint32_t * const pidxNode = a_pStack->apidxEntries[--a_pStack->cEntries]; + uint32_t const idxNode = readIdx(pidxNode); + NodeType * const pNode = a_pAllocator->ptrFromInt(idxNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), + ("pidxNode=%p[%#x] pNode=%p\n", pidxNode, *pidxNode, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + + /* Read node properties: */ + uint32_t const idxLeftNode = readIdx(&pNode->idxLeft); + NodeType * const pLeftNode = a_pAllocator->ptrFromInt(idxLeftNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), + ("idxLeftNode=%#x pLeftNode=%p\n", idxLeftNode, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + + uint32_t const idxRightNode = readIdx(&pNode->idxRight); + NodeType * const pRightNode = a_pAllocator->ptrFromInt(idxRightNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), + ("idxRight=%#x pRightNode=%p\n", idxRightNode, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + + uint8_t const cLeftHeight = pLeftNode ? pLeftNode->cHeight : 0; + AssertReturnStmt(cLeftHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_LEFT_HEIGHT); + + uint8_t const cRightHeight = pRightNode ? pRightNode->cHeight : 0; + AssertReturnStmt(cRightHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_RIGHT_HEIGHT); + + /* Decide what needs doing: */ + if (cRightHeight + 1 < cLeftHeight) + { + Assert(cRightHeight + 2 == cLeftHeight); + AssertReturnStmt(pLeftNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_LEFT); + + uint32_t const idxLeftLeftNode = readIdx(&pLeftNode->idxLeft); + NodeType * const pLeftLeftNode = a_pAllocator->ptrFromInt(idxLeftLeftNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftLeftNode), + ("idxLeftLeftNode=%#x pLeftLeftNode=%p\n", idxLeftLeftNode, pLeftLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftLeftNode)); + + uint32_t const idxLeftRightNode = readIdx(&pLeftNode->idxRight); + NodeType * const pLeftRightNode = a_pAllocator->ptrFromInt(idxLeftRightNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftRightNode), + ("idxLeftRightNode=%#x pLeftRightNode=%p\n", idxLeftRightNode, pLeftRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftRightNode)); + + uint8_t const cLeftRightHeight = pLeftRightNode ? pLeftRightNode->cHeight : 0; + if ((pLeftLeftNode ? pLeftLeftNode->cHeight : 0) >= cLeftRightHeight) + { + AssertReturnStmt(cLeftRightHeight + 2 <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_NEW_HEIGHT); + pNode->idxLeft = idxLeftRightNode; + pNode->cHeight = (uint8_t)(cLeftRightHeight + 1); + pLeftNode->cHeight = (uint8_t)(cLeftRightHeight + 2); + pLeftNode->idxRight = idxNode; + *pidxNode = idxLeftNode; +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #1\n", a_pStack->cEntries); +#endif + } + else + { + AssertReturnStmt(cLeftRightHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_RIGHT_HEIGHT); + AssertReturnStmt(pLeftRightNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_RIGHT); + + uint32_t const idxLeftRightLeftNode = readIdx(&pLeftRightNode->idxLeft); + AssertReturnStmt(a_pAllocator->isIntValid(idxLeftRightLeftNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + uint32_t const idxLeftRightRightNode = readIdx(&pLeftRightNode->idxRight); + AssertReturnStmt(a_pAllocator->isIntValid(idxLeftRightRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + pLeftNode->idxRight = idxLeftRightLeftNode; + pNode->idxLeft = idxLeftRightRightNode; + + pLeftRightNode->idxLeft = idxLeftNode; + pLeftRightNode->idxRight = idxNode; + pLeftNode->cHeight = cLeftRightHeight; + pNode->cHeight = cLeftRightHeight; + pLeftRightNode->cHeight = cLeftHeight; + *pidxNode = idxLeftRightNode; +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #2\n", a_pStack->cEntries); +#endif + } + m_cRebalancingOperations++; + } + else if (cLeftHeight + 1 < cRightHeight) + { + Assert(cLeftHeight + 2 == cRightHeight); + AssertReturnStmt(pRightNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_RIGHT); + + uint32_t const idxRightLeftNode = readIdx(&pRightNode->idxLeft); + NodeType * const pRightLeftNode = a_pAllocator->ptrFromInt(idxRightLeftNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightLeftNode), + ("idxRightLeftNode=%#x pRightLeftNode=%p\n", idxRightLeftNode, pRightLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightLeftNode)); + + uint32_t const idxRightRightNode = readIdx(&pRightNode->idxRight); + NodeType * const pRightRightNode = a_pAllocator->ptrFromInt(idxRightRightNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightRightNode), + ("idxRightRightNode=%#x pRightRightNode=%p\n", idxRightRightNode, pRightRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightRightNode)); + + uint8_t const cRightLeftHeight = pRightLeftNode ? pRightLeftNode->cHeight : 0; + if ((pRightRightNode ? pRightRightNode->cHeight : 0) >= cRightLeftHeight) + { + AssertReturnStmt(cRightLeftHeight + 2 <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_NEW_HEIGHT); + + pNode->idxRight = idxRightLeftNode; + pRightNode->idxLeft = idxNode; + pNode->cHeight = (uint8_t)(cRightLeftHeight + 1); + pRightNode->cHeight = (uint8_t)(cRightLeftHeight + 2); + *pidxNode = idxRightNode; +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #3 h=%d, *pidxNode=%#x\n", a_pStack->cEntries, pRightNode->cHeight, *pidxNode); +#endif + RTHARDAVL_STRICT_CHECK_HEIGHTS(pRightNode, NULL, 0); + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); + } + else + { + AssertReturnStmt(cRightLeftHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_LEFT_HEIGHT); + AssertReturnStmt(pRightLeftNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_LEFT); + + uint32_t const idxRightLeftRightNode = readIdx(&pRightLeftNode->idxRight); + AssertReturnStmt(a_pAllocator->isIntValid(idxRightLeftRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + uint32_t const idxRightLeftLeftNode = readIdx(&pRightLeftNode->idxLeft); + AssertReturnStmt(a_pAllocator->isIntValid(idxRightLeftLeftNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + pRightNode->idxLeft = idxRightLeftRightNode; + pNode->idxRight = idxRightLeftLeftNode; + + pRightLeftNode->idxRight = idxRightNode; + pRightLeftNode->idxLeft = idxNode; + pRightNode->cHeight = cRightLeftHeight; + pNode->cHeight = cRightLeftHeight; + pRightLeftNode->cHeight = cRightHeight; + *pidxNode = idxRightLeftNode; +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #4 h=%d, *pidxNode=%#x\n", a_pStack->cEntries, pRightLeftNode->cHeight, *pidxNode); +#endif + } + m_cRebalancingOperations++; + } + else + { + uint8_t const cHeight = (uint8_t)(RT_MAX(cLeftHeight, cRightHeight) + 1); + AssertReturnStmt(cHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_NEW_HEIGHT); + if (cHeight == pNode->cHeight) + { +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #5, h=%d - done\n", a_pStack->cEntries, cHeight); +#endif + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); + if (pLeftNode) + RTHARDAVL_STRICT_CHECK_HEIGHTS(pLeftNode, NULL, 0); + if (pRightNode) + RTHARDAVL_STRICT_CHECK_HEIGHTS(pRightNode, NULL, 0); + break; + } +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #5, h=%d - \n", a_pStack->cEntries, cHeight); +#endif + pNode->cHeight = cHeight; + } + } + return VINF_SUCCESS; + } +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_hardavlrange_h */ + diff --git a/include/iprt/cpp/hardavlslaballocator.h b/include/iprt/cpp/hardavlslaballocator.h new file mode 100644 index 00000000..515782b5 --- /dev/null +++ b/include/iprt/cpp/hardavlslaballocator.h @@ -0,0 +1,218 @@ +/** @file + * IPRT - Hardened AVL tree slab allocator. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_hardavlslaballocator_h +#define IPRT_INCLUDED_cpp_hardavlslaballocator_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +/** @addtogroup grp_rt_cpp_hardavl + * @{ + */ + + +/** + * Slab allocator for the hardened AVL tree. + */ +template +struct RTCHardAvlTreeSlabAllocator +{ + /** Pointer to an array of nodes. */ + NodeType *m_paNodes; + /** Node allocation bitmap: 1 = free, 0 = allocated. */ + uint64_t *m_pbmAlloc; + /** Max number of nodes in m_paNodes and valid bits in m_pbmAlloc. */ + uint32_t m_cNodes; + /** Pointer error counter. */ + uint32_t m_cErrors; + /** Allocation hint. */ + uint32_t m_idxAllocHint; + uint32_t m_uPadding; + + enum + { + kNilIndex = 0, + kErr_IndexOutOfBound = -1, + kErr_PointerOutOfBound = -2, + kErr_MisalignedPointer = -3, + kErr_NodeIsFree = -4, + kErr_Last = kErr_NodeIsFree + }; + + RTCHardAvlTreeSlabAllocator() RT_NOEXCEPT + : m_paNodes(NULL) + , m_pbmAlloc(NULL) + , m_cNodes(0) + , m_cErrors(0) + , m_idxAllocHint(0) + , m_uPadding(0) + {} + + inline void initSlabAllocator(uint32_t a_cNodes, NodeType *a_paNodes, uint64_t *a_pbmAlloc) RT_NOEXCEPT + { + m_cNodes = a_cNodes; + m_paNodes = a_paNodes; + m_pbmAlloc = a_pbmAlloc; + + /* Initialize the allocation bit. */ + RT_BZERO(a_pbmAlloc, (a_cNodes + 63) / 64 * 8); + ASMBitSetRange(a_pbmAlloc, 0, a_cNodes); + } + + inline NodeType *ptrFromInt(uint32_t a_idxNode1) RT_NOEXCEPT + { + if (a_idxNode1 == (uint32_t)kNilIndex) + return NULL; + AssertMsgReturnStmt(a_idxNode1 <= m_cNodes, ("a_idxNode1=%#x m_cNodes=%#x\n", a_idxNode1, m_cNodes), + m_cErrors++, (NodeType *)(intptr_t)kErr_IndexOutOfBound); + AssertMsgReturnStmt(ASMBitTest(m_pbmAlloc, a_idxNode1 - 1) == false, ("a_idxNode1=%#x\n", a_idxNode1), + m_cErrors++, (NodeType *)(intptr_t)kErr_NodeIsFree); + return &m_paNodes[a_idxNode1 - 1]; + } + + static inline bool isPtrRetOkay(NodeType *a_pNode) RT_NOEXCEPT + { + return (uintptr_t)a_pNode < (uintptr_t)kErr_Last; + } + + static inline int ptrErrToStatus(NodeType *a_pNode) RT_NOEXCEPT + { + return (int)(intptr_t)a_pNode - (VERR_HARDAVL_INDEX_OUT_OF_BOUNDS - kErr_IndexOutOfBound); + } + + inline uint32_t ptrToInt(NodeType *a_pNode) RT_NOEXCEPT + { + if (a_pNode == NULL) + return 0; + uintptr_t const offNode = (uintptr_t)a_pNode - (uintptr_t)m_paNodes; + uintptr_t const idxNode0 = offNode / sizeof(m_paNodes[0]); + AssertMsgReturnStmt((offNode % sizeof(m_paNodes[0])) == 0, + ("pNode=%p / offNode=%#zx vs m_paNodes=%p L %#x, each %#x bytes\n", + a_pNode, offNode, m_paNodes, m_cNodes, sizeof(m_paNodes[0])), + m_cErrors++, (uint32_t)kErr_MisalignedPointer); + AssertMsgReturnStmt(idxNode0 < m_cNodes, + ("pNode=%p vs m_paNodes=%p L %#x\n", a_pNode, m_paNodes, m_cNodes), + m_cErrors++, (uint32_t)kErr_PointerOutOfBound); + AssertMsgReturnStmt(ASMBitTest(m_pbmAlloc, idxNode0) == false, ("a_pNode=%p idxNode0=%#x\n", a_pNode, idxNode0), + m_cErrors++, (uint32_t)kErr_NodeIsFree); + return idxNode0 + 1; + } + + static inline bool isIdxRetOkay(uint32_t a_idxNode) RT_NOEXCEPT + { + return a_idxNode < (uint32_t)kErr_Last; + } + + static inline int idxErrToStatus(uint32_t a_idxNode) RT_NOEXCEPT + { + return (int)a_idxNode - (VERR_HARDAVL_INDEX_OUT_OF_BOUNDS - kErr_IndexOutOfBound); + } + + inline bool isIntValid(uint32_t a_idxNode1) RT_NOEXCEPT + { + return a_idxNode1 <= m_cNodes; + } + + inline int freeNode(NodeType *a_pNode) RT_NOEXCEPT + { + uint32_t idxNode1 = ptrToInt(a_pNode); + if (idxNode1 == (uint32_t)kNilIndex) + return 0; + if (idxNode1 < (uint32_t)kErr_Last) + { + AssertMsgReturnStmt(ASMAtomicBitTestAndSet(m_pbmAlloc, idxNode1 - 1) == false, + ("a_pNode=%p idxNode1=%#x\n", a_pNode, idxNode1), + m_cErrors++, kErr_NodeIsFree); + return 0; + } + return (int)idxNode1; + } + + inline NodeType *allocateNode(void) RT_NOEXCEPT + { + /* + * Use the hint first, then scan the whole bitmap. + * Note! We don't expect concurrent allocation calls, so no need to repeat. + */ + uint32_t const idxHint = m_idxAllocHint; + uint32_t idxNode0; + if ( idxHint >= m_cNodes + || (int32_t)(idxNode0 = (uint32_t)ASMBitNextSet(m_pbmAlloc, m_cNodes, idxHint)) < 0) + idxNode0 = (uint32_t)ASMBitFirstSet(m_pbmAlloc, m_cNodes); + if ((int32_t)idxNode0 >= 0) + { + if (ASMAtomicBitTestAndClear(m_pbmAlloc, idxNode0) == true) + { + m_idxAllocHint = idxNode0; + return &m_paNodes[idxNode0]; + } + AssertMsgFailed(("idxNode0=%#x\n", idxNode0)); + m_cErrors++; + } + return NULL; + } +}; + + +/** + * Placeholder structure for ring-3 slab allocator. + */ +typedef struct RTCHardAvlTreeSlabAllocatorR3_T +{ + /** Pointer to an array of nodes. */ + RTR3PTR m_paNodes; + /** Node allocation bitmap: 1 = free, 0 = allocated. */ + RTR3PTR m_pbmAlloc; + /** Max number of nodes in m_paNodes and valid bits in m_pbmAlloc. */ + uint32_t m_cNodes; + /** Pointer error counter. */ + uint32_t m_cErrors; + /** Allocation hint. */ + uint32_t m_idxAllocHint; + uint32_t m_uPadding; +} RTCHardAvlTreeSlabAllocatorR3_T; +AssertCompileSize(RTCHardAvlTreeSlabAllocatorR3_T, + sizeof(RTCHardAvlTreeSlabAllocator) - (sizeof(void *) - sizeof(RTR3PTR)) * 2); + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_hardavlslaballocator_h */ + diff --git a/include/iprt/cpp/list.h b/include/iprt/cpp/list.h new file mode 100644 index 00000000..864c3329 --- /dev/null +++ b/include/iprt/cpp/list.h @@ -0,0 +1,1143 @@ +/** @file + * IPRT - Generic List Class. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_list_h +#define IPRT_INCLUDED_cpp_list_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include /* for memcpy */ +#include + +#include /* For std::bad_alloc */ + +/** @defgroup grp_rt_cpp_list C++ List support + * @ingroup grp_rt_cpp + * + * @brief Generic C++ list class support. + * + * This list classes manage any amount of data in a fast and easy to use way. + * They have no dependencies on STL, only on generic memory management methods + * of IRPT. This allows list handling in situations where the use of STL + * container classes is forbidden. + * + * Not all of the functionality of STL container classes is implemented. There + * are no iterators or any other high level access/modifier methods (e.g. + * std::algorithms). + * + * The implementation is array based which allows fast access to the items. + * Appending items is usually also fast, cause the internal array is + * preallocated. To minimize the memory overhead, native types (that is + * everything smaller then the size of void*) are directly saved in the array. + * If bigger types are used (e.g. RTCString) the internal array is an array of + * pointers to the objects. + * + * The size of the internal array will usually not shrink, but grow + * automatically. Only certain methods, like RTCList::clear or the "=" operator + * will reset any previously allocated memory. You can call + * RTCList::setCapacity for manual adjustment. If the size of an new list will + * be known, calling the constructor with the necessary capacity will speed up + * the insertion of the new items. + * + * For the full public interface these list classes offer see RTCListBase. + * + * There are some requirements for the types used which follow: + * -# They need a default and a copy constructor. + * -# Some methods (e.g. RTCList::contains) need an equal operator. + * -# If the type is some complex class (that is, having a constructor which + * allocates members on the heap) it has to be greater than sizeof(void*) to + * be used correctly. If this is not the case you can manually overwrite the + * list behavior. Just add T* as a second parameter to the list template if + * your class is called T. Another possibility is to specialize the list for + * your target class. See below for more information. + * + * The native types like int, bool, ptr, ..., are meeting this criteria, so + * they are save to use. + * + * Please note that the return type of some of the getter methods are slightly + * different depending on the list type. Native types return the item by value, + * items with a size greater than sizeof(void*) by reference. As native types + * saved directly in the internal array, returning a reference to them (and + * saving them in a reference as well) would make them invalid (or pointing to + * a wrong item) when the list is changed in the meanwhile. Returning a + * reference for bigger types isn't problematic and makes sure we get out the + * best speed of the list. The one exception to this rule is the index + * operator[]. This operator always return a reference to make it possible to + * use it as a lvalue. Its your responsibility to make sure the list isn't + * changed when using the value as reference returned by this operator. + * + * The list class is reentrant. For a thread-safe variant see RTCMTList. + * + * Implementation details: + * It is possible to specialize any type. This might be necessary to get the + * best speed out of the list. Examples are the 64-bit types, which use the + * native (no pointers) implementation even on a 32-bit host. Consult the + * source code for more details. + * + * Current specialized implementations: + * - int64_t: RTCList + * - uint64_t: RTCList + * + * @{ + */ + +/** + * The guard definition. + */ +template +class RTCListGuard; + +/** + * The default guard which does nothing. + */ +template <> +class RTCListGuard +{ +public: + inline void enterRead() const {} + inline void leaveRead() const {} + inline void enterWrite() {} + inline void leaveWrite() {} + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif +}; + +/** + * General helper template for managing native values in RTCListBase. + */ +template +class RTCListHelper +{ +public: + static inline void set(T2 *p, size_t i, const T1 &v) { p[i] = v; } + static inline T1 & at(T2 *p, size_t i) { return p[i]; } + static inline const T1 &atConst(T2 const *p, size_t i) { return p[i]; } + static inline size_t find(T2 *p, const T1 &v, size_t cElements) + { + size_t i = cElements; + while (i-- > 0) + if (p[i] == v) + return i; + return cElements; + } + static inline void copyTo(T2 *p, T2 *const p1 , size_t iTo, size_t cSize) + { + if (cSize > 0) + memcpy(&p[iTo], &p1[0], sizeof(T1) * cSize); + } + static inline void erase(T2 * /* p */, size_t /* i */) { /* Nothing to do here. */ } + static inline void eraseRange(T2 * /* p */, size_t /* cFrom */, size_t /* cSize */) { /* Nothing to do here. */ } +}; + +/** + * Specialized helper template for managing pointer values in RTCListBase. + */ +template +class RTCListHelper +{ +public: + static inline void set(T1 **p, size_t i, const T1 &v) { p[i] = new T1(v); } + static inline T1 & at(T1 **p, size_t i) { return *p[i]; } + static inline const T1 &atConst(T1 * const *p, size_t i) { return *p[i]; } + static inline size_t find(T1 **p, const T1 &v, size_t cElements) + { + size_t i = cElements; + while (i-- > 0) + if (*p[i] == v) + return i; + return cElements; + } + static inline void copyTo(T1 **p, T1 **const p1 , size_t iTo, size_t cSize) + { + for (size_t i = 0; i < cSize; ++i) + p[iTo + i] = new T1(*p1[i]); + } + static inline void erase(T1 **p, size_t i) { delete p[i]; } + static inline void eraseRange(T1 **p, size_t iFrom, size_t cItems) + { + while (cItems-- > 0) + delete p[iFrom++]; + } +}; + +/** + * This is the base class for all other list classes. It implements the + * necessary list functionality in a type independent way and offers the public + * list interface to the user. + */ +template +class RTCListBase +{ + /** @name Traits. + * + * Defines the return type of most of the getter methods. If the internal + * used type is a pointer, we return a reference. If not we return by + * value. + * + * @{ + */ + typedef typename RTCIfPtr::result GET_RTYPE; + typedef typename RTCIfPtr::result GET_CRTYPE; + /** @} */ + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCListBase(size_t cCapacity = kDefaultCapacity) + : m_pArray(0) + , m_cElements(0) + , m_cCapacity(0) + { + if (cCapacity > 0) + growArray(cCapacity); + } + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCListBase(const RTCListBase& other) + : m_pArray(0) + , m_cElements(0) + , m_cCapacity(0) + { + other.m_guard.enterRead(); + + size_t const cElementsOther = other.m_cElements; + resizeArrayNoErase(cElementsOther); + RTCListHelper::copyTo(m_pArray, other.m_pArray, 0, cElementsOther); + m_cElements = cElementsOther; + + other.m_guard.leaveRead(); + } + + /** + * Destructor. + */ + ~RTCListBase() + { + RTCListHelper::eraseRange(m_pArray, 0, m_cElements); + if (m_pArray) + { + RTMemFree(m_pArray); + m_pArray = NULL; + } + m_cElements = m_cCapacity = 0; + } + + /** + * Sets a new capacity within the list. + * + * If the new capacity is bigger than the old size, it will be simply + * preallocated more space for the new items. If the new capacity is + * smaller than the previous size, items at the end of the list will be + * deleted. + * + * @param cCapacity The new capacity within the list. + * @throws std::bad_alloc + */ + void setCapacity(size_t cCapacity) + { + m_guard.enterWrite(); + resizeArray(cCapacity); + m_guard.leaveWrite(); + } + + /** + * Return the current capacity of the list. + * + * @return The actual capacity. + */ + size_t capacity() const + { + m_guard.enterRead(); + size_t cRet = m_cCapacity; + m_guard.leaveRead(); + return cRet; + } + + /** + * Check if an list contains any items. + * + * @return True if there is more than zero items, false otherwise. + */ + bool isEmpty() const + { + m_guard.enterRead(); + bool fEmpty = m_cElements == 0; + m_guard.leaveRead(); + return fEmpty; + } + + /** + * Return the current count of elements within the list. + * + * @return The current element count. + */ + size_t size() const + { + m_guard.enterRead(); + size_t cRet = m_cElements; + m_guard.leaveRead(); + return cRet; + } + + /** + * Inserts an item to the list at position @a i. + * + * @param i The position of the new item. The must be within or at the + * exact end of the list. Indexes specified beyond the end of + * the list will be changed to an append() operation and strict + * builds will raise an assert. + * @param val The new item. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase &insert(size_t i, const T &val) + { + m_guard.enterWrite(); + + AssertMsgStmt(i <= m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements); + + if (m_cElements == m_cCapacity) + growArray(m_cCapacity + kDefaultCapacity); + + memmove(&m_pArray[i + 1], &m_pArray[i], (m_cElements - i) * sizeof(ITYPE)); + RTCListHelper::set(m_pArray, i, val); + ++m_cElements; + + m_guard.leaveWrite(); + return *this; + } + + /** + * Inserts a list to the list at position @a i. + * + * @param i The position of the new item. The must be within or at the + * exact end of the list. Indexes specified beyond the end of + * the list will be changed to an append() operation and strict + * builds will raise an assert. + * @param other The other list. This MUST not be the same as the destination + * list, will assert and return without doing anything if this + * happens. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase &insert(size_t i, const RTCListBase &other) + { + AssertReturn(this != &other, *this); + + other.m_guard.enterRead(); + m_guard.enterWrite(); + + AssertMsgStmt(i <= m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements); + + size_t cElementsOther = other.m_cElements; + if (RT_LIKELY(cElementsOther > 0)) + { + if (m_cCapacity - m_cElements < cElementsOther) + growArray(m_cCapacity + (cElementsOther - (m_cCapacity - m_cElements))); + if (i < m_cElements) + memmove(&m_pArray[i + cElementsOther], &m_pArray[i], (m_cElements - i) * sizeof(ITYPE)); + + RTCListHelper::copyTo(&m_pArray[i], other.m_pArray, 0, cElementsOther); + m_cElements += cElementsOther; + } + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); + return *this; + } + + /** + * Prepend an item to the list. + * + * @param val The new item. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase &prepend(const T &val) + { + return insert(0, val); + } + + /** + * Prepend a list of type T to the list. + * + * @param other The list to prepend. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase &prepend(const RTCListBase &other) + { + return insert(0, other); + } + + /** + * Append a default item to the list. + * + * @return a mutable reference to the item + * @throws std::bad_alloc + */ + GET_RTYPE append() + { + m_guard.enterWrite(); + if (m_cElements == m_cCapacity) + growArray(m_cCapacity + kDefaultCapacity); + RTCListHelper::set(m_pArray, m_cElements, T()); + GET_RTYPE rRet = RTCListHelper::at(m_pArray, m_cElements); + ++m_cElements; + m_guard.leaveWrite(); + + return rRet; + } + + /** + * Append an item to the list. + * + * @param val The new item. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase &append(const T &val) + { + m_guard.enterWrite(); + if (m_cElements == m_cCapacity) + growArray(m_cCapacity + kDefaultCapacity); + RTCListHelper::set(m_pArray, m_cElements, val); + ++m_cElements; + m_guard.leaveWrite(); + + return *this; + } + + /** + * Append a list of type T to the list. + * + * @param other The list to append. Must not be the same as the destination + * list, will assert and return without doing anything. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase &append(const RTCListBase &other) + { + AssertReturn(this != &other, *this); + + other.m_guard.enterRead(); + m_guard.enterWrite(); + + insert(m_cElements, other); + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); + return *this; + } + + /** + * Copy the items of the other list into this list. + * + * All previous items of this list are deleted. + * + * @param other The list to copy. + * @return a reference to this list. + */ + RTCListBase &operator=(const RTCListBase& other) + { + /* Prevent self assignment */ + if (RT_LIKELY(this != &other)) + { + other.m_guard.enterRead(); + m_guard.enterWrite(); + + /* Delete all items. */ + RTCListHelper::eraseRange(m_pArray, 0, m_cElements); + + /* Need we to realloc memory. */ + if (other.m_cElements != m_cCapacity) + resizeArrayNoErase(other.m_cElements); + m_cElements = other.m_cElements; + + /* Copy new items. */ + RTCListHelper::copyTo(m_pArray, other.m_pArray, 0, other.m_cElements); + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); + } + return *this; + } + + /** + * Compares if this list's items match the other list. + * + * @returns \c true if both lists contain the same items, \c false if not. + * @param other The list to compare this list with. + */ + bool operator==(const RTCListBase& other) + { + /* Prevent self comparrison */ + if (RT_LIKELY(this == &other)) + return true; + + other.m_guard.enterRead(); + m_guard.enterRead(); + + bool fEqual = true; + if (other.m_cElements == m_cElements) + { + for (size_t i = 0; i < m_cElements; i++) + { + if (RTCListHelper::at(m_pArray, i) != RTCListHelper::at(other.m_pArray, i)) + { + fEqual = false; + break; + } + } + } + else + fEqual = false; + + m_guard.leaveRead(); + other.m_guard.leaveRead(); + + return fEqual; + } + + /** + * Compares if this list's items do not match the other list. + * + * @returns \c true if the lists do not match, \c false if otherwise. + * @param other The list to compare this list with. + */ + bool operator!=(const RTCListBase& other) + { + return !(*this == other); + } + + /** + * Replace an item in the list. + * + * @param i The position of the item to replace. If this is out of range, + * the request will be ignored, strict builds will assert. + * @param val The new value. + * @return a reference to this list. + */ + RTCListBase &replace(size_t i, const T &val) + { + m_guard.enterWrite(); + + if (i < m_cElements) + { + RTCListHelper::erase(m_pArray, i); + RTCListHelper::set(m_pArray, i, val); + } + else + AssertMsgFailed(("i=%zu m_cElements=%zu\n", i, m_cElements)); + + m_guard.leaveWrite(); + return *this; + } + + /** + * Applies a filter of type T to this list. + * + * @param other The list which contains the elements to filter out from this list. + * @return a reference to this list. + */ + RTCListBase &filter(const RTCListBase &other) + { + AssertReturn(this != &other, *this); + + other.m_guard.enterRead(); + m_guard.enterWrite(); + + for (size_t i = 0; i < m_cElements; i++) + { + for (size_t f = 0; f < other.m_cElements; f++) + { + if (RTCListHelper::at(m_pArray, i) == RTCListHelper::at(other.m_pArray, f)) + removeAtLocked(i); + } + } + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); + return *this; + } + + /** + * Return the first item as constant object. + * + * @return A reference or pointer to the first item. + * + * @note No boundary checks are done. Make sure there is at least one + * element. + */ + GET_CRTYPE first() const + { + m_guard.enterRead(); + Assert(m_cElements > 0); + GET_CRTYPE res = RTCListHelper::at(m_pArray, 0); + m_guard.leaveRead(); + return res; + } + + /** + * Return the first item. + * + * @return A reference or pointer to the first item. + * + * @note No boundary checks are done. Make sure there is at least one + * element. + */ + GET_RTYPE first() + { + m_guard.enterRead(); + Assert(m_cElements > 0); + GET_RTYPE res = RTCListHelper::at(m_pArray, 0); + m_guard.leaveRead(); + return res; + } + + /** + * Return the last item as constant object. + * + * @return A reference or pointer to the last item. + * + * @note No boundary checks are done. Make sure there is at least one + * element. + */ + GET_CRTYPE last() const + { + m_guard.enterRead(); + Assert(m_cElements > 0); + GET_CRTYPE res = RTCListHelper::at(m_pArray, m_cElements - 1); + m_guard.leaveRead(); + return res; + } + + /** + * Return the last item. + * + * @return A reference or pointer to the last item. + * + * @note No boundary checks are done. Make sure there is at least one + * element. + */ + GET_RTYPE last() + { + m_guard.enterRead(); + Assert(m_cElements > 0); + GET_RTYPE res = RTCListHelper::at(m_pArray, m_cElements - 1); + m_guard.leaveRead(); + return res; + } + + /** + * Return the item at position @a i as constant object. + * + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. + * @return The item at position @a i. + */ + GET_CRTYPE at(size_t i) const + { + m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); + GET_CRTYPE res = RTCListHelper::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + + /** + * Return the item at position @a i. + * + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. + * @return The item at position @a i. + */ + GET_RTYPE at(size_t i) + { + m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); + GET_RTYPE res = RTCListHelper::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + + /** + * Return the item at position @a i as mutable reference. + * + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. + * @return The item at position @a i. + */ + T &operator[](size_t i) + { + m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); + T &res = RTCListHelper::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + + /** + * Return the item at position @a i as immutable reference. + * + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. + * @return The item at position @a i. + */ + const T &operator[](size_t i) const + { + m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); + const T &rRet = RTCListHelper::atConst(m_pArray, i); + m_guard.leaveRead(); + return rRet; + } + + /** + * Return a copy of the item at position @a i or default value if out of range. + * + * @param i The position of the item to return. + * @return Copy of the item at position @a i or default value. + */ + T value(size_t i) const + { + m_guard.enterRead(); + if (RT_LIKELY(i < m_cElements)) + { + T res = RTCListHelper::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + m_guard.leaveRead(); + return T(); + } + + /** + * Return a copy of the item at position @a i, or @a defaultVal if out of range. + * + * @param i The position of the item to return. + * @param defaultVal The value to return in case @a i is invalid. + * @return Copy of the item at position @a i or @a defaultVal. + */ + T value(size_t i, const T &defaultVal) const + { + m_guard.enterRead(); + if (RT_LIKELY(i < m_cElements)) + { + T res = RTCListHelper::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + m_guard.leaveRead(); + return defaultVal; + } + + /** + * Check if @a val is contained in the array. + * + * @param val The value to check for. + * @return true if it is found, false otherwise. + */ + bool contains(const T &val) const + { + m_guard.enterRead(); + bool fRc = RTCListHelper::find(m_pArray, val, m_cElements) < m_cElements; + m_guard.leaveRead(); + return fRc; + } + + /** + * Remove the first item. + * + * @note You should make sure the list isn't empty. Strict builds will assert. + * The other builds will quietly ignore the request. + */ + void removeFirst() + { + removeAt(0); + } + + /** + * Remove the last item. + * + * @note You should make sure the list isn't empty. Strict builds will assert. + * The other builds will quietly ignore the request. + */ + void removeLast() + { + m_guard.enterWrite(); + removeAtLocked(m_cElements - 1); + m_guard.leaveWrite(); + } + + /** + * Remove the item at position @a i. + * + * @param i The position of the item to remove. Out of bounds values will + * be ignored and an assertion will be raised in strict builds. + */ + void removeAt(size_t i) + { + m_guard.enterWrite(); + removeAtLocked(i); + m_guard.leaveWrite(); + } + + /** + * Remove a range of items from the list. + * + * @param iStart The start position of the items to remove. + * @param iEnd The end position of the items to remove (excluded). + */ + void removeRange(size_t iStart, size_t iEnd) + { + AssertReturnVoid(iStart <= iEnd); + m_guard.enterWrite(); + + AssertMsgStmt(iEnd <= m_cElements, ("iEnd=%zu m_cElements=%zu\n", iEnd, m_cElements), iEnd = m_cElements); + AssertMsgStmt(iStart < m_cElements, ("iStart=%zu m_cElements=%zu\n", iStart, m_cElements), iStart = m_cElements); + size_t const cElements = iEnd - iStart; + if (cElements > 0) + { + Assert(iStart < m_cElements); + RTCListHelper::eraseRange(m_pArray, iStart, cElements); + if (m_cElements > iEnd) + memmove(&m_pArray[iStart], &m_pArray[iEnd], (m_cElements - iEnd) * sizeof(ITYPE)); + m_cElements -= cElements; + } + + m_guard.leaveWrite(); + } + + /** + * Delete all items in the list. + */ + void clear() + { + m_guard.enterWrite(); + + /* Values cleanup */ + RTCListHelper::eraseRange(m_pArray, 0, m_cElements); + if (m_cElements != kDefaultCapacity) + resizeArrayNoErase(kDefaultCapacity); + m_cElements = 0; + + m_guard.leaveWrite(); + } + + /** + * Return the raw array. + * + * For native types this is a pointer to continuous memory of the items. For + * pointer types this is a continuous memory of pointers to the items. + * + * @warning If you change anything in the underlaying list, this memory + * will very likely become invalid. So take care when using this + * method and better try to avoid using it. + * + * @returns the raw memory. + */ + ITYPE *raw() const + { + m_guard.enterRead(); + ITYPE *pRet = m_pArray; + m_guard.leaveRead(); + return pRet; + } + + RTCListBase &operator<<(const T &val) + { + return append(val); + } + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif + + /** + * The default capacity of the list. This is also used as grow factor. + */ + static const size_t kDefaultCapacity; + +protected: + + /** + * Generic resizes the array, surplus elements are erased. + * + * @param cElementsNew The new array size. + * @throws std::bad_alloc. + */ + void resizeArray(size_t cElementsNew) + { + /* Same size? */ + if (cElementsNew == m_cCapacity) + return; + + /* If we get smaller we have to delete some of the objects at the end + of the list. */ + if ( cElementsNew < m_cElements + && m_pArray) + RTCListHelper::eraseRange(m_pArray, cElementsNew, m_cElements - cElementsNew); + + resizeArrayNoErase(cElementsNew); + } + + /** + * Resizes the array without doing the erase() thing on surplus elements. + * + * @param cElementsNew The new array size. + * @throws std::bad_alloc. + */ + void resizeArrayNoErase(size_t cElementsNew) + { + /* Same size? */ + if (cElementsNew == m_cCapacity) + return; + + /* Resize the array. */ + if (cElementsNew > 0) + { + void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew); + if (!pvNew) + { +#ifdef RT_EXCEPTIONS_ENABLED + throw std::bad_alloc(); +#endif + return; + } + m_pArray = static_cast(pvNew); + } + /* If we get zero we delete the array it self. */ + else if (m_pArray) + { + RTMemFree(m_pArray); + m_pArray = NULL; + } + + m_cCapacity = cElementsNew; + if (m_cElements > cElementsNew) + m_cElements = cElementsNew; + } + + /** + * Special realloc method which require that the array will grow. + * + * @param cElementsNew The new array size. + * @throws std::bad_alloc. + * @note No boundary checks are done! + */ + void growArray(size_t cElementsNew) + { + Assert(cElementsNew > m_cCapacity); + void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew); + if (pvNew) + { + m_cCapacity = cElementsNew; + m_pArray = static_cast(pvNew); + } + else + { +#ifdef RT_EXCEPTIONS_ENABLED + throw std::bad_alloc(); +#endif + } + } + + /** + * Remove the item at position @a i. + * + * @param i The position of the item to remove. Out of bounds values will + * be ignored and an assertion will be raised in strict builds. + * @remarks + */ + void removeAtLocked(size_t i) + { + AssertMsgReturnVoid(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements)); + + RTCListHelper::erase(m_pArray, i); + if (i < m_cElements - 1) + memmove(&m_pArray[i], &m_pArray[i + 1], (m_cElements - i - 1) * sizeof(ITYPE)); + --m_cElements; + } + + + /** The internal list array. */ + ITYPE *m_pArray; + /** The current count of items in use. */ + size_t m_cElements; + /** The current capacity of the internal array. */ + size_t m_cCapacity; + /** The guard used to serialize the access to the items. */ + RTCListGuard m_guard; +}; + +template +const size_t RTCListBase::kDefaultCapacity = 10; + +/** + * Template class which automatically determines the type of list to use. + * + * @see RTCListBase + */ +template sizeof(void*)), T*, T>::result> +class RTCList : public RTCListBase +{ + /* Traits */ + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + RTCList(const BASE &other) + : BASE(other) {} + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif +}; + +/** + * Specialized class for using the native type list for unsigned 64-bit + * values even on a 32-bit host. + * + * @see RTCListBase + */ +template <> +class RTCList: public RTCListBase +{ + /* Traits */ + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif +}; + +/** + * Specialized class for using the native type list for signed 64-bit + * values even on a 32-bit host. + * + * @see RTCListBase + */ +template <> +class RTCList: public RTCListBase +{ + /* Traits */ + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_list_h */ + diff --git a/include/iprt/cpp/lock.h b/include/iprt/cpp/lock.h new file mode 100644 index 00000000..3a0c4bcd --- /dev/null +++ b/include/iprt/cpp/lock.h @@ -0,0 +1,179 @@ +/** @file + * IPRT - Classes for Scope-based Locking. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_lock_h +#define IPRT_INCLUDED_cpp_lock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#ifdef RT_LOCK_STRICT +# include +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cpp_lock C++ Scope-based Locking + * @ingroup grp_rt_cpp + * @{ + */ + +class RTCLock; + +/** + * The mutex lock. + * + * This is used as an object data member if the intention is to lock + * a single object. This can also be used statically, initialized in + * a global variable, for class wide purposes. + * + * This is best used together with RTCLock. + */ +class RTCLockMtx +{ +friend class RTCLock; + +private: + RTCRITSECT mMtx; + +public: + RTCLockMtx() + { +#ifdef RT_LOCK_STRICT_ORDER + RTCritSectInitEx(&mMtx, 0 /*fFlags*/, + RTLockValidatorClassCreateUnique(RT_SRC_POS, NULL), + RTLOCKVAL_SUB_CLASS_NONE, NULL); +#else + RTCritSectInit(&mMtx); +#endif + } + + /** Use to when creating locks that belongs in the same "class". */ + RTCLockMtx(RT_SRC_POS_DECL, uint32_t uSubClass = RTLOCKVAL_SUB_CLASS_NONE) + { +#ifdef RT_LOCK_STRICT_ORDER + RTCritSectInitEx(&mMtx, 0 /*fFlags*/, + RTLockValidatorClassForSrcPos(RT_SRC_POS_ARGS, NULL), + uSubClass, NULL); +#else + NOREF(uSubClass); + RTCritSectInit(&mMtx); + RT_SRC_POS_NOREF(); +#endif + } + + ~RTCLockMtx() + { + RTCritSectDelete(&mMtx); + } + + /* lock() and unlock() are private so that only friend RTCLock can access + them. */ +private: + inline void lock() + { + RTCritSectEnter(&mMtx); + } + + inline void unlock() + { + RTCritSectLeave(&mMtx); + } +}; + + +/** + * The stack object for automatic locking and unlocking. + * + * This is a helper class for automatic locks, to simplify requesting a + * RTCLockMtx and to not forget releasing it. To request a RTCLockMtx, simply + * create an instance of RTCLock on the stack and pass the mutex to it: + * + * @code + extern RTCLockMtx gMtx; // wherever this is + ... + if (...) + { + RTCLock lock(gMtx); + ... // do stuff + // when lock goes out of scope, destructor releases the mutex + } + @endcode + * + * You can also explicitly release the mutex by calling RTCLock::release(). + * This might be helpful if the lock doesn't go out of scope early enough + * for your mutex to be released. + */ +class RTCLock +{ +private: + /** Reference to the lock we're holding. */ + RTCLockMtx &m_rMtx; + /** Whether we're currently holding the lock of if it was already + * explictily released by the release() method. */ + bool m_fLocked; + +public: + RTCLock(RTCLockMtx &a_rMtx) + : m_rMtx(a_rMtx) + { + m_rMtx.lock(); + m_fLocked = true; + } + + ~RTCLock() + { + if (m_fLocked) + m_rMtx.unlock(); + } + + inline void release() + { + if (m_fLocked) + { + m_rMtx.unlock(); + m_fLocked = false; + } + } +}; + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_cpp_lock_h */ + diff --git a/include/iprt/cpp/meta.h b/include/iprt/cpp/meta.h new file mode 100644 index 00000000..e6b9796e --- /dev/null +++ b/include/iprt/cpp/meta.h @@ -0,0 +1,125 @@ +/** @file + * IPRT - C++ Meta programming. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_meta_h +#define IPRT_INCLUDED_cpp_meta_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_cpp_meta C++ Meta programming utilities + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Check for a condition on compile time and dependent of the result TrueResult + * or FalseResult will be defined. + * + * @param Condition Condition to check. + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template +struct RTCIf; + +/** + * Check for a condition on compile time and dependent of the result TrueResult + * or FalseResult will be defined. + * + * True specialization of RTCIf. + * + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template +struct RTCIf +{ + typedef TrueResult result; +}; + +/** + * Check for a condition on compile time and dependent of the result TrueResult + * or FalseResult will be defined. + * + * False specialization of RTCIf. + * + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template +struct RTCIf +{ + typedef FalseResult result; +}; + +/** + * Check if @a T is a pointer or not at compile time and dependent of the + * result TrueResult or FalseResult will be defined. + * + * False version of RTCIfPtr. + * + * @param Condition Condition to check. + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template +struct RTCIfPtr +{ + typedef FalseResult result; +}; + +/** + * Check if @a T is a pointer or not at compile time and dependent of the + * result TrueResult or FalseResult will be defined. + * + * True specialization of RTCIfPtr. + * + * @param Condition Condition to check. + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template +struct RTCIfPtr +{ + typedef TrueResult result; +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_meta_h */ + diff --git a/include/iprt/cpp/ministring.h b/include/iprt/cpp/ministring.h new file mode 100644 index 00000000..80ad7cb5 --- /dev/null +++ b/include/iprt/cpp/ministring.h @@ -0,0 +1,1638 @@ +/** @file + * IPRT - C++ string class. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_ministring_h +#define IPRT_INCLUDED_cpp_ministring_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +#include + + +/** @defgroup grp_rt_cpp_string C++ String support + * @ingroup grp_rt_cpp + * @{ + */ + +/** @brief C++ string class. + * + * This is a C++ string class that does not depend on anything else except IPRT + * memory management functions. Semantics are like in std::string, except it + * can do a lot less. + * + * Note that RTCString does not differentiate between NULL strings + * and empty strings. In other words, RTCString("") and RTCString(NULL) + * behave the same. In both cases, RTCString allocates no memory, reports + * a zero length and zero allocated bytes for both, and returns an empty + * C-style string from c_str(). + * + * @note RTCString ASSUMES that all strings it deals with are valid UTF-8. + * The caller is responsible for not breaking this assumption. + */ +#ifdef VBOX + /** @remarks Much of the code in here used to be in com::Utf8Str so that + * com::Utf8Str can now derive from RTCString and only contain code + * that is COM-specific, such as com::Bstr conversions. Compared to + * the old Utf8Str though, RTCString always knows the length of its + * member string and the size of the buffer so it can use memcpy() + * instead of strdup(). + */ +#endif +class RT_DECL_CLASS RTCString +{ +public: +#if defined(RT_NEED_NEW_AND_DELETE) && ( !defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) \ + || defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF)) + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif + + /** + * Creates an empty string that has no memory allocated. + */ + RTCString() + : m_psz(NULL), + m_cch(0), + m_cbAllocated(0) + { + } + + /** + * Creates a copy of another RTCString. + * + * This allocates s.length() + 1 bytes for the new instance, unless s is empty. + * + * @param a_rSrc The source string. + * + * @throws std::bad_alloc + */ + RTCString(const RTCString &a_rSrc) + { + copyFromN(a_rSrc.m_psz, a_rSrc.m_cch); + } + + /** + * Creates a copy of a C-style string. + * + * This allocates strlen(pcsz) + 1 bytes for the new instance, unless s is empty. + * + * @param pcsz The source string. + * + * @throws std::bad_alloc + */ + RTCString(const char *pcsz) + { + copyFromN(pcsz, pcsz ? strlen(pcsz) : 0); + } + + /** + * Create a partial copy of another RTCString. + * + * @param a_rSrc The source string. + * @param a_offSrc The byte offset into the source string. + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + */ + RTCString(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos) + { + if (a_offSrc < a_rSrc.m_cch) + copyFromN(&a_rSrc.m_psz[a_offSrc], RT_MIN(a_cchSrc, a_rSrc.m_cch - a_offSrc)); + else + { + m_psz = NULL; + m_cch = 0; + m_cbAllocated = 0; + } + } + + /** + * Create a partial copy of a C-style string. + * + * @param a_pszSrc The source string (UTF-8). + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. This must not + * be '0' as the compiler could easily mistake + * that for the va_list constructor. + */ + RTCString(const char *a_pszSrc, size_t a_cchSrc) + { + size_t cchMax = a_pszSrc ? RTStrNLen(a_pszSrc, a_cchSrc) : 0; + copyFromN(a_pszSrc, RT_MIN(a_cchSrc, cchMax)); + } + + /** + * Create a string containing @a a_cTimes repetitions of the character @a + * a_ch. + * + * @param a_cTimes The number of times the character is repeated. + * @param a_ch The character to fill the string with. + */ + RTCString(size_t a_cTimes, char a_ch) + : m_psz(NULL), + m_cch(0), + m_cbAllocated(0) + { + Assert((unsigned)a_ch < 0x80); + if (a_cTimes) + { + reserve(a_cTimes + 1); + memset(m_psz, a_ch, a_cTimes); + m_psz[a_cTimes] = '\0'; + m_cch = a_cTimes; + } + } + + /** + * Create a new string given the format string and its arguments. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param a_va Argument vector containing the arguments + * specified by the format string. + * @sa printfV + * @remarks Not part of std::string. + */ + RTCString(const char *a_pszFormat, va_list a_va) RT_IPRT_FORMAT_ATTR(1, 0) + : m_psz(NULL), + m_cch(0), + m_cbAllocated(0) + { + printfV(a_pszFormat, a_va); + } + + /** + * Destructor. + */ + virtual ~RTCString() + { + cleanup(); + } + + /** + * String length in bytes. + * + * Returns the length of the member string in bytes, which is equal to strlen(c_str()). + * In other words, this does not count unicode codepoints; use utf8length() for that. + * The byte length is always cached so calling this is cheap and requires no + * strlen() invocation. + * + * @returns m_cbLength. + */ + size_t length() const + { + return m_cch; + } + + /** + * String length in unicode codepoints. + * + * As opposed to length(), which returns the length in bytes, this counts + * the number of unicode codepoints. This is *not* cached so calling this + * is expensive. + * + * @returns Number of codepoints in the member string. + */ + size_t uniLength() const + { + return m_psz ? RTStrUniLen(m_psz) : 0; + } + + /** + * The allocated buffer size (in bytes). + * + * Returns the number of bytes allocated in the internal string buffer, which is + * at least length() + 1 if length() > 0; for an empty string, this returns 0. + * + * @returns m_cbAllocated. + */ + size_t capacity() const + { + return m_cbAllocated; + } + + /** + * Make sure at that least cb of buffer space is reserved. + * + * Requests that the contained memory buffer have at least cb bytes allocated. + * This may expand or shrink the string's storage, but will never truncate the + * contained string. In other words, cb will be ignored if it's smaller than + * length() + 1. + * + * @param cb New minimum size (in bytes) of member memory buffer. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + void reserve(size_t cb) + { + if ( ( cb != m_cbAllocated + && cb > m_cch + 1) + || ( m_psz == NULL + && cb > 0)) + { + int rc = RTStrRealloc(&m_psz, cb); + if (RT_SUCCESS(rc)) + m_cbAllocated = cb; +#ifdef RT_EXCEPTIONS_ENABLED + else + throw std::bad_alloc(); +#endif + } + } + + /** + * A C like version of the reserve method, i.e. return code instead of throw. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + * @param cb New minimum size (in bytes) of member memory buffer. + */ + int reserveNoThrow(size_t cb) RT_NOEXCEPT + { + if ( ( cb != m_cbAllocated + && cb > m_cch + 1) + || ( m_psz == NULL + && cb > 0)) + { + int rc = RTStrRealloc(&m_psz, cb); + if (RT_SUCCESS(rc)) + m_cbAllocated = cb; + else + return rc; + } + return VINF_SUCCESS; + } + + /** + * Deallocates all memory. + */ + inline void setNull() + { + cleanup(); + } + + /** + * Assigns a copy of pcsz to @a this. + * + * @param pcsz The source string. + * + * @throws std::bad_alloc On allocation failure. The object is left describing + * a NULL string. + * + * @returns Reference to the object. + */ + RTCString &operator=(const char *pcsz) + { + if (m_psz != pcsz) + { + cleanup(); + copyFromN(pcsz, pcsz ? strlen(pcsz) : 0); + } + return *this; + } + + /** + * Assigns a copy of s to @a this. + * + * @param s The source string. + * + * @throws std::bad_alloc On allocation failure. The object is left describing + * a NULL string. + * + * @returns Reference to the object. + */ + RTCString &operator=(const RTCString &s) + { + if (this != &s) + { + cleanup(); + copyFromN(s.m_psz, s.m_cch); + } + return *this; + } + + /** + * Assigns a copy of another RTCString. + * + * @param a_rSrc Reference to the source string. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &assign(const RTCString &a_rSrc); + + /** + * Assigns a copy of another RTCString. + * + * @param a_rSrc Reference to the source string. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int assignNoThrow(const RTCString &a_rSrc) RT_NOEXCEPT; + + /** + * Assigns a copy of a C-style string. + * + * @param a_pszSrc Pointer to the C-style source string. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @remarks ASSUMES valid + */ + RTCString &assign(const char *a_pszSrc); + + /** + * Assigns a copy of a C-style string. + * + * @param a_pszSrc Pointer to the C-style source string. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + * @remarks ASSUMES valid + */ + int assignNoThrow(const char *a_pszSrc) RT_NOEXCEPT; + + /** + * Assigns a partial copy of another RTCString. + * + * @param a_rSrc The source string. + * @param a_offSrc The byte offset into the source string. + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &assign(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos); + + /** + * Assigns a partial copy of another RTCString. + * + * @param a_rSrc The source string. + * @param a_offSrc The byte offset into the source string. + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int assignNoThrow(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos) RT_NOEXCEPT; + + /** + * Assigns a partial copy of a C-style string. + * + * @param a_pszSrc The source string (UTF-8). + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &assign(const char *a_pszSrc, size_t a_cchSrc); + + /** + * Assigns a partial copy of a C-style string. + * + * @param a_pszSrc The source string (UTF-8). + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int assignNoThrow(const char *a_pszSrc, size_t a_cchSrc) RT_NOEXCEPT; + + /** + * Assigs a string containing @a a_cTimes repetitions of the character @a a_ch. + * + * @param a_cTimes The number of times the character is repeated. + * @param a_ch The character to fill the string with. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &assign(size_t a_cTimes, char a_ch); + + /** + * Assigs a string containing @a a_cTimes repetitions of the character @a a_ch. + * + * @param a_cTimes The number of times the character is repeated. + * @param a_ch The character to fill the string with. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int assignNoThrow(size_t a_cTimes, char a_ch) RT_NOEXCEPT; + + /** + * Assigns the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + RTCString &printf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Assigns the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int printfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Assigns the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + RTCString &printfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Assigns the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int printfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Appends the string @a that to @a rThat. + * + * @param rThat The string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(const RTCString &rThat); + + /** + * Appends the string @a that to @a rThat. + * + * @param rThat The string to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(const RTCString &rThat) RT_NOEXCEPT; + + /** + * Appends the string @a pszSrc to @a this. + * + * @param pszSrc The C-style string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(const char *pszSrc); + + /** + * Appends the string @a pszSrc to @a this. + * + * @param pszSrc The C-style string to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(const char *pszSrc) RT_NOEXCEPT; + + /** + * Appends the a substring from @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (byte offset, + * not codepoint). + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(const RTCString &rThat, size_t offStart, size_t cchMax = RTSTR_MAX); + + /** + * Appends the a substring from @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (byte offset, + * not codepoint). + * @param cchMax The maximum number of bytes to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(const RTCString &rThat, size_t offStart, size_t cchMax = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Appends the first @a cchMax chars from string @a pszThat to @a this. + * + * @param pszThat The C-style string to append. + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(const char *pszThat, size_t cchMax); + + /** + * Appends the first @a cchMax chars from string @a pszThat to @a this. + * + * @param pszThat The C-style string to append. + * @param cchMax The maximum number of bytes to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(const char *pszThat, size_t cchMax) RT_NOEXCEPT; + + /** + * Appends the given character to @a this. + * + * @param ch The character to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(char ch); + + /** + * Appends the given character to @a this. + * + * @param ch The character to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(char ch) RT_NOEXCEPT; + + /** + * Appends the given unicode code point to @a this. + * + * @param uc The unicode code point to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &appendCodePoint(RTUNICP uc); + + /** + * Appends the given unicode code point to @a this. + * + * @param uc The unicode code point to append. + * @returns VINF_SUCCESS, VERR_INVALID_UTF8_ENCODING or VERR_NO_STRING_MEMORY. + */ + int appendCodePointNoThrow(RTUNICP uc) RT_NOEXCEPT; + + /** + * Appends the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + RTCString &appendPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Appends the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendPrintfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Appends the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + RTCString &appendPrintfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Appends the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendPrintfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Shortcut to append(), RTCString variant. + * + * @param rThat The string to append. + * @returns Reference to the object. + */ + RTCString &operator+=(const RTCString &rThat) + { + return append(rThat); + } + + /** + * Shortcut to append(), const char* variant. + * + * @param pszThat The C-style string to append. + * @returns Reference to the object. + */ + RTCString &operator+=(const char *pszThat) + { + return append(pszThat); + } + + /** + * Shortcut to append(), char variant. + * + * @param ch The character to append. + * + * @returns Reference to the object. + */ + RTCString &operator+=(char ch) + { + return append(ch); + } + + /** + * Converts the member string to upper case. + * + * @returns Reference to the object. + */ + RTCString &toUpper() RT_NOEXCEPT + { + if (length()) + { + /* Folding an UTF-8 string may result in a shorter encoding (see + testcase), so recalculate the length afterwards. */ + ::RTStrToUpper(m_psz); + size_t cchNew = strlen(m_psz); + Assert(cchNew <= m_cch); + m_cch = cchNew; + } + return *this; + } + + /** + * Converts the member string to lower case. + * + * @returns Reference to the object. + */ + RTCString &toLower() RT_NOEXCEPT + { + if (length()) + { + /* Folding an UTF-8 string may result in a shorter encoding (see + testcase), so recalculate the length afterwards. */ + ::RTStrToLower(m_psz); + size_t cchNew = strlen(m_psz); + Assert(cchNew <= m_cch); + m_cch = cchNew; + } + return *this; + } + + /** + * Erases a sequence from the string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start erasing. + * @param cchLength How much following @a offStart to erase. + */ + RTCString &erase(size_t offStart = 0, size_t cchLength = npos) RT_NOEXCEPT; + + /** + * Replaces a span of @a this string with a replacement string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param rStrReplacement The replacement string. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + * @note Non-standard behaviour if offStart is beyond the end of the string. + * No change will occure and strict builds hits a debug assertion. + */ + RTCString &replace(size_t offStart, size_t cchLength, const RTCString &rStrReplacement); + + /** + * Replaces a span of @a this string with a replacement string. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param rStrReplacement The replacement string. + */ + int replaceNoThrow(size_t offStart, size_t cchLength, const RTCString &rStrReplacement) RT_NOEXCEPT; + + /** + * Replaces a span of @a this string with a replacement substring. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param rStrReplacement The string from which a substring is taken. + * @param offReplacement The offset into @a rStrReplacement where the + * replacement substring starts. + * @param cchReplacement The maximum length of the replacement substring. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + * @note Non-standard behaviour if offStart or offReplacement is beyond the + * end of the repective strings. No change is made in the former case, + * while we consider it an empty string in the latter. In both + * situation a debug assertion is raised in strict builds. + */ + RTCString &replace(size_t offStart, size_t cchLength, const RTCString &rStrReplacement, + size_t offReplacement, size_t cchReplacement); + + /** + * Replaces a span of @a this string with a replacement substring. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param rStrReplacement The string from which a substring is taken. + * @param offReplacement The offset into @a rStrReplacement where the + * replacement substring starts. + * @param cchReplacement The maximum length of the replacement substring. + */ + int replaceNoThrow(size_t offStart, size_t cchLength, const RTCString &rStrReplacement, + size_t offReplacement, size_t cchReplacement) RT_NOEXCEPT; + + /** + * Replaces a span of @a this string with the replacement string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszReplacement The replacement string. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + * @note Non-standard behaviour if offStart is beyond the end of the string. + * No change will occure and strict builds hits a debug assertion. + */ + RTCString &replace(size_t offStart, size_t cchLength, const char *pszReplacement); + + /** + * Replaces a span of @a this string with the replacement string. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszReplacement The replacement string. + */ + int replaceNoThrow(size_t offStart, size_t cchLength, const char *pszReplacement) RT_NOEXCEPT; + + /** + * Replaces a span of @a this string with the replacement string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszReplacement The replacement string. + * @param cchReplacement How much of @a pszReplacement to use at most. If a + * zero terminator is found before reaching this value, + * we'll stop there. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + * @note Non-standard behaviour if offStart is beyond the end of the string. + * No change will occure and strict builds hits a debug assertion. + */ + RTCString &replace(size_t offStart, size_t cchLength, const char *pszReplacement, size_t cchReplacement); + + /** + * Replaces a span of @a this string with the replacement string. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszReplacement The replacement string. + * @param cchReplacement How much of @a pszReplacement to use at most. If a + * zero terminator is found before reaching this value, + * we'll stop there. + */ + int replaceNoThrow(size_t offStart, size_t cchLength, const char *pszReplacement, size_t cchReplacement) RT_NOEXCEPT; + + /** + * Truncates the string to a max length of @a cchMax. + * + * If the string is shorter than @a cchMax characters, no change is made. + * + * If the @a cchMax is not at the start of a UTF-8 sequence, it will be adjusted + * down to the start of the UTF-8 sequence. Thus, after a truncation, the + * length() may be smaller than @a cchMax. + * + */ + RTCString &truncate(size_t cchMax) RT_NOEXCEPT; + + /** + * Index operator. + * + * Returns the byte at the given index, or a null byte if the index is not + * smaller than length(). This does _not_ count codepoints but simply points + * into the member C-style string. + * + * @param i The index into the string buffer. + * @returns char at the index or null. + */ + inline char operator[](size_t i) const RT_NOEXCEPT + { + if (i < length()) + return m_psz[i]; + return '\0'; + } + + /** + * Returns the contained string as a const C-style string pointer. + * + * This never returns NULL; if the string is empty, this returns a pointer to + * static null byte. + * + * @returns const pointer to C-style string. + */ + inline const char *c_str() const RT_NOEXCEPT + { + return (m_psz) ? m_psz : ""; + } + + /** + * Returns a non-const raw pointer that allows to modify the string directly. + * As opposed to c_str() and raw(), this DOES return NULL for an empty string + * because we cannot return a non-const pointer to a static "" global. + * + * @warning + * -# Be sure not to modify data beyond the allocated memory! Call + * capacity() to find out how large that buffer is. + * -# After any operation that modifies the length of the string, + * you _must_ call RTCString::jolt(), or subsequent copy operations + * may go nowhere. Better not use mutableRaw() at all. + */ + char *mutableRaw() RT_NOEXCEPT + { + return m_psz; + } + + /** + * Clean up after using mutableRaw. + * + * Intended to be called after something has messed with the internal string + * buffer (e.g. after using mutableRaw() or Utf8Str::asOutParam()). Resets the + * internal lengths correctly. Otherwise subsequent copy operations may go + * nowhere. + */ + void jolt() RT_NOEXCEPT + { + if (m_psz) + { + m_cch = strlen(m_psz); + m_cbAllocated = m_cch + 1; /* (Required for the Utf8Str::asOutParam case) */ + } + else + { + m_cch = 0; + m_cbAllocated = 0; + } + } + + /** + * Returns @c true if the member string has no length. + * + * This is @c true for instances created from both NULL and "" input + * strings. + * + * This states nothing about how much memory might be allocated. + * + * @returns @c true if empty, @c false if not. + */ + bool isEmpty() const RT_NOEXCEPT + { + return length() == 0; + } + + /** + * Returns @c false if the member string has no length. + * + * This is @c false for instances created from both NULL and "" input + * strings. + * + * This states nothing about how much memory might be allocated. + * + * @returns @c false if empty, @c true if not. + */ + bool isNotEmpty() const RT_NOEXCEPT + { + return length() != 0; + } + + /** Case sensitivity selector. */ + enum CaseSensitivity + { + CaseSensitive, + CaseInsensitive + }; + + /** + * Compares the member string to a C-string. + * + * @param pcszThat The string to compare with. + * @param cs Whether comparison should be case-sensitive. + * @returns 0 if equal, negative if this is smaller than @a pcsz, positive + * if larger. + */ + int compare(const char *pcszThat, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT + { + /* This klugde is for m_cch=0 and m_psz=NULL. pcsz=NULL and psz="" + are treated the same way so that str.compare(str2.c_str()) works. */ + if (length() == 0) + return pcszThat == NULL || *pcszThat == '\0' ? 0 : -1; + + if (cs == CaseSensitive) + return ::RTStrCmp(m_psz, pcszThat); + return ::RTStrICmp(m_psz, pcszThat); + } + + /** + * Compares the member string to another RTCString. + * + * @param rThat The string to compare with. + * @param cs Whether comparison should be case-sensitive. + * @returns 0 if equal, negative if this is smaller than @a pcsz, positive + * if larger. + */ + int compare(const RTCString &rThat, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT + { + if (cs == CaseSensitive) + return ::RTStrCmp(m_psz, rThat.m_psz); + return ::RTStrICmp(m_psz, rThat.m_psz); + } + + /** + * Compares the two strings. + * + * @returns true if equal, false if not. + * @param rThat The string to compare with. + */ + bool equals(const RTCString &rThat) const RT_NOEXCEPT + { + return rThat.length() == length() + && ( length() == 0 + || memcmp(rThat.m_psz, m_psz, length()) == 0); + } + + /** + * Compares the two strings. + * + * @returns true if equal, false if not. + * @param pszThat The string to compare with. + */ + bool equals(const char *pszThat) const RT_NOEXCEPT + { + /* This klugde is for m_cch=0 and m_psz=NULL. pcsz=NULL and psz="" + are treated the same way so that str.equals(str2.c_str()) works. */ + if (length() == 0) + return pszThat == NULL || *pszThat == '\0'; + return RTStrCmp(pszThat, m_psz) == 0; + } + + /** + * Compares the two strings ignoring differences in case. + * + * @returns true if equal, false if not. + * @param that The string to compare with. + */ + bool equalsIgnoreCase(const RTCString &that) const RT_NOEXCEPT + { + /* Unfolded upper and lower case characters may require different + amount of encoding space, so the length optimization doesn't work. */ + return RTStrICmp(that.m_psz, m_psz) == 0; + } + + /** + * Compares the two strings ignoring differences in case. + * + * @returns true if equal, false if not. + * @param pszThat The string to compare with. + */ + bool equalsIgnoreCase(const char *pszThat) const RT_NOEXCEPT + { + /* This klugde is for m_cch=0 and m_psz=NULL. pcsz=NULL and psz="" + are treated the same way so that str.equalsIgnoreCase(str2.c_str()) works. */ + if (length() == 0) + return pszThat == NULL || *pszThat == '\0'; + return RTStrICmp(pszThat, m_psz) == 0; + } + + /** @name Comparison operators. + * @{ */ + bool operator==(const RTCString &that) const { return equals(that); } + bool operator!=(const RTCString &that) const { return !equals(that); } + bool operator<( const RTCString &that) const { return compare(that) < 0; } + bool operator>( const RTCString &that) const { return compare(that) > 0; } + + bool operator==(const char *pszThat) const { return equals(pszThat); } + bool operator!=(const char *pszThat) const { return !equals(pszThat); } + bool operator<( const char *pszThat) const { return compare(pszThat) < 0; } + bool operator>( const char *pszThat) const { return compare(pszThat) > 0; } + /** @} */ + + /** Max string offset value. + * + * When returned by a method, this indicates failure. When taken as input, + * typically a default, it means all the way to the string terminator. + */ + static const size_t npos; + + /** + * Find the given substring. + * + * Looks for @a pszNeedle in @a this starting at @a offStart and returns its + * position as a byte (not codepoint) offset, counting from the beginning of + * @a this as 0. + * + * @param pszNeedle The substring to find. + * @param offStart The (byte) offset into the string buffer to start + * searching. + * + * @returns 0 based position of pszNeedle. npos if not found. + */ + size_t find(const char *pszNeedle, size_t offStart = 0) const RT_NOEXCEPT; + size_t find_first_of(const char *pszNeedle, size_t offStart = 0) const RT_NOEXCEPT + { return find(pszNeedle, offStart); } + + /** + * Find the given substring. + * + * Looks for @a pStrNeedle in @a this starting at @a offStart and returns its + * position as a byte (not codepoint) offset, counting from the beginning of + * @a this as 0. + * + * @param pStrNeedle The substring to find. + * @param offStart The (byte) offset into the string buffer to start + * searching. + * + * @returns 0 based position of pStrNeedle. npos if not found or pStrNeedle is + * NULL or an empty string. + */ + size_t find(const RTCString *pStrNeedle, size_t offStart = 0) const RT_NOEXCEPT; + + /** + * Find the given substring. + * + * Looks for @a rStrNeedle in @a this starting at @a offStart and returns its + * position as a byte (not codepoint) offset, counting from the beginning of + * @a this as 0. + * + * @param rStrNeedle The substring to find. + * @param offStart The (byte) offset into the string buffer to start + * searching. + * + * @returns 0 based position of pStrNeedle. npos if not found or pStrNeedle is + * NULL or an empty string. + */ + size_t find(const RTCString &rStrNeedle, size_t offStart = 0) const RT_NOEXCEPT; + size_t find_first_of(const RTCString &rStrNeedle, size_t offStart = 0) const RT_NOEXCEPT + { return find(rStrNeedle, offStart); } + + /** + * Find the given character (byte). + * + * @returns 0 based position of chNeedle. npos if not found or pStrNeedle is + * NULL or an empty string. + * @param chNeedle The character (byte) to find. + * @param offStart The (byte) offset into the string buffer to start + * searching. Default is start of the string. + * + * @note This searches for a C character value, not a codepoint. Use the + * string version to locate codepoints above U+7F. + */ + size_t find(char chNeedle, size_t offStart = 0) const RT_NOEXCEPT; + size_t find_first_of(char chNeedle, size_t offStart = 0) const RT_NOEXCEPT + { return find(chNeedle, offStart); } + + /** + * Replaces all occurences of cFind with cReplace in the member string. + * In order not to produce invalid UTF-8, the characters must be ASCII + * values less than 128; this is not verified. + * + * @param chFind Character to replace. Must be ASCII < 128. + * @param chReplace Character to replace cFind with. Must be ASCII < 128. + */ + void findReplace(char chFind, char chReplace) RT_NOEXCEPT; + + /** + * Count the occurences of the specified character in the string. + * + * @param ch What to search for. Must be ASCII < 128. + * @remarks QString::count + */ + size_t count(char ch) const RT_NOEXCEPT; + + /** + * Count the occurences of the specified sub-string in the string. + * + * @param psz What to search for. + * @param cs Case sensitivity selector. + * @remarks QString::count + */ + size_t count(const char *psz, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Count the occurences of the specified sub-string in the string. + * + * @param pStr What to search for. + * @param cs Case sensitivity selector. + * @remarks QString::count + */ + size_t count(const RTCString *pStr, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Strips leading and trailing spaces. + * + * @returns this + */ + RTCString &strip() RT_NOEXCEPT; + + /** + * Strips leading spaces. + * + * @returns this + */ + RTCString &stripLeft() RT_NOEXCEPT; + + /** + * Strips trailing spaces. + * + * @returns this + */ + RTCString &stripRight() RT_NOEXCEPT; + + /** + * Returns a substring of @a this as a new Utf8Str. + * + * Works exactly like its equivalent in std::string. With the default + * parameters "0" and "npos", this always copies the entire string. The + * "pos" and "n" arguments represent bytes; it is the caller's responsibility + * to ensure that the offsets do not copy invalid UTF-8 sequences. When + * used in conjunction with find() and length(), this will work. + * + * @param pos Index of first byte offset to copy from @a this, + * counting from 0. + * @param n Number of bytes to copy, starting with the one at "pos". + * The copying will stop if the null terminator is encountered before + * n bytes have been copied. + */ + RTCString substr(size_t pos = 0, size_t n = npos) const + { + return RTCString(*this, pos, n); + } + + /** + * Returns a substring of @a this as a new Utf8Str. As opposed to substr(), this + * variant takes codepoint offsets instead of byte offsets. + * + * @param pos Index of first unicode codepoint to copy from + * @a this, counting from 0. + * @param n Number of unicode codepoints to copy, starting with + * the one at "pos". The copying will stop if the null + * terminator is encountered before n codepoints have + * been copied. + */ + RTCString substrCP(size_t pos = 0, size_t n = npos) const; + + /** + * Returns true if @a this ends with @a that. + * + * @param that Suffix to test for. + * @param cs Case sensitivity selector. + * @returns true if match, false if mismatch. + */ + bool endsWith(const RTCString &that, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Returns true if @a this begins with @a that. + * @param that Prefix to test for. + * @param cs Case sensitivity selector. + * @returns true if match, false if mismatch. + */ + bool startsWith(const RTCString &that, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Checks if the string starts with the given word, ignoring leading blanks. + * + * @param pszWord The word to test for. + * @param enmCase Case sensitivity selector. + * @returns true if match, false if mismatch. + */ + bool startsWithWord(const char *pszWord, CaseSensitivity enmCase = CaseSensitive) const RT_NOEXCEPT; + + /** + * Checks if the string starts with the given word, ignoring leading blanks. + * + * @param rThat Prefix to test for. + * @param enmCase Case sensitivity selector. + * @returns true if match, false if mismatch. + */ + bool startsWithWord(const RTCString &rThat, CaseSensitivity enmCase = CaseSensitive) const RT_NOEXCEPT; + + /** + * Returns true if @a this contains @a that (strstr). + * + * @param that Substring to look for. + * @param cs Case sensitivity selector. + * @returns true if found, false if not found. + */ + bool contains(const RTCString &that, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Returns true if @a this contains @a pszNeedle (strstr). + * + * @param pszNeedle Substring to look for. + * @param cs Case sensitivity selector. + * @returns true if found, false if not found. + */ + bool contains(const char *pszNeedle, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Attempts to convert the member string into a 32-bit integer. + * + * @returns 32-bit unsigned number on success. + * @returns 0 on failure. + */ + int32_t toInt32() const RT_NOEXCEPT + { + return RTStrToInt32(c_str()); + } + + /** + * Attempts to convert the member string into an unsigned 32-bit integer. + * + * @returns 32-bit unsigned number on success. + * @returns 0 on failure. + */ + uint32_t toUInt32() const RT_NOEXCEPT + { + return RTStrToUInt32(c_str()); + } + + /** + * Attempts to convert the member string into an 64-bit integer. + * + * @returns 64-bit unsigned number on success. + * @returns 0 on failure. + */ + int64_t toInt64() const RT_NOEXCEPT + { + return RTStrToInt64(c_str()); + } + + /** + * Attempts to convert the member string into an unsigned 64-bit integer. + * + * @returns 64-bit unsigned number on success. + * @returns 0 on failure. + */ + uint64_t toUInt64() const RT_NOEXCEPT + { + return RTStrToUInt64(c_str()); + } + + /** + * Attempts to convert the member string into an unsigned 64-bit integer. + * + * @param i Where to return the value on success. + * @returns IPRT error code, see RTStrToInt64. + */ + int toInt(uint64_t &i) const RT_NOEXCEPT; + + /** + * Attempts to convert the member string into an unsigned 32-bit integer. + * + * @param i Where to return the value on success. + * @returns IPRT error code, see RTStrToInt32. + */ + int toInt(uint32_t &i) const RT_NOEXCEPT; + + /** Splitting behavior regarding empty sections in the string. */ + enum SplitMode + { + KeepEmptyParts, /**< Empty parts are added as empty strings to the result list. */ + RemoveEmptyParts /**< Empty parts are skipped. */ + }; + + /** + * Splits a string separated by strSep into its parts. + * + * @param a_rstrSep The separator to search for. + * @param a_enmMode How should empty parts be handled. + * @returns separated strings as string list. + * @throws std::bad_alloc On allocation error. + */ + RTCList split(const RTCString &a_rstrSep, + SplitMode a_enmMode = RemoveEmptyParts) const; + + /** + * Joins a list of strings together using the provided separator and + * an optional prefix for each item in the list. + * + * @param a_rList The list to join. + * @param a_rstrPrefix The prefix used for appending to each item. + * @param a_rstrSep The separator used for joining. + * @returns joined string. + * @throws std::bad_alloc On allocation error. + */ + static RTCString joinEx(const RTCList &a_rList, + const RTCString &a_rstrPrefix /* = "" */, + const RTCString &a_rstrSep /* = "" */); + + /** + * Joins a list of strings together using the provided separator. + * + * @param a_rList The list to join. + * @param a_rstrSep The separator used for joining. + * @returns joined string. + * @throws std::bad_alloc On allocation error. + */ + static RTCString join(const RTCList &a_rList, + const RTCString &a_rstrSep = ""); + + /** + * Swaps two strings in a fast way. + * + * Exception safe. + * + * @param a_rThat The string to swap with. + */ + inline void swap(RTCString &a_rThat) RT_NOEXCEPT + { + char *pszTmp = m_psz; + size_t cchTmp = m_cch; + size_t cbAllocatedTmp = m_cbAllocated; + + m_psz = a_rThat.m_psz; + m_cch = a_rThat.m_cch; + m_cbAllocated = a_rThat.m_cbAllocated; + + a_rThat.m_psz = pszTmp; + a_rThat.m_cch = cchTmp; + a_rThat.m_cbAllocated = cbAllocatedTmp; + } + +protected: + + /** + * Hide operator bool() to force people to use isEmpty() explicitly. + */ + operator bool() const; + + /** + * Destructor implementation, also used to clean up in operator=() before + * assigning a new string. + */ + void cleanup() RT_NOEXCEPT + { + if (m_psz) + { + RTStrFree(m_psz); + m_psz = NULL; + m_cch = 0; + m_cbAllocated = 0; + } + } + + /** + * Protected internal helper to copy a string. + * + * This ignores the previous object state, so either call this from a + * constructor or call cleanup() first. copyFromN() unconditionally sets + * the members to a copy of the given other strings and makes no + * assumptions about previous contents. Can therefore be used both in copy + * constructors, when member variables have no defined value, and in + * assignments after having called cleanup(). + * + * @param pcszSrc The source string. + * @param cchSrc The number of chars (bytes) to copy from the + * source strings. RTSTR_MAX is NOT accepted. + * + * @throws std::bad_alloc On allocation failure. The object is left + * describing a NULL string. + */ + void copyFromN(const char *pcszSrc, size_t cchSrc) + { + if (cchSrc) + { + m_psz = RTStrAlloc(cchSrc + 1); + if (RT_LIKELY(m_psz)) + { + m_cch = cchSrc; + m_cbAllocated = cchSrc + 1; + memcpy(m_psz, pcszSrc, cchSrc); + m_psz[cchSrc] = '\0'; + } + else + { + m_cch = 0; + m_cbAllocated = 0; +#ifdef RT_EXCEPTIONS_ENABLED + throw std::bad_alloc(); +#endif + } + } + else + { + m_cch = 0; + m_cbAllocated = 0; + m_psz = NULL; + } + } + + /** + * Appends exactly @a cchSrc chars from @a pszSrc to @a this. + * + * This is an internal worker for the append() methods. + * + * @returns Reference to the object. + * @param pszSrc The source string. + * @param cchSrc The source string length (exact). + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + */ + RTCString &appendWorker(const char *pszSrc, size_t cchSrc); + + /** + * Appends exactly @a cchSrc chars from @a pszSrc to @a this. + * + * This is an internal worker for the appendNoThrow() methods. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + * @param pszSrc The source string. + * @param cchSrc The source string length (exact). + */ + int appendWorkerNoThrow(const char *pszSrc, size_t cchSrc) RT_NOEXCEPT; + + /** + * Replaces exatly @a cchLength chars at @a offStart with @a cchSrc from @a + * pszSrc. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszSrc The replacement string. + * @param cchSrc The exactly length of the replacement string. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &replaceWorker(size_t offStart, size_t cchLength, const char *pszSrc, size_t cchSrc); + + /** + * Replaces exatly @a cchLength chars at @a offStart with @a cchSrc from @a + * pszSrc. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszSrc The replacement string. + * @param cchSrc The exactly length of the replacement string. + */ + int replaceWorkerNoThrow(size_t offStart, size_t cchLength, const char *pszSrc, size_t cchSrc) RT_NOEXCEPT; + + static DECLCALLBACK(size_t) printfOutputCallback(void *pvArg, const char *pachChars, size_t cbChars); + static DECLCALLBACK(size_t) printfOutputCallbackNoThrow(void *pvArg, const char *pachChars, size_t cbChars) RT_NOEXCEPT; + + char *m_psz; /**< The string buffer. */ + size_t m_cch; /**< strlen(m_psz) - i.e. no terminator included. */ + size_t m_cbAllocated; /**< Size of buffer that m_psz points to; at least m_cbLength + 1. */ +}; + +/** @} */ + + +/** @addtogroup grp_rt_cpp_string + * @{ + */ + +/** + * Concatenate two strings. + * + * @param a_rstr1 String one. + * @param a_rstr2 String two. + * @returns the concatenate string. + * + * @relates RTCString + */ +RTDECL(const RTCString) operator+(const RTCString &a_rstr1, const RTCString &a_rstr2); + +/** + * Concatenate two strings. + * + * @param a_rstr1 String one. + * @param a_psz2 String two. + * @returns the concatenate string. + * + * @relates RTCString + */ +RTDECL(const RTCString) operator+(const RTCString &a_rstr1, const char *a_psz2); + +/** + * Concatenate two strings. + * + * @param a_psz1 String one. + * @param a_rstr2 String two. + * @returns the concatenate string. + * + * @relates RTCString + */ +RTDECL(const RTCString) operator+(const char *a_psz1, const RTCString &a_rstr2); + +/** + * Class with RTCString::printf as constructor for your convenience. + * + * Constructing a RTCString string object from a format string and a variable + * number of arguments can easily be confused with the other RTCString + * constructors, thus this child class. + * + * The usage of this class is like the following: + * @code + RTCStringFmt strName("program name = %s", argv[0]); + @endcode + */ +class RTCStringFmt : public RTCString +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + */ + explicit RTCStringFmt(const char *a_pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2) + { + va_list va; + va_start(va, a_pszFormat); + printfV(a_pszFormat, va); + va_end(va); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +protected: + RTCStringFmt() {} +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_ministring_h */ + diff --git a/include/iprt/cpp/mtlist.h b/include/iprt/cpp/mtlist.h new file mode 100644 index 00000000..915fcbad --- /dev/null +++ b/include/iprt/cpp/mtlist.h @@ -0,0 +1,185 @@ +/** @file + * IPRT - Generic thread-safe list Class. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_mtlist_h +#define IPRT_INCLUDED_cpp_mtlist_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** @addtogroup grp_rt_cpp_list + * @{ + */ + +/** + * A guard class for thread-safe read/write access. + */ +template <> +class RTCListGuard +{ +public: + RTCListGuard() : m_hRWSem(NIL_RTSEMRW) + { +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) + RTLOCKVALCLASS hClass; + int rc = RTLockValidatorClassCreate(&hClass, true /*fAutodidact*/, RT_SRC_POS, "RTCListGuard"); + AssertStmt(RT_SUCCESS(rc), hClass = NIL_RTLOCKVALCLASS); + rc = RTSemRWCreateEx(&m_hRWSem, 0 /*fFlags*/, hClass, RTLOCKVAL_SUB_CLASS_NONE, NULL /*pszNameFmt*/); + AssertRC(rc); +#else + int rc = RTSemRWCreateEx(&m_hRWSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, 0, NULL); + AssertRC(rc); +#endif + } + + ~RTCListGuard() + { + RTSemRWDestroy(m_hRWSem); + m_hRWSem = NIL_RTSEMRW; + } + + inline void enterRead() const { int rc = RTSemRWRequestRead(m_hRWSem, RT_INDEFINITE_WAIT); AssertRC(rc); } + inline void leaveRead() const { int rc = RTSemRWReleaseRead(m_hRWSem); AssertRC(rc); } + inline void enterWrite() { int rc = RTSemRWRequestWrite(m_hRWSem, RT_INDEFINITE_WAIT); AssertRC(rc); } + inline void leaveWrite() { int rc = RTSemRWReleaseWrite(m_hRWSem); AssertRC(rc); } + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +private: + mutable RTSEMRW m_hRWSem; +}; + +/** + * @brief Generic thread-safe list class. + * + * RTCMTList is a thread-safe implementation of the list class. It uses a + * read/write semaphore to serialize the access to the items. Several readers + * can simultaneous access different or the same item. If one thread is writing + * to an item, the other accessors are blocked until the write has finished. + * + * Although the access is guarded, the user has to make sure the list content + * is consistent when iterating over the list or doing any other kind of access + * which makes assumptions about the list content. For a finer control of access + * restrictions, use your own locking mechanism and the standard list + * implementation. + * + * @see RTCListBase + */ +template sizeof(void*)), T*, T>::result> +class RTCMTList : public RTCListBase +{ + /* Traits */ + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using the native type list for + * unsigned 64-bit values even on a 32-bit host. + * + * @see RTCListBase + */ +template <> +class RTCMTList: public RTCListBase +{ + /* Traits */ + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using the native type list for + * signed 64-bit values even on a 32-bit host. + * + * @see RTCListBase + */ +template <> +class RTCMTList: public RTCListBase +{ + /* Traits */ + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_mtlist_h */ + diff --git a/include/iprt/cpp/path.h b/include/iprt/cpp/path.h new file mode 100644 index 00000000..1a3c7f99 --- /dev/null +++ b/include/iprt/cpp/path.h @@ -0,0 +1,249 @@ +/** @file + * IPRT - C++ path utilities. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_path_h +#define IPRT_INCLUDED_cpp_path_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +/** @defgroup grp_rt_cpp_path C++ Path Utilities + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * RTPathAbs() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrAbs Reference to the destination string. + * @param pszRelative The relative source string. + */ +DECLINLINE(int) RTPathAbsCxx(RTCString &rStrAbs, const char *pszRelative) +{ + Assert(rStrAbs.c_str() != pszRelative); + int rc = rStrAbs.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + { + unsigned cTries = 8; + for (;;) + { + char *pszDst = rStrAbs.mutableRaw(); + size_t cbCap = rStrAbs.capacity(); + rc = RTPathAbsEx(NULL, pszRelative, RTPATH_STR_F_STYLE_HOST, pszDst, &cbCap); + if (RT_SUCCESS(rc)) + break; + *pszDst = '\0'; + if (rc != VERR_BUFFER_OVERFLOW) + break; + if (--cTries == 0) + break; + rc = rStrAbs.reserveNoThrow(RT_MIN(RT_ALIGN_Z(cbCap, 64), RTPATH_MAX)); + if (RT_FAILURE(rc)) + break; + } + rStrAbs.jolt(); + } + return rc; +} + + +/** + * RTPathAbs() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrAbs Reference to the destination string. + * @param rStrRelative Reference to the relative source string. + */ +DECLINLINE(int) RTPathAbsCxx(RTCString &rStrAbs, RTCString const &rStrRelative) +{ + return RTPathAbsCxx(rStrAbs, rStrRelative.c_str()); +} + + + +/** + * RTPathAbsEx() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrAbs Reference to the destination string. + * @param pszBase The base path, optional. + * @param pszRelative The relative source string. + * @param fFlags RTPATH_STR_F_STYLE_XXX and RTPATHABS_F_XXX flags. + */ +DECLINLINE(int) RTPathAbsExCxx(RTCString &rStrAbs, const char *pszBase, const char *pszRelative, uint32_t fFlags = RTPATH_STR_F_STYLE_HOST) +{ + Assert(rStrAbs.c_str() != pszRelative); + int rc = rStrAbs.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + { + unsigned cTries = 8; + for (;;) + { + char *pszDst = rStrAbs.mutableRaw(); + size_t cbCap = rStrAbs.capacity(); + rc = RTPathAbsEx(pszBase, pszRelative, fFlags, pszDst, &cbCap); + if (RT_SUCCESS(rc)) + break; + *pszDst = '\0'; + if (rc != VERR_BUFFER_OVERFLOW) + break; + if (--cTries == 0) + break; + rc = rStrAbs.reserveNoThrow(RT_MIN(RT_ALIGN_Z(cbCap, 64), RTPATH_MAX)); + if (RT_FAILURE(rc)) + break; + } + rStrAbs.jolt(); + } + return rc; +} + + +DECLINLINE(int) RTPathAbsExCxx(RTCString &rStrAbs, RTCString const &rStrBase, RTCString const &rStrRelative, uint32_t fFlags = RTPATH_STR_F_STYLE_HOST) +{ + return RTPathAbsExCxx(rStrAbs, rStrBase.c_str(), rStrRelative.c_str(), fFlags); +} + + +DECLINLINE(int) RTPathAbsExCxx(RTCString &rStrAbs, const char *pszBase, RTCString const &rStrRelative, uint32_t fFlags = RTPATH_STR_F_STYLE_HOST) +{ + return RTPathAbsExCxx(rStrAbs, pszBase, rStrRelative.c_str(), fFlags); +} + + +DECLINLINE(int) RTPathAbsExCxx(RTCString &rStrAbs, RTCString const &rStrBase, const char *pszRelative, uint32_t fFlags = RTPATH_STR_F_STYLE_HOST) +{ + return RTPathAbsExCxx(rStrAbs, rStrBase.c_str(), pszRelative, fFlags); +} + + + +/** + * RTPathAppPrivateNoArch() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrDst Reference to the destination string. + */ +DECLINLINE(int) RTPathAppPrivateNoArchCxx(RTCString &rStrDst) +{ + int rc = rStrDst.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + { + char *pszDst = rStrDst.mutableRaw(); + rc = RTPathAppPrivateNoArch(pszDst, rStrDst.capacity()); + if (RT_FAILURE(rc)) + *pszDst = '\0'; + rStrDst.jolt(); + } + return rc; + +} + + +/** + * RTPathAppend() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrDst Reference to the destination string. + * @param pszAppend One or more components to append to the path already + * present in @a rStrDst. + */ +DECLINLINE(int) RTPathAppendCxx(RTCString &rStrDst, const char *pszAppend) +{ + Assert(rStrDst.c_str() != pszAppend); + size_t cbEstimate = rStrDst.length() + 1 + strlen(pszAppend) + 1; + int rc; + if (rStrDst.capacity() >= cbEstimate) + rc = VINF_SUCCESS; + else + rc = rStrDst.reserveNoThrow(RT_ALIGN_Z(cbEstimate, 8)); + if (RT_SUCCESS(rc)) + { + rc = RTPathAppend(rStrDst.mutableRaw(), rStrDst.capacity(), pszAppend); + if (rc == VERR_BUFFER_OVERFLOW) + { + rc = rStrDst.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(rStrDst.mutableRaw(), rStrDst.capacity(), pszAppend); + } + rStrDst.jolt(); + } + return rc; +} + + +/** + * RTPathAppend() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrDst Reference to the destination string. + * @param rStrAppend One or more components to append to the path already + * present in @a rStrDst. + */ +DECLINLINE(int) RTPathAppendCxx(RTCString &rStrDst, RTCString const &rStrAppend) +{ + Assert(&rStrDst != &rStrAppend); + size_t cbEstimate = rStrDst.length() + 1 + rStrAppend.length() + 1; + int rc; + if (rStrDst.capacity() >= cbEstimate) + rc = VINF_SUCCESS; + else + rc = rStrDst.reserveNoThrow(RT_ALIGN_Z(cbEstimate, 8)); + if (RT_SUCCESS(rc)) + { + rc = RTPathAppend(rStrDst.mutableRaw(), rStrDst.capacity(), rStrAppend.c_str()); + if (rc == VERR_BUFFER_OVERFLOW) + { + rc = rStrDst.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(rStrDst.mutableRaw(), rStrDst.capacity(), rStrAppend.c_str()); + } + rStrDst.jolt(); + } + return rc; +} + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_path_h */ + diff --git a/include/iprt/cpp/restanyobject.h b/include/iprt/cpp/restanyobject.h new file mode 100644 index 00000000..a83a769b --- /dev/null +++ b/include/iprt/cpp/restanyobject.h @@ -0,0 +1,139 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Any Object Class. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restanyobject_h +#define IPRT_INCLUDED_cpp_restanyobject_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @defgroup grp_rt_cpp_restanyobj C++ Representational State Transfer (REST) Any Object Class. + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Wrapper object that can represent any kind of basic REST object. + * + * This class is the result of a couple of design choices made in our REST + * data model. If could have been avoided if we used pointers all over + * the place and didn't rely entirely on the object specific implementations + * of deserializeFromJson and fromString to do the deserializing or everything. + * + * The assumption, though, was that most of the data we're dealing with has a + * known structure and maps to fixed types. So, the data model was optimized + * for that rather than flexiblity here. + */ +class RT_DECL_CLASS RTCRestAnyObject : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestAnyObject() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestAnyObject(); + + /** Copy constructor. */ + RTCRestAnyObject(RTCRestAnyObject const &a_rThat); + /** Copy assignment operator. */ + RTCRestAnyObject &operator=(RTCRestAnyObject const &a_rThat); + + /** Safe copy assignment method. */ + int assignCopy(RTCRestAnyObject const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, boolean variant. */ + int assignCopy(RTCRestBool const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, int64_t variant. */ + int assignCopy(RTCRestInt64 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, int32_t variant. */ + int assignCopy(RTCRestInt32 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, int16_t variant. */ + int assignCopy(RTCRestInt16 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, double variant. */ + int assignCopy(RTCRestDouble const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, string variant. */ + int assignCopy(RTCRestString const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, array variant. */ + int assignCopy(RTCRestArray const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, string map variant. */ + int assignCopy(RTCRestStringMap const &a_rThat) RT_NOEXCEPT; + + /** Safe value assignment method, boolean variant. */ + int assignValue(bool a_fValue) RT_NOEXCEPT; + /** Safe value assignment method, int64_t variant. */ + int assignValue(int64_t a_iValue) RT_NOEXCEPT; + /** Safe value assignment method, int32_t variant. */ + int assignValue(int32_t a_iValue) RT_NOEXCEPT; + /** Safe value assignment method, int16_t variant. */ + int assignValue(int16_t a_iValue) RT_NOEXCEPT; + /** Safe value assignment method, double variant. */ + int assignValue(double a_iValue) RT_NOEXCEPT; + /** Safe value assignment method, string variant. */ + int assignValue(RTCString const &a_rValue) RT_NOEXCEPT; + /** Safe value assignment method, C-string variant. */ + int assignValue(const char *a_pszValue) RT_NOEXCEPT; + + /** Make a clone of this object. */ + inline RTCRestAnyObject *clone() const RT_NOEXCEPT { return (RTCRestAnyObject *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int setNull(void) RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** Deserialization w/ instantiation. */ + static FNDESERIALIZEINSTANCEFROMJSON deserializeInstanceFromJson; + +protected: + /** The data. */ + RTCRestObjectBase *m_pData; +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restanyobject_h */ + diff --git a/include/iprt/cpp/restarray.h b/include/iprt/cpp/restarray.h new file mode 100644 index 00000000..56509c4e --- /dev/null +++ b/include/iprt/cpp/restarray.h @@ -0,0 +1,463 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Array Template Class. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restarray_h +#define IPRT_INCLUDED_cpp_restarray_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_rt_cpp_restarray C++ Representational State Transfer (REST) Array Template Class. + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Abstract base class for the RTCRestArray template. + */ +class RT_DECL_CLASS RTCRestArrayBase : public RTCRestObjectBase +{ +public: + /** Default destructor. */ + RTCRestArrayBase() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestArrayBase(); + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** + * Clear the content of the map. + */ + void clear() RT_NOEXCEPT; + + /** + * Check if an list contains any items. + * + * @return True if there is more than zero items, false otherwise. + */ + inline bool isEmpty() const RT_NOEXCEPT + { + return m_cElements == 0; + } + + /** + * Gets the number of entries in the map. + */ + inline size_t size() const RT_NOEXCEPT + { + return m_cElements; + } + + /** + * Returns the base object pointer at a given index. + * + * @returns The base object at @a a_idx, NULL if out of range. + * @param a_idx The array index. + */ + inline RTCRestObjectBase *atBase(size_t a_idx) RT_NOEXCEPT + { + if (a_idx < m_cElements) + return m_papElements[a_idx]; + return NULL; + } + + /** + * Returns the const base object pointer at a given index. + * + * @returns The base object at @a a_idx, NULL if out of range. + * @param a_idx The array index. + */ + inline RTCRestObjectBase const *atBase(size_t a_idx) const RT_NOEXCEPT + { + if (a_idx < m_cElements) + return m_papElements[a_idx]; + return NULL; + } + + /** + * Removes the element at @a a_idx. + * @returns true if @a a_idx is valid, false if out of range. + * @param a_idx The index of the element to remove. + * The value ~(size_t)0 is an alias for the final element. + */ + bool removeAt(size_t a_idx) RT_NOEXCEPT; + + /** + * Makes sure the array can hold at the given number of entries. + * + * @returns VINF_SUCCESS or VERR_NO_MEMORY. + * @param a_cEnsureCapacity The number of elements to ensure capacity to hold. + */ + int ensureCapacity(size_t a_cEnsureCapacity) RT_NOEXCEPT; + + +protected: + /** The array. */ + RTCRestObjectBase **m_papElements; + /** Number of elements in the array. */ + size_t m_cElements; + /** The number of elements m_papElements can hold. + * The difference between m_cCapacity and m_cElements are all NULLs. */ + size_t m_cCapacity; + + /** + * Helper for creating a clone. + * + * @returns Pointer to new array on success, NULL if out of memory. + */ + virtual RTCRestArrayBase *createClone(void) const RT_NOEXCEPT = 0; + + /** + * Wrapper around the value constructor. + * + * @returns Pointer to new value object on success, NULL if out of memory. + */ + virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT = 0; + + /** + * For accessing the static deserializeInstanceFromJson() method of the value. + */ + virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT = 0; + + /** + * Worker for the copy assignment method and copyArrayWorkerMayThrow(). + * + * This will use createEntryCopy to do the copying. + * + * @returns VINF_SUCCESS on success, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_rThat The array to copy. Caller makes 100% sure the it has + * the same type as the destination. + */ + int copyArrayWorkerNoThrow(RTCRestArrayBase const &a_rThat) RT_NOEXCEPT; + + /** + * Wrapper around copyArrayWorkerNoThrow for the copy constructor and the + * assignment operator. + */ + void copyArrayWorkerMayThrow(RTCRestArrayBase const &a_rThat); + + /** + * Worker for performing inserts. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_idx Where to insert it. The value ~(size_t)0 is an alias for m_cElements. + * @param a_pValue The value to insert. Ownership is transferred to the map on success. + * @param a_fReplace Whether to replace existing entry rather than insert. + */ + int insertWorker(size_t a_idx, RTCRestObjectBase *a_pValue, bool a_fReplace) RT_NOEXCEPT; + + /** + * Worker for performing inserts. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_idx Where to insert it. The value ~(size_t)0 is an alias for m_cElements. + * @param a_rValue The value to copy into the map. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + int insertCopyWorker(size_t a_idx, RTCRestObjectBase const &a_rValue, bool a_fReplace) RT_NOEXCEPT; + +private: + /** Copy constructor on this class should never be used. */ + RTCRestArrayBase(RTCRestArrayBase const &a_rThat); + /** Copy assignment operator on this class should never be used. */ + RTCRestArrayBase &operator=(RTCRestArrayBase const &a_rThat); +}; + + + +/** + * Limited array class. + */ +template class RTCRestArray : public RTCRestArrayBase +{ +public: + /** Default constructor - empty array. */ + RTCRestArray() RT_NOEXCEPT + : RTCRestArrayBase() + { + } + + /** Destructor. */ + ~RTCRestArray() + { + } + + /** Copy constructor. */ + RTCRestArray(RTCRestArray const &a_rThat) + : RTCRestArrayBase() + { + copyArrayWorkerMayThrow(a_rThat); + } + + /** Copy assignment operator. */ + inline RTCRestArray &operator=(RTCRestArray const &a_rThat) + { + copyArrayWorkerMayThrow(a_rThat); + return *this; + } + + /** Safe copy assignment method. */ + inline int assignCopy(RTCRestArray const &a_rThat) RT_NOEXCEPT + { + return copyArrayWorkerNoThrow(a_rThat); + } + + /** Make a clone of this object. */ + inline RTCRestArray *clone() const RT_NOEXCEPT + { + return (RTCRestArray *)baseClone(); + } + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) RTCRestArray(); + } + + /** Factory method for elements. */ + static DECLCALLBACK(RTCRestObjectBase *) createElementInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) ElementType(); + } + + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT + { + *a_ppInstance = new (std::nothrow) RTCRestArray(); + if (*a_ppInstance) + return (*a_ppInstance)->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); + } + + + /** + * Insert the given object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_INVALID_POINTER, VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_idx The insertion index. ~(size_t)0 is an alias for the end. + * @param a_pThat The object to insert. The array takes ownership of the object on success. + */ + inline int insert(size_t a_idx, ElementType *a_pThat) RT_NOEXCEPT + { + return insertWorker(a_idx, a_pThat, false /*a_fReplace*/); + } + + /** + * Insert a copy of the object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_idx The insertion index. ~(size_t)0 is an alias for the end. + * @param a_rThat The object to insert a copy of. + */ + inline int insertCopy(size_t a_idx, ElementType const &a_rThat) RT_NOEXCEPT + { + return insertCopyWorker(a_idx, a_rThat, false /*a_fReplace*/); + } + + /** + * Appends the given object to the array. + * + * @returns VINF_SUCCESS on success. + * VERR_INVALID_POINTER, VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_pThat The object to insert. The array takes ownership of the object on success. + */ + inline int append(ElementType *a_pThat) RT_NOEXCEPT + { + return insertWorker(~(size_t)0, a_pThat, false /*a_fReplace*/); + } + + /** + * Appends a copy of the object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_rThat The object to insert a copy of. + */ + inline int appendCopy(ElementType const &a_rThat) RT_NOEXCEPT + { + return insertCopyWorker(~(size_t)0, a_rThat, false /*a_fReplace*/); + } + + /** + * Prepends the given object to the array. + * + * @returns VINF_SUCCESS on success. + * VERR_INVALID_POINTER, VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_pThat The object to insert. The array takes ownership of the object on success. + */ + inline int prepend(ElementType *a_pThat) RT_NOEXCEPT + { + return insertWorker(0, a_pThat, false /*a_fReplace*/); + } + + /** + * Prepends a copy of the object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_rThat The object to insert a copy of. + */ + inline int prependCopy(ElementType const &a_rThat) RT_NOEXCEPT + { + return insertCopyWorker(0, a_rThat, false /*a_fReplace*/); + } + + /** + * Insert the given object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_INVALID_POINTER, VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_idx The index of the existing object to replace. + * @param a_pThat The replacement object. The array takes ownership of the object on success. + */ + inline int replace(size_t a_idx, ElementType *a_pThat) RT_NOEXCEPT + { + return insertWorker(a_idx, a_pThat, true /*a_fReplace*/); + } + + /** + * Insert a copy of the object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_idx The index of the existing object to replace. + * @param a_rThat The object to insert a copy of. + */ + inline int replaceCopy(size_t a_idx, ElementType const &a_rThat) RT_NOEXCEPT + { + return insertCopyWorker(a_idx, a_rThat, true /*a_fReplace*/); + } + + /** + * Returns the object at a given index. + * + * @returns The object at @a a_idx, NULL if out of range. + * @param a_idx The array index. + */ + inline ElementType *at(size_t a_idx) RT_NOEXCEPT + { + if (a_idx < m_cElements) + return (ElementType *)m_papElements[a_idx]; + return NULL; + } + + /** + * Returns the object at a given index, const variant. + * + * @returns The object at @a a_idx, NULL if out of range. + * @param a_idx The array index. + */ + inline ElementType const *at(size_t a_idx) const RT_NOEXCEPT + { + if (a_idx < m_cElements) + return (ElementType const *)m_papElements[a_idx]; + return NULL; + } + + /** + * Returns the first object in the array. + * @returns The first object, NULL if empty. + */ + inline ElementType *first() RT_NOEXCEPT + { + return at(0); + } + + /** + * Returns the first object in the array, const variant. + * @returns The first object, NULL if empty. + */ + inline ElementType const *first() const RT_NOEXCEPT + { + return at(0); + } + + /** + * Returns the last object in the array. + * @returns The last object, NULL if empty. + */ + inline ElementType *last() RT_NOEXCEPT + { + return at(m_cElements - 1); + } + + /** + * Returns the last object in the array, const variant. + * @returns The last object, NULL if empty. + */ + inline ElementType const *last() const RT_NOEXCEPT + { + return at(m_cElements - 1); + } + + +protected: + virtual RTCRestArrayBase *createClone(void) const RT_NOEXCEPT RT_OVERRIDE + { + return new (std::nothrow) RTCRestArray(); + } + + virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT RT_OVERRIDE + { + return new (std::nothrow) ElementType(); + } + + virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT RT_OVERRIDE + { + return ElementType::deserializeInstanceFromJson(a_rCursor, a_ppInstance); + } +}; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restarray_h */ + diff --git a/include/iprt/cpp/restbase.h b/include/iprt/cpp/restbase.h new file mode 100644 index 00000000..912610df --- /dev/null +++ b/include/iprt/cpp/restbase.h @@ -0,0 +1,1106 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Base Classes. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restbase_h +#define IPRT_INCLUDED_cpp_restbase_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include /* VERR_NO_MEMORY */ +#include +#include +#include +#include + + +/** @defgroup grp_rt_cpp_restbase C++ Representational State Transfer (REST) Base Classes. + * @ingroup grp_rt_cpp + * @{ + */ + +/* forward decl: */ +class RTCRestOutputBase; +class RTCRestJsonPrimaryCursor; + +/** + * JSON cursor structure. + * + * This reduces the number of parameters passed around when deserializing JSON + * input and also helps constructing full object name for logging and error reporting. + */ +struct RT_DECL_CLASS RTCRestJsonCursor +{ + /** Handle to the value being parsed. */ + RTJSONVAL m_hValue; + /** Name of the value. */ + const char *m_pszName; + /** Pointer to the parent, NULL if primary. */ + struct RTCRestJsonCursor const *m_pParent; + /** Pointer to the primary cursor structure. */ + RTCRestJsonPrimaryCursor *m_pPrimary; + + RTCRestJsonCursor(struct RTCRestJsonCursor const &a_rParent) RT_NOEXCEPT + : m_hValue(NIL_RTJSONVAL), m_pszName(NULL), m_pParent(&a_rParent), m_pPrimary(a_rParent.m_pPrimary) + { } + + RTCRestJsonCursor(RTJSONVAL hValue, const char *pszName, struct RTCRestJsonCursor *pParent) RT_NOEXCEPT + : m_hValue(hValue), m_pszName(pszName), m_pParent(pParent), m_pPrimary(pParent->m_pPrimary) + { } + + RTCRestJsonCursor(RTJSONVAL hValue, const char *pszName) RT_NOEXCEPT + : m_hValue(hValue), m_pszName(pszName), m_pParent(NULL), m_pPrimary(NULL) + { } + + ~RTCRestJsonCursor() + { + if (m_hValue != NIL_RTJSONVAL) + { + RTJsonValueRelease(m_hValue); + m_hValue = NIL_RTJSONVAL; + } + } +}; + + +/** + * The primary JSON cursor class. + */ +class RT_DECL_CLASS RTCRestJsonPrimaryCursor +{ +public: + /** The cursor for the first level. */ + RTCRestJsonCursor m_Cursor; + /** Error info keeper. */ + PRTERRINFO m_pErrInfo; + + /** Creates a primary json cursor with optiona error info. */ + RTCRestJsonPrimaryCursor(RTJSONVAL hValue, const char *pszName, PRTERRINFO pErrInfo = NULL) RT_NOEXCEPT + : m_Cursor(hValue, pszName) + , m_pErrInfo(pErrInfo) + { + m_Cursor.m_pPrimary = this; + } + + virtual ~RTCRestJsonPrimaryCursor() + { } + + /** + * Add an error message. + * + * @returns a_rc + * @param a_rCursor The cursor reporting the error. + * @param a_rc The status code. + * @param a_pszFormat Format string. + * @param ... Format string arguments. + */ + virtual int addError(RTCRestJsonCursor const &a_rCursor, int a_rc, const char *a_pszFormat, ...) RT_NOEXCEPT; + + /** + * Reports that the current field is not known. + * + * @returns Status to propagate. + * @param a_rCursor The cursor for the field. + */ + virtual int unknownField(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT; + + /** + * Copies the full path into pszDst. + * + * @returns pszDst + * @param a_rCursor The cursor to start walking at. + * @param a_pszDst Where to put the path. + * @param a_cbDst Size of the destination buffer. + */ + virtual char *getPath(RTCRestJsonCursor const &a_rCursor, char *a_pszDst, size_t a_cbDst) const RT_NOEXCEPT; +}; + + +/** + * Abstract base class for REST primitive types and data objects (via + * RTCRestDataObject). + * + * The only information this keeps is the null indicator. + */ +class RT_DECL_CLASS RTCRestObjectBase +{ +public: + RTCRestObjectBase() RT_NOEXCEPT; + RTCRestObjectBase(RTCRestObjectBase const &a_rThat) RT_NOEXCEPT; + virtual ~RTCRestObjectBase(); + + /** Copy assignment operator. */ + RTCRestObjectBase &operator=(RTCRestObjectBase const &a_rThat) RT_NOEXCEPT; + + /** + * Create a copy of this object. + * + * @returns Pointer to copy. + */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT = 0; + + /** + * Tests if the object is @a null. + * @returns true if null, false if not. + */ + inline bool isNull(void) const RT_NOEXCEPT { return m_fNullIndicator; }; + + /** + * Sets the object to @a null and fills it with defaults. + * @returns IPRT status code (from resetToDefault). + */ + virtual int setNull(void) RT_NOEXCEPT; + + /** + * Sets the object to not-null state (i.e. undoes setNull()). + * @remarks Only really important for strings. + */ + virtual void setNotNull(void) RT_NOEXCEPT; + + /** + * Resets the object to all default values. + * @returns IPRT status code. + */ + virtual int resetToDefault() RT_NOEXCEPT = 0; + + /** + * Serialize the object as JSON. + * + * @returns a_rDst + * @param a_rDst The destination for the serialization. + */ + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT = 0; + + /** + * Deserialize object from the given JSON iterator. + * + * @returns IPRT status code. + * @param a_rCursor The JSON cursor. + */ + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT = 0; + + /** + * Polymorphic JSON deserialization helper that instantiate the matching class using + * the discriminator field. + * + * @returns IPRT status code. + * @param a_rCursor The JSON cursor. + * @param a_ppInstance Where to return the deserialized instance. + * May return an object on failure. + */ + typedef DECLCALLBACKTYPE(int, FNDESERIALIZEINSTANCEFROMJSON,(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance)); + /** Pointer to a FNDESERIALIZEINSTANCEFROMJSON function. */ + typedef FNDESERIALIZEINSTANCEFROMJSON *PFNDESERIALIZEINSTANCEFROMJSON; + + /** + * Flags for toString(). + * + * The kCollectionFormat_xxx bunch controls multiple values in arrays + * are formatted. They are ignored by everyone else. + * + * @note When adding collection format types, make sure to also + * update RTCRestArrayBase::toString(). + * @note Bit 24 is reserved (for kHdrField_MapCollection). + */ + enum + { + kCollectionFormat_Unspecified = 0, /**< Not specified. */ + kCollectionFormat_csv, /**< Comma-separated list. */ + kCollectionFormat_ssv, /**< Space-separated list. */ + kCollectionFormat_tsv, /**< Tab-separated list. */ + kCollectionFormat_pipes, /**< Pipe-separated list. */ + kCollectionFormat_multi, /**< Special collection type that must be handled by caller of toString. */ + kCollectionFormat_Mask = 7, /**< Collection type mask. */ + + kToString_Append = 8 /**< Append to the string/object (rather than assigning). */ + }; + + /** + * String conversion. + * + * The default implementation of is a wrapper around serializeAsJson(). + * + * @returns IPRT status code. + * @param a_pDst Pointer to the destionation string. + * @param a_fFlags kCollectionFormat_xxx. + */ + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT; + + /** + * String convertsion, naive variant. + * + * @returns String represenation. + */ + RTCString toString() const; + + /** + * Convert from (header) string value. + * + * The default implementation of is a wrapper around deserializeFromJson(). + * + * @returns IPRT status code. + * @param a_rValue The string value string to parse. + * @param a_pszName Field name or similar. + * @param a_pErrInfo Where to return additional error info. Optional. + * @param a_fFlags kCollectionFormat_xxx. + */ + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT; + + /** Type classification */ + typedef enum kTypeClass + { + kTypeClass_Invalid = 0, + kTypeClass_Bool, /**< Primitive: bool. */ + kTypeClass_Int64, /**< Primitive: int64_t. */ + kTypeClass_Int32, /**< Primitive: int32_t. */ + kTypeClass_Int16, /**< Primitive: int16_t. */ + kTypeClass_Double, /**< Primitive: double. */ + kTypeClass_String, /**< Primitive: string. */ + kTypeClass_Date, /**< Date. */ + kTypeClass_Uuid, /**< UUID. */ + kTypeClass_Binary, /**< Binary blob. */ + kTypeClass_DataObject, /**< Data object child (RTCRestDataObject). */ + kTypeClass_AnyObject, /**< Any kind of object (RTCRestAnyObject). */ + kTypeClass_Array, /**< Array (containing any kind of object). */ + kTypeClass_StringMap, /**< String map (containing any kind of object). */ + kTypeClass_StringEnum /**< String enum. */ + } kTypeClass; + + /** + * Returns the object type class. + */ + virtual kTypeClass typeClass(void) const RT_NOEXCEPT = 0; + + /** + * Returns the object type name. + */ + virtual const char *typeName(void) const RT_NOEXCEPT = 0; + +protected: + /** Null indicator. + * @remarks The null values could be mapped onto C/C++ NULL pointer values, + * with the consequence that all data members in objects and such would + * have had to been allocated individually, even simple @a bool members. + * Given that we're overly paranoid about heap allocations (std::bad_alloc), + * it's more fitting to use a null indicator for us. + */ + bool m_fNullIndicator; +}; + + +/** + * Class wrapping 'bool'. + */ +class RT_DECL_CLASS RTCRestBool : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestBool() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestBool(RTCRestBool const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestBool(bool fValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestBool(); + /** Copy assignment operator. */ + RTCRestBool &operator=(RTCRestBool const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestBool const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(bool a_fValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestBool *clone() const RT_NOEXCEPT { return (RTCRestBool *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + bool m_fValue; +}; + + +/** + * Class wrapping 'int64_t'. + */ +class RT_DECL_CLASS RTCRestInt64 : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestInt64() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestInt64(RTCRestInt64 const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestInt64(int64_t a_iValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestInt64(); + /** Copy assignment operator. */ + RTCRestInt64 &operator=(RTCRestInt64 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestInt64 const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(int64_t a_iValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestInt64 *clone() const RT_NOEXCEPT { return (RTCRestInt64 *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + int64_t m_iValue; +}; + + +/** + * Class wrapping 'int32_t'. + */ +class RT_DECL_CLASS RTCRestInt32 : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestInt32() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestInt32(RTCRestInt32 const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestInt32(int32_t iValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestInt32() RT_NOEXCEPT; + /** Copy assignment operator. */ + RTCRestInt32 &operator=(RTCRestInt32 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestInt32 const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(int32_t a_iValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestInt32 *clone() const { return (RTCRestInt32 *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + int32_t m_iValue; +}; + + +/** + * Class wrapping 'int16_t'. + */ +class RT_DECL_CLASS RTCRestInt16 : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestInt16() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestInt16(RTCRestInt16 const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestInt16(int16_t iValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestInt16(); + /** Copy assignment operator. */ + RTCRestInt16 &operator=(RTCRestInt16 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestInt16 const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(int16_t a_iValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestInt16 *clone() const RT_NOEXCEPT { return (RTCRestInt16 *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + int16_t m_iValue; +}; + + +/** + * Class wrapping 'double'. + */ +class RT_DECL_CLASS RTCRestDouble : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestDouble() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestDouble(RTCRestDouble const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestDouble(double rdValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestDouble(); + /** Copy assignment operator. */ + RTCRestDouble &operator=(RTCRestDouble const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestDouble const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(double a_rdValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestDouble *clone() const RT_NOEXCEPT { return (RTCRestDouble *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + double m_rdValue; +}; + + +/** + * Class wrapping 'RTCString'. + */ +class RT_DECL_CLASS RTCRestString : public RTCRestObjectBase, public RTCString +{ +public: + /** Default constructor. */ + RTCRestString() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestString(); + + /** Copy constructor. */ + RTCRestString(RTCRestString const &a_rThat); + /** From value constructor. */ + RTCRestString(RTCString const &a_rThat); + /** From value constructor. */ + RTCRestString(const char *a_pszSrc); + /** Safe copy assignment method. */ + int assignCopy(RTCRestString const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCString const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(const char *a_pszThat) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestString *clone() const RT_NOEXCEPT { return (RTCRestString *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int setNull(void) RT_NOEXCEPT RT_OVERRIDE; /* (ambigious, so overrider it to make sure.) */ + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + + /** @name RTCString assignment methods we need to replace to manage the null indicator + * @{ */ + int assignNoThrow(const RTCString &a_rSrc) RT_NOEXCEPT; + int assignNoThrow(const char *a_pszSrc) RT_NOEXCEPT; + int assignNoThrow(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos) RT_NOEXCEPT; + int assignNoThrow(const char *a_pszSrc, size_t a_cchSrc) RT_NOEXCEPT; + int assignNoThrow(size_t a_cTimes, char a_ch) RT_NOEXCEPT; + int printfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + int printfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + RTCRestString &operator=(const char *a_pcsz); + RTCRestString &operator=(const RTCString &a_rThat); + RTCRestString &operator=(const RTCRestString &a_rThat); + RTCRestString &assign(const RTCString &a_rSrc); + RTCRestString &assign(const char *a_pszSrc); + RTCRestString &assign(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos); + RTCRestString &assign(const char *a_pszSrc, size_t a_cchSrc); + RTCRestString &assign(size_t a_cTimes, char a_ch); + RTCRestString &printf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + RTCRestString &printfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + /** @} */ +}; + + +/** + * Date class. + * + * There are numerous ways of formatting a timestamp and the specifications + * we're currently working with doesn't have a way of telling it seems. + * Thus, decoding need to have fail safes built in so the user can give hints. + * The formatting likewise needs to be told which format to use by the user. + * + * Two side-effects of the format stuff is that the default constructor creates + * an object that is null, and resetToDefault will do the same bug leave the + * format as a hint. + */ +class RT_DECL_CLASS RTCRestDate : public RTCRestObjectBase +{ +public: + /** Default constructor. + * @note The result is a null-object. */ + RTCRestDate() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestDate(RTCRestDate const &a_rThat); + /** Destructor. */ + virtual ~RTCRestDate(); + /** Copy assignment operator. */ + RTCRestDate &operator=(RTCRestDate const &a_rThat); + /** Safe copy assignment method. */ + int assignCopy(RTCRestDate const &a_rThat) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestDate *clone() const RT_NOEXCEPT{ return (RTCRestDate *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + + /** Date formats. */ + typedef enum + { + kFormat_Invalid = 0, + kFormat_Rfc2822, /**< Format it according to RFC-2822. */ + kFormat_Rfc7131, /**< Format it according to RFC-7131 (HTTP). */ + kFormat_Rfc3339, /**< Format it according to RFC-3339 (ISO-8601) (no fraction). */ + kFormat_Rfc3339_Fraction_2, /**< Format it according to RFC-3339 (ISO-8601) with two digit fraction (hundreths). */ + kFormat_Rfc3339_Fraction_3, /**< Format it according to RFC-3339 (ISO-8601) with three digit fraction (milliseconds). */ + kFormat_Rfc3339_Fraction_6, /**< Format it according to RFC-3339 (ISO-8601) with six digit fraction (microseconds). */ + kFormat_Rfc3339_Fraction_9, /**< Format it according to RFC-3339 (ISO-8601) with nine digit fraction (nanoseconds). */ + kFormat_End + } kFormat; + + /** + * Assigns the value, formats it as a string and clears the null indicator. + * + * @returns VINF_SUCCESS, VERR_NO_STR_MEMORY or VERR_INVALID_PARAMETER. + * @param a_pTimeSpec The time spec to set. + * @param a_enmFormat The date format to use when formatting it. + */ + int assignValue(PCRTTIMESPEC a_pTimeSpec, kFormat a_enmFormat) RT_NOEXCEPT; + int assignValueRfc2822(PCRTTIMESPEC a_pTimeSpec) RT_NOEXCEPT; /**< Convenience method for email/whatnot. */ + int assignValueRfc7131(PCRTTIMESPEC a_pTimeSpec) RT_NOEXCEPT; /**< Convenience method for HTTP date. */ + int assignValueRfc3339(PCRTTIMESPEC a_pTimeSpec) RT_NOEXCEPT; /**< Convenience method for ISO-8601 timstamp. */ + + /** + * Assigns the current UTC time and clears the null indicator . + * + * @returns VINF_SUCCESS, VERR_NO_STR_MEMORY or VERR_INVALID_PARAMETER. + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_enmFormat The date format to use when formatting it. + */ + int assignNow(kFormat a_enmFormat) RT_NOEXCEPT; + int assignNowRfc2822() RT_NOEXCEPT; /**< Convenience method for email/whatnot. */ + int assignNowRfc7131() RT_NOEXCEPT; /**< Convenience method for HTTP date. */ + int assignNowRfc3339() RT_NOEXCEPT; /**< Convenience method for ISO-8601 timstamp. */ + + /** + * Sets the format to help deal with decoding issues. + * + * This can also be used to change the date format for an okay timespec. + * @returns IPRT status code. + * @param a_enmFormat The date format to try/set. + */ + int setFormat(kFormat a_enmFormat) RT_NOEXCEPT; + + /** Check if the value is okay (m_TimeSpec & m_Exploded). */ + inline bool isOkay() const RT_NOEXCEPT { return m_fTimeSpecOkay; } + /** Get the timespec value. */ + inline RTTIMESPEC const &getTimeSpec() const RT_NOEXCEPT { return m_TimeSpec; } + /** Get the exploded time. */ + inline RTTIME const &getExploded() const RT_NOEXCEPT { return m_Exploded; } + /** Gets the format. */ + inline kFormat getFormat() const RT_NOEXCEPT { return m_enmFormat; } + /** Get the formatted/raw string value. */ + inline RTCString const &getString() const RT_NOEXCEPT { return m_strFormatted; } + + /** Get nanoseconds since unix epoch. */ + inline int64_t getEpochNano() const RT_NOEXCEPT { return RTTimeSpecGetNano(&m_TimeSpec); } + /** Get seconds since unix epoch. */ + inline int64_t getEpochSeconds() const RT_NOEXCEPT { return RTTimeSpecGetSeconds(&m_TimeSpec); } + /** Checks if UTC time. */ + inline bool isUtc() const RT_NOEXCEPT { return (m_Exploded.fFlags & RTTIME_FLAGS_TYPE_MASK) != RTTIME_FLAGS_TYPE_LOCAL; } + /** Checks if local time. */ + inline bool isLocal() const RT_NOEXCEPT { return (m_Exploded.fFlags & RTTIME_FLAGS_TYPE_MASK) == RTTIME_FLAGS_TYPE_LOCAL; } + +protected: + /** The value. */ + RTTIMESPEC m_TimeSpec; + /** The exploded time value. */ + RTTIME m_Exploded; + /** Set if m_TimeSpec is okay, consult m_strFormatted if not. */ + bool m_fTimeSpecOkay; + /** The format / format hint. */ + kFormat m_enmFormat; + /** The formatted date string. + * This will be the raw input string for a deserialized value, where as for + * a value set by the user it will be the formatted value. */ + RTCString m_strFormatted; + + /** + * Explodes and formats the m_TimeSpec value. + * + * Sets m_Exploded, m_strFormatted, m_fTimeSpecOkay, and m_enmFormat, clears m_fNullIndicator. + * + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_enmFormat The format to use. + */ + int explodeAndFormat(kFormat a_enmFormat) RT_NOEXCEPT; + + /** + * Formats the m_Exploded value. + * + * Sets m_strFormatted, m_fTimeSpecOkay, and m_enmFormat, clears m_fNullIndicator. + * + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_enmFormat The format to use. + */ + int format(kFormat a_enmFormat) RT_NOEXCEPT; + + /** + * Internal worker that attempts to decode m_strFormatted. + * + * Sets m_fTimeSpecOkay. + * + * @returns IPRT status code. + * @param enmFormat Specific format to try, kFormat_Invalid (default) to try guess it. + */ + int decodeFormattedString(kFormat enmFormat = kFormat_Invalid) RT_NOEXCEPT; +}; + + +/** We should provide a proper UUID class eventually. Currently it is not used. */ +typedef RTCRestString RTCRestUuid; + + +/** + * String enum base class. + */ +class RT_DECL_CLASS RTCRestStringEnumBase : public RTCRestObjectBase +{ +public: + /** Enum map entry. */ + typedef struct ENUMMAPENTRY + { + const char *pszName; + uint32_t cchName; + int32_t iValue; + } ENUMMAPENTRY; + + /** Default constructor. */ + RTCRestStringEnumBase() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestStringEnumBase(); + + /** Copy constructor. */ + RTCRestStringEnumBase(RTCRestStringEnumBase const &a_rThat); + /** Copy assignment operator. */ + RTCRestStringEnumBase &operator=(RTCRestStringEnumBase const &a_rThat); + + /** Safe copy assignment method. */ + int assignCopy(RTCRestStringEnumBase const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + inline int assignCopy(RTCString const &a_rThat) RT_NOEXCEPT { return setByString(a_rThat); } + /** Safe copy assignment method. */ + inline int assignCopy(const char *a_pszThat) RT_NOEXCEPT { return setByString(a_pszThat); } + + /* Overridden methods: */ + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** + * Sets the value given a C-string value. + * + * @retval VINF_SUCCESS on success. + * @retval VWRN_NOT_FOUND if not mappable to enum value. + * @retval VERR_NO_STR_MEMORY if not mappable and we're out of memory. + * @param a_pszValue The string value. + * @param a_cchValue The string value length. Optional. + */ + int setByString(const char *a_pszValue, size_t a_cchValue = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Sets the value given a string value. + * + * @retval VINF_SUCCESS on success. + * @retval VWRN_NOT_FOUND if not mappable to enum value. + * @retval VERR_NO_STR_MEMORY if not mappable and we're out of memory. + * @param a_rValue The string value. + */ + int setByString(RTCString const &a_rValue) RT_NOEXCEPT; + + /** + * Gets the string value. + */ + const char *getString() const RT_NOEXCEPT; + + /** Maps the given string value to an enum. */ + int stringToEnum(const char *a_pszValue, size_t a_cchValue = RTSTR_MAX) RT_NOEXCEPT; + /** Maps the given string value to an enum. */ + int stringToEnum(RTCString const &a_rStrValue) RT_NOEXCEPT; + /** Maps the given string value to an enum. */ + const char *enumToString(int a_iEnumValue, size_t *a_pcchString) RT_NOEXCEPT; + + +protected: + /** The enum value. */ + int m_iEnumValue; + /** The string value if not a match. */ + RTCString m_strValue; + + /** + * Worker for setting the object to the given enum value. + * + * @retval true on success. + * @retval false if a_iEnumValue can't be translated. + * @param a_iEnumValue The enum value to set. + */ + bool setWorker(int a_iEnumValue) RT_NOEXCEPT; + + /** Helper for implementing RTCRestObjectBase::clone(). */ + RTCRestObjectBase *cloneWorker(RTCRestStringEnumBase *a_pDst) const RT_NOEXCEPT; + + /** + * Gets the mapping table. + * + * @returns Pointer to the translation table. + * @param pcEntries Where to return the translation table size. + */ + virtual ENUMMAPENTRY const *getMappingTable(size_t *pcEntries) const RT_NOEXCEPT = 0; +}; + + +/** + * String enum template class. + * + * Takes the enum type as argument. + */ +template +class RTCRestStringEnum : public RTCRestStringEnumBase +{ +public: + typedef EnumType Type; /**< The enum type. */ + + /** Default constructor */ + RTCRestStringEnum() RT_NOEXCEPT : RTCRestStringEnumBase() { } + /** Constructor with initial enum value. */ + RTCRestStringEnum(Type a_enmValue) RT_NOEXCEPT : RTCRestStringEnumBase() { set(a_enmValue); } + /** Constructor with string default. */ + RTCRestStringEnum(const char *a_pszDefault) : RTCRestStringEnumBase() { setByString(a_pszDefault); } + /** Copy constructor */ + RTCRestStringEnum(RTCRestStringEnum const &a_rThat) : RTCRestStringEnumBase(a_rThat) { } + /** Make a clone of this object. */ + inline RTCRestStringEnum *clone() const RT_NOEXCEPT { return (RTCRestStringEnum *)baseClone(); } + + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE + { + return cloneWorker(new (std::nothrow) RTCRestStringEnum()); + } + + /** Copy assignment operator. */ + RTCRestStringEnum &operator=(RTCRestStringEnum const &a_rThat) RT_NOEXCEPT + { + RTCRestStringEnumBase::operator=(a_rThat); + return *this; + } + + /** + * Gets the enum value. + * @returns enum value. + * @retval kXxxxInvalid means there was no mapping for the string, or that + * no value has been assigned yet. + */ + Type get() const RT_NOEXCEPT { return (Type)m_iEnumValue; } + + /** + * Sets the object value to @a a_enmType + * + * @returns true if a_enmType is valid, false if not. + * @param a_enmType The new value. + */ + bool set(Type a_enmType) RT_NOEXCEPT { return setWorker((int)a_enmType); } + + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE { return "RTCRestStringEnum"; } + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) RTCRestStringEnum(); + } + + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT + { + *a_ppInstance = new (std::nothrow) RTCRestStringEnum(); + if (*a_ppInstance) + return (*a_ppInstance)->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); + } + +protected: + /** Enum mapping table. */ + static const ENUMMAPENTRY s_aMappingTable[]; + /** Enum mapping table size. */ + static const size_t s_cMappingTable; + + virtual ENUMMAPENTRY const *getMappingTable(size_t *pcEntries) const RT_NOEXCEPT RT_OVERRIDE + { + *pcEntries = s_cMappingTable; + return s_aMappingTable; + } +}; + + +/** + * Class for handling binary blobs (strings). + * + * There are specializations of this class for body parameters and responses, + * see RTCRestBinaryParameter and RTCRestBinaryResponse. + */ +class RT_DECL_CLASS RTCRestBinary : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestBinary() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestBinary(); + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinary const &a_rThat) RT_NOEXCEPT; + /** Safe buffer copy method. */ + virtual int assignCopy(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT; + + /** Use the specified data buffer directly. */ + virtual int assignReadOnly(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT; + /** Use the specified data buffer directly. */ + virtual int assignWriteable(void *a_pvBuf, size_t a_cbBuf) RT_NOEXCEPT; + /** Frees the data held by the object and resets it default state. */ + virtual void freeData() RT_NOEXCEPT; + + /** Returns a pointer to the data blob. */ + inline const uint8_t *getPtr() const RT_NOEXCEPT { return m_pbData; } + /** Gets the size of the data. */ + inline size_t getSize() const RT_NOEXCEPT { return m_cbData; } + + /** Make a clone of this object. */ + inline RTCRestBinary *clone() const RT_NOEXCEPT { return (RTCRestBinary *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int setNull(void) RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault(void) RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +protected: + /** Pointer to data blob. */ + uint8_t *m_pbData; + /** Amount of valid data in the blob. */ + size_t m_cbData; + /** Number of bytes allocated for the m_pbData buffer. */ + size_t m_cbAllocated; + /** Set if the data is freeable, only ever clear if user data. */ + bool m_fFreeable; + /** Set if the data blob is readonly user provided data. */ + bool m_fReadOnly; + +private: + /* No copy constructor or copy assignment: */ + RTCRestBinary(RTCRestBinary const &a_rThat); + RTCRestBinary &operator=(RTCRestBinary const &a_rThat); +}; + + +/** + * Abstract base class for REST data model classes. + */ +class RT_DECL_CLASS RTCRestDataObject : public RTCRestObjectBase +{ +public: + RTCRestDataObject() RT_NOEXCEPT; + RTCRestDataObject(RTCRestDataObject const &a_rThat) RT_NOEXCEPT; + virtual ~RTCRestDataObject(); + + /* Overridden methods:*/ + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** + * Serialize the object members as JSON. + * + * @returns a_rDst + * @param a_rDst The destination for the serialization. + */ + virtual RTCRestOutputBase &serializeMembersAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT; + + /** + * Deserialize object from the given JSON iterator. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if field is unknown. Top level caller will do + * invoke unknownField() on it. + * + * @param a_rCursor The JSON cursor with the current member. + * @param a_cchName The length of a_rCursor.m_pszName. + */ + virtual int deserializeMemberFromJson(RTCRestJsonCursor const &a_rCursor, size_t a_cchName) RT_NOEXCEPT; + +protected: + /** The is-set bits for all the fields. */ + uint64_t m_fIsSet; + + /** Copy assignment operator. */ + RTCRestDataObject &operator=(RTCRestDataObject const &a_rThat) RT_NOEXCEPT; + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestDataObject const &a_rThat) RT_NOEXCEPT; +}; + + +/** + * Abstract base class for polymorphic REST data model classes. + */ +class RT_DECL_CLASS RTCRestPolyDataObject : public RTCRestDataObject +{ +public: + RTCRestPolyDataObject() RT_NOEXCEPT; + RTCRestPolyDataObject(RTCRestPolyDataObject const &a_rThat) RT_NOEXCEPT; + virtual ~RTCRestPolyDataObject(); + + /* Overridden methods:*/ + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + + /** Checks if the instance is of a child class (@c true) or of the parent (@c false). */ + virtual bool isChild() const RT_NOEXCEPT; + +protected: + + /** Copy assignment operator. */ + RTCRestPolyDataObject &operator=(RTCRestPolyDataObject const &a_rThat) RT_NOEXCEPT; +}; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restbase_h */ + diff --git a/include/iprt/cpp/restclient.h b/include/iprt/cpp/restclient.h new file mode 100644 index 00000000..b62a89ea --- /dev/null +++ b/include/iprt/cpp/restclient.h @@ -0,0 +1,826 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Client Classes. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restclient_h +#define IPRT_INCLUDED_cpp_restclient_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @defgroup grp_rt_cpp_restclient C++ Representational State Transfer (REST) Client Classes. + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Specialization of RTCRestBinary for use with body parameters in a client. + * + * This enables registering data callbacks for provinding data to upload. + */ +class RT_DECL_CLASS RTCRestBinaryParameter : public RTCRestBinary +{ +public: + /** Default constructor. */ + RTCRestBinaryParameter() RT_NOEXCEPT; + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinaryParameter const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. + * @note Resets callbacks and ASSUMES that @a a_cbData is the content length. */ + virtual int assignCopy(RTCRestBinary const &a_rThat) RT_NOEXCEPT RT_OVERRIDE; + /** Safe copy assignment method. + * @note Resets callbacks and ASSUMES that @a a_cbData is the content length. */ + virtual int assignCopy(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Use the specified data buffer directly. + * @note Resets callbacks and ASSUMES that @a a_cbData is the content length. */ + virtual int assignReadOnly(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + /** + * Use the specified data buffer directly. + * @note This will assert and work like assignReadOnly. */ + virtual int assignWriteable(void *a_pvBuf, size_t a_cbBuf) RT_NOEXCEPT RT_OVERRIDE; + + /** Make a clone of this object. */ + inline RTCRestBinaryParameter *clone() const RT_NOEXCEPT { return (RTCRestBinaryParameter *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + + /** + * Retrieves the callback data. + */ + inline void *getCallbackData() const RT_NOEXCEPT { return m_pvCallbackData; } + + /** + * Sets the content-type for an upload. + * + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_pszContentType The content type to set. + * If NULL, no content type is set. + */ + int setContentType(const char *a_pszContentType) RT_NOEXCEPT; + + /** + * Gets the content type that was set. + */ + inline RTCString const &getContentType() const RT_NOEXCEPT { return m_strContentType; } + + /** + * Gets the content-length value (UINT64_MAX if not available). + */ + inline uint64_t getContentLength() const RT_NOEXCEPT { return m_cbContentLength; } + + /** + * Callback for producing bytes to upload. + * + * @returns IPRT status code. + * @param a_pThis The related string object. + * @param a_pvDst Where to put the bytes. + * @param a_cbDst Max number of bytes to produce. + * @param a_offContent The byte offset corresponding to the start of @a a_pvDst. + * @param a_pcbActual Where to return the number of bytes actually produced. + * + * @remarks Use getCallbackData to get the user data. + * + * @note The @a a_offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The value + * is the sum of the previously returned @a *pcbActual values. + */ + typedef DECLCALLBACKTYPE(int, FNPRODUCER,(RTCRestBinaryParameter *a_pThis, void *a_pvDst, size_t a_cbDst, + uint64_t a_offContent, size_t *a_pcbActual)) /*RT_NOEXCEPT*/; + /** Pointer to a byte producer callback. */ + typedef FNPRODUCER *PFNPRODUCER; + + /** + * Sets the producer callback. + * + * @param a_pfnProducer The callback function for producing data. + * @param a_pvCallbackData Data the can be retrieved from the callback + * using getCallbackData(). + * @param a_cbContentLength The amount of data that will be uploaded and + * to be set as the value of the content-length + * header field. Pass UINT64_MAX if not known. + * + * @note This will drop any buffer previously registered using setUploadData(). + */ + void setProducerCallback(PFNPRODUCER a_pfnProducer, void *a_pvCallbackData = NULL, uint64_t a_cbContentLength = UINT64_MAX) RT_NOEXCEPT; + + /** + * Preprares transmission via the @a a_hHttp client instance. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @internal + */ + virtual int xmitPrepare(RTHTTP a_hHttp) const RT_NOEXCEPT; + + /** + * For completing and/or undoing setup from xmitPrepare. + * + * @param a_hHttp The HTTP client instance. + * @internal + */ + virtual void xmitComplete(RTHTTP a_hHttp) const RT_NOEXCEPT; + +protected: + /** Number of bytes corresponding to content-length. + * UINT64_MAX if not known. Used both for unploads and downloads. */ + uint64_t m_cbContentLength; + /** The content type if set (upload only). */ + RTCString m_strContentType; + /** Pointer to user-registered producer callback function (upload only). */ + PFNPRODUCER m_pfnProducer; + /** User argument for both callbacks (both). */ + void *m_pvCallbackData; + + /** @copydoc FNRTHTTPUPLOADCALLBACK */ + static DECLCALLBACK(int) xmitHttpCallback(RTHTTP hHttp, void *pvBuf, size_t cbBuf, uint64_t offContent, + size_t *pcbActual, void *pvUser) RT_NOEXCEPT; + +private: + /* No copy constructor or copy assignment: */ + RTCRestBinaryParameter(RTCRestBinaryParameter const &a_rThat); + RTCRestBinaryParameter &operator=(RTCRestBinaryParameter const &a_rThat); +}; + + +/** + * Specialization of RTCRestBinary for use with responses in a client. + * + * This enables registering data callbacks for consuming downloaded data. + */ +class RT_DECL_CLASS RTCRestBinaryResponse : public RTCRestBinary +{ +public: + /** Default constructor. */ + RTCRestBinaryResponse() RT_NOEXCEPT; + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinaryResponse const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinary const &a_rThat) RT_NOEXCEPT RT_OVERRIDE; + /** Safe copy assignment method. + * @note This will assert and fail as it makes no sense for a download. */ + virtual int assignCopy(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Use the specified data buffer directly. + * @note This will assert and fail as it makes no sense for a download. + */ + virtual int assignReadOnly(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + /** + * Use the specified data buffer directly. + * @note This will drop any previously registered producer callback and user data. + */ + virtual int assignWriteable(void *a_pvBuf, size_t a_cbBuf) RT_NOEXCEPT RT_OVERRIDE; + + /** Make a clone of this object. */ + inline RTCRestBinaryResponse *clone() const RT_NOEXCEPT { return (RTCRestBinaryResponse *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + + /** + * Retrieves the callback data. + */ + inline void *getCallbackData() const RT_NOEXCEPT { return m_pvCallbackData; } + + /** + * Sets the max size to download to memory. + * + * This also indicates the intention to download to a memory buffer, so it + * will drop any previously registered consumer callback and its user data. + * + * @param a_cbMaxDownload Maximum number of bytes to download to memory. + * If 0, a default is selected (currently 32MiB for + * 32-bit hosts and 128MiB for 64-bit). + */ + void setMaxDownloadSize(size_t a_cbMaxDownload) RT_NOEXCEPT; + + /** + * Gets the content-length value (UINT64_MAX if not available). + */ + inline uint64_t getContentLength() const RT_NOEXCEPT { return m_cbContentLength; } + + /** + * Callback for consuming downloaded bytes. + * + * @returns IPRT status code. + * @param a_pThis The related string object. + * @param a_pvSrc Buffer containing the bytes. + * @param a_cbSrc The number of bytes in the buffer. + * @param a_uHttpStatus The HTTP status code. + * @param a_offContent The byte offset corresponding to the start of @a a_pvSrc. + * @param a_cbContent The content length field value, UINT64_MAX if not available. + * + * @remarks Use getCallbackData to get the user data. + * + * @note The @a a_offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The value + * is the sum of the previous @a a_cbSrc values. + */ + typedef DECLCALLBACKTYPE(int, FNCONSUMER,(RTCRestBinaryResponse *a_pThis, const void *a_pvSrc, size_t a_cbSrc, + uint32_t a_uHttpStatus, uint64_t a_offContent, uint64_t a_cbContent)) /*RT_NOEXCEPT*/; + /** Pointer to a byte consumer callback. */ + typedef FNCONSUMER *PFNCONSUMER; + + /** + * Sets the consumer callback. + * + * @param a_pfnConsumer The callback function for consuming downloaded data. + * NULL if data should be stored in m_pbData (the default). + * @param a_pvCallbackData Data the can be retrieved from the callback + * using getCallbackData(). + */ + void setConsumerCallback(PFNCONSUMER a_pfnConsumer, void *a_pvCallbackData = NULL) RT_NOEXCEPT; + + /** + * Preprares for receiving via the @a a_hHttp client instance. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @param a_fCallbackFlags The HTTP callback flags (status code spec). + * @internal + */ + virtual int receivePrepare(RTHTTP a_hHttp, uint32_t a_fCallbackFlags) RT_NOEXCEPT; + + /** + * For completing and/or undoing setup from receivePrepare. + * + * @param a_hHttp The HTTP client instance. + * @internal + */ + virtual void receiveComplete(RTHTTP a_hHttp) RT_NOEXCEPT; + +protected: + /** Number of bytes corresponding to content-length. + * UINT64_MAX if not known. Used both for unploads and downloads. */ + uint64_t m_cbContentLength; + /** Number of bytes downloaded thus far. */ + uint64_t m_cbDownloaded; + /** Pointer to user-registered consumer callback function (download only). */ + PFNCONSUMER m_pfnConsumer; + /** User argument for both callbacks (both). */ + void *m_pvCallbackData; + /** Maximum data to download to memory (download only). */ + size_t m_cbMaxDownload; + + /** @copydoc FNRTHTTPDOWNLOADCALLBACK */ + static DECLCALLBACK(int) receiveHttpCallback(RTHTTP hHttp, void const *pvBuf, size_t cbBuf, uint32_t uHttpStatus, + uint64_t offContent, uint64_t cbContent, void *pvUser) RT_NOEXCEPT; + +private: + /* No copy constructor or copy assignment: */ + RTCRestBinaryResponse(RTCRestBinaryResponse const &a_rThat); + RTCRestBinaryResponse &operator=(RTCRestBinaryResponse const &a_rThat); +}; + + +/** + * Base class for REST client requests. + * + * This encapsulates parameters and helps transform them into a HTTP request. + * + * Parameters can be transfered in a number of places: + * - Path part of the URL. + * - Query part of the URL. + * - HTTP header fields. + * - FORM body. + * - JSON body. + * - XML body. + * - ... + * + * They can be require or optional. The latter may have default values. In + * swagger 3 they can also be nullable, which means the null-indicator cannot + * be used for tracking optional parameters. + */ +class RT_DECL_CLASS RTCRestClientRequestBase +{ +public: + RTCRestClientRequestBase() RT_NOEXCEPT; + virtual ~RTCRestClientRequestBase(); + RTCRestClientRequestBase(RTCRestClientRequestBase const &a_rThat) RT_NOEXCEPT; + RTCRestClientRequestBase &operator=(RTCRestClientRequestBase const &a_rThat) RT_NOEXCEPT; + + /** + * Reset all members to default values. + * @returns IPRT status code. + */ + virtual int resetToDefault() RT_NOEXCEPT = 0; + + /** + * Getter for the operation name. Provided by the generated + * subclasses so that base class code may use it for more + * informative logs. + */ + virtual const char *getOperationName() const RT_NOEXCEPT = 0; + + /** + * Prepares the HTTP handle for transmitting this request. + * + * @returns IPRT status code. + * @param a_pStrPath Where to set path parameters. Will be appended to the base path. + * @param a_pStrQuery Where to set query parameters. + * @param a_hHttp Where to set header parameters and such. + * @param a_pStrBody Where to set body parameters. + */ + virtual int xmitPrepare(RTCString *a_pStrPath, RTCString *a_pStrQuery, RTHTTP a_hHttp, RTCString *a_pStrBody) const RT_NOEXCEPT = 0; + + /** + * Always called after the request has been transmitted. + * + * @param a_rcStatus Negative numbers are IPRT errors, positive are HTTP status codes. + * @param a_hHttp The HTTP handle the request was performed on. + */ + virtual void xmitComplete(int a_rcStatus, RTHTTP a_hHttp) const RT_NOEXCEPT = 0; + + /** + * Checks if there are were any assignment errors. + */ + inline bool hasAssignmentErrors() const RT_NOEXCEPT { return m_fErrorSet != 0; } + +protected: + /** Set of fields that have been explicitly assigned a value. */ + uint64_t m_fIsSet; + /** Set of fields where value assigning failed. */ + uint64_t m_fErrorSet; + + /** Path parameter descriptor. */ + typedef struct + { + const char *pszName; /**< The name string to replace (including {}). */ + size_t cchName; /**< Length of pszName. */ + uint32_t fFlags; /**< The toString flags. */ + uint8_t iBitNo; /**< The parameter bit number. */ + } PATHPARAMDESC; + + /** Path parameter state. */ + typedef struct + { + RTCRestObjectBase const *pObj; /**< Pointer to the parameter object. */ + size_t offName; /**< Maintained by worker. */ + } PATHPARAMSTATE; + + /** + * Do path parameters. + * + * @returns IPRT status code + * @param a_pStrPath The destination path. + * @param a_pszPathTemplate The path template string. + * @param a_cchPathTemplate The length of the path template string. + * @param a_paPathParams The path parameter descriptors (static). + * @param a_paPathParamStates The path parameter objects and states. + * @param a_cPathParams Number of path parameters. + */ + int doPathParameters(RTCString *a_pStrPath, const char *a_pszPathTemplate, size_t a_cchPathTemplate, + PATHPARAMDESC const *a_paPathParams, PATHPARAMSTATE *a_paPathParamStates, size_t a_cPathParams) const RT_NOEXCEPT; + + /** Query parameter descriptor. */ + typedef struct + { + const char *pszName; /**< The parameter name. */ + uint32_t fFlags; /**< The toString flags. */ + bool fRequired; /**< Required or not. */ + uint8_t iBitNo; /**< The parameter bit number. */ + } QUERYPARAMDESC; + + /** + * Do query parameters. + * + * @returns IPRT status code + * @param a_pStrQuery The destination string. + * @param a_paQueryParams The query parameter descriptors. + * @param a_papQueryParamObjs The query parameter objects, parallel to @a a_paQueryParams. + * @param a_cQueryParams Number of query parameters. + */ + int doQueryParameters(RTCString *a_pStrQuery, QUERYPARAMDESC const *a_paQueryParams, + RTCRestObjectBase const **a_papQueryParamObjs, size_t a_cQueryParams) const RT_NOEXCEPT; + + /** Header parameter descriptor. */ + typedef struct + { + const char *pszName; /**< The parameter name. */ + uint32_t fFlags; /**< The toString flags. */ + bool fRequired; /**< Required or not. */ + uint8_t iBitNo; /**< The parameter bit number. */ + bool fMapCollection; /**< Collect headers starting with pszName into a map. */ + } HEADERPARAMDESC; + + /** + * Do header parameters. + * + * @returns IPRT status code + * @param a_hHttp Where to set header parameters. + * @param a_paHeaderParams The header parameter descriptors. + * @param a_papHeaderParamObjs The header parameter objects, parallel to @a a_paHeaderParams. + * @param a_cHeaderParams Number of header parameters. + */ + int doHeaderParameters(RTHTTP a_hHttp, HEADERPARAMDESC const *a_paHeaderParams, + RTCRestObjectBase const **a_papHeaderParamObjs, size_t a_cHeaderParams) const RT_NOEXCEPT; +}; + + +/** + * Base class for REST client responses. + */ +class RT_DECL_CLASS RTCRestClientResponseBase +{ +public: + /** Default constructor. */ + RTCRestClientResponseBase() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestClientResponseBase(); + /** Copy constructor. */ + RTCRestClientResponseBase(RTCRestClientResponseBase const &a_rThat); + /** Copy assignment operator. */ + RTCRestClientResponseBase &operator=(RTCRestClientResponseBase const &a_rThat); + + /** + * Resets the object state. + */ + virtual void reset(void) RT_NOEXCEPT; + + /** + * Getter for the operation name. Provided by the generated + * subclasses so that base class code may use it for more + * informative logs. + */ + virtual const char *getOperationName() const RT_NOEXCEPT = 0; + + /** + * Prepares the HTTP handle for receiving the response. + * + * This may install callbacks and such like. + * + * When overridden, the parent class must always be called. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP handle to prepare for receiving. + */ + virtual int receivePrepare(RTHTTP a_hHttp) RT_NOEXCEPT; + + /** + * Called when the HTTP request has been completely received. + * + * @param a_rcStatus Negative numbers are IPRT errors, positive are HTTP status codes. + * @param a_hHttp The HTTP handle the request was performed on. + * This can be NIL_RTHTTP should something fail early, in + * which case it is possible receivePrepare() wasn't called. + * + * @note Called before consumeBody() but after consumeHeader(). + */ + virtual void receiveComplete(int a_rcStatus, RTHTTP a_hHttp) RT_NOEXCEPT; + + /** + * Callback that consumes HTTP body data from the server. + * + * @param a_pchData Body data. + * @param a_cbData Amount of body data. + * + * @note Called after consumeHeader(). + */ + virtual void consumeBody(const char *a_pchData, size_t a_cbData) RT_NOEXCEPT; + + /** + * Called after status, headers and body all have been presented. + * + * @returns IPRT status code. + */ + virtual void receiveFinal() RT_NOEXCEPT; + + /** + * Getter for m_rcStatus. + * @returns Negative numbers are IPRT errors, positive are HTTP status codes. + */ + inline int getStatus() const RT_NOEXCEPT { return m_rcStatus; } + + /** + * Getter for m_rcHttp. + * @returns HTTP status code or VERR_NOT_AVAILABLE. + */ + inline int getHttpStatus() const RT_NOEXCEPT { return m_rcHttp; } + + /** + * Getter for m_pErrInfo. + */ + inline PCRTERRINFO getErrInfo(void) const RT_NOEXCEPT { return m_pErrInfo; } + + /** + * Getter for m_strContentType. + */ + inline RTCString const &getContentType(void) const RT_NOEXCEPT { return m_strContentType; } + + +protected: + /** Negative numbers are IPRT errors, positive are HTTP status codes. */ + int m_rcStatus; + /** The HTTP status code, VERR_NOT_AVAILABLE if not set. */ + int m_rcHttp; + /** Error information. */ + PRTERRINFO m_pErrInfo; + /** The value of the Content-Type header field. */ + RTCString m_strContentType; + + PRTERRINFO getErrInfoInternal(void) RT_NOEXCEPT; + void deleteErrInfo(void) RT_NOEXCEPT; + void copyErrInfo(PCRTERRINFO pErrInfo) RT_NOEXCEPT; + + /** + * Reports an error (or warning if a_rc non-negative). + * + * @returns a_rc + * @param a_rc The status code to report and return. The first + * error status is assigned to m_rcStatus, subsequent + * ones as well as informational statuses are not + * recorded by m_rcStatus. + * @param a_pszFormat The message format string. + * @param ... Message arguments. + */ + int addError(int a_rc, const char *a_pszFormat, ...) RT_NOEXCEPT; + + /** + * Deserializes a header field value. + * + * @returns IPRT status code. + * @param a_pObj The object to deserialize into. + * @param a_pchValue Pointer to the value (not zero terminated). + * Not necessarily valid UTF-8! + * @param a_cchValue The value length. + * @param a_fFlags Flags to pass to fromString(). + * @param a_pszErrorTag The error tag (field name). + */ + int deserializeHeader(RTCRestObjectBase *a_pObj, const char *a_pchValue, size_t a_cchValue, + uint32_t a_fFlags, const char *a_pszErrorTag) RT_NOEXCEPT; + + /** + * Deserializes a header field value. + * + * @returns IPRT status code. + * @param a_pMap The string map object to deserialize into. + * @param a_pchField Pointer to the map field name. (Caller dropped the prefix.) + * Not necessarily valid UTF-8! + * @param a_cchField Length of field name. + * @param a_pchValue Pointer to the value (not zero terminated). + * Not necessarily valid UTF-8! + * @param a_cchValue The value length. + * @param a_fFlags Flags to pass to fromString(). + * @param a_pszErrorTag The error tag (field name). + */ + int deserializeHeaderIntoMap(RTCRestStringMapBase *a_pMap, const char *a_pchField, size_t a_cchField, + const char *a_pchValue, size_t a_cchValue, uint32_t a_fFlags, const char *a_pszErrorTag) RT_NOEXCEPT; + + /** + * Helper that does the deserializing of the response body + * via deserializeBodyFromJsonCursor(). + * + * @param a_pchData The body blob. + * @param a_cbData The size of the body blob. + * @param a_pszBodyName The name of the body parameter. + */ + void deserializeBody(const char *a_pchData, size_t a_cbData, const char *a_pszBodyName) RT_NOEXCEPT; + + /** + * Called by deserializeBody to do the actual body deserialization. + * + * @param a_rCursor The JSON cursor. + */ + virtual void deserializeBodyFromJsonCursor(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT; + + /** + * Primary json cursor for parsing bodies. + */ + class PrimaryJsonCursorForBody : public RTCRestJsonPrimaryCursor + { + public: + RTCRestClientResponseBase *m_pThat; /**< Pointer to response object. */ + PrimaryJsonCursorForBody(RTJSONVAL hValue, const char *pszName, RTCRestClientResponseBase *a_pThat) RT_NOEXCEPT; + virtual int addError(RTCRestJsonCursor const &a_rCursor, int a_rc, const char *a_pszFormat, ...) RT_NOEXCEPT RT_OVERRIDE; + virtual int unknownField(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + }; + + + /** + * Consumes a header. + * + * Child classes can override this to pick up their header fields, but must + * always call the parent class. + * + * @returns IPRT status code. + * @param a_uMatchWord Match word constructed by RTHTTP_MAKE_HDR_MATCH_WORD + * @param a_pchField The field name (not zero terminated). + * Not necessarily valid UTF-8! + * @param a_cchField The length of the field. + * @param a_pchValue The field value (not zero terminated). + * @param a_cchValue The length of the value. + */ + virtual int consumeHeader(uint32_t a_uMatchWord, const char *a_pchField, size_t a_cchField, + const char *a_pchValue, size_t a_cchValue) RT_NOEXCEPT; + +private: + /** Callback for use with RTHttpSetHeaderCallback. */ + static DECLCALLBACK(int) receiveHttpHeaderCallback(RTHTTP hHttp, uint32_t uMatchWord, const char *pchField, size_t cchField, + const char *pchValue, size_t cchValue, void *pvUser) RT_NOEXCEPT; +}; + + +/** + * Base class for REST client responses. + */ +class RT_DECL_CLASS RTCRestClientApiBase +{ +public: + RTCRestClientApiBase() RT_NOEXCEPT; + virtual ~RTCRestClientApiBase(); + + /** @name Host and Base path (URL) handling. + * @{ */ + /** + * Gets the server URL. + */ + const char *getServerUrl(void) const RT_NOEXCEPT; + + /** + * Sets the whole server URL. + * @returns IPRT status code. + * @param a_pszUrl The new server URL. NULL/empty to reset to default. + */ + int setServerUrl(const char *a_pszUrl) RT_NOEXCEPT; + + /** + * Sets the scheme part of the the server URL. + * @returns IPRT status code. + * @param a_pszScheme The new scheme. Does not accept NULL or empty string. + */ + int setServerScheme(const char *a_pszScheme) RT_NOEXCEPT; + + /** + * Sets the authority (hostname + port) part of the the server URL. + * @returns IPRT status code. + * @param a_pszAuthority The new authority. Does not accept NULL or empty string. + */ + int setServerAuthority(const char *a_pszAuthority) RT_NOEXCEPT; + + /** + * Sets the base path part of the the server URL. + * @returns IPRT status code. + * @param a_pszBasePath The new base path. Does not accept NULL or empty string. + */ + int setServerBasePath(const char *a_pszBasePath) RT_NOEXCEPT; + + /** + * Gets the default server URL as specified in the specs. + * @returns Server URL. + */ + virtual const char *getDefaultServerUrl() const RT_NOEXCEPT = 0; + + /** + * Gets the default server base path as specified in the specs. + * @returns Host string (start of URL). + */ + virtual const char *getDefaultServerBasePath() const RT_NOEXCEPT = 0; + /** @} */ + + /** + * Sets the CA file to use for HTTPS. + */ + int setCAFile(const char *pcszCAFile) RT_NOEXCEPT; + /** @overload */ + int setCAFile(const RTCString &strCAFile) RT_NOEXCEPT; + + /** Flags to doCall. */ + enum + { + kDoCall_OciReqSignExcludeBody = 1, /**< Exclude the body when doing OCI request signing. */ + kDoCall_RequireBody = 2 /**< The body is required. */ + }; + +protected: + /** Handle to the HTTP connection object. */ + RTHTTP m_hHttp; + /** The server URL to use. If empty use the default. */ + RTCString m_strServerUrl; + /** The CA file to use. If empty use the default. */ + RTCString m_strCAFile; + + /* Make non-copyable (RTCNonCopyable causes warnings): */ + RTCRestClientApiBase(RTCRestClientApiBase const &); + RTCRestClientApiBase *operator=(RTCRestClientApiBase const &); + + /** + * Re-initializes the HTTP instance. + * + * @returns IPRT status code. + */ + virtual int reinitHttpInstance() RT_NOEXCEPT; + + /** + * Hook that's called when doCall has fully assembled the request. + * + * Can be used for request signing and similar final steps. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @param a_rStrFullUrl The full URL. + * @param a_enmHttpMethod The HTTP request method. + * @param a_rStrXmitBody The body text. + * @param a_fFlags kDoCall_XXX. + */ + virtual int xmitReady(RTHTTP a_hHttp, RTCString const &a_rStrFullUrl, RTHTTPMETHOD a_enmHttpMethod, + RTCString const &a_rStrXmitBody, uint32_t a_fFlags) RT_NOEXCEPT; + + /** + * Implements stuff for making an API call. + * + * @returns a_pResponse->getStatus() + * @param a_rRequest Reference to the request object. + * @param a_enmHttpMethod The HTTP request method. + * @param a_pResponse Pointer to the response object. + * @param a_pszMethod The method name, for logging purposes. + * @param a_fFlags kDoCall_XXX. + */ + virtual int doCall(RTCRestClientRequestBase const &a_rRequest, RTHTTPMETHOD a_enmHttpMethod, + RTCRestClientResponseBase *a_pResponse, const char *a_pszMethod, uint32_t a_fFlags) RT_NOEXCEPT; + + /** + * Implements OCI style request signing. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @param a_rStrFullUrl The full URL. + * @param a_enmHttpMethod The HTTP request method. + * @param a_rStrXmitBody The body text. + * @param a_fFlags kDoCall_XXX. + * @param a_hKey The key to use for signing. + * @param a_rStrKeyId The key ID. + * + * @remarks The signing scheme is covered by a series of drafts RFC, the latest being: + * https://tools.ietf.org/html/draft-cavage-http-signatures-10 + */ + int ociSignRequest(RTHTTP a_hHttp, RTCString const &a_rStrFullUrl, RTHTTPMETHOD a_enmHttpMethod, + RTCString const &a_rStrXmitBody, uint32_t a_fFlags, RTCRKEY a_hKey, RTCString const &a_rStrKeyId) RT_NOEXCEPT; + + /** + * Worker for the server URL modifiers. + * + * @returns IPRT status code. + * @param a_pszServerUrl The current server URL (for comparing). + * @param a_offDst The offset of the component in the current server URL. + * @param a_cchDst The current component length. + * @param a_pszSrc The new URL component value. + * @param a_cchSrc The length of the new component. + */ + int setServerUrlPart(const char *a_pszServerUrl, size_t a_offDst, size_t a_cchDst, const char *a_pszSrc, size_t a_cchSrc) RT_NOEXCEPT; +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restclient_h */ + diff --git a/include/iprt/cpp/restoutput.h b/include/iprt/cpp/restoutput.h new file mode 100644 index 00000000..2f2c57d5 --- /dev/null +++ b/include/iprt/cpp/restoutput.h @@ -0,0 +1,280 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Output Classes. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restoutput_h +#define IPRT_INCLUDED_cpp_restoutput_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +/** @defgroup grp_rt_cpp_restoutput C++ Representational State Transfer (REST) Output Classes. + * @ingroup grp_rt_cpp + * @{ + */ + + +/** + * Abstract base class for serializing data objects. + */ +class RT_DECL_CLASS RTCRestOutputBase +{ +public: + RTCRestOutputBase() RT_NOEXCEPT; + virtual ~RTCRestOutputBase(); + + /** + * Raw output function. + * + * @returns Number of bytes outputted. + * @param a_pchString The string to output (not necessarily terminated). + * @param a_cchToWrite The length of the string + */ + virtual size_t output(const char *a_pchString, size_t a_cchToWrite) RT_NOEXCEPT = 0; + + /** + * RTStrPrintf like function (see @ref pg_rt_str_format). + * + * @returns Number of bytes outputted. + * @param pszFormat The format string. + * @param ... Argument specfied in @a pszFormat. + */ + inline size_t printf(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(2, 3) + { + va_list va; + va_start(va, pszFormat); + size_t cchWritten = this->vprintf(pszFormat, va); + va_end(va); + return cchWritten; + } + + /** + * RTStrPrintfV like function (see @ref pg_rt_str_format). + * + * @returns Number of bytes outputted. + * @param pszFormat The format string. + * @param va Argument specfied in @a pszFormat. + */ + size_t vprintf(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(2, 0); + + /** + * Begins an array. + * @returns Previous output state. Pass to endArray() when done. + */ + virtual uint32_t beginArray() RT_NOEXCEPT; + + /** + * Ends an array. + * @param a_uOldState Previous output state (returned by beginArray()). + */ + virtual void endArray(uint32_t a_uOldState) RT_NOEXCEPT; + + /** + * Begins an object. + * @returns Previous output state. Pass to endObject() when done. + */ + virtual uint32_t beginObject() RT_NOEXCEPT; + + /** + * Ends an array. + * @param a_uOldState Previous output state (returned by beginObject()). + */ + virtual void endObject(uint32_t a_uOldState) RT_NOEXCEPT; + + /** + * Outputs a value separator. + * This is called before a value, not after. + */ + virtual void valueSeparator() RT_NOEXCEPT; + + /** + * Outputs a value separator, name and name separator. + */ + virtual void valueSeparatorAndName(const char *a_pszName, size_t a_cchName) RT_NOEXCEPT; + + /** Outputs a null-value. */ + void nullValue() RT_NOEXCEPT; + +protected: + /** The current indentation level (bits 15:0) and separator state (bit 31). */ + uint32_t m_uState; + + /** @callback_method_impl{FNRTSTROUTPUT} */ + static DECLCALLBACK(size_t) printfOutputCallback(void *pvArg, const char *pachChars, size_t cbChars) RT_NOEXCEPT; +}; + + +/** + * Abstract base class for pretty output. + */ +class RT_DECL_CLASS RTCRestOutputPrettyBase : public RTCRestOutputBase +{ +public: + RTCRestOutputPrettyBase() RT_NOEXCEPT; + virtual ~RTCRestOutputPrettyBase(); + + /** + * Begins an array. + * @returns Previous output state. Pass to endArray() when done. + */ + virtual uint32_t beginArray() RT_NOEXCEPT RT_OVERRIDE; + + /** + * Ends an array. + * @param a_uOldState Previous output state (returned by beginArray()). + */ + virtual void endArray(uint32_t a_uOldState) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Begins an object. + * @returns Previous output state. Pass to endObject() when done. + */ + virtual uint32_t beginObject() RT_NOEXCEPT RT_OVERRIDE; + + /** + * Ends an array. + * @param a_uOldState Previous output state (returned by beginObject()). + */ + virtual void endObject(uint32_t a_uOldState) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Outputs a value separator. + * This is called before a value, not after. + */ + virtual void valueSeparator() RT_NOEXCEPT RT_OVERRIDE; + + /** + * Outputs a value separator, name and name separator. + */ + virtual void valueSeparatorAndName(const char *a_pszName, size_t a_cchName) RT_NOEXCEPT RT_OVERRIDE; + +protected: + /** Helper for outputting the correct amount of indentation. */ + void outputIndentation() RT_NOEXCEPT; +}; + + +/** + * Serialize to a string object. + */ +class RT_DECL_CLASS RTCRestOutputToString : public RTCRestOutputBase +{ +public: + /** + * Creates an instance that appends to @a a_pDst. + * @param a_pDst Pointer to the destination string object. + * NULL is not accepted and will assert. + * @param a_fAppend Whether to append to the current string value, or + * nuke the string content before starting the output. + */ + RTCRestOutputToString(RTCString *a_pDst, bool a_fAppend = false) RT_NOEXCEPT; + virtual ~RTCRestOutputToString(); + + virtual size_t output(const char *a_pchString, size_t a_cchToWrite) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Finalizes the output and releases the string object to the caller. + * + * @returns The released string object. NULL if we ran out of memory or if + * called already. + * + * @remark This sets m_pDst to NULL and the object cannot be use for any + * more output afterwards. + */ + virtual RTCString *finalize() RT_NOEXCEPT; + +protected: + /** Pointer to the destination string. NULL after finalize(). */ + RTCString *m_pDst; + /** Set if we ran out of memory and should ignore subsequent calls. */ + bool m_fOutOfMemory; + + /* Make non-copyable (RTCNonCopyable causes warnings): */ + RTCRestOutputToString(RTCRestOutputToString const &); + RTCRestOutputToString *operator=(RTCRestOutputToString const &); +}; + + +/** + * Serialize pretty JSON to a string object. + */ +class RT_DECL_CLASS RTCRestOutputPrettyToString : public RTCRestOutputPrettyBase +{ +public: + /** + * Creates an instance that appends to @a a_pDst. + * @param a_pDst Pointer to the destination string object. + * NULL is not accepted and will assert. + * @param a_fAppend Whether to append to the current string value, or + * nuke the string content before starting the output. + */ + RTCRestOutputPrettyToString(RTCString *a_pDst, bool a_fAppend = false) RT_NOEXCEPT; + virtual ~RTCRestOutputPrettyToString(); + + virtual size_t output(const char *a_pchString, size_t a_cchToWrite) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Finalizes the output and releases the string object to the caller. + * + * @returns The released string object. NULL if we ran out of memory or if + * called already. + * + * @remark This sets m_pDst to NULL and the object cannot be use for any + * more output afterwards. + */ + virtual RTCString *finalize() RT_NOEXCEPT; + +protected: + /** Pointer to the destination string. NULL after finalize(). */ + RTCString *m_pDst; + /** Set if we ran out of memory and should ignore subsequent calls. */ + bool m_fOutOfMemory; + + /* Make non-copyable (RTCNonCopyable causes warnings): */ + RTCRestOutputPrettyToString(RTCRestOutputToString const &); + RTCRestOutputPrettyToString *operator=(RTCRestOutputToString const &); +}; + + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restoutput_h */ + diff --git a/include/iprt/cpp/reststringmap.h b/include/iprt/cpp/reststringmap.h new file mode 100644 index 00000000..cff201bb --- /dev/null +++ b/include/iprt/cpp/reststringmap.h @@ -0,0 +1,499 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) String Map Template. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_reststringmap_h +#define IPRT_INCLUDED_cpp_reststringmap_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @defgroup grp_rt_cpp_reststingmap C++ Representational State Transfer (REST) String Map Template + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Abstract base class for the RTCRestStringMap template. + */ +class RT_DECL_CLASS RTCRestStringMapBase : public RTCRestObjectBase +{ +public: + /** Default destructor. */ + RTCRestStringMapBase() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestStringMapBase(RTCRestStringMapBase const &a_rThat); + /** Destructor. */ + virtual ~RTCRestStringMapBase(); + /** Copy assignment operator. */ + RTCRestStringMapBase &operator=(RTCRestStringMapBase const &a_rThat); + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + // later? + //virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + //virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + // uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** + * Clear the content of the map. + */ + void clear() RT_NOEXCEPT; + + /** + * Checks if the map is empty. + */ + inline bool isEmpty() const RT_NOEXCEPT { return m_cEntries == 0; } + + /** + * Gets the number of entries in the map. + */ + size_t size() const RT_NOEXCEPT; + + /** + * Checks if the map contains the given key. + * @returns true if key found, false if not. + * @param a_pszKey The key to check fo. + */ + bool containsKey(const char *a_pszKey) const RT_NOEXCEPT; + + /** + * Checks if the map contains the given key. + * @returns true if key found, false if not. + * @param a_rStrKey The key to check fo. + */ + bool containsKey(RTCString const &a_rStrKey) const RT_NOEXCEPT; + + /** + * Remove any key-value pair with the given key. + * @returns true if anything was removed, false if not found. + * @param a_pszKey The key to remove. + */ + bool remove(const char *a_pszKey) RT_NOEXCEPT; + + /** + * Remove any key-value pair with the given key. + * @returns true if anything was removed, false if not found. + * @param a_rStrKey The key to remove. + */ + bool remove(RTCString const &a_rStrKey) RT_NOEXCEPT; + + /** + * Creates a new value and inserts it under the given key, returning the new value. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_ppValue Where to return the pointer to the value. + * @param a_pszKey The key to put it under. + * @param a_cchKey The length of the key. Default is the entire string. + * @param a_fReplace Whether to replace or fail on key collision. + */ + int putNewValue(RTCRestObjectBase **a_ppValue, const char *a_pszKey, size_t a_cchKey = RTSTR_MAX, bool a_fReplace = false) RT_NOEXCEPT; + + /** + * Creates a new value and inserts it under the given key, returning the new value. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_ppValue Where to return the pointer to the value. + * @param a_rStrKey The key to put it under. + * @param a_fReplace Whether to replace or fail on key collision. + */ + int putNewValue(RTCRestObjectBase **a_ppValue, RTCString const &a_rStrKey, bool a_fReplace = false) RT_NOEXCEPT; + +protected: + /** Map entry. */ + typedef struct MapEntry + { + /** String space core. */ + RTSTRSPACECORE Core; + /** List node for enumeration. */ + RTLISTNODE ListEntry; + /** The key. + * @remarks Core.pszString points to the value of this object. So, consider it const. */ + RTCString strKey; + /** The value. */ + RTCRestObjectBase *pValue; + } MapEntry; + /** The map tree. */ + RTSTRSPACE m_Map; + /** The enumeration list head (MapEntry). */ + RTLISTANCHOR m_ListHead; + /** Number of map entries. */ + size_t m_cEntries; + +public: + /** @name Map Iteration + * @{ */ + /** Const iterator. */ + class ConstIterator + { + private: + MapEntry *m_pCur; + ConstIterator() RT_NOEXCEPT; + protected: + ConstIterator(MapEntry *a_pEntry) RT_NOEXCEPT : m_pCur(a_pEntry) { } + public: + ConstIterator(ConstIterator const &a_rThat) RT_NOEXCEPT : m_pCur(a_rThat.m_pCur) { } + + /** Gets the key string. */ + inline RTCString const &getKey() RT_NOEXCEPT { return m_pCur->strKey; } + /** Gets poitner to the value object. */ + inline RTCRestObjectBase const *getValue() RT_NOEXCEPT { return m_pCur->pValue; } + + /** Advance to the next map entry. */ + inline ConstIterator &operator++() RT_NOEXCEPT + { + m_pCur = RTListNodeGetNextCpp(&m_pCur->ListEntry, MapEntry, ListEntry); + return *this; + } + + /** Advance to the previous map entry. */ + inline ConstIterator &operator--() RT_NOEXCEPT + { + m_pCur = RTListNodeGetPrevCpp(&m_pCur->ListEntry, MapEntry, ListEntry); + return *this; + } + + /** Compare equal. */ + inline bool operator==(ConstIterator const &a_rThat) RT_NOEXCEPT { return m_pCur == a_rThat.m_pCur; } + /** Compare not equal. */ + inline bool operator!=(ConstIterator const &a_rThat) RT_NOEXCEPT { return m_pCur != a_rThat.m_pCur; } + + /* Map class must be friend so it can use the MapEntry constructor. */ + friend class RTCRestStringMapBase; + }; + + /** Returns iterator for the first map entry (unless it's empty and it's also the end). */ + inline ConstIterator begin() const RT_NOEXCEPT + { + if (!RTListIsEmpty(&m_ListHead)) + return ConstIterator(RTListNodeGetNextCpp(&m_ListHead, MapEntry, ListEntry)); + return end(); + } + /** Returns iterator for the last map entry (unless it's empty and it's also the end). */ + inline ConstIterator last() const RT_NOEXCEPT + { + if (!RTListIsEmpty(&m_ListHead)) + return ConstIterator(RTListNodeGetPrevCpp(&m_ListHead, MapEntry, ListEntry)); + return end(); + } + /** Returns the end iterator. This does not ever refer to an actual map entry. */ + inline ConstIterator end() const RT_NOEXCEPT + { + return ConstIterator(RT_FROM_CPP_MEMBER(&m_ListHead, MapEntry, ListEntry)); + } + /** @} */ + + +protected: + /** + * Helper for creating a clone. + * + * @returns Pointer to new map object on success, NULL if out of memory. + */ + virtual RTCRestStringMapBase *createClone(void) const RT_NOEXCEPT = 0; + + /** + * Wrapper around the value constructor. + * + * @returns Pointer to new value object on success, NULL if out of memory. + */ + virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT = 0; + + /** + * For accessing the static deserializeInstanceFromJson() method of the value. + */ + virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT = 0; + + /** + * Worker for the copy assignment method and copyMapWorkerMayThrow. + * + * This will use createEntryCopy to do the copying. + * + * @returns VINF_SUCCESS on success, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_rThat The map to copy. Caller makes 100% sure the it has + * the same type as the destination. + */ + int copyMapWorkerNoThrow(RTCRestStringMapBase const &a_rThat) RT_NOEXCEPT; + + /** + * Wrapper around copyMapWorkerNoThrow() that throws allocation errors, making + * it suitable for copy constructors and assignment operators. + */ + void copyMapWorkerMayThrow(RTCRestStringMapBase const &a_rThat); + + /** + * Worker for performing inserts. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_pszKey The key. + * @param a_pValue The value to insert. Ownership is transferred to the map on success. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + * @param a_cchKey The key length, the whole string by default. + */ + int putWorker(const char *a_pszKey, RTCRestObjectBase *a_pValue, bool a_fReplace, size_t a_cchKey = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Worker for performing inserts. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_pszKey The key. + * @param a_rValue The value to copy into the map. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + * @param a_cchKey The key length, the whole string by default. + */ + int putCopyWorker(const char *a_pszKey, RTCRestObjectBase const &a_rValue, bool a_fReplace, size_t a_cchKey = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Worker for getting the value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_pszKey The key which value to look up. + */ + RTCRestObjectBase *getWorker(const char *a_pszKey) RT_NOEXCEPT; + + /** + * Worker for getting the value corresponding to the given key, const variant. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_pszKey The key which value to look up. + */ + RTCRestObjectBase const *getWorker(const char *a_pszKey) const RT_NOEXCEPT; + +private: + static DECLCALLBACK(int) stringSpaceDestructorCallback(PRTSTRSPACECORE pStr, void *pvUser) RT_NOEXCEPT; +}; + + +/** + * Limited map class. + */ +template class RTCRestStringMap : public RTCRestStringMapBase +{ +public: + /** Default constructor, creates emtpy map. */ + RTCRestStringMap() RT_NOEXCEPT + : RTCRestStringMapBase() + {} + + /** Copy constructor. */ + RTCRestStringMap(RTCRestStringMap const &a_rThat) + : RTCRestStringMapBase() + { + copyMapWorkerMayThrow(a_rThat); + } + + /** Destructor. */ + virtual ~RTCRestStringMap() + { + /* nothing to do here. */ + } + + /** Copy assignment operator. */ + RTCRestStringMap &operator=(RTCRestStringMap const &a_rThat) + { + copyMapWorkerMayThrow(a_rThat); + return *this; + } + + /** Safe copy assignment method. */ + int assignCopy(RTCRestStringMap const &a_rThat) RT_NOEXCEPT + { + return copyMapWorkerNoThrow(a_rThat); + } + + /** Make a clone of this object. */ + inline RTCRestStringMap *clone() const RT_NOEXCEPT + { + return (RTCRestStringMap *)baseClone(); + } + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) RTCRestStringMap(); + } + + /** Factory method for values. */ + static DECLCALLBACK(RTCRestObjectBase *) createValueInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) ValueType(); + } + + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT + { + *a_ppInstance = new (std::nothrow) RTCRestStringMap(); + if (*a_ppInstance) + return (*a_ppInstance)->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); + } + + /** + * Inserts the given object into the map. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_pszKey The key. + * @param a_pValue The value to insert. Ownership is transferred to the map on success. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + inline int put(const char *a_pszKey, ValueType *a_pValue, bool a_fReplace = false) RT_NOEXCEPT + { + return putWorker(a_pszKey, a_pValue, a_fReplace); + } + + /** + * Inserts the given object into the map. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_rStrKey The key. + * @param a_pValue The value to insert. Ownership is transferred to the map on success. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + inline int put(RTCString const &a_rStrKey, ValueType *a_pValue, bool a_fReplace = false) RT_NOEXCEPT + { + return putWorker(a_rStrKey.c_str(), a_pValue, a_fReplace, a_rStrKey.length()); + } + + /** + * Inserts a copy of the given object into the map. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_pszKey The key. + * @param a_rValue The value to insert a copy of. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + inline int putCopy(const char *a_pszKey, const ValueType &a_rValue, bool a_fReplace = false) RT_NOEXCEPT + { + return putCopyWorker(a_pszKey, a_rValue, a_fReplace); + } + + /** + * Inserts a copy of the given object into the map. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_rStrKey The key. + * @param a_rValue The value to insert a copy of. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + inline int putCopy(RTCString const &a_rStrKey, const ValueType &a_rValue, bool a_fReplace = false) RT_NOEXCEPT + { + return putCopyWorker(a_rStrKey.c_str(), a_rValue, a_fReplace, a_rStrKey.length()); + } + + /** + * Gets the value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_pszKey The key which value to look up. + */ + inline ValueType *get(const char *a_pszKey) RT_NOEXCEPT + { + return (ValueType *)getWorker(a_pszKey); + } + + /** + * Gets the value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_rStrKey The key which value to look up. + */ + inline ValueType *get(RTCString const &a_rStrKey) RT_NOEXCEPT + { + return (ValueType *)getWorker(a_rStrKey.c_str()); + } + + /** + * Gets the const value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_pszKey The key which value to look up. + */ + inline ValueType const *get(const char *a_pszKey) const RT_NOEXCEPT + { + return (ValueType const *)getWorker(a_pszKey); + } + + /** + * Gets the const value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_rStrKey The key which value to look up. + */ + inline ValueType const *get(RTCString const &a_rStrKey) const RT_NOEXCEPT + { + return (ValueType const *)getWorker(a_rStrKey.c_str()); + } + + /** @todo enumerator*/ + +protected: + virtual RTCRestStringMapBase *createClone(void) const RT_NOEXCEPT RT_OVERRIDE + { + return new (std::nothrow) RTCRestStringMap(); + } + + virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT RT_OVERRIDE + { + return new (std::nothrow) ValueType(); + } + + virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT RT_OVERRIDE + { + return ValueType::deserializeInstanceFromJson(a_rCursor, a_ppInstance); + } +}; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_reststringmap_h */ + diff --git a/include/iprt/cpp/utils.h b/include/iprt/cpp/utils.h new file mode 100644 index 00000000..f5b36fa8 --- /dev/null +++ b/include/iprt/cpp/utils.h @@ -0,0 +1,149 @@ +/** @file + * IPRT - C++ Utilities (useful templates, defines and such). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_utils_h +#define IPRT_INCLUDED_cpp_utils_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_cpp IPRT C++ APIs */ + +/** @defgroup grp_rt_cpp_util C++ Utilities + * @ingroup grp_rt_cpp + * @{ + */ + +#define DPTR(CLASS) CLASS##Private *d = static_cast(d_ptr) +#define QPTR(CLASS) CLASS *q = static_cast(q_ptr) + +/** + * A simple class used to prevent copying and assignment. + * + * Inherit from this class in order to prevent automatic generation + * of the copy constructor and assignment operator in your class. + */ +class RTCNonCopyable +{ +protected: + RTCNonCopyable() {} + ~RTCNonCopyable() {} +private: + RTCNonCopyable(RTCNonCopyable const &); + RTCNonCopyable &operator=(RTCNonCopyable const &); +}; + + +/** + * Shortcut to |const_cast()| that automatically derives the correct + * type (class) for the const_cast template's argument from its own argument. + * + * Can be used to temporarily cancel the |const| modifier on the left-hand side + * of assignment expressions, like this: + * @code + * const Class That; + * ... + * unconst(That) = SomeValue; + * @endcode + * + * @todo What to do about the prefix here? + */ +template +inline C &unconst(const C &that) +{ + return const_cast(that); +} + + +/** + * Shortcut to |const_cast()| that automatically derives the correct + * type (class) for the const_cast template's argument from its own argument. + * + * Can be used to temporarily cancel the |const| modifier on the left-hand side + * of assignment expressions, like this: + * @code + * const Class *pThat; + * ... + * unconst(pThat) = SomeValue; + * @endcode + * + * @todo What to do about the prefix here? + */ +template +inline C *unconst(const C *that) +{ + return const_cast(that); +} + + +/** + * Macro for generating a non-const getter version from a const getter. + * + * @param a_RetType The getter return type. + * @param a_Class The class name. + * @param a_Getter The getter name. + * @param a_ArgDecls The argument declaration for the getter method. + * @param a_ArgList The argument list for the call. + */ +#define RT_CPP_GETTER_UNCONST(a_RetType, a_Class, a_Getter, a_ArgDecls, a_ArgList) \ + a_RetType a_Getter a_ArgDecls \ + { \ + return static_cast< a_Class const *>(this)-> a_Getter a_ArgList; \ + } + + +/** + * Macro for generating a non-const getter version from a const getter, + * unconsting the return value as well. + * + * @param a_RetType The getter return type. + * @param a_Class The class name. + * @param a_Getter The getter name. + * @param a_ArgDecls The argument declaration for the getter method. + * @param a_ArgList The argument list for the call. + */ +#define RT_CPP_GETTER_UNCONST_RET(a_RetType, a_Class, a_Getter, a_ArgDecls, a_ArgList) \ + a_RetType a_Getter a_ArgDecls \ + { \ + return const_cast(static_cast< a_Class const *>(this)-> a_Getter a_ArgList); \ + } + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_utils_h */ + diff --git a/include/iprt/cpp/xml.h b/include/iprt/cpp/xml.h new file mode 100644 index 00000000..9459f9d3 --- /dev/null +++ b/include/iprt/cpp/xml.h @@ -0,0 +1,1247 @@ +/** @file + * IPRT - XML Helper APIs. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_xml_h +#define IPRT_INCLUDED_cpp_xml_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef IN_RING3 +# error "There are no XML APIs available in Ring-0 Context!" +#endif +#ifdef IPRT_NO_CRT +# error "Not available in no-CRT mode because it depends on exceptions, std::list, std::map and stdio.h." +#endif + +#include +#include +#include + +#include +#include + + +/** @defgroup grp_rt_cpp_xml C++ XML support + * @ingroup grp_rt_cpp + * @{ + */ + +/* Forwards */ +typedef struct _xmlParserInput xmlParserInput; +typedef xmlParserInput *xmlParserInputPtr; +typedef struct _xmlParserCtxt xmlParserCtxt; +typedef xmlParserCtxt *xmlParserCtxtPtr; +typedef struct _xmlError xmlError; +typedef xmlError *xmlErrorPtr; + +typedef struct _xmlAttr xmlAttr; +typedef struct _xmlNode xmlNode; + +#define RT_XML_CONTENT_SMALL _8K +#define RT_XML_CONTENT_LARGE _128K +#define RT_XML_ATTR_TINY 64 +#define RT_XML_ATTR_SMALL _1K +#define RT_XML_ATTR_MEDIUM _8K +#define RT_XML_ATTR_LARGE _64K + +/** @} */ + +namespace xml +{ + +/** + * @addtogroup grp_rt_cpp_xml + * @{ + */ + +// Exceptions +////////////////////////////////////////////////////////////////////////////// + +class RT_DECL_CLASS LogicError : public RTCError +{ +public: + + LogicError(const char *aMsg = NULL) + : RTCError(aMsg) + {} + + LogicError(RT_SRC_POS_DECL); +}; + +class RT_DECL_CLASS RuntimeError : public RTCError +{ +public: + + RuntimeError(const char *aMsg = NULL) + : RTCError(aMsg) + {} +}; + +class RT_DECL_CLASS XmlError : public RuntimeError +{ +public: + XmlError(xmlErrorPtr aErr); + + static char* Format(xmlErrorPtr aErr); +}; + +// Logical errors +////////////////////////////////////////////////////////////////////////////// + +class RT_DECL_CLASS ENotImplemented : public LogicError +{ +public: + ENotImplemented(const char *aMsg = NULL) : LogicError(aMsg) {} + ENotImplemented(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {} +}; + +class RT_DECL_CLASS EInvalidArg : public LogicError +{ +public: + EInvalidArg(const char *aMsg = NULL) : LogicError(aMsg) {} + EInvalidArg(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {} +}; + +class RT_DECL_CLASS EDocumentNotEmpty : public LogicError +{ +public: + EDocumentNotEmpty(const char *aMsg = NULL) : LogicError(aMsg) {} + EDocumentNotEmpty(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {} +}; + +class RT_DECL_CLASS ENodeIsNotElement : public LogicError +{ +public: + ENodeIsNotElement(const char *aMsg = NULL) : LogicError(aMsg) {} + ENodeIsNotElement(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {} +}; + +// Runtime errors +////////////////////////////////////////////////////////////////////////////// + +class RT_DECL_CLASS EIPRTFailure : public RuntimeError +{ +public: + + EIPRTFailure(int aRC, const char *pszContextFmt, ...); + + int rc() const + { + return mRC; + } + +private: + int mRC; +}; + +/** + * The Stream class is a base class for I/O streams. + */ +class RT_DECL_CLASS Stream +{ +public: + + virtual ~Stream() {} + + virtual const char *uri() const = 0; + + /** + * Returns the current read/write position in the stream. The returned + * position is a zero-based byte offset from the beginning of the file. + * + * Throws ENotImplemented if this operation is not implemented for the + * given stream. + */ + virtual uint64_t pos() const = 0; + + /** + * Sets the current read/write position in the stream. + * + * @param aPos Zero-based byte offset from the beginning of the stream. + * + * Throws ENotImplemented if this operation is not implemented for the + * given stream. + */ + virtual void setPos (uint64_t aPos) = 0; +}; + +/** + * The Input class represents an input stream. + * + * This input stream is used to read the settings tree from. + * This is an abstract class that must be subclassed in order to fill it with + * useful functionality. + */ +class RT_DECL_CLASS Input : virtual public Stream +{ +public: + + /** + * Reads from the stream to the supplied buffer. + * + * @param aBuf Buffer to store read data to. + * @param aLen Buffer length. + * + * @return Number of bytes read. + */ + virtual int read (char *aBuf, int aLen) = 0; +}; + +/** + * + */ +class RT_DECL_CLASS Output : virtual public Stream +{ +public: + + /** + * Writes to the stream from the supplied buffer. + * + * @param aBuf Buffer to write data from. + * @param aLen Buffer length. + * + * @return Number of bytes written. + */ + virtual int write (const char *aBuf, int aLen) = 0; + + /** + * Truncates the stream from the current position and upto the end. + * The new file size will become exactly #pos() bytes. + * + * Throws ENotImplemented if this operation is not implemented for the + * given stream. + */ + virtual void truncate() = 0; +}; + + +////////////////////////////////////////////////////////////////////////////// + +/** + * The File class is a stream implementation that reads from and writes to + * regular files. + * + * The File class uses IPRT File API for file operations. Note that IPRT File + * API is not thread-safe. This means that if you pass the same RTFILE handle to + * different File instances that may be simultaneously used on different + * threads, you should care about serialization; otherwise you will get garbage + * when reading from or writing to such File instances. + */ +class RT_DECL_CLASS File : public Input, public Output +{ +public: + + /** + * Possible file access modes. + */ + enum Mode { Mode_Read, Mode_WriteCreate, Mode_Overwrite, Mode_ReadWrite }; + + /** + * Opens a file with the given name in the given mode. If @a aMode is Read + * or ReadWrite, the file must exist. If @a aMode is Write, the file must + * not exist. Otherwise, an EIPRTFailure exception will be thrown. + * + * @param aMode File mode. + * @param aFileName File name. + * @param aFlushIt Whether to flush a writable file before closing it. + */ + File(Mode aMode, const char *aFileName, bool aFlushIt = false); + + /** + * Uses the given file handle to perform file operations. This file + * handle must be already open in necessary mode (read, or write, or mixed). + * + * The read/write position of the given handle will be reset to the + * beginning of the file on success. + * + * Note that the given file handle will not be automatically closed upon + * this object destruction. + * + * @note It you pass the same RTFILE handle to more than one File instance, + * please make sure you have provided serialization in case if these + * instasnces are to be simultaneously used by different threads. + * Otherwise you may get garbage when reading or writing. + * + * @param aHandle Open file handle. + * @param aFileName File name (for reference). + * @param aFlushIt Whether to flush a writable file before closing it. + */ + File(RTFILE aHandle, const char *aFileName = NULL, bool aFlushIt = false); + + /** + * Destroys the File object. If the object was created from a file name + * the corresponding file will be automatically closed. If the object was + * created from a file handle, it will remain open. + */ + virtual ~File(); + + const char *uri() const; + + uint64_t pos() const; + void setPos(uint64_t aPos); + + /** + * See Input::read(). If this method is called in wrong file mode, + * LogicError will be thrown. + */ + int read(char *aBuf, int aLen); + + /** + * See Output::write(). If this method is called in wrong file mode, + * LogicError will be thrown. + */ + int write(const char *aBuf, int aLen); + + /** + * See Output::truncate(). If this method is called in wrong file mode, + * LogicError will be thrown. + */ + void truncate(); + +private: + + /* Obscure class data */ + struct Data; + Data *m; + + /* auto_ptr data doesn't have proper copy semantics */ + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(File); +}; + +/** + * The MemoryBuf class represents a stream implementation that reads from the + * memory buffer. + */ +class RT_DECL_CLASS MemoryBuf : public Input +{ +public: + + MemoryBuf (const char *aBuf, size_t aLen, const char *aURI = NULL); + + virtual ~MemoryBuf(); + + const char *uri() const; + + int read(char *aBuf, int aLen); + uint64_t pos() const; + void setPos(uint64_t aPos); + +private: + /* Obscure class data */ + struct Data; + Data *m; + + /* auto_ptr data doesn't have proper copy semantics */ + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(MemoryBuf); +}; + + +/* + * GlobalLock + * + * + */ + + +typedef DECLCALLBACKTYPE_EX(xmlParserInput *, RT_NOTHING, FNEXTERNALENTITYLOADER,(const char *aURI, const char *aID, + xmlParserCtxt *aCtxt)); +typedef FNEXTERNALENTITYLOADER *PFNEXTERNALENTITYLOADER; /**< xmlExternalEntityLoader w/ noexcept. */ + +class RT_DECL_CLASS GlobalLock +{ +public: + GlobalLock(); + ~GlobalLock(); + + void setExternalEntityLoader(PFNEXTERNALENTITYLOADER pFunc); + + static xmlParserInput* callDefaultLoader(const char *aURI, + const char *aID, + xmlParserCtxt *aCtxt); + +private: + /* Obscure class data. */ + struct Data; + struct Data *m; +}; + +class ElementNode; +typedef std::list ElementNodesList; + +class AttributeNode; + +class ContentNode; + +/** + * Node base class. + * + * Cannot be used directly, but ElementNode, ContentNode and AttributeNode + * derive from this. This does implement useful public methods though. + * + * + */ +class RT_DECL_CLASS Node +{ +public: + virtual ~Node(); + + const char *getName() const; + const char *getPrefix() const; + const char *getNamespaceURI() const; + bool nameEqualsNS(const char *pcszNamespace, const char *pcsz) const; + bool nameEquals(const char *pcsz) const + { + return nameEqualsNS(NULL, pcsz); + } + bool nameEqualsN(const char *pcsz, size_t cchMax, const char *pcszNamespace = NULL) const; + + const char *getValue() const; + const char *getValueN(size_t cchValueLimit) const; + bool copyValue(int32_t &i) const; + bool copyValue(uint32_t &i) const; + bool copyValue(int64_t &i) const; + bool copyValue(uint64_t &i) const; + + /** @name Introspection. + * @{ */ + /** Is this an ElementNode instance. + * @returns true / false */ + bool isElement() const + { + return m_Type == IsElement; + } + + /** Is this an ContentNode instance. + * @returns true / false */ + bool isContent() const + { + return m_Type == IsContent; + } + + /** Is this an AttributeNode instance. + * @returns true / false */ + bool isAttribute() const + { + return m_Type == IsAttribute; + } + + int getLineNumber() const; + /** @} */ + + /** @name General tree enumeration. + * + * Use the introspection methods isElement() and isContent() before doing static + * casting. Parents are always or ElementNode type, but siblings and children + * can be of both ContentNode and ElementNode types. + * + * @remarks Attribute node are in the attributes list, while both content and + * element nodes are in the list of children. See ElementNode. + * + * @remarks Careful mixing tree walking with node removal! + * @{ + */ + /** Get the parent node + * @returns Pointer to the parent node, or NULL if root. */ + const Node *getParent() const + { + return m_pParent; + } + + /** Get the previous sibling. + * @returns Pointer to the previous sibling node, NULL if first child. + */ + const Node *getPrevSibiling() const + { + if (!m_pParentListAnchor) + return NULL; + return RTListGetPrevCpp(m_pParentListAnchor, this, const Node, m_listEntry); + } + + /** Get the next sibling. + * @returns Pointer to the next sibling node, NULL if last child. */ + const Node *getNextSibiling() const + { + if (!m_pParentListAnchor) + return NULL; + return RTListGetNextCpp(m_pParentListAnchor, this, const Node, m_listEntry); + } + /** @} */ + +protected: + /** Node types. */ + typedef enum { IsElement, IsAttribute, IsContent } EnumType; + + /** The type of node this is an instance of. */ + EnumType m_Type; + /** The parent node (always an element), NULL if root. */ + Node *m_pParent; + + xmlNode *m_pLibNode; ///< != NULL if this is an element or content node + xmlAttr *m_pLibAttr; ///< != NULL if this is an attribute node + const char *m_pcszNamespacePrefix; ///< not always set + const char *m_pcszNamespaceHref; ///< full http:// spec + const char *m_pcszName; ///< element or attribute name, points either into pLibNode or pLibAttr; + ///< NULL if this is a content node + + /** Child list entry of this node. (List head m_pParent->m_children or + * m_pParent->m_attribute depending on the type.) */ + RTLISTNODE m_listEntry; + /** Pointer to the parent list anchor. + * This allows us to use m_listEntry both for children and attributes. */ + PRTLISTANCHOR m_pParentListAnchor; + + // hide the default constructor so people use only our factory methods + Node(EnumType type, + Node *pParent, + PRTLISTANCHOR pListAnchor, + xmlNode *pLibNode, + xmlAttr *pLibAttr); + Node(const Node &x); // no copying + + friend class AttributeNode; + friend class ElementNode; /* C list hack. */ +}; + +/** + * Node subclass that represents an attribute of an element. + * + * For attributes, Node::getName() returns the attribute name, and Node::getValue() + * returns the attribute value, if any. + * + * Since the Node constructor is private, one can create new attribute nodes + * only through the following factory methods: + * + * -- ElementNode::setAttribute() + */ +class RT_DECL_CLASS AttributeNode : public Node +{ +public: + +protected: + // hide the default constructor so people use only our factory methods + AttributeNode(const ElementNode *pElmRoot, + Node *pParent, + PRTLISTANCHOR pListAnchor, + xmlAttr *pLibAttr); + AttributeNode(const AttributeNode &x); // no copying + + friend class Node; + friend class ElementNode; +}; + +/** + * Node subclass that represents an element. + * + * For elements, Node::getName() returns the element name, and Node::getValue() + * returns the text contents, if any. + * + * Since the Node constructor is private, one can create element nodes + * only through the following factory methods: + * + * -- Document::createRootElement() + * -- ElementNode::createChild() + */ +class RT_DECL_CLASS ElementNode : public Node +{ +public: + int getChildElements(ElementNodesList &children, const char *pcszMatch = NULL) const; + + const ElementNode *findChildElementNS(const char *pcszNamespace, const char *pcszMatch) const; + const ElementNode *findChildElement(const char *pcszMatch) const + { + return findChildElementNS(NULL, pcszMatch); + } + const ElementNode *findChildElementFromId(const char *pcszId) const; + + /** Finds the first decendant matching the name at the end of @a pcszPath and + * optionally namespace. + * + * @returns Pointer to the child string value, NULL if not found or no value. + * @param pcszPath Path to the child element. Slashes can be used to + * make a simple path to any decendant. + * @param pcszNamespace The namespace to match, NULL (default) match any + * namespace. When using a path, this matches all + * elements along the way. + * @see findChildElement, findChildElementP + */ + const ElementNode *findChildElementP(const char *pcszPath, const char *pcszNamespace = NULL) const; + + /** Finds the first child with matching the give name and optionally namspace, + * returning its value. + * + * @returns Pointer to the child string value, NULL if not found or no value. + * @param pcszPath Path to the child element. Slashes can be used to + * make a simple path to any decendant. + * @param pcszNamespace The namespace to match, NULL (default) match any + * namespace. When using a path, this matches all + * elements along the way. + * @see findChildElement, findChildElementP + */ + const char *findChildElementValueP(const char *pcszPath, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getValue(); + return NULL; + } + + /** Finds the first child with matching the give name and optionally namspace, + * returning its value. Checks the length against the limit. + * + * @returns Pointer to the child string value, NULL if not found or no value. + * @param pcszPath Path to the child element. Slashes can be used to + * make a simple path to any decendant. + * @param cchValueLimit If the length of the returned value exceeds this + * limit a EIPRTFailure exception will be thrown. + * @param pcszNamespace The namespace to match, NULL (default) match any + * namespace. When using a path, this matches all + * elements along the way. + * @see findChildElement, findChildElementP + */ + const char *findChildElementValuePN(const char *pcszPath, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getValueN(cchValueLimit); + return NULL; + } + + /** Combines findChildElementNS and findAttributeValue. + * + * @returns Pointer to attribute string value, NULL if either the element or + * the attribute was not found. + * @param pcszChild The child element name. + * @param pcszAttribute The attribute name. + * @param pcszChildNamespace The namespace to match @a pcszChild with, NULL + * (default) match any namespace. + * @param pcszAttributeNamespace The namespace prefix to apply to the + * attribute, NULL (default) match any namespace. + * @see findChildElementNS and findAttributeValue + * @note The findChildElementAttributeValueP() method would do the same thing + * given the same inputs, but it would be slightly slower, thus the + * separate method. + */ + const char *findChildElementAttributeValue(const char *pcszChild, const char *pcszAttribute, + const char *pcszChildNamespace = NULL, + const char *pcszAttributeNamespace = NULL) const + { + const ElementNode *pElem = findChildElementNS(pcszChildNamespace, pcszChild); + if (pElem) + return pElem->findAttributeValue(pcszAttribute, pcszAttributeNamespace); + return NULL; + } + + /** Combines findChildElementP and findAttributeValue. + * + * @returns Pointer to attribute string value, NULL if either the element or + * the attribute was not found. + * @param pcszPath Path to the child element. Slashes can be used + * to make a simple path to any decendant. + * @param pcszAttribute The attribute name. + * @param pcszPathNamespace The namespace to match @a pcszPath with, NULL + * (default) match any namespace. When using a + * path, this matches all elements along the way. + * @param pcszAttributeNamespace The namespace prefix to apply to the + * attribute, NULL (default) match any namespace. + * @see findChildElementP and findAttributeValue + */ + const char *findChildElementAttributeValueP(const char *pcszPath, const char *pcszAttribute, + const char *pcszPathNamespace = NULL, + const char *pcszAttributeNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszPathNamespace); + if (pElem) + return pElem->findAttributeValue(pcszAttribute, pcszAttributeNamespace); + return NULL; + } + + /** Combines findChildElementP and findAttributeValueN. + * + * @returns Pointer to attribute string value, NULL if either the element or + * the attribute was not found. + * @param pcszPath The attribute name. Slashes can be used to make a + * simple path to any decendant. + * @param pcszAttribute The attribute name. + * @param cchValueLimit If the length of the returned value exceeds this + * limit a EIPRTFailure exception will be thrown. + * @param pcszPathNamespace The namespace to match @a pcszPath with, NULL + * (default) match any namespace. When using a + * path, this matches all elements along the way. + * @param pcszAttributeNamespace The namespace prefix to apply to the + * attribute, NULL (default) match any namespace. + * @see findChildElementP and findAttributeValue + */ + const char *findChildElementAttributeValuePN(const char *pcszPath, const char *pcszAttribute, + size_t cchValueLimit, + const char *pcszPathNamespace = NULL, + const char *pcszAttributeNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszPathNamespace); + if (pElem) + return pElem->findAttributeValueN(pcszAttribute, cchValueLimit, pcszAttributeNamespace); + return NULL; + } + + + /** @name Tree enumeration. + * @{ */ + + /** Get the next tree element in a full tree enumeration. + * + * By starting with the root node, this can be used to enumerate the entire tree + * (or sub-tree if @a pElmRoot is used). + * + * @returns Pointer to the next element in the tree, NULL if we're done. + * @param pElmRoot The root of the tree we're enumerating. NULL if + * it's the entire tree. + */ + ElementNode const *getNextTreeElement(ElementNode const *pElmRoot = NULL) const; + RT_CPP_GETTER_UNCONST_RET(ElementNode *, ElementNode, getNextTreeElement, (const ElementNode *pElmRoot = NULL), (pElmRoot)) + + /** Get the first child node. + * @returns Pointer to the first child node, NULL if no children. */ + const Node *getFirstChild() const + { + return RTListGetFirstCpp(&m_children, const Node, m_listEntry); + } + RT_CPP_GETTER_UNCONST_RET(Node *, ElementNode, getFirstChild,(),()) + + /** Get the last child node. + * @returns Pointer to the last child node, NULL if no children. */ + const Node *getLastChild() const + { + return RTListGetLastCpp(&m_children, const Node, m_listEntry); + } + + /** Get the first child node. + * @returns Pointer to the first child node, NULL if no children. */ + const ElementNode *getFirstChildElement() const; + + /** Get the last child node. + * @returns Pointer to the last child node, NULL if no children. */ + const ElementNode *getLastChildElement() const; + + /** Get the previous sibling element. + * @returns Pointer to the previous sibling element, NULL if first child + * element. + * @see getNextSibilingElement, getPrevSibling + */ + const ElementNode *getPrevSibilingElement() const; + + /** Get the next sibling element. + * @returns Pointer to the next sibling element, NULL if last child element. + * @see getPrevSibilingElement, getNextSibling + */ + const ElementNode *getNextSibilingElement() const; + + /** Find the previous element matching the given name and namespace (optionally). + * @returns Pointer to the previous sibling element, NULL if first child + * element. + * @param pcszName The element name to match. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @note Changed the order of the arguments. + */ + const ElementNode *findPrevSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const; + + /** Find the next element matching the given name and namespace (optionally). + * @returns Pointer to the previous sibling element, NULL if first child + * element. + * @param pcszName The element name to match. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @note Changed the order of the arguments. + */ + const ElementNode *findNextSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const; + /** @} */ + + /** @name Attribute enumeration + * @{ */ + + /** Get the first attribute node. + * @returns Pointer to the first child node, NULL if no attributes. */ + const AttributeNode *getFirstAttribute() const + { + return RTListGetFirstCpp(&m_attributes, const AttributeNode, m_listEntry); + } + + /** Get the last attribute node. + * @returns Pointer to the last child node, NULL if no attributes. */ + const AttributeNode *getLastAttribute() const + { + return RTListGetLastCpp(&m_attributes, const AttributeNode, m_listEntry); + } + + /** @} */ + + const AttributeNode *findAttribute(const char *pcszMatch, const char *pcszNamespace = NULL) const; + /** Find the first attribute with the given name, returning its value string. + * @returns Pointer to the attribute string value. + * @param pcszName The attribute name. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @see getAttributeValue + */ + const char *findAttributeValue(const char *pcszName, const char *pcszNamespace = NULL) const + { + const AttributeNode *pAttr = findAttribute(pcszName, pcszNamespace); + if (pAttr) + return pAttr->getValue(); + return NULL; + } + /** Find the first attribute with the given name, returning its value string. + * @returns Pointer to the attribute string value. + * @param pcszName The attribute name. + * @param cchValueLimit If the length of the returned value exceeds this + * limit a EIPRTFailure exception will be thrown. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @see getAttributeValue + */ + const char *findAttributeValueN(const char *pcszName, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { + const AttributeNode *pAttr = findAttribute(pcszName, pcszNamespace); + if (pAttr) + return pAttr->getValueN(cchValueLimit); + return NULL; + } + + bool getAttributeValue(const char *pcszMatch, const char *&pcsz, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &pcsz, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &str, pcszNamespace); } + bool getAttributeValuePath(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &str, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, int32_t &i, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &i, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, uint32_t &i, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &i, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, int64_t &i, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &i, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, uint64_t &u, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &u, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, bool &f, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &f, pcszNamespace); } + bool getAttributeValueN(const char *pcszMatch, const char *&pcsz, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { return getAttributeValueN(pcszMatch, &pcsz, cchValueLimit, pcszNamespace); } + bool getAttributeValueN(const char *pcszMatch, RTCString &str, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { return getAttributeValueN(pcszMatch, &str, cchValueLimit, pcszNamespace); } + bool getAttributeValuePathN(const char *pcszMatch, RTCString &str, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { return getAttributeValueN(pcszMatch, &str, cchValueLimit, pcszNamespace); } + + /** @name Variants that for clarity does not use references for output params. + * @{ */ + bool getAttributeValue(const char *pcszMatch, const char **ppcsz, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const; + bool getAttributeValuePath(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, int32_t *pi, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, uint32_t *pu, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, int64_t *piValue, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, uint64_t *pu, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, bool *pf, const char *pcszNamespace = NULL) const; + bool getAttributeValueN(const char *pcszMatch, const char **ppcsz, size_t cchValueLimit, const char *pcszNamespace = NULL) const; + bool getAttributeValueN(const char *pcszMatch, RTCString *pStr, size_t cchValueLimit, const char *pcszNamespace = NULL) const; + bool getAttributeValuePathN(const char *pcszMatch, RTCString *pStr, size_t cchValueLimit, const char *pcszNamespace = NULL) const; + /** @} */ + + /** @name Convenience methods for convering the element value. + * @{ */ + bool getElementValue(int32_t *piValue) const; + bool getElementValue(uint32_t *puValue) const; + bool getElementValue(int64_t *piValue) const; + bool getElementValue(uint64_t *puValue) const; + bool getElementValue(bool *pfValue) const; + /** @} */ + + /** @name Convenience findChildElementValueP and getElementValue. + * @{ */ + bool getChildElementValueP(const char *pcszPath, int32_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(piValue); + } + bool getChildElementValueP(const char *pcszPath, uint32_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(puValue); + } + bool getChildElementValueP(const char *pcszPath, int64_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(piValue); + } + bool getChildElementValueP(const char *pcszPath, uint64_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(puValue); + } + bool getChildElementValueP(const char *pcszPath, bool *pfValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(pfValue); + } + + /** @} */ + + /** @name Convenience findChildElementValueP and getElementValue with a + * default value being return if the child element isn't present. + * + * @remarks These will return false on conversion errors. + * @{ */ + bool getChildElementValueDefP(const char *pcszPath, int32_t iDefault, int32_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(piValue); + *piValue = iDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, uint32_t uDefault, uint32_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(puValue); + *puValue = uDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, int64_t iDefault, int64_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(piValue); + *piValue = iDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, uint64_t uDefault, uint64_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(puValue); + *puValue = uDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, bool fDefault, bool *pfValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(pfValue); + *pfValue = fDefault; + return true; + } + /** @} */ + + ElementNode *createChild(const char *pcszElementName); + + ContentNode *addContent(const char *pcszContent); + ContentNode *addContent(const RTCString &strContent) + { + return addContent(strContent.c_str()); + } + + ContentNode *setContent(const char *pcszContent); + ContentNode *setContent(const RTCString &strContent) + { + return setContent(strContent.c_str()); + } + + AttributeNode *setAttribute(const char *pcszName, const char *pcszValue); + AttributeNode *setAttribute(const char *pcszName, const RTCString &strValue) + { + return setAttribute(pcszName, strValue.c_str()); + } + AttributeNode *setAttributePath(const char *pcszName, const RTCString &strValue); + AttributeNode *setAttribute(const char *pcszName, int32_t i); + AttributeNode *setAttribute(const char *pcszName, uint32_t i); + AttributeNode *setAttribute(const char *pcszName, int64_t i); + AttributeNode *setAttribute(const char *pcszName, uint64_t i); + AttributeNode *setAttributeHex(const char *pcszName, uint32_t i); + AttributeNode *setAttribute(const char *pcszName, bool f); + + virtual ~ElementNode(); + +protected: + // hide the default constructor so people use only our factory methods + ElementNode(const ElementNode *pElmRoot, Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode); + ElementNode(const ElementNode &x); // no copying + + /** We keep a pointer to the root element for attribute namespace handling. */ + const ElementNode *m_pElmRoot; + + /** List of child elements and content nodes. */ + RTLISTANCHOR m_children; + /** List of attributes nodes. */ + RTLISTANCHOR m_attributes; + + static void buildChildren(ElementNode *pElmRoot); + + friend class Node; + friend class Document; + friend class XmlFileParser; +}; + +/** + * Node subclass that represents content (non-element text). + * + * Since the Node constructor is private, one can create new content nodes + * only through the following factory methods: + * + * -- ElementNode::addContent() + */ +class RT_DECL_CLASS ContentNode : public Node +{ +public: + +protected: + // hide the default constructor so people use only our factory methods + ContentNode(Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode); + ContentNode(const ContentNode &x); // no copying + + friend class Node; + friend class ElementNode; +}; + + +/** + * Handy helper class with which one can loop through all or some children + * of a particular element. See NodesLoop::forAllNodes() for details. + */ +class RT_DECL_CLASS NodesLoop +{ +public: + NodesLoop(const ElementNode &node, const char *pcszMatch = NULL); + ~NodesLoop(); + const ElementNode* forAllNodes() const; + +private: + /* Obscure class data */ + struct Data; + Data *m; +}; + +/** + * The XML document class. An instance of this needs to be created by a user + * of the XML classes and then passed to + * + * -- XmlMemParser or XmlFileParser to read an XML document; those classes then + * fill the caller's Document with ElementNode, ContentNode and AttributeNode + * instances. The typical sequence then is: + * @code + Document doc; + XmlFileParser parser; + parser.read("file.xml", doc); + Element *pElmRoot = doc.getRootElement(); + @endcode + * + * -- XmlMemWriter or XmlFileWriter to write out an XML document after it has + * been created and filled. Example: + * + * @code + Document doc; + Element *pElmRoot = doc.createRootElement(); + // add children + xml::XmlFileWriter writer(doc); + writer.write("file.xml", true); + @endcode + */ +class RT_DECL_CLASS Document +{ +public: + Document(); + ~Document(); + + Document(const Document &x); + Document& operator=(const Document &x); + + const ElementNode* getRootElement() const; + ElementNode* getRootElement(); + + ElementNode* createRootElement(const char *pcszRootElementName, + const char *pcszComment = NULL); + +private: + friend class XmlMemParser; + friend class XmlFileParser; + friend class XmlMemWriter; + friend class XmlStringWriter; + friend class XmlFileWriter; + + void refreshInternals(); + + /* Obscure class data */ + struct Data; + Data *m; +}; + +/* + * XmlParserBase + * + */ + +class RT_DECL_CLASS XmlParserBase +{ +protected: + XmlParserBase(); + ~XmlParserBase(); + + xmlParserCtxtPtr m_ctxt; +}; + +/* + * XmlMemParser + * + */ + +class RT_DECL_CLASS XmlMemParser : public XmlParserBase +{ +public: + XmlMemParser(); + ~XmlMemParser(); + + void read(const void* pvBuf, size_t cbSize, const RTCString &strFilename, Document &doc); +}; + +/* + * XmlFileParser + * + */ + +class RT_DECL_CLASS XmlFileParser : public XmlParserBase +{ +public: + XmlFileParser(); + ~XmlFileParser(); + + void read(const RTCString &strFilename, Document &doc); + +private: + /* Obscure class data */ + struct Data; + struct Data *m; + + static int ReadCallback(void *aCtxt, char *aBuf, int aLen) RT_NOTHROW_PROTO; + static int CloseCallback(void *aCtxt) RT_NOTHROW_PROTO; +}; + +/** + * XmlMemWriter + */ +class RT_DECL_CLASS XmlMemWriter +{ +public: + XmlMemWriter(); + ~XmlMemWriter(); + + void write(const Document &doc, void** ppvBuf, size_t *pcbSize); + +private: + void* m_pBuf; +}; + + +/** + * XmlStringWriter - writes the XML to an RTCString instance. + */ +class RT_DECL_CLASS XmlStringWriter +{ +public: + XmlStringWriter(); + + int write(const Document &rDoc, RTCString *pStrDst); + +private: + static int WriteCallbackForSize(void *pvUser, const char *pachBuf, int cbToWrite) RT_NOTHROW_PROTO; + static int WriteCallbackForReal(void *pvUser, const char *pachBuf, int cbToWrite) RT_NOTHROW_PROTO; + static int CloseCallback(void *pvUser) RT_NOTHROW_PROTO; + + /** Pointer to the destination string while we're in the write() call. */ + RTCString *m_pStrDst; + /** Set by WriteCallback if we cannot grow the destination string. */ + bool m_fOutOfMemory; +}; + + +/** + * XmlFileWriter + */ +class RT_DECL_CLASS XmlFileWriter +{ +public: + XmlFileWriter(Document &doc); + ~XmlFileWriter(); + + /** + * Writes the XML document to the specified file. + * + * @param pcszFilename The name of the output file. + * @param fSafe If @c true, some extra safety precautions will be + * taken when writing the file: + * -# The file is written with a '-tmp' suffix. + * -# It is flushed to disk after writing. + * -# Any original file is renamed to '-prev'. + * -# The '-tmp' file is then renamed to the + * specified name. + * -# The directory changes are flushed to disk. + * The suffixes are available via s_pszTmpSuff and + * s_pszPrevSuff. + */ + void write(const char *pcszFilename, bool fSafe); + + static int WriteCallback(void *aCtxt, const char *aBuf, int aLen) RT_NOTHROW_PROTO; + static int CloseCallback(void *aCtxt) RT_NOTHROW_PROTO; + + /** The suffix used by XmlFileWriter::write() for the temporary file. */ + static const char * const s_pszTmpSuff; + /** The suffix used by XmlFileWriter::write() for the previous (backup) file. */ + static const char * const s_pszPrevSuff; + +private: + void writeInternal(const char *pcszFilename, bool fSafe); + + /* Obscure class data */ + struct Data; + Data *m; +}; + +#if defined(_MSC_VER) +#pragma warning (default:4251) +#endif + +/** @} */ + +} // end namespace xml + +#endif /* !IPRT_INCLUDED_cpp_xml_h */ + diff --git a/include/iprt/cpuset.h b/include/iprt/cpuset.h new file mode 100644 index 00000000..c5882472 --- /dev/null +++ b/include/iprt/cpuset.h @@ -0,0 +1,353 @@ +/** @file + * IPRT - CPU Set. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpuset_h +#define IPRT_INCLUDED_cpuset_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include /* RTMpCpuIdToSetIndex */ +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cpuset RTCpuSet - CPU Set + * @ingroup grp_rt + * @{ + */ + + +/** + * Clear all CPUs. + * + * @returns pSet. + * @param pSet Pointer to the set. + */ +DECLINLINE(PRTCPUSET) RTCpuSetEmpty(PRTCPUSET pSet) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + pSet->bmSet[i] = 0; + return pSet; +} + + +/** + * Set all CPUs. + * + * @returns pSet. + * @param pSet Pointer to the set. + */ +DECLINLINE(PRTCPUSET) RTCpuSetFill(PRTCPUSET pSet) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + pSet->bmSet[i] = UINT64_MAX; + return pSet; +} + + +/** + * Copies one set to another. + * + * @param pDst Pointer to the destination set. + * @param pSrc Pointer to the source set. + */ +DECLINLINE(void) RTCpuSetCopy(PRTCPUSET pDst, PRTCPUSET pSrc) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pDst->bmSet); i++) + pDst->bmSet[i] = pSrc->bmSet[i]; +} + + +/** + * ANDs the given CPU set with another. + * + * @returns pSet. + * @param pSet Pointer to the set. + * @param pAndMaskSet Pointer to the AND-mask set. + */ +DECLINLINE(PRTCPUSET) RTCpuSetAnd(PRTCPUSET pSet, PRTCPUSET pAndMaskSet) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + ASMAtomicAndU64((volatile uint64_t *)&pSet->bmSet[i], pAndMaskSet->bmSet[i]); + return pSet; +} + + +/** + * Adds a CPU given by its identifier to the set. + * + * @returns 0 on success, -1 if idCpu isn't valid. + * @param pSet Pointer to the set. + * @param idCpu The identifier of the CPU to add. + * @remarks The modification is atomic. + */ +DECLINLINE(int) RTCpuSetAdd(PRTCPUSET pSet, RTCPUID idCpu) +{ + int iCpu = RTMpCpuIdToSetIndex(idCpu); + if (RT_LIKELY(iCpu >= 0)) + { + ASMAtomicBitSet(pSet, iCpu); + return 0; + } + return -1; +} + + +/** + * Adds a CPU given by its identifier to the set. + * + * @returns 0 on success, -1 if iCpu isn't valid. + * @param pSet Pointer to the set. + * @param iCpu The index of the CPU to add. + * @remarks The modification is atomic. + */ +DECLINLINE(int) RTCpuSetAddByIndex(PRTCPUSET pSet, int iCpu) +{ + if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS)) + { + ASMAtomicBitSet(pSet, iCpu); + return 0; + } + return -1; +} + + +/** + * Removes a CPU given by its identifier from the set. + * + * @returns 0 on success, -1 if idCpu isn't valid. + * @param pSet Pointer to the set. + * @param idCpu The identifier of the CPU to delete. + * @remarks The modification is atomic. + */ +DECLINLINE(int) RTCpuSetDel(PRTCPUSET pSet, RTCPUID idCpu) +{ + int iCpu = RTMpCpuIdToSetIndex(idCpu); + if (RT_LIKELY(iCpu >= 0)) + { + ASMAtomicBitClear(pSet, iCpu); + return 0; + } + return -1; +} + + +/** + * Removes a CPU given by its index from the set. + * + * @returns 0 on success, -1 if iCpu isn't valid. + * @param pSet Pointer to the set. + * @param iCpu The index of the CPU to delete. + * @remarks The modification is atomic. + */ +DECLINLINE(int) RTCpuSetDelByIndex(PRTCPUSET pSet, int iCpu) +{ + if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS)) + { + ASMAtomicBitClear(pSet, iCpu); + return 0; + } + return -1; +} + + +/** + * Checks if a CPU given by its identifier is a member of the set. + * + * @returns true / false accordingly. + * @param pSet Pointer to the set. + * @param idCpu The identifier of the CPU to look for. + * @remarks The test is atomic. + */ +DECLINLINE(bool) RTCpuSetIsMember(PCRTCPUSET pSet, RTCPUID idCpu) +{ + int iCpu = RTMpCpuIdToSetIndex(idCpu); + if (RT_LIKELY(iCpu >= 0)) + return ASMBitTest((volatile void *)pSet, iCpu); + return false; +} + + +/** + * Checks if a CPU given by its index is a member of the set. + * + * @returns true / false accordingly. + * @param pSet Pointer to the set. + * @param iCpu The index of the CPU in the set. + * @remarks The test is atomic. + */ +DECLINLINE(bool) RTCpuSetIsMemberByIndex(PCRTCPUSET pSet, int iCpu) +{ + if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS)) + return ASMBitTest((volatile void *)pSet, iCpu); + return false; +} + + +/** + * Checks if the two sets match or not. + * + * @returns true / false accordingly. + * @param pSet1 The first set. + * @param pSet2 The second set. + */ +DECLINLINE(bool) RTCpuSetIsEqual(PCRTCPUSET pSet1, PCRTCPUSET pSet2) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet1->bmSet); i++) + if (pSet1->bmSet[i] != pSet2->bmSet[i]) + return false; + return true; +} + + +/** + * Checks if the CPU set is empty or not. + * + * @returns true / false accordingly. + * @param pSet Pointer to the set. + */ +DECLINLINE(bool) RTCpuSetIsEmpty(PRTCPUSET pSet) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + if (pSet->bmSet[i]) + return false; + return true; +} + + +/** + * Converts the CPU set to a 64-bit mask. + * + * @returns The mask. + * @param pSet Pointer to the set. + * @remarks Use with extreme care as it may lose information! + */ +DECLINLINE(uint64_t) RTCpuSetToU64(PCRTCPUSET pSet) +{ + return pSet->bmSet[0]; +} + + +/** + * Initializes the CPU set from a 64-bit mask. + * + * @param pSet Pointer to the set. + * @param fMask The mask. + */ +DECLINLINE(PRTCPUSET) RTCpuSetFromU64(PRTCPUSET pSet, uint64_t fMask) +{ + size_t i; + + pSet->bmSet[0] = fMask; + for (i = 1; i < RT_ELEMENTS(pSet->bmSet); i++) + pSet->bmSet[i] = 0; + + return pSet; +} + + +/** + * Count the CPUs in the set. + * + * @returns CPU count. + * @param pSet Pointer to the set. + */ +DECLINLINE(int) RTCpuSetCount(PCRTCPUSET pSet) +{ + int cCpus = 0; + size_t i; + + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + { + uint64_t u64 = pSet->bmSet[i]; + if (u64 != 0) + { + unsigned iCpu = 64; + while (iCpu-- > 0) + { + if (u64 & 1) + cCpus++; + u64 >>= 1; + } + } + } + return cCpus; +} + + +/** + * Get the highest set index. + * + * @returns The higest set index, -1 if all bits are clear. + * @param pSet Pointer to the set. + */ +DECLINLINE(int) RTCpuLastIndex(PCRTCPUSET pSet) +{ + size_t i = RT_ELEMENTS(pSet->bmSet); + while (i-- > 0) + { + uint64_t u64 = pSet->bmSet[i]; + if (u64) + { + /* There are more efficient ways to do this in asm.h... */ + unsigned iBit; + for (iBit = 63; iBit > 0; iBit--) + { + if (u64 & RT_BIT_64(63)) + break; + u64 <<= 1; + } + return (int)i * 64 + (int)iBit; + } + } + return 0; +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_cpuset_h */ + diff --git a/include/iprt/crc.h b/include/iprt/crc.h new file mode 100644 index 00000000..60706493 --- /dev/null +++ b/include/iprt/crc.h @@ -0,0 +1,250 @@ +/** @file + * IPRT - CRCs and Checksums. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crc_h +#define IPRT_INCLUDED_crc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crc RTCrc - Checksums and CRCs. + * @ingroup grp_rt + * @{ + */ + + +/** @defgroup grp_rt_crc32 CRC-32 + * @{ */ +/** + * Calculate CRC-32 for a memory block. + * + * @returns CRC-32 for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint32_t) RTCrc32(const void *pv, size_t cb); + +/** + * Start a multiblock CRC-32 calculation. + * + * @returns Start CRC-32. + */ +RTDECL(uint32_t) RTCrc32Start(void); + +/** + * Processes a multiblock of a CRC-32 calculation. + * + * @returns Intermediate CRC-32 value. + * @param uCRC32 Current CRC-32 intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint32_t) RTCrc32Process(uint32_t uCRC32, const void *pv, size_t cb); + +/** + * Complete a multiblock CRC-32 calculation. + * + * @returns CRC-32 value. + * @param uCRC32 Current CRC-32 intermediate value. + */ +RTDECL(uint32_t) RTCrc32Finish(uint32_t uCRC32); +/** @} */ + + +/** @defgroup grp_rt_crc64 CRC-64 Calculation + * @{ */ +/** + * Calculate CRC-64 for a memory block. + * + * @returns CRC-64 for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint64_t) RTCrc64(const void *pv, size_t cb); + +/** + * Start a multiblock CRC-64 calculation. + * + * @returns Start CRC-64. + */ +RTDECL(uint64_t) RTCrc64Start(void); + +/** + * Processes a multiblock of a CRC-64 calculation. + * + * @returns Intermediate CRC-64 value. + * @param uCRC64 Current CRC-64 intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint64_t) RTCrc64Process(uint64_t uCRC64, const void *pv, size_t cb); + +/** + * Complete a multiblock CRC-64 calculation. + * + * @returns CRC-64 value. + * @param uCRC64 Current CRC-64 intermediate value. + */ +RTDECL(uint64_t) RTCrc64Finish(uint64_t uCRC64); +/** @} */ + + +/** @defgroup grp_rt_crc_adler32 Adler-32 + * @{ */ +/** + * Calculate Adler-32 for a memory block. + * + * @returns Adler-32 for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint32_t) RTCrcAdler32(void const *pv, size_t cb); + +/** + * Start a multiblock Adler-32 calculation. + * + * @returns Start Adler-32. + */ +RTDECL(uint32_t) RTCrcAdler32Start(void); + +/** + * Processes a multiblock of a Adler-32 calculation. + * + * @returns Intermediate Adler-32 value. + * @param uCrc Current Adler-32 intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint32_t) RTCrcAdler32Process(uint32_t uCrc, void const *pv, size_t cb); + +/** + * Complete a multiblock Adler-32 calculation. + * + * @returns Adler-32 value. + * @param uCrc Current Adler-32 intermediate value. + */ +RTDECL(uint32_t) RTCrcAdler32Finish(uint32_t uCrc); + +/** @} */ + + +/** @defgroup grp_rt_crc32c CRC-32C + * @{ */ +/** + * Calculate CRC-32C for a memory block. + * + * @returns CRC-32C for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint32_t) RTCrc32C(const void *pv, size_t cb); + +/** + * Start a multiblock CRC-32 calculation. + * + * @returns Start CRC-32. + */ +RTDECL(uint32_t) RTCrc32CStart(void); + +/** + * Processes a multiblock of a CRC-32C calculation. + * + * @returns Intermediate CRC-32C value. + * @param uCRC32C Current CRC-32C intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint32_t) RTCrc32CProcess(uint32_t uCRC32C, const void *pv, size_t cb); + +/** + * Complete a multiblock CRC-32 calculation. + * + * @returns CRC-32 value. + * @param uCRC32 Current CRC-32 intermediate value. + */ +RTDECL(uint32_t) RTCrc32CFinish(uint32_t uCRC32); + +/** @} */ + + +/** @defgroup grp_rt_crc16ccitt CRC-16-CCITT + * @{ */ +/** + * Calculate CRC-16-CCITT for a memory block. + * + * @returns CRC-16-CCITT for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint16_t) RTCrc16Ccitt(const void *pv, size_t cb); + +/** + * Start a multiblock CRC-16-CCITT calculation. + * + * @returns Start CRC-16-CCITT. + */ +RTDECL(uint16_t) RTCrc16CcittStart(void); + +/** + * Processes a multiblock of a CRC-16-CCITT calculation. + * + * @returns Intermediate CRC-16-CCITT value. + * @param uCrc Current CRC-16-CCITT intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint16_t) RTCrc16CcittProcess(uint16_t uCrc, const void *pv, size_t cb); + +/** + * Complete a multiblock CRC-16-CCITT calculation. + * + * @returns CRC-16-CCITT value. + * @param uCrc Current CRC-16-CCITT intermediate value. + */ +RTDECL(uint16_t) RTCrc16CcittFinish(uint16_t uCrc); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crc_h */ + diff --git a/include/iprt/critsect.h b/include/iprt/critsect.h new file mode 100644 index 00000000..861cb675 --- /dev/null +++ b/include/iprt/critsect.h @@ -0,0 +1,768 @@ +/** @file + * IPRT - Critical Sections. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_critsect_h +#define IPRT_INCLUDED_critsect_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#if defined(IN_RING3) || defined(IN_RING0) +# include +#endif +#ifdef RT_LOCK_STRICT_ORDER +# include +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_critsect RTCritSect - Critical Sections + * + * "Critical section" synchronization primitives can be used to + * protect a section of code or data to which access must be exclusive; + * only one thread can hold access to a critical section at one time. + * + * A critical section is a fast recursive write lock; if the critical + * section is not acquired, then entering it is fast (requires no system + * call). IPRT uses the Windows terminology here; on other platform, this + * might be called a "futex" or a "fast mutex". As opposed to IPRT + * "fast mutexes" (see @ref grp_rt_sems_fast_mutex ), critical sections + * are recursive. + * + * Use RTCritSectInit to initialize a critical section; use RTCritSectEnter + * and RTCritSectLeave to acquire and release access. + * + * For an overview of all types of synchronization primitives provided + * by IPRT (event, mutex/fast mutex/read-write mutex semaphores), see + * @ref grp_rt_sems . + * + * @ingroup grp_rt + * @{ + */ + +/** + * Critical section. + */ +typedef struct RTCRITSECT +{ + /** Magic used to validate the section state. + * RTCRITSECT_MAGIC is the value of an initialized & operational section. */ + volatile uint32_t u32Magic; + /** Number of lockers. + * -1 if the section is free. */ + volatile int32_t cLockers; + /** The owner thread. */ + volatile RTNATIVETHREAD NativeThreadOwner; + /** Number of nested enter operations performed. + * Greater or equal to 1 if owned, 0 when free. + */ + volatile int32_t cNestings; + /** Section flags - the RTCRITSECT_FLAGS_* \#defines. */ + uint32_t fFlags; + /** The semaphore to block on. */ + RTSEMEVENT EventSem; + /** Lock validator record. Only used in strict builds. */ + R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec; + /** Alignment padding. */ + RTHCPTR Alignment; +} RTCRITSECT; +AssertCompileSize(RTCRITSECT, HC_ARCH_BITS == 32 ? 32 : 48); + +/** RTCRITSECT::u32Magic value. (Hiromi Uehara) */ +#define RTCRITSECT_MAGIC UINT32_C(0x19790326) + +/** @name RTCritSectInitEx flags / RTCRITSECT::fFlags + * @{ */ +/** If set, nesting(/recursion) is not allowed. */ +#define RTCRITSECT_FLAGS_NO_NESTING UINT32_C(0x00000001) +/** Disables lock validation. */ +#define RTCRITSECT_FLAGS_NO_LOCK_VAL UINT32_C(0x00000002) +/** Bootstrap hack for use with certain memory allocator locks only! */ +#define RTCRITSECT_FLAGS_BOOTSTRAP_HACK UINT32_C(0x00000004) +/** If set, the critical section becomes a dummy that doesn't serialize any + * threads. This flag can only be set at creation time. + * + * The intended use is avoiding lots of conditional code where some component + * might or might not require entering a critical section before access. */ +#define RTCRITSECT_FLAGS_NOP UINT32_C(0x00000008) +/** Indicates that this is a ring-0 critical section. */ +#define RTCRITSECT_FLAGS_RING0 UINT32_C(0x00000010) +/** @} */ + + +#if defined(IN_RING3) || defined(IN_RING0) + +/** + * Initialize a critical section. + */ +RTDECL(int) RTCritSectInit(PRTCRITSECT pCritSect); + +/** + * Initialize a critical section. + * + * @returns iprt status code. + * @param pCritSect Pointer to the critical section structure. + * @param fFlags Flags, any combination of the RTCRITSECT_FLAGS + * \#defines. + * @param hClass The class (no reference consumed). If NIL, no lock + * order validation will be performed on this lock. + * @param uSubClass The sub-class. This is used to define lock order + * within a class. RTLOCKVAL_SUB_CLASS_NONE is the + * recommended value here. + * @param pszNameFmt Name format string for the lock validator, optional + * (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); + +/** + * Changes the lock validator sub-class of the critical section. + * + * It is recommended to try make sure that nobody is using this critical section + * while changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param pCritSect The critical section. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTCritSectSetSubClass(PRTCRITSECT pCritSect, uint32_t uSubClass); + +/** + * Enter a critical section. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * @param pCritSect The critical section. + */ +RTDECL(int) RTCritSectEnter(PRTCRITSECT pCritSect); + +/** + * Enter a critical section. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pCritSect The critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Try enter a critical section. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pCritSect The critical section. + */ +RTDECL(int) RTCritSectTryEnter(PRTCRITSECT pCritSect); + +/** + * Try enter a critical section. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pCritSect The critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +# ifdef IN_RING3 /* Crazy APIs: ring-3 only. */ + +/** + * Enter multiple critical sections. + * + * This function will enter ALL the specified critical sections before returning. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * @param cCritSects Number of critical sections in the array. + * @param papCritSects Array of critical section pointers. + * + * @remark Please note that this function will not necessarily come out favourable in a + * fight with other threads which are using the normal RTCritSectEnter() function. + * Therefore, avoid having to enter multiple critical sections! + */ +RTDECL(int) RTCritSectEnterMultiple(size_t cCritSects, PRTCRITSECT *papCritSects); + +/** + * Enter multiple critical sections. + * + * This function will enter ALL the specified critical sections before returning. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param cCritSects Number of critical sections in the array. + * @param papCritSects Array of critical section pointers. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + * + * @remark See RTCritSectEnterMultiple(). + */ +RTDECL(int) RTCritSectEnterMultipleDebug(size_t cCritSects, PRTCRITSECT *papCritSects, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +# endif /* IN_RING3 */ + +/** + * Leave a critical section. + * + * @returns VINF_SUCCESS. + * @param pCritSect The critical section. + */ +RTDECL(int) RTCritSectLeave(PRTCRITSECT pCritSect); + +/** + * Leave multiple critical sections. + * + * @returns VINF_SUCCESS. + * @param cCritSects Number of critical sections in the array. + * @param papCritSects Array of critical section pointers. + */ +RTDECL(int) RTCritSectLeaveMultiple(size_t cCritSects, PRTCRITSECT *papCritSects); + +/** + * Deletes a critical section. + * + * @returns VINF_SUCCESS. + * @param pCritSect The critical section. + */ +RTDECL(int) RTCritSectDelete(PRTCRITSECT pCritSect); + +/** + * Checks the caller is the owner of the critical section. + * + * @returns true if owner. + * @returns false if not owner. + * @param pCritSect The critical section. + */ +DECLINLINE(bool) RTCritSectIsOwner(PCRTCRITSECT pCritSect) +{ + return pCritSect->NativeThreadOwner == RTThreadNativeSelf(); +} + +#endif /* IN_RING3 || IN_RING0 */ + +/** + * Checks the section is owned by anyone. + * + * @returns true if owned. + * @returns false if not owned. + * @param pCritSect The critical section. + */ +DECLINLINE(bool) RTCritSectIsOwned(PCRTCRITSECT pCritSect) +{ + return pCritSect->NativeThreadOwner != NIL_RTNATIVETHREAD; +} + +/** + * Gets the thread id of the critical section owner. + * + * @returns Thread id of the owner thread if owned. + * @returns NIL_RTNATIVETHREAD is not owned. + * @param pCritSect The critical section. + */ +DECLINLINE(RTNATIVETHREAD) RTCritSectGetOwner(PCRTCRITSECT pCritSect) +{ + return pCritSect->NativeThreadOwner; +} + +/** + * Checks if a critical section is initialized or not. + * + * @returns true if initialized. + * @returns false if not initialized. + * @param pCritSect The critical section. + */ +DECLINLINE(bool) RTCritSectIsInitialized(PCRTCRITSECT pCritSect) +{ + return pCritSect->u32Magic == RTCRITSECT_MAGIC; +} + +/** + * Gets the recursion depth. + * + * @returns The recursion depth. + * @param pCritSect The Critical section + */ +DECLINLINE(uint32_t) RTCritSectGetRecursion(PCRTCRITSECT pCritSect) +{ + return (uint32_t)pCritSect->cNestings; +} + +/** + * Gets the waiter count + * + * @returns The waiter count + * @param pCritSect The Critical section + */ +DECLINLINE(int32_t) RTCritSectGetWaiters(PCRTCRITSECT pCritSect) +{ + return pCritSect->cLockers; +} + +/* Lock strict build: Remap the three enter calls to the debug versions. */ +#if defined(RT_LOCK_STRICT) && !defined(RTCRITSECT_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# ifdef IPRT_INCLUDED_asm_h +# define RTCritSectEnter(pCritSect) RTCritSectEnterDebug(pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectTryEnter(pCritSect) RTCritSectTryEnterDebug(pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectEnterMultiple(cCritSects, pCritSect) RTCritSectEnterMultipleDebug((cCritSects), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define RTCritSectEnter(pCritSect) RTCritSectEnterDebug(pCritSect, 0, RT_SRC_POS) +# define RTCritSectTryEnter(pCritSect) RTCritSectTryEnterDebug(pCritSect, 0, RT_SRC_POS) +# define RTCritSectEnterMultiple(cCritSects, pCritSect) RTCritSectEnterMultipleDebug((cCritSects), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +/* Strict lock order: Automatically classify locks by init location. */ +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTCRITSECT_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# define RTCritSectInit(pCritSect) \ + RTCritSectInitEx((pCritSect), 0 /*fFlags*/, \ + RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ + RTLOCKVAL_SUB_CLASS_NONE, NULL) +#endif + +/** @} */ + + + +/** @defgroup grp_rt_critsectrw RTCritSectRw - Read/Write Critical Sections + * @ingroup grp_rt + * @{ + */ + +/** + * Union that allows us to atomically update both the state and + * exclusive owner if the hardware supports cmpxchg16b or similar. + */ +typedef union RTCRITSECTRWSTATE +{ + struct + { + /** The state variable. + * All accesses are atomic and it bits are defined like this: + * Bits 0..14 - cReads. + * Bit 15 - Unused. + * Bits 16..31 - cWrites. + * Bit 31 - fDirection; 0=Read, 1=Write. + * Bits 32..46 - cWaitingReads + * Bit 47 - Unused. + * Bits 48..62 - cWaitingWrites - doesn't make sense here, not used. + * Bit 63 - Unused. + */ + uint64_t u64State; + /** The write owner. */ + RTNATIVETHREAD hNativeWriter; + } s; + RTUINT128U u128; +} RTCRITSECTRWSTATE; + + +/** + * Read/write critical section. + */ +typedef struct RTCRITSECTRW +{ + /** Magic used to validate the section state. + * RTCRITSECTRW_MAGIC is the value of an initialized & operational section. */ + volatile uint32_t u32Magic; + + /** Indicates whether hEvtRead needs resetting. */ + bool volatile fNeedReset; + /** Explicit alignment padding. */ + bool volatile afPadding[1]; + /** Section flags - the RTCRITSECT_FLAGS_* \#defines. */ + uint16_t fFlags; + + /** The number of reads made by the current writer. */ + uint32_t volatile cWriterReads; + /** The number of recursions made by the current writer. (The initial grabbing + * of the lock counts as the first one.) */ + uint32_t volatile cWriteRecursions; + /** The core state. */ + RTCRITSECTRWSTATE volatile u; + + /** What the writer threads are blocking on. */ + RTSEMEVENT hEvtWrite; + /** What the read threads are blocking on when waiting for the writer to + * finish. */ + RTSEMEVENTMULTI hEvtRead; + + /** The validator record for the writer. */ + R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorWrite; + /** The validator record for the readers. */ + R3R0PTRTYPE(PRTLOCKVALRECSHRD) pValidatorRead; +} RTCRITSECTRW; +AssertCompileSize(RTCRITSECTRW, HC_ARCH_BITS == 32 ? 48 : 64); + +/** RTCRITSECTRW::u32Magic value. (Eric Allan Dolphy, Jr.) */ +#define RTCRITSECTRW_MAGIC UINT32_C(0x19280620) +/** RTCRITSECTRW::u32Magic dead value. */ +#define RTCRITSECTRW_MAGIC_DEAD UINT32_C(0x19640629) + +/** @name RTCRITSECTRW::u64State values. + * @note Using RTCSRW instead of RTCRITSECTRW to save space. + * @{ */ +#define RTCSRW_CNT_BITS 15 +#define RTCSRW_CNT_MASK UINT64_C(0x00007fff) + +#define RTCSRW_CNT_RD_SHIFT 0 +#define RTCSRW_CNT_RD_MASK (RTCSRW_CNT_MASK << RTCSRW_CNT_RD_SHIFT) +#define RTCSRW_CNT_WR_SHIFT 16 +#define RTCSRW_CNT_WR_MASK (RTCSRW_CNT_MASK << RTCSRW_CNT_WR_SHIFT) + +#define RTCSRW_DIR_SHIFT 31 +#define RTCSRW_DIR_MASK RT_BIT_64(RTCSRW_DIR_SHIFT) +#define RTCSRW_DIR_READ UINT64_C(0) +#define RTCSRW_DIR_WRITE UINT64_C(1) + +#define RTCSRW_WAIT_CNT_RD_SHIFT 32 +#define RTCSRW_WAIT_CNT_RD_MASK (RTCSRW_CNT_MASK << RTCSRW_WAIT_CNT_RD_SHIFT) +/* #define RTCSRW_WAIT_CNT_WR_SHIFT 48 */ +/* #define RTCSRW_WAIT_CNT_WR_MASK (RTCSRW_CNT_MASK << RTCSRW_WAIT_CNT_WR_SHIFT) */ +/** @} */ + +#if defined(IN_RING3) || defined(IN_RING0) + +/** + * Initialize a critical section. + */ +RTDECL(int) RTCritSectRwInit(PRTCRITSECTRW pThis); + +/** + * Initialize a critical section. + * + * @returns IPRT status code. + * @param pThis Pointer to the read/write critical section. + * @param fFlags Flags, any combination of the RTCRITSECT_FLAGS + * \#defines. + * @param hClass The class (no reference consumed). If NIL, no lock + * order validation will be performed on this lock. + * @param uSubClass The sub-class. This is used to define lock order + * within a class. RTLOCKVAL_SUB_CLASS_NONE is the + * recommended value here. + * @param pszNameFmt Name format string for the lock validator, optional + * (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTCritSectRwInitEx(PRTCRITSECTRW pThis, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); + +/** + * Changes the lock validator sub-class of the critical section. + * + * It is recommended to try make sure that nobody is using this critical section + * while changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param pThis Pointer to the read/write critical section. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTCritSectRwSetSubClass(PRTCRITSECTRW pThis, uint32_t uSubClass); + + +/** + * Enter a critical section with shared (read) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwEnterShared(PRTCRITSECTRW pThis); + +/** + * Enter a critical section with shared (read) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectRwEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Try enter a critical section with shared (read) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwTryEnterShared(PRTCRITSECTRW pThis); + +/** + * Try enter a critical section with shared (read) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectRwTryEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Leave a critical section held with shared access. + * + * @returns IPRT status code. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwLeaveShared(PRTCRITSECTRW pThis); + + +/** + * Enter a critical section with exclusive (write) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwEnterExcl(PRTCRITSECTRW pThis); + +/** + * Enter a critical section with exclusive (write) access. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectRwEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Try enter a critical section with exclusive (write) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwTryEnterExcl(PRTCRITSECTRW pThis); + +/** + * Try enter a critical section with exclusive (write) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectRwTryEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Leave a critical section held exclusively. + * + * @returns IPRT status code; VINF_SUCCESS, VERR_NOT_OWNER, VERR_SEM_DESTROYED, + * or VERR_WRONG_ORDER. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwLeaveExcl(PRTCRITSECTRW pThis); + + +/** + * Deletes a critical section. + * + * @returns VINF_SUCCESS. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwDelete(PRTCRITSECTRW pThis); + +/** + * Checks the caller is the exclusive (write) owner of the critical section. + * + * @retval true if owner. + * @retval false if not owner. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(bool) RTCritSectRwIsWriteOwner(PRTCRITSECTRW pThis); + +/** + * Checks if the caller is one of the read owners of the critical section. + * + * @note !CAUTION! This API doesn't work reliably if lock validation isn't + * enabled. Meaning, the answer is not trustworhty unless + * RT_LOCK_STRICT or RTCRITSECTRW_STRICT was defined at build time. + * Also, make sure you do not use RTCRITSECTRW_FLAGS_NO_LOCK_VAL when + * creating the semaphore. And finally, if you used a locking class, + * don't disable deadlock detection by setting cMsMinDeadlock to + * RT_INDEFINITE_WAIT. + * + * In short, only use this for assertions. + * + * @returns @c true if reader, @c false if not. + * @param pThis Pointer to the read/write critical section. + * @param fWannaHear What you'd like to hear when lock validation is not + * available. (For avoiding asserting all over the + * place.) + */ +RTDECL(bool) RTCritSectRwIsReadOwner(PRTCRITSECTRW pThis, bool fWannaHear); + +/** + * Gets the write recursion count. + * + * @returns The write recursion count (0 if bad critsect). + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(uint32_t) RTCritSectRwGetWriteRecursion(PRTCRITSECTRW pThis); + +/** + * Gets the read recursion count of the current writer. + * + * @returns The read recursion count (0 if bad critsect). + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(uint32_t) RTCritSectRwGetWriterReadRecursion(PRTCRITSECTRW pThis); + +/** + * Gets the current number of reads. + * + * This includes all read recursions, so it might be higher than the number of + * read owners. It does not include reads done by the current writer. + * + * @returns The read count (0 if bad critsect). + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(uint32_t) RTCritSectRwGetReadCount(PRTCRITSECTRW pThis); + +#endif /* IN_RING3 || IN_RING0 */ + +/** + * Checks if a critical section is initialized or not. + * + * @retval true if initialized. + * @retval false if not initialized. + * @param pThis Pointer to the read/write critical section. + */ +DECLINLINE(bool) RTCritSectRwIsInitialized(PCRTCRITSECTRW pThis) +{ + return pThis->u32Magic == RTCRITSECTRW_MAGIC; +} + +/* Lock strict build: Remap the three enter calls to the debug versions. */ +#if defined(RT_LOCK_STRICT) && !defined(RTCRITSECTRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# ifdef IPRT_INCLUDED_asm_h +# define RTCritSectRwEnterExcl(pThis) RTCritSectRwEnterExclDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectRwTryEnterExcl(pThis) RTCritSectRwTryEnterExclDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectRwEnterShared(pThis) RTCritSectRwEnterSharedDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectRwTryEnterShared(pThis) RTCritSectRwTryEnterSharedDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define RTCritSectRwEnterExcl(pThis) RTCritSectRwEnterExclDebug(pThis, 0, RT_SRC_POS) +# define RTCritSectRwTryEnterExcl(pThis) RTCritSectRwTryEnterExclDebug(pThis, 0, RT_SRC_POS) +# define RTCritSectRwEnterShared(pThis) RTCritSectRwEnterSharedDebug(pThis, 0, RT_SRC_POS) +# define RTCritSectRwTryEnterShared(pThis) RTCritSectRwTryEnterSharedDebug(pThis, 0, RT_SRC_POS) +# endif +#endif + +/* Strict lock order: Automatically classify locks by init location. */ +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTCRITSECTRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# define RTCritSectRwInit(a_pThis) \ + RTCritSectRwInitEx((a_pThis), 0 /*fFlags*/, \ + RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ + RTLOCKVAL_SUB_CLASS_NONE, NULL) +#endif + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_critsect_h */ + diff --git a/include/iprt/crypto/Makefile.kup b/include/iprt/crypto/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/crypto/applecodesign.h b/include/iprt/crypto/applecodesign.h new file mode 100644 index 00000000..df546e06 --- /dev/null +++ b/include/iprt/crypto/applecodesign.h @@ -0,0 +1,290 @@ +/** @file + * IPRT - Apple Code Signing Structures and APIs. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_applecodesign_h +#define IPRT_INCLUDED_crypto_applecodesign_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +/** @defgroup grp_rt_craplcs RTCrAppleCs - Apple Code Signing + * @ingroup grp_rt_crypto + * @{ + */ + +/** Apple developer ID for iPhone application software development signing. */ +#define RTCR_APPLE_CS_DEVID_IPHONE_SW_DEV_OID "1.2.840.113635.100.6.1.2" +/** Apple developer ID for Mac application software development signing. */ +#define RTCR_APPLE_CS_DEVID_MAC_SW_DEV_OID "1.2.840.113635.100.6.1.12" +/** Apple developer ID for application signing. */ +#define RTCR_APPLE_CS_DEVID_APPLICATION_OID "1.2.840.113635.100.6.1.13" +/** Apple developer ID for installer signing. */ +#define RTCR_APPLE_CS_DEVID_INSTALLER_OID "1.2.840.113635.100.6.1.14" +/** Apple developer ID for kernel extension signing. */ +#define RTCR_APPLE_CS_DEVID_KEXT_OID "1.2.840.113635.100.6.1.18" +/** Apple certificate policy OID. */ +#define RTCR_APPLE_CS_CERTIFICATE_POLICY_OID "1.2.840.113635.100.5.1" + + +/** @name RTCRAPLCS_MAGIC_XXX - Apple code signing magic values for identifying blobs + * @note No byte order conversion required. + * @{ */ +#define RTCRAPLCS_MAGIC_BLOBWRAPPER RT_N2H_U32_C(UINT32_C(0xfade0b01)) +#define RTCRAPLCS_MAGIC_EMBEDDED_SIGNATURE_OLD RT_N2H_U32_C(UINT32_C(0xfade0b02)) +#define RTCRAPLCS_MAGIC_REQUIREMENT RT_N2H_U32_C(UINT32_C(0xfade0c00)) +#define RTCRAPLCS_MAGIC_REQUIREMENTS RT_N2H_U32_C(UINT32_C(0xfade0c01)) +#define RTCRAPLCS_MAGIC_CODEDIRECTORY RT_N2H_U32_C(UINT32_C(0xfade0c02)) +#define RTCRAPLCS_MAGIC_EMBEDDED_SIGNATURE RT_N2H_U32_C(UINT32_C(0xfade0cc0)) +#define RTCRAPLCS_MAGIC_DETACHED_SIGNATURE RT_N2H_U32_C(UINT32_C(0xfade0cc1)) +/** @} */ + +/** @name Apple code signing versions. + * @note Requires byte order conversion of the field value. That way + * greater-than and less-than comparisons works correctly. + * @{ */ +#define RTCRAPLCS_VER_2_0 UINT32_C(0x00020000) +#define RTCRAPLCS_VER_SUPPORTS_SCATTER UINT32_C(0x00020100) +#define RTCRAPLCS_VER_SUPPORTS_TEAMID UINT32_C(0x00020200) +#define RTCRAPLCS_VER_SUPPORTS_CODE_LIMIT_64 UINT32_C(0x00020300) +#define RTCRAPLCS_VER_SUPPORTS_EXEC_SEG UINT32_C(0x00020400) +/** @} */ + +/** @name RTCRAPLCS_SLOT_XXX - Apple code signing slots. + * @note No byte order conversion required. + * @{ */ +#define RTCRAPLCS_SLOT_CODEDIRECTORY RT_N2H_U32_C(UINT32_C(0x00000000)) +#define RTCRAPLCS_SLOT_INFO RT_N2H_U32_C(UINT32_C(0x00000001)) +#define RTCRAPLCS_SLOT_REQUIREMENTS RT_N2H_U32_C(UINT32_C(0x00000002)) +#define RTCRAPLCS_SLOT_RESOURCEDIR RT_N2H_U32_C(UINT32_C(0x00000003)) +#define RTCRAPLCS_SLOT_APPLICATION RT_N2H_U32_C(UINT32_C(0x00000004)) +#define RTCRAPLCS_SLOT_ENTITLEMENTS RT_N2H_U32_C(UINT32_C(0x00000005)) +#define RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES RT_N2H_U32_C(UINT32_C(0x00001000)) +#define RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES_END RT_N2H_U32_C(UINT32_C(0x00001005)) +#define RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES_COUNT UINT32_C(0x00000005) +#define RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORY_INC RT_N2H_U32_C(UINT32_C(0x00000001)) +/** The signature. + * This is simply a RTCRAPLCSHDR/RTCRAPLCS_MAGIC_BLOBWRAPPER followed by a DER + * encoded \#PKCS7 ContentInfo structure containing signedData. The inner + * signedData structure signs external data, so its ContentInfo member is set + * to 1.2.840.113549.1.7.1 and has no data. */ +#define RTCRAPLCS_SLOT_SIGNATURE RT_N2H_U32_C(UINT32_C(0x00010000)) +/** @} */ + +/** @name RTCRAPLCS_HASHTYPE_XXX - Apple code signing hash types + * @note Byte sized field, so no byte order concerns. + * @{ */ +#define RTCRAPLCS_HASHTYPE_SHA1 UINT8_C(1) +#define RTCRAPLCS_HASHTYPE_SHA256 UINT8_C(2) +#define RTCRAPLCS_HASHTYPE_SHA256_TRUNCATED UINT8_C(3) /**< Truncated to 20 bytes (SHA1 size). */ +#define RTCRAPLCS_HASHTYPE_SHA384 UINT8_C(4) +/** @} */ + + +/** + * Apple code signing blob header. + */ +typedef struct RTCRAPLCSHDR +{ + /** The magic value (RTCRAPLCS_MAGIC_XXX). + * (Big endian, but constant are big endian already.) */ + uint32_t uMagic; + /** The total length of the blob. Big endian. */ + uint32_t cb; +} RTCRAPLCSHDR; +AssertCompileSize(RTCRAPLCSHDR, 8); +/** Pointer to a CS blob header. */ +typedef RTCRAPLCSHDR *PRTCRAPLCSHDR; +/** Pointer to a const CS blob header. */ +typedef RTCRAPLCSHDR const *PCRTCRAPLCSHDR; + +/** + * Apple code signing super blob slot. + */ +typedef struct RTCRAPLCSBLOBSLOT +{ + /** Slot type, RTCRAPLCS_SLOT_XXX. + * (Big endian, but so are the constants too). */ + uint32_t uType; + /** Data offset. Big endian. */ + uint32_t offData; +} RTCRAPLCSBLOBSLOT; +AssertCompileSize(RTCRAPLCSBLOBSLOT, 8); +/** Pointer to a super blob slot. */ +typedef RTCRAPLCSBLOBSLOT *PRTCRAPLCSBLOBSLOT; +/** Pointer to a const super blob slot. */ +typedef RTCRAPLCSBLOBSLOT const *PCRTCRAPLCSBLOBSLOT; + +/** + * Apple code signing super blob. + */ +typedef struct RTCRAPLCSSUPERBLOB +{ + /** Header (uMagic = RTCRAPLCS_MAGIC_EMBEDDED_SIGNATURE? + * or RTCRAPLCS_MAGIC_EMBEDDED_SIGNATURE_OLD? ). */ + RTCRAPLCSHDR Hdr; + /** Number of slots. Big endian. */ + uint32_t cSlots; + /** Slots. */ + RT_FLEXIBLE_ARRAY_EXTENSION + RTCRAPLCSBLOBSLOT aSlots[RT_FLEXIBLE_ARRAY]; +} RTCRAPLCSSUPERBLOB; +AssertCompileMemberOffset(RTCRAPLCSSUPERBLOB, aSlots, 12); +/** Pointer to a CS super blob. */ +typedef RTCRAPLCSSUPERBLOB *PRTCRAPLCSSUPERBLOB; +/** Pointer to a const CS super blob. */ +typedef RTCRAPLCSSUPERBLOB const *PCRTCRAPLCSSUPERBLOB; + +/** + * Code directory (RTCRAPLCS_MAGIC_CODEDIRECTORY). + */ +typedef struct RTCRAPLCSCODEDIRECTORY +{ + /** 0x00: Header (uMagic = RTCRAPLCS_MAGIC_CODEDIRECTORY). */ + RTCRAPLCSHDR Hdr; + /** 0x08: The version number (RTCRAPLCS_VER_XXX). + * @note Big endian, host order constants. */ + uint32_t uVersion; + /** 0x0c: Flags & mode, RTCRAPLCS_???. (Big endian. ) */ + uint32_t fFlags; + /** 0x10: Offset of the hash slots. Big endian. + * Special slots found below this offset, code slots at and after. */ + uint32_t offHashSlots; + /** 0x14: Offset of the identifier string. Big endian. */ + uint32_t offIdentifier; + /** 0x18: Number of special hash slots. Hubertus Bigend style. */ + uint32_t cSpecialSlots; + /** 0x1c: Number of code hash slots. Big endian. */ + uint32_t cCodeSlots; + /** 0x20: Number of bytes of code that's covered, 32-bit wide. Big endian. */ + uint32_t cbCodeLimit32; + /** 0x24: The hash size. */ + uint8_t cbHash; + /** 0x25: The hash type (RTCRAPLCS_HASHTYPE_XXX). */ + uint8_t bHashType; + /** 0x26: Platform identifier or zero. */ + uint8_t idPlatform; + /** 0x27: The page shift value. zero if infinite page size. */ + uint8_t cPageShift; + /** 0x28: Spare field, MBZ. */ + uint32_t uUnused1; + /** 0x2c: Offset of scatter vector (optional). Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_SCATTER */ + uint32_t offScatter; + /** 0x30: Offset of team identifier (optional). Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_TEAMID */ + uint32_t offTeamId; + /** 0x34: Unused field, MBZ. + * @since RTCRAPLCS_VER_SUPPORTS_CODE_LIMIT_64 */ + uint32_t uUnused2; + /** 0x38: Number of bytes of code that's covered, 64-bit wide. Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_CODE_LIMIT_64 */ + uint64_t cbCodeLimit64; + /** 0x40: File offset of the first segment. Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_EXEC_SEG */ + uint64_t offExecSeg; + /** 0x48: The size of the first segment. Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_EXEC_SEG */ + uint64_t cbExecSeg; + /** 0x50: Flags for the first segment. Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_EXEC_SEG */ + uint64_t fExecSeg; +} RTCRAPLCSCODEDIRECTORY; +AssertCompileSize(RTCRAPLCSCODEDIRECTORY, 0x58); +/** Pointer to a CS code directory. */ +typedef RTCRAPLCSCODEDIRECTORY *PRTCRAPLCSCODEDIRECTORY; +/** Pointer to a const CS code directory. */ +typedef RTCRAPLCSCODEDIRECTORY const *PCRTCRAPLCSCODEDIRECTORY; + + +/** + * IPRT structure for working with an Apple code signing blob. + */ +typedef struct RTCRAPLCS +{ + uint8_t const *pbBlob; + size_t cbBlob; + size_t auReserved[4]; +} RTCRAPLCS; +/** Pointer to an IPRT CS blob descriptor. */ +typedef RTCRAPLCS *PRTCRAPLCS; + +/** + * Initialize a RTCRAPLCS descriptor and validate the blob data. + * + * @returns IPRT status code. + * @param pDesc The descirptor to initialize. + * @param pvBlob The blob bytes. + * @param cbBlob The number of bytes in the blob. + * @param fFlags Future validation flags, MBZ. + * @param pErrInfo Where to return additional error details. Optional. + */ +RTDECL(int) RTCrAppleCsInit(PRTCRAPLCS pDesc, void const *pvBlob, size_t cbBlob, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Callback used by RTCrAppleCsVerifyImage to digest a section of the image. + * + * @return IPRT status code. + * @param hDigest The digest to feed the bytes to. + * @param off The RVA of the bytes to digest. + * @param cb Number of bytes to digest. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTCRAPPLECSDIGESTAREA,(RTCRDIGEST hDigest, size_t off, size_t cb, void *pvUser)); +/** Pointer to a image digest callback. */ +typedef FNRTCRAPPLECSDIGESTAREA *PFNRTCRAPPLECSDIGESTAREA; + +/** + * Verifies an image against the given signature blob. + * + * @return IPRT status code. + * @param pDesc The apple code signing blob to verify against. + * @param fFlags Future verification flags, MBZ. + * @param pfnCallback Image digest callback. + * @param pvUser User argument for the callback. + * @param pErrInfo Where to return additional error details. Optional. + */ +RTDECL(int) RTCrAppleCsVerifyImage(PRTCRAPLCS pDesc, uint32_t fFlags, PFNRTCRAPPLECSDIGESTAREA pfnCallback, + void *pvUser, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrAppleCsQuerySigneddData(PRTCRAPLCS pDesc, PRTCRPKCS7SIGNEDDATA pSignedData, PRTERRINFO pErrInfo); + +/** @} */ + +#endif /* !IPRT_INCLUDED_crypto_applecodesign_h */ + diff --git a/include/iprt/crypto/cipher.h b/include/iprt/crypto/cipher.h new file mode 100644 index 00000000..9fb3cd02 --- /dev/null +++ b/include/iprt/crypto/cipher.h @@ -0,0 +1,156 @@ +/** @file + * IPRT - Crypto - Symmetric Ciphers. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_cipher_h +#define IPRT_INCLUDED_crypto_cipher_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +RT_C_DECLS_BEGIN + +struct RTCRX509SUBJECTPUBLICKEYINFO; + +/** @defgroup grp_rt_crcipher RTCrCipher - Symmetric Ciphers + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * A symmetric cipher handle. + * + * @remarks In OpenSSL terms this corresponds to a EVP_CIPHER, while in Microsoft + * terms it is an algorithm handle. The latter is why a handle was + * choosen rather than constant descriptor structure pointer. */ +typedef struct RTCRCIPHERINT *RTCRCIPHER; +/** Pointer to a symmetric cipher handle. */ +typedef RTCRCIPHER *PRTCRCIPHER; +/** Nil symmetric cipher handle. */ +#define NIL_RTCRCIPHER ((RTCRCIPHER)0) +/** Symmetric cipher context */ +typedef struct RTCRCIPHERCTXINT *RTCRCIPHERCTX; +/** Pointer to a symmetric cipher context */ +typedef RTCRCIPHERCTX *PRTCRCIPHERCTX; +/** Nil symmetric cipher context */ +#define NIL_RTCRCIPHERCTX ((RTCRCIPHERCTX)0) + +/** + * Symmetric cipher types. + * + * @note Only add new types at the end, existing values must be stable. + */ +typedef enum RTCRCIPHERTYPE +{ + /** Invalid zero value. */ + RTCRCIPHERTYPE_INVALID = 0, + /** XTS-AES-128 (NIST SP 800-38E). */ + RTCRCIPHERTYPE_XTS_AES_128, + /** XTS-AES-256 (NIST SP 800-38E). */ + RTCRCIPHERTYPE_XTS_AES_256, + /** GCM-AES-128. */ + RTCRCIPHERTYPE_GCM_AES_128, + /** GCM-AES-256. */ + RTCRCIPHERTYPE_GCM_AES_256, + /* CTR-AES-128 */ + RTCRCIPHERTYPE_CTR_AES_128, + /* CTR-AES-256 */ + RTCRCIPHERTYPE_CTR_AES_256, + /** End of valid symmetric cipher types. */ + RTCRCIPHERTYPE_END, + /** Make sure the type is a 32-bit one. */ + RTCRCIPHERTYPE_32BIT_HACK = 0x7fffffff +} RTCRCIPHERTYPE; + + +RTDECL(int) RTCrCipherOpenByType(PRTCRCIPHER phCipher, RTCRCIPHERTYPE enmType, uint32_t fFlags); +RTDECL(uint32_t) RTCrCipherRetain(RTCRCIPHER hCipher); +RTDECL(uint32_t) RTCrCipherRelease(RTCRCIPHER hCipher); +RTDECL(uint32_t) RTCrCipherGetKeyLength(RTCRCIPHER hCipher); +RTDECL(uint32_t) RTCrCipherGetInitializationVectorLength(RTCRCIPHER hCipher); +RTDECL(uint32_t) RTCrCipherGetBlockSize(RTCRCIPHER hCipher); + +RTDECL(int) RTCrCipherCtxFree(RTCRCIPHERCTX phCipherCtx); + +RTDECL(int) RTCrCipherCtxEncryptInit(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + PRTCRCIPHERCTX phCipherCtx); +RTDECL(int) RTCrCipherCtxEncryptProcess(RTCRCIPHERCTX hCipherCtx, void const *pvPlainText, size_t cbPlainText, + void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted); +RTDECL(int) RTCrCipherCtxEncryptFinish(RTCRCIPHERCTX hCipherCtx, + void *pvEncrypted, size_t *pcbEncrypted, + void *pvTag, size_t cbTag, size_t *pcbTag); + +RTDECL(int) RTCrCipherCtxDecryptInit(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + void *pvTag, size_t cbTag, PRTCRCIPHERCTX phCipherCtx); +RTDECL(int) RTCrCipherCtxDecryptProcess(RTCRCIPHERCTX hCipherCtx, + void const *pvEncrypted, size_t cbEncrypted, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText); +RTDECL(int) RTCrCipherCtxDecryptFinish(RTCRCIPHERCTX hCipherCtx, + void *pvPlainText, size_t *pcbPlainText); + + +RTDECL(int) RTCrCipherEncrypt(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvPlainText, size_t cbPlainText, + void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted); +RTDECL(int) RTCrCipherDecrypt(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvEncrypted, size_t cbEncrypted, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText); +RTDECL(int) RTCrCipherEncryptEx(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + void const *pvPlainText, size_t cbPlainText, + void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted, + void *pvTag, size_t cbTag, size_t *pcbTag); +RTDECL(int) RTCrCipherDecryptEx(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + void *pvTag, size_t cbTag, + void const *pvEncrypted, size_t cbEncrypted, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_cipher_h */ + diff --git a/include/iprt/crypto/digest.h b/include/iprt/crypto/digest.h new file mode 100644 index 00000000..bdf3698a --- /dev/null +++ b/include/iprt/crypto/digest.h @@ -0,0 +1,331 @@ +/** @file + * IPRT - Crypto - Cryptographic Hash / Message Digest. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_digest_h +#define IPRT_INCLUDED_crypto_digest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crdigest RTCrDigest - Crypographic Hash / Message Digest API. + * @ingroup grp_rt + * @{ + */ + +/** + * Cryptographic hash / message digest provider descriptor. + * + * This gives the basic details and identifiers of the algorithm as well as + * function pointers to the implementation. + */ +typedef struct RTCRDIGESTDESC +{ + /** The message digest provider name. */ + const char *pszName; + /** The object ID string. */ + const char *pszObjId; + /** Pointer to a NULL terminated table of alias object IDs (optional). */ + const char * const *papszObjIdAliases; + /** The IPRT digest type. */ + RTDIGESTTYPE enmType; + /** The max size of the final hash (binary). */ + uint32_t cbHash; + /** The size of the state. */ + uint32_t cbState; + /** Flags, RTCRDIGESTDESC_F_XXX. */ + uint32_t fFlags; + + /** + * Allocates the digest data. + */ + DECLCALLBACKMEMBER(void *, pfnNew,(void)); + + /** + * Frees the digest data. + * + * @param pvState The opaque message digest state. + */ + DECLCALLBACKMEMBER(void, pfnFree,(void *pvState)); + + /** + * Updates the digest with more data. + * + * @param pvState The opaque message digest state. + * @param pvData The data to add to the digest. + * @param cbData The amount of data to add to the digest. + */ + DECLCALLBACKMEMBER(void, pfnUpdate,(void *pvState, const void *pvData, size_t cbData)); + + /** + * Finalizes the digest calculation. + * + * @param pvState The opaque message digest state. + * @param pbHash Where to store the output digest. This buffer is at + * least RTCRDIGESTDESC::cbHash bytes large. + */ + DECLCALLBACKMEMBER(void, pfnFinal,(void *pvState, uint8_t *pbHash)); + + /** + * (Re-)Initializes the digest. Optional. + * + * Optional, RT_BZERO will be used if NULL. + * + * @returns IPRT status code. + * @param pvState The opaque message digest state. + * @param pvOpaque Opaque algortihm specific parameter. + * @param fReInit Set if this is a re-init call. + */ + DECLCALLBACKMEMBER(int, pfnInit,(void *pvState, void *pvOpaque, bool fReInit)); + + /** + * Deletes the message digest state. + * + * Optional, memset will be used if NULL. + * + * @param pvState The opaque message digest state. + */ + DECLCALLBACKMEMBER(void, pfnDelete,(void *pvState)); + + /** + * Clones the message digest state. + * + * Optional, memcpy will be used if NULL. + * + * @returns IPRT status code. + * @param pvState The opaque message digest state (destination). + * @param pvSrcState The opaque message digest state to clone (source). + */ + DECLCALLBACKMEMBER(int, pfnClone,(void *pvState, void const *pvSrcState)); + + /** + * Gets the hash size. + * + * Optional, if not provided RTCRDIGESTDESC::cbHash will be returned. If + * provided though, RTCRDIGESTDESC::cbHash must be set to the largest possible + * hash size. + * + * @returns The hash size. + * @param pvState The opaque message digest state. + */ + DECLCALLBACKMEMBER(uint32_t, pfnGetHashSize,(void *pvState)); + + /** + * Gets the digest type (when enmType is RTDIGESTTYPE_UNKNOWN). + * + * @returns The hash size. + * @param pvState The opaque message digest state. + */ + DECLCALLBACKMEMBER(RTDIGESTTYPE, pfnGetDigestType,(void *pvState)); +} RTCRDIGESTDESC; +/** Pointer to const message digest details and vtable. */ +typedef RTCRDIGESTDESC const *PCRTCRDIGESTDESC; + +/** @name RTCRDIGESTDESC_F_XXX + * @{ */ +/** Digest is deprecated. */ +#define RTCRDIGESTDESC_F_DEPRECATED RT_BIT_32(0) +/** Digest is compromised. */ +#define RTCRDIGESTDESC_F_COMPROMISED RT_BIT_32(1) +/** Digest is severely compromised. */ +#define RTCRDIGESTDESC_F_SERVERELY_COMPROMISED RT_BIT_32(2) +/** @} */ + +/** + * Finds a cryptographic hash / message digest descriptor by object identifier + * string. + * + * @returns Pointer to the message digest details & vtable if found. NULL if + * not found. + * @param pszObjId The dotted object identifier string of the message + * digest algorithm. + * @param ppvOpaque Where to return an opaque implementation specfici + * sub-type indicator that can be passed to + * RTCrDigestCreate. This is optional, fewer + * algortihms are available if not specified. + */ +RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjIdString(const char *pszObjId, void **ppvOpaque); + +/** + * Finds a cryptographic hash / message digest descriptor by object identifier + * ASN.1 object. + * + * @returns Pointer to the message digest details & vtable if found. NULL if + * not found. + * @param pObjId The ASN.1 object ID of the message digest algorithm. + * @param ppvOpaque Where to return an opaque implementation specfici + * sub-type indicator that can be passed to + * RTCrDigestCreate. This is optional, fewer + * algortihms are available if not specified. + */ +RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjId(PCRTASN1OBJID pObjId, void **ppvOpaque); + +RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByType(RTDIGESTTYPE enmDigestType); +RTDECL(int) RTCrDigestCreateByObjIdString(PRTCRDIGEST phDigest, const char *pszObjId); +RTDECL(int) RTCrDigestCreateByObjId(PRTCRDIGEST phDigest, PCRTASN1OBJID pObjId); +RTDECL(int) RTCrDigestCreateByType(PRTCRDIGEST phDigest, RTDIGESTTYPE enmDigestType); + + +/** + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success from a deprecated hash algorithm. + * @retval VINF_CR_DIGEST_COMPROMISED on success from a compromised hash algorithm. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success from a severely compromised hash algorithm. + */ +RTDECL(int) RTCrDigestCreate(PRTCRDIGEST phDigest, PCRTCRDIGESTDESC pDesc, void *pvOpaque); +/** + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success from a deprecated hash algorithm. + * @retval VINF_CR_DIGEST_COMPROMISED on success from a compromised hash algorithm. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success from a severely compromised hash algorithm. + */ +RTDECL(int) RTCrDigestClone(PRTCRDIGEST phDigest, RTCRDIGEST hSrc); +/** + * Resets the digest to start calculating a new digest. + */ +RTDECL(int) RTCrDigestReset(RTCRDIGEST hDigest); + +/** + * Retains a references to the digest. + * + * @returns New reference count. UINT32_MAX if invalid handle. + * @param hDigest Handle to the digest. + */ +RTDECL(uint32_t) RTCrDigestRetain(RTCRDIGEST hDigest); +/** + * Releases a references to the digest. + * + * @returns New reference count. UINT32_MAX if invalid handle. + * @param hDigest Handle to the digest. NIL is ignored (returns 0). + */ +RTDECL(uint32_t) RTCrDigestRelease(RTCRDIGEST hDigest); + +/** + * Updates the digest with more message data. + * + * @returns IPRT status code. + * @param hDigest Handle to the digest. + * @param pvData Pointer to the message data. + * @param cbData The number of bytes of data @a pvData points to. + */ +RTDECL(int) RTCrDigestUpdate(RTCRDIGEST hDigest, void const *pvData, size_t cbData); + +/** + * Updates the digest with more message data from the given VFS file handle. + * + * @returns IPRT status code. + * @param hDigest Handle to the digest. + * @param hVfsFile Handle to the VFS file. + * @param fRewindFile Rewind to the start of the file if @a true, start + * consumption at the current file position if @a false. + */ +RTDECL(int) RTCrDigestUpdateFromVfsFile(RTCRDIGEST hDigest, RTVFSFILE hVfsFile, bool fRewindFile); + +/** + * Finalizes the hash calculation, copying out the resulting hash value. + * + * This can be called more than once and will always return the same result. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success from a deprecated hash algorithm. + * @retval VINF_CR_DIGEST_COMPROMISED on success from a compromised hash algorithm. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success from a severely compromised hash algorithm. + * @retval VINF_BUFFER_UNDERFLOW if the supplied buffer is too big. + * @retval VERR_BUFFER_OVERFLOW if the supplied buffer is too small. + * @retval VERR_INVALID_STATE if there is nothing to finalize. + * + * @param hDigest The digest handle. + * @param pvHash Where to return the hash. Optional. + * @param cbHash The hash size. Optional. + */ +RTDECL(int) RTCrDigestFinal(RTCRDIGEST hDigest, void *pvHash, size_t cbHash); + +RTDECL(bool) RTCrDigestMatch(RTCRDIGEST hDigest, void const *pvHash, size_t cbHash); +RTDECL(uint8_t const *) RTCrDigestGetHash(RTCRDIGEST hDigest); +RTDECL(uint32_t) RTCrDigestGetHashSize(RTCRDIGEST hDigest); +RTDECL(uint64_t) RTCrDigestGetConsumedSize(RTCRDIGEST hDigest); +RTDECL(bool) RTCrDigestIsFinalized(RTCRDIGEST hDigest); +RTDECL(RTDIGESTTYPE) RTCrDigestGetType(RTCRDIGEST hDigest); +RTDECL(const char *) RTCrDigestGetAlgorithmOid(RTCRDIGEST hDigest); + +/** + * Gets the flags for the algorithm. + * + * @returns RTCRDIGESTDESC_F_XXX, UINT32_MAX on invalid handle. + * @param hDigest The digest handle. + */ +RTDECL(uint32_t) RTCrDigestGetFlags(RTCRDIGEST hDigest); + + +/** + * Translates an IPRT digest type value to an OID. + * + * @returns Dotted OID string on success, NULL if not translatable. + * @param enmDigestType The IPRT digest type value to convert. + */ +RTDECL(const char *) RTCrDigestTypeToAlgorithmOid(RTDIGESTTYPE enmDigestType); + +/** + * Translates an IPRT digest type value to a name/descriptive string. + * + * The purpose here is for human readable output rather than machine readable + * output, i.e. the names aren't set in stone. + * + * @returns Pointer to read-only string, NULL if unknown type. + * @param enmDigestType The IPRT digest type value to convert. + */ +RTDECL(const char *) RTCrDigestTypeToName(RTDIGESTTYPE enmDigestType); + +/** + * Translates an IPRT digest type value to a hash size. + * + * @returns Hash size (in bytes). + * @param enmDigestType The IPRT digest type value to convert. + */ +RTDECL(uint32_t) RTCrDigestTypeToHashSize(RTDIGESTTYPE enmDigestType); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_digest_h */ + diff --git a/include/iprt/crypto/key.h b/include/iprt/crypto/key.h new file mode 100644 index 00000000..a58d8ee6 --- /dev/null +++ b/include/iprt/crypto/key.h @@ -0,0 +1,126 @@ +/** @file + * IPRT - Cryptographic Keys + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_key_h +#define IPRT_INCLUDED_crypto_key_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +struct RTCRPEMSECTION; +struct RTCRX509SUBJECTPUBLICKEYINFO; + +/** @defgroup grp_rt_crkey RTCrKey - Crypotgraphic Keys. + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * Key types. + */ +typedef enum RTCRKEYTYPE +{ + /** Invalid zero value. */ + RTCRKEYTYPE_INVALID = 0, + /** RSA private key. */ + RTCRKEYTYPE_RSA_PRIVATE, + /** RSA public key. */ + RTCRKEYTYPE_RSA_PUBLIC, + /** End of key types. */ + RTCRKEYTYPE_END, + /** The usual type size hack. */ + RTCRKEYTYPE_32BIT_HACK = 0x7fffffff +} RTCRKEYTYPE; + + +RTDECL(int) RTCrKeyCreateFromSubjectPublicKeyInfo(PRTCRKEY phKey, struct RTCRX509SUBJECTPUBLICKEYINFO const *pSrc, + PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(int) RTCrKeyCreateFromPublicAlgorithmAndBits(PRTCRKEY phKey, PCRTASN1OBJID pAlgorithm, + PCRTASN1BITSTRING pPublicKey, + PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(int) RTCrKeyCreateFromPemSection(PRTCRKEY phKey, uint32_t fFlags, struct RTCRPEMSECTION const *pSection, + const char *pszPassword, PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(int) RTCrKeyCreateFromBuffer(PRTCRKEY phKey, uint32_t fFlags, void const *pvSrc, size_t cbSrc, + const char *pszPassword, PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(int) RTCrKeyCreateFromFile(PRTCRKEY phKey, uint32_t fFlags, const char *pszFilename, + const char *pszPassword, PRTERRINFO pErrInfo); +/** @todo add support for decrypting private keys. */ +/** @name RTCRKEYFROM_F_XXX + * @{ */ +/** Only PEM sections, no binary fallback. + * @sa RTCRPEMREADFILE_F_ONLY_PEM */ +#define RTCRKEYFROM_F_ONLY_PEM RT_BIT(1) +/** Valid flags. */ +#define RTCRKEYFROM_F_VALID_MASK UINT32_C(0x00000002) +/** @} */ + +RTDECL(int) RTCrKeyCreateNewRsa(PRTCRKEY phKey, uint32_t cBits, uint32_t uPubExp, uint32_t fFlags); + + +RTDECL(uint32_t) RTCrKeyRetain(RTCRKEY hKey); +RTDECL(uint32_t) RTCrKeyRelease(RTCRKEY hKey); +RTDECL(RTCRKEYTYPE) RTCrKeyGetType(RTCRKEY hKey); +RTDECL(bool) RTCrKeyHasPrivatePart(RTCRKEY hKey); +RTDECL(bool) RTCrKeyHasPublicPart(RTCRKEY hKey); +RTDECL(uint32_t) RTCrKeyGetBitCount(RTCRKEY hKey); +RTDECL(int) RTCrKeyQueryRsaModulus(RTCRKEY hKey, PRTBIGNUM pModulus); +RTDECL(int) RTCrKeyQueryRsaPrivateExponent(RTCRKEY hKey, PRTBIGNUM pPrivateExponent); + +/** Public key markers. */ +extern RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyPublicMarkers[]; +/** Number of entries in g_aRTCrKeyPublicMarkers. */ +extern RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyPublicMarkers; +/** Private key markers. */ +extern RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyPrivateMarkers[]; +/** Number of entries in g_aRTCrKeyPrivateMarkers. */ +extern RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyPrivateMarkers; +/** Private and public key markers. */ +extern RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyAllMarkers[]; +/** Number of entries in g_aRTCrKeyAllMarkers. */ +extern RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyAllMarkers; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_key_h */ + diff --git a/include/iprt/crypto/misc.h b/include/iprt/crypto/misc.h new file mode 100644 index 00000000..bc4419fd --- /dev/null +++ b/include/iprt/crypto/misc.h @@ -0,0 +1,76 @@ +/** @file + * IPRT - Crypto - Miscellaneous. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_misc_h +#define IPRT_INCLUDED_crypto_misc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crmisc RTCrMisc - Miscellaneous + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * Get cryptographically strong random bytes. + * + * The buffer will always be filled with random bytes, however only + * on @c VINF_SUCCESS is it guaranteed to be strong random bytes. + * + * @retval VINF_SUCCESS + * @retval VERR_CR_RANDOM_FAILED if insufficient strong random bytes or some similar failure. + * @retval VERR_CR_RANDOM_SETUP_FAILED if setting up strong random failed + * and no strong bytes returned. + * + * @param pvDst Where to return the random bytes. + * @param cbDst How many random bytes to return. + */ +RTDECL(int) RTCrRandBytes(void *pvDst, size_t cbDst); + +RTDECL(int) RTCrPkcs5Pbkdf2Hmac(void const *pvInput, size_t cbInput, void const *pvSalt, size_t cbSalt, uint32_t cIterations, + RTDIGESTTYPE enmDigestType, size_t cbKeyLen, void *pvOutput); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_misc_h */ + diff --git a/include/iprt/crypto/pem.h b/include/iprt/crypto/pem.h new file mode 100644 index 00000000..c36bc587 --- /dev/null +++ b/include/iprt/crypto/pem.h @@ -0,0 +1,304 @@ +/** @file + * IPRT - Crypto - PEM-file Reader & Writer. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_pem_h +#define IPRT_INCLUDED_crypto_pem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include /* PRTASN1CORE */ +#include /* PFNRTSTROUTPUT */ + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_spc RTCrPem - PEM-file Reader & Writer + * @ingroup grp_rt_crypto + * @{ + */ + + +/** + * One PEM marker word (use RT_STR_TUPLE to initialize). + */ +typedef struct RTCRPEMMARKERWORD +{ + /** The word string. */ + const char *pszWord; + /** The length. */ + uint32_t cchWord; +} RTCRPEMMARKERWORD; +/** Pointer to a const marker word. */ +typedef RTCRPEMMARKERWORD const *PCRTCRPEMMARKERWORD; + + +/** + * A PEM marker. + * + * This is an array of words with lengths, optimized for avoid unnecessary + * strlen() while searching the file content. It is ASSUMED that all PEM + * section markers starts with either 'BEGIN' or 'END', followed by the words + * in the this structure. + */ +typedef struct RTCRPEMMARKER +{ + /** Pointer to an array of marker words. */ + PCRTCRPEMMARKERWORD paWords; + /** Number of works in the array papszWords points to. */ + uint32_t cWords; +} RTCRPEMMARKER; +/** Pointer to a const PEM marker. */ +typedef RTCRPEMMARKER const *PCRTCRPEMMARKER; + + +/** + * A PEM field. + */ +typedef struct RTCRPEMFIELD +{ + /** Pointer to the next field. */ + struct RTCRPEMFIELD const *pNext; + /** The field value. */ + char const *pszValue; + /** The field value length. */ + size_t cchValue; + /** The field name length. */ + size_t cchName; + /** The field name. */ + RT_FLEXIBLE_ARRAY_EXTENSION + char szName[RT_FLEXIBLE_ARRAY]; +} RTCRPEMFIELD; +/** Pointer to a PEM field. */ +typedef RTCRPEMFIELD *PRTCRPEMFIELD; +/** Pointer to a const PEM field. */ +typedef RTCRPEMFIELD const *PCRTCRPEMFIELD; + + +/** + * A PEM section. + * + * The API works on linked lists of these. + */ +typedef struct RTCRPEMSECTION +{ + /** Pointer to the next file section. */ + struct RTCRPEMSECTION const *pNext; + /** The marker for this section. NULL if binary file. */ + PCRTCRPEMMARKER pMarker; + /** Pointer to the binary data. */ + uint8_t *pbData; + /** The size of the binary data. */ + size_t cbData; + /** List of fields, NULL if none. */ + PCRTCRPEMFIELD pFieldHead; + /** Set if RTCRPEMREADFILE_F_SENSITIVE was specified. */ + bool fSensitive; +} RTCRPEMSECTION; +/** Pointer to a PEM section. */ +typedef RTCRPEMSECTION *PRTCRPEMSECTION; +/** Pointer to a const PEM section. */ +typedef RTCRPEMSECTION const *PCRTCRPEMSECTION; + + +/** + * Frees sections returned by RTCrPemReadFile and RTCrPemParseContent. + * @returns IPRT status code. + * @param pSectionHead The first section. + */ +RTDECL(int) RTCrPemFreeSections(PCRTCRPEMSECTION pSectionHead); + +/** + * Parses the given data and returns a list of binary sections. + * + * If the file isn't an ASCII file or if no markers were found, the entire file + * content is returned as one single section (with pMarker = NULL). + * + * @returns IPRT status code. + * @retval VINF_EOF if the file is empty. The @a ppSectionHead value will be + * NULL. + * @retval VWRN_NOT_FOUND no section was found and RTCRPEMREADFILE_F_ONLY_PEM + * is specified. The @a ppSectionHead value will be NULL. + * + * @param pvContent The content bytes to parse. + * @param cbContent The number of content bytes. + * @param fFlags RTCRPEMREADFILE_F_XXX. + * @param paMarkers Array of one or more section markers to look for. + * @param cMarkers Number of markers in the array. + * @param ppSectionHead Where to return the head of the section list. Call + * RTCrPemFreeSections to free. + * @param pErrInfo Where to return extend error info. Optional. + */ +RTDECL(int) RTCrPemParseContent(void const *pvContent, size_t cbContent, uint32_t fFlags, + PCRTCRPEMMARKER paMarkers, size_t cMarkers, PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo); + +/** + * Reads the content of the given file and returns a list of binary sections + * found in the file. + * + * If the file isn't an ASCII file or if no markers were found, the entire file + * content is returned as one single section (with pMarker = NULL). + * + * @returns IPRT status code. + * @retval VINF_EOF if the file is empty. The @a ppSectionHead value will be + * NULL. + * @retval VWRN_NOT_FOUND no section was found and RTCRPEMREADFILE_F_ONLY_PEM + * is specified. The @a ppSectionHead value will be NULL. + * + * @param pszFilename The path to the file to read. + * @param fFlags RTCRPEMREADFILE_F_XXX. + * @param paMarkers Array of one or more section markers to look for. + * @param cMarkers Number of markers in the array. + * @param ppSectionHead Where to return the head of the section list. Call + * RTCrPemFreeSections to free. + * @param pErrInfo Where to return extend error info. Optional. + */ +RTDECL(int) RTCrPemReadFile(const char *pszFilename, uint32_t fFlags, PCRTCRPEMMARKER paMarkers, size_t cMarkers, + PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo); +/** @name RTCRPEMREADFILE_F_XXX - Flags for RTCrPemReadFile and + * RTCrPemParseContent. + * @{ */ +/** Continue on encoding error. */ +#define RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR RT_BIT(0) +/** Only PEM sections, no binary fallback. */ +#define RTCRPEMREADFILE_F_ONLY_PEM RT_BIT(1) +/** Sensitive data, use the safer allocator. */ +#define RTCRPEMREADFILE_F_SENSITIVE RT_BIT(2) +/** Valid flags. */ +#define RTCRPEMREADFILE_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Finds the beginning of first PEM section using the specified markers. + * + * This will not look any further than the first section. Nor will it check for + * binaries. + * + * @returns Pointer to the "-----BEGIN XXXX" sequence on success. + * NULL if not found. + * @param pvContent The content bytes to parse. + * @param cbContent The number of content bytes. + * @param paMarkers Array of one or more section markers to look for. + * @param cMarkers Number of markers in the array. + */ +RTDECL(const char *) RTCrPemFindFirstSectionInContent(void const *pvContent, size_t cbContent, + PCRTCRPEMMARKER paMarkers, size_t cMarkers); + + +/** + * PEM formatter for a binary data blob. + * + * @returns Number of output bytes (sum of @a pfnOutput return values). + * @param pfnOutput The output callback function. + * @param pvUser The user argument to the output callback. + * @param pvContent The binary blob to output. + * @param cbContent Size of the binary blob. + * @param pszMarker The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or + * similar. + * @sa RTCrPemWriteAsn1, RTCrPemWriteAsn1ToVfsFile, + * RTCrPemWriteAsn1ToVfsFile + */ +RTDECL(size_t) RTCrPemWriteBlob(PFNRTSTROUTPUT pfnOutput, void *pvUser, + const void *pvContent, size_t cbContent, const char *pszMarker); + +RTDECL(ssize_t) RTCrPemWriteBlobToVfsIoStrm(RTVFSIOSTREAM hVfsIos, const void *pvContent, size_t cbContent, const char *pszMarker); +RTDECL(ssize_t) RTCrPemWriteBlobToVfsFile(RTVFSFILE hVfsFile, const void *pvContent, size_t cbContent, const char *pszMarker); + +/** + * PEM formatter for a generic ASN.1 structure. + * + * This will call both RTAsn1EncodePrepare() and RTAsn1EncodeWrite() on + * @a pRoot. Uses DER encoding. + * + * @returns Number of outputted chars (sum of @a pfnOutput return values), + * negative values are error status codes from the ASN.1 encoding. + * @param pfnOutput The output callback function. + * @param pvUser The user argument to the output callback. + * @param fFlags Reserved, MBZ. + * @param pRoot The root of the ASN.1 to encode and format as PEM. + * @param pszMarker The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or + * similar. + * @param pErrInfo For encoding errors. Optional. + * @sa RTCrPemWriteAsn1ToVfsFile, RTCrPemWriteAsn1ToVfsFile, + * RTCrPemWriteBlob + */ +RTDECL(ssize_t) RTCrPemWriteAsn1(PFNRTSTROUTPUT pfnOutput, void *pvUser, PRTASN1CORE pRoot, + uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo); + +/** + * PEM formatter for a generic ASN.1 structure and output it to @a hVfsIos. + * + * This will call both RTAsn1EncodePrepare() and RTAsn1EncodeWrite() on + * @a pRoot. Uses DER encoding. + * + * @returns Number of chars written, negative values are error status codes from + * the ASN.1 encoding or from RTVfsIoStrmWrite(). + * @param hVfsIos Handle to the I/O stream to write it to. + * @param fFlags Reserved, MBZ. + * @param pRoot The root of the ASN.1 to encode and format as PEM. + * @param pszMarker The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or + * similar. + * @param pErrInfo For encoding errors. Optional. + * @sa RTCrPemWriteAsn1ToVfsFile, RTCrPemWriteAsn1, RTCrPemWriteBlob + */ +RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsIoStrm(RTVFSIOSTREAM hVfsIos, PRTASN1CORE pRoot, + uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo); + +/** + * PEM formatter for a generic ASN.1 structure and output it to @a hVfsFile. + * + * This will call both RTAsn1EncodePrepare() and RTAsn1EncodeWrite() on + * @a pRoot. Uses DER encoding. + * + * @returns Number of chars written, negative values are error status codes from + * the ASN.1 encoding or from RTVfsIoStrmWrite(). + * @param hVfsFile Handle to the file to write it to. + * @param fFlags Reserved, MBZ. + * @param pRoot The root of the ASN.1 to encode and format as PEM. + * @param pszMarker The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or + * similar. + * @param pErrInfo For encoding errors. Optional. + * @sa RTCrPemWriteAsn1ToVfsIoStrm, RTCrPemWriteAsn1, RTCrPemWriteBlob + */ +RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsFile(RTVFSFILE hVfsFile, PRTASN1CORE pRoot, + uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_pem_h */ + diff --git a/include/iprt/crypto/pkcs7.h b/include/iprt/crypto/pkcs7.h new file mode 100644 index 00000000..2bc3f950 --- /dev/null +++ b/include/iprt/crypto/pkcs7.h @@ -0,0 +1,709 @@ +/** @file + * IPRT - PKCS \#7, Cryptographic Message Syntax Standard (aka CMS). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_pkcs7_h +#define IPRT_INCLUDED_crypto_pkcs7_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +struct RTCRPKCS7CONTENTINFO; + + +/** @defgroup grp_rt_crpkcs7 RTCrPkcs7 - PKCS \#7, Cryptographic Message Syntax Standard (aka CMS). + * @ingroup grp_rt_crypto + * @{ + */ + +/** PKCS \#7 data object ID.*/ +#define RTCR_PKCS7_DATA_OID "1.2.840.113549.1.7.1" +/** PKCS \#7 signedData object ID. */ +#define RTCR_PKCS7_SIGNED_DATA_OID "1.2.840.113549.1.7.2" +/** PKCS \#7 envelopedData object ID. */ +#define RTCR_PKCS7_ENVELOPED_DATA_OID "1.2.840.113549.1.7.3" +/** PKCS \#7 signedAndEnvelopedData object ID. */ +#define RTCR_PKCS7_SIGNED_AND_ENVELOPED_DATA_OID "1.2.840.113549.1.7.4" +/** PKCS \#7 digestedData object ID. */ +#define RTCR_PKCS7_DIGESTED_DATA_OID "1.2.840.113549.1.7.5" +/** PKCS \#7 encryptedData object ID. */ +#define RTCR_PKCS7_ENCRYPTED_DATA_OID "1.2.840.113549.1.7.6" + + +/** + * PKCS \#7 IssuerAndSerialNumber (IPRT representation). + */ +typedef struct RTCRPKCS7ISSUERANDSERIALNUMBER +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The certificate name. */ + RTCRX509NAME Name; + /** The certificate serial number. */ + RTASN1INTEGER SerialNumber; +} RTCRPKCS7ISSUERANDSERIALNUMBER; +/** Pointer to the IPRT representation of a PKCS \#7 IssuerAndSerialNumber. */ +typedef RTCRPKCS7ISSUERANDSERIALNUMBER *PRTCRPKCS7ISSUERANDSERIALNUMBER; +/** Pointer to the const IPRT representation of a PKCS \#7 + * IssuerAndSerialNumber. */ +typedef RTCRPKCS7ISSUERANDSERIALNUMBER const *PCRTCRPKCS7ISSUERANDSERIALNUMBER; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7ISSUERANDSERIALNUMBER, RTDECL, RTCrPkcs7IssuerAndSerialNumber, SeqCore.Asn1Core); + + +/** Pointer to the IPRT representation of a PKCS \#7 SignerInfo. */ +typedef struct RTCRPKCS7SIGNERINFO *PRTCRPKCS7SIGNERINFO; +/** Pointer to the const IPRT representation of a PKCS \#7 SignerInfo. */ +typedef struct RTCRPKCS7SIGNERINFO const *PCRTCRPKCS7SIGNERINFO; +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SIGNERINFOS, RTCRPKCS7SIGNERINFO, RTDECL, RTCrPkcs7SignerInfos); + + +/** + * Attribute value type (for the union). + */ +typedef enum RTCRPKCS7ATTRIBUTETYPE +{ + /** Zero is invalid. */ + RTCRPKCS7ATTRIBUTETYPE_INVALID = 0, + /** Not present, union is NULL. */ + RTCRPKCS7ATTRIBUTETYPE_NOT_PRESENT, + /** Unknown values, pCores. */ + RTCRPKCS7ATTRIBUTETYPE_UNKNOWN, + /** Object IDs, use pObjIds. */ + RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS, + /** Octet strings, use pOctetStrings. */ + RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS, + /** Counter signatures (PKCS \#9), use pCounterSignatures. + * RTCR_PKCS9_ID_COUNTER_SIGNATURE_OID - 1.2.840.113549.1.9.6. */ + RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES, + /** Signing time (PKCS \#9), use pSigningTime. + * RTCR_PKCS9_ID_SIGNING_TIME_OID - 1.2.840.113549.1.9.5. */ + RTCRPKCS7ATTRIBUTETYPE_SIGNING_TIME, + /** Microsoft timestamp info (RFC-3161) signed data, use pContentInfo. + * RTCR_PKCS9_ID_MS_TIMESTAMP - 1.3.6.1.4.1.311.3.3.1. */ + RTCRPKCS7ATTRIBUTETYPE_MS_TIMESTAMP, + /** Microsoft nested PKCS\#7 signature (signtool /as). + * RTCR_PKCS9_ID_MS_NESTED_SIGNATURE - 1.3.6.1.4.1.311.2.4.1. */ + RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE, + /** Microsoft statement type, use pObjIdSeqs. + * RTCR_PKCS9_ID_MS_STATEMENT_TYPE - 1.3.6.1.4.1.311.2.1.11. */ + RTCRPKCS7ATTRIBUTETYPE_MS_STATEMENT_TYPE, + /** Apple plist with the all code directory digests, use pOctetStrings. + * RTCR_PKCS9_ID_APPLE_MULTI_CD_PLIST - 1.2.840.113635.100.9.1. */ + RTCRPKCS7ATTRIBUTETYPE_APPLE_MULTI_CD_PLIST, + /** Blow the type up to 32-bits. */ + RTCRPKCS7ATTRIBUTETYPE_32BIT_HACK = 0x7fffffff +} RTCRPKCS7ATTRIBUTETYPE; + +/** + * PKCS \#7 Attribute (IPRT representation). + */ +typedef struct RTCRPKCS7ATTRIBUTE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The attribute type (object ID). */ + RTASN1OBJID Type; + /** The type of data found in the values union. */ + RTCRPKCS7ATTRIBUTETYPE enmType; + /** Value allocation. */ + RTASN1ALLOCATION Allocation; + /** Values. */ + union + { + /** ASN.1 cores (RTCRPKCS7ATTRIBUTETYPE_UNKNOWN). */ + PRTASN1SETOFCORES pCores; + /** ASN.1 object identifiers (RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS). */ + PRTASN1SETOFOBJIDS pObjIds; + /** Sequence of ASN.1 object identifiers (RTCRPKCS7ATTRIBUTETYPE_MS_STATEMENT_TYPE). */ + PRTASN1SETOFOBJIDSEQS pObjIdSeqs; + /** ASN.1 octet strings (RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS). */ + PRTASN1SETOFOCTETSTRINGS pOctetStrings; + /** Counter signatures RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES(). */ + PRTCRPKCS7SIGNERINFOS pCounterSignatures; + /** Signing time(s) (RTCRPKCS7ATTRIBUTETYPE_SIGNING_TIME). */ + PRTASN1SETOFTIMES pSigningTime; + /** Microsoft timestamp (RFC-3161 signed data, RTCRPKCS7ATTRIBUTETYPE_MS_TIMESTAMP), + * Microsoft nested signature (RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE). */ + struct RTCRPKCS7SETOFCONTENTINFOS *pContentInfos; + } uValues; +} RTCRPKCS7ATTRIBUTE; +/** Pointer to the IPRT representation of a PKCS \#7 Attribute. */ +typedef RTCRPKCS7ATTRIBUTE *PRTCRPKCS7ATTRIBUTE; +/** Pointer to the const IPRT representation of a PKCS \#7 Attribute. */ +typedef RTCRPKCS7ATTRIBUTE const *PCRTCRPKCS7ATTRIBUTE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7ATTRIBUTE, RTDECL, RTCrPkcs7Attribute, SeqCore.Asn1Core); + +RTDECL(int) RTCrPkcs7Attribute_SetAppleMultiCdPlist(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOCTETSTRINGS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetContentType(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOBJIDS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetCounterSignatures(PRTCRPKCS7ATTRIBUTE pThis, PCRTCRPKCS7SIGNERINFOS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetMessageDigest(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOCTETSTRINGS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetMsStatementType(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOBJIDSEQS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetMsNestedSignature(PRTCRPKCS7ATTRIBUTE pThis, struct RTCRPKCS7SETOFCONTENTINFOS const *pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetMsTimestamp(PRTCRPKCS7ATTRIBUTE pThis, struct RTCRPKCS7SETOFCONTENTINFOS const *pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetSigningTime(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFTIMES pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); + +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7ATTRIBUTES, RTCRPKCS7ATTRIBUTE, RTDECL, RTCrPkcs7Attributes); + +RTDECL(int) RTCrPkcs7Attributes_HashAttributes(PRTCRPKCS7ATTRIBUTES pAttributes, RTCRDIGEST hDigest, PRTERRINFO pErrInfo); + + +/** + * One PKCS \#7 SignerInfo (IPRT representation). + */ +typedef struct RTCRPKCS7SIGNERINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The structure version (RTCRPKCS7SIGNERINFO_V1). */ + RTASN1INTEGER Version; + /** The issuer and serial number of the certificate used to produce the + * encrypted digest below. */ + RTCRPKCS7ISSUERANDSERIALNUMBER IssuerAndSerialNumber; + /** The digest algorithm use to digest the signed content. */ + RTCRX509ALGORITHMIDENTIFIER DigestAlgorithm; + /** Authenticated attributes, optional [0]. + * @todo Check how other producers formats this. The microsoft one does not + * have explicit tags, but combines it with the SET OF. */ + RTCRPKCS7ATTRIBUTES AuthenticatedAttributes; + /** The digest encryption algorithm use to encrypt the digest of the signed + * content. */ + RTCRX509ALGORITHMIDENTIFIER DigestEncryptionAlgorithm; + /** The encrypted digest. */ + RTASN1OCTETSTRING EncryptedDigest; + /** Unauthenticated attributes, optional [1]. + * @todo Check how other producers formats this. The microsoft one does not + * have explicit tags, but combines it with the SET OF. */ + RTCRPKCS7ATTRIBUTES UnauthenticatedAttributes; +} RTCRPKCS7SIGNERINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7SIGNERINFO, RTDECL, RTCrPkcs7SignerInfo, SeqCore.Asn1Core); + +RTDECL(int) RTCrPkcs7SignerInfo_SetAuthenticatedAttributes(PRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7ATTRIBUTES pAttributes, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7SignerInfo_SetUnauthenticatedAttributes(PRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7ATTRIBUTES pAttributes, + PCRTASN1ALLOCATORVTABLE pAllocator); + +/** RTCRPKCS7SIGNERINFO::Version value. */ +#define RTCRPKCS7SIGNERINFO_V1 1 + +/** @name PKCS \#9 Attribute IDs + * @{ */ +/** Content type (RFC-2630 11.1). + * Value: Object Identifier */ +#define RTCR_PKCS9_ID_CONTENT_TYPE_OID "1.2.840.113549.1.9.3" +/** Message digest (RFC-2630 11.2). + * Value: Octet string. */ +#define RTCR_PKCS9_ID_MESSAGE_DIGEST_OID "1.2.840.113549.1.9.4" +/** Signing time (RFC-2630 11.3). + * Value: Octet string. */ +#define RTCR_PKCS9_ID_SIGNING_TIME_OID "1.2.840.113549.1.9.5" +/** Counter signature (RFC-2630 11.4). + * Value: SignerInfo. */ +#define RTCR_PKCS9_ID_COUNTER_SIGNATURE_OID "1.2.840.113549.1.9.6" +/** Microsoft timestamp (RTF-3161) counter signature (SignedData). + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. It's actually listed as SPC by MS. */ +#define RTCR_PKCS9_ID_MS_TIMESTAMP "1.3.6.1.4.1.311.3.3.1" +/** Microsoft nested PKCS\#7 signature. + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. */ +#define RTCR_PKCS9_ID_MS_NESTED_SIGNATURE "1.3.6.1.4.1.311.2.4.1" +/** Microsoft statement type. + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. It's actually listed as SPC by MS. */ +#define RTCR_PKCS9_ID_MS_STATEMENT_TYPE "1.3.6.1.4.1.311.2.1.11" +/** Microsoft opus info. + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. It's actually listed as SPC by MS. */ +#define RTCR_PKCS9_ID_MS_SP_OPUS_INFO "1.3.6.1.4.1.311.2.1.12" +/** Apple code signing multi-code-directory plist. + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. */ +#define RTCR_PKCS9_ID_APPLE_MULTI_CD_PLIST "1.2.840.113635.100.9.1" +/** @} */ + + +/** + * Get the (next) signing time attribute from the specfied SignerInfo or one of + * the immediate counter signatures. + * + * @returns Pointer to the signing time if found, NULL if not. + * @param pThis The SignerInfo to search. + * @param ppSignerInfo Pointer to variable keeping track of the + * enumeration, optional. + * + * If specified the input value is taken to the be + * SignerInfo of the previously returned signing + * time. The value pointed to is NULL, the + * search/enum restarts. + * + * On successful return this is set to the + * SignerInfo which we found the signing time in. + */ +RTDECL(PCRTASN1TIME) RTCrPkcs7SignerInfo_GetSigningTime(PCRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7SIGNERINFO *ppSignerInfo); + + +/** + * Get the (first) timestamp from within a Microsoft timestamp server counter + * signature. + * + * @returns Pointer to the signing time if found, NULL if not. + * @param pThis The SignerInfo to search. + * @param ppContentInfoRet Where to return the pointer to the counter + * signature, optional. + */ +RTDECL(PCRTASN1TIME) RTCrPkcs7SignerInfo_GetMsTimestamp(PCRTCRPKCS7SIGNERINFO pThis, + struct RTCRPKCS7CONTENTINFO const **ppContentInfoRet); + + + +/** + * PKCS \#7 ContentInfo (IPRT representation). + */ +typedef struct RTCRPKCS7CONTENTINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Object ID identifying the content below. */ + RTASN1OBJID ContentType; + /** Content, optional, explicit tag 0. + * + * Hack alert! This should've been an explict context tag 0 structure with a + * type selected according to ContentType. However, it's simpler to replace the + * explicit context with an OCTET STRING with implict tag 0. Then we can tag + * along on the encapsulation logic RTASN1OCTETSTRING provides for the dynamic + * inner type. The default decoder code will detect known structures as + * outlined in the union below, and decode the octet string content as an + * anonymous RTASN1CORE if not known. + * + * If the user want to decode the octet string content differently, it can do so + * by destroying and freeing the current encapsulated pointer, replacing it with + * it's own. (Of course following the RTASN1OCTETSTRING rules.) Just remember + * to also update the value in the union. + * + * @remarks What's signed and verified is Content.pEncapsulated->uData.pv. + */ + RTASN1OCTETSTRING Content; + /** Pointer to the CMS octet string that's inside the Content, NULL if PKCS \#7. + * + * Hack alert! When transitioning from PKCS \#7 to CMS, the designers decided to + * change things and add another wrapper. This time we're talking about a real + * octet string, not like the one above which is really an explicit content tag. + * When constructing or decoding CMS content, this will be the same pointer as + * Content.pEncapsulated, while the union below will be holding the same pointer + * as pCmsContent->pEncapsulated. + */ + PRTASN1OCTETSTRING pCmsContent; + /** Same as Content.pEncapsulated, except a choice of known types. */ + union + { + /** ContentType is RTCRPKCS7SIGNEDDATA_OID. */ + struct RTCRPKCS7SIGNEDDATA *pSignedData; + /** ContentType is RTCRSPCINDIRECTDATACONTENT_OID. */ + struct RTCRSPCINDIRECTDATACONTENT *pIndirectDataContent; + /** ContentType is RTCRTSPTSTINFO_OID. */ + struct RTCRTSPTSTINFO *pTstInfo; + /** Generic / Unknown / User. */ + PRTASN1CORE pCore; + } u; +} RTCRPKCS7CONTENTINFO; +/** Pointer to the IPRT representation of a PKCS \#7 ContentInfo. */ +typedef RTCRPKCS7CONTENTINFO *PRTCRPKCS7CONTENTINFO; +/** Pointer to the const IPRT representation of a PKCS \#7 ContentInfo. */ +typedef RTCRPKCS7CONTENTINFO const *PCRTCRPKCS7CONTENTINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7CONTENTINFO, RTDECL, RTCrPkcs7ContentInfo, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SETOFCONTENTINFOS, RTCRPKCS7CONTENTINFO, RTDECL, RTCrPkcs7SetOfContentInfos); + +RTDECL(bool) RTCrPkcs7ContentInfo_IsSignedData(PCRTCRPKCS7CONTENTINFO pThis); + + +/** + * PKCS \#7 Certificate choice. + */ +typedef enum RTCRPKCS7CERTCHOICE +{ + RTCRPKCS7CERTCHOICE_INVALID = 0, + RTCRPKCS7CERTCHOICE_X509, + RTCRPKCS7CERTCHOICE_EXTENDED_PKCS6, + RTCRPKCS7CERTCHOICE_AC_V1, + RTCRPKCS7CERTCHOICE_AC_V2, + RTCRPKCS7CERTCHOICE_OTHER, + RTCRPKCS7CERTCHOICE_END, + RTCRPKCS7CERTCHOICE_32BIT_HACK = 0x7fffffff +} RTCRPKCS7CERTCHOICE; + + +/** + * Common representation for PKCS \#7 ExtendedCertificateOrCertificate and the + * CMS CertificateChoices types. + */ +typedef struct RTCRPKCS7CERT +{ + /** Dummy ASN.1 record, not encoded. */ + RTASN1DUMMY Dummy; + /** The value allocation. */ + RTASN1ALLOCATION Allocation; + /** The choice of value. */ + RTCRPKCS7CERTCHOICE enmChoice; + /** The value union. */ + union + { + /** Standard X.509 certificate (RTCRCMSCERTIFICATECHOICE_X509). */ + PRTCRX509CERTIFICATE pX509Cert; + /** Extended PKCS \#6 certificate (RTCRCMSCERTIFICATECHOICE_EXTENDED_PKCS6). */ + PRTASN1CORE pExtendedCert; + /** Attribute certificate version 1 (RTCRCMSCERTIFICATECHOICE_AC_V1). */ + PRTASN1CORE pAcV1; + /** Attribute certificate version 2 (RTCRCMSCERTIFICATECHOICE_AC_V2). */ + PRTASN1CORE pAcV2; + /** Other certificate (RTCRCMSCERTIFICATECHOICE_OTHER). */ + PRTASN1CORE pOtherCert; + } u; +} RTCRPKCS7CERT; +/** Pointer to the IPRT representation of PKCS \#7 or CMS certificate. */ +typedef RTCRPKCS7CERT *PRTCRPKCS7CERT; +/** Pointer to the const IPRT representation of PKCS \#7 or CMS certificate. */ +typedef RTCRPKCS7CERT const *PCRTCRPKCS7CERT; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7CERT, RTDECL, RTCrPkcs7Cert, Dummy.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SETOFCERTS, RTCRPKCS7CERT, RTDECL, RTCrPkcs7SetOfCerts); + +RTDECL(int) RTCrPkcs7Cert_SetX509Cert(PRTCRPKCS7CERT pThis, PCRTCRX509CERTIFICATE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Cert_SetExtendedCert(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Cert_SetAcV1(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Cert_SetAcV2(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Cert_SetOtherCert(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + +RTDECL(PCRTCRX509CERTIFICATE) RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(PCRTCRPKCS7SETOFCERTS pCertificates, + PCRTCRX509NAME pIssuer, + PCRTASN1INTEGER pSerialNumber); + + +/** + * PKCS \#7 SignedData (IPRT representation). + */ +typedef struct RTCRPKCS7SIGNEDDATA +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The structure version value (1). */ + RTASN1INTEGER Version; + /** The digest algorithms that are used to signed the content (ContentInfo). */ + RTCRX509ALGORITHMIDENTIFIERS DigestAlgorithms; + /** The content that's being signed. */ + RTCRPKCS7CONTENTINFO ContentInfo; + /** Certificates, optional, implicit tag 0. (Required by Authenticode.) */ + RTCRPKCS7SETOFCERTS Certificates; + /** Certificate revocation lists, optional, implicit tag 1. + * Not used by Authenticode, so currently stubbed. */ + RTASN1CORE Crls; + /** Signer infos. */ + RTCRPKCS7SIGNERINFOS SignerInfos; +} RTCRPKCS7SIGNEDDATA; +/** Pointer to the IPRT representation of a PKCS \#7 SignedData. */ +typedef RTCRPKCS7SIGNEDDATA *PRTCRPKCS7SIGNEDDATA; +/** Pointer to the const IPRT representation of a PKCS \#7 SignedData. */ +typedef RTCRPKCS7SIGNEDDATA const *PCRTCRPKCS7SIGNEDDATA; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7SIGNEDDATA, RTDECL, RTCrPkcs7SignedData, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SETOFSIGNEDDATA, RTCRPKCS7SIGNEDDATA, RTDECL, RTCrPkcs7SetOfSignedData); + +/** PKCS \#7 SignedData object ID. */ +#define RTCRPKCS7SIGNEDDATA_OID RTCR_PKCS7_SIGNED_DATA_OID + +/** PKCS \#7 SignedData version number 1. */ +#define RTCRPKCS7SIGNEDDATA_V1 1 +/* No version 2 seems to exist. */ +/** CMS SignedData version number 3. + * This should only be used if there are version 1 attribute certificates + * present, or if there are version 3 SignerInfo items present, or if + * enmcCountInfo is not id-data (RFC-5652, section 5.1). */ +#define RTCRPKCS7SIGNEDDATA_V3 3 +/** CMS SignedData version number 4. + * This should only be used if there are version 2 attribute certificates + * present (RFC-5652, section 5.1). */ +#define RTCRPKCS7SIGNEDDATA_V4 4 +/** CMS SignedData version number 5. + * This should only be used if there are certificates or/and CRLs of the + * OTHER type present (RFC-5652, section 5.1). */ +#define RTCRPKCS7SIGNEDDATA_V5 5 + +RTDECL(int) RTCrPkcs7SignedData_SetCertificates(PRTCRPKCS7SIGNEDDATA pThis, PCRTCRPKCS7SETOFCERTS pCerts, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7SignedData_SetCrls(PRTCRPKCS7SIGNEDDATA pThis, PCRTASN1CORE pCerts, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** @name RTCRPKCS7SIGNEDDATA_SANITY_F_XXX - Flags for RTPkcs7SignedDataCheckSantiy. + * @{ */ +/** Check for authenticode restrictions. */ +#define RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE RT_BIT_32(0) +/** Check that all the hash algorithms are known to IPRT. */ +#define RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH RT_BIT_32(1) +/** Require signing certificate to be present. */ +#define RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT RT_BIT_32(2) +/** @} */ + +/** PKCS\#7/CMS (content info) markers. */ +extern RTDATADECL(RTCRPEMMARKER const) g_aRTCrPkcs7Markers[]; +/** Number of entries in g_aRTCrPkcs7Markers. */ +extern RTDATADECL(uint32_t const) g_cRTCrPkcs7Markers; + +/** @name Flags for RTCrPkcs7ContentInfo_ReadFromBuffer + * @{ */ +/** Only allow PEM certificates, not binary ones. + * @sa RTCRPEMREADFILE_F_ONLY_PEM */ +#define RTCRPKCS7_READ_F_PEM_ONLY RT_BIT(1) +/** @} */ + +RTDECL(int) RTCrPkcs7_ReadFromBuffer(PRTCRPKCS7CONTENTINFO pContentInfo, const void *pvBuf, size_t cbBuf, + uint32_t fFlags, PCRTASN1ALLOCATORVTABLE pAllocator, + bool *pfCmsLabeled, PRTERRINFO pErrInfo, const char *pszErrorTag); + + +/** + * PKCS \#7 DigestInfo (IPRT representation). + */ +typedef struct RTCRPKCS7DIGESTINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The digest algorithm use to digest the signed content. */ + RTCRX509ALGORITHMIDENTIFIER DigestAlgorithm; + /** The digest. */ + RTASN1OCTETSTRING Digest; +} RTCRPKCS7DIGESTINFO; +/** Pointer to the IPRT representation of a PKCS \#7 DigestInfo object. */ +typedef RTCRPKCS7DIGESTINFO *PRTCRPKCS7DIGESTINFO; +/** Pointer to the const IPRT representation of a PKCS \#7 DigestInfo object. */ +typedef RTCRPKCS7DIGESTINFO const *PCRTCRPKCS7DIGESTINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7DIGESTINFO, RTDECL, RTCrPkcs7DigestInfo, SeqCore.Asn1Core); + + +/** + * Callback function for use with RTCrPkcs7VerifySignedData. + * + * @returns IPRT status code. + * @param pCert The certificate to verify. + * @param hCertPaths Unless the certificate is trusted directly, this + * is a reference to the certificate path builder + * and verifier instance that we used to establish + * at least valid trusted path to @a pCert. The + * callback can use this to enforce additional + * certificate lineage requirements, effective + * policy checks and whatnot. + * This is NIL_RTCRX509CERTPATHS if the certificate + * is directly trusted. + * @param fFlags Mix of the RTCRPKCS7VCC_F_XXX flags. + * @param pvUser The user argument. + * @param pErrInfo Optional error info buffer. + */ +typedef DECLCALLBACKTYPE(int, FNRTCRPKCS7VERIFYCERTCALLBACK,(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, + uint32_t fFlags, void *pvUser, PRTERRINFO pErrInfo)); +/** Pointer to a FNRTCRPKCS7VERIFYCERTCALLBACK callback. */ +typedef FNRTCRPKCS7VERIFYCERTCALLBACK *PFNRTCRPKCS7VERIFYCERTCALLBACK; + +/** @name RTCRPKCS7VCC_F_XXX - Flags for FNRTCRPKCS7VERIFYCERTCALLBACK. + * @{ */ +/** Normal callback for a direct signatory of the signed data. */ +#define RTCRPKCS7VCC_F_SIGNED_DATA RT_BIT_32(0) +/** Check that the signatory can be trusted for timestamps. */ +#define RTCRPKCS7VCC_F_TIMESTAMP RT_BIT_32(1) +/** @} */ + +/** + * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK, + * Default implementation that checks for the DigitalSignature KeyUsage bit.} + */ +RTDECL(int) RTCrPkcs7VerifyCertCallbackDefault(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags, + void *pvUser, PRTERRINFO pErrInfo); + +/** + * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK, + * Standard code signing. Use this for Microsoft SPC.} + */ +RTDECL(int) RTCrPkcs7VerifyCertCallbackCodeSigning(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags, + void *pvUser, PRTERRINFO pErrInfo); + +/** + * Verifies PKCS \#7 SignedData. + * + * For compatability with alternative crypto providers, the user must work on + * the top level PKCS \#7 structure instead directly on the SignedData. + * + * @returns IPRT status code. + * @param pContentInfo PKCS \#7 content info structure. + * @param fFlags RTCRPKCS7VERIFY_SD_F_XXX. + * @param hAdditionalCerts Store containing additional certificates to + * supplement those mentioned in the signed data. + * @param hTrustedCerts Store containing trusted certificates. + * @param pValidationTime The time we're supposed to validate the + * certificates chains at. Ignored for signatures + * with valid signing time attributes. + * When RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME + * is set, this is updated to the actual validation + * time used. + * @param pfnVerifyCert Callback for checking that a certificate used + * for signing the data is suitable. + * @param pvUser User argument for the callback. + * @param pErrInfo Optional error info buffer. + * @sa RTCrPkcs7VerifySignedDataWithExternalData + */ +RTDECL(int) RTCrPkcs7VerifySignedData(PCRTCRPKCS7CONTENTINFO pContentInfo, uint32_t fFlags, + RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts, + PCRTTIMESPEC pValidationTime, PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, void *pvUser, + PRTERRINFO pErrInfo); + + +/** + * Verifies PKCS \#7 SignedData with external data. + * + * For compatability with alternative crypto providers, the user must work on + * the top level PKCS \#7 structure instead directly on the SignedData. + * + * @returns IPRT status code. + * @param pContentInfo PKCS \#7 content info structure. + * @param fFlags RTCRPKCS7VERIFY_SD_F_XXX. + * @param hAdditionalCerts Store containing additional certificates to + * supplement those mentioned in the signed data. + * @param hTrustedCerts Store containing trusted certificates. + * @param pValidationTime The time we're supposed to validate the + * certificates chains at. Ignored for signatures + * with valid signing time attributes. + * When RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME + * is set, this is updated to the actual validation + * time used. + * @param pfnVerifyCert Callback for checking that a certificate used + * for signing the data is suitable. + * @param pvUser User argument for the callback. + * @param pvData The signed external data. + * @param cbData The size of the signed external data. + * @param pErrInfo Optional error info buffer. + * @sa RTCrPkcs7VerifySignedData + */ +RTDECL(int) RTCrPkcs7VerifySignedDataWithExternalData(PCRTCRPKCS7CONTENTINFO pContentInfo, uint32_t fFlags, + RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts, + PCRTTIMESPEC pValidationTime, + PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, void *pvUser, + void const *pvData, size_t cbData, PRTERRINFO pErrInfo); + +/** @name RTCRPKCS7VERIFY_SD_F_XXX - Flags for RTCrPkcs7VerifySignedData and + * RTCrPkcs7VerifySignedDataWithExternalData + * @{ */ +/** Always use the signing time attribute if present, requiring it to be + * verified as valid. The default behavior is to ignore unverifiable + * signing time attributes and use the @a pValidationTime instead. */ +#define RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT RT_BIT_32(0) +/** Same as RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT for the MS + * timestamp counter signatures. */ +#define RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT RT_BIT_32(1) +/** Only use signing time attributes from counter signatures. */ +#define RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY RT_BIT_32(2) +/** Don't validate the counter signature containing the signing time, just use + * it unverified. This is useful if we don't necessarily have the root + * certificates for the timestamp server handy, but use with great care. + * @sa RTCRPKCS7VERIFY_SD_F_USE_MS_TIMESTAMP_UNVERIFIED */ +#define RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED RT_BIT_32(3) +/** Don't validate the MS counter signature containing the signing timestamp. + * @sa RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED */ +#define RTCRPKCS7VERIFY_SD_F_USE_MS_TIMESTAMP_UNVERIFIED RT_BIT_32(4) +/** Do not consider timestamps in microsoft counter signatures. */ +#define RTCRPKCS7VERIFY_SD_F_IGNORE_MS_TIMESTAMP RT_BIT_32(5) +/** The signed data requires certificates to have the timestamp extended + * usage bit present. This is used for recursivly verifying MS timestamp + * signatures. */ +#define RTCRPKCS7VERIFY_SD_F_USAGE_TIMESTAMPING RT_BIT_32(6) +/** Skip the verification of the certificate trust paths, taking all + * certificates to be trustworthy. */ +#define RTCRPKCS7VERIFY_SD_F_TRUST_ALL_CERTS RT_BIT_32(7) +/** Update @a pValidationTime with the actual validation time used. + * This requires RTCRPKCS7VERIFY_SD_F_HAS_SIGNER_INDEX to get a consistent + * result. And yeah, it unconst the parameter, which is patently ugly. */ +#define RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME RT_BIT_32(8) +/** Check trust anchors (@sa RTCrX509CertPathsSetTrustAnchorChecks). */ +#define RTCRPKCS7VERIFY_SD_F_CHECK_TRUST_ANCHORS RT_BIT_32(9) + +/** This can be used to only verify one given signer info. + * Max index value is 15. */ +#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX(a_idxSignerInfo) \ + ( RTCRPKCS7VERIFY_SD_F_HAS_SIGNER_INDEX \ + | (((a_idxSignerInfo) & RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MAX) << RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_SHIFT) ) +/** Has a valid value in RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MASK. */ +#define RTCRPKCS7VERIFY_SD_F_HAS_SIGNER_INDEX RT_BIT_32(23) +/** Signer index shift value. */ +#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_SHIFT 24 +/** Signer index mask. */ +#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MASK UINT32_C(0x0f000000) +/** Max signer index value (inclusive). */ +#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MAX \ + (RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MASK >> RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_SHIFT) + +/** Indicates internally that we're validating a counter signature and should + * use different rules when checking out the authenticated attributes. + * @internal */ +#define RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE RT_BIT_32(31) +/** @} */ + + +RTDECL(int) RTCrPkcs7SimpleSignSignedData(uint32_t fFlags, PCRTCRX509CERTIFICATE pSigner, RTCRKEY hPrivateKey, + void const *pvData, size_t cbData, RTDIGESTTYPE enmDigestType, + RTCRSTORE hAdditionalCerts, PCRTCRPKCS7ATTRIBUTES pAdditionalAuthenticatedAttribs, + void *pvResult, size_t *pcbResult, PRTERRINFO pErrInfo); + +/** @name RTCRPKCS7SIGN_SD_F_XXX - Flags for RTCrPkcs7SimpleSign. + * @{ */ +/** Detached data. */ +#define RTCRPKCS7SIGN_SD_F_DEATCHED RT_BIT_32(0) +/** No SMIME capabilities attribute. */ +#define RTCRPKCS7SIGN_SD_F_NO_SMIME_CAP RT_BIT_32(1) +/** Produce version 1 output (PKCS\#7), rather than version 3 (CMS). */ +#define RTCRPKCS7SIGN_SD_F_USE_V1 RT_BIT_32(2) +/** Avoid extra OCTET STRING encapsulation around the data blob. + * This is needed for Authenticode signatures. This requires that the + * content type is supplied via the additional authenticated attributes. + * @note Currently only works with RTCRPKCS7SIGN_SD_F_USE_V1. */ +#define RTCRPKCS7SIGN_SD_F_NO_DATA_ENCAP RT_BIT_32(3) +/** Valid flag mask. */ +#define RTCRPKCS7SIGN_SD_F_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_pkcs7_h */ + diff --git a/include/iprt/crypto/pkix.h b/include/iprt/crypto/pkix.h new file mode 100644 index 00000000..98120fbf --- /dev/null +++ b/include/iprt/crypto/pkix.h @@ -0,0 +1,582 @@ +/** @file + * IPRT - Public Key Infrastructure APIs. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_pkix_h +#define IPRT_INCLUDED_crypto_pkix_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +RT_C_DECLS_BEGIN + +struct RTCRX509CERTIFICATE; +struct RTCRX509SUBJECTPUBLICKEYINFO; + +/** @defgroup grp_rt_crpkix RTCrPkix - Public Key Infrastructure APIs + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * Verifies the signature (@a pSignatureValue) of the give data (@a pvData) + * using the specfied public key (@a pPublicKey) and algorithm. + * + * @returns IPRT status code. + * @param pAlgorithm The signature algorithm (digest w/ cipher). + * @param hPublicKey The public key. + * @param pParameters Parameter to the public key algorithm. Optional. + * @param pSignatureValue The signature value. + * @param pvData The signed data. + * @param cbData The amount of signed data. + * @param pErrInfo Where to return extended error info. Optional. + * + * @remarks Depending on the IPRT build configuration, the verficiation may be + * performed more than once using all available crypto implementations. + */ +RTDECL(int) RTCrPkixPubKeyVerifySignature(PCRTASN1OBJID pAlgorithm, RTCRKEY hPublicKey, PCRTASN1DYNTYPE pParameters, + PCRTASN1BITSTRING pSignatureValue, const void *pvData, size_t cbData, + PRTERRINFO pErrInfo); + + +/** + * Verifies the signed digest (@a pvSignedDigest) against our digest (@a + * hDigest) using the specfied public key (@a pPublicKey) and algorithm. + * + * @returns IPRT status code. + * @param pAlgorithm The signature algorithm (digest w/ cipher). + * @param hPublicKey The public key. + * @param pParameters Parameter to the public key algorithm. Optional. + * @param pvSignedDigest The signed digest. + * @param cbSignedDigest The signed digest size. + * @param hDigest The digest of the data to compare @a pvSignedDigest + * with. + * @param pErrInfo Where to return extended error info. Optional. + * + * @remarks Depending on the IPRT build configuration, the verficiation may be + * performed more than once using all available crypto implementations. + */ +RTDECL(int) RTCrPkixPubKeyVerifySignedDigest(PCRTASN1OBJID pAlgorithm, RTCRKEY hPublicKey, PCRTASN1DYNTYPE pParameters, + void const *pvSignedDigest, size_t cbSignedDigest, + RTCRDIGEST hDigest, PRTERRINFO pErrInfo); + +/** + * Wrapper around RTCrPkixPubKeyVerifySignedDigest & RTCrKeyCreateFromAlgorithmAndBits. + * + * @note The public key info must include digest type for this to work. + */ +RTDECL(int) RTCrPkixPubKeyVerifySignedDigestByCertPubKeyInfo(struct RTCRX509SUBJECTPUBLICKEYINFO const *pCertPubKeyInfo, + void const *pvSignedDigest, size_t cbSignedDigest, + RTCRDIGEST hDigest, PRTERRINFO pErrInfo); + +/** + * Checks if the hash size can be handled by the given public key. + */ +RTDECL(bool) RTCrPkixPubKeyCanHandleDigestType(struct RTCRX509SUBJECTPUBLICKEYINFO const *pPublicKeyInfo, + RTDIGESTTYPE enmDigestType, PRTERRINFO pErrInfo); + +/** + * Checks if the hash size can be handled by the given certificate's public key. + */ +RTDECL(bool) RTCrPkixCanCertHandleDigestType(struct RTCRX509CERTIFICATE const *pCertificate, + RTDIGESTTYPE enmDigestType, PRTERRINFO pErrInfo); + +/** + * Signs a digest (@a hDigest) using the specified private key (@a pPrivateKey) and algorithm. + * + * @returns IPRT status code. + * @param pAlgorithm The signature algorithm (digest w/ cipher). + * @param hPrivateKey Handle to the private key to use. + * @param pParameters Parameter to the public key algorithm. Optional. + * @param hDigest The digest of the data being signed. + * @param fFlags Flags for future extensions, MBZ. + * @param pvSignature The output signature buffer. Pass NULL to query + * the signature size. + * @param pcbSignature On input the variable pointed to holds the size of + * the buffer @a pvSignature points to. + * On return the variable pointed to is set to the size + * of the returned signature, or the required size in + * case of VERR_BUFFER_OVERFLOW. + * @param pErrInfo Where to return extended error info. Optional. + * + * @remarks Depending on the IPRT build configuration and the algorithm used, the + * signing may be performed more than once using all available crypto + * implementations. + */ +RTDECL(int) RTCrPkixPubKeySignDigest(PCRTASN1OBJID pAlgorithm, RTCRKEY hPrivateKey, PCRTASN1DYNTYPE pParameters, + RTCRDIGEST hDigest, uint32_t fFlags, + void *pvSignature, size_t *pcbSignature, PRTERRINFO pErrInfo); + +/** + * Gets the cipher OID matching the given signature algorithm. + * + * @returns Cipher OID string on success, NULL on failure. + * @param pAlgorithm The signature algorithm (digest w/ cipher). + */ +RTDECL(const char *) RTCrPkixGetCiperOidFromSignatureAlgorithm(PCRTASN1OBJID pAlgorithm); + + +/** @name PKCS-1 Object Identifiers (OIDs) + * @{ */ +#define RTCR_PKCS1_OID "1.2.840.113549.1.1" +#define RTCR_PKCS1_RSA_OID "1.2.840.113549.1.1.1" +#define RTCR_PKCS1_MD2_WITH_RSA_OID "1.2.840.113549.1.1.2" +#define RTCR_PKCS1_MD4_WITH_RSA_OID "1.2.840.113549.1.1.3" +#define RTCR_PKCS1_MD5_WITH_RSA_OID "1.2.840.113549.1.1.4" +#define RTCR_PKCS1_SHA1_WITH_RSA_OID "1.2.840.113549.1.1.5" +#define RTCR_PKCS1_RSA_OAEP_ENCRYPTION_SET_OID "1.2.840.113549.1.1.6" +#define RTCR_PKCS1_RSA_AES_OAEP_OID "1.2.840.113549.1.1.7" +#define RTCR_PKCS1_MSGF1_OID "1.2.840.113549.1.1.8" +#define RTCR_PKCS1_P_SPECIFIED_OID "1.2.840.113549.1.1.9" +#define RTCR_PKCS1_RSASSA_PSS_OID "1.2.840.113549.1.1.10" +#define RTCR_PKCS1_SHA256_WITH_RSA_OID "1.2.840.113549.1.1.11" +#define RTCR_PKCS1_SHA384_WITH_RSA_OID "1.2.840.113549.1.1.12" +#define RTCR_PKCS1_SHA512_WITH_RSA_OID "1.2.840.113549.1.1.13" +#define RTCR_PKCS1_SHA224_WITH_RSA_OID "1.2.840.113549.1.1.14" +#define RTCR_PKCS1_SHA512T224_WITH_RSA_OID "1.2.840.113549.1.1.15" +#define RTCR_PKCS1_SHA512T256_WITH_RSA_OID "1.2.840.113549.1.1.16" +/** @} */ + + +/** + * Public key signature scheme provider descriptor. + */ +typedef struct RTCRPKIXSIGNATUREDESC +{ + /** The signature scheme provider name. */ + const char *pszName; + /** The object ID string. */ + const char *pszObjId; + /** Pointer to a NULL terminated table of alias object IDs (optional). */ + const char * const *papszObjIdAliases; + /** The size of the state. */ + uint32_t cbState; + /** Reserved for future / explicit padding. */ + uint32_t uReserved; + /** Provider specific field. This generally indicates the kind of padding + * scheme to employ with the given OID. */ + uintptr_t uProviderSpecific; + + /** + * Initializes the state of the signature scheme provider. + * + * Optional, RT_BZERO will be used if NULL. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param pvOpaque Opaque provider specific parameter. + * @param fSigning Set if a signing operation is going to be performed, + * clear if it is a verification. This is a fixed + * setting for the lifetime of the instance due to the + * algorithm requiring different keys. + * @param hKey The key handle. Caller has retained it for the + * lifetime of the state being initialize. + * @param pParams Algorithm/key parameters, optional. Will be NULL if + * none. + */ + DECLCALLBACKMEMBER(int, pfnInit,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, void *pvOpaque, bool fSigning, + RTCRKEY hKey, PCRTASN1DYNTYPE pParams)); + + /** + * Resets the state before performing another signing or verification. + * + * Optional. It is assumed that the provider does not have any state needing to + * be re-initialized if this method is not implemented. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param fSigning Exactly the same value as the init call. + */ + DECLCALLBACKMEMBER(int, pfnReset,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, bool fSigning)); + + /** + * Deletes the provider state. Optional. + * + * The state will be securely wiped clean after the call, regardless of whether + * the method is implemented or not. + * + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param fSigning Exactly the same value as the init call. + */ + DECLCALLBACKMEMBER(void, pfnDelete,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, bool fSigning)); + + /** + * Verifies a signed message digest (fSigning = false). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the signature checked out correctly. + * @retval VINF_CR_DIGEST_DEPRECATED if the signature checked out correctly + * but the hash algorithm is deprecated. + * @retval VINF_CR_DIGEST_COMPROMISED if the signature checked out correctly + * but the hash algorithm is compromised. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED if the signature checked out + * correctly but the hash algorithm is severely compromised. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param hKey The key handle associated with the state at init. + * @param hDigest The handle to the digest. Calls RTCrDigestFinal to + * complete and retreive the final hash value. + * @param pvSignature The signature to validate. + * @param cbSignature The size of the signature (in bytes). + */ + DECLCALLBACKMEMBER(int, pfnVerify,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, RTCRKEY hKey, + RTCRDIGEST hDigest, void const *pvSignature, size_t cbSignature)); + + /** + * Sign a message digest (fSigning = true). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success but the hash algorithm is deprecated. + * @retval VINF_CR_DIGEST_COMPROMISED on success but the hash algorithm is compromised. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success but the hash algorithm + * is severely compromised. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * @retval VERR_BUFFER_OVERFLOW if the signature buffer is too small, the + * require buffer size will be available in @a *pcbSignature. + * + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param hKey The key handle associated with the state at init. + * @param hDigest The handle to the digest. Calls RTCrDigestFinal to + * complete and retreive the final hash value. + * @param pvSignature The output signature buffer. + * @param pcbSignature On input the variable pointed to holds the size of + * the buffer @a pvSignature points to. + * On return the variable pointed to is set to the size + * of the returned signature, or the required size in + * case of VERR_BUFFER_OVERFLOW. + */ + DECLCALLBACKMEMBER(int, pfnSign,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, RTCRKEY hKey, + RTCRDIGEST hDigest, void *pvSignature, size_t *pcbSignature)); + +} RTCRPKIXSIGNATUREDESC; +/** Pointer to a public key signature scheme provider descriptor. */ +typedef RTCRPKIXSIGNATUREDESC const *PCRTCRPKIXSIGNATUREDESC; + +/** + * Locates a signature schema provider descriptor by object ID string. + * @returns Pointer to descriptor on success, NULL on if not found. + * @param pszObjId The ID of the signature to search for. + * @param ppvOpaque Where to store an opaque schema parameter. Optional. + */ +PCRTCRPKIXSIGNATUREDESC RTCrPkixSignatureFindByObjIdString(const char *pszObjId, void *ppvOpaque); + +/** + * Locates a signature schema provider descriptor by ASN.1 object ID. + * @returns Pointer to descriptor on success, NULL on if not found. + * @param pObjId The ID of the signature to search for. + * @param ppvOpaque Where to store an opaque schema parameter. Optional. + */ +PCRTCRPKIXSIGNATUREDESC RTCrPkixSignatureFindByObjId(PCRTASN1OBJID pObjId, void **ppvOpaque); + +/** + * Create a signature schema provier instance. + * + * @returns IPRT status code. + * @param phSignature Where to return the handle to the created instance. + * @param pDesc The signature schema provider descriptor. Use + * RTCrPkixSignatureFindByObjIdString() or RTCrPkixSignatureFindByObjId() + * to get this. + * @param pvOpaque The opaque schema parameter returned by the find functions. + * @param fSigning Set if the intention is to sign stuff, clear if verification only. + * @param hKey The key handle. A referenced will be retained. + * @param pParams Algorithm/key parameters, optional. + */ +RTDECL(int) RTCrPkixSignatureCreate(PRTCRPKIXSIGNATURE phSignature, PCRTCRPKIXSIGNATUREDESC pDesc, void *pvOpaque, + bool fSigning, RTCRKEY hKey, PCRTASN1DYNTYPE pParams); +/** Convenience wrapper function for RTCrPkixSignatureCreate(). */ +RTDECL(int) RTCrPkixSignatureCreateByObjIdString(PRTCRPKIXSIGNATURE phSignature, const char *pszObjId, + RTCRKEY hKey, PCRTASN1DYNTYPE pParams, bool fSigning); +/** Convenience wrapper function for RTCrPkixSignatureCreate(). */ +RTDECL(int) RTCrPkixSignatureCreateByObjId(PRTCRPKIXSIGNATURE phSignature, PCRTASN1OBJID pObjId, RTCRKEY hKey, + PCRTASN1DYNTYPE pParams, bool fSigning); + +/** + * Retains a reference to the signature schema provider instance. + * + * @returns New reference count on success, UINT32_MAX if invalid handle. + * @param hSignature The signature schema provider handle. + */ +RTDECL(uint32_t) RTCrPkixSignatureRetain(RTCRPKIXSIGNATURE hSignature); + +/** + * Releases a reference to the signature schema provider instance. + * + * @returns New reference count on success, UINT32_MAX if invalid handle. + * @param hSignature The signature schema provider handle. NIL is ignored. + */ +RTDECL(uint32_t) RTCrPkixSignatureRelease(RTCRPKIXSIGNATURE hSignature); + +/** + * Verifies a signed message digest. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the signature checked out correctly. + * @retval VINF_CR_DIGEST_DEPRECATED if the signature checked out correctly + * but the hash algorithm is deprecated. + * @retval VINF_CR_DIGEST_COMPROMISED if the signature checked out correctly + * but the hash algorithm is compromised. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED if the signature checked out + * correctly but the hash algorithm is severely compromised. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * + * @param hSignature The signature schema provider handle. + * @param hDigest The handle to the digest. All that must have been + * feed to it via RTCrDigestUpdate() and friends prior + * to calling this function. The function will itself + * call RTCrDigestFinal() to complete and retreive the + * final hash value. + * @param pvSignature The signature to validate. + * @param cbSignature The size of the signature (in bytes). + */ +RTDECL(int) RTCrPkixSignatureVerify(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, void const *pvSignature, size_t cbSignature); +/** Convenience wrapper function for RTCrPkixSignatureVerify(). */ +RTDECL(int) RTCrPkixSignatureVerifyBitString(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, PCRTASN1BITSTRING pSignature); +/** Convenience wrapper function for RTCrPkixSignatureVerify(). */ +RTDECL(int) RTCrPkixSignatureVerifyOctetString(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, PCRTASN1OCTETSTRING pSignature); + +/** + * Sign a message digest. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success but the hash algorithm is deprecated. + * @retval VINF_CR_DIGEST_COMPROMISED on success but the hash algorithm is compromised. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success but the hash algorithm + * is severely compromised. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * @retval VERR_BUFFER_OVERFLOW if the signature buffer is too small, the + * require buffer size will be available in @a *pcbSignature. + * + * @param hSignature The signature schema provider handle. + * @param hDigest The handle to the digest. All that must have been + * feed to it via RTCrDigestUpdate() and friends prior + * to calling this function. The function will itself + * call RTCrDigestFinal() to complete and retreive the + * final hash value. + * @param pvSignature The output signature buffer. + * @param pcbSignature On input the variable pointed to holds the size of + * the buffer @a pvSignature points to. + * On return the variable pointed to is set to the size + * of the returned signature, or the required size in + * case of VERR_BUFFER_OVERFLOW. + */ +RTDECL(int) RTCrPkixSignatureSign(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, void *pvSignature, size_t *pcbSignature); + + +/** + * Public key encryption scheme provider descriptor. + * + * @todo This is just a sketch left over from when the signature code was + * chiseled out. + */ +typedef struct RTCRPKIXENCRYPTIONDESC +{ + /** The encryption scheme provider name. */ + const char *pszName; + /** The object ID string. */ + const char *pszObjId; + /** Pointer to a NULL terminated table of alias object IDs (optional). */ + const char * const *papszObjIdAliases; + /** The size of the state. */ + uint32_t cbState; + /** Reserved for future use / padding. */ + uint32_t uReserved; + /** Provider specific field. */ + uintptr_t uProviderSpecific; + + /** + * Initializes the state for this encryption scheme. + * + * Optional, RT_BZERO will be used if NULL. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param pvOpaque Opaque provider specific parameter. + * @param fEncrypt Set if the instance will be encrypting, clear if it + * will be decrypting. This aspect of the instance is + * immutable due to the algorithm requiring different + * keys for each of the operations. + * @param pKey The key to use (whether private or public depends on + * the operation type). + * @param pParams Algorithm/key parameters, optional. Will be NULL if + * none. + */ + DECLCALLBACKMEMBER(int, pfnInit,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, void *pvOpaque, bool fEncrypt, + PCRTASN1BITSTRING pKey, PCRTASN1DYNTYPE pParams)); + + /** + * Re-initializes the provider state. + * + * Optional. It is assumed that the provider does not have any state needing + * to be re-initialized if this method is not implemented. (Do not assume that + * a final encrypt/decrypt call has been made prior to this call.) + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param enmOperation Same as for the earlier pfnInit call. + */ + DECLCALLBACKMEMBER(int, pfnReset,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, bool fEncrypt)); + + /** + * Deletes the provider state. Optional. + * + * The state will be securely wiped clean after the call, regardless of whether + * the method is implemented or not. + * + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param enmOperation Same as for the earlier pfnInit call. + */ + DECLCALLBACKMEMBER(void, pfnDelete,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, bool fEncrypt)); + + /** + * Encrypt using the public key (fEncrypt = true). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small, the require + * buffer size will be available in @a *pcbCiphertext. The caller can + * should retry the call with a larger buffer. + * + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param pvPlaintext The plaintext to encrypt. + * @param cbPlaintext The number of bytes of plaintext. + * @param pvCiphertext Where to return the ciphertext (if any). + * @param cbMaxCiphertext The size of the buffer @a pvCiphertext points to. + * @param pcbCiphertext Where to return the actual number of bytes of + * ciphertext returned. + * @param fFinal Whether this is the final call. + */ + DECLCALLBACKMEMBER(int, pfnEncrypt,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, + void const *pvPlaintext, size_t cbPlaintext, + void *pvCiphertext, size_t cbMaxCiphertext, size_t *pcbCiphertext, bool fFinal)); + + /** + * Calculate the output buffer size for the next pfnEncrypt call. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param cbPlaintext The number of bytes of plaintext. + * @param pcbCiphertext Where to return the minimum buffer size. This may + * be larger than the actual number of bytes return. + * @param fFinal Whether this is the final call. + */ + DECLCALLBACKMEMBER(int, pfnEncryptLength,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, + size_t cbPlaintext, size_t *pcbCiphertext, bool fFinal)); + + /** + * Decrypt using the private key (fEncrypt = false). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small, the require + * buffer size will be available in @a *pcbCiphertext. The caller can + * should retry the call with a larger buffer. + * + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param pvCiphertext The ciphertext to decrypt. + * @param cbCiphertext The number of bytes of ciphertext. + * @param pvPlaintext Where to return the plaintext (if any). + * @param cbMaxPlaintext The size of the buffer @a pvPlaintext points to. + * @param pcbPlaintext Where to return the actual number of bytes of + * plaintext returned. + * @param fFinal Whether this is the final call. + */ + DECLCALLBACKMEMBER(int, pfnDecrypt,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, + void const *pvCiphertext, size_t cbCiphertext, + void *pvPlaintext, size_t cbMaxPlaintext, size_t *pcbPlaintext, bool fFinal)); + + /** + * Calculate the output buffer size for the next pfnDecrypt call. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param cbCiphertext The number of bytes of ciphertext. + * @param pcbPlaintext Where to return the minimum buffer size. This may + * be larger than the actual number of bytes return. + * @param fFinal Whether this is the final call. + */ + DECLCALLBACKMEMBER(int, pfnDecryptLength,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, + size_t cbCiphertext, size_t *pcbPlaintext, bool fFinal)); +} RTCRPKIXENCRYPTIONDESC; +/** Pointer to a public key encryption schema provider descriptor. */ +typedef RTCRPKIXENCRYPTIONDESC const *PCRTCRPKIXENCRYPTIONDESC; + + +PCRTCRPKIXENCRYPTIONDESC RTCrPkixEncryptionFindByObjIdString(const char *pszObjId, void *ppvOpaque); +PCRTCRPKIXENCRYPTIONDESC RTCrPkixEncryptionFindByObjId(PCRTASN1OBJID pObjId, void *ppvOpaque); +RTDECL(int) RTCrPkixEncryptionCreateByObjIdString(PRTCRPKIXENCRYPTION phEncryption, const char *pszObjId, + bool fEncrypt, RTCRKEY hKey, PCRTASN1DYNTYPE pParams); +RTDECL(int) RTCrPkixEncryptionCreateByObjId(PRTCRPKIXENCRYPTION phEncryption, PCRTASN1OBJID pObjId, bool fEncrypt, + RTCRKEY hKey, PCRTASN1DYNTYPE pParams); + + +RTDECL(int) RTCrPkixEncryptionCreate(PRTCRPKIXENCRYPTION phEncryption, PCRTCRPKIXENCRYPTIONDESC pDesc, void *pvOpaque, + bool fEncrypt, PCRTASN1BITSTRING pKey, PCRTASN1DYNTYPE pParams); +RTDECL(int) RTCrPkixEncryptionReset(RTCRPKIXENCRYPTION hEncryption); +RTDECL(uint32_t) RTCrPkixEncryptionRetain(RTCRPKIXENCRYPTION hEncryption); +RTDECL(uint32_t) RTCrPkixEncryptionRelease(RTCRPKIXENCRYPTION hEncryption); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_pkix_h */ + diff --git a/include/iprt/crypto/rc4.h b/include/iprt/crypto/rc4.h new file mode 100644 index 00000000..3576116f --- /dev/null +++ b/include/iprt/crypto/rc4.h @@ -0,0 +1,73 @@ +/** @file + * IPRT - Crypto - Alleged RC4 Cipher. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_rc4_h +#define IPRT_INCLUDED_crypto_rc4_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cr_rc4 RTCrRc4 - Alleged RC4 Cipher. + * @ingroup grp_rt_crypto + * @{ + */ + +/** RC4 key structure. */ +typedef union RTCRRC4KEY +{ + uint64_t au64Padding[(2 + 256) / 2]; +#ifdef HEADER_RC4_H + RC4_KEY Ossl; +#endif +} RTCRRC4KEY; +/** Pointer to a RC4 key structure. */ +typedef RTCRRC4KEY *PRTCRRC4KEY; +/** Pointer to a const RC4 key structure. */ +typedef RTCRRC4KEY const *PCRTCRRC4KEY; + +RTDECL(void) RTCrRc4SetKey(PRTCRRC4KEY pKey, size_t cbData, void const *pvData); +RTDECL(void) RTCrRc4(PRTCRRC4KEY pKey, size_t cbData, void const *pvDataIn, void *pvDataOut); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_rc4_h */ + diff --git a/include/iprt/crypto/rsa.h b/include/iprt/crypto/rsa.h new file mode 100644 index 00000000..34bc4505 --- /dev/null +++ b/include/iprt/crypto/rsa.h @@ -0,0 +1,166 @@ +/** @file + * IPRT - Crypto - RSA Public Key Cryptosystem . + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_rsa_h +#define IPRT_INCLUDED_crypto_rsa_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cr_rsa RTCrRsa - RSA Public Key Cryptosystem + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * RSA public key - ASN.1 IPRT representation. + */ +typedef struct RTCRRSAPUBLICKEY +{ + /** Sequence core for the structure. */ + RTASN1SEQUENCECORE SeqCore; + /** The modulus (n). */ + RTASN1INTEGER Modulus; + /** The public exponent (e). */ + RTASN1INTEGER PublicExponent; +} RTCRRSAPUBLICKEY; +/** Pointer to the ASN.1 IPRT representation of an RSA public key. */ +typedef RTCRRSAPUBLICKEY *PRTCRRSAPUBLICKEY; +/** Pointer to the const ASN.1 IPRT representation of an RSA public key. */ +typedef RTCRRSAPUBLICKEY const *PCRTCRRSAPUBLICKEY; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRRSAPUBLICKEY, RTDECL, RTCrRsaPublicKey, SeqCore.Asn1Core); + +RTDECL(bool) RTCrRsaPublicKey_CanHandleDigestType(PCRTCRRSAPUBLICKEY pRsaPublicKey, RTDIGESTTYPE enmDigestType, + PRTERRINFO pErrInfo); + + +/** + * RSA other prime info (ASN.1 IPRT representation). + */ +typedef struct RTCRRSAOTHERPRIMEINFO +{ + /** Sequence core for the structure. */ + RTASN1SEQUENCECORE SeqCore; + /** The prime (ri). */ + RTASN1INTEGER Prime; + /** The exponent (di). */ + RTASN1INTEGER Exponent; + /** The coefficient (ti). */ + RTASN1INTEGER Coefficient; +} RTCRRSAOTHERPRIMEINFO; +/** Pointer to the ASN.1 IPRT representation of RSA other prime info. */ +typedef RTCRRSAOTHERPRIMEINFO *PRTCRRSAOTHERPRIMEINFO; +/** Pointer to the const ASN.1 IPRT representation of RSA other prime info. */ +typedef RTCRRSAOTHERPRIMEINFO const *PCRTCRRSAOTHERPRIMEINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRRSAOTHERPRIMEINFO, RTDECL, RTCrRsaOtherPrimeInfo, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRRSAOTHERPRIMEINFOS, RTCRRSAOTHERPRIMEINFO, RTDECL, RTCrRsaOtherPrimeInfos); + +/** + * RSA private key - ASN.1 IPRT representation. + */ +typedef struct RTCRRSAPRIVATEKEY +{ + /** Sequence core for the structure. */ + RTASN1SEQUENCECORE SeqCore; + /** Key version number. */ + RTASN1INTEGER Version; + /** The modulus (n). */ + RTASN1INTEGER Modulus; + /** The public exponent (e). */ + RTASN1INTEGER PublicExponent; + /** The private exponent (d). */ + RTASN1INTEGER PrivateExponent; + /** The first prime factor (p) of the modulus (n). */ + RTASN1INTEGER Prime1; + /** The second prime factor (q) of the modulus (n). */ + RTASN1INTEGER Prime2; + /** The first exponent (d mod (p-1)). */ + RTASN1INTEGER Exponent1; + /** The second exponent (d mod (q-1)). */ + RTASN1INTEGER Exponent2; + /** The coefficient ((inverse of q) mod p). */ + RTASN1INTEGER Coefficient; + /** Optional other prime information (version must be 'multi' if present). */ + RTCRRSAOTHERPRIMEINFOS OtherPrimeInfos; +} RTCRRSAPRIVATEKEY; +/** Pointer to the ASN.1 IPRT representation of an RSA private key. */ +typedef RTCRRSAPRIVATEKEY *PRTCRRSAPRIVATEKEY; +/** Pointer to the const ASN.1 IPRT representation of an RSA private key. */ +typedef RTCRRSAPRIVATEKEY const *PCRTCRRSAPRIVATEKEY; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRRSAPRIVATEKEY, RTDECL, RTCrRsaPrivateKey, SeqCore.Asn1Core); + +/** @name RSA Private Key Versions + * @{ */ +#define RTCRRSAPRIVATEKEY_VERSION_TWO_PRIME 0 +#define RTCRRSAPRIVATEKEY_VERSION_MULTI 1 +/** @} */ + +RTDECL(bool) RTCrRsaPrivateKey_CanHandleDigestType(PCRTCRRSAPRIVATEKEY pRsaPrivateKey, RTDIGESTTYPE enmDigestType, + PRTERRINFO pErrInfo); + + +/** + * RSA DigestInfo used by the EMSA-PKCS1-v1_5 encoding method. + */ +typedef struct RTCRRSADIGESTINFO +{ + /** Sequence core for the structure. */ + RTASN1SEQUENCECORE SeqCore; + /** The digest algorithm. */ + RTCRX509ALGORITHMIDENTIFIER DigestAlgorithm; + /** The digest. */ + RTASN1OCTETSTRING Digest; +} RTCRRSADIGESTINFO; +/** Pointer to the ASN.1 IPRT representation of RSA digest info. */ +typedef RTCRRSADIGESTINFO *PRTCRRSADIGESTINFO; +/** Pointer to the const ASN.1 IPRT representation of RSA digest info. */ +typedef RTCRRSADIGESTINFO const *PCRTCRRSADIGESTINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRRSADIGESTINFO, RTDECL, RTCrRsaDigestInfo, SeqCore.Asn1Core); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_rsa_h */ + diff --git a/include/iprt/crypto/spc.h b/include/iprt/crypto/spc.h new file mode 100644 index 00000000..abe7fe36 --- /dev/null +++ b/include/iprt/crypto/spc.h @@ -0,0 +1,533 @@ +/** @file + * IPRT - Crypto - Microsoft SPC / Authenticode. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_spc_h +#define IPRT_INCLUDED_crypto_spc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cr_spc RTCrSpc - Microsoft Authenticode + * @ingroup grp_rt_crypto + * @{ + */ + +/** Value for RTCR_PKCS9_ID_MS_STATEMENT_TYPE. */ +#define RTCRSPC_STMT_TYPE_INDIVIDUAL_CODE_SIGNING "1.3.6.1.4.1.311.2.1.21" + +/** + * PE Image page hash table, generic union. + * + * @remarks This table isn't used by ldrPE.cpp, it walks the table in a generic + * fashion using the hash size. So, we can ditch it if we feel like it. + */ +typedef union RTCRSPCPEIMAGEPAGEHASHES +{ + /** MD5 page hashes. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** The hash. */ + uint8_t abHash[RTSHA1_HASH_SIZE]; + } aMd5[1]; + + /** SHA-1 page hashes. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** The hash. */ + uint8_t abHash[RTSHA1_HASH_SIZE]; + } aSha1[1]; + + /** SHA-256 page hashes. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** The hash. */ + uint8_t abHash[RTSHA256_HASH_SIZE]; + } aSha256[1]; + + /** SHA-512 page hashes. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** The hash. */ + uint8_t abHash[RTSHA512_HASH_SIZE]; + } aSha512[1]; + + /** Generic view of ONE hash. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** Variable length hash field. */ + uint8_t abHash[1]; + } Generic; +} RTCRSPCPEIMAGEPAGEHASHES; +/** Pointer to a PE image page hash table union. */ +typedef RTCRSPCPEIMAGEPAGEHASHES *PRTCRSPCPEIMAGEPAGEHASHES; +/** Pointer to a const PE image page hash table union. */ +typedef RTCRSPCPEIMAGEPAGEHASHES const *PCRTCRSPCPEIMAGEPAGEHASHES; + + +/** + * Serialization wrapper for raw RTCRSPCPEIMAGEPAGEHASHES data. + */ +typedef struct RTCRSPCSERIALIZEDPAGEHASHES +{ + /** The page hashes are within a set. Dunno if there could be multiple + * entries in this set, never seen it yet, so I doubt it. */ + RTASN1SETCORE SetCore; + /** Octet string containing the raw data. */ + RTASN1OCTETSTRING RawData; + + /** Pointer to the hash data within that string. + * The hash algorithm is given by the object attribute type in + * RTCRSPCSERIALIZEDOBJECTATTRIBUTE. It is generally the same as for the + * whole image hash. */ + PCRTCRSPCPEIMAGEPAGEHASHES pData; + /** Field the user can use to store the number of pages in pData. */ + uint32_t cPages; +} RTCRSPCSERIALIZEDPAGEHASHES; +/** Pointer to a serialized wrapper for page hashes. */ +typedef RTCRSPCSERIALIZEDPAGEHASHES *PRTCRSPCSERIALIZEDPAGEHASHES; +/** Pointer to a const serialized wrapper for page hashes. */ +typedef RTCRSPCSERIALIZEDPAGEHASHES const *PCRTCRSPCSERIALIZEDPAGEHASHES; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSERIALIZEDPAGEHASHES, RTDECL, RTCrSpcSerializedPageHashes, SetCore.Asn1Core); + +RTDECL(int) RTCrSpcSerializedPageHashes_UpdateDerivedData(PRTCRSPCSERIALIZEDPAGEHASHES pThis); + + +/** + * Data type selection for RTCRSPCSERIALIZEDOBJECTATTRIBUTE. + */ +typedef enum RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE +{ + /** Invalid zero entry. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_INVALID = 0, + /** Not present pro forma. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_NOT_PRESENT, + /** Unknown object. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_UNKNOWN, + /** SHA-1 page hashes (pPageHashes). */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1, + /** SHA-256 page hashes (pPageHashes). */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2, + /** End of valid values. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_END, + /** Blow up the type to at least 32-bits. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_32BIT_HACK +} RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE; + +/** + * One serialized object attribute (PE image data). + */ +typedef struct RTCRSPCSERIALIZEDOBJECTATTRIBUTE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The attribute type. */ + RTASN1OBJID Type; + /** The allocation of the data type. */ + RTASN1ALLOCATION Allocation; + /** Indicates the valid value in the union. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE enmType; + /** Union with data format depending on the Type. */ + union + { + /** The unknown value (RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_UNKNOWN). */ + PRTASN1CORE pCore; + /** Page hashes (RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1 or + * RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2). */ + PRTCRSPCSERIALIZEDPAGEHASHES pPageHashes; + } u; +} RTCRSPCSERIALIZEDOBJECTATTRIBUTE; +/** Pointer to a serialized object attribute. */ +typedef RTCRSPCSERIALIZEDOBJECTATTRIBUTE *PRTCRSPCSERIALIZEDOBJECTATTRIBUTE; +/** Pointer to a const serialized object attribute. */ +typedef RTCRSPCSERIALIZEDOBJECTATTRIBUTE const *PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSERIALIZEDOBJECTATTRIBUTE, RTDECL, RTCrSpcSerializedObjectAttribute, SeqCore.Asn1Core); + +RTDECL(int) RTCrSpcSerializedObjectAttribute_SetV1Hashes(PRTCRSPCSERIALIZEDOBJECTATTRIBUTE pThis, + PCRTCRSPCSERIALIZEDPAGEHASHES, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcSerializedObjectAttribute_SetV2Hashes(PRTCRSPCSERIALIZEDOBJECTATTRIBUTE pThis, + PCRTCRSPCSERIALIZEDPAGEHASHES, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** @name RTCRSPCSERIALIZEDOBJECTATTRIBUTE::Type values + * @{ */ +/** Serialized object attribute type for page hashes version 1. */ +#define RTCRSPC_PE_IMAGE_HASHES_V1_OID "1.3.6.1.4.1.311.2.3.1" +/** Serialized object attribute type for page hashes version 2. */ +#define RTCRSPC_PE_IMAGE_HASHES_V2_OID "1.3.6.1.4.1.311.2.3.2" +/** @} */ + + +/* + * Set of serialized object attributes (PE image data). + */ +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRSPCSERIALIZEDOBJECTATTRIBUTES, RTCRSPCSERIALIZEDOBJECTATTRIBUTE, RTDECL, + RTCrSpcSerializedObjectAttributes); + +/** The UUID found in RTCRSPCSERIALIZEDOBJECT::Uuid for + * RTCRSPCSERIALIZEDOBJECTATTRIBUTES. */ +#define RTCRSPCSERIALIZEDOBJECT_UUID_STR "d586b5a6-a1b4-6624-ae05-a217da8e60d6" + + +/** + * Decoded encapsulated data type selection in RTCRSPCSERIALIZEDOBJECT. + */ +typedef enum RTCRSPCSERIALIZEDOBJECTTYPE +{ + /** Invalid zero value. */ + RTCRSPCSERIALIZEDOBJECTTYPE_INVALID = 0, + /** Serialized object attributes (RTCRSPCSERIALIZEDOBJECT_UUID_STR / pAttribs). */ + RTCRSPCSERIALIZEDOBJECTTYPE_ATTRIBUTES, + /** End of valid values. */ + RTCRSPCSERIALIZEDOBJECTTYPE_END, + /** MAke sure the type is at least 32-bit wide. */ + RTCRSPCSERIALIZEDOBJECTTYPE_32BIT_HACK = 0x7fffffff +} RTCRSPCSERIALIZEDOBJECTTYPE; + +/** + * A serialized object (PE image data). + */ +typedef struct RTCRSPCSERIALIZEDOBJECT +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The UUID of the data object. */ + RTASN1OCTETSTRING Uuid; + /** Serialized data object. */ + RTASN1OCTETSTRING SerializedData; + + /** Indicates the valid pointer in the union. */ + RTCRSPCSERIALIZEDOBJECTTYPE enmType; + /** Union of pointers shadowing SerializedData.pEncapsulated. */ + union + { + /** Generic core pointer. */ + PRTASN1CORE pCore; + /** Pointer to decoded data if Uuid is RTCRSPCSERIALIZEDOBJECT_UUID_STR. */ + PRTCRSPCSERIALIZEDOBJECTATTRIBUTES pData; + } u; +} RTCRSPCSERIALIZEDOBJECT; +/** Pointer to a serialized object (PE image data). */ +typedef RTCRSPCSERIALIZEDOBJECT *PRTCRSPCSERIALIZEDOBJECT; +/** Pointer to a const serialized object (PE image data). */ +typedef RTCRSPCSERIALIZEDOBJECT const *PCRTCRSPCSERIALIZEDOBJECT; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSERIALIZEDOBJECT, RTDECL, RTCrSpcSerializedObject, SeqCore.Asn1Core); + + +/** + * RTCRSPCSTRING choices. + */ +typedef enum RTCRSPCSTRINGCHOICE +{ + /** Invalid zero value. */ + RTCRSPCSTRINGCHOICE_INVALID = 0, + /** Not present. */ + RTCRSPCSTRINGCHOICE_NOT_PRESENT, + /** UCS-2 string (pUcs2). */ + RTCRSPCSTRINGCHOICE_UCS2, + /** ASCII string (pAscii). */ + RTCRSPCSTRINGCHOICE_ASCII, + /** End of valid values. */ + RTCRSPCSTRINGCHOICE_END, + /** Blow the type up to 32-bit. */ + RTCRSPCSTRINGCHOICE_32BIT_HACK = 0x7fffffff +} RTCRSPCSTRINGCHOICE; + +/** + * Stupid microsoft choosy string type. + */ +typedef struct RTCRSPCSTRING +{ + /** Dummy core. */ + RTASN1DUMMY Dummy; + /** Allocation of what the pointer below points to. */ + RTASN1ALLOCATION Allocation; + /** Pointer choice.*/ + RTCRSPCSTRINGCHOICE enmChoice; + /** Pointer union. */ + union + { + /** Tag 0, implicit: UCS-2 (BMP) string. */ + PRTASN1STRING pUcs2; + /** Tag 1, implicit: ASCII (IA5) string. */ + PRTASN1STRING pAscii; + } u; +} RTCRSPCSTRING; +/** Pointer to a stupid microsoft string choice. */ +typedef RTCRSPCSTRING *PRTCRSPCSTRING; +/** Pointer to a const stupid microsoft string choice. */ +typedef RTCRSPCSTRING const *PCRTCRSPCSTRING; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSTRING, RTDECL, RTCrSpcString, Dummy.Asn1Core); + +RTDECL(int) RTCrSpcString_SetUcs2(PRTCRSPCSTRING pThis, PCRTASN1STRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcString_SetAscii(PRTCRSPCSTRING pThis, PCRTASN1STRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + + +/** + * RTCRSPCSTRING choices. + */ +typedef enum RTCRSPCLINKCHOICE +{ + /** Invalid zero value. */ + RTCRSPCLINKCHOICE_INVALID = 0, + /** Not present. */ + RTCRSPCLINKCHOICE_NOT_PRESENT, + /** URL (ASCII) string (pUrl). */ + RTCRSPCLINKCHOICE_URL, + /** Serialized object (pMoniker). */ + RTCRSPCLINKCHOICE_MONIKER, + /** Filename (pT2). */ + RTCRSPCLINKCHOICE_FILE, + /** End of valid values. */ + RTCRSPCLINKCHOICE_END, + /** Blow the type up to 32-bit. */ + RTCRSPCLINKCHOICE_32BIT_HACK = 0x7fffffff +} RTCRSPCLINKCHOICE; + +/** + * PE image data link. + */ +typedef struct RTCRSPCLINK +{ + /** Dummy core. */ + RTASN1DUMMY Dummy; + /** Allocation of what the pointer below points to. */ + RTASN1ALLOCATION Allocation; + /** Pointer choice.*/ + RTCRSPCLINKCHOICE enmChoice; + /** Pointer union. */ + union + { + /** Tag 0, implicit: An URL encoded as an IA5 STRING. */ + PRTASN1STRING pUrl; + /** Tag 1, implicit: A serialized object. */ + PRTCRSPCSERIALIZEDOBJECT pMoniker; + /** Tag 2, explicit: The default, a file name. + * Documented to be set to "<<>>" when used. */ + struct + { + /** Context tag 2. */ + RTASN1CONTEXTTAG2 CtxTag2; + /** The file name string. */ + RTCRSPCSTRING File; + } *pT2; + } u; +} RTCRSPCLINK; +/** Poitner to a PE image data link. */ +typedef RTCRSPCLINK *PRTCRSPCLINK; +/** Poitner to a const PE image data link. */ +typedef RTCRSPCLINK const *PCRTCRSPCLINK; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCLINK, RTDECL, RTCrSpcLink, Dummy.Asn1Core); + +RTDECL(int) RTCrSpcLink_SetUrl(PRTCRSPCLINK pThis, PCRTASN1STRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcLink_SetMoniker(PRTCRSPCLINK pThis, PCRTCRSPCSERIALIZEDOBJECT pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcLink_SetFile(PRTCRSPCLINK pThis, PCRTCRSPCSTRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + + +#if 0 /** @todo Might not be the correct bit order. */ +/** + * Flag values for RTCRSPCPEIMAGEDATA::Flags and RTCRSPCPEIMAGEDATA::fFlags. + */ +typedef enum RTCRSPCPEIMAGEFLAGS +{ + RTCRSPCPEIMAGEFLAGS_INCLUDE_RESOURCES = 0, + RTCRSPCPEIMAGEFLAGS_INCLUDE_DEBUG_INFO = 1, + RTCRSPCPEIMAGEFLAGS_IMPORT_ADDRESS_TABLE = 2 +} RTCRSPCPEIMAGEFLAGS; +#endif + + +/** + * Authenticode PE Image data. + */ +typedef struct RTCRSPCPEIMAGEDATA +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** One of the RTCRSPCPEIMAGEFLAGS value, default is + * RTCRSPCPEIMAGEFLAGS_INCLUDE_RESOURCES. Obsolete with v2 page hashes? */ + RTASN1BITSTRING Flags; + /** Tag 0, explicit: Link to the data. */ + struct + { + /** Context tag 0. */ + RTASN1CONTEXTTAG0 CtxTag0; + /** Link to the data. */ + RTCRSPCLINK File; + } T0; +} RTCRSPCPEIMAGEDATA; +/** Pointer to a authenticode PE image data representation. */ +typedef RTCRSPCPEIMAGEDATA *PRTCRSPCPEIMAGEDATA; +/** Pointer to a const authenticode PE image data representation. */ +typedef RTCRSPCPEIMAGEDATA const *PCRTCRSPCPEIMAGEDATA; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCPEIMAGEDATA, RTDECL, RTCrSpcPeImageData, SeqCore.Asn1Core); + +RTDECL(int) RTCrSpcPeImageData_SetFlags(PRTCRSPCPEIMAGEDATA pThis, PCRTASN1BITSTRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcPeImageData_SetFile(PRTCRSPCPEIMAGEDATA pThis, PCRTCRSPCLINK pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** The object ID for SpcPeImageData. */ +#define RTCRSPCPEIMAGEDATA_OID "1.3.6.1.4.1.311.2.1.15" + + +/** + * Data type selection for RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE. + */ +typedef enum RTCRSPCAAOVTYPE +{ + /** Invalid zero entry. */ + RTCRSPCAAOVTYPE_INVALID = 0, + /** Not present (pro forma). */ + RTCRSPCAAOVTYPE_NOT_PRESENT, + /** Unknown object. */ + RTCRSPCAAOVTYPE_UNKNOWN, + /** PE image data (pPeImage). */ + RTCRSPCAAOVTYPE_PE_IMAGE_DATA, + /** End of valid values. */ + RTCRSPCAAOVTYPE_END, + /** Blow up the type to at least 32-bits. */ + RTCRSPCAAOVTYPE_32BIT_HACK +} RTCRSPCAAOVTYPE; + +/** + * Authenticode attribute type and optional value. + * + * Note! Spec says the value should be explicitly tagged, but in real life + * it isn't. So, not very optional? + */ +typedef struct RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** An object ID indicating the type of the value. */ + RTASN1OBJID Type; + /** Allocation of the optional data value. */ + RTASN1ALLOCATION Allocation; + /** The valid pointer. */ + RTCRSPCAAOVTYPE enmType; + /** The value part depends on the Type. */ + union + { + /** RTCRSPCAAOVTYPE_UNKNOWN / Generic. */ + PRTASN1CORE pCore; + /** RTCRSPCAAOVTYPE_PE_IMAGE_DATA / RTCRSPCPEIMAGEDATA_OID. */ + PRTCRSPCPEIMAGEDATA pPeImage; + } uValue; +} RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE; +/** Pointer to a authentication attribute type and optional value + * representation. */ +typedef RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE *PRTCRSPCATTRIBUTETYPEANDOPTIONALVALUE; +/** Pointer to a const authentication attribute type and optional value + * representation. */ +typedef RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE const *PCRTCRSPCATTRIBUTETYPEANDOPTIONALVALUE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE, RTDECL, RTCrSpcAttributeTypeAndOptionalValue, SeqCore.Asn1Core); + +RTDECL(int) RTCrSpcAttributeTypeAndOptionalValue_SetPeImage(PRTCRSPCATTRIBUTETYPEANDOPTIONALVALUE pThis, + PCRTCRSPCPEIMAGEDATA pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Authenticode indirect data content. + */ +typedef struct RTCRSPCINDIRECTDATACONTENT +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Additional data. */ + RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE Data; + /** The whole image digest. */ + RTCRPKCS7DIGESTINFO DigestInfo; +} RTCRSPCINDIRECTDATACONTENT; +/** Pointer to a authenticode indirect data content representation. */ +typedef RTCRSPCINDIRECTDATACONTENT *PRTCRSPCINDIRECTDATACONTENT; +/** Pointer to a const authenticode indirect data content representation. */ +typedef RTCRSPCINDIRECTDATACONTENT const *PCRTCRSPCINDIRECTDATACONTENT; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCINDIRECTDATACONTENT, RTDECL, RTCrSpcIndirectDataContent, SeqCore.Asn1Core); + +/** The object ID for SpcIndirectDataContent. */ +#define RTCRSPCINDIRECTDATACONTENT_OID "1.3.6.1.4.1.311.2.1.4" + +/** + * Check the sanity of an Authenticode SPCIndirectDataContent object. + * + * @returns IPRT status code + * @param pIndData The Authenticode SPCIndirectDataContent to + * check. + * @param pSignedData The related signed data object. + * @param fFlags RTCRSPCINDIRECTDATACONTENT_SANITY_F_XXX. + * @param pErrInfo Optional error info. + */ +RTDECL(int) RTCrSpcIndirectDataContent_CheckSanityEx(PCRTCRSPCINDIRECTDATACONTENT pIndData, PCRTCRPKCS7SIGNEDDATA pSignedData, + uint32_t fFlags, PRTERRINFO pErrInfo); +/** @name RTCRSPCINDIRECTDATACONTENT_SANITY_F_XXX for RTCrSpcIndirectDataContent_CheckSanityEx. + * @{ */ +/** The digest hash algorithm must be known to IPRT. */ +#define RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH RT_BIT_32(0) +/** PE image signing, check expectations of the spec. */ +#define RTCRSPCINDIRECTDATACONTENT_SANITY_F_PE_IMAGE RT_BIT_32(1) +/** @} */ + +/** + * Gets the first SPC serialized object attribute in a SPC PE image. + * + * @returns Pointer to the attribute with the given type, NULL if not found. + * @param pThis The Authenticode SpcIndirectDataContent. + * @param enmType The type of attribute to get. + */ +RTDECL(PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE) +RTCrSpcIndirectDataContent_GetPeImageObjAttrib(PCRTCRSPCINDIRECTDATACONTENT pThis, + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE enmType); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_spc_h */ + diff --git a/include/iprt/crypto/ssl.h b/include/iprt/crypto/ssl.h new file mode 100644 index 00000000..5c69811b --- /dev/null +++ b/include/iprt/crypto/ssl.h @@ -0,0 +1,143 @@ +/** @file + * IPRT - Secure Socket Layer (SSL) / Transport Security Layer (TLS) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_ssl_h +#define IPRT_INCLUDED_crypto_ssl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crssl RTCrSsl - Secure Socket Layer (SSL) / Transport Security Layer (TLS) + * @ingroup grp_rt_crypto + * @{ + */ + +/** SSL handle. */ +typedef R3PTRTYPE(struct RTCRSSLINT *) RTCRSSL; +/** Pointer to a SSL handle. */ +typedef RTCRSSL *PRTCRSSL; +/** Nil SSL handle. */ +#define NIL_RTCRSSL ((RTCRSSL)0) + +/** SSL session handle. */ +typedef R3PTRTYPE(struct RTCRSSLSESSIONINT *) RTCRSSLSESSION; +/** Pointer to a SSL session handle. */ +typedef RTCRSSLSESSION *PRTCRSSLSESSION; +/** Nil SSL session handle. */ +#define NIL_RTCRSSLSESSION ((RTCRSSLSESSION)0) + + +RTDECL(int) RTCrSslCreate(PRTCRSSL phSsl, uint32_t fFlags); + +/** + * Retains a reference to the SSL handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSsl The SSL handle. + */ +RTDECL(uint32_t) RTCrSslRetain(RTCRSSL hSsl); + +/** + * Release a reference to the SSL handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSsl The SSL handle. The NIL handle is quietly + * ignored and 0 is returned. + */ +RTDECL(uint32_t) RTCrSslRelease(RTCRSSL hSsl); + +#define RTCRSSL_FILE_F_PEM 0 +#define RTCRSSL_FILE_F_ASN1 RT_BIT_32(1) + +RTDECL(int) RTCrSslSetCertificateFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags); +RTDECL(int) RTCrSslSetPrivateKeyFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags); +RTDECL(int) RTCrSslLoadTrustedRootCerts(RTCRSSL hSsl, const char *pszFile, const char *pszDir); +RTDECL(int) RTCrSslSetNoPeerVerify(RTCRSSL hSsl); +/** @todo Min/max protocol setters. */ + + + +RTDECL(int) RTCrSslCreateSession(RTCRSSL hSsl, RTSOCKET hSocket, uint32_t fFlags, PRTCRSSLSESSION phSslSession); +RTDECL(int) RTCrSslCreateSessionForNativeSocket(RTCRSSL hSsl, RTHCINTPTR hNativeSocket, uint32_t fFlags, + PRTCRSSLSESSION phSslSession); +/** @name RTCRSSLSESSION_F_XXX - Flags for RTCrSslCreateSession and RTCrSslCreateSessionForNativeSocket. + * @{ */ +/** The socket is non-blocking. */ +#define RTCRSSLSESSION_F_NON_BLOCKING RT_BIT_32(0) +/** @} */ + +/** + * Retains a reference to the SSL session handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSslSession The SSL session handle. + */ +RTDECL(uint32_t) RTCrSslSessionRetain(RTCRSSLSESSION hSslSession); + +/** + * Release a reference to the SSL handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSslSession The SSL session handle. The NIL handle is quietly + * ignored and 0 is returned. + */ +RTDECL(uint32_t) RTCrSslSessionRelease(RTCRSSLSESSION hSslSession); + +RTDECL(int) RTCrSslSessionAccept(RTCRSSLSESSION hSslSession, uint32_t fFlags); +RTDECL(int) RTCrSslSessionConnect(RTCRSSLSESSION hSslSession, uint32_t fFlags); + +RTDECL(const char *) RTCrSslSessionGetVersion(RTCRSSLSESSION hSslSession); +RTDECL(int) RTCrSslSessionGetCertIssuerNameAsString(RTCRSSLSESSION hSslSession, char *pszBuf, size_t cbBuf, size_t *pcbActual); +RTDECL(bool) RTCrSslSessionPending(RTCRSSLSESSION hSslSession); +RTDECL(ssize_t) RTCrSslSessionRead(RTCRSSLSESSION hSslSession, void *pvBuf, size_t cbToRead); +RTDECL(ssize_t) RTCrSslSessionWrite(RTCRSSLSESSION hSslSession, void const *pvBuf, size_t cbToWrite); + + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_ssl_h */ + diff --git a/include/iprt/crypto/store.h b/include/iprt/crypto/store.h new file mode 100644 index 00000000..c25e21e7 --- /dev/null +++ b/include/iprt/crypto/store.h @@ -0,0 +1,410 @@ +/** @file + * IPRT - Cryptographic (Certificate) Store. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_store_h +#define IPRT_INCLUDED_crypto_store_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crstore RTCrStore - Crypotgraphic (Certificate) Store. + * @ingroup grp_rt_crypto + * @{ + */ + + +/** + * A certificate store search. + * + * Used by the store provider to keep track of the current location of a + * certificate search. + */ +typedef struct RTCRSTORECERTSEARCH +{ + /** Opaque provider specific storage. + * + * Provider restriction: The provider is only allowed to use the two first + * entries for the find-all searches, because the front-end API may want the + * last two for implementing specific searches on top of it. */ + uintptr_t auOpaque[4]; +} RTCRSTORECERTSEARCH; +/** Pointer to a certificate store search. */ +typedef RTCRSTORECERTSEARCH *PRTCRSTORECERTSEARCH; + + +/** + * Info about a wanted certificate. + * + * All the search criteria are optional, but for a safe and efficient search + * it's recommended to specify all possible ones. If none are given, the search + * function will fail. + * + * For use with RTCrStoreCertAddFromFishingExpedition and others. + */ +typedef struct RTCRCERTWANTED +{ + /** The certificate subject name, optional. + * The format is: "C=US, ST=California, L=Redwood Shores, O=Oracle Corporation" */ + const char *pszSubject; + /** The size of the DER (ASN.1) encoded certificate, optional (0). */ + uint16_t cbEncoded; + /** Set if abSha1 contains a valid SHA-1 fingerprint. */ + bool fSha1Fingerprint; + /** Set if abSha512 contains a valid SHA-512 fingerprint. */ + bool fSha512Fingerprint; + /** The SHA-1 fingerprint (of the encoded data). */ + uint8_t abSha1[RTSHA1_HASH_SIZE]; + /** The SHA-512 fingerprint (of the encoded data). */ + uint8_t abSha512[RTSHA512_HASH_SIZE]; + /** User pointer for directly associating other data with the entry. + * Subclassing the structure isn't possible because it's passed as an array. */ + void const *pvUser; +} RTCRCERTWANTED; +/** Pointer to a const certificat wanted structure. */ +typedef RTCRCERTWANTED const *PCRTCRCERTWANTED; + + +/** + * Standard store identifiers. + * + * This is a least common denominator approach to system specific certificate + * stores, could be extended to include things other than certificates later if + * we need it. + * + * Windows has lots of different stores, they'll be combined by the + * implementation, possibly leading to duplicates. The user stores on Windows + * seems to be unioned with the system (machine) stores. + * + * Linux may have different stores depending on the distro/version/installation, + * in which case we'll combine them, which will most likely lead to + * duplicates just like on windows. Haven't found any easily accessible + * per-user certificate stores on linux yet, so they'll all be empty. + * + * Mac OS X seems a lot simpler, at least from the GUI point of view. Each + * keychains as a "Certificates" folder (the "My Certificates" folder seems to + * only be a matching of "Keys" and "Certificates"). However, there are two + * system keychains that we need to combine, "System" and "System Roots". As + * with Windows and Linux, there is a possibility for duplicates here. + * + * On solaris we have currently no idea where to look for a certificate store, + * so that doesn't yet work. + * + * Because of the OS X setup, we do not provide any purpose specific + */ +typedef enum RTCRSTOREID +{ + /** Mandatory invalid zero value. */ + RTCRSTOREID_INVALID = 0, + /** Open the certificate store of the current user containing trusted + * CAs and certificates. + * @remarks This may or may not include all the certificates in the system + * store, that's host dependent. So, you better look in both. */ + RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES, + /** Open the certificate store of the system containg trusted CAs + * and certificates. */ + RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES, + /** Open the certificate store of the current user containing intermediate CAs. + * @remarks This may or may not include all the certificates in the system + * store, that's host dependent. So, you better look in both. */ + RTCRSTOREID_USER_INTERMEDIATE_CAS, + /** Open the certificate store of the system containg intermediate CAs. */ + RTCRSTOREID_SYSTEM_INTERMEDIATE_CAS, + /** End of valid values. */ + RTCRSTOREID_END, + /** Traditional enum type compression prevention hack. */ + RTCRSTOREID_32BIT_HACK = 0x7fffffff +} RTCRSTOREID; + +/** + * Creates a snapshot of a standard store. + * + * This will return an in-memory store containing all data from the given store. + * There will be no duplicates in this one. + * + * @returns IPRT status code. + * @param phStore Where to return the store handle. Use + * RTCrStoreRelease to release it. + * @param enmStoreId The store to snapshot. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCreateSnapshotById(PRTCRSTORE phStore, RTCRSTOREID enmStoreId, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts(PRTCRSTORE phStore, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrStoreCreateInMem(PRTCRSTORE phStore, uint32_t cSizeHint); +RTDECL(int) RTCrStoreCreateInMemEx(PRTCRSTORE phStore, uint32_t cSizeHint, RTCRSTORE hParentStore); + +RTDECL(uint32_t) RTCrStoreRetain(RTCRSTORE hStore); +RTDECL(uint32_t) RTCrStoreRelease(RTCRSTORE hStore); +RTDECL(PCRTCRCERTCTX) RTCrStoreCertByIssuerAndSerialNo(RTCRSTORE hStore, PCRTCRX509NAME pIssuer, PCRTASN1INTEGER pSerialNo); + +/** + * Add a certificate to the store. + * + * @returns IPRT status code. + * @retval VWRN_ALREADY_EXISTS if the certificate is already present and + * RTCRCERTCTX_F_ADD_IF_NOT_FOUND was specified. + * @retval VERR_WRITE_PROTECT if the store doesn't support adding. + * @param hStore The store to add the certificate to. + * @param fFlags RTCRCERTCTX_F_XXX. Encoding must be specified. + * RTCRCERTCTX_F_ADD_IF_NOT_FOUND is supported. + * @param pvSrc The encoded certificate bytes. + * @param cbSrc The size of the encoded certificate. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddEncoded(RTCRSTORE hStore, uint32_t fFlags, void const *pvSrc, size_t cbSrc, PRTERRINFO pErrInfo); + +/** + * Add an X.509 packaged certificate to the store. + * + * @returns IPRT status code. + * @retval VWRN_ALREADY_EXISTS if the certificate is already present and + * RTCRCERTCTX_F_ADD_IF_NOT_FOUND was specified. + * @retval VERR_WRITE_PROTECT if the store doesn't support adding. + * @param hStore The store to add the certificate to. + * @param fFlags RTCRCERTCTX_F_XXX. Encoding must is optional, + * but must be RTCRCERTCTX_F_ENC_X509_DER if given. + * RTCRCERTCTX_F_ADD_IF_NOT_FOUND is supported. + * @param pCertificate The certificate to add. We may have to encode + * it, thus not const. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddX509(RTCRSTORE hStore, uint32_t fFlags, PRTCRX509CERTIFICATE pCertificate, PRTERRINFO pErrInfo); + +/** + * Adds certificates from files in the specified directory. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The store to add the certificate(s) to. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param pszDir The path to the directory. + * @param paSuffixes List of suffixes of files to process. + * @param cSuffixes Number of suffixes. If this is 0, all files are + * processed. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddFromDir(RTCRSTORE hStore, uint32_t fFlags, const char *pszDir, + PCRTSTRTUPLE paSuffixes, size_t cSuffixes, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrStoreCertAddWantedFromDir(RTCRSTORE hStore, uint32_t fFlags, + const char *pszDir, PCRTSTRTUPLE paSuffixes, size_t cSuffixes, + PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo); + +/** + * Adds certificates from the specified file. + * + * The supported file formats are: + * - PEM (base 64 blobs wrapped in -----BEGIN / END----). Support multiple + * certificates in one file. + * - Binary DER ASN.1 certificate. Only one per file. + * - Java key store version 2. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The store to add the certificate(s) to. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param pszFilename The filename. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrStoreCertAddWantedFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, + PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo); + +/** + * Adds certificates from the specified java key store file. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The store to add the certificate(s) to. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param pszFilename The path to the JKS file. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddFromJavaKeyStore(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Adds certificates from an in-memory java key store. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The store to add the certificate(s) to. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param pvContent Pointer to the key store bytes. + * @param cbContent The size of the key store. + * @param pszErrorName The file name or whatever helpful indicator the + * caller want in the error messages. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddFromJavaKeyStoreInMem(RTCRSTORE hStore, uint32_t fFlags, void const *pvContent, size_t cbContent, + const char *pszErrorName, PRTERRINFO pErrInfo); + +/** + * Adds all certificates from @a hStoreSrc into @a hStore. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The destination store. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param hStoreSrc The source store. + */ +RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc); + +RTDECL(int) RTCrStoreCertAddWantedFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hSrcStore, + PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound); + +RTDECL(int) RTCrStoreCertCheckWanted(RTCRSTORE hStore, PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound); + + +RTDECL(int) RTCrStoreCertAddWantedFromFishingExpedition(RTCRSTORE hStore, uint32_t fFlags, + PCRTCRCERTWANTED paWanted, size_t cWanted, + bool *pafFound, PRTERRINFO pErrInfo); + +/** + * Exports the certificates in the store to a PEM file + * + * @returns IPRT status code. + * @param hStore The store which certificates should be exported. + * @param fFlags Reserved for the future, MBZ. + * @param pszFilename The name of the destination PEM file. This will + * be truncated. + */ +RTDECL(int) RTCrStoreCertExportAsPem(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename); + +/** + * Counts the number of certificates in the store. + * + * @returns Certificate count on success, UINT32_MAX on failure. + * @param hStore The store which certificates should be counted. + */ +RTDECL(uint32_t) RTCrStoreCertCount(RTCRSTORE hStore); + +RTDECL(int) RTCrStoreCertFindAll(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch); +RTDECL(int) RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(RTCRSTORE hStore, PCRTCRX509NAME pSubject, + PRTCRSTORECERTSEARCH pSearch); +RTDECL(PCRTCRCERTCTX) RTCrStoreCertSearchNext(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch); +RTDECL(int) RTCrStoreCertSearchDestroy(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch); + +RTDECL(int) RTCrStoreConvertToOpenSslCertStore(RTCRSTORE hStore, uint32_t fFlags, void **ppvOpenSslStore, PRTERRINFO pErrInfo); +RTDECL(int) RTCrStoreConvertToOpenSslCertStack(RTCRSTORE hStore, uint32_t fFlags, void **ppvOpenSslStack, PRTERRINFO pErrInfo); + + +/** @} */ + + +/** @defgroup grp_rt_crcertctx RTCrCertCtx - (Store) Certificate Context. + * @{ */ + + +/** + * Certificate context. + * + * This is returned by the certificate store APIs and is part of a larger + * reference counted structure. All the data is read only. + */ +typedef struct RTCRCERTCTX +{ + /** Flags, RTCRCERTCTX_F_XXX. */ + uint32_t fFlags; + /** The size of the (DER) encoded certificate. */ + uint32_t cbEncoded; + /** Pointer to the (DER) encoded certificate. */ + uint8_t const *pabEncoded; + /** Pointer to the decoded X.509 representation of the certificate. + * This can be NULL when pTaInfo is present. */ + PCRTCRX509CERTIFICATE pCert; + /** Pointer to the decoded TrustAnchorInfo for the certificate. This can be + * NULL, even for trust anchors, as long as pCert isn't. */ + PCRTCRTAFTRUSTANCHORINFO pTaInfo; + /** Reserved for future use. */ + void *paReserved[2]; +} RTCRCERTCTX; + +/** @name RTCRCERTCTX_F_XXX. + * @{ */ +/** Encoding mask. */ +#define RTCRCERTCTX_F_ENC_MASK UINT32_C(0x000000ff) +/** X.509 certificate, DER encoded. */ +#define RTCRCERTCTX_F_ENC_X509_DER UINT32_C(0x00000000) +/** RTF-5914 trust anchor info, DER encoded. */ +#define RTCRCERTCTX_F_ENC_TAF_DER UINT32_C(0x00000001) +#if 0 +/** Extended certificate, DER encoded. */ +#define RTCRCERTCTX_F_ENC_PKCS6_DER UINT32_C(0x00000002) +#endif +/** Mask containing the flags that ends up in the certificate context. */ +#define RTCRCERTCTX_F_MASK UINT32_C(0x000000ff) + +/** Add APIs: Add the certificate if not found. */ +#define RTCRCERTCTX_F_ADD_IF_NOT_FOUND UINT32_C(0x00010000) +/** Add APIs: Continue on error when possible. */ +#define RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR UINT32_C(0x00020000) +/** @} */ + + +RTDECL(uint32_t) RTCrCertCtxRetain(PCRTCRCERTCTX pCertCtx); +RTDECL(uint32_t) RTCrCertCtxRelease(PCRTCRCERTCTX pCertCtx); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_store_h */ + diff --git a/include/iprt/crypto/taf.h b/include/iprt/crypto/taf.h new file mode 100644 index 00000000..4966a7b2 --- /dev/null +++ b/include/iprt/crypto/taf.h @@ -0,0 +1,202 @@ +/** @file + * IPRT - Crypto - Trust Anchor Format (RFC-5914). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_taf_h +#define IPRT_INCLUDED_crypto_taf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crtaf RTCrTaf - Trust Anchor Format (RFC-5914) + * @ingroup grp_rt_crypto + * @{ + */ + + +/** + * RFC-5914 CertPathControls (IPRT representation). + */ +typedef struct RTCRTAFCERTPATHCONTROLS +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The trust anchor subject. For use in path construction. */ + RTCRX509NAME TaName; + /** Certificate, optional, implicit tag 0. */ + RTCRX509CERTIFICATE Certificate; + /** Certificate policies, optional, implicit tag 1. + * @remarks This is an ASN.1 SEQUENCE, not an ASN.1 SET as the name + * mistakenly might be taken to indicate. */ + RTCRX509CERTIFICATEPOLICIES PolicySet; + /** Policy flags, optional, implicit tag 2. */ + RTASN1BITSTRING PolicyFlags; + /** Name constraints, optional, implicit tag 3. */ + RTCRX509NAMECONSTRAINTS NameConstr; + /** Path length constraints, optional, implicit tag 4. */ + RTASN1INTEGER PathLenConstraint; +} RTCRTAFCERTPATHCONTROLS; +/** Pointer to the IPRT representation of a RFC-5914 CertPathControls. */ +typedef RTCRTAFCERTPATHCONTROLS *PRTCRTAFCERTPATHCONTROLS; +/** Pointer to the const IPRT representation of a RFC-5914 CertPathControls. */ +typedef RTCRTAFCERTPATHCONTROLS const *PCRTCRTAFCERTPATHCONTROLS; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTAFCERTPATHCONTROLS, RTDECL, RTCrTafCertPathControls, SeqCore.Asn1Core); + +/** @name Bit definitions for RTCRTAFCERTPATHCONTROL::PolicyFlags + * @{ */ +#define RTCRTAFCERTPOLICYFLAGS_INHIBIT_POLICY_MAPPING 0 +#define RTCRTAFCERTPOLICYFLAGS_REQUIRE_EXPLICIT_POLICY 1 +#define RTCRTAFCERTPOLICYFLAGS_INHIBIT_ANY_POLICY 2 +/** @} */ + + +/** + * RFC-5914 TrustAnchorInfo (IPRT representation). + */ +typedef struct RTCRTAFTRUSTANCHORINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The version number (defaults to v1). */ + RTASN1INTEGER Version; + /** The public key of the trust anchor. */ + RTCRX509SUBJECTPUBLICKEYINFO PubKey; + /** Key identifier. */ + RTASN1OCTETSTRING KeyIdentifier; + /** Trust anchor title, optional, size 1 to 64. */ + RTASN1STRING TaTitle; + /** Certificate path controls, optional. */ + RTCRTAFCERTPATHCONTROLS CertPath; + /** Extensions, explicit optional, context tag 1. */ + struct + { + /** Context tag 1. */ + RTASN1CONTEXTTAG1 CtxTag1; + /** The extensions. */ + RTCRX509EXTENSIONS Exts; + } T1; + /** Title language tag, implicit optional, context tag 2. + * Defaults to "en". */ + RTASN1STRING TaTitleLangTag; +} RTCRTAFTRUSTANCHORINFO; +/** Pointer to the IPRT representation of a RFC-5914 TrustAnchorInfo. */ +typedef RTCRTAFTRUSTANCHORINFO *PRTCRTAFTRUSTANCHORINFO; +/** Pointer to the const IPRT representation of a RFC-5914 TrustAnchorInfo. */ +typedef RTCRTAFTRUSTANCHORINFO const *PCRTCRTAFTRUSTANCHORINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTAFTRUSTANCHORINFO, RTDECL, RTCrTafTrustAnchorInfo, SeqCore.Asn1Core); + +/** TrustAnchorInfo version 1. */ +#define RTCRTAFTRUSTANCHORINFO_V1 1 + + +/** Indicates what kind of value a TrustAnchorChoice structure contains. */ +typedef enum RTCRTAFTRUSTANCHORCHOICEVAL +{ + /** Invalid zero value. */ + RTCRTAFTRUSTANCHORCHOICEVAL_INVALID = 0, + /** RTCRTAFTRUSTANCHORCHOICE::u.pCertificate. */ + RTCRTAFTRUSTANCHORCHOICEVAL_CERTIFICATE, + /** RTCRTAFTRUSTANCHORCHOICE::u.pT1. */ + RTCRTAFTRUSTANCHORCHOICEVAL_TBS_CERTIFICATE, + /** RTCRTAFTRUSTANCHORCHOICE::u.pT2. */ + RTCRTAFTRUSTANCHORCHOICEVAL_TRUST_ANCHOR_INFO, + /** End of valid choices. */ + RTCRTAFTRUSTANCHORCHOICEVAL_END, + /** Make sure it's (at least) 32-bit wide. */ + RTCRTAFTRUSTANCHORCHOICEVAL_32BIT_HACK = 0x7fffffff +} RTCRTAFTRUSTANCHORCHOICEVAL; + + +/** + * RFC-5914 TrustAnchorChoice (IPRT representation). + */ +typedef struct RTCRTAFTRUSTANCHORCHOICE +{ + /** Dummy object for simplifying everything. */ + RTASN1DUMMY Dummy; + /** Allocation for the valid member (to optimize space usage). */ + RTASN1ALLOCATION Allocation; + /** Indicates which of the pointers are valid. */ + RTCRTAFTRUSTANCHORCHOICEVAL enmChoice; + /** Choice union. */ + union + { + /** Generic ASN.1 core pointer for the choice. */ + PRTASN1CORE pAsn1Core; + /** Choice 0: X509 certificate. */ + PRTCRX509CERTIFICATE pCertificate; + /** Choice 1: To-be-signed certificate part. This may differ from the + * TBSCertificate member of the original certificate. */ + struct + { + /** Explicit context tag. */ + RTASN1CONTEXTTAG1 CtxTag1; + /** Pointer to the TBS certificate structure. */ + RTCRX509TBSCERTIFICATE TbsCert; + } *pT1; + + /** Choice 2: To-be-signed certificate part. This may differ from the + * TBSCertificate member of the original certificate. */ + struct + { + /** Explicit context tag. */ + RTASN1CONTEXTTAG2 CtxTag2; + /** Pointer to the trust anchor infomration structure. */ + RTCRTAFTRUSTANCHORINFO TaInfo; + } *pT2; + } u; +} RTCRTAFTRUSTANCHORCHOICE; +/** Pointer to the IPRT representation of a RFC-5914 TrustAnchorChoice. */ +typedef RTCRTAFTRUSTANCHORCHOICE *PRTCRTAFTRUSTANCHORCHOICE; +/** Pointer to the const IPRT representation of a RFC-5914 TrustAnchorChoice. */ +typedef RTCRTAFTRUSTANCHORCHOICE const *PCRTCRTAFTRUSTANCHORCHOICE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTAFTRUSTANCHORCHOICE, RTDECL, RTCrTafTrustAnchorChoice, Dummy.Asn1Core); + +/* + * RFC-5914 TrustAnchorList (IPRT representation). + */ +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRTAFTRUSTANCHORLIST, RTCRTAFTRUSTANCHORCHOICE, RTDECL, RTCrTafTrustAnchorList); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_taf_h */ + diff --git a/include/iprt/crypto/tsp.h b/include/iprt/crypto/tsp.h new file mode 100644 index 00000000..8b421044 --- /dev/null +++ b/include/iprt/crypto/tsp.h @@ -0,0 +1,148 @@ +/** @file + * IPRT - Crypto - Time-Stamp Protocol (RFC-3161). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_tsp_h +#define IPRT_INCLUDED_crypto_tsp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cr_tap RTCrTap - Time-Stamp Protocol (RFC-3161) + * @ingroup grp_rt_crypto + * @{ + */ + + +/** + * RFC-3161 MessageImprint (IPRT representation). + */ +typedef struct RTCRTSPMESSAGEIMPRINT +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The digest algorithm used to produce HashedMessage. */ + RTCRX509ALGORITHMIDENTIFIER HashAlgorithm; + /** The digest of the message being timestamped. */ + RTASN1OCTETSTRING HashedMessage; +} RTCRTSPMESSAGEIMPRINT; +/** Pointer to the IPRT representation of a RFC-3161 MessageImprint. */ +typedef RTCRTSPMESSAGEIMPRINT *PRTCRTSPMESSAGEIMPRINT; +/** Pointer to the const IPRT representation of a RFC-3161 MessageImprint. */ +typedef RTCRTSPMESSAGEIMPRINT const *PCRTCRTSPMESSAGEIMPRINT; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTSPMESSAGEIMPRINT, RTDECL, RTCrTspMessageImprint, SeqCore.Asn1Core); + + +/** + * RFC-3161 Accuracy (IPRT representation). + */ +typedef struct RTCRTSPACCURACY +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The seconds accuracy. + * This will be larger than 0. If 1 inspect the Millis field. */ + RTASN1INTEGER Seconds; + /** The millisecond accuracy, optional, implicit tag 0. + * Range 1..999. If 1 inspect the Micros field. */ + RTASN1INTEGER Millis; + /** The microsecond accuracy, optional, implicit tag 1. + * Range 1..999. */ + RTASN1INTEGER Micros; +} RTCRTSPACCURACY; +/** Pointer to the IPRT representation of a RFC-3161 Accuracy. */ +typedef RTCRTSPACCURACY *PRTCRTSPACCURACY; +/** Pointer to the const IPRT representation of a RFC-3161 Accuracy. */ +typedef RTCRTSPACCURACY const *PCRTCRTSPACCURACY; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTSPACCURACY, RTDECL, RTCrTspAccuracy, SeqCore.Asn1Core); + + +/** + * RFC-3161 TSTInfo (IPRT representation). + */ +typedef struct RTCRTSPTSTINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The structure version number, current only 1 is valid. */ + RTASN1INTEGER Version; + /** Time authority policy. */ + RTASN1OBJID Policy; + /** The message imprint. */ + RTCRTSPMESSAGEIMPRINT MessageImprint; + /** Timestamp request serial number. */ + RTASN1INTEGER SerialNumber; + /** The timestamp. */ + RTASN1TIME GenTime; + /** The timestamp accuracy, optional. */ + RTCRTSPACCURACY Accuracy; + /** Ordering, whatever that means, defaults to FALSE. */ + RTASN1BOOLEAN Ordering; + /** Nonce, optional. */ + RTASN1INTEGER Nonce; + /** Timestamp authority name, explicit optional. + * (Should match a name in the certificate of the signature.) */ + struct + { + /** Context tag 0. */ + RTASN1CONTEXTTAG0 CtxTag0; + /** The TSA name. */ + RTCRX509GENERALNAME Tsa; + } T0; + /** Extensions, optional, implicit tag 1. */ + RTCRX509EXTENSION Extensions; +} RTCRTSPTSTINFO; +/** Pointer to the IPRT representation of a RFC-3161 TSTInfo. */ +typedef RTCRTSPTSTINFO *PRTCRTSPTSTINFO; +/** Pointer to the const IPRT representation of a RFC-3161 TSTInfo. */ +typedef RTCRTSPTSTINFO const *PCRTCRTSPTSTINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTSPTSTINFO, RTDECL, RTCrTspTstInfo, SeqCore.Asn1Core); + +/** The object identifier for RTCRTSPTSTINFO. + * Found in the ContentType field of PKCS \#7's ContentInfo structure and + * the equivalent CMS field. */ +#define RTCRTSPTSTINFO_OID "1.2.840.113549.1.9.16.1.4" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_tsp_h */ + diff --git a/include/iprt/crypto/x509.h b/include/iprt/crypto/x509.h new file mode 100644 index 00000000..41f5bcc0 --- /dev/null +++ b/include/iprt/crypto/x509.h @@ -0,0 +1,1180 @@ +/** @file + * IPRT - Crypto - X.509, Public Key and Privilege Management Infrastructure. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_x509_h +#define IPRT_INCLUDED_crypto_x509_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +struct RTCRPKCS7SETOFCERTS; + + +/** @defgroup grp_rt_crypto Crypto + * @ingroup grp_rt + * @{ + */ + +/** @defgroup grp_rt_crx509 RTCrX509 - Public Key and Privilege Management Infrastructure. + * @{ + */ + +/** + * X.509 algorithm identifier (IPRT representation). + */ +typedef struct RTCRX509ALGORITHMIDENTIFIER +{ + /** The sequence making up this algorithm identifier. */ + RTASN1SEQUENCECORE SeqCore; + /** The algorithm object ID. */ + RTASN1OBJID Algorithm; + /** Optional parameters specified by the algorithm. */ + RTASN1DYNTYPE Parameters; +} RTCRX509ALGORITHMIDENTIFIER; +/** Poitner to the IPRT representation of a X.509 algorithm identifier. */ +typedef RTCRX509ALGORITHMIDENTIFIER *PRTCRX509ALGORITHMIDENTIFIER; +/** Poitner to the const IPRT representation of a X.509 algorithm identifier. */ +typedef RTCRX509ALGORITHMIDENTIFIER const *PCRTCRX509ALGORITHMIDENTIFIER; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509ALGORITHMIDENTIFIER, RTDECL, RTCrX509AlgorithmIdentifier, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRX509ALGORITHMIDENTIFIERS, RTCRX509ALGORITHMIDENTIFIER, RTDECL, RTCrX509AlgorithmIdentifiers); + +/** + * Tries to convert an X.509 digest algorithm ID into a RTDIGESTTYPE value. + * + * @returns Valid RTDIGESTTYPE on success, RTDIGESTTYPE_INVALID on failure. + * @param pThis The IPRT representation of a X.509 algorithm + * identifier object. + */ +RTDECL(RTDIGESTTYPE) RTCrX509AlgorithmIdentifier_QueryDigestType(PCRTCRX509ALGORITHMIDENTIFIER pThis); + +/** + * Tries to figure the digest size of an X.509 digest algorithm ID. + * + * @returns The digest size in bytes, UINT32_MAX if unknown digest. + * @param pThis The IPRT representation of a X.509 algorithm + * identifier object. + */ +RTDECL(uint32_t) RTCrX509AlgorithmIdentifier_QueryDigestSize(PCRTCRX509ALGORITHMIDENTIFIER pThis); + +RTDECL(int) RTCrX509AlgorithmIdentifier_CompareWithString(PCRTCRX509ALGORITHMIDENTIFIER pThis, const char *pszObjId); + +/** + * Compares a digest with an encrypted digest algorithm, checking if they + * specify the same digest. + * + * @returns 0 if same digest, -1 if the digest is unknown, 1 if the encrypted + * digest does not match. + * @param pDigest The digest algorithm. + * @param pEncryptedDigest The encrypted digest algorithm. + */ +RTDECL(int) RTCrX509AlgorithmIdentifier_CompareDigestAndEncryptedDigest(PCRTCRX509ALGORITHMIDENTIFIER pDigest, + PCRTCRX509ALGORITHMIDENTIFIER pEncryptedDigest); +/** + * Compares a digest OID with an encrypted digest algorithm OID, checking if + * they specify the same digest. + * + * @returns 0 if same digest, -1 if the digest is unknown, 1 if the encrypted + * digest does not match. + * @param pszDigestOid The digest algorithm OID. + * @param pszEncryptedDigestOid The encrypted digest algorithm OID. + */ +RTDECL(int) RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid(const char *pszDigestOid, + const char *pszEncryptedDigestOid); + + +/** + * Combine the encryption algorithm with the digest algorithm. + * + * @returns OID of encrypted digest algorithm. + * @param pEncryption The encryption algorithm. Will work if this is + * the OID of an encrypted digest algorithm too, as + * long as it matches @a pDigest. + * @param pDigest The digest algorithm. Will work if this is the + * OID of an encrypted digest algorithm too, as + * long as it matches @a pEncryption. + */ +RTDECL(const char *) RTCrX509AlgorithmIdentifier_CombineEncryptionAndDigest(PCRTCRX509ALGORITHMIDENTIFIER pEncryption, + PCRTCRX509ALGORITHMIDENTIFIER pDigest); + +/** + * Combine the encryption algorithm OID with the digest algorithm OID. + * + * @returns OID of encrypted digest algorithm. + * @param pszEncryptionOid The encryption algorithm. Will work if this is + * the OID of an encrypted digest algorithm too, as + * long as it matches @a pszDigestOid. + * @param pszDigestOid The digest algorithm. Will work if this is the + * OID of an encrypted digest algorithm too, as + * long as it matches @a pszEncryptionOid. + */ +RTDECL(const char *) RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid(const char *pszEncryptionOid, + const char *pszDigestOid); + + +/** @name Typical Digest Algorithm OIDs. + * @{ */ +#define RTCRX509ALGORITHMIDENTIFIERID_MD2 "1.2.840.113549.2.2" +#define RTCRX509ALGORITHMIDENTIFIERID_MD4 "1.2.840.113549.2.4" +#define RTCRX509ALGORITHMIDENTIFIERID_MD5 "1.2.840.113549.2.5" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA1 "1.3.14.3.2.26" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA256 "2.16.840.1.101.3.4.2.1" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA384 "2.16.840.1.101.3.4.2.2" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512 "2.16.840.1.101.3.4.2.3" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA224 "2.16.840.1.101.3.4.2.4" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512T224 "2.16.840.1.101.3.4.2.5" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512T256 "2.16.840.1.101.3.4.2.6" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_224 "2.16.840.1.101.3.4.2.7" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_256 "2.16.840.1.101.3.4.2.8" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_384 "2.16.840.1.101.3.4.2.9" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_512 "2.16.840.1.101.3.4.2.10" +#define RTCRX509ALGORITHMIDENTIFIERID_WHIRLPOOL "1.0.10118.3.0.55" +/** @} */ + +/** @name Encrypted Digest Algorithm OIDs. + * @remarks The PKCS variants are the default ones, alternative OID are marked + * as such. + * @{ */ +#define RTCRX509ALGORITHMIDENTIFIERID_RSA "1.2.840.113549.1.1.1" +#define RTCRX509ALGORITHMIDENTIFIERID_MD2_WITH_RSA "1.2.840.113549.1.1.2" +#define RTCRX509ALGORITHMIDENTIFIERID_MD4_WITH_RSA "1.2.840.113549.1.1.3" +#define RTCRX509ALGORITHMIDENTIFIERID_MD5_WITH_RSA "1.2.840.113549.1.1.4" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA1_WITH_RSA "1.2.840.113549.1.1.5" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA256_WITH_RSA "1.2.840.113549.1.1.11" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA384_WITH_RSA "1.2.840.113549.1.1.12" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512_WITH_RSA "1.2.840.113549.1.1.13" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA224_WITH_RSA "1.2.840.113549.1.1.14" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512T224_WITH_RSA "1.2.840.113549.1.1.15" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512T256_WITH_RSA "1.2.840.113549.1.1.16" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_224_WITH_RSA "2.16.840.1.101.3.4.3.13" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_256_WITH_RSA "2.16.840.1.101.3.4.3.14" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_384_WITH_RSA "2.16.840.1.101.3.4.3.15" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_512_WITH_RSA "2.16.840.1.101.3.4.3.16" +/** @} */ + + + + +/** + * One X.509 AttributeTypeAndValue (IPRT representation). + */ +typedef struct RTCRX509ATTRIBUTETYPEANDVALUE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The attribute type (object ID). */ + RTASN1OBJID Type; + /** The attribute value (what it is is defined by Type). */ + RTASN1DYNTYPE Value; +} RTCRX509ATTRIBUTETYPEANDVALUE; +/** Pointer to a X.509 AttributeTypeAndValue (IPRT representation). */ +typedef RTCRX509ATTRIBUTETYPEANDVALUE *PRTCRX509ATTRIBUTETYPEANDVALUE; +/** Pointer to a const X.509 AttributeTypeAndValue (IPRT representation). */ +typedef RTCRX509ATTRIBUTETYPEANDVALUE const *PCRTCRX509ATTRIBUTETYPEANDVALUE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509ATTRIBUTETYPEANDVALUE, RTDECL, RTCrX509AttributeTypeAndValue, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRX509ATTRIBUTETYPEANDVALUES, RTCRX509ATTRIBUTETYPEANDVALUE, RTDECL, RTCrX509AttributeTypeAndValues); + +RTASN1TYPE_ALIAS(RTCRX509RELATIVEDISTINGUISHEDNAME, RTCRX509ATTRIBUTETYPEANDVALUES, RTCrX509RelativeDistinguishedName, RTCrX509AttributeTypeAndValues); + + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509NAME, RTCRX509RELATIVEDISTINGUISHEDNAME, RTDECL, RTCrX509Name); +RTDECL(int) RTCrX509Name_CheckSanity(PCRTCRX509NAME pName, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(bool) RTCrX509Name_MatchByRfc5280(PCRTCRX509NAME pLeft, PCRTCRX509NAME pRight); + +/** + * Name constraint matching (RFC-5280). + * + * @returns true on match, false on mismatch. + * @param pConstraint The constraint name. + * @param pName The name to match against the constraint. + * @sa RTCrX509GeneralName_ConstraintMatch, + * RTCrX509RelativeDistinguishedName_ConstraintMatch + */ +RTDECL(bool) RTCrX509Name_ConstraintMatch(PCRTCRX509NAME pConstraint, PCRTCRX509NAME pName); +RTDECL(int) RTCrX509Name_RecodeAsUtf8(PRTCRX509NAME pThis, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Matches the directory name against a comma separated list of the component + * strings (case sensitive). + * + * @returns true if match, false if mismatch. + * @param pThis The name object. + * @param pszString The string to match against. For example: + * "C=US, ST=California, L=Redwood Shores, O=Oracle Corporation" + * + * @remarks This is doing a straight compare, no extra effort is expended in + * dealing with different component order. If the component order + * differs, there won't be any match. + */ +RTDECL(bool) RTCrX509Name_MatchWithString(PCRTCRX509NAME pThis, const char *pszString); + +/** + * Formats the name as a command separated list of components with type + * prefixes. + * + * The output of this function is suitable for use with + * RTCrX509Name_MatchWithString. + * + * @returns IPRT status code. + * @param pThis The name object. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pcbActual Where to return the number of bytes required for the + * output, including the null terminator character. + * Optional. + */ +RTDECL(int) RTCrX509Name_FormatAsString(PCRTCRX509NAME pThis, char *pszBuf, size_t cbBuf, size_t *pcbActual); + + +/** + * Looks up the RDN ID and returns the short name for it, if found. + * + * @returns Short name (e.g. 'CN') or NULL. + * @param pRdnId The RDN ID to look up. + */ +RTDECL(const char *) RTCrX509Name_GetShortRdn(PCRTASN1OBJID pRdnId); + +/** + * One X.509 OtherName (IPRT representation). + */ +typedef struct RTCRX509OTHERNAME +{ + /** The sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The name type identifier. */ + RTASN1OBJID TypeId; + /** The name value (explicit tag 0). */ + RTASN1DYNTYPE Value; +} RTCRX509OTHERNAME; +/** Pointer to a X.509 OtherName (IPRT representation). */ +typedef RTCRX509OTHERNAME *PRTCRX509OTHERNAME; +/** Pointer to a const X.509 OtherName (IPRT representation). */ +typedef RTCRX509OTHERNAME const *PCRTCRX509OTHERNAME; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509OTHERNAME, RTDECL, RTCrX509OtherName, SeqCore.Asn1Core); + + +typedef enum RTCRX509GENERALNAMECHOICE +{ + RTCRX509GENERALNAMECHOICE_INVALID = 0, + RTCRX509GENERALNAMECHOICE_OTHER_NAME, + RTCRX509GENERALNAMECHOICE_RFC822_NAME, + RTCRX509GENERALNAMECHOICE_DNS_NAME, + RTCRX509GENERALNAMECHOICE_X400_ADDRESS, + RTCRX509GENERALNAMECHOICE_DIRECTORY_NAME, + RTCRX509GENERALNAMECHOICE_EDI_PARTY_NAME, + RTCRX509GENERALNAMECHOICE_URI, + RTCRX509GENERALNAMECHOICE_IP_ADDRESS, + RTCRX509GENERALNAMECHOICE_REGISTERED_ID, + RTCRX509GENERALNAMECHOICE_END, + RTCRX509GENERALNAMECHOICE_32BIT_HACK = 0x7fffffff +} RTCRX509GENERALNAMECHOICE; + +/** + * One X.509 GeneralName (IPRT representation). + * + * This is represented as a union. Use the RTCRX509GENERALNAME_IS_XXX predicate + * macros to figure out which member is valid (Asn1Core is always valid). + */ +typedef struct RTCRX509GENERALNAME +{ + /** Dummy ASN.1 record, not encoded. */ + RTASN1DUMMY Dummy; + /** The value allocation. */ + RTASN1ALLOCATION Allocation; + /** The choice of value. */ + RTCRX509GENERALNAMECHOICE enmChoice; + /** The value union. */ + union + { + /** Tag 0: Other Name. */ + PRTCRX509OTHERNAME pT0_OtherName; + /** Tag 1: RFC-822 Name. */ + PRTASN1STRING pT1_Rfc822; + /** Tag 2: DNS name. */ + PRTASN1STRING pT2_DnsName; + /** Tag 3: X.400 Address. */ + struct + { + /** Context tag 3. */ + RTASN1CONTEXTTAG3 CtxTag3; + /** Later. */ + RTASN1DYNTYPE X400Address; + } *pT3; + /** Tag 4: Directory Name. */ + struct + { + /** Context tag 4. */ + RTASN1CONTEXTTAG4 CtxTag4; + /** Directory name. */ + RTCRX509NAME DirectoryName; + } *pT4; + /** Tag 5: EDI Party Name. */ + struct + { + /** Context tag 5. */ + RTASN1CONTEXTTAG5 CtxTag5; + /** Later. */ + RTASN1DYNTYPE EdiPartyName; + } *pT5; + /** Tag 6: URI. */ + PRTASN1STRING pT6_Uri; + /** Tag 7: IP address. Either 4/8 (IPv4) or 16/32 (IPv16) octets long. */ + PRTASN1OCTETSTRING pT7_IpAddress; + /** Tag 8: Registered ID. */ + PRTASN1OBJID pT8_RegisteredId; + } u; +} RTCRX509GENERALNAME; +/** Pointer to the IPRT representation of an X.509 general name. */ +typedef RTCRX509GENERALNAME *PRTCRX509GENERALNAME; +/** Pointer to the const IPRT representation of an X.509 general name. */ +typedef RTCRX509GENERALNAME const *PCRTCRX509GENERALNAME; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509GENERALNAME, RTDECL, RTCrX509GeneralName, Dummy.Asn1Core); + +/** @name RTCRX509GENERALNAME tag predicates. + * @{ */ +#define RTCRX509GENERALNAME_IS_OTHER_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_OTHER_NAME) +#define RTCRX509GENERALNAME_IS_RFC822_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_RFC822_NAME) +#define RTCRX509GENERALNAME_IS_DNS_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_DNS_NAME) +#define RTCRX509GENERALNAME_IS_X400_ADDRESS(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_X400_ADDRESS) +#define RTCRX509GENERALNAME_IS_DIRECTORY_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_DIRECTORY_NAME) +#define RTCRX509GENERALNAME_IS_EDI_PARTY_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_EDI_PARTY_NAME) +#define RTCRX509GENERALNAME_IS_URI(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_URI) +#define RTCRX509GENERALNAME_IS_IP_ADDRESS(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_IP_ADDRESS) +#define RTCRX509GENERALNAME_IS_REGISTERED_ID(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_REGISTERED_ID) +/** @} */ + + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509GENERALNAMES, RTCRX509GENERALNAME, RTDECL, RTCrX509GeneralNames); +RTDECL(bool) RTCrX509GeneralName_ConstraintMatch(PCRTCRX509GENERALNAME pConstraint, PCRTCRX509GENERALNAME pName); + + +/** + * X.509 Validity (IPRT representation). + */ +typedef struct RTCRX509VALIDITY +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Effective starting. */ + RTASN1TIME NotBefore; + /** Expires after. */ + RTASN1TIME NotAfter; +} RTCRX509VALIDITY; +/** Pointer to the IPRT representation of an X.509 validity sequence. */ +typedef RTCRX509VALIDITY *PRTCRX509VALIDITY; +/** Pointer ot the const IPRT representation of an X.509 validity sequence. */ +typedef RTCRX509VALIDITY const *PCRTCRX509VALIDITY; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509VALIDITY, RTDECL, RTCrX509Validity, SeqCore.Asn1Core); + +RTDECL(bool) RTCrX509Validity_IsValidAtTimeSpec(PCRTCRX509VALIDITY pThis, PCRTTIMESPEC pTimeSpec); + + +#if 0 +/** + * X.509 UniqueIdentifier (IPRT representation). + */ +typedef struct RTCRX509UNIQUEIDENTIFIER +{ + /** Representation is a bit string. */ + RTASN1BITSTRING BitString; +} RTCRX509UNIQUEIDENTIFIER; +/** Pointer to the IPRT representation of an X.509 unique identifier. */ +typedef RTCRX509UNIQUEIDENTIFIER *PRTCRX509UNIQUEIDENTIFIER; +/** Pointer to the const IPRT representation of an X.509 unique identifier. */ +typedef RTCRX509UNIQUEIDENTIFIER const *PCRTCRX509UNIQUEIDENTIFIER; +RTASN1TYPE_STANDARD_PROTOTYPES_NO_GET_CORE(RTCRX509UNIQUEIDENTIFIER, RTDECL, RTCrX509UniqueIdentifier); +#endif +RTASN1TYPE_ALIAS(RTCRX509UNIQUEIDENTIFIER, RTASN1BITSTRING, RTCrX509UniqueIdentifier, RTAsn1BitString); + + +/** + * X.509 SubjectPublicKeyInfo (IPRT representation). + */ +typedef struct RTCRX509SUBJECTPUBLICKEYINFO +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** The algorithm used with the public key. */ + RTCRX509ALGORITHMIDENTIFIER Algorithm; + /** A bit string containing the public key. + * + * For algorithms like rsaEncryption this is generally a sequence of two + * integers, where the first one has lots of bits, and the second one being a + * modulous value. These are details specific to the algorithm and not relevant + * when validating the certificate chain. */ + RTASN1BITSTRING SubjectPublicKey; +} RTCRX509SUBJECTPUBLICKEYINFO; +/** Pointer to the IPRT representation of an X.509 subject public key info + * sequence. */ +typedef RTCRX509SUBJECTPUBLICKEYINFO *PRTCRX509SUBJECTPUBLICKEYINFO; +/** Pointer to the const IPRT representation of an X.509 subject public key info + * sequence. */ +typedef RTCRX509SUBJECTPUBLICKEYINFO const *PCRTCRX509SUBJECTPUBLICKEYINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509SUBJECTPUBLICKEYINFO, RTDECL, RTCrX509SubjectPublicKeyInfo, SeqCore.Asn1Core); + + +/** + * One X.509 AuthorityKeyIdentifier (IPRT representation). + */ +typedef struct RTCRX509AUTHORITYKEYIDENTIFIER +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Tag 0, optional, implicit: Key identifier. */ + RTASN1OCTETSTRING KeyIdentifier; + /** Tag 1, optional, implicit: Issuer name. */ + RTCRX509GENERALNAMES AuthorityCertIssuer; + /** Tag 2, optional, implicit: Serial number of issuer. */ + RTASN1INTEGER AuthorityCertSerialNumber; +} RTCRX509AUTHORITYKEYIDENTIFIER; +/** Pointer to the IPRT representation of an X.509 AuthorityKeyIdentifier + * sequence. */ +typedef RTCRX509AUTHORITYKEYIDENTIFIER *PRTCRX509AUTHORITYKEYIDENTIFIER; +/** Pointer to the const IPRT representation of an X.509 AuthorityKeyIdentifier + * sequence. */ +typedef RTCRX509AUTHORITYKEYIDENTIFIER const *PCRTCRX509AUTHORITYKEYIDENTIFIER; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509AUTHORITYKEYIDENTIFIER, RTDECL, RTCrX509AuthorityKeyIdentifier, SeqCore.Asn1Core); + + +/** + * One X.509 OldAuthorityKeyIdentifier (IPRT representation). + */ +typedef struct RTCRX509OLDAUTHORITYKEYIDENTIFIER +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Tag 0, optional, implicit: Key identifier. */ + RTASN1OCTETSTRING KeyIdentifier; + struct + { + RTASN1CONTEXTTAG1 CtxTag1; + /** Tag 1, optional, implicit: Issuer name. */ + RTCRX509NAME AuthorityCertIssuer; + } T1; + /** Tag 2, optional, implicit: Serial number of issuer. */ + RTASN1INTEGER AuthorityCertSerialNumber; +} RTCRX509OLDAUTHORITYKEYIDENTIFIER; +/** Pointer to the IPRT representation of an X.509 AuthorityKeyIdentifier + * sequence. */ +typedef RTCRX509OLDAUTHORITYKEYIDENTIFIER *PRTCRX509OLDAUTHORITYKEYIDENTIFIER; +/** Pointer to the const IPRT representation of an X.509 AuthorityKeyIdentifier + * sequence. */ +typedef RTCRX509OLDAUTHORITYKEYIDENTIFIER const *PCRTCRX509OLDAUTHORITYKEYIDENTIFIER; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509OLDAUTHORITYKEYIDENTIFIER, RTDECL, RTCrX509OldAuthorityKeyIdentifier, SeqCore.Asn1Core); + + +/** + * One X.509 PolicyQualifierInfo (IPRT representation). + */ +typedef struct RTCRX509POLICYQUALIFIERINFO +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** The policy object ID. */ + RTASN1OBJID PolicyQualifierId; + /** Anything defined by the policy qualifier id. */ + RTASN1DYNTYPE Qualifier; +} RTCRX509POLICYQUALIFIERINFO; +/** Pointer to the IPRT representation of an X.509 PolicyQualifierInfo + * sequence. */ +typedef RTCRX509POLICYQUALIFIERINFO *PRTCRX509POLICYQUALIFIERINFO; +/** Pointer to the const IPRT representation of an X.509 PolicyQualifierInfo + * sequence. */ +typedef RTCRX509POLICYQUALIFIERINFO const *PCRTCRX509POLICYQUALIFIERINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509POLICYQUALIFIERINFO, RTDECL, RTCrX509PolicyQualifierInfo, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509POLICYQUALIFIERINFOS, RTCRX509POLICYQUALIFIERINFO, RTDECL, RTCrX509PolicyQualifierInfos); + + +/** + * One X.509 PolicyInformation (IPRT representation). + */ +typedef struct RTCRX509POLICYINFORMATION +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** The policy object ID. */ + RTASN1OBJID PolicyIdentifier; + /** Optional sequence of policy qualifiers. */ + RTCRX509POLICYQUALIFIERINFOS PolicyQualifiers; +} RTCRX509POLICYINFORMATION; +/** Pointer to the IPRT representation of an X.509 PolicyInformation + * sequence. */ +typedef RTCRX509POLICYINFORMATION *PRTCRX509POLICYINFORMATION; +/** Pointer to the const IPRT representation of an X.509 PolicyInformation + * sequence. */ +typedef RTCRX509POLICYINFORMATION const *PCRTCRX509POLICYINFORMATION; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509POLICYINFORMATION, RTDECL, RTCrX509PolicyInformation, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509CERTIFICATEPOLICIES, RTCRX509POLICYINFORMATION, RTDECL, RTCrX509CertificatePolicies); + +/** Sepcial policy object ID that matches any policy. */ +#define RTCRX509_ID_CE_CP_ANY_POLICY_OID "2.5.29.32.0" + + +/** + * One X.509 PolicyMapping (IPRT representation). + */ +typedef struct RTCRX509POLICYMAPPING +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Issuer policy ID. */ + RTASN1OBJID IssuerDomainPolicy; + /** Subject policy ID. */ + RTASN1OBJID SubjectDomainPolicy; +} RTCRX509POLICYMAPPING; +/** Pointer to the IPRT representation of a sequence of X.509 PolicyMapping. */ +typedef RTCRX509POLICYMAPPING *PRTCRX509POLICYMAPPING; +/** Pointer to the const IPRT representation of a sequence of X.509 + * PolicyMapping. */ +typedef RTCRX509POLICYMAPPING const *PCRTCRX509POLICYMAPPING; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509POLICYMAPPING, RTDECL, RTCrX509PolicyMapping, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509POLICYMAPPINGS, RTCRX509POLICYMAPPING, RTDECL, RTCrX509PolicyMappings); + + +/** + * X.509 BasicConstraints (IPRT representation). + */ +typedef struct RTCRX509BASICCONSTRAINTS +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Is this ia certficiate authority? Default to false. */ + RTASN1BOOLEAN CA; + /** Path length constraint. */ + RTASN1INTEGER PathLenConstraint; +} RTCRX509BASICCONSTRAINTS; +/** Pointer to the IPRT representation of a sequence of X.509 + * BasicConstraints. */ +typedef RTCRX509BASICCONSTRAINTS *PRTCRX509BASICCONSTRAINTS; +/** Pointer to the const IPRT representation of a sequence of X.509 + * BasicConstraints. */ +typedef RTCRX509BASICCONSTRAINTS const *PCRTCRX509BASICCONSTRAINTS; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509BASICCONSTRAINTS, RTDECL, RTCrX509BasicConstraints, SeqCore.Asn1Core); + + +/** + * X.509 GeneralSubtree (IPRT representation). + */ +typedef struct RTCRX509GENERALSUBTREE +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Base name. */ + RTCRX509GENERALNAME Base; + /** Tag 0, optional: Minimum, default 0. Fixed at 0 by RFC-5280. */ + RTASN1INTEGER Minimum; + /** Tag 1, optional: Maximum. Fixed as not-present by RFC-5280. */ + RTASN1INTEGER Maximum; +} RTCRX509GENERALSUBTREE; +/** Pointer to the IPRT representation of a sequence of X.509 GeneralSubtree. */ +typedef RTCRX509GENERALSUBTREE *PRTCRX509GENERALSUBTREE; +/** Pointer to the const IPRT representation of a sequence of X.509 + * GeneralSubtree. */ +typedef RTCRX509GENERALSUBTREE const *PCRTCRX509GENERALSUBTREE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509GENERALSUBTREE, RTDECL, RTCrX509GeneralSubtree, SeqCore.Asn1Core); + +RTDECL(bool) RTCrX509GeneralSubtree_ConstraintMatch(PCRTCRX509GENERALSUBTREE pConstraint, PCRTCRX509GENERALSUBTREE pName); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509GENERALSUBTREES, RTCRX509GENERALSUBTREE, RTDECL, RTCrX509GeneralSubtrees); + + +/** + * X.509 NameConstraints (IPRT representation). + */ +typedef struct RTCRX509NAMECONSTRAINTS +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Tag 0, optional: Permitted subtrees. */ + struct + { + /** Context tag. */ + RTASN1CONTEXTTAG0 CtxTag0; + /** The permitted subtrees. */ + RTCRX509GENERALSUBTREES PermittedSubtrees; + } T0; + /** Tag 1, optional: Excluded subtrees. */ + struct + { + /** Context tag. */ + RTASN1CONTEXTTAG1 CtxTag1; + /** The excluded subtrees. */ + RTCRX509GENERALSUBTREES ExcludedSubtrees; + } T1; +} RTCRX509NAMECONSTRAINTS; +/** Pointer to the IPRT representation of a sequence of X.509 + * NameConstraints. */ +typedef RTCRX509NAMECONSTRAINTS *PRTCRX509NAMECONSTRAINTS; +/** Pointer to the const IPRT representation of a sequence of X.509 + * NameConstraints. */ +typedef RTCRX509NAMECONSTRAINTS const *PCRTCRX509NAMECONSTRAINTS; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509NAMECONSTRAINTS, RTDECL, RTCrX509NameConstraints, SeqCore.Asn1Core); + + +/** + * X.509 PolicyConstraints (IPRT representation). + */ +typedef struct RTCRX509POLICYCONSTRAINTS +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Tag 0, optional: Certificates before an explicit policy is required. */ + RTASN1INTEGER RequireExplicitPolicy; + /** Tag 1, optional: Certificates before policy mapping is inhibited. */ + RTASN1INTEGER InhibitPolicyMapping; +} RTCRX509POLICYCONSTRAINTS; +/** Pointer to the IPRT representation of a sequence of X.509 + * PolicyConstraints. */ +typedef RTCRX509POLICYCONSTRAINTS *PRTCRX509POLICYCONSTRAINTS; +/** Pointer to the const IPRT representation of a sequence of X.509 + * PolicyConstraints. */ +typedef RTCRX509POLICYCONSTRAINTS const *PCRTCRX509POLICYCONSTRAINTS; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509POLICYCONSTRAINTS, RTDECL, RTCrX509PolicyConstraints, SeqCore.Asn1Core); + + +/** + * Indicates what an X.509 extension value encapsulates. + */ +typedef enum RTCRX509EXTENSIONVALUE +{ + RTCRX509EXTENSIONVALUE_INVALID = 0, + /** Unknown, no decoding available just the octet string. */ + RTCRX509EXTENSIONVALUE_UNKNOWN, + /** Unencapsulated (i.e. octet string). */ + RTCRX509EXTENSIONVALUE_NOT_ENCAPSULATED, + + /** Bit string (RTASN1BITSTRING). */ + RTCRX509EXTENSIONVALUE_BIT_STRING, + /** Octet string (RTASN1OCTETSTRING). */ + RTCRX509EXTENSIONVALUE_OCTET_STRING, + /** Integer string (RTASN1INTEGER). */ + RTCRX509EXTENSIONVALUE_INTEGER, + /** Sequence of object identifiers (RTASN1SEQOFOBJIDS). */ + RTCRX509EXTENSIONVALUE_SEQ_OF_OBJ_IDS, + + /** Authority key identifier (RTCRX509AUTHORITYKEYIDENTIFIER). */ + RTCRX509EXTENSIONVALUE_AUTHORITY_KEY_IDENTIFIER, + /** Old Authority key identifier (RTCRX509OLDAUTHORITYKEYIDENTIFIER). */ + RTCRX509EXTENSIONVALUE_OLD_AUTHORITY_KEY_IDENTIFIER, + /** Certificate policies (RTCRX509CERTIFICATEPOLICIES). */ + RTCRX509EXTENSIONVALUE_CERTIFICATE_POLICIES, + /** Sequence of policy mappings (RTCRX509POLICYMAPPINGS). */ + RTCRX509EXTENSIONVALUE_POLICY_MAPPINGS, + /** Basic constraints (RTCRX509BASICCONSTRAINTS). */ + RTCRX509EXTENSIONVALUE_BASIC_CONSTRAINTS, + /** Name constraints (RTCRX509NAMECONSTRAINTS). */ + RTCRX509EXTENSIONVALUE_NAME_CONSTRAINTS, + /** Policy constraints (RTCRX509POLICYCONSTRAINTS). */ + RTCRX509EXTENSIONVALUE_POLICY_CONSTRAINTS, + /** Sequence of general names (RTCRX509GENERALNAMES). */ + RTCRX509EXTENSIONVALUE_GENERAL_NAMES, + + /** Blow the type up to 32-bits. */ + RTCRX509EXTENSIONVALUE_32BIT_HACK = 0x7fffffff +} RTCRX509EXTENSIONVALUE; + +/** + * One X.509 Extension (IPRT representation). + */ +typedef struct RTCRX509EXTENSION +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Extension ID. */ + RTASN1OBJID ExtnId; + /** Whether this is critical (default @c false). */ + RTASN1BOOLEAN Critical; + /** Indicates what ExtnValue.pEncapsulated points at. */ + RTCRX509EXTENSIONVALUE enmValue; + /** The value. + * Contains extension specific data that we don't yet parse. */ + RTASN1OCTETSTRING ExtnValue; +} RTCRX509EXTENSION; +/** Pointer to the IPRT representation of one X.509 extensions. */ +typedef RTCRX509EXTENSION *PRTCRX509EXTENSION; +/** Pointer to the const IPRT representation of one X.509 extension. */ +typedef RTCRX509EXTENSION const *PCRTCRX509EXTENSION; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509EXTENSION, RTDECL, RTCrX509Extension, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509EXTENSIONS, RTCRX509EXTENSION, RTDECL, RTCrX509Extensions); + +RTDECL(int) RTCrX509Extension_ExtnValue_DecodeAsn1(PRTASN1CURSOR pCursor, uint32_t fFlags, + PRTCRX509EXTENSION pThis, const char *pszErrorTag); + + +/** + * X.509 To-be-signed certificate information (IPRT representation). + */ +typedef struct RTCRX509TBSCERTIFICATE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Structure version. */ + struct + { + /** Context tag with value 0. */ + RTASN1CONTEXTTAG0 CtxTag0; + /** The actual value (RTCRX509TBSCERTIFICATE_V1, ...). */ + RTASN1INTEGER Version; + } T0; + /** The serial number of the certificate. */ + RTASN1INTEGER SerialNumber; + /** The signature algorithm. */ + RTCRX509ALGORITHMIDENTIFIER Signature; + /** The issuer name. */ + RTCRX509NAME Issuer; + /** The certificate validity period. */ + RTCRX509VALIDITY Validity; + /** The subject name. */ + RTCRX509NAME Subject; + /** The public key for this certificate. */ + RTCRX509SUBJECTPUBLICKEYINFO SubjectPublicKeyInfo; + /** Issuer unique identifier (optional, version >= v2). */ + struct + { + /** Context tag with value 1. */ + RTASN1CONTEXTTAG1 CtxTag1; + /** The unique identifier value. */ + RTCRX509UNIQUEIDENTIFIER IssuerUniqueId; + } T1; + /** Subject unique identifier (optional, version >= v2). */ + struct + { + /** Context tag with value 2. */ + RTASN1CONTEXTTAG2 CtxTag2; + /** The unique identifier value. */ + RTCRX509UNIQUEIDENTIFIER SubjectUniqueId; + } T2; + /** Extensions (optional, version >= v3). */ + struct + { + /** Context tag with value 3. */ + RTASN1CONTEXTTAG3 CtxTag3; + /** The unique identifier value. */ + RTCRX509EXTENSIONS Extensions; + /** Extensions summary flags (RTCRX509TBSCERTIFICATE_F_PRESENT_XXX). */ + uint32_t fFlags; + /** Key usage flags (RTCRX509CERT_KEY_USAGE_F_XXX). */ + uint32_t fKeyUsage; + /** Extended key usage flags (RTCRX509CERT_EKU_F_XXX). */ + uint64_t fExtKeyUsage; + + /** Pointer to the authority key ID extension if present. */ + PCRTCRX509AUTHORITYKEYIDENTIFIER pAuthorityKeyIdentifier; + /** Pointer to the OLD authority key ID extension if present. */ + PCRTCRX509OLDAUTHORITYKEYIDENTIFIER pOldAuthorityKeyIdentifier; + /** Pointer to the subject key ID extension if present. */ + PCRTASN1OCTETSTRING pSubjectKeyIdentifier; + /** Pointer to the alternative subject name extension if present. */ + PCRTCRX509GENERALNAMES pAltSubjectName; + /** Pointer to the alternative issuer name extension if present. */ + PCRTCRX509GENERALNAMES pAltIssuerName; + /** Pointer to the certificate policies extension if present. */ + PCRTCRX509CERTIFICATEPOLICIES pCertificatePolicies; + /** Pointer to the policy mappings extension if present. */ + PCRTCRX509POLICYMAPPINGS pPolicyMappings; + /** Pointer to the basic constraints extension if present. */ + PCRTCRX509BASICCONSTRAINTS pBasicConstraints; + /** Pointer to the name constraints extension if present. */ + PCRTCRX509NAMECONSTRAINTS pNameConstraints; + /** Pointer to the policy constraints extension if present. */ + PCRTCRX509POLICYCONSTRAINTS pPolicyConstraints; + /** Pointer to the inhibit anyPolicy extension if present. */ + PCRTASN1INTEGER pInhibitAnyPolicy; + } T3; +} RTCRX509TBSCERTIFICATE; +/** Pointer to the IPRT representation of a X.509 TBSCertificate. */ +typedef RTCRX509TBSCERTIFICATE *PRTCRX509TBSCERTIFICATE; +/** Pointer to the const IPRT representation of a X.509 TBSCertificate. */ +typedef RTCRX509TBSCERTIFICATE const *PCRTCRX509TBSCERTIFICATE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509TBSCERTIFICATE, RTDECL, RTCrX509TbsCertificate, SeqCore.Asn1Core); + +/** @name RTCRX509TBSCERTIFICATE::T0.Version values. + * @{ */ +#define RTCRX509TBSCERTIFICATE_V1 0 +#define RTCRX509TBSCERTIFICATE_V2 1 +#define RTCRX509TBSCERTIFICATE_V3 2 +/** @} */ + +/** @name RTCRX509TBSCERTIFICATE::T3.fFlags values. + * @{ */ +#define RTCRX509TBSCERTIFICATE_F_PRESENT_KEY_USAGE RT_BIT_32(0) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_EXT_KEY_USAGE RT_BIT_32(1) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_SUBJECT_KEY_IDENTIFIER RT_BIT_32(2) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_SUBJECT_ALT_NAME RT_BIT_32(3) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_ISSUER_ALT_NAME RT_BIT_32(4) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_CERTIFICATE_POLICIES RT_BIT_32(5) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_POLICY_MAPPINGS RT_BIT_32(6) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_BASIC_CONSTRAINTS RT_BIT_32(7) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_NAME_CONSTRAINTS RT_BIT_32(8) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_POLICY_CONSTRAINTS RT_BIT_32(9) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_AUTHORITY_KEY_IDENTIFIER RT_BIT_32(10) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_OLD_AUTHORITY_KEY_IDENTIFIER RT_BIT_32(11) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_ACCEPTABLE_CERT_POLICIES RT_BIT_32(12) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_INHIBIT_ANY_POLICY RT_BIT_32(13) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_OTHER RT_BIT_32(22) /**< Other unknown extension present. */ +#define RTCRX509TBSCERTIFICATE_F_PRESENT_NONE RT_BIT_32(23) /**< No extensions present. */ +/** @} */ + +/** @name X.509 Key Usage flags. (RFC-5280 section 4.2.1.3.) + * @{ */ +#define RTCRX509CERT_KEY_USAGE_F_DIGITAL_SIGNATURE_BIT 0 +#define RTCRX509CERT_KEY_USAGE_F_DIGITAL_SIGNATURE RT_BIT_32(0) +#define RTCRX509CERT_KEY_USAGE_F_CONTENT_COMMITTMENT_BIT 1 +#define RTCRX509CERT_KEY_USAGE_F_CONTENT_COMMITTMENT RT_BIT_32(1) +#define RTCRX509CERT_KEY_USAGE_F_KEY_ENCIPHERMENT_BIT 2 +#define RTCRX509CERT_KEY_USAGE_F_KEY_ENCIPHERMENT RT_BIT_32(2) +#define RTCRX509CERT_KEY_USAGE_F_DATA_ENCIPHERMENT_BIT 3 +#define RTCRX509CERT_KEY_USAGE_F_DATA_ENCIPHERMENT RT_BIT_32(3) +#define RTCRX509CERT_KEY_USAGE_F_KEY_AGREEMENT_BIT 4 +#define RTCRX509CERT_KEY_USAGE_F_KEY_AGREEMENT RT_BIT_32(4) +#define RTCRX509CERT_KEY_USAGE_F_KEY_CERT_SIGN_BIT 5 +#define RTCRX509CERT_KEY_USAGE_F_KEY_CERT_SIGN RT_BIT_32(5) +#define RTCRX509CERT_KEY_USAGE_F_CRL_SIGN_BIT 6 +#define RTCRX509CERT_KEY_USAGE_F_CRL_SIGN RT_BIT_32(6) +#define RTCRX509CERT_KEY_USAGE_F_ENCIPHERMENT_ONLY_BIT 7 +#define RTCRX509CERT_KEY_USAGE_F_ENCIPHERMENT_ONLY RT_BIT_32(7) +#define RTCRX509CERT_KEY_USAGE_F_DECIPHERMENT_ONLY_BIT 8 +#define RTCRX509CERT_KEY_USAGE_F_DECIPHERMENT_ONLY RT_BIT_32(8) +/** @} */ + +/** @name X.509 Extended Key Usage flags. (RFC-5280 section 4.2.1.12, ++.) + * @remarks Needless to say, these flags doesn't cover all possible extended key + * usages, because there is a potential unlimited number of them. Only + * ones relevant to IPRT and it's users are covered. + * @{ */ +#define RTCRX509CERT_EKU_F_ANY RT_BIT_64(0) +#define RTCRX509CERT_EKU_F_SERVER_AUTH RT_BIT_64(1) +#define RTCRX509CERT_EKU_F_CLIENT_AUTH RT_BIT_64(2) +#define RTCRX509CERT_EKU_F_CODE_SIGNING RT_BIT_64(3) +#define RTCRX509CERT_EKU_F_EMAIL_PROTECTION RT_BIT_64(4) +#define RTCRX509CERT_EKU_F_IPSEC_END_SYSTEM RT_BIT_64(5) +#define RTCRX509CERT_EKU_F_IPSEC_TUNNEL RT_BIT_64(6) +#define RTCRX509CERT_EKU_F_IPSEC_USER RT_BIT_64(7) +#define RTCRX509CERT_EKU_F_TIMESTAMPING RT_BIT_64(8) +#define RTCRX509CERT_EKU_F_OCSP_SIGNING RT_BIT_64(9) +#define RTCRX509CERT_EKU_F_DVCS RT_BIT_64(10) +#define RTCRX509CERT_EKU_F_SBGP_CERT_AA_SERVICE_AUTH RT_BIT_64(11) +#define RTCRX509CERT_EKU_F_EAP_OVER_PPP RT_BIT_64(12) +#define RTCRX509CERT_EKU_F_EAP_OVER_LAN RT_BIT_64(13) +#define RTCRX509CERT_EKU_F_OTHER RT_BIT_64(16) /**< Other unknown extended key usage present. */ +#define RTCRX509CERT_EKU_F_APPLE_CODE_SIGNING RT_BIT_64(24) +#define RTCRX509CERT_EKU_F_APPLE_CODE_SIGNING_DEVELOPMENT RT_BIT_64(25) +#define RTCRX509CERT_EKU_F_APPLE_SOFTWARE_UPDATE_SIGNING RT_BIT_64(26) +#define RTCRX509CERT_EKU_F_APPLE_CODE_SIGNING_THIRD_PARTY RT_BIT_64(27) +#define RTCRX509CERT_EKU_F_APPLE_RESOURCE_SIGNING RT_BIT_64(28) +#define RTCRX509CERT_EKU_F_APPLE_SYSTEM_IDENTITY RT_BIT_64(29) +#define RTCRX509CERT_EKU_F_MS_TIMESTAMP_SIGNING RT_BIT_64(32) +#define RTCRX509CERT_EKU_F_MS_NT5_CRYPTO RT_BIT_64(33) +#define RTCRX509CERT_EKU_F_MS_OEM_WHQL_CRYPTO RT_BIT_64(34) +#define RTCRX509CERT_EKU_F_MS_EMBEDDED_NT_CRYPTO RT_BIT_64(35) +#define RTCRX509CERT_EKU_F_MS_KERNEL_MODE_CODE_SIGNING RT_BIT_64(36) +#define RTCRX509CERT_EKU_F_MS_LIFETIME_SIGNING RT_BIT_64(37) +#define RTCRX509CERT_EKU_F_MS_DRM RT_BIT_64(38) +#define RTCRX509CERT_EKU_F_MS_DRM_INDIVIDUALIZATION RT_BIT_64(39) +#define RTCRX509CERT_EKU_F_MS_WHQL_CRYPTO RT_BIT_64(40) +#define RTCRX509CERT_EKU_F_MS_ATTEST_WHQL_CRYPTO RT_BIT_64(41) +/** @} */ + +/** @name Key purpose OIDs (extKeyUsage) + * @{ */ +#define RTCRX509_ANY_EXTENDED_KEY_USAGE_OID "2.5.29.37.0" +#define RTCRX509_ID_KP_OID "1.3.6.1.5.5.7.3" +#define RTCRX509_ID_KP_SERVER_AUTH_OID "1.3.6.1.5.5.7.3.1" +#define RTCRX509_ID_KP_CLIENT_AUTH_OID "1.3.6.1.5.5.7.3.2" +#define RTCRX509_ID_KP_CODE_SIGNING_OID "1.3.6.1.5.5.7.3.3" +#define RTCRX509_ID_KP_EMAIL_PROTECTION_OID "1.3.6.1.5.5.7.3.4" +#define RTCRX509_ID_KP_IPSEC_END_SYSTEM_OID "1.3.6.1.5.5.7.3.5" +#define RTCRX509_ID_KP_IPSEC_TUNNEL_OID "1.3.6.1.5.5.7.3.6" +#define RTCRX509_ID_KP_IPSEC_USER_OID "1.3.6.1.5.5.7.3.7" +#define RTCRX509_ID_KP_TIMESTAMPING_OID "1.3.6.1.5.5.7.3.8" +#define RTCRX509_ID_KP_OCSP_SIGNING_OID "1.3.6.1.5.5.7.3.9" +#define RTCRX509_ID_KP_DVCS_OID "1.3.6.1.5.5.7.3.10" +#define RTCRX509_ID_KP_SBGP_CERT_AA_SERVICE_AUTH_OID "1.3.6.1.5.5.7.3.11" +#define RTCRX509_ID_KP_EAP_OVER_PPP_OID "1.3.6.1.5.5.7.3.13" +#define RTCRX509_ID_KP_EAP_OVER_LAN_OID "1.3.6.1.5.5.7.3.14" +/** @} */ + +/** @name Microsoft extended key usage OIDs + * @{ */ +#define RTCRX509_MS_EKU_CERT_TRUST_LIST_SIGNING_OID "1.3.6.1.4.1.311.10.3.1" +#define RTCRX509_MS_EKU_TIMESTAMP_SIGNING_OID "1.3.6.1.4.1.311.10.3.2" +#define RTCRX509_MS_EKU_SERVER_GATED_CRYPTO_OID "1.3.6.1.4.1.311.10.3.3" +#define RTCRX509_MS_EKU_SGC_SERIALIZED_OID "1.3.6.1.4.1.311.10.3.3.1" +#define RTCRX509_MS_EKU_ENCRYPTED_FILE_SYSTEM_OID "1.3.6.1.4.1.311.10.3.4" +#define RTCRX509_MS_EKU_WHQL_CRYPTO_OID "1.3.6.1.4.1.311.10.3.5" +#define RTCRX509_MS_EKU_ATTEST_WHQL_CRYPTO_OID "1.3.6.1.4.1.311.10.3.5.1" +#define RTCRX509_MS_EKU_NT5_CRYPTO_OID "1.3.6.1.4.1.311.10.3.6" +#define RTCRX509_MS_EKU_OEM_WHQL_CRYPTO_OID "1.3.6.1.4.1.311.10.3.7" +#define RTCRX509_MS_EKU_EMBEDDED_NT_CRYPTO_OID "1.3.6.1.4.1.311.10.3.8" +#define RTCRX509_MS_EKU_ROOT_LIST_SIGNER_OID "1.3.6.1.4.1.311.10.3.9" +#define RTCRX509_MS_EKU_QUALIFIED_SUBORDINATE_OID "1.3.6.1.4.1.311.10.3.10" +#define RTCRX509_MS_EKU_KEY_RECOVERY_3_OID "1.3.6.1.4.1.311.10.3.11" +#define RTCRX509_MS_EKU_DOCUMENT_SIGNING_OID "1.3.6.1.4.1.311.10.3.12" +#define RTCRX509_MS_EKU_LIFETIME_SIGNING_OID "1.3.6.1.4.1.311.10.3.13" +#define RTCRX509_MS_EKU_MOBILE_DEVICE_SOFTWARE_OID "1.3.6.1.4.1.311.10.3.14" +#define RTCRX509_MS_EKU_SMART_DISPLAY_OID "1.3.6.1.4.1.311.10.3.15" +#define RTCRX509_MS_EKU_CSP_SIGNATURE_OID "1.3.6.1.4.1.311.10.3.16" +#define RTCRX509_MS_EKU_EFS_RECOVERY_OID "1.3.6.1.4.1.311.10.3.4.1" +#define RTCRX509_MS_EKU_DRM_OID "1.3.6.1.4.1.311.10.5.1" +#define RTCRX509_MS_EKU_DRM_INDIVIDUALIZATION_OID "1.3.6.1.4.1.311.10.5.2" +#define RTCRX509_MS_EKU_LICENSES_OID "1.3.6.1.4.1.311.10.5.3" +#define RTCRX509_MS_EKU_LICENSE_SERVER_OID "1.3.6.1.4.1.311.10.5.4" +#define RTCRX509_MS_EKU_ENROLLMENT_AGENT_OID "1.3.6.1.4.1.311.20.2.1" +#define RTCRX509_MS_EKU_SMARTCARD_LOGON_OID "1.3.6.1.4.1.311.20.2.2" +#define RTCRX509_MS_EKU_CA_EXCHANGE_OID "1.3.6.1.4.1.311.21.5" +#define RTCRX509_MS_EKU_KEY_RECOVERY_21_OID "1.3.6.1.4.1.311.21.6" +#define RTCRX509_MS_EKU_SYSTEM_HEALTH_OID "1.3.6.1.4.1.311.47.1.1" +#define RTCRX509_MS_EKU_SYSTEM_HEALTH_LOOPHOLE_OID "1.3.6.1.4.1.311.47.1.3" +#define RTCRX509_MS_EKU_KERNEL_MODE_CODE_SIGNING_OID "1.3.6.1.4.1.311.61.1.1" +/** @} */ + +/** @name Apple extended key usage OIDs + * @{ */ +#define RTCRX509_APPLE_EKU_APPLE_EXTENDED_KEY_USAGE_OID "1.2.840.113635.100.4" +#define RTCRX509_APPLE_EKU_CODE_SIGNING_OID "1.2.840.113635.100.4.1" +#define RTCRX509_APPLE_EKU_CODE_SIGNING_DEVELOPMENT_OID "1.2.840.113635.100.4.1.1" +#define RTCRX509_APPLE_EKU_SOFTWARE_UPDATE_SIGNING_OID "1.2.840.113635.100.4.1.2" +#define RTCRX509_APPLE_EKU_CODE_SIGNING_THRID_PARTY_OID "1.2.840.113635.100.4.1.3" +#define RTCRX509_APPLE_EKU_RESOURCE_SIGNING_OID "1.2.840.113635.100.4.1.4" +#define RTCRX509_APPLE_EKU_ICHAT_SIGNING_OID "1.2.840.113635.100.4.2" +#define RTCRX509_APPLE_EKU_ICHAT_ENCRYPTION_OID "1.2.840.113635.100.4.3" +#define RTCRX509_APPLE_EKU_SYSTEM_IDENTITY_OID "1.2.840.113635.100.4.4" +#define RTCRX509_APPLE_EKU_CRYPTO_ENV_OID "1.2.840.113635.100.4.5" +#define RTCRX509_APPLE_EKU_CRYPTO_PRODUCTION_ENV_OID "1.2.840.113635.100.4.5.1" +#define RTCRX509_APPLE_EKU_CRYPTO_MAINTENANCE_ENV_OID "1.2.840.113635.100.4.5.2" +#define RTCRX509_APPLE_EKU_CRYPTO_TEST_ENV_OID "1.2.840.113635.100.4.5.3" +#define RTCRX509_APPLE_EKU_CRYPTO_DEVELOPMENT_ENV_OID "1.2.840.113635.100.4.5.4" +#define RTCRX509_APPLE_EKU_CRYPTO_QOS_OID "1.2.840.113635.100.4.6" +#define RTCRX509_APPLE_EKU_CRYPTO_TIER0_QOS_OID "1.2.840.113635.100.4.6.1" +#define RTCRX509_APPLE_EKU_CRYPTO_TIER1_QOS_OID "1.2.840.113635.100.4.6.2" +#define RTCRX509_APPLE_EKU_CRYPTO_TIER2_QOS_OID "1.2.840.113635.100.4.6.3" +#define RTCRX509_APPLE_EKU_CRYPTO_TIER3_QOS_OID "1.2.840.113635.100.4.6.4" +/** @} */ + +/** + * Use this to update derived values after changing the certificate + * extensions. + * + * @returns IPRT status code + * @param pThis The certificate. + * @param pErrInfo Where to return additional error information. Optional. + */ +RTDECL(int) RTCrX509TbsCertificate_ReprocessExtensions(PRTCRX509TBSCERTIFICATE pThis, PRTERRINFO pErrInfo); + + +/** + * One X.509 Certificate (IPRT representation). + */ +typedef struct RTCRX509CERTIFICATE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The to-be-signed certificate information. */ + RTCRX509TBSCERTIFICATE TbsCertificate; + /** The signature algorithm (must match TbsCertificate.Signature). */ + RTCRX509ALGORITHMIDENTIFIER SignatureAlgorithm; + /** The signature value. */ + RTASN1BITSTRING SignatureValue; +} RTCRX509CERTIFICATE; +/** Pointer to the IPRT representation of one X.509 certificate. */ +typedef RTCRX509CERTIFICATE *PRTCRX509CERTIFICATE; +/** Pointer to the const IPRT representation of one X.509 certificate. */ +typedef RTCRX509CERTIFICATE const *PCRTCRX509CERTIFICATE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509CERTIFICATE, RTDECL, RTCrX509Certificate, SeqCore.Asn1Core); + +/** + * Checks if a certificate matches a given issuer name and serial number. + * + * @returns True / false. + * @param pCertificate The X.509 certificat. + * @param pIssuer The issuer name to match against. + * @param pSerialNumber The serial number to match against. + */ +RTDECL(bool) RTCrX509Certificate_MatchIssuerAndSerialNumber(PCRTCRX509CERTIFICATE pCertificate, + PCRTCRX509NAME pIssuer, PCRTASN1INTEGER pSerialNumber); + +RTDECL(bool) RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280(PCRTCRX509CERTIFICATE pThis, PCRTCRX509NAME pName); +RTDECL(bool) RTCrX509Certificate_IsSelfSigned(PCRTCRX509CERTIFICATE pCertificate); + +RTDECL(int) RTCrX509Certificate_VerifySignature(PCRTCRX509CERTIFICATE pThis, PCRTASN1OBJID pAlgorithm, + PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey, + PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509Certificate_VerifySignatureSelfSigned(PCRTCRX509CERTIFICATE pThis, PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509Certificate_ReadFromFile(PRTCRX509CERTIFICATE pCertificate, const char *pszFilename, uint32_t fFlags, + PCRTASN1ALLOCATORVTABLE pAllocator, PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509Certificate_ReadFromBuffer(PRTCRX509CERTIFICATE pCertificate, const void *pvBuf, size_t cbBuf, + uint32_t fFlags, PCRTASN1ALLOCATORVTABLE pAllocator, + PRTERRINFO pErrInfo, const char *pszErrorTag); +/** @name Flags for RTCrX509Certificate_ReadFromFile and + * RTCrX509Certificate_ReadFromBuffer + * @{ */ +/** Only allow PEM certificates, not binary ones. + * @sa RTCRPEMREADFILE_F_ONLY_PEM */ +#define RTCRX509CERT_READ_F_PEM_ONLY RT_BIT(1) +/** @} */ + +/** X509 Certificate markers for RTCrPemFindFirstSectionInContent et al. */ +extern RTDATADECL(RTCRPEMMARKER const) g_aRTCrX509CertificateMarkers[]; +/** Number of entries in g_aRTCrX509CertificateMarkers. */ +extern RTDATADECL(uint32_t const) g_cRTCrX509CertificateMarkers; + + +/** Wrapper around RTCrPemWriteAsn1ToVfsIoStrm(). */ +DECLINLINE(ssize_t) RTCrX509Certificate_WriteToVfsIoStrm(RTVFSIOSTREAM hVfsIos, PRTCRX509CERTIFICATE pCertificate, + PRTERRINFO pErrInfo) +{ + return RTCrPemWriteAsn1ToVfsIoStrm(hVfsIos, &pCertificate->SeqCore.Asn1Core, 0 /*fFlags*/, + g_aRTCrX509CertificateMarkers[0].paWords[0].pszWord, pErrInfo); +} + +/** Wrapper around RTCrPemWriteAsn1ToVfsFile(). */ +DECLINLINE(ssize_t) RTCrX509Certificate_WriteToVfsFile(RTVFSFILE hVfsFile, PRTCRX509CERTIFICATE pCertificate, + PRTERRINFO pErrInfo) +{ + return RTCrPemWriteAsn1ToVfsFile(hVfsFile, &pCertificate->SeqCore.Asn1Core, 0 /*fFlags*/, + g_aRTCrX509CertificateMarkers[0].paWords[0].pszWord, pErrInfo); +} + +/** @name X.509 Certificate Extensions + * @{ */ +/** Old AuthorityKeyIdentifier OID. */ +#define RTCRX509_ID_CE_OLD_AUTHORITY_KEY_IDENTIFIER_OID "2.5.29.1" +/** Old CertificatePolicies extension OID. */ +#define RTCRX509_ID_CE_OLD_CERTIFICATE_POLICIES_OID "2.5.29.3" +/** Old SubjectAltName extension OID. */ +#define RTCRX509_ID_CE_OLD_SUBJECT_ALT_NAME_OID "2.5.29.7" +/** Old IssuerAltName extension OID. */ +#define RTCRX509_ID_CE_OLD_ISSUER_ALT_NAME_OID "2.5.29.8" +/** Old BasicContraints extension OID. */ +#define RTCRX509_ID_CE_OLD_BASIC_CONSTRAINTS_OID "2.5.29.10" +/** SubjectKeyIdentifier OID. */ +#define RTCRX509_ID_CE_SUBJECT_KEY_IDENTIFIER_OID "2.5.29.14" +/** KeyUsage OID. */ +#define RTCRX509_ID_CE_KEY_USAGE_OID "2.5.29.15" +/** PrivateKeyUsagePeriod OID. */ +#define RTCRX509_ID_CE_PRIVATE_KEY_USAGE_PERIOD_OID "2.5.29.16" +/** SubjectAltName extension OID. */ +#define RTCRX509_ID_CE_SUBJECT_ALT_NAME_OID "2.5.29.17" +/** IssuerAltName extension OID. */ +#define RTCRX509_ID_CE_ISSUER_ALT_NAME_OID "2.5.29.18" +/** BasicContraints extension OID. */ +#define RTCRX509_ID_CE_BASIC_CONSTRAINTS_OID "2.5.29.19" +/** NameContraints extension OID. */ +#define RTCRX509_ID_CE_NAME_CONSTRAINTS_OID "2.5.29.30" +/** CertificatePolicies extension OID. */ +#define RTCRX509_ID_CE_CERTIFICATE_POLICIES_OID "2.5.29.32" +/** PolicyMappings extension OID. */ +#define RTCRX509_ID_CE_POLICY_MAPPINGS_OID "2.5.29.33" +/** AuthorityKeyIdentifier OID. */ +#define RTCRX509_ID_CE_AUTHORITY_KEY_IDENTIFIER_OID "2.5.29.35" +/** PolicyContraints extension OID. */ +#define RTCRX509_ID_CE_POLICY_CONSTRAINTS_OID "2.5.29.36" +/** ExtKeyUsage (extended key usage) extension OID. */ +#define RTCRX509_ID_CE_EXT_KEY_USAGE_OID "2.5.29.37" +/** ExtKeyUsage: OID for permitting any unspecified key usage. */ +#define RTCRX509_ID_CE_ANY_EXTENDED_KEY_USAGE_OID "2.5.29.37.0" +/** AuthorityAttributeIdentifier OID. */ +#define RTCRX509_ID_CE_AUTHORITY_ATTRIBUTE_IDENTIFIER_OID "2.5.29.38" +/** AcceptableCertPolicies OID. */ +#define RTCRX509_ID_CE_ACCEPTABLE_CERT_POLICIES_OID "2.5.29.52" +/** InhibitAnyPolicy OID. */ +#define RTCRX509_ID_CE_INHIBIT_ANY_POLICY_OID "2.5.29.54" +/** @} */ + + +/* + * Sequence of X.509 Certifcates (IPRT representation). + */ +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRX509CERTIFICATES, RTCRX509CERTIFICATE, RTDECL, RTCrX509Certificates); + +/** + * Looks up a certificate by issuer name and serial number. + * + * @returns Pointer to the given certificate if found, NULL if not. + * @param pCertificates The X.509 certificate set to search. + * @param pIssuer The issuer name of the wanted certificate. + * @param pSerialNumber The serial number of the wanted certificate. + */ +RTDECL(PCRTCRX509CERTIFICATE) RTCrX509Certificates_FindByIssuerAndSerialNumber(PCRTCRX509CERTIFICATES pCertificates, + PCRTCRX509NAME pIssuer, + PCRTASN1INTEGER pSerialNumber); + + + +RTDECL(int) RTCrX509CertPathsCreate(PRTCRX509CERTPATHS phCertPaths, PCRTCRX509CERTIFICATE pTarget); +RTDECL(uint32_t) RTCrX509CertPathsRetain(RTCRX509CERTPATHS hCertPaths); +RTDECL(uint32_t) RTCrX509CertPathsRelease(RTCRX509CERTPATHS hCertPaths); +RTDECL(int) RTCrX509CertPathsSetTrustedStore(RTCRX509CERTPATHS hCertPaths, RTCRSTORE hTrustedStore); +RTDECL(int) RTCrX509CertPathsSetUntrustedStore(RTCRX509CERTPATHS hCertPaths, RTCRSTORE hUntrustedStore); +RTDECL(int) RTCrX509CertPathsSetUntrustedArray(RTCRX509CERTPATHS hCertPaths, PCRTCRX509CERTIFICATE paCerts, uint32_t cCerts); +RTDECL(int) RTCrX509CertPathsSetUntrustedSet(RTCRX509CERTPATHS hCertPaths, struct RTCRPKCS7SETOFCERTS const *pSetOfCerts); +RTDECL(int) RTCrX509CertPathsSetValidTime(RTCRX509CERTPATHS hCertPaths, PCRTTIME pTime); +RTDECL(int) RTCrX509CertPathsSetValidTimeSpec(RTCRX509CERTPATHS hCertPaths, PCRTTIMESPEC pTimeSpec); +RTDECL(int) RTCrX509CertPathsSetTrustAnchorChecks(RTCRX509CERTPATHS hCertPaths, bool fEnable); +RTDECL(int) RTCrX509CertPathsCreateEx(PRTCRX509CERTPATHS phCertPaths, PCRTCRX509CERTIFICATE pTarget, RTCRSTORE hTrustedStore, + RTCRSTORE hUntrustedStore, PCRTCRX509CERTIFICATE paUntrustedCerts, uint32_t cUntrustedCerts, + PCRTTIMESPEC pValidTime); +RTDECL(int) RTCrX509CertPathsBuild(RTCRX509CERTPATHS hCertPaths, PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509CertPathsDumpOne(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, uint32_t uVerbosity, + PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser); +RTDECL(int) RTCrX509CertPathsDumpAll(RTCRX509CERTPATHS hCertPaths, uint32_t uVerbosity, + PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser); + +RTDECL(int) RTCrX509CertPathsValidateOne(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509CertPathsValidateAll(RTCRX509CERTPATHS hCertPaths, uint32_t *pcValidPaths, PRTERRINFO pErrInfo); + +RTDECL(uint32_t) RTCrX509CertPathsGetPathCount(RTCRX509CERTPATHS hCertPaths); +RTDECL(int) RTCrX509CertPathsQueryPathInfo(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, + bool *pfTrusted, uint32_t *pcNodes, PCRTCRX509NAME *ppSubject, + PCRTCRX509SUBJECTPUBLICKEYINFO *ppPublicKeyInfo, + PCRTCRX509CERTIFICATE *ppCert, PCRTCRCERTCTX *ppCertCtx, int *prcVerify); +RTDECL(uint32_t) RTCrX509CertPathsGetPathLength(RTCRX509CERTPATHS hCertPaths, uint32_t iPath); +RTDECL(int) RTCrX509CertPathsGetPathVerifyResult(RTCRX509CERTPATHS hCertPaths, uint32_t iPath); +RTDECL(PCRTCRX509CERTIFICATE) RTCrX509CertPathsGetPathNodeCert(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, uint32_t iNode); + + +RT_C_DECLS_END + +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_crypto_x509_h */ + diff --git a/include/iprt/ctype.h b/include/iprt/ctype.h new file mode 100644 index 00000000..139af524 --- /dev/null +++ b/include/iprt/ctype.h @@ -0,0 +1,251 @@ +/** @file + * IPRT - Simple character type classiciation and conversion. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ctype_h +#define IPRT_INCLUDED_ctype_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @name C locale predicates and conversions. + * + * For most practical purposes, this can safely be used when parsing UTF-8 + * strings. Just keep in mind that we only deal with the first 127 chars and + * that full correctness is only archived using the non-existing RTLocIs* API. + * + * @remarks Use the marcros, not the inlined functions. + * + * @remarks ASSUMES the source code includes the basic ASCII chars. This is a + * general IPRT assumption. + * @{ */ +#define RT_C_IS_BLANK(ch) RTLocCIsBlank((ch)) +#define RT_C_IS_ALNUM(ch) RTLocCIsAlNum((ch)) +#define RT_C_IS_ALPHA(ch) RTLocCIsAlpha((ch)) +#define RT_C_IS_CNTRL(ch) RTLocCIsCntrl((ch)) +#define RT_C_IS_DIGIT(ch) RTLocCIsDigit((ch)) +#define RT_C_IS_LOWER(ch) RTLocCIsLower((ch)) +#define RT_C_IS_GRAPH(ch) RTLocCIsGraph((ch)) +#define RT_C_IS_ODIGIT(ch) RTLocCIsODigit((ch)) +#define RT_C_IS_PRINT(ch) RTLocCIsPrint((ch)) +#define RT_C_IS_PUNCT(ch) RTLocCIsPunct((ch)) +#define RT_C_IS_SPACE(ch) RTLocCIsSpace((ch)) +#define RT_C_IS_UPPER(ch) RTLocCIsUpper((ch)) +#define RT_C_IS_XDIGIT(ch) RTLocCIsXDigit((ch)) + +#define RT_C_TO_LOWER(ch) RTLocCToLower((ch)) +#define RT_C_TO_UPPER(ch) RTLocCToUpper((ch)) + +/** + * Checks for a blank character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsBlank(int ch) +{ + return ch == 0x20 /* space */ + || ch == 0x09; /* horizontal tab */ +} + +/** + * Checks for a control character. + * + * @returns true / false. + * @param ch The character to test. + * + * @note Will return true of ch is '\0'! + */ +DECL_FORCE_INLINE(bool) RTLocCIsCntrl(int ch) +{ + return (unsigned)ch < 32U /* 0..2f */ + || ch == 0x7f; +} + +/** + * Checks for a decimal digit. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsDigit(int ch) +{ + return (unsigned)ch - 0x30 < 10U; /* 30..39 */ +} + +/** + * Checks for a lower case character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsLower(int ch) +{ + return (unsigned)ch - 0x61U < 26U; /* 61..7a */ +} + +/** + * Checks for an octal digit. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsODigit(int ch) +{ + return (unsigned)ch - 0x30 < 8U; /* 30..37 */ +} + +/** + * Checks for a printable character (whitespace included). + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsPrint(int ch) +{ + return (unsigned)ch - 0x20U < 95U; /* 20..7e */ +} + +/** + * Checks for punctuation (?). + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsPunct(int ch) +{ + return (unsigned)ch - 0x21U < 15U /* 21..2f */ + || (unsigned)ch - 0x3aU < 7U /* 3a..40 */ + || (unsigned)ch - 0x5bU < 6U /* 5a..60 */ + || (unsigned)ch - 0x7bU < 4U /* 7b..7e */; +} + +/** + * Checks for a white-space character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsSpace(int ch) +{ + return ch == 0x20 /* 20 (space) */ + || (unsigned)ch - 0x09U < 5U; /* 09..0d */ +} + +/** + * Checks for an upper case character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsUpper(int ch) +{ + return (unsigned)ch - 0x41 < 26U; /* 41..5a */ +} + +/** + * Checks for a hexadecimal digit. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsXDigit(int ch) +{ + return (unsigned)ch - 0x30 < 10U /* 30..39 (0-9) */ + || (unsigned)ch - 0x41 < 6 /* 41..46 (A-F) */ + || (unsigned)ch - 0x61 < 6; /* 61..66 (a-f) */ +} + +/** + * Checks for an alphabetic character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsAlpha(int ch) +{ + return RTLocCIsLower(ch) || RTLocCIsUpper(ch); +} + +/** + * Checks for an alphanumerical character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsAlNum(int ch) +{ + return RTLocCIsDigit(ch) || RTLocCIsAlpha(ch); +} + +/** + * Checks for a printable character whitespace excluded. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsGraph(int ch) +{ + return RTLocCIsPrint(ch) && !RTLocCIsBlank(ch); +} + + +/** + * Converts the character to lower case if applicable. + * + * @returns lower cased character or ch. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(int) RTLocCToLower(int ch) +{ + return RTLocCIsUpper(ch) ? (ch) + 0x20 : (ch); +} + +/** + * Converts the character to upper case if applicable. + * + * @returns upper cased character or ch. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(int) RTLocCToUpper(int ch) +{ + return RTLocCIsLower(ch) ? (ch) - 0x20 : (ch); +} + + +/** @} */ + +#endif /* !IPRT_INCLUDED_ctype_h */ diff --git a/include/iprt/dbg.h b/include/iprt/dbg.h new file mode 100644 index 00000000..64a3a94b --- /dev/null +++ b/include/iprt/dbg.h @@ -0,0 +1,2034 @@ +/* $Id: dbg.h $ */ +/** @file + * IPRT - Debugging Routines. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_dbg_h +#define IPRT_INCLUDED_dbg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_rt_dbg RTDbg - Debugging Routines + * @ingroup grp_rt + * @{ + */ + + +/** Debug segment index. */ +typedef uint32_t RTDBGSEGIDX; +/** Pointer to a debug segment index. */ +typedef RTDBGSEGIDX *PRTDBGSEGIDX; +/** Pointer to a const debug segment index. */ +typedef RTDBGSEGIDX const *PCRTDBGSEGIDX; +/** NIL debug segment index. */ +#define NIL_RTDBGSEGIDX UINT32_C(0xffffffff) +/** The last normal segment index. */ +#define RTDBGSEGIDX_LAST UINT32_C(0xffffffef) +/** Special segment index that indicates that the offset is a relative + * virtual address (RVA). I.e. an offset from the start of the module. */ +#define RTDBGSEGIDX_RVA UINT32_C(0xfffffff0) +/** Special segment index that indicates that the offset is a absolute. */ +#define RTDBGSEGIDX_ABS UINT32_C(0xfffffff1) +/** The last valid special segment index. */ +#define RTDBGSEGIDX_SPECIAL_LAST RTDBGSEGIDX_ABS +/** The last valid special segment index. */ +#define RTDBGSEGIDX_SPECIAL_FIRST (RTDBGSEGIDX_LAST + 1U) + + + +/** @name RTDBGSYMADDR_FLAGS_XXX + * Flags used when looking up a symbol by address. + * @{ */ +/** Less or equal address. (default) */ +#define RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL UINT32_C(0) +/** Greater or equal address. */ +#define RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL UINT32_C(1) +/** Don't consider absolute symbols in deferred modules. */ +#define RTDBGSYMADDR_FLAGS_SKIP_ABS_IN_DEFERRED UINT32_C(2) +/** Don't search for absolute symbols if it's expensive. */ +#define RTDBGSYMADDR_FLAGS_SKIP_ABS UINT32_C(4) +/** Mask of valid flags. */ +#define RTDBGSYMADDR_FLAGS_VALID_MASK UINT32_C(7) +/** @} */ + +/** @name RTDBGSYMBOLADD_F_XXX - Flags for RTDbgModSymbolAdd and RTDbgAsSymbolAdd. + * @{ */ +/** Replace existing symbol with same address. */ +#define RTDBGSYMBOLADD_F_REPLACE_SAME_ADDR UINT32_C(0x00000001) +/** Replace any existing symbols overlapping the symbol range. */ +#define RTDBGSYMBOLADD_F_REPLACE_ANY UINT32_C(0x00000002) +/** Adjust sizes on address conflict. This applies to the symbol being added + * as well as existing symbols. */ +#define RTDBGSYMBOLADD_F_ADJUST_SIZES_ON_CONFLICT UINT32_C(0x00000004) +/** Mask of valid flags. */ +#define RTDBGSYMBOLADD_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** Max length (including '\\0') of a segment name. */ +#define RTDBG_SEGMENT_NAME_LENGTH (128 - 8 - 8 - 8 - 4 - 4) + +/** + * Debug module segment. + */ +typedef struct RTDBGSEGMENT +{ + /** The load address. + * RTUINTPTR_MAX if not applicable. */ + RTUINTPTR Address; + /** The image relative virtual address of the segment. + * RTUINTPTR_MAX if not applicable. */ + RTUINTPTR uRva; + /** The segment size. */ + RTUINTPTR cb; + /** The segment flags. (reserved) */ + uint32_t fFlags; + /** The segment index. */ + RTDBGSEGIDX iSeg; + /** Symbol name. */ + char szName[RTDBG_SEGMENT_NAME_LENGTH]; +} RTDBGSEGMENT; +/** Pointer to a debug module segment. */ +typedef RTDBGSEGMENT *PRTDBGSEGMENT; +/** Pointer to a const debug module segment. */ +typedef RTDBGSEGMENT const *PCRTDBGSEGMENT; + + +/** + * Return type. + */ +typedef enum RTDBGRETURNTYPE +{ + /** The usual invalid 0 value. */ + RTDBGRETURNTYPE_INVALID = 0, + /** Near 16-bit return. */ + RTDBGRETURNTYPE_NEAR16, + /** Near 32-bit return. */ + RTDBGRETURNTYPE_NEAR32, + /** Near 64-bit return. */ + RTDBGRETURNTYPE_NEAR64, + /** Far 16:16 return. */ + RTDBGRETURNTYPE_FAR16, + /** Far 16:32 return. */ + RTDBGRETURNTYPE_FAR32, + /** Far 16:64 return. */ + RTDBGRETURNTYPE_FAR64, + /** 16-bit iret return (e.g. real or 286 protect mode). */ + RTDBGRETURNTYPE_IRET16, + /** 32-bit iret return. */ + RTDBGRETURNTYPE_IRET32, + /** 32-bit iret return. */ + RTDBGRETURNTYPE_IRET32_PRIV, + /** 32-bit iret return to V86 mode. */ + RTDBGRETURNTYPE_IRET32_V86, + /** @todo 64-bit iret return. */ + RTDBGRETURNTYPE_IRET64, + /** The end of the valid return types. */ + RTDBGRETURNTYPE_END, + /** The usual 32-bit blowup. */ + RTDBGRETURNTYPE_32BIT_HACK = 0x7fffffff +} RTDBGRETURNTYPE; + +/** + * Figures the size of the return state on the stack. + * + * @returns number of bytes. 0 if invalid parameter. + * @param enmRetType The type of return. + */ +DECLINLINE(unsigned) RTDbgReturnTypeSize(RTDBGRETURNTYPE enmRetType) +{ + switch (enmRetType) + { + case RTDBGRETURNTYPE_NEAR16: return 2; + case RTDBGRETURNTYPE_NEAR32: return 4; + case RTDBGRETURNTYPE_NEAR64: return 8; + case RTDBGRETURNTYPE_FAR16: return 4; + case RTDBGRETURNTYPE_FAR32: return 4; + case RTDBGRETURNTYPE_FAR64: return 8; + case RTDBGRETURNTYPE_IRET16: return 6; + case RTDBGRETURNTYPE_IRET32: return 4*3; + case RTDBGRETURNTYPE_IRET32_PRIV: return 4*5; + case RTDBGRETURNTYPE_IRET32_V86: return 4*9; + case RTDBGRETURNTYPE_IRET64: return 5*8; + + case RTDBGRETURNTYPE_INVALID: + case RTDBGRETURNTYPE_END: + case RTDBGRETURNTYPE_32BIT_HACK: + break; + } + return 0; +} + +/** + * Check if near return. + * + * @returns true if near, false if far or iret. + * @param enmRetType The type of return. + */ +DECLINLINE(bool) RTDbgReturnTypeIsNear(RTDBGRETURNTYPE enmRetType) +{ + return enmRetType == RTDBGRETURNTYPE_NEAR32 + || enmRetType == RTDBGRETURNTYPE_NEAR64 + || enmRetType == RTDBGRETURNTYPE_NEAR16; +} + + + +/** Magic value for RTDBGUNWINDSTATE::u32Magic (James Moody). */ +#define RTDBGUNWINDSTATE_MAGIC UINT32_C(0x19250326) +/** Magic value for RTDBGUNWINDSTATE::u32Magic after use. */ +#define RTDBGUNWINDSTATE_MAGIC_DEAD UINT32_C(0x20101209) + +/** + * Unwind machine state. + */ +typedef struct RTDBGUNWINDSTATE +{ + /** Structure magic (RTDBGUNWINDSTATE_MAGIC) */ + uint32_t u32Magic; + /** The state architecture. */ + RTLDRARCH enmArch; + + /** The program counter register. + * amd64/x86: RIP/EIP/IP + * sparc: PC + * arm32: PC / R15 + */ + uint64_t uPc; + + /** Return type. */ + RTDBGRETURNTYPE enmRetType; + + /** Register state (see enmArch). */ + union + { + /** RTLDRARCH_AMD64, RTLDRARCH_X86_32 and RTLDRARCH_X86_16. */ + struct + { + /** General purpose registers indexed by X86_GREG_XXX. */ + uint64_t auRegs[16]; + /** The frame address. */ + RTFAR64 FrameAddr; + /** Set if we're in real or virtual 8086 mode. */ + bool fRealOrV86; + /** The flags register. */ + uint64_t uRFlags; + /** Trap error code. */ + uint64_t uErrCd; + /** Segment registers (indexed by X86_SREG_XXX). */ + uint16_t auSegs[6]; + + /** Bitmap tracking register we've loaded and which content can possibly be trusted. */ + union + { + /** For effective clearing of the bits. */ + uint32_t fAll; + /** Detailed view. */ + struct + { + /** Bitmap indicating whether a GPR was loaded (parallel to auRegs). */ + uint16_t fRegs; + /** Bitmap indicating whether a segment register was loaded (parallel to auSegs). */ + uint8_t fSegs; + /** Set if uPc was loaded. */ + RT_GCC_EXTENSION uint8_t fPc : 1; + /** Set if FrameAddr was loaded. */ + RT_GCC_EXTENSION uint8_t fFrameAddr : 1; + /** Set if uRFlags was loaded. */ + RT_GCC_EXTENSION uint8_t fRFlags : 1; + /** Set if uErrCd was loaded. */ + RT_GCC_EXTENSION uint8_t fErrCd : 1; + } s; + } Loaded; + } x86; + + /** @todo add ARM and others as needed. */ + } u; + + /** + * Stack read callback. + * + * @returns IPRT status code. + * @param pThis Pointer to this structure. + * @param uSp The stack pointer address. + * @param cbToRead The number of bytes to read. + * @param pvDst Where to put the bytes we read. + */ + DECLCALLBACKMEMBER(int, pfnReadStack,(struct RTDBGUNWINDSTATE *pThis, RTUINTPTR uSp, size_t cbToRead, void *pvDst)); + /** User argument (useful for pfnReadStack). */ + void *pvUser; + +} RTDBGUNWINDSTATE; + +/** + * Try read a 16-bit value off the stack. + * + * @returns pfnReadStack result. + * @param pThis The unwind state. + * @param uSrcAddr The stack address. + * @param puDst The read destination. + */ +DECLINLINE(int) RTDbgUnwindLoadStackU16(PRTDBGUNWINDSTATE pThis, RTUINTPTR uSrcAddr, uint16_t *puDst) +{ + return pThis->pfnReadStack(pThis, uSrcAddr, sizeof(*puDst), puDst); +} + +/** + * Try read a 32-bit value off the stack. + * + * @returns pfnReadStack result. + * @param pThis The unwind state. + * @param uSrcAddr The stack address. + * @param puDst The read destination. + */ +DECLINLINE(int) RTDbgUnwindLoadStackU32(PRTDBGUNWINDSTATE pThis, RTUINTPTR uSrcAddr, uint32_t *puDst) +{ + return pThis->pfnReadStack(pThis, uSrcAddr, sizeof(*puDst), puDst); +} + +/** + * Try read a 64-bit value off the stack. + * + * @returns pfnReadStack result. + * @param pThis The unwind state. + * @param uSrcAddr The stack address. + * @param puDst The read destination. + */ +DECLINLINE(int) RTDbgUnwindLoadStackU64(PRTDBGUNWINDSTATE pThis, RTUINTPTR uSrcAddr, uint64_t *puDst) +{ + return pThis->pfnReadStack(pThis, uSrcAddr, sizeof(*puDst), puDst); +} + + + +/** Max length (including '\\0') of a symbol name. */ +#define RTDBG_SYMBOL_NAME_LENGTH (512 - 8 - 8 - 8 - 4 - 4 - 8) + +/** + * Debug symbol. + */ +typedef struct RTDBGSYMBOL +{ + /** Symbol value (address). + * This depends a bit who you ask. It will be the same as offSeg when you + * as RTDbgMod, but the mapping address if you ask RTDbgAs. */ + RTUINTPTR Value; + /** Symbol size. */ + RTUINTPTR cb; + /** Offset into the segment specified by iSeg. */ + RTUINTPTR offSeg; + /** Segment number. */ + RTDBGSEGIDX iSeg; + /** Symbol Flags. (reserved). */ + uint32_t fFlags; + /** Symbol ordinal. + * This is set to UINT32_MAX if the ordinals aren't supported. */ + uint32_t iOrdinal; + /** Symbol name. */ + char szName[RTDBG_SYMBOL_NAME_LENGTH]; +} RTDBGSYMBOL; +/** Pointer to debug symbol. */ +typedef RTDBGSYMBOL *PRTDBGSYMBOL; +/** Pointer to const debug symbol. */ +typedef const RTDBGSYMBOL *PCRTDBGSYMBOL; + + +/** + * Allocate a new symbol structure. + * + * @returns Pointer to a new structure on success, NULL on failure. + */ +RTDECL(PRTDBGSYMBOL) RTDbgSymbolAlloc(void); + +/** + * Duplicates a symbol structure. + * + * @returns Pointer to duplicate on success, NULL on failure. + * + * @param pSymInfo The symbol info to duplicate. + */ +RTDECL(PRTDBGSYMBOL) RTDbgSymbolDup(PCRTDBGSYMBOL pSymInfo); + +/** + * Free a symbol structure previously allocated by a RTDbg method. + * + * @param pSymInfo The symbol info to free. NULL is ignored. + */ +RTDECL(void) RTDbgSymbolFree(PRTDBGSYMBOL pSymInfo); + + +/** Max length (including '\\0') of a debug info file name. */ +#define RTDBG_FILE_NAME_LENGTH (260) + + +/** + * Debug line number information. + */ +typedef struct RTDBGLINE +{ + /** Address. + * This depends a bit who you ask. It will be the same as offSeg when you + * as RTDbgMod, but the mapping address if you ask RTDbgAs. */ + RTUINTPTR Address; + /** Offset into the segment specified by iSeg. */ + RTUINTPTR offSeg; + /** Segment number. */ + RTDBGSEGIDX iSeg; + /** Line number. */ + uint32_t uLineNo; + /** Symbol ordinal. + * This is set to UINT32_MAX if the ordinals aren't supported. */ + uint32_t iOrdinal; + /** Filename. */ + char szFilename[RTDBG_FILE_NAME_LENGTH]; +} RTDBGLINE; +/** Pointer to debug line number. */ +typedef RTDBGLINE *PRTDBGLINE; +/** Pointer to const debug line number. */ +typedef const RTDBGLINE *PCRTDBGLINE; + +/** + * Allocate a new line number structure. + * + * @returns Pointer to a new structure on success, NULL on failure. + */ +RTDECL(PRTDBGLINE) RTDbgLineAlloc(void); + +/** + * Duplicates a line number structure. + * + * @returns Pointer to duplicate on success, NULL on failure. + * + * @param pLine The line number to duplicate. + */ +RTDECL(PRTDBGLINE) RTDbgLineDup(PCRTDBGLINE pLine); + +/** + * Free a line number structure previously allocated by a RTDbg method. + * + * @param pLine The line number to free. NULL is ignored. + */ +RTDECL(void) RTDbgLineFree(PRTDBGLINE pLine); + + +/** + * Dump the stack of the current thread into @a pszStack. + * + * This could be a little slow as it reads image and debug info again for each call. + * + * @returns Length of string returned in @a pszStack. + * @param pszStack The output buffer. + * @param cbStack The size of the output buffer. + * @param fFlags Future flags, MBZ. + * + * @remarks Not present on all systems and contexts. + */ +RTDECL(size_t) RTDbgStackDumpSelf(char *pszStack, size_t cbStack, uint32_t fFlags); + + +# ifdef IN_RING3 + +/** @defgroup grp_rt_dbgcfg RTDbgCfg - Debugging Configuration + * + * The settings used when loading and processing debug info is kept in a + * RTDBGCFG instance since it's generally shared for a whole debugging session + * and anyhow would be a major pain to pass as individual parameters to each + * call. The debugging config API not only keeps the settings information but + * also provide APIs for making use of it, and in some cases, like for instance + * symbol severs, retriving and maintaining it. + * + * @todo Work in progress - APIs are still missing, adding when needed. + * + * @{ + */ + +/** Debugging configuration handle. */ +typedef struct RTDBGCFGINT *RTDBGCFG; +/** Pointer to a debugging configuration handle. */ +typedef RTDBGCFG *PRTDBGCFG; +/** NIL debug configuration handle. */ +#define NIL_RTDBGCFG ((RTDBGCFG)0) + +/** @name RTDBGCFG_FLAGS_XXX - Debugging configuration flags. + * @{ */ +/** Use deferred loading. */ +#define RTDBGCFG_FLAGS_DEFERRED RT_BIT_64(0) +/** Don't use the symbol server (http). */ +#define RTDBGCFG_FLAGS_NO_SYM_SRV RT_BIT_64(1) +/** Don't use system search paths. + * On windows this means not using _NT_ALT_SYMBOL_PATH, _NT_SYMBOL_PATH, + * _NT_SOURCE_PATH, and _NT_EXECUTABLE_PATH. + * On other systems the effect has yet to be determined. */ +#define RTDBGCFG_FLAGS_NO_SYSTEM_PATHS RT_BIT_64(2) +/** Don't search the debug and image paths recursively. */ +#define RTDBGCFG_FLAGS_NO_RECURSIV_SEARCH RT_BIT_64(3) +/** Don't search the source paths recursively. */ +#define RTDBGCFG_FLAGS_NO_RECURSIV_SRC_SEARCH RT_BIT_64(4) +/** @} */ + +/** + * Debugging configuration properties. + * + * The search paths are using the DOS convention of semicolon as separator + * character. The the special 'srv' + asterisk syntax known from the windows + * debugger search paths are also supported to some extent, as is 'cache' + + * asterisk. + */ +typedef enum RTDBGCFGPROP +{ + /** The customary invalid 0 value. */ + RTDBGCFGPROP_INVALID = 0, + /** RTDBGCFG_FLAGS_XXX. + * Env: _FLAGS + * The environment variable can be specified as a unsigned value or one or more + * mnemonics separated by spaces. */ + RTDBGCFGPROP_FLAGS, + /** List of paths to search for symbol files and images. + * Env: _PATH */ + RTDBGCFGPROP_PATH, + /** List of symbol file suffixes (semicolon separated). + * Env: _SUFFIXES */ + RTDBGCFGPROP_SUFFIXES, + /** List of paths to search for source files. + * Env: _SRC_PATH */ + RTDBGCFGPROP_SRC_PATH, + /** End of valid values. */ + RTDBGCFGPROP_END, + /** The customary 32-bit type hack. */ + RTDBGCFGPROP_32BIT_HACK = 0x7fffffff +} RTDBGCFGPROP; + +/** + * Configuration property change operation. + */ +typedef enum RTDBGCFGOP +{ + /** Customary invalid 0 value. */ + RTDBGCFGOP_INVALID = 0, + /** Replace the current value with the given one. */ + RTDBGCFGOP_SET, + /** Append the given value to the existing one. For integer values this is + * considered a bitwise OR operation. */ + RTDBGCFGOP_APPEND, + /** Prepend the given value to the existing one. For integer values this is + * considered a bitwise OR operation. */ + RTDBGCFGOP_PREPEND, + /** Removes the value from the existing one. For interger values the value is + * complemented and ANDed with the existing one, clearing all the specified + * flags/bits. */ + RTDBGCFGOP_REMOVE, + /** End of valid values. */ + RTDBGCFGOP_END, + /** Customary 32-bit type hack. */ + RTDBGCFGOP_32BIT_HACK = 0x7fffffff +} RTDBGCFGOP; + + + +/** + * Initializes a debugging configuration. + * + * @returns IPRT status code. + * @param phDbgCfg Where to return the configuration handle. + * @param pszEnvVarPrefix The environment variable prefix. If NULL, the + * environment is not consulted. + * @param fNativePaths Whether to pick up native paths from the + * environment. + * + * @sa RTDbgCfgChangeString, RTDbgCfgChangeUInt. + */ +RTDECL(int) RTDbgCfgCreate(PRTDBGCFG phDbgCfg, const char *pszEnvVarPrefix, bool fNativePaths); + +/** + * Retains a new reference to a debugging config. + * + * @returns New reference count. + * UINT32_MAX is returned if the handle is invalid (asserted). + * @param hDbgCfg The config handle. + */ +RTDECL(uint32_t) RTDbgCfgRetain(RTDBGCFG hDbgCfg); + +/** + * Releases a references to a debugging config. + * + * @returns New reference count, if 0 the config was freed. UINT32_MAX is + * returned if the handle is invalid (asserted). + * @param hDbgCfg The config handle. + */ +RTDECL(uint32_t) RTDbgCfgRelease(RTDBGCFG hDbgCfg); + +/** + * Changes a property value by string. + * + * For string values the string is used more or less as given. For integer + * values and flags, it can contains both values (ORed together) or property + * specific mnemonics (ORed / ~ANDed). + * + * @returns IPRT status code. + * @retval VERR_DBG_CFG_INVALID_VALUE + * @param hDbgCfg The debugging configuration handle. + * @param enmProp The property to change. + * @param enmOp How to change the property. + * @param pszValue The property value to apply. + */ +RTDECL(int) RTDbgCfgChangeString(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, RTDBGCFGOP enmOp, const char *pszValue); + +/** + * Changes a property value by unsigned integer (64-bit). + * + * This can only be applied to integer and flag properties. + * + * @returns IPRT status code. + * @retval VERR_DBG_CFG_NOT_UINT_PROP + * @param hDbgCfg The debugging configuration handle. + * @param enmProp The property to change. + * @param enmOp How to change the property. + * @param uValue The property value to apply. + */ +RTDECL(int) RTDbgCfgChangeUInt(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, RTDBGCFGOP enmOp, uint64_t uValue); + +/** + * Query a property value as string. + * + * Integer and flags properties are returned as a list of mnemonics if possible, + * otherwise as simple hex values. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if there isn't sufficient buffer space. Nothing + * is written. + * @param hDbgCfg The debugging configuration handle. + * @param enmProp The property to change. + * @param pszValue The output buffer. + * @param cbValue The size of the output buffer. + */ +RTDECL(int) RTDbgCfgQueryString(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, char *pszValue, size_t cbValue); + +/** + * Query a property value as unsigned integer (64-bit). + * + * Only integer and flags properties can be queried this way. + * + * @returns IPRT status code. + * @retval VERR_DBG_CFG_NOT_UINT_PROP + * @param hDbgCfg The debugging configuration handle. + * @param enmProp The property to change. + * @param puValue Where to return the value. + */ +RTDECL(int) RTDbgCfgQueryUInt(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, uint64_t *puValue); + +/** + * Log callback. + * + * @param hDbgCfg The debug config instance. + * @param iLevel The message level. + * @param pszMsg The message. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTDBGCFGLOG,(RTDBGCFG hDbgCfg, uint32_t iLevel, const char *pszMsg, void *pvUser)); +/** Pointer to a log callback. */ +typedef FNRTDBGCFGLOG *PFNRTDBGCFGLOG; + +/** + * Sets the log callback for the configuration. + * + * This will fail if there is already a log callback present, unless pfnCallback + * is NULL. + * + * @returns IPRT status code. + * @param hDbgCfg The debugging configuration handle. + * @param pfnCallback The callback function. NULL to unset. + * @param pvUser The user argument. + */ +RTDECL(int) RTDbgCfgSetLogCallback(RTDBGCFG hDbgCfg, PFNRTDBGCFGLOG pfnCallback, void *pvUser); + +/** + * Callback used by the RTDbgCfgOpen function to try out a file that was found. + * + * @returns On statuses other than VINF_CALLBACK_RETURN and + * VERR_CALLBACK_RETURN the search will continue till the end of the + * list. These status codes will not necessarily be propagated to the + * caller in any consistent manner. + * @retval VINF_CALLBACK_RETURN if successfully opened the file and it's time + * to return + * @retval VERR_CALLBACK_RETURN if we should stop searching immediately. + * + * @param hDbgCfg The debugging configuration handle. + * @param pszFilename The path to the file that should be tried out. + * @param pvUser1 First user parameter. + * @param pvUser2 Second user parameter. + */ +typedef DECLCALLBACKTYPE(int, FNRTDBGCFGOPEN,(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)); +/** Pointer to a open-file callback used to the RTDbgCfgOpen functions. */ +typedef FNRTDBGCFGOPEN *PFNRTDBGCFGOPEN; + + +RTDECL(int) RTDbgCfgOpenEx(RTDBGCFG hDbgCfg, const char *pszFilename, const char *pszCacheSubDir, + const char *pszUuidMappingSubDir, uint32_t fFlags, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenPeImage(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenPdb70(RTDBGCFG hDbgCfg, const char *pszFilename, PCRTUUID pUuid, uint32_t uAge, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenPdb20(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp, uint32_t uAge, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenDbg(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenDwo(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t uCrc32, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenDwoBuildId(RTDBGCFG hDbgCfg, const char *pszFilename, const uint8_t *pbBuildId, + size_t cbBuildId, PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenDsymBundle(RTDBGCFG hDbgCfg, const char *pszFilename, PCRTUUID pUuid, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenMachOImage(RTDBGCFG hDbgCfg, const char *pszFilename, PCRTUUID pUuid, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); + +/** @name RTDBGCFG_O_XXX - Open flags for RTDbgCfgOpen. + * @{ */ +/** The operative system mask. The values are RT_OPSYS_XXX. */ +#define RTDBGCFG_O_OPSYS_MASK UINT32_C(0x000000ff) +/** Use debuginfod style symbol servers when encountered in the path. */ +#define RTDBGCFG_O_DEBUGINFOD RT_BIT_32(24) +/** Same as RTDBGCFG_FLAGS_NO_SYSTEM_PATHS. */ +#define RTDBGCFG_O_NO_SYSTEM_PATHS RT_BIT_32(25) +/** The files may be compressed MS styled. */ +#define RTDBGCFG_O_MAYBE_COMPRESSED_MS RT_BIT_32(26) +/** Whether to make a recursive search. */ +#define RTDBGCFG_O_RECURSIVE RT_BIT_32(27) +/** We're looking for a separate debug file. */ +#define RTDBGCFG_O_EXT_DEBUG_FILE RT_BIT_32(28) +/** We're looking for an executable image. */ +#define RTDBGCFG_O_EXECUTABLE_IMAGE RT_BIT_32(29) +/** The file search should be done in an case insensitive fashion. */ +#define RTDBGCFG_O_CASE_INSENSITIVE RT_BIT_32(30) +/** Use Windbg style symbol servers when encountered in the path. */ +#define RTDBGCFG_O_SYMSRV RT_BIT_32(31) +/** Mask of valid flags. */ +#define RTDBGCFG_O_VALID_MASK UINT32_C(0xff0000ff) +/** @} */ + + +/** @name Static symbol cache configuration + * @{ */ +/** The cache subdirectory containing the UUID mappings for .dSYM bundles. + * The UUID mappings implemented by IPRT are splitting the image/dsym UUID up + * into five 4 digit parts that maps to directories and one twelve digit part + * that maps to a symbolic link. The symlink points to the file in the + * Contents/Resources/DWARF/ directory of the .dSYM bundle for a .dSYM map, and + * to the image file (Contents/MacOS/bundlename for bundles) for image map. + * + * According to available documentation, both lldb and gdb are able to use these + * UUID maps to find debug info while debugging. See: + * http://lldb.llvm.org/symbols.html + */ +#define RTDBG_CACHE_UUID_MAP_DIR_DSYMS "dsym-uuids" +/** The cache subdirectory containing the UUID mappings for image files. */ +#define RTDBG_CACHE_UUID_MAP_DIR_IMAGES "image-uuids" +/** Suffix used for the cached .dSYM debug files. + * In .dSYM bundles only the .dSYM/Contents/Resources/DWARF/debug-file is + * copied into the cache, and in order to not clash with the stripped/rich image + * file, the cache tool slaps this suffix onto the name. */ +#define RTDBG_CACHE_DSYM_FILE_SUFFIX ".dwarf" +/** @} */ + +# endif /* IN_RING3 */ + +/** @} */ + + +/** @defgroup grp_rt_dbgas RTDbgAs - Debug Address Space + * @{ + */ + +/** + * Creates an empty address space. + * + * @returns IPRT status code. + * + * @param phDbgAs Where to store the address space handle on success. + * @param FirstAddr The first address in the address space. + * @param LastAddr The last address in the address space. + * @param pszName The name of the address space. + */ +RTDECL(int) RTDbgAsCreate(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, const char *pszName); + +/** + * Variant of RTDbgAsCreate that takes a name format string. + * + * @returns IPRT status code. + * + * @param phDbgAs Where to store the address space handle on success. + * @param FirstAddr The first address in the address space. + * @param LastAddr The last address in the address space. + * @param pszNameFmt The name format of the address space. + * @param va Format arguments. + */ +RTDECL(int) RTDbgAsCreateV(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Variant of RTDbgAsCreate that takes a name format string. + * + * @returns IPRT status code. + * + * @param phDbgAs Where to store the address space handle on success. + * @param FirstAddr The first address in the address space. + * @param LastAddr The last address in the address space. + * @param pszNameFmt The name format of the address space. + * @param ... Format arguments. + */ +RTDECL(int) RTDbgAsCreateF(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Retains a reference to the address space. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgAsRetain(RTDBGAS hDbgAs); + +/** + * Release a reference to the address space. + * + * When the reference count reaches zero, the address space is destroyed. + * That means unlinking all the modules it currently contains, potentially + * causing some or all of them to be destroyed as they are managed by + * reference counting. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hDbgAs The address space handle. The NIL handle is quietly + * ignored and 0 is returned. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgAsRelease(RTDBGAS hDbgAs); + +/** + * Locks the address space for exclusive access. + * + * @returns IRPT status code + * @param hDbgAs The address space handle. + */ +RTDECL(int) RTDbgAsLockExcl(RTDBGAS hDbgAs); + +/** + * Counters the actions of one RTDbgAsUnlockExcl call. + * + * @returns IRPT status code + * @param hDbgAs The address space handle. + */ +RTDECL(int) RTDbgAsUnlockExcl(RTDBGAS hDbgAs); + +/** + * Gets the name of an address space. + * + * @returns read only address space name. + * NULL if hDbgAs is invalid. + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(const char *) RTDbgAsName(RTDBGAS hDbgAs); + +/** + * Gets the first address in an address space. + * + * @returns The address. + * 0 if hDbgAs is invalid. + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(RTUINTPTR) RTDbgAsFirstAddr(RTDBGAS hDbgAs); + +/** + * Gets the last address in an address space. + * + * @returns The address. + * 0 if hDbgAs is invalid. + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(RTUINTPTR) RTDbgAsLastAddr(RTDBGAS hDbgAs); + +/** + * Gets the number of modules in the address space. + * + * This can be used together with RTDbgAsModuleByIndex + * to enumerate the modules. + * + * @returns The number of modules. + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgAsModuleCount(RTDBGAS hDbgAs); + +/** @name Flags for RTDbgAsModuleLink and RTDbgAsModuleLinkSeg + * @{ */ +/** Replace all conflicting module. + * (The conflicting modules will be removed the address space and their + * references released.) */ +#define RTDBGASLINK_FLAGS_REPLACE RT_BIT_32(0) +/** Mask containing the valid flags. */ +#define RTDBGASLINK_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Links a module into the address space at the give address. + * + * The size of the mapping is determined using RTDbgModImageSize(). + * + * @returns IPRT status code. + * @retval VERR_OUT_OF_RANGE if the specified address will put the module + * outside the address space. + * @retval VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings. + * + * @param hDbgAs The address space handle. + * @param hDbgMod The module handle of the module to be linked in. + * @param ImageAddr The address to link the module at. + * @param fFlags See RTDBGASLINK_FLAGS_*. + */ +RTDECL(int) RTDbgAsModuleLink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTUINTPTR ImageAddr, uint32_t fFlags); + +/** + * Links a segment into the address space at the give address. + * + * The size of the mapping is determined using RTDbgModSegmentSize(). + * + * @returns IPRT status code. + * @retval VERR_OUT_OF_RANGE if the specified address will put the module + * outside the address space. + * @retval VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings. + * + * @param hDbgAs The address space handle. + * @param hDbgMod The module handle. + * @param iSeg The segment number (0-based) of the segment to be + * linked in. + * @param SegAddr The address to link the segment at. + * @param fFlags See RTDBGASLINK_FLAGS_*. + */ +RTDECL(int) RTDbgAsModuleLinkSeg(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR SegAddr, uint32_t fFlags); + +/** + * Unlinks all the mappings of a module from the address space. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the module wasn't found. + * + * @param hDbgAs The address space handle. + * @param hDbgMod The module handle of the module to be unlinked. + */ +RTDECL(int) RTDbgAsModuleUnlink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod); + +/** + * Unlinks the mapping at the specified address. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no module or segment is mapped at that address. + * + * @param hDbgAs The address space handle. + * @param Addr The address within the mapping to be unlinked. + */ +RTDECL(int) RTDbgAsModuleUnlinkByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr); + +/** + * Get a the handle of a module in the address space by is index. + * + * @returns A retained handle to the specified module. The caller must release + * the returned reference. + * NIL_RTDBGMOD if invalid index or handle. + * + * @param hDbgAs The address space handle. + * @param iModule The index of the module to get. + * + * @remarks The module indexes may change after calls to RTDbgAsModuleLink, + * RTDbgAsModuleLinkSeg, RTDbgAsModuleUnlink and + * RTDbgAsModuleUnlinkByAddr. + */ +RTDECL(RTDBGMOD) RTDbgAsModuleByIndex(RTDBGAS hDbgAs, uint32_t iModule); + +/** + * Queries mapping module information by handle. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no mapping was found at the specified address. + * + * @param hDbgAs The address space handle. + * @param Addr Address within the mapping of the module or segment. + * @param phMod Where to the return the retained module handle. + * Optional. + * @param pAddr Where to return the base address of the mapping. + * Optional. + * @param piSeg Where to return the segment index. This is set to + * NIL if the entire module is mapped as a single + * mapping. Optional. + */ +RTDECL(int) RTDbgAsModuleByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTDBGMOD phMod, PRTUINTPTR pAddr, PRTDBGSEGIDX piSeg); + +/** + * Queries mapping module information by name. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no mapping was found at the specified address. + * @retval VERR_OUT_OF_RANGE if the name index was out of range. + * + * @param hDbgAs The address space handle. + * @param pszName The module name. + * @param iName There can be more than one module by the same name + * in an address space. This argument indicates which + * is meant. (0 based) + * @param phMod Where to the return the retained module handle. + */ +RTDECL(int) RTDbgAsModuleByName(RTDBGAS hDbgAs, const char *pszName, uint32_t iName, PRTDBGMOD phMod); + +/** + * Information about a mapping. + * + * This is used by RTDbgAsModuleGetMapByIndex. + */ +typedef struct RTDBGASMAPINFO +{ + /** The mapping address. */ + RTUINTPTR Address; + /** The segment mapped there. + * This is NIL_RTDBGSEGIDX if the entire module image is mapped here. */ + RTDBGSEGIDX iSeg; +} RTDBGASMAPINFO; +/** Pointer to info about an address space mapping. */ +typedef RTDBGASMAPINFO *PRTDBGASMAPINFO; +/** Pointer to const info about an address space mapping. */ +typedef RTDBGASMAPINFO const *PCRTDBGASMAPINFO; + +/** + * Queries mapping information for a module given by index. + * + * @returns IRPT status code. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_OUT_OF_RANGE if the name index was out of range. + * @retval VINF_BUFFER_OVERFLOW if the array is too small and the returned + * information is incomplete. + * + * @param hDbgAs The address space handle. + * @param iModule The index of the module to get. + * @param paMappings Where to return the mapping information. The buffer + * size is given by *pcMappings. + * @param pcMappings IN: Size of the paMappings array. OUT: The number of + * entries returned. + * @param fFlags Flags for reserved for future use. MBZ. + * + * @remarks See remarks for RTDbgAsModuleByIndex regarding the volatility of the + * iModule parameter. + */ +RTDECL(int) RTDbgAsModuleQueryMapByIndex(RTDBGAS hDbgAs, uint32_t iModule, PRTDBGASMAPINFO paMappings, uint32_t *pcMappings, uint32_t fFlags); + +/** + * Adds a symbol to a module in the address space. + * + * @returns IPRT status code. See RTDbgModSymbolAdd for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if no module was found at the specified address. + * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding + * custom symbols. + * + * @param hDbgAs The address space handle. + * @param pszSymbol The symbol name. + * @param Addr The address of the symbol. + * @param cb The size of the symbol. + * @param fFlags Symbol flags, RTDBGSYMBOLADD_F_XXX. + * @param piOrdinal Where to return the symbol ordinal on success. If + * the interpreter doesn't do ordinals, this will be set to + * UINT32_MAX. Optional + */ +RTDECL(int) RTDbgAsSymbolAdd(RTDBGAS hDbgAs, const char *pszSymbol, RTUINTPTR Addr, RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal); + +/** + * Query a symbol by address. + * + * @returns IPRT status code. See RTDbgModSymbolAddr for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module. + * @retval VERR_INVALID_PARAMETER if incorrect flags. + * + * @param hDbgAs The address space handle. + * @param Addr The address which closest symbol is requested. + * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX. + * @param poffDisp Where to return the distance between the symbol + * and address. Optional. + * @param pSymbol Where to return the symbol info. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsSymbolByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, uint32_t fFlags, + PRTINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); + +/** + * Query a symbol by address. + * + * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module. + * @retval VERR_INVALID_PARAMETER if incorrect flags. + * + * @param hDbgAs The address space handle. + * @param Addr The address which closest symbol is requested. + * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX. + * @param poffDisp Where to return the distance between the symbol + * and address. Optional. + * @param ppSymInfo Where to return the pointer to the allocated symbol + * info. Always set. Free with RTDbgSymbolFree. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsSymbolByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, uint32_t fFlags, + PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo, PRTDBGMOD phMod); + +/** + * Query a symbol by name. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if not found. + * + * @param hDbgAs The address space handle. + * @param pszSymbol The symbol name. It is possible to limit the scope + * of the search by prefixing the symbol with a module + * name pattern followed by a bang (!) character. + * RTStrSimplePatternNMatch is used for the matching. + * @param pSymbol Where to return the symbol info. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsSymbolByName(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); + +/** + * Query a symbol by name, allocating the returned symbol structure. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if not found. + * + * @param hDbgAs The address space handle. + * @param pszSymbol The symbol name. See RTDbgAsSymbolByName for more. + * @param ppSymbol Where to return the pointer to the allocated + * symbol info. Always set. Free with RTDbgSymbolFree. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsSymbolByNameA(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL *ppSymbol, PRTDBGMOD phMod); + +/** + * Adds a line number to a module in the address space. + * + * @returns IPRT status code. See RTDbgModLineAdd for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if no module was found at the specified address. + * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding + * custom symbols. + * + * @param hDbgAs The address space handle. + * @param pszFile The file name. + * @param uLineNo The line number. + * @param Addr The address of the symbol. + * @param piOrdinal Where to return the line number ordinal on success. + * If the interpreter doesn't do ordinals, this will be + * set to UINT32_MAX. Optional. + */ +RTDECL(int) RTDbgAsLineAdd(RTDBGAS hDbgAs, const char *pszFile, uint32_t uLineNo, RTUINTPTR Addr, uint32_t *piOrdinal); + +/** + * Query a line number by address. + * + * @returns IPRT status code. See RTDbgModLineAddrA for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module. + * + * @param hDbgAs The address space handle. + * @param Addr The address which closest symbol is requested. + * @param poffDisp Where to return the distance between the line + * number and address. + * @param pLine Where to return the line number information. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsLineByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod); + +/** + * Query a line number by address. + * + * @returns IPRT status code. See RTDbgModLineAddrA for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module. + * + * @param hDbgAs The address space handle. + * @param Addr The address which closest symbol is requested. + * @param poffDisp Where to return the distance between the line + * number and address. + * @param ppLine Where to return the pointer to the allocated line + * number info. Always set. Free with RTDbgLineFree. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsLineByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE *ppLine, PRTDBGMOD phMod); + +/** @todo Missing some bits here. */ + +/** @} */ + + +# ifdef IN_RING3 +/** @defgroup grp_rt_dbgmod RTDbgMod - Debug Module Interpreter + * @{ + */ + +/** + * Creates a module based on the default debug info container. + * + * This can be used to manually load a module and its symbol. The primary user + * group is the debug info interpreters, which use this API to create an + * efficient debug info container behind the scenes and forward all queries to + * it once the info has been loaded. + * + * @returns IPRT status code. + * + * @param phDbgMod Where to return the module handle. + * @param pszName The name of the module (mandatory). + * @param cbSeg The size of initial segment. If zero, segments will + * have to be added manually using RTDbgModSegmentAdd. + * @param fFlags Flags reserved for future extensions, MBZ for now. + */ +RTDECL(int) RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cbSeg, uint32_t fFlags); + +RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, + RTLDRARCH enmArch, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTUINTPTR uSubtrahend, + RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromPeImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, + PRTLDRMOD phLdrMod, uint32_t cbImage, uint32_t uTimeDateStamp, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromDbg(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t cbImage, + uint32_t uTimeDateStamp, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromPdb(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t cbImage, + PCRTUUID pUuid, uint32_t Age, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromDwo(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t cbImage, + uint32_t uCrc32, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromMachOImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, + RTLDRARCH enmArch, PRTLDRMOD phLdrModIn, uint32_t cbImage, uint32_t cSegs, + PCRTDBGSEGMENT paSegs, PCRTUUID pUuid, RTDBGCFG hDbgCfg, uint32_t fFlags); + +/** @name Flags for RTDbgModCreate and friends. + * @{ */ +/** Overrides the hDbgCfg settings and forces an image and/or symbol file + * search. RTDbgModCreate will quietly ignore this flag. */ +#define RTDBGMOD_F_NOT_DEFERRED RT_BIT_32(0) +/** Mach-O: Load the __LINKEDIT segment (@sa RTLDR_O_MACHO_LOAD_LINKEDIT). */ +#define RTDBGMOD_F_MACHO_LOAD_LINKEDIT RT_BIT_32(1) +/** Valid flag mask. */ +#define RTDBGMOD_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + + +/** + * Retains another reference to the module. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hDbgMod The module handle. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgModRetain(RTDBGMOD hDbgMod); + +/** + * Release a reference to the module. + * + * When the reference count reaches zero, the module is destroyed. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hDbgMod The module handle. The NIL handle is quietly ignored + * and 0 is returned. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgModRelease(RTDBGMOD hDbgMod); + +/** + * Removes all content from the debug module (container), optionally only + * leaving segments and image size intact. + * + * This is only possible on container modules, i.e. created by RTDbgModCreate(). + * + * @returns IPRT status code. + * @param hDbgMod The module handle. + * @param fLeaveSegments Whether to leave segments (and image size) as is. + */ +RTDECL(int) RTDbgModRemoveAll(RTDBGMOD hDbgMod, bool fLeaveSegments); + +/** + * Gets the module name. + * + * @returns Pointer to a read only string containing the name. + * + * @param hDbgMod The module handle. + */ +RTDECL(const char *) RTDbgModName(RTDBGMOD hDbgMod); + +/** + * Gets the name of the debug info file we're using. + * + * @returns Pointer to a read only string containing the filename, NULL if we + * don't use one. + * + * @param hDbgMod The module handle. + */ +RTDECL(const char *) RTDbgModDebugFile(RTDBGMOD hDbgMod); + +/** + * Gets the image filename (as specified by the user). + * + * @returns Pointer to a read only string containing the filename. + * + * @param hDbgMod The module handle. + */ +RTDECL(const char *) RTDbgModImageFile(RTDBGMOD hDbgMod); + +/** + * Gets the image filename actually used if it differs from RTDbgModImageFile. + * + * @returns Pointer to a read only string containing the filename, NULL if same + * as RTDBgModImageFile. + * + * @param hDbgMod The module handle. + */ +RTDECL(const char *) RTDbgModImageFileUsed(RTDBGMOD hDbgMod); + +/** + * Checks if the loading of the debug info has been postponed. + * + * @returns true if postponed, false if not or invalid handle. + * @param hDbgMod The module handle. + */ +RTDECL(bool) RTDbgModIsDeferred(RTDBGMOD hDbgMod); + +/** + * Checks if the debug info is exports only. + * + * @returns true if exports only, false if not or invalid handle. + * @param hDbgMod The module handle. + */ +RTDECL(bool) RTDbgModIsExports(RTDBGMOD hDbgMod); + +/** + * Converts an image relative address to a segment:offset address. + * + * @returns Segment index on success. + * NIL_RTDBGSEGIDX is returned if the module handle or the RVA are + * invalid. + * + * @param hDbgMod The module handle. + * @param uRva The image relative address to convert. + * @param poffSeg Where to return the segment offset. Optional. + */ +RTDECL(RTDBGSEGIDX) RTDbgModRvaToSegOff(RTDBGMOD hDbgMod, RTUINTPTR uRva, PRTUINTPTR poffSeg); + +/** + * Gets the module tag value if any. + * + * @returns The tag. 0 if hDbgMod is invalid. + * + * @param hDbgMod The module handle. + */ +RTDECL(uint64_t) RTDbgModGetTag(RTDBGMOD hDbgMod); + +/** + * Tags or untags the module. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * + * @param hDbgMod The module handle. + * @param uTag The tag value. The convention is that 0 is no tag + * and any other value means it's tagged. It's adviced + * to use some kind of unique number like an address + * (global or string cache for instance) to avoid + * collisions with other users + */ +RTDECL(int) RTDbgModSetTag(RTDBGMOD hDbgMod, uint64_t uTag); + + +/** + * Image size when mapped if segments are mapped adjacently. + * + * For ELF, PE, and Mach-O images this is (usually) a natural query, for LX and + * NE and such it's a bit odder and the answer may not make much sense for them. + * + * @returns Image mapped size. + * RTUINTPTR_MAX is returned if the handle is invalid. + * + * @param hDbgMod The module handle. + */ +RTDECL(RTUINTPTR) RTDbgModImageSize(RTDBGMOD hDbgMod); + +/** + * Gets the image format. + * + * @returns Image format. + * @retval RTLDRFMT_INVALID if the handle is invalid or if the format isn't known. + * @param hDbgMod The debug module handle. + * @sa RTLdrGetFormat + */ +RTDECL(RTLDRFMT) RTDbgModImageGetFormat(RTDBGMOD hDbgMod); + +/** + * Gets the image architecture. + * + * @returns Image architecture. + * @retval RTLDRARCH_INVALID if the handle is invalid. + * @retval RTLDRARCH_WHATEVER if unknown. + * @param hDbgMod The debug module handle. + * @sa RTLdrGetArch + */ +RTDECL(RTLDRARCH) RTDbgModImageGetArch(RTDBGMOD hDbgMod); + +/** + * Generic method for querying image properties. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the property query isn't supported (either all + * or that specific property). The caller must handle this result. + * @retval VERR_NOT_FOUND the property was not found in the module. The caller + * must also normally deal with this. + * @retval VERR_INVALID_FUNCTION if the function value is wrong. + * @retval VERR_INVALID_PARAMETER if the fixed buffer size is wrong. Correct + * size in @a *pcbRet. + * @retval VERR_BUFFER_OVERFLOW if the function doesn't have a fixed size + * buffer and the buffer isn't big enough. Correct size in @a *pcbRet. + * @retval VERR_INVALID_HANDLE if the handle is invalid. + * + * @param hDbgMod The debug module handle. + * @param enmProp The property to query. + * @param pvBuf Pointer to the input / output buffer. In most cases + * it's only used for returning data. + * @param cbBuf The size of the buffer. + * @param pcbRet Where to return the amount of data returned. On + * buffer size errors, this is set to the correct size. + * Optional. + * @sa RTLdrQueryPropEx + */ +RTDECL(int) RTDbgModImageQueryProp(RTDBGMOD hDbgMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet); + + +/** + * Adds a segment to the module. Optional feature. + * + * This method is intended used for manually constructing debug info for a + * module. The main usage is from other debug info interpreters that want to + * avoid writing a debug info database and instead uses the standard container + * behind the scenes. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if this feature isn't support by the debug info + * interpreter. This is a common return code. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_ADDRESS_WRAP if uRva+cb wraps around. + * @retval VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE if pszName is too short or long. + * @retval VERR_INVALID_PARAMETER if fFlags contains undefined flags. + * @retval VERR_DBG_SPECIAL_SEGMENT if *piSeg is a special segment. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if *piSeg doesn't meet expectations. + * + * @param hDbgMod The module handle. + * @param uRva The image relative address of the segment. + * @param cb The size of the segment. + * @param pszName The segment name. Does not normally need to be + * unique, although this is somewhat up to the + * debug interpreter to decide. + * @param fFlags Segment flags. Reserved for future used, MBZ. + * @param piSeg The segment index or NIL_RTDBGSEGIDX on input. + * The assigned segment index on successful return. + * Optional. + */ +RTDECL(int) RTDbgModSegmentAdd(RTDBGMOD hDbgMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, + uint32_t fFlags, PRTDBGSEGIDX piSeg); + +/** + * Gets the number of segments in the module. + * + * This is can be used to determine the range which can be passed to + * RTDbgModSegmentByIndex and derivates. + * + * @returns The segment relative address. + * NIL_RTDBGSEGIDX if the handle is invalid. + * + * @param hDbgMod The module handle. + */ +RTDECL(RTDBGSEGIDX) RTDbgModSegmentCount(RTDBGMOD hDbgMod); + +/** + * Query information about a segment. + * + * This can be used together with RTDbgModSegmentCount to enumerate segments. + * The index starts a 0 and stops one below RTDbgModSegmentCount. + * + * @returns IPRT status code. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if iSeg is too high. + * @retval VERR_DBG_SPECIAL_SEGMENT if iSeg indicates a special segment. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * + * @param hDbgMod The module handle. + * @param iSeg The segment index. No special segments. + * @param pSegInfo Where to return the segment info. The + * RTDBGSEGMENT::Address member will be set to + * RTUINTPTR_MAX or the load address used at link time. + */ +RTDECL(int) RTDbgModSegmentByIndex(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo); + +/** + * Gets the size of a segment. + * + * This is a just a wrapper around RTDbgModSegmentByIndex. + * + * @returns The segment size. + * RTUINTPTR_MAX is returned if either the handle and segment index are + * invalid. + * + * @param hDbgMod The module handle. + * @param iSeg The segment index. RTDBGSEGIDX_ABS is not allowed. + * If RTDBGSEGIDX_RVA is used, the functions returns + * the same value as RTDbgModImageSize. + */ +RTDECL(RTUINTPTR) RTDbgModSegmentSize(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg); + +/** + * Gets the image relative address of a segment. + * + * This is a just a wrapper around RTDbgModSegmentByIndex. + * + * @returns The segment relative address. + * RTUINTPTR_MAX is returned if either the handle and segment index are + * invalid. + * + * @param hDbgMod The module handle. + * @param iSeg The segment index. No special segment indexes + * allowed (asserted). + */ +RTDECL(RTUINTPTR) RTDbgModSegmentRva(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg); + + +/** + * Adds a line number to the module. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding + * custom symbols. This is a common place occurrence. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or + * short. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_DBG_ADDRESS_WRAP if off+cb wraps around. + * @retval VERR_INVALID_PARAMETER if the symbol flags sets undefined bits. + * @retval VERR_DBG_DUPLICATE_SYMBOL + * @retval VERR_DBG_ADDRESS_CONFLICT + * + * @param hDbgMod The module handle. + * @param pszSymbol The symbol name. + * @param iSeg The segment index. + * @param off The segment offset. + * @param cb The size of the symbol. Can be zero, although this + * may depend somewhat on the debug interpreter. + * @param fFlags Symbol flags, RTDBGSYMBOLADD_F_XXX. + * @param piOrdinal Where to return the symbol ordinal on success. If + * the interpreter doesn't do ordinals, this will be set to + * UINT32_MAX. Optional. + */ +RTDECL(int) RTDbgModSymbolAdd(RTDBGMOD hDbgMod, const char *pszSymbol, RTDBGSEGIDX iSeg, RTUINTPTR off, + RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal); + +/** + * Gets the symbol count. + * + * This can be used together wtih RTDbgModSymbolByOrdinal or + * RTDbgModSymbolByOrdinalA to enumerate all the symbols. + * + * @returns The number of symbols in the module. + * UINT32_MAX is returned if the module handle is invalid or some other + * error occurs. + * + * @param hDbgMod The module handle. + */ +RTDECL(uint32_t) RTDbgModSymbolCount(RTDBGMOD hDbgMod); + +/** + * Queries symbol information by ordinal number. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_NOT_SUPPORTED if lookup by ordinal is not supported. + * + * @param hDbgMod The module handle. + * @param iOrdinal The symbol ordinal number. 0-based. The highest + * number is RTDbgModSymbolCount() - 1. + * @param pSymInfo Where to store the symbol information. + */ +RTDECL(int) RTDbgModSymbolByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo); + +/** + * Queries symbol information by ordinal number. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_NOT_SUPPORTED if lookup by ordinal is not supported. + * @retval VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number. + * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails. + * + * @param hDbgMod The module handle. + * @param iOrdinal The symbol ordinal number. 0-based. The highest + * number is RTDbgModSymbolCount() - 1. + * @param ppSymInfo Where to store the pointer to the returned + * symbol information. Always set. Free with + * RTDbgSymbolFree. + */ +RTDECL(int) RTDbgModSymbolByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL *ppSymInfo); + +/** + * Queries symbol information by address. + * + * The returned symbol is what the debug info interpreter considers the symbol + * most applicable to the specified address. This usually means a symbol with an + * address equal or lower than the requested. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_INVALID_PARAMETER if incorrect flags. + * + * @param hDbgMod The module handle. + * @param iSeg The segment number. + * @param off The offset into the segment. + * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX. + * @param poffDisp Where to store the distance between the + * specified address and the returned symbol. + * Optional. + * @param pSymInfo Where to store the symbol information. + */ +RTDECL(int) RTDbgModSymbolByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags, + PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo); + +/** + * Queries symbol information by address. + * + * The returned symbol is what the debug info interpreter considers the symbol + * most applicable to the specified address. This usually means a symbol with an + * address equal or lower than the requested. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails. + * @retval VERR_INVALID_PARAMETER if incorrect flags. + * + * @param hDbgMod The module handle. + * @param iSeg The segment index. + * @param off The offset into the segment. + * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX. + * @param poffDisp Where to store the distance between the + * specified address and the returned symbol. Optional. + * @param ppSymInfo Where to store the pointer to the returned + * symbol information. Always set. Free with + * RTDbgSymbolFree. + */ +RTDECL(int) RTDbgModSymbolByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags, + PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo); + +/** + * Queries symbol information by symbol name. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found. + * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or + * short. + * + * @param hDbgMod The module handle. + * @param pszSymbol The symbol name. + * @param pSymInfo Where to store the symbol information. + */ +RTDECL(int) RTDbgModSymbolByName(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL pSymInfo); + +/** + * Queries symbol information by symbol name. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found. + * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or + * short. + * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails. + * + * @param hDbgMod The module handle. + * @param pszSymbol The symbol name. + * @param ppSymInfo Where to store the pointer to the returned + * symbol information. Always set. Free with + * RTDbgSymbolFree. + */ +RTDECL(int) RTDbgModSymbolByNameA(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL *ppSymInfo); + +/** + * Adds a line number to the module. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding + * custom symbols. This should be consider a normal response. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_FILE_NAME_OUT_OF_RANGE if the file name is too longer or + * empty. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_INVALID_PARAMETER if the line number flags sets undefined bits. + * + * @param hDbgMod The module handle. + * @param pszFile The file name. + * @param uLineNo The line number. + * @param iSeg The segment index. + * @param off The segment offset. + * @param piOrdinal Where to return the line number ordinal on + * success. If the interpreter doesn't do ordinals, + * this will be set to UINT32_MAX. Optional. + */ +RTDECL(int) RTDbgModLineAdd(RTDBGMOD hDbgMod, const char *pszFile, uint32_t uLineNo, + RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t *piOrdinal); + +/** + * Gets the line number count. + * + * This can be used together wtih RTDbgModLineByOrdinal or RTDbgModSymbolByLineA + * to enumerate all the line number information. + * + * @returns The number of line numbers in the module. + * UINT32_MAX is returned if the module handle is invalid or some other + * error occurs. + * + * @param hDbgMod The module handle. + */ +RTDECL(uint32_t) RTDbgModLineCount(RTDBGMOD hDbgMod); + +/** + * Queries line number information by ordinal number. + * + * This can be used to enumerate the line numbers for the module. Use + * RTDbgModLineCount() to figure the end of the ordinals. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers. + * @retval VERR_DBG_LINE_NOT_FOUND if there is no line number with that + * ordinal. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + + * @param hDbgMod The module handle. + * @param iOrdinal The line number ordinal number. + * @param pLineInfo Where to store the information about the line + * number. + */ +RTDECL(int) RTDbgModLineByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo); + +/** + * Queries line number information by ordinal number. + * + * This can be used to enumerate the line numbers for the module. Use + * RTDbgModLineCount() to figure the end of the ordinals. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers. + * @retval VERR_DBG_LINE_NOT_FOUND if there is no line number with that + * ordinal. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_NO_MEMORY if RTDbgLineAlloc fails. + * + * @param hDbgMod The module handle. + * @param iOrdinal The line number ordinal number. + * @param ppLineInfo Where to store the pointer to the returned line + * number information. Always set. Free with + * RTDbgLineFree. + */ +RTDECL(int) RTDbgModLineByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE *ppLineInfo); + +/** + * Queries line number information by address. + * + * The returned line number is what the debug info interpreter considers the + * one most applicable to the specified address. This usually means a line + * number with an address equal or lower than the requested. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers. + * @retval VERR_DBG_LINE_NOT_FOUND if no suitable line number was found. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * + * @param hDbgMod The module handle. + * @param iSeg The segment number. + * @param off The offset into the segment. + * @param poffDisp Where to store the distance between the + * specified address and the returned symbol. + * Optional. + * @param pLineInfo Where to store the line number information. + */ +RTDECL(int) RTDbgModLineByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE pLineInfo); + +/** + * Queries line number information by address. + * + * The returned line number is what the debug info interpreter considers the + * one most applicable to the specified address. This usually means a line + * number with an address equal or lower than the requested. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers. + * @retval VERR_DBG_LINE_NOT_FOUND if no suitable line number was found. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_NO_MEMORY if RTDbgLineAlloc fails. + * + * @param hDbgMod The module handle. + * @param iSeg The segment number. + * @param off The offset into the segment. + * @param poffDisp Where to store the distance between the + * specified address and the returned symbol. + * Optional. + * @param ppLineInfo Where to store the pointer to the returned line + * number information. Always set. Free with + * RTDbgLineFree. + */ +RTDECL(int) RTDbgModLineByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE *ppLineInfo); + +/** + * Try use unwind information to unwind one frame. + * + * @returns IPRT status code. Last informational status from stack reader callback. + * @retval VERR_DBG_NO_UNWIND_INFO if the module contains no unwind information. + * @retval VERR_DBG_UNWIND_INFO_NOT_FOUND if no unwind information was found + * for the location given by iSeg:off. + * + * @param hDbgMod The module handle. + * @param iSeg The segment number of the program counter. + * @param off The offset into @a iSeg. Together with @a iSeg + * this corresponds to the RTDBGUNWINDSTATE::uPc + * value pointed to by @a pState. + * @param pState The unwind state to work. + * + * @sa RTLdrUnwindFrame + */ +RTDECL(int) RTDbgModUnwindFrame(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTDBGUNWINDSTATE pState); + +/** @} */ +# endif /* IN_RING3 */ + + + +/** @name Kernel Debug Info API + * + * This is a specialized API for obtaining symbols and structure information + * about the running kernel. It is relatively OS specific. Its purpose and + * operation is doesn't map all that well onto RTDbgMod, so a few dedicated + * functions was created for it. + * + * @{ */ + +/** Handle to the kernel debug info. */ +typedef struct RTDBGKRNLINFOINT *RTDBGKRNLINFO; +/** Pointer to a kernel debug info handle. */ +typedef RTDBGKRNLINFO *PRTDBGKRNLINFO; +/** Nil kernel debug info handle. */ +#define NIL_RTDBGKRNLINFO ((RTDBGKRNLINFO)0) + +/** + * Opens the kernel debug info. + * + * @returns IPRT status code. Can fail for any number of reasons. + * + * @param phKrnlInfo Where to return the kernel debug info handle on + * success. + * @param fFlags Flags reserved for future use. Must be zero. + */ +RTR0DECL(int) RTR0DbgKrnlInfoOpen(PRTDBGKRNLINFO phKrnlInfo, uint32_t fFlags); + +/** + * Retains a reference to the kernel debug info handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * @param hKrnlInfo The kernel info handle. + */ +RTR0DECL(uint32_t) RTR0DbgKrnlInfoRetain(RTDBGKRNLINFO hKrnlInfo); + + +/** + * Releases a reference to the kernel debug info handle, destroying it when the + * counter reaches zero. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * @param hKrnlInfo The kernel info handle. NIL_RTDBGKRNLINFO is + * quietly ignored. + */ +RTR0DECL(uint32_t) RTR0DbgKrnlInfoRelease(RTDBGKRNLINFO hKrnlInfo); + +/** + * Queries the offset (in bytes) of a member of a kernel structure. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and offset at @a poffMember. + * @retval VERR_NOT_FOUND if the structure or the member was not found. + * @retval VERR_INVALID_HANDLE if hKrnlInfo is bad. + * @retval VERR_INVALID_POINTER if any of the pointers are bad. + * + * @param hKrnlInfo The kernel info handle. + * @param pszModule The name of the module to search, pass NULL to + * search the default kernel module(s). + * @param pszStructure The structure name. + * @param pszMember The member name. + * @param poffMember Where to return the offset. + */ +RTR0DECL(int) RTR0DbgKrnlInfoQueryMember(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszStructure, + const char *pszMember, size_t *poffMember); + + +/** + * Queries the value (usually the address) of a kernel symbol. + * + * This may go looking for the symbol in other modules, in which case it will + * always check the kernel symbol table first. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and value at @a ppvSymbol. + * @retval VERR_SYMBOL_NOT_FOUND + * @retval VERR_INVALID_HANDLE if hKrnlInfo is bad. + * @retval VERR_INVALID_POINTER if any of the pointers are bad. + * + * @param hKrnlInfo The kernel info handle. + * @param pszModule The name of the module to search, pass NULL to + * search the default kernel module(s). + * @param pszSymbol The C name of the symbol. + * On Windows NT there are the following special symbols: + * - __ImageBase: The base address of the module. + * - __ImageSize: The size of the module. + * - __ImageNtHdrs: Address of the NT headers. + * @param ppvSymbol Where to return the symbol value, passing NULL is + * OK. This may be modified even on failure, in + * particular, it will be set to NULL when + * VERR_SYMBOL_NOT_FOUND is returned. + * + * @sa RTR0DbgKrnlInfoGetSymbol, RTLdrGetSymbol + */ +RTR0DECL(int) RTR0DbgKrnlInfoQuerySymbol(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, + const char *pszSymbol, void **ppvSymbol); + +/** + * Wrapper around RTR0DbgKrnlInfoQuerySymbol that returns the symbol. + * + * @return Symbol address if found, NULL if not found or some invalid parameter + * or something. + * @param hKrnlInfo The kernel info handle. + * @param pszModule The name of the module to search, pass NULL to + * search the default kernel module(s). + * @param pszSymbol The C name of the symbol. + * On Windows NT there are the following special symbols: + * - __ImageBase: The base address of the module. + * - __ImageSize: The size of the module. + * - __ImageNtHdrs: Address of the NT headers. + * @sa RTR0DbgKrnlInfoQuerySymbol, RTLdrGetSymbol + */ +RTR0DECL(void *) RTR0DbgKrnlInfoGetSymbol(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszSymbol); + +/** + * Queries the size (in bytes) of a kernel data type. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and size at @a pcbType. + * @retval VERR_NOT_FOUND if the type was not found. + * @retval VERR_INVALID_HANDLE if hKrnlInfo is bad. + * @retval VERR_INVALID_POINTER if any of the pointers are bad. + * @retval VERR_WRONG_TYPE if the type was not a valid data type (e.g. a + * function) + * + * @param hKrnlInfo The kernel info handle. + * @param pszModule The name of the module to search, pass NULL to + * search the default kernel module(s). + * @param pszType The type name. + * @param pcbType Where to return the size of the type. + */ +RTR0DECL(int) RTR0DbgKrnlInfoQuerySize(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, + const char *pszType, size_t *pcbType); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_dbg_h */ + diff --git a/include/iprt/dir.h b/include/iprt/dir.h new file mode 100644 index 00000000..ff47c974 --- /dev/null +++ b/include/iprt/dir.h @@ -0,0 +1,894 @@ +/** @file + * IPRT - Directory Manipulation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_dir_h +#define IPRT_INCLUDED_dir_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_dir RTDir - Directory Manipulation + * @ingroup grp_rt + * @{ + */ + +/** + * Check for the existence of a directory. + * + * All symbolic links will be attemped resolved. If that is undesirable, please + * use RTPathQueryInfo instead. + * + * @returns true if exist and is a directory. + * @returns false if not exists or isn't a directory. + * @param pszPath Path to the directory. + */ +RTDECL(bool) RTDirExists(const char *pszPath); + +/** @name RTDirCreate flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTDIRCREATE_FLAGS_NO_SYMLINKS RT_BIT(0) +/** Set the not-content-indexed flag (default). Windows only atm. */ +#define RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET RT_BIT(1) +/** Do not set the not-content-indexed flag. Windows only atm. */ +#define RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET UINT32_C(0) +/** Ignore errors setting the not-content-indexed flag. Windows only atm. */ +#define RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL RT_BIT(2) +/** Ignore umask when applying the mode. */ +#define RTDIRCREATE_FLAGS_IGNORE_UMASK RT_BIT(3) +/** Valid mask. */ +#define RTDIRCREATE_FLAGS_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Creates a directory. + * + * @returns iprt status code. + * @param pszPath Path to the directory to create. + * @param fMode The mode of the new directory. + * @param fCreate Create flags, RTDIRCREATE_FLAGS_*. + */ +RTDECL(int) RTDirCreate(const char *pszPath, RTFMODE fMode, uint32_t fCreate); + +/** + * Creates a directory including all non-existing parent directories. + * + * @returns iprt status code. + * @param pszPath Path to the directory to create. + * @param fMode The mode of the new directories. + */ +RTDECL(int) RTDirCreateFullPath(const char *pszPath, RTFMODE fMode); + +/** + * Creates a directory including all non-existing parent directories. + * + * @returns iprt status code. + * @param pszPath Path to the directory to create. + * @param fMode The mode of the new directories. + * @param fFlags Create flags, RTDIRCREATE_FLAGS_*. + */ +RTDECL(int) RTDirCreateFullPathEx(const char *pszPath, RTFMODE fMode, uint32_t fFlags); + +/** + * Creates a new directory with a unique name using the given template. + * + * One or more trailing X'es in the template will be replaced by random alpha + * numeric characters until a RTDirCreate succeeds or we run out of patience. + * For instance: + * "/tmp/myprog-XXXXXX" + * + * As an alternative to trailing X'es, it + * is possible to put 3 or more X'es somewhere inside the directory name. In + * the following string only the last bunch of X'es will be modified: + * "/tmp/myprog-XXX-XXX.tmp" + * + * @returns iprt status code. + * @param pszTemplate The directory name template on input. The actual + * directory name on success. Empty string on failure. + * @param fMode The mode to create the directory with. Use 0700 + * unless you have reason not to. + */ +RTDECL(int) RTDirCreateTemp(char *pszTemplate, RTFMODE fMode); + +/** + * Secure version of @a RTDirCreateTemp with a fixed mode of 0700. + * + * This function behaves in the same way as @a RTDirCreateTemp with two + * additional points. Firstly the mode is fixed to 0700. Secondly it will + * fail if it is not possible to perform the operation securely. Possible + * reasons include that the directory could be removed by another unprivileged + * user before it is used (e.g. if is created in a non-sticky /tmp directory) + * or that the path contains symbolic links which another unprivileged user + * could manipulate; however the exact criteria will be specified on a + * platform-by-platform basis as platform support is added. + * @see RTPathIsSecure for the current list of criteria. + * @returns iprt status code. + * @returns VERR_NOT_SUPPORTED if the interface can not be supported on the + * current platform at this time. + * @returns VERR_INSECURE if the directory could not be created securely. + * @param pszTemplate The directory name template on input. The + * actual directory name on success. Empty string + * on failure. + */ +RTDECL(int) RTDirCreateTempSecure(char *pszTemplate); + +/** + * Creates a new directory with a unique name by appending a number. + * + * This API differs from RTDirCreateTemp & RTDirCreateTempSecure in that it + * first tries to create the directory without any random bits, thus the best + * case result will be prettier. It also differs in that it does not take a + * template, but is instead given a template description, and will only use + * digits for the filling. + * + * For sake of convenience and debugging , the current implementation + * starts at 0 and will increment sequentally for a while before switching to + * random numbers. + * + * On success @a pszPath contains the path created. + * + * @returns iprt status code. + * @param pszPath The path to the directory. On input the base template + * name. On successful return, the unique directory we + * created. + * @param cbSize The size of the pszPath buffer. Needs enough space for + * holding the digits and the optional separator. + * @param fMode The mode of the new directory. + * @param cchDigits How many digits should the number have (zero padded). + * @param chSep The separator used between the path and the number. Can + * be zero. (optional) + */ +RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, size_t cchDigits, char chSep); + +/** + * Removes a directory if empty. + * + * @returns iprt status code. + * @param pszPath Path to the directory to remove. + */ +RTDECL(int) RTDirRemove(const char *pszPath); + +/** + * Removes a directory tree recursively. + * + * @returns iprt status code. + * @param pszPath Path to the directory to remove recursively. + * @param fFlags Flags, see RTDIRRMREC_F_XXX. + * + * @remarks This will not work on a root directory. + */ +RTDECL(int) RTDirRemoveRecursive(const char *pszPath, uint32_t fFlags); + +/** @name RTDirRemoveRecursive flags. + * @{ */ +/** Delete the content of the directory and the directory itself. */ +#define RTDIRRMREC_F_CONTENT_AND_DIR UINT32_C(0) +/** Only delete the content of the directory, omit the directory it self. */ +#define RTDIRRMREC_F_CONTENT_ONLY RT_BIT_32(0) +/** Long path hack: Don't apply RTPathAbs to the path. */ +#define RTDIRRMREC_F_NO_ABS_PATH RT_BIT_32(1) +/** Mask of valid flags. */ +#define RTDIRRMREC_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Flushes the specified directory. + * + * This API is not implemented on all systems. On some systems it may be + * unnecessary if you've already flushed the file. If you really care for your + * data and is entering dangerous territories, it doesn't hurt calling it after + * flushing and closing the file. + * + * @returns IPRT status code. + * @retval VERR_NOT_IMPLEMENTED must be expected. + * @retval VERR_NOT_SUPPORTED must be expected. + * @param pszPath Path to the directory. + */ +RTDECL(int) RTDirFlush(const char *pszPath); + +/** + * Flushes the parent directory of the specified file. + * + * This is just a wrapper around RTDirFlush. + * + * @returns IPRT status code, see RTDirFlush for details. + * @param pszChild Path to the file which parent should be flushed. + */ +RTDECL(int) RTDirFlushParent(const char *pszChild); + + + +/** + * Filter option for RTDirOpenFiltered(). + */ +typedef enum RTDIRFILTER +{ + /** The usual invalid 0 entry. */ + RTDIRFILTER_INVALID = 0, + /** No filter should be applied (and none was specified). */ + RTDIRFILTER_NONE, + /** The Windows NT filter. + * The following wildcard chars: *, ?, <, > and " + * The matching is done on the uppercased strings. */ + RTDIRFILTER_WINNT, + /** The UNIX filter. + * The following wildcard chars: *, ?, [..] + * The matching is done on exact case. */ + RTDIRFILTER_UNIX, + /** The UNIX filter, uppercased matching. + * Same as RTDIRFILTER_UNIX except that the strings are uppercased before comparing. */ + RTDIRFILTER_UNIX_UPCASED, + + /** The usual full 32-bit value. */ + RTDIRFILTER_32BIT_HACK = 0x7fffffff +} RTDIRFILTER; + + +/** + * Directory entry type. + * + * This is the RTFS_TYPE_MASK stuff shifted down 12 bits and + * identical to the BSD/LINUX ABI. See RTFS_TYPE_DIRENTRYTYPE_SHIFT. + */ +typedef enum RTDIRENTRYTYPE +{ + /** Unknown type (DT_UNKNOWN). */ + RTDIRENTRYTYPE_UNKNOWN = 0, + /** Named pipe (fifo) (DT_FIFO). */ + RTDIRENTRYTYPE_FIFO = 001, + /** Character device (DT_CHR). */ + RTDIRENTRYTYPE_DEV_CHAR = 002, + /** Directory (DT_DIR). */ + RTDIRENTRYTYPE_DIRECTORY = 004, + /** Block device (DT_BLK). */ + RTDIRENTRYTYPE_DEV_BLOCK = 006, + /** Regular file (DT_REG). */ + RTDIRENTRYTYPE_FILE = 010, + /** Symbolic link (DT_LNK). */ + RTDIRENTRYTYPE_SYMLINK = 012, + /** Socket (DT_SOCK). */ + RTDIRENTRYTYPE_SOCKET = 014, + /** Whiteout (DT_WHT). */ + RTDIRENTRYTYPE_WHITEOUT = 016 +} RTDIRENTRYTYPE; + + +/** + * Directory entry. + * + * This is inspired by the POSIX interfaces. + */ +#pragma pack(1) +typedef struct RTDIRENTRY +{ + /** The unique identifier (within the file system) of this file system object (d_ino). + * + * Together with INodeIdDevice, this field can be used as a OS wide unique id + * when both their values are not 0. This field is 0 if the information is not + * available. */ + RTINODE INodeId; + /** The entry type. (d_type) + * + * @warning RTDIRENTRYTYPE_UNKNOWN is a common return value here since not all + * file systems (or Unixes) stores the type of a directory entry and + * instead expects the user to use stat() to get it. So, when you see + * this you should use RTDirQueryUnknownType or RTDirQueryUnknownTypeEx + * to get the type, or if if you're lazy, use RTDirReadEx. + */ + RTDIRENTRYTYPE enmType; + /** The length of the filename, excluding the terminating nul character. */ + uint16_t cbName; + /** The filename. (no path) + * Using the pcbDirEntry parameter of RTDirRead makes this field variable in size. */ + char szName[260]; +} RTDIRENTRY; +#pragma pack() +/** Pointer to a directory entry. */ +typedef RTDIRENTRY *PRTDIRENTRY; +/** Pointer to a const directory entry. */ +typedef RTDIRENTRY const *PCRTDIRENTRY; + + +/** + * Directory entry with extended information. + * + * This is inspired by the PC interfaces. + */ +#pragma pack(1) +typedef struct RTDIRENTRYEX +{ + /** Full information about the object. */ + RTFSOBJINFO Info; + /** The length of the short field (number of RTUTF16 entries (not chars)). + * It is 16-bit for reasons of alignment. */ + uint16_t cwcShortName; + /** The short name for 8.3 compatibility. + * Empty string if not available. + * Since the length is a bit tricky for a UTF-8 encoded name, and since this + * is practically speaking only a windows thing, it is encoded as UCS-2. */ + RTUTF16 wszShortName[14]; + /** The length of the filename. */ + uint16_t cbName; + /** The filename. (no path) + * Using the pcbDirEntry parameter of RTDirReadEx makes this field variable in size. */ + char szName[260]; +} RTDIRENTRYEX; +#pragma pack() +/** Pointer to a directory entry. */ +typedef RTDIRENTRYEX *PRTDIRENTRYEX; +/** Pointer to a const directory entry. */ +typedef RTDIRENTRYEX const *PCRTDIRENTRYEX; + + +/** + * Opens a directory. + * + * @returns iprt status code. + * @param phDir Where to store the open directory handle. + * @param pszPath Path to the directory to open. + */ +RTDECL(int) RTDirOpen(RTDIR *phDir, const char *pszPath); + +/** @name RTDIR_F_XXX - RTDirOpenFiltered flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTDIR_F_NO_SYMLINKS RT_BIT_32(0) +/** Deny relative opening of anything above this directory. */ +#define RTDIR_F_DENY_ASCENT RT_BIT_32(1) +/** Don't follow symbolic links in the final component. */ +#define RTDIR_F_NO_FOLLOW RT_BIT_32(2) +/** Long path hack: Don't apply RTPathAbs to the path. */ +#define RTDIR_F_NO_ABS_PATH RT_BIT_32(3) +/** Valid flag mask. */ +#define RTDIR_F_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Opens a directory with flags and optional filtering. + * + * @returns IPRT status code. + * @retval VERR_IS_A_SYMLINK if RTDIR_F_NO_FOLLOW is set, @a enmFilter is + * RTDIRFILTER_NONE and @a pszPath points to a symbolic link and does + * not end with a slash. Note that on Windows this does not apply to + * file symlinks, only directory symlinks, for the file variant + * VERR_NOT_A_DIRECTORY will be returned. + * + * @param phDir Where to store the open directory handle. + * @param pszPath Path to the directory to search, this must include wildcards. + * @param enmFilter The kind of filter to apply. Setting this to RTDIRFILTER_NONE makes + * this function behave like RTDirOpen. + * @param fFlags Open flags, RTDIR_F_XXX. + * + */ +RTDECL(int) RTDirOpenFiltered(RTDIR *phDir, const char *pszPath, RTDIRFILTER enmFilter, uint32_t fFlags); + +/** + * Closes a directory. + * + * @returns iprt status code. + * @param hDir Handle to open directory returned by RTDirOpen() or + * RTDirOpenFiltered(). + */ +RTDECL(int) RTDirClose(RTDIR hDir); + +/** + * Checks if the supplied directory handle is valid. + * + * @returns true if valid. + * @returns false if invalid. + * @param hDir The directory handle. + */ +RTDECL(bool) RTDirIsValid(RTDIR hDir); + +/** + * Reads the next entry in the directory. + * + * @returns VINF_SUCCESS and data in pDirEntry on success. + * @returns VERR_NO_MORE_FILES when the end of the directory has been reached. + * @returns VERR_BUFFER_OVERFLOW if the buffer is too small to contain the filename. If + * pcbDirEntry is specified it will be updated with the required buffer size. + * @returns suitable iprt status code on other errors. + * + * @param hDir Handle to the open directory. + * @param pDirEntry Where to store the information about the next + * directory entry on success. + * @param pcbDirEntry Optional parameter used for variable buffer size. + * + * On input the variable pointed to contains the size of the pDirEntry + * structure. This must be at least OFFSET(RTDIRENTRY, szName[2]) bytes. + * + * On successful output the field is updated to + * OFFSET(RTDIRENTRY, szName[pDirEntry->cbName + 1]). + * + * When the data doesn't fit in the buffer and VERR_BUFFER_OVERFLOW is + * returned, this field contains the required buffer size. + * + * The value is unchanged in all other cases. + */ +RTDECL(int) RTDirRead(RTDIR hDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry); + +/** + * Reads the next entry in the directory returning extended information. + * + * @returns VINF_SUCCESS and data in pDirEntry on success. + * @returns VERR_NO_MORE_FILES when the end of the directory has been reached. + * @returns VERR_BUFFER_OVERFLOW if the buffer is too small to contain the filename. If + * pcbDirEntry is specified it will be updated with the required buffer size. + * @returns suitable iprt status code on other errors. + * + * @param hDir Handle to the open directory. + * @param pDirEntry Where to store the information about the next + * directory entry on success. + * @param pcbDirEntry Optional parameter used for variable buffer size. + * + * On input the variable pointed to contains the size of the pDirEntry + * structure. This must be at least OFFSET(RTDIRENTRYEX, szName[2]) bytes. + * + * On successful output the field is updated to + * OFFSET(RTDIRENTRYEX, szName[pDirEntry->cbName + 1]). + * + * When the data doesn't fit in the buffer and VERR_BUFFER_OVERFLOW is + * returned, this field contains the required buffer size. + * + * The value is unchanged in all other cases. + * @param enmAdditionalAttribs + * Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + */ +RTDECL(int) RTDirReadEx(RTDIR hDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags); + +/** + * Wrapper around RTDirReadEx that does the directory entry buffer handling. + * + * Call RTDirReadExAFree to free the buffers allocated by this function. + * + * @returns IPRT status code, see RTDirReadEx() for details. + * + * @param hDir Handle to the open directory. + * @param ppDirEntry Pointer to the directory entry pointer. Initialize this + * to NULL before the first call. + * @param pcbDirEntry Where the API caches the allocation size. Set this to + * zero before the first call. + * @param enmAddAttr See RTDirReadEx. + * @param fFlags See RTDirReadEx. + */ +RTDECL(int) RTDirReadExA(RTDIR hDir, PRTDIRENTRYEX *ppDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags); + +/** + * Frees the buffer allocated by RTDirReadExA. + * + * @param ppDirEntry Pointer to the directory entry pointer. + * @param pcbDirEntry Where the API caches the allocation size. + */ +RTDECL(void) RTDirReadExAFree(PRTDIRENTRYEX *ppDirEntry, size_t *pcbDirEntry); + +/** + * Resolves RTDIRENTRYTYPE_UNKNOWN values returned by RTDirRead. + * + * @returns IPRT status code (see RTPathQueryInfo). + * @param pszComposedName The path to the directory entry. The caller must + * compose this, it's NOT sufficient to pass + * RTDIRENTRY::szName! + * @param fFollowSymlinks Whether to follow symbolic links or not. + * @param penmType Pointer to the RTDIRENTRY::enmType member. If this + * is not RTDIRENTRYTYPE_UNKNOWN and, if + * @a fFollowSymlinks is false, not + * RTDIRENTRYTYPE_SYMLINK, the function will return + * immediately without doing anything. Otherwise it + * will use RTPathQueryInfo to try figure out the + * correct value. On failure, this will be unchanged. + */ +RTDECL(int) RTDirQueryUnknownType(const char *pszComposedName, bool fFollowSymlinks, RTDIRENTRYTYPE *penmType); + +/** + * Resolves RTDIRENTRYTYPE_UNKNOWN values returned by RTDirRead, extended + * version. + * + * @returns IPRT status code (see RTPathQueryInfo). + * @param pszComposedName The path to the directory entry. The caller must + * compose this, it's NOT sufficient to pass + * RTDIRENTRY::szName! + * @param fFollowSymlinks Whether to follow symbolic links or not. + * @param penmType Pointer to the RTDIRENTRY::enmType member or + * similar. Will NOT be checked on input. + * @param pObjInfo The object info buffer to use with RTPathQueryInfo. + */ +RTDECL(int) RTDirQueryUnknownTypeEx(const char *pszComposedName, bool fFollowSymlinks, RTDIRENTRYTYPE *penmType, PRTFSOBJINFO pObjInfo); + +/** + * Checks if the directory entry returned by RTDirRead is '.', '..' or similar. + * + * @returns true / false. + * @param pDirEntry The directory entry to check. + */ +RTDECL(bool) RTDirEntryIsStdDotLink(PRTDIRENTRY pDirEntry); + +/** + * Checks if the directory entry returned by RTDirReadEx is '.', '..' or + * similar. + * + * @returns true / false. + * @param pDirEntryEx The extended directory entry to check. + */ +RTDECL(bool) RTDirEntryExIsStdDotLink(PCRTDIRENTRYEX pDirEntryEx); + +/** + * Rewind and restart the directory reading. + * + * @returns IRPT status code. + * @param hDir The directory handle to rewind. + */ +RTDECL(int) RTDirRewind(RTDIR hDir); + +/** + * Renames a file. + * + * Identical to RTPathRename except that it will ensure that the source is a directory. + * + * @returns IPRT status code. + * @returns VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + * @param fRename See RTPathRename. + */ +RTDECL(int) RTDirRename(const char *pszSrc, const char *pszDst, unsigned fRename); + + +/** + * Query information about an open directory. + * + * @returns iprt status code. + * + * @param hDir Handle to the open directory. + * @param pObjInfo Object information structure to be filled on successful return. + * @param enmAdditionalAttribs Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + */ +RTR3DECL(int) RTDirQueryInfo(RTDIR hDir, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs); + + +/** + * Changes one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @returns VERR_NOT_SUPPORTED is returned if the operation isn't supported by the OS. + * + * @param hDir Handle to the open directory. + * @param pAccessTime Pointer to the new access time. NULL if not to be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if not to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + */ +RTR3DECL(int) RTDirSetTimes(RTDIR hDir, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + + +/** + * Changes the mode flags of an open directory. + * + * The API requires at least one of the mode flag sets (Unix/Dos) to + * be set. The type is ignored. + * + * @returns iprt status code. + * @param hDir Handle to the open directory. + * @param fMode The new file mode, see @ref grp_rt_fs for details. + */ +RTDECL(int) RTDirSetMode(RTDIR hDir, RTFMODE fMode); + + +/** @defgroup grp_rt_dir_rel Directory relative APIs + * + * This group of APIs allows working with paths that are relative to an open + * directory, therebye eliminating some classic path related race conditions on + * systems with native support for these kinds of operations. + * + * On NT (Windows) there is native support for addressing files, directories and + * stuff _below_ the open directory. It is not possible to go upwards + * (hDir:../../grandparent), at least not with NTFS, forcing us to use the + * directory path as a fallback and opening us to potential races. + * + * On most unix-like systems here is now native support for all of this. + * + * @{ */ + +/** + * Open a file relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory to open relative to. + * @param pszRelFilename The relative path to the file. + * @param fOpen Open flags, i.e a combination of the RTFILE_O_XXX + * defines. The ACCESS, ACTION and DENY flags are + * mandatory! + * @param phFile Where to store the handle to the opened file. + * + * @sa RTFileOpen + */ +RTDECL(int) RTDirRelFileOpen(RTDIR hDir, const char *pszRelFilename, uint64_t fOpen, PRTFILE phFile); + + + +/** + * Opens a directory relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory to open relative to. + * @param pszDir The relative path to the directory to open. + * @param phDir Where to store the directory handle. + * + * @sa RTDirOpen + */ +RTDECL(int) RTDirRelDirOpen(RTDIR hDir, const char *pszDir, RTDIR *phDir); + +/** + * Opens a directory relative to @a hDir, with flags and optional filtering. + * + * @returns IPRT status code. + * @retval VERR_IS_A_SYMLINK if RTDIR_F_NO_FOLLOW is set, @a enmFilter is + * RTDIRFILTER_NONE and @a pszPath points to a symbolic link and does + * not end with a slash. Note that on Windows this does not apply to + * file symlinks, only directory symlinks, for the file variant + * VERR_NOT_A_DIRECTORY will be returned. + * + * @param hDir The directory to open relative to. + * @param pszDirAndFilter The relative path to the directory to search, this + * must include wildcards. + * @param enmFilter The kind of filter to apply. Setting this to + * RTDIRFILTER_NONE makes this function behave like + * RTDirOpen. + * @param fFlags Open flags, RTDIR_F_XXX. + * @param phDir Where to store the directory handle. + * + * @sa RTDirOpenFiltered + */ +RTDECL(int) RTDirRelDirOpenFiltered(RTDIR hDir, const char *pszDirAndFilter, RTDIRFILTER enmFilter, + uint32_t fFlags, RTDIR *phDir); + +/** + * Creates a directory relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the directory to create. + * @param fMode The mode of the new directory. + * @param fCreate Create flags, RTDIRCREATE_FLAGS_XXX. + * @param phSubDir Where to return the handle of the created directory. + * Optional. + * + * @sa RTDirCreate + */ +RTDECL(int) RTDirRelDirCreate(RTDIR hDir, const char *pszRelPath, RTFMODE fMode, uint32_t fCreate, RTDIR *phSubDir); + +/** + * Removes a directory relative to @a hDir if empty. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the directory to remove. + * + * @sa RTDirRemove + */ +RTDECL(int) RTDirRelDirRemove(RTDIR hDir, const char *pszRelPath); + + +/** + * Query information about a file system object relative to @a hDir. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the object exists, information returned. + * @retval VERR_PATH_NOT_FOUND if any but the last component in the specified + * path was not found or was not a directory. + * @retval VERR_FILE_NOT_FOUND if the object does not exist (but path to the + * parent directory exists). + * + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param pObjInfo Object information structure to be filled on successful + * return. + * @param enmAddAttr Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @sa RTPathQueryInfoEx + */ +RTDECL(int) RTDirRelPathQueryInfo(RTDIR hDir, const char *pszRelPath, PRTFSOBJINFO pObjInfo, + RTFSOBJATTRADD enmAddAttr, uint32_t fFlags); + +/** + * Changes the mode flags of a file system object relative to @a hDir. + * + * The API requires at least one of the mode flag sets (Unix/Dos) to + * be set. The type is ignored. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param fMode The new file mode, see @ref grp_rt_fs for details. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @sa RTPathSetMode + */ +RTDECL(int) RTDirRelPathSetMode(RTDIR hDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags); + +/** + * Changes one or more of the timestamps associated of file system object + * relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param pAccessTime Pointer to the new access time. + * @param pModificationTime Pointer to the new modification time. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + * + * @sa RTPathSetTimesEx + */ +RTDECL(int) RTDirRelPathSetTimes(RTDIR hDir, const char *pszRelPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags); + +/** + * Changes the owner and/or group of a file system object relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param uid The new file owner user id. Pass NIL_RTUID to leave + * this unchanged. + * @param gid The new group id. Pass NIL_RTGID to leave this + * unchanged. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @sa RTPathSetOwnerEx + */ +RTDECL(int) RTDirRelPathSetOwner(RTDIR hDir, const char *pszRelPath, uint32_t uid, uint32_t gid, uint32_t fFlags); + +/** + * Renames a directory relative path within a filesystem. + * + * This will rename symbolic links. If RTPATHRENAME_FLAGS_REPLACE is used and + * pszDst is a symbolic link, it will be replaced and not its target. + * + * @returns IPRT status code. + * @param hDirSrc The directory the source path is relative to. + * @param pszSrc The source path, relative to @a hDirSrc. + * @param hDirDst The directory the destination path is relative to. + * @param pszDst The destination path, relative to @a hDirDst. + * @param fRename Rename flags, RTPATHRENAME_FLAGS_XXX. + * + * @sa RTPathRename + */ +RTDECL(int) RTDirRelPathRename(RTDIR hDirSrc, const char *pszSrc, RTDIR hDirDst, const char *pszDst, unsigned fRename); + +/** + * Removes the last component of the directory relative path. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param fUnlink Unlink flags, RTPATHUNLINK_FLAGS_XXX. + * + * @sa RTPathUnlink + */ +RTDECL(int) RTDirRelPathUnlink(RTDIR hDir, const char *pszRelPath, uint32_t fUnlink); + + + +/** + * Creates a symbolic link (@a pszSymlink) relative to @a hDir targeting @a + * pszTarget. + * + * @returns IPRT status code. + * @param hDir The directory @a pszSymlink is relative to. + * @param pszSymlink The relative path of the symbolic link. + * @param pszTarget The path to the symbolic link target. This is + * relative to @a pszSymlink or an absolute path. + * @param enmType The symbolic link type. For Windows compatability + * it is very important to set this correctly. When + * RTSYMLINKTYPE_UNKNOWN is used, the API will try + * make a guess and may attempt query information + * about @a pszTarget in the process. + * @param fCreate Create flags, RTSYMLINKCREATE_FLAGS_XXX. + * + * @sa RTSymlinkCreate + */ +RTDECL(int) RTDirRelSymlinkCreate(RTDIR hDir, const char *pszSymlink, const char *pszTarget, + RTSYMLINKTYPE enmType, uint32_t fCreate); + +/** + * Read the symlink target relative to @a hDir. + * + * @returns IPRT status code. + * @retval VERR_NOT_SYMLINK if @a pszSymlink does not specify a symbolic link. + * @retval VERR_BUFFER_OVERFLOW if the link is larger than @a cbTarget. The + * buffer will contain what all we managed to read, fully terminated + * if @a cbTarget > 0. + * + * @param hDir The directory @a pszSymlink is relative to. + * @param pszSymlink The relative path to the symbolic link that should + * be read. + * @param pszTarget The target buffer. + * @param cbTarget The size of the target buffer. + * @param fRead Read flags, RTSYMLINKREAD_FLAGS_XXX. + * + * @sa RTSymlinkRead + */ +RTDECL(int) RTDirRelSymlinkRead(RTDIR hDir, const char *pszSymlink, char *pszTarget, size_t cbTarget, uint32_t fRead); + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_dir_h */ + diff --git a/include/iprt/dvm.h b/include/iprt/dvm.h new file mode 100644 index 00000000..25f12526 --- /dev/null +++ b/include/iprt/dvm.h @@ -0,0 +1,639 @@ +/** @file + * IPRT Disk Volume Management API (DVM). + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_dvm_h +#define IPRT_INCLUDED_dvm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_dvm IPRT Disk Volume Management + * @{ + */ + +/** + * Volume type. + * Comparable to the FS type in MBR partition maps + * or the partition type GUIDs in GPT tables. + */ +typedef enum RTDVMVOLTYPE +{ + /** Invalid. */ + RTDVMVOLTYPE_INVALID = 0, + /** Unknown. */ + RTDVMVOLTYPE_UNKNOWN, + /** Volume hosts a NTFS filesystem. */ + RTDVMVOLTYPE_NTFS, + /** Volume hosts a FAT12 filesystem. */ + RTDVMVOLTYPE_FAT12, + /** Volume hosts a FAT16 filesystem. */ + RTDVMVOLTYPE_FAT16, + /** Volume hosts a FAT32 filesystem. */ + RTDVMVOLTYPE_FAT32, + + /** EFI system partition (c12a7328-f81f-11d2-ba4b-00a0c93ec93b). */ + RTDVMVOLTYPE_EFI_SYSTEM, + + /** Volume hosts a Mac OS X HFS or HFS+ filesystem. */ + RTDVMVOLTYPE_DARWIN_HFS, + /** Volume hosts a Mac OS X APFS filesystem. */ + RTDVMVOLTYPE_DARWIN_APFS, + + /** Volume hosts a Linux swap. */ + RTDVMVOLTYPE_LINUX_SWAP, + /** Volume hosts a Linux filesystem. */ + RTDVMVOLTYPE_LINUX_NATIVE, + /** Volume hosts a Linux LVM. */ + RTDVMVOLTYPE_LINUX_LVM, + /** Volume hosts a Linux SoftRaid. */ + RTDVMVOLTYPE_LINUX_SOFTRAID, + + /** Volume hosts a FreeBSD disklabel. */ + RTDVMVOLTYPE_FREEBSD, + /** Volume hosts a NetBSD disklabel. */ + RTDVMVOLTYPE_NETBSD, + /** Volume hosts a OpenBSD disklabel. */ + RTDVMVOLTYPE_OPENBSD, + /** Volume hosts a Solaris volume. */ + RTDVMVOLTYPE_SOLARIS, + + /** Volume hosts a Windows basic data partition . */ + RTDVMVOLTYPE_WIN_BASIC, + /** Volume hosts a Microsoft reserved partition (MSR). */ + RTDVMVOLTYPE_WIN_MSR, + /** Volume hosts a Windows logical disk manager (LDM) metadata partition. */ + RTDVMVOLTYPE_WIN_LDM_META, + /** Volume hosts a Windows logical disk manager (LDM) data partition. */ + RTDVMVOLTYPE_WIN_LDM_DATA, + /** Volume hosts a Windows recovery partition. */ + RTDVMVOLTYPE_WIN_RECOVERY, + /** Volume hosts a storage spaces partition. */ + RTDVMVOLTYPE_WIN_STORAGE_SPACES, + + /** Volume hosts an IBM general parallel file system (GPFS). */ + RTDVMVOLTYPE_IBM_GPFS, + + /** OS/2 (Arca Noae) type 1 partition. */ + RTDVMVOLTYPE_ARCA_OS2, + + /** End of the valid values. */ + RTDVMVOLTYPE_END, + /** Usual 32bit hack. */ + RTDVMVOLTYPE_32BIT_HACK = 0x7fffffff +} RTDVMVOLTYPE; + +/** @defgroup grp_dvm_flags Flags used by RTDvmCreate. + * @{ */ +/** DVM flags - Blocks are always marked as unused if the volume has + * no block status callback set. + * The default is to mark them as used. */ +#define DVM_FLAGS_NO_STATUS_CALLBACK_MARK_AS_UNUSED RT_BIT_32(0) +/** DVM flags - Space which is unused in the map will be marked as used + * when calling RTDvmMapQueryBlockStatus(). */ +#define DVM_FLAGS_UNUSED_SPACE_MARK_AS_USED RT_BIT_32(1) +/** Mask of all valid flags. */ +#define DVM_FLAGS_VALID_MASK UINT32_C(0x00000003) +/** @} */ + + +/** @defgroup grp_dvm_vol_flags Volume flags used by RTDvmVolumeGetFlags(). + * @{ */ +/** Volume flags - Volume is bootable. */ +#define DVMVOLUME_FLAGS_BOOTABLE RT_BIT_64(0) +/** Volume flags - Volume is active. */ +#define DVMVOLUME_FLAGS_ACTIVE RT_BIT_64(1) +/** Volume is contiguous on the underlying medium and RTDvmVolumeQueryRange(). */ +#define DVMVOLUME_F_CONTIGUOUS RT_BIT_64(2) +/** @} */ + +/** A handle to a volume manager. */ +typedef struct RTDVMINTERNAL *RTDVM; +/** A pointer to a volume manager handle. */ +typedef RTDVM *PRTDVM; +/** NIL volume manager handle. */ +#define NIL_RTDVM ((RTDVM)~0) + +/** A handle to a volume in a volume map. */ +typedef struct RTDVMVOLUMEINTERNAL *RTDVMVOLUME; +/** A pointer to a volume handle. */ +typedef RTDVMVOLUME *PRTDVMVOLUME; +/** NIL volume handle. */ +#define NIL_RTDVMVOLUME ((RTDVMVOLUME)~0) + +/** + * Callback for querying the block allocation status of a volume. + * + * @returns IPRT status code. + * @param pvUser Opaque user data passed when setting the callback. + * @param off Offset relative to the start of the volume. + * @param cb Range to check in bytes. + * @param pfAllocated Where to store the allocation status on success. + */ +typedef DECLCALLBACKTYPE(int, FNDVMVOLUMEQUERYBLOCKSTATUS,(void *pvUser, uint64_t off, uint64_t cb, bool *pfAllocated)); +/** Pointer to a query block allocation status callback. */ +typedef FNDVMVOLUMEQUERYBLOCKSTATUS *PFNDVMVOLUMEQUERYBLOCKSTATUS; + +/** + * Create a new volume manager. + * + * @returns IPRT status. + * @param phVolMgr Where to store the handle to the volume manager on + * success. + * @param hVfsFile The disk/container/whatever. + * @param cbSector Size of one sector in bytes. + * @param fFlags Combination of RTDVM_FLAGS_* + */ +RTDECL(int) RTDvmCreate(PRTDVM phVolMgr, RTVFSFILE hVfsFile, uint32_t cbSector, uint32_t fFlags); + +/** + * Retain a given volume manager. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVolMgr The volume manager to retain. + */ +RTDECL(uint32_t) RTDvmRetain(RTDVM hVolMgr); + +/** + * Releases a given volume manager. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVolMgr The volume manager to release. + */ +RTDECL(uint32_t) RTDvmRelease(RTDVM hVolMgr); + +/** + * Probes the underyling disk for the best volume manager format handler + * and opens it. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no backend can handle the volume map on the disk. + * @param hVolMgr The volume manager handle. + */ +RTDECL(int) RTDvmMapOpen(RTDVM hVolMgr); + +/** + * Initializes a new volume map using the given format handler. + * + * @returns IPRT status code. + * @param hVolMgr The volume manager handle. + * @param pszFmt The format to use for the new map. + */ +RTDECL(int) RTDvmMapInitialize(RTDVM hVolMgr, const char *pszFmt); + +/** + * Gets the name of the currently used format of the disk map. + * + * @returns Name of the format. + * @param hVolMgr The volume manager handle. + */ +RTDECL(const char *) RTDvmMapGetFormatName(RTDVM hVolMgr); + +/** + * DVM format types. + */ +typedef enum RTDVMFORMATTYPE +{ + /** Invalid zero value. */ + RTDVMFORMATTYPE_INVALID = 0, + /** Master boot record. */ + RTDVMFORMATTYPE_MBR, + /** GUID partition table. */ + RTDVMFORMATTYPE_GPT, + /** BSD labels. */ + RTDVMFORMATTYPE_BSD_LABEL, + /** End of valid values. */ + RTDVMFORMATTYPE_END, + /** 32-bit type size hack. */ + RTDVMFORMATTYPE_32BIT_HACK = 0x7fffffff +} RTDVMFORMATTYPE; + +/** + * Gets the format type of the current disk map. + * + * @returns Format type. RTDVMFORMATTYPE_INVALID on invalid input. + * @param hVolMgr The volume manager handle. + */ +RTDECL(RTDVMFORMATTYPE) RTDvmMapGetFormatType(RTDVM hVolMgr); + +/** + * Gets the UUID of the disk if applicable. + * + * Disks using the MBR format may return the 32-bit disk identity in the + * u32TimeLow field and set the rest to zero. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the partition scheme doesn't do UUIDs. + * @retval VINF_NOT_SUPPORTED if non-UUID disk ID is returned. + * @param hVolMgr The volume manager handle. + * @param pUuid Where to return the UUID. + * + * @todo It's quite possible this should be turned into a map-level edition of + * RTDvmVolumeQueryProp... + */ +RTDECL(int) RTDvmMapQueryDiskUuid(RTDVM hVolMgr, PRTUUID pUuid); + +/** + * Gets the number of valid partitions in the map. + * + * @returns The number of valid volumes in the map or UINT32_MAX on failure. + * @param hVolMgr The volume manager handle. + */ +RTDECL(uint32_t) RTDvmMapGetValidVolumes(RTDVM hVolMgr); + +/** + * Gets the maximum number of partitions the map can hold. + * + * @returns The maximum number of volumes in the map or UINT32_MAX on failure. + * @param hVolMgr The volume manager handle. + */ +RTDECL(uint32_t) RTDvmMapGetMaxVolumes(RTDVM hVolMgr); + +/** + * Get the first valid volume from a map. + * + * @returns IPRT status code. + * @param hVolMgr The volume manager handle. + * @param phVol Where to store the handle to the first volume on + * success. Release with RTDvmVolumeRelease(). + */ +RTDECL(int) RTDvmMapQueryFirstVolume(RTDVM hVolMgr, PRTDVMVOLUME phVol); + +/** + * Get the first valid volume from a map. + * + * @returns IPRT status code. + * @param hVolMgr The volume manager handle. + * @param hVol Handle of the current volume. + * @param phVolNext Where to store the handle to the next volume on + * success. Release with RTDvmVolumeRelease(). + */ +RTDECL(int) RTDvmMapQueryNextVolume(RTDVM hVolMgr, RTDVMVOLUME hVol, PRTDVMVOLUME phVolNext); + +/** + * Returns whether the given block on the disk is in use. + * + * @returns IPRT status code. + * @param hVolMgr The volume manager handle. + * @param off The start offset to check for. + * @param cb The range in bytes to check. + * @param pfAllocated Where to store the in-use status on success. + * + * @remark This method will return true even if a part of the range is not in use. + */ +RTDECL(int) RTDvmMapQueryBlockStatus(RTDVM hVolMgr, uint64_t off, uint64_t cb, bool *pfAllocated); + +/** + * Partition/map table location information. + * @sa RTDvmMapQueryTableLocations + */ +typedef struct RTDVMTABLELOCATION +{ + /** The byte offset on the underlying media. */ + uint64_t off; + /** The table size in bytes. */ + uint64_t cb; + /** Number of padding bytes / free space between the actual table and + * first partition. */ + uint64_t cbPadding; +} RTDVMTABLELOCATION; +/** Pointer to partition table location info. */ +typedef RTDVMTABLELOCATION *PRTDVMTABLELOCATION; +/** Pointer to const partition table location info. */ +typedef RTDVMTABLELOCATION const *PCRTDVMTABLELOCATION; + + +/** @name RTDVMMAPQTABLOC_F_XXX - Flags for RTDvmMapQueryTableLocations + * @{ */ +/** Make sure GPT includes the protective MBR. */ +#define RTDVMMAPQTABLOC_F_INCLUDE_LEGACY RT_BIT_32(0) +/** Valid flags. */ +#define RTDVMMAPQTABLOC_F_VALID_MASK UINT32_C(1) +/** @} */ + +/** + * Query the partition table locations. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the table is too small, @a *pcActual will be + * set to the required size. + * @retval VERR_BUFFER_UNDERFLOW if the table is too big and @a pcActual is + * NULL. + * @param hVolMgr The volume manager handle. + * @param fFlags Flags, see RTDVMMAPQTABLOC_F_XXX. + * @param paLocations Where to return the info. This can be NULL if @a + * cLocations is zero and @a pcActual is given. + * @param cLocations The size of @a paLocations in items. + * @param pcActual Where to return the actual number of locations, or + * on VERR_BUFFER_OVERFLOW the necessary table size. + * Optional, when not specified the cLocations value + * must match exactly or it fails with + * VERR_BUFFER_UNDERFLOW. + */ +RTDECL(int) RTDvmMapQueryTableLocations(RTDVM hVolMgr, uint32_t fFlags, + PRTDVMTABLELOCATION paLocations, size_t cLocations, size_t *pcActual); + +/** + * Retains a valid volume handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVol The volume to retain. + */ +RTDECL(uint32_t) RTDvmVolumeRetain(RTDVMVOLUME hVol); + +/** + * Releases a valid volume handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVol The volume to release. + */ +RTDECL(uint32_t) RTDvmVolumeRelease(RTDVMVOLUME hVol); + +/** + * Sets the callback to query the block allocation status for a volume. + * This overwrites any other callback set previously. + * + * @returns nothing. + * @param hVol The volume handle. + * @param pfnQueryBlockStatus The callback to set. Can be NULL to disable + * a previous callback. + * @param pvUser Opaque user data passed in the callback. + */ +RTDECL(void) RTDvmVolumeSetQueryBlockStatusCallback(RTDVMVOLUME hVol, + PFNDVMVOLUMEQUERYBLOCKSTATUS pfnQueryBlockStatus, + void *pvUser); + +/** + * Get the size of a volume in bytes. + * + * @returns Size of the volume in bytes or 0 on failure. + * @param hVol The volume handle. + */ +RTDECL(uint64_t) RTDvmVolumeGetSize(RTDVMVOLUME hVol); + +/** + * Gets the name of the volume if supported. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param ppszVolName Where to store the name of the volume on success. + * The string must be freed with RTStrFree(). + */ +RTDECL(int) RTDvmVolumeQueryName(RTDVMVOLUME hVol, char **ppszVolName); + +/** + * Get the volume type of the volume if supported. + * + * @returns The volume type on success, DVMVOLTYPE_INVALID if hVol is invalid. + * @param hVol The volume handle. + */ +RTDECL(RTDVMVOLTYPE) RTDvmVolumeGetType(RTDVMVOLUME hVol); + +/** + * Get the volume flags of the volume if supported. + * + * @returns The volume flags or UINT64_MAX on failure. + * @param hVol The volume handle. + */ +RTDECL(uint64_t) RTDvmVolumeGetFlags(RTDVMVOLUME hVol); + +/** + * Queries the range of the given volume on the underlying medium. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the DVMVOLUME_F_CONTIGUOUS flag is not returned by RTDvmVolumeGetFlags(). + * @param hVol The volume handle. + * @param poffStart Where to store the start offset in bytes on the underlying medium. + * @param poffLast Where to store the last offset in bytes on the underlying medium (inclusive). + */ +RTDECL(int) RTDvmVolumeQueryRange(RTDVMVOLUME hVol, uint64_t *poffStart, uint64_t *poffLast); + +/** + * Returns the partition/whatever table location of the volume. + * + * For volume format with a single table, like GPT and BSD-labels, it will + * return the location of that table. Though for GPT, the fake MBR will not be + * included. + * + * For logical (extended) MBR-style volumes, this will return the location of + * the extended partition table. For primary volumes the MBR location is + * returned. The special MBR case is why this operation is done on the volume + * rather than the volume manager. + * + * Using RTDvmVolumeGetIndex with RTDVMVOLIDX_IN_PART_TABLE should get you + * the index in the table returned by this function. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param poffTable Where to return the byte offset on the underlying + * media of the (partition/volume/whatever) table. + * @param pcbTable Where to return the table size in bytes. (This does + * not include any alignment padding or such, just + * padding up to sector/block size.) + */ +RTDECL(int) RTDvmVolumeQueryTableLocation(RTDVMVOLUME hVol, uint64_t *poffTable, uint64_t *pcbTable); + +/** + * RTDvmVolumeGetIndex indexes. + */ +typedef enum RTDVMVOLIDX +{ + /** Invalid zero value. */ + RTDVMVOLIDX_INVALID = 0, + /** Index matching the host's volume numbering. + * This is a pseudo index, that gets translated to one of the others depending + * on which host we're running on. */ + RTDVMVOLIDX_HOST, + /** Only consider user visible ones, i.e. don't count MBR extended partition + * entries and such like. */ + RTDVMVOLIDX_USER_VISIBLE, + /** Index when all volumes, user visible, hidden, special, whatever ones are + * included. + * + * For MBR this is 1-based index where all primary entires are included whether + * in use or not. Only non-empty entries in extended tables are counted, though + * the forward link is included. */ + RTDVMVOLIDX_ALL, + /** The raw index within the partition/volume/whatever table. This have a kind + * of special meaning to MBR, where there are multiple tables. */ + RTDVMVOLIDX_IN_TABLE, + /** Follows the linux /dev/sdaX convention as closely as absolutely possible. */ + RTDVMVOLIDX_LINUX, + /** End of valid indexes. */ + RTDVMVOLIDX_END, + /** Make sure the type is 32-bit. */ + RTDVMVOLIDX_32BIT_HACK = 0x7fffffff +} RTDVMVOLIDX; + +/** + * Gets the tiven index for the specified volume. + * + * @returns The requested index, UINT32_MAX on failure. + * @param hVol The volume handle. + * @param enmIndex Which kind of index to get for the volume. + */ +RTDECL(uint32_t) RTDvmVolumeGetIndex(RTDVMVOLUME hVol, RTDVMVOLIDX enmIndex); + +/** + * Volume properties queriable via RTDvmVolumeQueryProp. + * + * @note Integer values can typically be queried in multiple sizes. This is + * handled by the frontend code. The format specific backends only + * have to handle the smallest allowed size. + */ +typedef enum RTDVMVOLPROP +{ + /** Customary invalid zero value. */ + RTDVMVOLPROP_INVALID = 0, + /** unsigned[16,32,64]: MBR first cylinder (0-based, CHS). */ + RTDVMVOLPROP_MBR_FIRST_CYLINDER, + /** unsigned[8,16,32,64]: MBR first head (0-based, CHS). */ + RTDVMVOLPROP_MBR_FIRST_HEAD, + /** unsigned[8,16,32,64]: MBR first sector (1-based, CHS). */ + RTDVMVOLPROP_MBR_FIRST_SECTOR, + /** unsigned[16,32,64]: MBR last cylinder (0-based, CHS). */ + RTDVMVOLPROP_MBR_LAST_CYLINDER, + /** unsigned[8,16,32,64]: MBR last head (0-based, CHS). */ + RTDVMVOLPROP_MBR_LAST_HEAD, + /** unsigned[8,16,32,64]: MBR last sector (1-based, CHS). */ + RTDVMVOLPROP_MBR_LAST_SECTOR, + /** unsigned[8,16,32,64]: MBR partition type. */ + RTDVMVOLPROP_MBR_TYPE, + /** RTUUID: GPT volume type. */ + RTDVMVOLPROP_GPT_TYPE, + /** RTUUID: GPT volume UUID. */ + RTDVMVOLPROP_GPT_UUID, + /** End of valid values. */ + RTDVMVOLPROP_END, + /** Make sure the type is 32-bit. */ + RTDVMVOLPROP_32BIT_HACK = 0x7fffffff +} RTDVMVOLPROP; + +/** + * Query a generic volume property. + * + * This is an extensible interface for retrieving mostly format specific + * information, or information that's not commonly used. (It's modeled after + * RTLdrQueryPropEx.) + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the property query isn't supported (either all + * or that specific property). The caller must handle this result. + * @retval VERR_NOT_FOUND is currently not returned, but intended for cases + * where it wasn't present in the tables. + * @retval VERR_INVALID_FUNCTION if the @a enmProperty value is wrong. + * @retval VERR_INVALID_PARAMETER if the fixed buffer size is wrong. Correct + * size in @a *pcbBuf. + * @retval VERR_BUFFER_OVERFLOW if the property doesn't have a fixed size + * buffer and the buffer isn't big enough. Correct size in @a *pcbBuf. + * @retval VERR_INVALID_HANDLE if the handle is invalid. + * @param hVol Handle to the volume. + * @param enmProperty The property to query. + * @param pvBuf Pointer to the input / output buffer. In most cases + * it's only used for returning data. + * @param cbBuf The size of the buffer. + * @param pcbBuf Where to return the amount of data returned. On + * buffer size errors, this is set to the correct size. + * Optional. + * @sa RTDvmVolumeGetPropU64 + */ +RTDECL(int) RTDvmVolumeQueryProp(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, void *pvBuf, size_t cbBuf, size_t *pcbBuf); + +/** + * Wrapper around RTDvmVolumeQueryProp for simplifying getting unimportant + * integer properties. + * + * @returns The property value if supported and found, the default value if not. + * Errors other than VERR_NOT_SUPPORTED and VERR_NOT_FOUND are + * asserted. + * @param hVol Handle to the volume. + * @param enmProperty The property to query. + * @param uDefault The value to return on error. + * @sa RTDvmVolumeQueryProp + */ +RTDECL(uint64_t) RTDvmVolumeGetPropU64(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, uint64_t uDefault); + +/** + * Reads data from the given volume. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param off Where to start reading from - 0 is the beginning of + * the volume. + * @param pvBuf Where to store the read data. + * @param cbRead How many bytes to read. + */ +RTDECL(int) RTDvmVolumeRead(RTDVMVOLUME hVol, uint64_t off, void *pvBuf, size_t cbRead); + +/** + * Writes data to the given volume. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param off Where to start writing to - 0 is the beginning of + * the volume. + * @param pvBuf The data to write. + * @param cbWrite How many bytes to write. + */ +RTDECL(int) RTDvmVolumeWrite(RTDVMVOLUME hVol, uint64_t off, const void *pvBuf, size_t cbWrite); + +/** + * Returns the description of a given volume type. + * + * @returns The description of the type. + * @param enmVolType The volume type. + */ +RTDECL(const char *) RTDvmVolumeTypeGetDescr(RTDVMVOLTYPE enmVolType); + +/** + * Creates an VFS file from a volume handle. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param fOpen RTFILE_O_XXX. + * @param phVfsFileOut Where to store the VFS file handle on success. + */ +RTDECL(int) RTDvmVolumeCreateVfsFile(RTDVMVOLUME hVol, uint64_t fOpen, PRTVFSFILE phVfsFileOut); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_dvm_h */ + diff --git a/include/iprt/efi.h b/include/iprt/efi.h new file mode 100644 index 00000000..30bb4475 --- /dev/null +++ b/include/iprt/efi.h @@ -0,0 +1,299 @@ +/** @file + * IPRT - EFI related utilities. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_efi_h +#define IPRT_INCLUDED_efi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_efi RTEfi - EFI utilities + * @ingroup grp_rt + * @{ + */ + + +#ifdef IN_RING3 + +/** + * Converts an EFI time to a time spec (UTC). + * + * @returns pTimeSpec on success. + * @returns NULL if the pEfiTime data is invalid. + * @param pTimeSpec Where to store the converted time. + * @param pEfiTime Pointer to the EFI time struct. + */ +RTDECL(PRTTIMESPEC) RTEfiTimeToTimeSpec(PRTTIMESPEC pTimeSpec, PCEFI_TIME pEfiTime); + + +/** + * Converts a time spec (UTC) to an EFI time. + * + * @returns pEfiTime on success. + * @returns NULL if the pTimeSpec data is invalid. + * @param pEfiTime Pointer to the EFI time struct. + * @param pTimeSpec The time spec to convert. + */ +RTDECL(PEFI_TIME) RTEfiTimeFromTimeSpec(PEFI_TIME pEfiTime, PCRTTIMESPEC pTimeSpec); + + +/** + * Converts the given EFI GUID to the IPRT UUID representation. + * + * @returns pUuid. + * @param pUuid Where to store the converted GUID. + * @param pEfiGuid The EFI GUID to convert. + */ +RTDECL(PRTUUID) RTEfiGuidToUuid(PRTUUID pUuid, PCEFI_GUID pEfiGuid); + + +/** + * Converts the given EFI GUID to the IPRT UUID representation. + * + * @returns pEfiGuid. + * @param pEfiGuid Where to store the converted UUID. + * @param pUuid The UUID to convert. + */ +RTDECL(PEFI_GUID) RTEfiGuidFromUuid(PEFI_GUID pEfiGuid, PCRTUUID pUuid); + + +/** + * Compares two EFI GUID values. + * + * @returns 0 if eq, < 0 or > 0. + * @param pGuid1 First value to compare. + * @param pGuid2 Second value to compare. + */ +RTDECL(int) RTEfiGuidCompare(PCEFI_GUID pGuid1, PCEFI_GUID pGuid2); + + +/** + * Opens an EFI variable store. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the store. + * @param fMntFlags RTVFSMNT_F_XXX. + * @param fVarStoreFlags Reserved, MBZ. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTEfiVarStoreOpenAsVfs(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fVarStoreFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + + +/** @name RTEFIVARSTORE_CREATE_F_XXX - RTEfiVarStoreCreate flags + * @{ */ +/** Use default options. */ +#define RTEFIVARSTORE_CREATE_F_DEFAULT UINT32_C(0) +/** Don't create a fault tolerant write working space. + * The default is to create one reducing the size of the variable store. */ +#define RTEFIVARSTORE_CREATE_F_NO_FTW_WORKING_SPACE RT_BIT_32(0) +/** Mask containing all valid flags. */ +#define RTEFIVARSTORE_CREATE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Creates a new EFI variable store. + * + * @returns IRPT status code. + * @param hVfsFile The store file. + * @param offStore The offset into @a hVfsFile of the file. + * Typically 0. + * @param cbStore The size of the variable store. Pass 0 if the rest of + * hVfsFile should be used. The remaining space for variables + * will be less because of some metadata overhead. + * @param fFlags See RTEFIVARSTORE_F_XXX. + * @param cbBlock The logical block size. + * @param pErrInfo Additional error information, maybe. Optional. + */ +RTDECL(int) RTEfiVarStoreCreate(RTVFSFILE hVfsFile, uint64_t offStore, uint64_t cbStore, uint32_t fFlags, uint32_t cbBlock, + PRTERRINFO pErrInfo); + + +/** + * EFI signature type. + */ +typedef enum RTEFISIGTYPE +{ + /** Invalid type, do not use. */ + RTEFISIGTYPE_INVALID = 0, + /** First valid signature type. */ + RTEFISIGTYPE_FIRST_VALID, + /** Signature contains a SHA256 hash. */ + RTEFISIGTYPE_SHA256 = RTEFISIGTYPE_FIRST_VALID, + /** Signature contains a RSA2048 key (only the modulus in big endian form, + * the exponent is always 65537/0x10001). */ + RTEFISIGTYPE_RSA2048, + /** Signature contains a RSA2048 signature of a SHA256 hash. */ + RTEFISIGTYPE_RSA2048_SHA256, + /** Signature contains a SHA1 hash. */ + RTEFISIGTYPE_SHA1, + /** Signature contains a RSA2048 signature of a SHA1 hash. */ + RTEFISIGTYPE_RSA2048_SHA1, + /** Signature contains a DER encoded X.509 certificate. */ + RTEFISIGTYPE_X509, + /** First invalid type (do not use). */ + RTEFISIGTYPE_FIRST_INVALID, + /** 32bit blowup hack.*/ + RTEFISIGTYPE_32BIT_HACK = 0x7fffffff +} RTEFISIGTYPE; + + +/** + * EFI signature database enumeration callback. + * + * @returns IPRT status code, any status code other than VINF_SUCCESS will abort the enumeration. + * @param hEfiSigDb Handle to the EFI signature database this callback is called on. + * @param enmSigType The signature type. + * @param pUuidOwner Signature owner UUID. + * @param pvSig The signature data (dependent on the type). + * @param cbSig Size of the signature in bytes. + * @param pvUser Opaque user data passed in RTEfiSigDbEnum(). + */ +typedef DECLCALLBACKTYPE(int, FNRTEFISIGDBENUMSIG,(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner, + const void *pvSig, size_t cbSig, void *pvUser)); +/** Pointer to a EFI signature database enumeration callback. */ +typedef FNRTEFISIGDBENUMSIG *PFNRTEFISIGDBENUMSIG; + + +/** + * Creates an empty EFI signature database. + * + * @returns IPRT status code. + * @param phEfiSigDb Where to store the handle to the empty EFI signature database on success. + */ +RTDECL(int) RTEfiSigDbCreate(PRTEFISIGDB phEfiSigDb); + + +/** + * Destroys the given EFI signature database handle. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle to destroy. + */ +RTDECL(int) RTEfiSigDbDestroy(RTEFISIGDB hEfiSigDb); + + +/** + * Adds the signatures from an existing signature database contained in the given file. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param hVfsFileIn The file handle containing the existing signature database. + */ +RTDECL(int) RTEfiSigDbAddFromExistingDb(RTEFISIGDB hEfiSigDb, RTVFSFILE hVfsFileIn); + + +/** + * Adds a new signature to the given signature database from the given file. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param enmSigType Type of the signature. + * @param pUuidOwner The UUID of the signature owner. + * @param hVfsFileIn File handle containing the signature data. + */ +RTDECL(int) RTEfiSigDbAddSignatureFromFile(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner, RTVFSFILE hVfsFileIn); + + +/** + * Adds a new signature to the given signature database from the given buffer. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param enmSigType Type of the signature. + * @param pUuidOwner The UUID of the signature owner. + * @param pvBuf Pointer to the signature data. + * @param cbBuf Size of the signature data in bytes. + */ +RTDECL(int) RTEfiSigDbAddSignatureFromBuf(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner, + const void *pvBuf, size_t cbBuf); + + +/** + * Writes the given EFI signature database to the given file. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param hVfsFileOut The file handle to write the signature database to. + */ +RTDECL(int) RTEfiSigDbWriteToFile(RTEFISIGDB hEfiSigDb, RTVFSFILE hVfsFileOut); + + +/** + * Enumerate all signatures in the given EFI signature database. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param pfnEnumSig The callback to call for each signature. + * @param pvUser Opaque user data to pass to the callback. + */ +RTDECL(int) RTEfiSigDbEnum(RTEFISIGDB hEfiSigDb, PFNRTEFISIGDBENUMSIG pfnEnumSig, void *pvUser); + + +/** + * Returns a human readable string of the given signature type. + * + * @returns Human readable string. + * @param enmSigType The signature type. + */ +RTDECL(const char *) RTEfiSigDbTypeStringify(RTEFISIGTYPE enmSigType); + + +/** + * Returns a pointer to the EFI GUID identifying the given signature type. + * + * @returns Pointer to the EFI GUID. + * @param enmSigType The signature type. + */ +RTDECL(PCEFI_GUID) RTEfiSigDbTypeGetGuid(RTEFISIGTYPE enmSigType); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_efi_h */ + diff --git a/include/iprt/env.h b/include/iprt/env.h new file mode 100644 index 00000000..3b3d13b2 --- /dev/null +++ b/include/iprt/env.h @@ -0,0 +1,473 @@ +/** @file + * IPRT - Process Environment Strings. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_env_h +#define IPRT_INCLUDED_env_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_env RTEnv - Process Environment Strings + * @ingroup grp_rt + * @{ + */ + +#ifdef IN_RING3 + +/** Special handle that indicates the default process environment. */ +#define RTENV_DEFAULT ((RTENV)~(uintptr_t)0) + +/** + * Creates an empty environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param pEnv Where to store the handle of the new environment block. + */ +RTDECL(int) RTEnvCreate(PRTENV pEnv); + +/** + * Creates an empty environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param phEnv Where to store the handle of the new environment block. + * @param fFlags Zero or more RTENV_CREATE_F_XXX flags. + */ +RTDECL(int) RTEnvCreateEx(PRTENV phEnv, uint32_t fFlags); + +/** @name RTENV_CREATE_F_XXX - Flags for RTEnvCreateEx() and RTEnvCreateChangeRecordEx() + * @{ */ +/** Allow equal ('=') as the first character of a variable name. + * This is useful for compatibility with Windows' handling of CWD on drives, as + * these are stored on the form "=D:=D:\tmp\asdf". It is only really useful + * for creating environment blocks for processes and such, since the CRT doesn't + * allow us to apply it directly to the process enviornment. */ +#define RTENV_CREATE_F_ALLOW_EQUAL_FIRST_IN_VAR RT_BIT_32(0) +/** Valid flags. */ +#define RTENV_CREATE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Creates an environment block and fill it with variables from the given + * environment array. + * + * @returns IPRT status code. + * @retval VWRN_ENV_NOT_FULLY_TRANSLATED may be returned when passing + * RTENV_DEFAULT and one or more of the environment variables have + * codeset incompatibilities. The problematic variables will be + * ignored and not included in the clone, thus the clone will have + * fewer variables. + * @retval VERR_NO_MEMORY + * @retval VERR_NO_STR_MEMORY + * @retval VERR_INVALID_HANDLE + * + * @param pEnv Where to store the handle of the new environment block. + * @param EnvToClone The environment to clone. + */ +RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone); + +/** + * Creates an environment block from an UTF-16 environment raw block. + * + * This is the reverse of RTEnvQueryUtf16Block. + * + * @returns IPRT status code. + * @retval VERR_NO_MEMORY + * @retval VERR_NO_STR_MEMORY + * + * @param phEnv Where to store the handle of the new environment block. + * @param pwszzBlock List of zero terminated string end with a zero length + * string (or two zero terminators if you prefer). The + * strings are on the RTPutEnv format (VAR=VALUE), except + * they are all expected to include an equal sign. + * @param fFlags Flags served for the future. + */ +RTDECL(int) RTEnvCloneUtf16Block(PRTENV phEnv, PCRTUTF16 pwszzBlock, uint32_t fFlags); + +/** + * Destroys an environment block. + * + * @returns IPRT status code. + * + * @param Env Environment block handle. + * Both RTENV_DEFAULT and NIL_RTENV are silently ignored. + */ +RTDECL(int) RTEnvDestroy(RTENV Env); + +/** + * Resets the environment block to contain zero variables. + * + * @returns IPRT status code. + * + * @param hEnv Environment block handle. RTENV_DEFAULT is not supported. + */ +RTDECL(int) RTEnvReset(RTENV hEnv); + +/** + * Get the execve/spawnve/main envp. + * + * All returned strings are in the current process' codepage. + * This array is only valid until the next RTEnv call. + * + * @returns Pointer to the raw array of environment variables. + * @returns NULL if Env is NULL or invalid. + * + * @param Env Environment block handle. + * + * @note This is NOT available on Windows. It is also not a stable export + * and will hopefully be replaced before long (see todo). + * + * @todo This needs to change to return a copy of the env vars like + * RTEnvQueryUtf16Block does! + */ +RTDECL(char const * const *) RTEnvGetExecEnvP(RTENV Env); + +/** + * Get a sorted, UTF-16 environment block for CreateProcess. + * + * @returns IPRT status code. + * + * @param hEnv Environment block handle. + * @param ppwszzBlock Where to return the environment block. This must be + * freed by calling RTEnvFreeUtf16Block. + */ +RTDECL(int) RTEnvQueryUtf16Block(RTENV hEnv, PRTUTF16 *ppwszzBlock); + +/** + * Frees an environment block returned by RTEnvGetUtf16Block(). + * + * @param pwszzBlock What RTEnvGetUtf16Block returned. NULL is ignored. + */ +RTDECL(void) RTEnvFreeUtf16Block(PRTUTF16 pwszzBlock); + +/** + * Get a sorted, UTF-8 environment block. + * + * The environment block is a sequence of putenv formatted ("NAME=VALUE" or + * "NAME") zero terminated strings ending with an empty string (i.e. last string + * has two zeros). + * + * @returns IPRT status code. + * + * @param hEnv Environment block handle. + * @param fSorted Whether to sort it, this will affect @a hEnv. + * @param ppszzBlock Where to return the environment block. This must be + * freed by calling RTEnvFreeUtf8Block. + * @param pcbBlock Where to return the size of the block. Optional. + */ +RTDECL(int) RTEnvQueryUtf8Block(RTENV hEnv, bool fSorted, char **ppszzBlock, size_t *pcbBlock); + +/** + * Frees an environment block returned by RTEnvGetUtf8Block(). + * + * @param pszzBlock What RTEnvGetUtf8Block returned. NULL is ignored. + */ +RTDECL(void) RTEnvFreeUtf8Block(char *pszzBlock); + +/** + * Checks if an environment variable exists in the default environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param pszVar The environment variable name. + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(bool) RTEnvExist(const char *pszVar); +RTDECL(bool) RTEnvExistsBad(const char *pszVar); +RTDECL(bool) RTEnvExistsUtf8(const char *pszVar); + +/** + * Checks if an environment variable exists in a specific environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param Env The environment handle. + * @param pszVar The environment variable name. + */ +RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar); + +/** + * Gets an environment variable from the default environment block. (getenv). + * + * The caller is responsible for ensuring that nobody changes the environment + * while it's using the returned string pointer! + * + * @returns Pointer to read only string on success, NULL if the variable wasn't found. + * + * @param pszVar The environment variable name. + * + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(const char *) RTEnvGet(const char *pszVar); +RTDECL(const char *) RTEnvGetBad(const char *pszVar); +RTDECL(int) RTEnvGetUtf8(const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual); + +/** + * Gets an environment variable in a specific environment block. + * + * @returns IPRT status code. + * @retval VERR_ENV_VAR_NOT_FOUND if the variable was not found. + * @retval VERR_ENV_VAR_UNSET if @a hEnv is an environment change record and + * the variable has been recorded as unset. + * + * @param hEnv The environment handle. + * @param pszVar The environment variable name. + * @param pszValue Where to put the buffer. + * @param cbValue The size of the value buffer. + * @param pcchActual Returns the actual value string length. Optional. + */ +RTDECL(int) RTEnvGetEx(RTENV hEnv, const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual); + +/** + * Puts an variable=value string into the environment (putenv). + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param pszVarEqualValue The variable '=' value string. If the value and '=' is + * omitted, the variable is removed from the environment. + * + * @remark Don't assume the value is copied. + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(int) RTEnvPut(const char *pszVarEqualValue); +RTDECL(int) RTEnvPutBad(const char *pszVarEqualValue); +RTDECL(int) RTEnvPutUtf8(const char *pszVarEqualValue); + +/** + * Puts a copy of the passed in 'variable=value' string into the environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param Env Handle of the environment block. + * @param pszVarEqualValue The variable '=' value string. If the value and '=' is + * omitted, the variable is removed from the environment. + */ +RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue); + +/** + * Sets an environment variable (setenv(,,1)). + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param pszVar The environment variable name. + * @param pszValue The environment variable value. + * + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue); +RTDECL(int) RTEnvSetBad(const char *pszVar, const char *pszValue); +RTDECL(int) RTEnvSetUtf8(const char *pszVar, const char *pszValue); + +/** + * Sets an environment variable (setenv(,,1)). + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param Env The environment handle. + * @param pszVar The environment variable name. + * @param pszValue The environment variable value. + */ +RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue); + +/** + * Removes an environment variable from the default environment block. + * + * @returns IPRT status code. + * @returns VINF_ENV_VAR_NOT_FOUND if the variable was not found. + * + * @param pszVar The environment variable name. + * + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(int) RTEnvUnset(const char *pszVar); +RTDECL(int) RTEnvUnsetBad(const char *pszVar); +RTDECL(int) RTEnvUnsetUtf8(const char *pszVar); + +/** + * Removes an environment variable from the specified environment block. + * + * @returns IPRT status code. + * @returns VINF_ENV_VAR_NOT_FOUND if the variable was not found. + * + * @param Env The environment handle. + * @param pszVar The environment variable name. + */ +RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar); + + +/** + * Returns the value of a environment variable from the default + * environment block in a heap buffer. + * + * @returns Pointer to a string containing the value, free it using RTStrFree. + * NULL if the variable was not found or we're out of memory. + * + * @param pszVar The environment variable name (UTF-8). + */ +RTDECL(char *) RTEnvDup(const char *pszVar); + +/** + * Duplicates the value of a environment variable if it exists. + * + * @returns Pointer to a string containing the value, free it using RTStrFree. + * NULL if the variable was not found or we're out of memory. + * + * @param Env The environment handle. + * @param pszVar The environment variable name. + */ +RTDECL(char *) RTEnvDupEx(RTENV Env, const char *pszVar); + +/** + * Counts the variables in the environment. + * + * @returns Number of variables in the environment. UINT32_MAX on error. + * @param hEnv The environment handle. + * RTENV_DEFAULT is currently not accepted. + */ +RTDECL(uint32_t) RTEnvCountEx(RTENV hEnv); + +/** + * Queries an environment variable by it's index. + * + * This can be used together with RTEnvCount to enumerate the environment block. + * + * @returns IPRT status code. + * @retval VERR_ENV_VAR_NOT_FOUND if the index is out of bounds, output buffers + * untouched. + * @retval VERR_BUFFER_OVERFLOW if one of the buffers are too small. We'll + * fill it with as much we can in RTStrCopy fashion. + * @retval VINF_ENV_VAR_UNSET if @a hEnv is an environment change record and + * the variable at @a iVar is recorded as being unset. + * + * @param hEnv The environment handle. + * RTENV_DEFAULT is currently not accepted. + * @param iVar The variable index. + * @param pszVar Variable name buffer. + * @param cbVar The size of the variable name buffer. + * @param pszValue Value buffer. + * @param cbValue The size of the value buffer. + */ +RTDECL(int) RTEnvGetByIndexEx(RTENV hEnv, uint32_t iVar, char *pszVar, size_t cbVar, char *pszValue, size_t cbValue); + +/** + * Leaner and meaner version of RTEnvGetByIndexEx. + * + * This can be used together with RTEnvCount to enumerate the environment block. + * + * Use with caution as the returned pointer may change by the next call using + * the environment handle. Please only use this API in cases where there is no + * chance of races. + * + * @returns Pointer to the internal environment variable=value string on + * success. If @a hEnv is an environment change recordthe string may + * also be on the "variable" form, representing an unset operation. Do + * NOT change this string, it is read only! + * + * If the index is out of range on the environment handle is invalid, + * NULL is returned. + * + * @param hEnv The environment handle. + * RTENV_DEFAULT is currently not accepted. + * @param iVar The variable index. + */ +RTDECL(const char *) RTEnvGetByIndexRawEx(RTENV hEnv, uint32_t iVar); + + +/** + * Creates an empty environment change record. + * + * This is a special environment for use with RTEnvApplyChanges and similar + * purposes. The + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param phEnv Where to store the handle of the new environment block. + */ +RTDECL(int) RTEnvCreateChangeRecord(PRTENV phEnv); + +/** + * Extended version of RTEnvCreateChangeRecord that takes flags. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param phEnv Where to store the handle of the new environment block. + * @param fFlags Zero or more RTENV_CREATE_F_XXX flags. + */ +RTDECL(int) RTEnvCreateChangeRecordEx(PRTENV phEnv, uint32_t fFlags); + +/** + * Checks if @a hEnv is an environment change record. + * + * @returns true if it is, false if it's not or if the handle is invalid. + * @param hEnv The environment handle. + * @sa RTEnvCreateChangeRecord. + */ +RTDECL(bool) RTEnvIsChangeRecord(RTENV hEnv); + +/** + * Applies changes from one environment onto another. + * + * If @a hEnvChanges is a normal environment, its content is just added to @a + * hEnvDst, where variables in the destination can only be overwritten. However + * if @a hEnvChanges is a change record environment, variables in the + * destination can also be removed. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * @param hEnvDst The destination environment. + * @param hEnvChanges Handle to the environment containig the changes to + * apply. As said, especially useful if it's a environment + * change record. RTENV_DEFAULT is not supported here. + */ +RTDECL(int) RTEnvApplyChanges(RTENV hEnvDst, RTENV hEnvChanges); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_env_h */ + diff --git a/include/iprt/err.h b/include/iprt/err.h new file mode 100644 index 00000000..cfa1d115 --- /dev/null +++ b/include/iprt/err.h @@ -0,0 +1,2823 @@ +/** @file + * IPRT - Status Codes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_err_h +#define IPRT_INCLUDED_err_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_rt_err RTErr - Status Codes + * @ingroup grp_rt + * + * The IPRT status codes are in two ranges: {0..999} and {22000..32766}. The + * IPRT users are free to use the range {1000..21999}. See RTERR_RANGE1_FIRST, + * RTERR_RANGE1_LAST, RTERR_RANGE2_FIRST, RTERR_RANGE2_LAST, RTERR_USER_FIRST + * and RTERR_USER_LAST. + * + * @{ + */ + +/** @name Status Code Ranges + * @{ */ +/** The first status code in the primary IPRT range. */ +#define RTERR_RANGE1_FIRST 0 +/** The last status code in the primary IPRT range. */ +#define RTERR_RANGE1_LAST 999 + +/** The first status code in the secondary IPRT range. */ +#define RTERR_RANGE2_FIRST 22000 +/** The last status code in the secondary IPRT range. */ +#define RTERR_RANGE2_LAST 32766 + +/** The first status code in the user range. */ +#define RTERR_USER_FIRST 1000 +/** The last status code in the user range. */ +#define RTERR_USER_LAST 21999 +/** @} */ + + +/* SED-START */ + +/** Success. */ +#define VINF_SUCCESS 0 + +/** @name Misc. Status Codes + * @{ + */ +/** General failure - DON'T USE THIS!!! */ +#define VERR_GENERAL_FAILURE (-1) +/** Invalid parameter. */ +#define VERR_INVALID_PARAMETER (-2) +/** Invalid parameter. */ +#define VWRN_INVALID_PARAMETER 2 +/** Invalid magic or cookie. */ +#define VERR_INVALID_MAGIC (-3) +/** Invalid magic or cookie. */ +#define VWRN_INVALID_MAGIC 3 +/** Invalid loader handle. */ +#define VERR_INVALID_HANDLE (-4) +/** Invalid loader handle. */ +#define VWRN_INVALID_HANDLE 4 +/** Failed to lock the address range. */ +#define VERR_LOCK_FAILED (-5) +/** Invalid memory pointer. */ +#define VERR_INVALID_POINTER (-6) +/** Failed to patch the IDT. */ +#define VERR_IDT_FAILED (-7) +/** Memory allocation failed. */ +#define VERR_NO_MEMORY (-8) +/** Already loaded. */ +#define VERR_ALREADY_LOADED (-9) +/** Permission denied. */ +#define VERR_PERMISSION_DENIED (-10) +/** Permission denied. */ +#define VINF_PERMISSION_DENIED 10 +/** Version mismatch. */ +#define VERR_VERSION_MISMATCH (-11) +/** The request function is not implemented. */ +#define VERR_NOT_IMPLEMENTED (-12) +/** The request function is not implemented. */ +#define VINF_NOT_IMPLEMENTED 12 +/** Invalid flags was given. */ +#define VERR_INVALID_FLAGS (-13) + +/** Not equal. */ +#define VERR_NOT_EQUAL (-18) +/** The specified path does not point at a symbolic link. */ +#define VERR_NOT_SYMLINK (-19) +/** Failed to allocate temporary memory. */ +#define VERR_NO_TMP_MEMORY (-20) +/** Invalid file mode mask (RTFMODE). */ +#define VERR_INVALID_FMODE (-21) +/** Incorrect call order. */ +#define VERR_WRONG_ORDER (-22) +/** There is no TLS (thread local storage) available for storing the current thread. */ +#define VERR_NO_TLS_FOR_SELF (-23) +/** Failed to set the TLS (thread local storage) entry which points to our thread structure. */ +#define VERR_FAILED_TO_SET_SELF_TLS (-24) +/** Not able to allocate contiguous memory. */ +#define VERR_NO_CONT_MEMORY (-26) +/** No memory available for page table or page directory. */ +#define VERR_NO_PAGE_MEMORY (-27) +/** Already initialized. */ +#define VINF_ALREADY_INITIALIZED 28 +/** Already initialized. */ +#define VERR_ALREADY_INITIALIZED (-28) +/** The specified thread is dead. */ +#define VERR_THREAD_IS_DEAD (-29) +/** The specified thread is not waitable. */ +#define VERR_THREAD_NOT_WAITABLE (-30) +/** Pagetable not present. */ +#define VERR_PAGE_TABLE_NOT_PRESENT (-31) +/** Invalid context. + * Typically an API was used by the wrong thread. */ +#define VERR_INVALID_CONTEXT (-32) +/** The per process timer is busy. */ +#define VERR_TIMER_BUSY (-33) +/** Address conflict. */ +#define VERR_ADDRESS_CONFLICT (-34) +/** Unresolved (unknown) host platform error. */ +#define VERR_UNRESOLVED_ERROR (-35) +/** Invalid function. */ +#define VERR_INVALID_FUNCTION (-36) +/** Not supported. */ +#define VERR_NOT_SUPPORTED (-37) +/** Not supported. */ +#define VINF_NOT_SUPPORTED 37 +/** Access denied. */ +#define VERR_ACCESS_DENIED (-38) +/** Call interrupted. */ +#define VERR_INTERRUPTED (-39) +/** Call interrupted. */ +#define VINF_INTERRUPTED 39 +/** Timeout. */ +#define VERR_TIMEOUT (-40) +/** Timeout. */ +#define VINF_TIMEOUT 40 +/** Buffer too small to save result. */ +#define VERR_BUFFER_OVERFLOW (-41) +/** Buffer too small to save result. */ +#define VINF_BUFFER_OVERFLOW 41 +/** Data size overflow. */ +#define VERR_TOO_MUCH_DATA (-42) +/** Max threads number reached. */ +#define VERR_MAX_THRDS_REACHED (-43) +/** Max process number reached. */ +#define VERR_MAX_PROCS_REACHED (-44) +/** The recipient process has refused the signal. */ +#define VERR_SIGNAL_REFUSED (-45) +/** A signal is already pending. */ +#define VERR_SIGNAL_PENDING (-46) +/** The signal being posted is not correct. */ +#define VERR_SIGNAL_INVALID (-47) +/** The state changed. + * This is a generic error message and needs a context to make sense. */ +#define VERR_STATE_CHANGED (-48) +/** Warning, the state changed. + * This is a generic error message and needs a context to make sense. */ +#define VWRN_STATE_CHANGED 48 +/** Error while parsing UUID string */ +#define VERR_INVALID_UUID_FORMAT (-49) +/** The specified process was not found. */ +#define VERR_PROCESS_NOT_FOUND (-50) +/** The process specified to a non-block wait had not exited. */ +#define VERR_PROCESS_RUNNING (-51) +/** Retry the operation. */ +#define VERR_TRY_AGAIN (-52) +/** Retry the operation. */ +#define VINF_TRY_AGAIN 52 +/** Generic parse error. */ +#define VERR_PARSE_ERROR (-53) +/** Value out of range. */ +#define VERR_OUT_OF_RANGE (-54) +/** A numeric conversion encountered a value which was too big for the target. */ +#define VERR_NUMBER_TOO_BIG (-55) +/** A numeric conversion encountered a value which was too big for the target. */ +#define VWRN_NUMBER_TOO_BIG 55 +/** The number begin converted (string) contained no digits. */ +#define VERR_NO_DIGITS (-56) +/** The number begin converted (string) contained no digits. */ +#define VWRN_NO_DIGITS 56 +/** Encountered a '-' during conversion to an unsigned value. */ +#define VERR_NEGATIVE_UNSIGNED (-57) +/** Encountered a '-' during conversion to an unsigned value. */ +#define VWRN_NEGATIVE_UNSIGNED 57 +/** Error while characters translation (unicode and so). */ +#define VERR_NO_TRANSLATION (-58) +/** Error while characters translation (unicode and so). */ +#define VWRN_NO_TRANSLATION 58 +/** Encountered unicode code point which is reserved for use as endian indicator (0xffff or 0xfffe). */ +#define VERR_CODE_POINT_ENDIAN_INDICATOR (-59) +/** Encountered unicode code point in the surrogate range (0xd800 to 0xdfff). */ +#define VERR_CODE_POINT_SURROGATE (-60) +/** A string claiming to be UTF-8 is incorrectly encoded. */ +#define VERR_INVALID_UTF8_ENCODING (-61) +/** A string claiming to be in UTF-16 is incorrectly encoded. */ +#define VERR_INVALID_UTF16_ENCODING (-62) +/** Encountered a unicode code point which cannot be represented as UTF-16. */ +#define VERR_CANT_RECODE_AS_UTF16 (-63) +/** Got an out of memory condition trying to allocate a string. */ +#define VERR_NO_STR_MEMORY (-64) +/** Got an out of memory condition trying to allocate a UTF-16 (/UCS-2) string. */ +#define VERR_NO_UTF16_MEMORY (-65) +/** Get an out of memory condition trying to allocate a code point array. */ +#define VERR_NO_CODE_POINT_MEMORY (-66) +/** Can't free the memory because it's used in mapping. */ +#define VERR_MEMORY_BUSY (-67) +/** The timer can't be started because it's already active. */ +#define VERR_TIMER_ACTIVE (-68) +/** The timer can't be stopped because it's already suspended. */ +#define VERR_TIMER_SUSPENDED (-69) +/** The operation was cancelled by the user (copy) or another thread (local ipc). */ +#define VERR_CANCELLED (-70) +/** Failed to initialize a memory object. + * Exactly what this means is OS specific. */ +#define VERR_MEMOBJ_INIT_FAILED (-71) +/** Out of memory condition when allocating memory with low physical backing. */ +#define VERR_NO_LOW_MEMORY (-72) +/** Out of memory condition when allocating physical memory (without mapping). */ +#define VERR_NO_PHYS_MEMORY (-73) +/** The address (virtual or physical) is too big. */ +#define VERR_ADDRESS_TOO_BIG (-74) +/** Failed to map a memory object. */ +#define VERR_MAP_FAILED (-75) +/** Trailing characters. */ +#define VERR_TRAILING_CHARS (-76) +/** Trailing characters. */ +#define VWRN_TRAILING_CHARS 76 +/** Trailing spaces. */ +#define VERR_TRAILING_SPACES (-77) +/** Trailing spaces. */ +#define VWRN_TRAILING_SPACES 77 +/** Generic not found error. */ +#define VERR_NOT_FOUND (-78) +/** Generic not found warning. */ +#define VWRN_NOT_FOUND 78 +/** Generic invalid state error. */ +#define VERR_INVALID_STATE (-79) +/** Generic invalid state warning. */ +#define VWRN_INVALID_STATE 79 +/** Generic out of resources error. */ +#define VERR_OUT_OF_RESOURCES (-80) +/** Generic out of resources warning. */ +#define VWRN_OUT_OF_RESOURCES 80 +/** No more handles available, too many open handles. */ +#define VERR_NO_MORE_HANDLES (-81) +/** Preemption is disabled. + * The requested operation can only be performed when preemption is enabled. */ +#define VERR_PREEMPT_DISABLED (-82) +/** End of string. */ +#define VERR_END_OF_STRING (-83) +/** End of string. */ +#define VINF_END_OF_STRING 83 +/** A page count is out of range. */ +#define VERR_PAGE_COUNT_OUT_OF_RANGE (-84) +/** Generic object destroyed status. */ +#define VERR_OBJECT_DESTROYED (-85) +/** Generic object was destroyed by the call status. */ +#define VINF_OBJECT_DESTROYED 85 +/** Generic dangling objects status. */ +#define VERR_DANGLING_OBJECTS (-86) +/** Generic dangling objects status. */ +#define VWRN_DANGLING_OBJECTS 86 +/** Invalid Base64 encoding. */ +#define VERR_INVALID_BASE64_ENCODING (-87) +/** Return instigated by a callback or similar. */ +#define VERR_CALLBACK_RETURN (-88) +/** Return instigated by a callback or similar. */ +#define VINF_CALLBACK_RETURN 88 +/** Authentication failure. */ +#define VERR_AUTHENTICATION_FAILURE (-89) +/** Not a power of two. */ +#define VERR_NOT_POWER_OF_TWO (-90) +/** Status code, typically given as a parameter, that isn't supposed to be used. */ +#define VERR_IGNORED (-91) +/** Concurrent access to the object is not allowed. */ +#define VERR_CONCURRENT_ACCESS (-92) +/** The caller does not have a reference to the object. + * This status is used when two threads is caught sharing the same object + * reference. */ +#define VERR_CALLER_NO_REFERENCE (-93) +/** Generic no change error. */ +#define VERR_NO_CHANGE (-95) +/** Generic no change info. */ +#define VINF_NO_CHANGE 95 +/** Out of memory condition when allocating executable memory. */ +#define VERR_NO_EXEC_MEMORY (-96) +/** The alignment is not supported. */ +#define VERR_UNSUPPORTED_ALIGNMENT (-97) +/** The alignment is not really supported, however we got lucky with this + * allocation. */ +#define VINF_UNSUPPORTED_ALIGNMENT 97 +/** Duplicate something. */ +#define VERR_DUPLICATE (-98) +/** Something is missing. */ +#define VERR_MISSING (-99) +/** An unexpected (/unknown) exception was caught. */ +#define VERR_UNEXPECTED_EXCEPTION (-22400) +/** Buffer underflow. */ +#define VERR_BUFFER_UNDERFLOW (-22401) +/** Buffer underflow. */ +#define VINF_BUFFER_UNDERFLOW 22401 +/** Uneven input. */ +#define VERR_UNEVEN_INPUT (-22402) +/** Something is not available or not working properly. */ +#define VERR_NOT_AVAILABLE (-22403) +/** The RTPROC_FLAGS_DETACHED flag isn't supported. */ +#define VERR_PROC_DETACH_NOT_SUPPORTED (-22404) +/** An account is restricted in a certain way. */ +#define VERR_ACCOUNT_RESTRICTED (-22405) +/** An account is restricted in a certain way. */ +#define VINF_ACCOUNT_RESTRICTED 22405 +/** Not able satisfy all the requirements of the request. */ +#define VERR_UNABLE_TO_SATISFY_REQUIREMENTS (-22406) +/** Not able satisfy all the requirements of the request. */ +#define VWRN_UNABLE_TO_SATISFY_REQUIREMENTS 22406 +/** The requested allocation is too big. */ +#define VERR_ALLOCATION_TOO_BIG (-22407) +/** Mismatch. */ +#define VERR_MISMATCH (-22408) +/** Wrong type. */ +#define VERR_WRONG_TYPE (-22409) +/** Wrong type. */ +#define VWRN_WRONG_TYPE (22409) +/** This indicates that the process does not have sufficient privileges to + * perform the operation. */ +#define VERR_PRIVILEGE_NOT_HELD (-22410) +/** Process does not have the trusted code base (TCB) privilege needed for user + * authentication or/and process creation as a given user. TCB is also called + * 'Act as part of the operating system'. */ +#define VERR_PROC_TCB_PRIV_NOT_HELD (-22411) +/** Process does not have the assign primary token (APT) privilege needed + * for creating process as a given user. APT is also called 'Replace a process + * level token'. */ +#define VERR_PROC_APT_PRIV_NOT_HELD (-22412) +/** Process does not have the increase quota (IQ) privilege needed for + * creating a process as a given user. IQ is also called 'Increase quotas'. */ +#define VERR_PROC_IQ_PRIV_NOT_HELD (-22413) +/** The system has too many CPUs. */ +#define VERR_MP_TOO_MANY_CPUS (-22414) +/** Wrong parameter count. */ +#define VERR_WRONG_PARAMETER_COUNT (-22415) +/** Wrong parameter type. */ +#define VERR_WRONG_PARAMETER_TYPE (-22416) +/** Invalid client ID. */ +#define VERR_INVALID_CLIENT_ID (-22417) +/** Invalid session ID. */ +#define VERR_INVALID_SESSION_ID (-22418) +/** Requires process elevation (UAC). */ +#define VERR_PROC_ELEVATION_REQUIRED (-22419) +/** Incompatible configuration requested. */ +#define VERR_INCOMPATIBLE_CONFIG (-22420) +/** String is not terminated within the buffer bounds. */ +#define VERR_NO_STRING_TERMINATOR (-22421) +/** Empty string. */ +#define VERR_EMPTY_STRING (-22422) +/** Too many references to an object. */ +#define VERR_TOO_MANY_REFERENCES (-22423) +/** Returned by RTThreadQueryTerminationStatus to indicate that the thread is + * (or should be) terminating. */ +#define VINF_THREAD_IS_TERMINATING (22424) +/** The thread is terminating. */ +#define VERR_THREAD_IS_TERMINATING (-22424) +/** Unable to translate one or more of the arguments to the codeset the child + * process is expected to use. */ +#define VERR_PROC_NO_ARG_TRANSLATION (-22425) +/** Floating pointer underflow. */ +#define VERR_FLOAT_UNDERFLOW (-22426) +/** Floating pointer underflow. */ +#define VWRN_FLOAT_UNDERFLOW (22426) +/** Floating pointer overflow. */ +#define VERR_FLOAT_OVERFLOW (-22427) +/** Floating pointer overflow. */ +#define VWRN_FLOAT_OVERFLOW (22427) +/** @} */ + + +/** @name Common File/Disk/Pipe/etc Status Codes + * @{ + */ +/** Unresolved (unknown) file i/o error. */ +#define VERR_FILE_IO_ERROR (-100) +/** File/Device open failed. */ +#define VERR_OPEN_FAILED (-101) +/** File not found. */ +#define VERR_FILE_NOT_FOUND (-102) +/** Path not found. */ +#define VERR_PATH_NOT_FOUND (-103) +/** Invalid (malformed) file/path name. */ +#define VERR_INVALID_NAME (-104) +/** The object in question already exists. */ +#define VERR_ALREADY_EXISTS (-105) +/** The object in question already exists. */ +#define VWRN_ALREADY_EXISTS 105 +/** Too many open files. */ +#define VERR_TOO_MANY_OPEN_FILES (-106) +/** Seek error. */ +#define VERR_SEEK (-107) +/** Seek below file start. */ +#define VERR_NEGATIVE_SEEK (-108) +/** Trying to seek on device. */ +#define VERR_SEEK_ON_DEVICE (-109) +/** Reached the end of the file. */ +#define VERR_EOF (-110) +/** Reached the end of the file. */ +#define VINF_EOF 110 +/** Generic file read error. */ +#define VERR_READ_ERROR (-111) +/** Generic file write error. */ +#define VERR_WRITE_ERROR (-112) +/** Write protect error. */ +#define VERR_WRITE_PROTECT (-113) +/** Sharing violation, file is being used by another process. */ +#define VERR_SHARING_VIOLATION (-114) +/** Unable to lock a region of a file. */ +#define VERR_FILE_LOCK_FAILED (-115) +/** File access error, another process has locked a portion of the file. */ +#define VERR_FILE_LOCK_VIOLATION (-116) +/** File or directory can't be created. */ +#define VERR_CANT_CREATE (-117) +/** Directory can't be deleted. */ +#define VERR_CANT_DELETE_DIRECTORY (-118) +/** Can't move file to another disk. */ +#define VERR_NOT_SAME_DEVICE (-119) +/** The filename or extension is too long. */ +#define VERR_FILENAME_TOO_LONG (-120) +/** Media not present in drive. */ +#define VERR_MEDIA_NOT_PRESENT (-121) +/** The type of media was not recognized. Not formatted? */ +#define VERR_MEDIA_NOT_RECOGNIZED (-122) +/** Can't unlock - region was not locked. */ +#define VERR_FILE_NOT_LOCKED (-123) +/** Unrecoverable error: lock was lost. */ +#define VERR_FILE_LOCK_LOST (-124) +/** Can't delete directory with files. */ +#define VERR_DIR_NOT_EMPTY (-125) +/** A directory operation was attempted on a non-directory object. */ +#define VERR_NOT_A_DIRECTORY (-126) +/** A non-directory operation was attempted on a directory object. */ +#define VERR_IS_A_DIRECTORY (-127) +/** Tried to grow a file beyond the limit imposed by the process or the filesystem. */ +#define VERR_FILE_TOO_BIG (-128) +/** No pending request the aio context has to wait for completion. */ +#define VERR_FILE_AIO_NO_REQUEST (-129) +/** The request could not be canceled or prepared for another transfer + * because it is still in progress. */ +#define VERR_FILE_AIO_IN_PROGRESS (-130) +/** The request could not be canceled because it already completed. */ +#define VERR_FILE_AIO_COMPLETED (-131) +/** The I/O context couldn't be destroyed because there are still pending requests. */ +#define VERR_FILE_AIO_BUSY (-132) +/** The requests couldn't be submitted because that would exceed the capacity of the context. */ +#define VERR_FILE_AIO_LIMIT_EXCEEDED (-133) +/** The request was canceled. */ +#define VERR_FILE_AIO_CANCELED (-134) +/** The request wasn't submitted so it can't be canceled. */ +#define VERR_FILE_AIO_NOT_SUBMITTED (-135) +/** A request was not prepared and thus could not be submitted. */ +#define VERR_FILE_AIO_NOT_PREPARED (-136) +/** Not all requests could be submitted due to resource shortage. */ +#define VERR_FILE_AIO_INSUFFICIENT_RESSOURCES (-137) +/** Device or resource is busy. */ +#define VERR_RESOURCE_BUSY (-138) +/** A file operation was attempted on a non-file object. */ +#define VERR_NOT_A_FILE (-139) +/** A non-file operation was attempted on a file object. */ +#define VERR_IS_A_FILE (-140) +/** Unexpected filesystem object type. */ +#define VERR_UNEXPECTED_FS_OBJ_TYPE (-141) +/** A path does not start with a root specification. */ +#define VERR_PATH_DOES_NOT_START_WITH_ROOT (-142) +/** A path is relative, expected an absolute path. */ +#define VERR_PATH_IS_RELATIVE (-143) +/** A path is not relative (start with root), expected an relative path. */ +#define VERR_PATH_IS_NOT_RELATIVE (-144) +/** Zero length path. */ +#define VERR_PATH_ZERO_LENGTH (-145) +/** There are not enough events available on the host to create the I/O context. + * This exact meaning is host platform dependent. */ +#define VERR_FILE_AIO_INSUFFICIENT_EVENTS (-146) +/** The native file handle got stale while it was open. Can occur with + * files on network shares when the server is unresponsive. */ +#define VERR_STALE_FILE_HANDLE (-147) +/** @} */ + + +/** @name Generic Filesystem I/O Status Codes + * @{ + */ +/** Unresolved (unknown) disk i/o error. */ +#define VERR_DISK_IO_ERROR (-150) +/** Invalid drive number. */ +#define VERR_INVALID_DRIVE (-151) +/** Disk is full. */ +#define VERR_DISK_FULL (-152) +/** Disk was changed. */ +#define VERR_DISK_CHANGE (-153) +/** Drive is locked. */ +#define VERR_DRIVE_LOCKED (-154) +/** The specified disk or diskette cannot be accessed. */ +#define VERR_DISK_INVALID_FORMAT (-155) +/** Too many symbolic links. */ +#define VERR_TOO_MANY_SYMLINKS (-156) +/** The OS does not support setting the time stamps on a symbolic link. */ +#define VERR_NS_SYMLINK_SET_TIME (-157) +/** The OS does not support changing the owner of a symbolic link. */ +#define VERR_NS_SYMLINK_CHANGE_OWNER (-158) +/** Symbolic link not allowed. */ +#define VERR_SYMLINK_NOT_ALLOWED (-159) +/** Is a symbolic link. */ +#define VERR_IS_A_SYMLINK (-160) +/** Is a FIFO. */ +#define VERR_IS_A_FIFO (-161) +/** Is a socket. */ +#define VERR_IS_A_SOCKET (-162) +/** Is a block device. */ +#define VERR_IS_A_BLOCK_DEVICE (-163) +/** Is a character device. */ +#define VERR_IS_A_CHAR_DEVICE (-164) +/** No media in drive. */ +#define VERR_DRIVE_IS_EMPTY (-165) +/** @} */ + + +/** @name Generic Directory Enumeration Status Codes + * @{ + */ +/** Unresolved (unknown) search error. */ +#define VERR_SEARCH_ERROR (-200) +/** No more files found. */ +#define VERR_NO_MORE_FILES (-201) +/** No more search handles available. */ +#define VERR_NO_MORE_SEARCH_HANDLES (-202) +/** RTDirReadEx() failed to retrieve the extra data which was requested. */ +#define VWRN_NO_DIRENT_INFO 203 +/** @} */ + + +/** @name Internal Processing Errors + * @{ + */ +/** Internal error - this should never happen. */ +#define VERR_INTERNAL_ERROR (-225) +/** Internal error no. 2. */ +#define VERR_INTERNAL_ERROR_2 (-226) +/** Internal error no. 3. */ +#define VERR_INTERNAL_ERROR_3 (-227) +/** Internal error no. 4. */ +#define VERR_INTERNAL_ERROR_4 (-228) +/** Internal error no. 5. */ +#define VERR_INTERNAL_ERROR_5 (-229) +/** Internal error: Unexpected status code. */ +#define VERR_IPE_UNEXPECTED_STATUS (-230) +/** Internal error: Unexpected status code. */ +#define VERR_IPE_UNEXPECTED_INFO_STATUS (-231) +/** Internal error: Unexpected status code. */ +#define VERR_IPE_UNEXPECTED_ERROR_STATUS (-232) +/** Internal error: Uninitialized status code. + * @remarks This is used by value elsewhere. */ +#define VERR_IPE_UNINITIALIZED_STATUS (-233) +/** Internal error: Supposedly unreachable default case in a switch. */ +#define VERR_IPE_NOT_REACHED_DEFAULT_CASE (-234) +/** @} */ + + +/** @name Generic Device I/O Status Codes + * @{ + */ +/** Unresolved (unknown) device i/o error. */ +#define VERR_DEV_IO_ERROR (-250) +/** Device i/o: Bad unit. */ +#define VERR_IO_BAD_UNIT (-251) +/** Device i/o: Not ready. */ +#define VERR_IO_NOT_READY (-252) +/** Device i/o: Bad command. */ +#define VERR_IO_BAD_COMMAND (-253) +/** Device i/o: CRC error. */ +#define VERR_IO_CRC (-254) +/** Device i/o: Bad length. */ +#define VERR_IO_BAD_LENGTH (-255) +/** Device i/o: Sector not found. */ +#define VERR_IO_SECTOR_NOT_FOUND (-256) +/** Device i/o: General failure. */ +#define VERR_IO_GEN_FAILURE (-257) +/** @} */ + + +/** @name Generic Pipe I/O Status Codes + * @{ + */ +/** Unresolved (unknown) pipe i/o error. */ +#define VERR_PIPE_IO_ERROR (-300) +/** Broken pipe. */ +#define VERR_BROKEN_PIPE (-301) +/** Bad pipe. */ +#define VERR_BAD_PIPE (-302) +/** Pipe is busy. */ +#define VERR_PIPE_BUSY (-303) +/** No data in pipe. */ +#define VERR_NO_DATA (-304) +/** Pipe is not connected. */ +#define VERR_PIPE_NOT_CONNECTED (-305) +/** More data available in pipe. */ +#define VERR_MORE_DATA (-306) +/** Expected read pipe, got a write pipe instead. */ +#define VERR_PIPE_NOT_READ (-307) +/** Expected write pipe, got a read pipe instead. */ +#define VERR_PIPE_NOT_WRITE (-308) +/** @} */ + + +/** @name Generic Semaphores Status Codes + * @{ + */ +/** Unresolved (unknown) semaphore error. */ +#define VERR_SEM_ERROR (-350) +/** Too many semaphores. */ +#define VERR_TOO_MANY_SEMAPHORES (-351) +/** Exclusive semaphore is owned by another process. */ +#define VERR_EXCL_SEM_ALREADY_OWNED (-352) +/** The semaphore is set and cannot be closed. */ +#define VERR_SEM_IS_SET (-353) +/** The semaphore cannot be set again. */ +#define VERR_TOO_MANY_SEM_REQUESTS (-354) +/** Attempt to release mutex not owned by caller. */ +#define VERR_NOT_OWNER (-355) +/** The semaphore has been opened too many times. */ +#define VERR_TOO_MANY_OPENS (-356) +/** The maximum posts for the event semaphore has been reached. */ +#define VERR_TOO_MANY_POSTS (-357) +/** The event semaphore has already been posted. */ +#define VERR_ALREADY_POSTED (-358) +/** The event semaphore has already been posted. */ +#define VINF_ALREADY_POSTED (358) +/** The event semaphore has already been reset. */ +#define VERR_ALREADY_RESET (-359) +/** The semaphore is in use. */ +#define VERR_SEM_BUSY (-360) +/** The previous ownership of this semaphore has ended. */ +#define VERR_SEM_OWNER_DIED (-361) +/** Failed to open semaphore by name - not found. */ +#define VERR_SEM_NOT_FOUND (-362) +/** Semaphore destroyed while waiting. */ +#define VERR_SEM_DESTROYED (-363) +/** Nested ownership requests are not permitted for this semaphore type. */ +#define VERR_SEM_NESTED (-364) +/** The release call only release a semaphore nesting, i.e. the caller is still + * holding the semaphore. */ +#define VINF_SEM_NESTED (364) +/** Deadlock detected. */ +#define VERR_DEADLOCK (-365) +/** Ping-Pong listen or speak out of turn error. */ +#define VERR_SEM_OUT_OF_TURN (-366) +/** Tried to take a semaphore in a bad context. */ +#define VERR_SEM_BAD_CONTEXT (-367) +/** Don't spin for the semaphore, but it is safe to try grab it. */ +#define VINF_SEM_BAD_CONTEXT (367) +/** Wrong locking order detected. */ +#define VERR_SEM_LV_WRONG_ORDER (-368) +/** Wrong release order detected. */ +#define VERR_SEM_LV_WRONG_RELEASE_ORDER (-369) +/** Attempt to recursively enter a non-recursive lock. */ +#define VERR_SEM_LV_NESTED (-370) +/** Invalid parameters passed to the lock validator. */ +#define VERR_SEM_LV_INVALID_PARAMETER (-371) +/** The lock validator detected a deadlock. */ +#define VERR_SEM_LV_DEADLOCK (-372) +/** The lock validator detected an existing deadlock. + * The deadlock was not caused by the current operation, but existed already. */ +#define VERR_SEM_LV_EXISTING_DEADLOCK (-373) +/** Not the lock owner according our records. */ +#define VERR_SEM_LV_NOT_OWNER (-374) +/** An illegal lock upgrade was attempted. */ +#define VERR_SEM_LV_ILLEGAL_UPGRADE (-375) +/** The thread is not a valid signaller of the event. */ +#define VERR_SEM_LV_NOT_SIGNALLER (-376) +/** Internal error in the lock validator or related components. */ +#define VERR_SEM_LV_INTERNAL_ERROR (-377) +/** @} */ + + +/** @name Generic Network I/O Status Codes + * @{ + */ +/** Unresolved (unknown) network error. */ +#define VERR_NET_IO_ERROR (-400) +/** The network is busy or is out of resources. */ +#define VERR_NET_OUT_OF_RESOURCES (-401) +/** Net host name not found. */ +#define VERR_NET_HOST_NOT_FOUND (-402) +/** Network path not found. */ +#define VERR_NET_PATH_NOT_FOUND (-403) +/** General network printing error. */ +#define VERR_NET_PRINT_ERROR (-404) +/** The machine is not on the network. */ +#define VERR_NET_NO_NETWORK (-405) +/** Name is not unique on the network. */ +#define VERR_NET_NOT_UNIQUE_NAME (-406) + +/* These are BSD networking error codes - numbers correspond, don't mess! */ +/** Operation in progress. */ +#define VERR_NET_IN_PROGRESS (-436) +/** Operation already in progress. */ +#define VERR_NET_ALREADY_IN_PROGRESS (-437) +/** Attempted socket operation with a non-socket handle. + * (This includes closed handles.) */ +#define VERR_NET_NOT_SOCKET (-438) +/** Destination address required. */ +#define VERR_NET_DEST_ADDRESS_REQUIRED (-439) +/** Message too long. */ +#define VERR_NET_MSG_SIZE (-440) +/** Protocol wrong type for socket. */ +#define VERR_NET_PROTOCOL_TYPE (-441) +/** Protocol not available. */ +#define VERR_NET_PROTOCOL_NOT_AVAILABLE (-442) +/** Protocol not supported. */ +#define VERR_NET_PROTOCOL_NOT_SUPPORTED (-443) +/** Socket type not supported. */ +#define VERR_NET_SOCKET_TYPE_NOT_SUPPORTED (-444) +/** Operation not supported. */ +#define VERR_NET_OPERATION_NOT_SUPPORTED (-445) +/** Protocol family not supported. */ +#define VERR_NET_PROTOCOL_FAMILY_NOT_SUPPORTED (-446) +/** Address family not supported by protocol family. */ +#define VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED (-447) +/** Address already in use. */ +#define VERR_NET_ADDRESS_IN_USE (-448) +/** Can't assign requested address. */ +#define VERR_NET_ADDRESS_NOT_AVAILABLE (-449) +/** Network is down. */ +#define VERR_NET_DOWN (-450) +/** Network is unreachable. */ +#define VERR_NET_UNREACHABLE (-451) +/** Network dropped connection on reset. */ +#define VERR_NET_CONNECTION_RESET (-452) +/** Software caused connection abort. */ +#define VERR_NET_CONNECTION_ABORTED (-453) +/** Connection reset by peer. */ +#define VERR_NET_CONNECTION_RESET_BY_PEER (-454) +/** No buffer space available. */ +#define VERR_NET_NO_BUFFER_SPACE (-455) +/** Socket is already connected. */ +#define VERR_NET_ALREADY_CONNECTED (-456) +/** Socket is not connected. */ +#define VERR_NET_NOT_CONNECTED (-457) +/** Can't send after socket shutdown. */ +#define VERR_NET_SHUTDOWN (-458) +/** Too many references: can't splice. */ +#define VERR_NET_TOO_MANY_REFERENCES (-459) +/** Too many references: can't splice. */ +#define VERR_NET_CONNECTION_TIMED_OUT (-460) +/** Connection refused. */ +#define VERR_NET_CONNECTION_REFUSED (-461) +/* ELOOP is not net. */ +/* ENAMETOOLONG is not net. */ +/** Host is down. */ +#define VERR_NET_HOST_DOWN (-464) +/** No route to host. */ +#define VERR_NET_HOST_UNREACHABLE (-465) +/** Protocol error. */ +#define VERR_NET_PROTOCOL_ERROR (-466) +/** Incomplete packet was submitted by guest. */ +#define VERR_NET_INCOMPLETE_TX_PACKET (-467) +/** Winsock init error. */ +#define VERR_NET_INIT_FAILED (-468) +/** Trying to use too new winsock API. */ +#define VERR_NET_NOT_UNSUPPORTED (-469) +/** @} */ + + +/** @name TCP Status Codes + * @{ + */ +/** Stop the TCP server. */ +#define VERR_TCP_SERVER_STOP (-500) +/** The server was stopped. */ +#define VINF_TCP_SERVER_STOP 500 +/** The TCP server was shut down using RTTcpServerShutdown. */ +#define VERR_TCP_SERVER_SHUTDOWN (-501) +/** The TCP server was destroyed. */ +#define VERR_TCP_SERVER_DESTROYED (-502) +/** The TCP server has no client associated with it. */ +#define VINF_TCP_SERVER_NO_CLIENT 503 +/** @} */ + + +/** @name UDP Status Codes + * @{ + */ +/** Stop the UDP server. */ +#define VERR_UDP_SERVER_STOP (-520) +/** The server was stopped. */ +#define VINF_UDP_SERVER_STOP 520 +/** The UDP server was shut down using RTUdpServerShutdown. */ +#define VERR_UDP_SERVER_SHUTDOWN (-521) +/** The UDP server was destroyed. */ +#define VERR_UDP_SERVER_DESTROYED (-522) +/** The UDP server has no client associated with it. */ +#define VINF_UDP_SERVER_NO_CLIENT 523 +/** @} */ + + +/** @name L4 Specific Status Codes + * @{ + */ +/** Invalid offset in an L4 dataspace */ +#define VERR_L4_INVALID_DS_OFFSET (-550) +/** IPC error */ +#define VERR_IPC (-551) +/** Item already used */ +#define VERR_RESOURCE_IN_USE (-552) +/** Source/destination not found */ +#define VERR_IPC_PROCESS_NOT_FOUND (-553) +/** Receive timeout */ +#define VERR_IPC_RECEIVE_TIMEOUT (-554) +/** Send timeout */ +#define VERR_IPC_SEND_TIMEOUT (-555) +/** Receive cancelled */ +#define VERR_IPC_RECEIVE_CANCELLED (-556) +/** Send cancelled */ +#define VERR_IPC_SEND_CANCELLED (-557) +/** Receive aborted */ +#define VERR_IPC_RECEIVE_ABORTED (-558) +/** Send aborted */ +#define VERR_IPC_SEND_ABORTED (-559) +/** Couldn't map pages during receive */ +#define VERR_IPC_RECEIVE_MAP_FAILED (-560) +/** Couldn't map pages during send */ +#define VERR_IPC_SEND_MAP_FAILED (-561) +/** Send pagefault timeout in receive */ +#define VERR_IPC_RECEIVE_SEND_PF_TIMEOUT (-562) +/** Send pagefault timeout in send */ +#define VERR_IPC_SEND_SEND_PF_TIMEOUT (-563) +/** (One) receive buffer was too small, or too few buffers */ +#define VINF_IPC_RECEIVE_MSG_CUT 564 +/** (One) send buffer was too small, or too few buffers */ +#define VINF_IPC_SEND_MSG_CUT 565 +/** Dataspace manager server not found */ +#define VERR_L4_DS_MANAGER_NOT_FOUND (-566) +/** @} */ + + +/** @name Loader Status Codes. + * @{ + */ +/** Invalid executable signature. */ +#define VERR_INVALID_EXE_SIGNATURE (-600) +/** The iprt loader recognized a ELF image, but doesn't support loading it. */ +#define VERR_ELF_EXE_NOT_SUPPORTED (-601) +/** The iprt loader recognized a PE image, but doesn't support loading it. */ +#define VERR_PE_EXE_NOT_SUPPORTED (-602) +/** The iprt loader recognized a LX image, but doesn't support loading it. */ +#define VERR_LX_EXE_NOT_SUPPORTED (-603) +/** The iprt loader recognized a LE image, but doesn't support loading it. */ +#define VERR_LE_EXE_NOT_SUPPORTED (-604) +/** The iprt loader recognized a NE image, but doesn't support loading it. */ +#define VERR_NE_EXE_NOT_SUPPORTED (-605) +/** The iprt loader recognized a MZ image, but doesn't support loading it. */ +#define VERR_MZ_EXE_NOT_SUPPORTED (-606) +/** The iprt loader recognized an a.out image, but doesn't support loading it. */ +#define VERR_AOUT_EXE_NOT_SUPPORTED (-607) +/** Bad executable. */ +#define VERR_BAD_EXE_FORMAT (-608) +/** Symbol (export) not found. */ +#define VERR_SYMBOL_NOT_FOUND (-609) +/** Module not found. */ +#define VERR_MODULE_NOT_FOUND (-610) +/** The loader resolved an external symbol to an address to big for the image format. */ +#define VERR_SYMBOL_VALUE_TOO_BIG (-611) +/** The image is too big. */ +#define VERR_IMAGE_TOO_BIG (-612) +/** The image base address is to high for this image type. */ +#define VERR_IMAGE_BASE_TOO_HIGH (-614) +/** Mismatching architecture. */ +#define VERR_LDR_ARCH_MISMATCH (-615) +/** Mismatch between IPRT and native loader. */ +#define VERR_LDR_MISMATCH_NATIVE (-616) +/** Failed to resolve an imported (external) symbol. */ +#define VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND (-617) +/** Generic loader failure. */ +#define VERR_LDR_GENERAL_FAILURE (-618) +/** Code signing error. */ +#define VERR_LDR_IMAGE_HASH (-619) +/** The PE loader encountered delayed imports, a feature which hasn't been implemented yet. */ +#define VERR_LDRPE_DELAY_IMPORT (-620) +/** The PE loader encountered a malformed certificate. */ +#define VERR_LDRPE_CERT_MALFORMED (-621) +/** The PE loader encountered a certificate with an unsupported type or structure revision. */ +#define VERR_LDRPE_CERT_UNSUPPORTED (-622) +/** The PE loader doesn't know how to deal with the global pointer data directory entry yet. */ +#define VERR_LDRPE_GLOBALPTR (-623) +/** The PE loader doesn't support the TLS data directory yet. */ +#define VERR_LDRPE_TLS (-624) +/** The PE loader doesn't grok the COM descriptor data directory entry. */ +#define VERR_LDRPE_COM_DESCRIPTOR (-625) +/** The PE loader encountered an unknown load config directory/header size. */ +#define VERR_LDRPE_LOAD_CONFIG_SIZE (-626) +/** The PE loader encountered a lock prefix table, a feature which hasn't been implemented yet. */ +#define VERR_LDRPE_LOCK_PREFIX_TABLE (-627) +/** The PE loader encountered some Guard CF stuff in the load config. */ +#define VERR_LDRPE_GUARD_CF_STUFF (-628) +/** The ELF loader doesn't handle foreign endianness. */ +#define VERR_LDRELF_ODD_ENDIAN (-630) +/** The ELF image is 'dynamic', the ELF loader can only deal with 'relocatable' images at present. */ +#define VERR_LDRELF_DYN (-631) +/** The ELF image is 'executable', the ELF loader can only deal with 'relocatable' images at present. */ +#define VERR_LDRELF_EXEC (-632) +/** The ELF image was created for an unsupported target machine type. */ +#define VERR_LDRELF_MACHINE (-633) +/** The ELF version is not supported. */ +#define VERR_LDRELF_VERSION (-634) +/** The ELF loader cannot handle multiple SYMTAB sections. */ +#define VERR_LDRELF_MULTIPLE_SYMTABS (-635) +/** The ELF loader encountered a relocation type which is not implemented. */ +#define VERR_LDRELF_RELOCATION_NOT_SUPPORTED (-636) +/** The ELF loader encountered a bad symbol index. */ +#define VERR_LDRELF_INVALID_SYMBOL_INDEX (-637) +/** The ELF loader encountered an invalid symbol name offset. */ +#define VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET (-638) +/** The ELF loader encountered an invalid relocation offset. */ +#define VERR_LDRELF_INVALID_RELOCATION_OFFSET (-639) +/** The ELF loader didn't find the symbol/string table for the image. */ +#define VERR_LDRELF_NO_SYMBOL_OR_NO_STRING_TABS (-640) +/** The ELF loader encountered an unterminated string table. */ +#define VERR_LDRELF_UNTERMINATED_STRING_TAB (-641) +/** Invalid link address. */ +#define VERR_LDR_INVALID_LINK_ADDRESS (-647) +/** Invalid image relative virtual address. */ +#define VERR_LDR_INVALID_RVA (-648) +/** Invalid segment:offset address. */ +#define VERR_LDR_INVALID_SEG_OFFSET (-649) +/** @}*/ + +/** @name Debug Info Reader Status Codes. + * @{ + */ +/** The module contains no line number information. */ +#define VERR_DBG_NO_LINE_NUMBERS (-650) +/** The module contains no symbol information. */ +#define VERR_DBG_NO_SYMBOLS (-651) +/** The specified segment:offset address was invalid. Typically an attempt at + * addressing outside the segment boundary. */ +#define VERR_DBG_INVALID_ADDRESS (-652) +/** Invalid segment index. */ +#define VERR_DBG_INVALID_SEGMENT_INDEX (-653) +/** Invalid segment offset. */ +#define VERR_DBG_INVALID_SEGMENT_OFFSET (-654) +/** Invalid image relative virtual address. */ +#define VERR_DBG_INVALID_RVA (-655) +/** Invalid image relative virtual address. */ +#define VERR_DBG_SPECIAL_SEGMENT (-656) +/** Address conflict within a module/segment. + * Attempted to add a segment, symbol or line number that fully or partially + * overlaps with an existing one. */ +#define VERR_DBG_ADDRESS_CONFLICT (-657) +/** Duplicate symbol within the module. + * Attempted to add a symbol which name already exists within the module. */ +#define VERR_DBG_DUPLICATE_SYMBOL (-658) +/** The segment index specified when adding a new segment is already in use. */ +#define VERR_DBG_SEGMENT_INDEX_CONFLICT (-659) +/** No line number was found for the specified address/ordinal/whatever. */ +#define VERR_DBG_LINE_NOT_FOUND (-660) +/** The length of the symbol name is out of range. + * This means it is an empty string or that it's greater or equal to + * RTDBG_SYMBOL_NAME_LENGTH. */ +#define VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE (-661) +/** The length of the file name is out of range. + * This means it is an empty string or that it's greater or equal to + * RTDBG_FILE_NAME_LENGTH. */ +#define VERR_DBG_FILE_NAME_OUT_OF_RANGE (-662) +/** The length of the segment name is out of range. + * This means it is an empty string or that it is greater or equal to + * RTDBG_SEGMENT_NAME_LENGTH. */ +#define VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE (-663) +/** The specified address range wraps around. */ +#define VERR_DBG_ADDRESS_WRAP (-664) +/** The file is not a valid NM map file. */ +#define VERR_DBG_NOT_NM_MAP_FILE (-665) +/** The file is not a valid /proc/kallsyms file. */ +#define VERR_DBG_NOT_LINUX_KALLSYMS (-666) +/** No debug module interpreter matching the debug info. */ +#define VERR_DBG_NO_MATCHING_INTERPRETER (-667) +/** Bad DWARF line number header. */ +#define VERR_DWARF_BAD_LINE_NUMBER_HEADER (-668) +/** Unexpected end of DWARF unit. */ +#define VERR_DWARF_UNEXPECTED_END (-669) +/** DWARF LEB value overflows the decoder type. */ +#define VERR_DWARF_LEB_OVERFLOW (-670) +/** Bad DWARF extended line number opcode. */ +#define VERR_DWARF_BAD_LNE (-671) +/** Bad DWARF string. */ +#define VERR_DWARF_BAD_STRING (-672) +/** Bad DWARF position. */ +#define VERR_DWARF_BAD_POS (-673) +/** Bad DWARF info. */ +#define VERR_DWARF_BAD_INFO (-674) +/** Bad DWARF abbreviation data. */ +#define VERR_DWARF_BAD_ABBREV (-675) +/** A DWARF abbreviation was not found. */ +#define VERR_DWARF_ABBREV_NOT_FOUND (-676) +/** Encountered an unknown attribute form. */ +#define VERR_DWARF_UNKNOWN_FORM (-677) +/** Encountered an unexpected attribute form. */ +#define VERR_DWARF_UNEXPECTED_FORM (-678) +/** Unfinished code. */ +#define VERR_DWARF_TODO (-679) +/** Unknown location opcode. */ +#define VERR_DWARF_UNKNOWN_LOC_OPCODE (-680) +/** Expression stack overflow. */ +#define VERR_DWARF_STACK_OVERFLOW (-681) +/** Expression stack underflow. */ +#define VERR_DWARF_STACK_UNDERFLOW (-682) +/** Internal processing error in the DWARF code. */ +#define VERR_DWARF_IPE (-683) +/** Invalid configuration property value. */ +#define VERR_DBG_CFG_INVALID_VALUE (-684) +/** Not an integer property. */ +#define VERR_DBG_CFG_NOT_UINT_PROP (-685) +/** Deferred loading of information failed. */ +#define VERR_DBG_DEFERRED_LOAD_FAILED (-686) +/** Unfinished debug info reader code. */ +#define VERR_DBG_TODO (-687) +/** Found file, but it didn't match the search criteria. */ +#define VERR_DBG_FILE_MISMATCH (-688) +/** Internal processing error in the debug module reader code. */ +#define VERR_DBG_MOD_IPE (-689) +/** The symbol size was adjusted while adding it. */ +#define VINF_DBG_ADJUSTED_SYM_SIZE 690 +/** Unable to parse the CodeView debug information. */ +#define VERR_CV_BAD_FORMAT (-691) +/** Unfinished CodeView debug information feature. */ +#define VERR_CV_TODO (-692) +/** Internal processing error the CodeView debug information reader. */ +#define VERR_CV_IPE (-693) +/** No unwind information was found. */ +#define VERR_DBG_NO_UNWIND_INFO (-694) +/** No unwind information for the specified location. */ +#define VERR_DBG_UNWIND_INFO_NOT_FOUND (-695) +/** Malformed unwind information. */ +#define VERR_DBG_MALFORMED_UNWIND_INFO (-696) +/** @} */ + +/** @name Request Packet Status Codes. + * @{ + */ +/** Invalid RT request type. + * For the RTReqAlloc() case, the caller just specified an illegal enmType. For + * all the other occurrences it means indicates corruption, broken logic, or stupid + * interface user. */ +#define VERR_RT_REQUEST_INVALID_TYPE (-700) +/** Invalid RT request state. + * The state of the request packet was not the expected and accepted one(s). Either + * the interface user screwed up, or we've got corruption/broken logic. */ +#define VERR_RT_REQUEST_STATE (-701) +/** Invalid RT request packet. + * One or more of the RT controlled packet members didn't contain the correct + * values. Some thing's broken. */ +#define VERR_RT_REQUEST_INVALID_PACKAGE (-702) +/** The status field has not been updated yet as the request is still + * pending completion. Someone queried the iStatus field before the request + * has been fully processed. */ +#define VERR_RT_REQUEST_STATUS_STILL_PENDING (-703) +/** The request has been freed, don't read the status now. + * Someone is reading the iStatus field of a freed request packet. */ +#define VERR_RT_REQUEST_STATUS_FREED (-704) +/** @} */ + +/** @name Environment Status Code + * @{ + */ +/** The specified environment variable was not found. (RTEnvGetEx) */ +#define VERR_ENV_VAR_NOT_FOUND (-750) +/** The specified environment variable was not found. (RTEnvUnsetEx) */ +#define VINF_ENV_VAR_NOT_FOUND (750) +/** Unable to translate all the variables in the default environment due to + * codeset issues (LANG / LC_ALL / LC_CTYPE). */ +#define VWRN_ENV_NOT_FULLY_TRANSLATED (751) +/** Invalid environment variable name. */ +#define VERR_ENV_INVALID_VAR_NAME (-752) +/** The environment variable is an unset record. */ +#define VINF_ENV_VAR_UNSET (753) +/** The environment variable has been recorded as being unset. */ +#define VERR_ENV_VAR_UNSET (-753) +/** @} */ + +/** @name Multiprocessor Status Codes. + * @{ + */ +/** The specified cpu is offline. */ +#define VERR_CPU_OFFLINE (-800) +/** The specified cpu was not found. */ +#define VERR_CPU_NOT_FOUND (-801) +/** Not all of the requested CPUs showed up in the PFNRTMPWORKER. */ +#define VERR_NOT_ALL_CPUS_SHOWED (-802) +/** Internal processing error in the RTMp code.*/ +#define VERR_CPU_IPE_1 (-803) +/** @} */ + +/** @name RTGetOpt status codes + * @{ */ +/** RTGetOpt: Command line option not recognized. */ +#define VERR_GETOPT_UNKNOWN_OPTION (-825) +/** RTGetOpt: Command line option needs argument. */ +#define VERR_GETOPT_REQUIRED_ARGUMENT_MISSING (-826) +/** RTGetOpt: Command line option has argument with bad format. */ +#define VERR_GETOPT_INVALID_ARGUMENT_FORMAT (-827) +/** RTGetOpt: Not an option. */ +#define VINF_GETOPT_NOT_OPTION 828 +/** RTGetOpt: Command line option needs an index. */ +#define VERR_GETOPT_INDEX_MISSING (-829) +/** @} */ + +/** @name RTCache status codes + * @{ */ +/** RTCache: cache is full. */ +#define VERR_CACHE_FULL (-850) +/** RTCache: cache is empty. */ +#define VERR_CACHE_EMPTY (-851) +/** @} */ + +/** @name RTMemCache status codes + * @{ */ +/** Reached the max cache size. */ +#define VERR_MEM_CACHE_MAX_SIZE (-855) +/** @} */ + +/** @name RTS3 status codes + * @{ */ +/** Access denied error. */ +#define VERR_S3_ACCESS_DENIED (-875) +/** The bucket/key wasn't found. */ +#define VERR_S3_NOT_FOUND (-876) +/** Bucket already exists. */ +#define VERR_S3_BUCKET_ALREADY_EXISTS (-877) +/** Can't delete bucket with keys. */ +#define VERR_S3_BUCKET_NOT_EMPTY (-878) +/** The current operation was canceled. */ +#define VERR_S3_CANCELED (-879) +/** @} */ + +/** @name HTTP status codes + * @{ */ +/** HTTP Internal Server Error. */ +#define VERR_HTTP_STATUS_SERVER_ERROR (-884) +/** HTTP initialization failed. */ +#define VERR_HTTP_INIT_FAILED (-885) +/** The server has not found anything matching the URI given. */ +#define VERR_HTTP_NOT_FOUND (-886) +/** The request is for something forbidden. Authorization will not help. */ +#define VERR_HTTP_ACCESS_DENIED (-887) +/** The server did not understand the request due to bad syntax. */ +#define VERR_HTTP_BAD_REQUEST (-888) +/** Couldn't connect to the server (proxy?). */ +#define VERR_HTTP_COULDNT_CONNECT (-889) +/** SSL connection error. */ +#define VERR_HTTP_SSL_CONNECT_ERROR (-890) +/** CAcert is missing or has the wrong format. */ +#define VERR_HTTP_CACERT_WRONG_FORMAT (-891) +/** Certificate cannot be authenticated with the given CA certificates. */ +#define VERR_HTTP_CACERT_CANNOT_AUTHENTICATE (-892) +/** The current HTTP request was forcefully aborted */ +#define VERR_HTTP_ABORTED (-893) +/** Request was redirected. */ +#define VERR_HTTP_REDIRECTED (-894) +/** Proxy couldn't be resolved. */ +#define VERR_HTTP_PROXY_NOT_FOUND (-895) +/** The remote host couldn't be resolved. */ +#define VERR_HTTP_HOST_NOT_FOUND (-896) +/** Unexpected cURL error configure the proxy. */ +#define VERR_HTTP_CURL_PROXY_CONFIG (-897) +/** Generic CURL error. */ +#define VERR_HTTP_CURL_ERROR (-899) +/** @} */ + +/** @name RTManifest status codes + * @{ */ +/** A digest type used in the manifest file isn't supported. */ +#define VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE (-900) +/** An entry in the manifest file couldn't be interpreted correctly. */ +#define VERR_MANIFEST_WRONG_FILE_FORMAT (-901) +/** A digest doesn't match the corresponding file. */ +#define VERR_MANIFEST_DIGEST_MISMATCH (-902) +/** The file list doesn't match to the content of the manifest file. */ +#define VERR_MANIFEST_FILE_MISMATCH (-903) +/** The specified attribute (name) was not found in the manifest. */ +#define VERR_MANIFEST_ATTR_NOT_FOUND (-904) +/** The attribute type did not match. */ +#define VERR_MANIFEST_ATTR_TYPE_MISMATCH (-905) +/** No attribute of the specified types was found. */ +#define VERR_MANIFEST_ATTR_TYPE_NOT_FOUND (-906) +/** @} */ + +/** @name RTTar status codes + * @{ */ +/** The checksum of a tar header record doesn't match. */ +#define VERR_TAR_CHKSUM_MISMATCH (-925) +/** The tar end of file record was read. */ +#define VERR_TAR_END_OF_FILE (-926) +/** The tar file ended unexpectedly. */ +#define VERR_TAR_UNEXPECTED_EOS (-927) +/** The tar termination records was encountered without reaching the end of + * the input stream. */ +#define VERR_TAR_EOS_MORE_INPUT (-928) +/** A number tar header field was malformed. */ +#define VERR_TAR_BAD_NUM_FIELD (-929) +/** A numeric tar header field was not terminated correctly. */ +#define VERR_TAR_BAD_NUM_FIELD_TERM (-930) +/** A number tar header field was encoded using base-256 which this + * tar implementation currently does not support. */ +#define VERR_TAR_BASE_256_NOT_SUPPORTED (-931) +/** A number tar header field yielded a value too large for the internal + * variable of the tar interpreter. */ +#define VERR_TAR_NUM_VALUE_TOO_LARGE (-932) +/** The combined minor and major device number type is too small to hold the + * value stored in the tar header. */ +#define VERR_TAR_DEV_VALUE_TOO_LARGE (-933) +/** The mode field in a tar header is bad. */ +#define VERR_TAR_BAD_MODE_FIELD (-934) +/** The mode field should not include the type. */ +#define VERR_TAR_MODE_WITH_TYPE (-935) +/** The size field should be zero for links and symlinks. */ +#define VERR_TAR_SIZE_NOT_ZERO (-936) +/** Encountered an unknown type flag. */ +#define VERR_TAR_UNKNOWN_TYPE_FLAG (-937) +/** The tar header is all zeros. */ +#define VERR_TAR_ZERO_HEADER (-938) +/** Not a uniform standard tape v0.0 archive header. */ +#define VERR_TAR_NOT_USTAR_V00 (-939) +/** The name is empty. */ +#define VERR_TAR_EMPTY_NAME (-940) +/** A non-directory entry has a name ending with a slash. */ +#define VERR_TAR_NON_DIR_ENDS_WITH_SLASH (-941) +/** Encountered an unsupported portable archive exchange (pax) header. */ +#define VERR_TAR_UNSUPPORTED_PAX_TYPE (-942) +/** Encountered an unsupported Solaris Tar extension. */ +#define VERR_TAR_UNSUPPORTED_SOLARIS_HDR_TYPE (-943) +/** Encountered an unsupported GNU Tar extension. */ +#define VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE (-944) +/** Malformed checksum field in the tar header. */ +#define VERR_TAR_BAD_CHKSUM_FIELD (-945) +/** Malformed checksum field in the tar header. */ +#define VERR_TAR_MALFORMED_GNU_LONGXXXX (-946) +/** Too long name or link string. */ +#define VERR_TAR_NAME_TOO_LONG (-947) +/** A directory entry in the archive. */ +#define VINF_TAR_DIR_PATH (948) +/** @} */ + +/** @name RTPoll status codes + * @{ */ +/** The handle is not pollable. */ +#define VERR_POLL_HANDLE_NOT_POLLABLE (-950) +/** The handle ID is already present in the poll set. */ +#define VERR_POLL_HANDLE_ID_EXISTS (-951) +/** The handle ID was not found in the set. */ +#define VERR_POLL_HANDLE_ID_NOT_FOUND (-952) +/** The poll set is full. */ +#define VERR_POLL_SET_IS_FULL (-953) +/** @} */ + +/** @name Pkzip status codes + * @{ */ +/** No end of central directory record found. */ +#define VERR_PKZIP_NO_EOCB (-960) +/** Too long name string. */ +#define VERR_PKZIP_NAME_TOO_LONG (-961) +/** Local file header corrupt. */ +#define VERR_PKZIP_BAD_LF_HEADER (-962) +/** Central directory file header corrupt. */ +#define VERR_PKZIP_BAD_CDF_HEADER (-963) +/** Encountered an unknown type flag. */ +#define VERR_PKZIP_UNKNOWN_TYPE_FLAG (-964) +/** Found a ZIP64 Extra Information Field in a ZIP32 file. */ +#define VERR_PKZIP_ZIP64EX_IN_ZIP32 (-965) +/** @} */ + +/** @name RTZip status codes + * @{ */ +/** Generic zip error. */ +#define VERR_ZIP_ERROR (-22000) +/** The compressed data was corrupted. */ +#define VERR_ZIP_CORRUPTED (-22001) +/** Ran out of memory while compressing or uncompressing. */ +#define VERR_ZIP_NO_MEMORY (-22002) +/** The compression format version is unsupported. */ +#define VERR_ZIP_UNSUPPORTED_VERSION (-22003) +/** The compression method is unsupported. */ +#define VERR_ZIP_UNSUPPORTED_METHOD (-22004) +/** The compressed data started with a bad header. */ +#define VERR_ZIP_BAD_HEADER (-22005) +/** @} */ + +/** @name RTVfs status codes + * @{ */ +/** The VFS chain specification does not have a valid prefix. */ +#define VERR_VFS_CHAIN_NO_PREFIX (-22100) +/** The VFS chain specification is empty. */ +#define VERR_VFS_CHAIN_EMPTY (-22101) +/** Expected an element. */ +#define VERR_VFS_CHAIN_EXPECTED_ELEMENT (-22102) +/** The VFS object type is not known. */ +#define VERR_VFS_CHAIN_UNKNOWN_TYPE (-22103) +/** Expected a left parentheses. */ +#define VERR_VFS_CHAIN_EXPECTED_LEFT_PARENTHESES (-22104) +/** Expected a right parentheses. */ +#define VERR_VFS_CHAIN_EXPECTED_RIGHT_PARENTHESES (-22105) +/** Expected a provider name. */ +#define VERR_VFS_CHAIN_EXPECTED_PROVIDER_NAME (-22106) +/** Expected an element separator (| or :). */ +#define VERR_VFS_CHAIN_EXPECTED_SEPARATOR (-22107) +/** Leading element separator not permitted. */ +#define VERR_VFS_CHAIN_LEADING_SEPARATOR (-22108) +/** Trailing element separator not permitted. */ +#define VERR_VFS_CHAIN_TRAILING_SEPARATOR (-22109) +/** The provider is only allowed as the first element. */ +#define VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT (-22110) +/** The provider cannot be the first element. */ +#define VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT (-22111) +/** VFS object cast failed. */ +#define VERR_VFS_CHAIN_CAST_FAILED (-22112) +/** Internal error in the VFS chain code. */ +#define VERR_VFS_CHAIN_IPE (-22113) +/** VFS chain element provider not found. */ +#define VERR_VFS_CHAIN_PROVIDER_NOT_FOUND (-22114) +/** VFS chain does not terminate with the desired object type. */ +#define VERR_VFS_CHAIN_FINAL_TYPE_MISMATCH (-22115) +/** VFS chain element takes no arguments. */ +#define VERR_VFS_CHAIN_NO_ARGS (-22116) +/** VFS chain element takes exactly one argument. */ +#define VERR_VFS_CHAIN_ONE_ARG (-22117) +/** VFS chain element expected at most one argument. */ +#define VERR_VFS_CHAIN_AT_MOST_ONE_ARG (-22118) +/** VFS chain element expected at least one argument. */ +#define VERR_VFS_CHAIN_AT_LEAST_ONE_ARG (-22119) +/** VFS chain element takes exactly two arguments. */ +#define VERR_VFS_CHAIN_TWO_ARGS (-22120) +/** VFS chain element expected at least two arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_TWO_ARGS (-22121) +/** VFS chain element expected at most two arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_TWO_ARGS (-22122) +/** VFS chain element takes exactly three arguments. */ +#define VERR_VFS_CHAIN_THREE_ARGS (-22123) +/** VFS chain element expected at least three arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_THREE_ARGS (-22124) +/** VFS chain element expected at most three arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_THREE_ARGS (-22125) +/** VFS chain element takes exactly four arguments. */ +#define VERR_VFS_CHAIN_FOUR_ARGS (-22126) +/** VFS chain element expected at least four arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_FOUR_ARGS (-22127) +/** VFS chain element expected at most four arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_FOUR_ARGS (-22128) +/** VFS chain element takes exactly five arguments. */ +#define VERR_VFS_CHAIN_FIVE_ARGS (-22129) +/** VFS chain element expected at least five arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_FIVE_ARGS (-22130) +/** VFS chain element expected at most five arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_FIVE_ARGS (-22131) +/** VFS chain element takes exactly six arguments. */ +#define VERR_VFS_CHAIN_SIX_ARGS (-22132) +/** VFS chain element expected at least six arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_SIX_ARGS (-22133) +/** VFS chain element expected at most six arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_SIX_ARGS (-22134) +/** VFS chain element expected at most six arguments. */ +#define VERR_VFS_CHAIN_TOO_FEW_ARGS (-22135) +/** VFS chain element expected at most six arguments. */ +#define VERR_VFS_CHAIN_TOO_MANY_ARGS (-22136) +/** VFS chain element expected non-empty argument. */ +#define VERR_VFS_CHAIN_EMPTY_ARG (-22137) +/** Invalid argument to VFS chain element. */ +#define VERR_VFS_CHAIN_INVALID_ARGUMENT (-22138) +/** VFS chain element only provides file and I/O stream (ios) objects. */ +#define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS (-22139) +/** VFS chain element only provides I/O stream (ios) objects. */ +#define VERR_VFS_CHAIN_ONLY_IOS (-22140) +/** VFS chain element only provides directory (dir) objects. */ +#define VERR_VFS_CHAIN_ONLY_DIR (-22141) +/** VFS chain element only provides file system stream (fss) objects. */ +#define VERR_VFS_CHAIN_ONLY_FSS (-22142) +/** VFS chain element only provides file system (vfs) objects. */ +#define VERR_VFS_CHAIN_ONLY_VFS (-22143) +/** VFS chain element only provides file, I/O stream (ios), or + * directory (dir) objects. */ +#define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS_OR_DIR (-22144) +/** VFS chain element only provides file, I/O stream (ios), or + * directory (dir) objects. */ +#define VERR_VFS_CHAIN_ONLY_DIR_OR_VFS (-22145) +/** VFS chain element takes a file object as input. */ +#define VERR_VFS_CHAIN_TAKES_FILE (-22146) +/** VFS chain element takes a file or I/O stream (ios) object as input. */ +#define VERR_VFS_CHAIN_TAKES_FILE_OR_IOS (-22147) +/** VFS chain element takes a directory (dir) object as input. */ +#define VERR_VFS_CHAIN_TAKES_DIR (-22148) +/** VFS chain element takes a file system stream (fss) object as input. */ +#define VERR_VFS_CHAIN_TAKES_FSS (-22149) +/** VFS chain element takes a file system (vfs) object as input. */ +#define VERR_VFS_CHAIN_TAKES_VFS (-22150) +/** VFS chain element takes a directory (dir) or file system (vfs) + * object as input. */ +#define VERR_VFS_CHAIN_TAKES_DIR_OR_VFS (-22151) +/** VFS chain element takes a directory (dir), file system stream (fss), + * or file system (vfs) object as input. */ +#define VERR_VFS_CHAIN_TAKES_DIR_OR_FSS_OR_VFS (-22152) +/** VFS chain element only provides a read-only I/O stream, while the chain + * requires write access. */ +#define VERR_VFS_CHAIN_READ_ONLY_IOS (-22153) +/** VFS chain element only provides a read-only I/O stream, while the chain + * read access. */ +#define VERR_VFS_CHAIN_WRITE_ONLY_IOS (-22154) +/** VFS chain only has a single element and it is just a path, need to be + * treated as a normal file system request. */ +#define VERR_VFS_CHAIN_PATH_ONLY (-22155) +/** VFS chain element preceding the final path needs to be a directory, file + * system or file system stream. */ +#define VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY (-22156) +/** VFS chain doesn't end with a path only element. */ +#define VERR_VFS_CHAIN_NOT_PATH_ONLY (-22157) +/** The path only element at the end of the VFS chain is too short to make out + * the parent directory. */ +#define VERR_VFS_CHAIN_TOO_SHORT_FOR_PARENT (-22158) +/** @} */ + +/** @name RTDvm status codes + * @{ */ +/** The volume map doesn't contain any valid volume. */ +#define VERR_DVM_MAP_EMPTY (-22200) +/** There is no volume behind the current one. */ +#define VERR_DVM_MAP_NO_VOLUME (-22201) +/** @} */ + +/** @name Logger status codes + * @{ */ +/** The internal logger revision did not match. */ +#define VERR_LOG_REVISION_MISMATCH (-22300) +/** Logging is disabled or logger instance could not be created. */ +#define VINF_LOG_DISABLED (22301) +/** No logger instance. */ +#define VINF_LOG_NO_LOGGER (22302) +/** @} */ + +/* see above, 22400..22499 is used for misc codes! */ + +/** @name Logger status codes + * @{ */ +/** Power off is not supported by the hardware or the OS. */ +#define VERR_SYS_CANNOT_POWER_OFF (-22500) +/** The halt action was requested, but the OS may actually power + * off the machine. */ +#define VINF_SYS_MAY_POWER_OFF (22501) +/** Shutdown failed. */ +#define VERR_SYS_SHUTDOWN_FAILED (-22502) +/** Unsupported firmware property. */ +#define VERR_SYS_UNSUPPORTED_FIRMWARE_PROPERTY (-22503) +/** @} */ + +/** @name Filesystem status codes + * @{ */ +/** Filesystem can't be opened because it is corrupt. */ +#define VERR_FILESYSTEM_CORRUPT (-22600) +/** @} */ + +/** @name RTZipXar status codes. + * @{ */ +/** Wrong magic value. */ +#define VERR_XAR_WRONG_MAGIC (-22700) +/** Bad header size. */ +#define VERR_XAR_BAD_HDR_SIZE (-22701) +/** Unsupported version. */ +#define VERR_XAR_UNSUPPORTED_VERSION (-22702) +/** Unsupported hashing function. */ +#define VERR_XAR_UNSUPPORTED_HASH_FUNCTION (-22703) +/** The table of content (TOC) is too small and therefore can't be valid. */ +#define VERR_XAR_TOC_TOO_SMALL (-22704) +/** The table of content (TOC) is too big. */ +#define VERR_XAR_TOC_TOO_BIG (-22705) +/** The compressed table of content is too big. */ +#define VERR_XAR_TOC_TOO_BIG_COMPRESSED (-22706) +/** The uncompressed table of content size in the header didn't match what + * ZLib returned. */ +#define VERR_XAR_TOC_UNCOMP_SIZE_MISMATCH (-22707) +/** The table of content string length didn't match the size specified in the + * header. */ +#define VERR_XAR_TOC_STRLEN_MISMATCH (-22708) +/** The table of content isn't valid UTF-8. */ +#define VERR_XAR_TOC_UTF8_ENCODING (-22709) +/** XML error while parsing the table of content. */ +#define VERR_XAR_TOC_XML_PARSE_ERROR (-22710) +/** The table of content XML document does not have a toc element. */ +#define VERR_XML_TOC_ELEMENT_MISSING (-22711) +/** The table of content XML element (toc) has siblings, we expected it to be + * an only child or the root element (xar). */ +#define VERR_XML_TOC_ELEMENT_HAS_SIBLINGS (-22712) +/** The XAR table of content digest doesn't match. */ +#define VERR_XAR_TOC_DIGEST_MISMATCH (-22713) +/** Bad or missing XAR checksum element. */ +#define VERR_XAR_BAD_CHECKSUM_ELEMENT (-22714) +/** The hash function in the header doesn't match the one in the table of + * content. */ +#define VERR_XAR_HASH_FUNCTION_MISMATCH (-22715) +/** Bad digest length encountered in the table of content. */ +#define VERR_XAR_BAD_DIGEST_LENGTH (-22716) +/** The order of elements in the XAR file does not lend it self to expansion + * from via an I/O stream. */ +#define VERR_XAR_NOT_STREAMBLE_ELEMENT_ORDER (-22717) +/** Missing offset element in table of content sub-element. */ +#define VERR_XAR_MISSING_OFFSET_ELEMENT (-22718) +/** Bad offset element in table of content sub-element. */ +#define VERR_XAR_BAD_OFFSET_ELEMENT (-22719) +/** Missing size element in table of content sub-element. */ +#define VERR_XAR_MISSING_SIZE_ELEMENT (-22720) +/** Bad size element in table of content sub-element. */ +#define VERR_XAR_BAD_SIZE_ELEMENT (-22721) +/** Missing length element in table of content sub-element. */ +#define VERR_XAR_MISSING_LENGTH_ELEMENT (-22722) +/** Bad length element in table of content sub-element. */ +#define VERR_XAR_BAD_LENGTH_ELEMENT (-22723) +/** Bad file element in XAR table of content. */ +#define VERR_XAR_BAD_FILE_ELEMENT (-22724) +/** Missing data element for XAR file. */ +#define VERR_XAR_MISSING_DATA_ELEMENT (-22725) +/** Unknown XAR file type value. */ +#define VERR_XAR_UNKNOWN_FILE_TYPE (-22726) +/** Missing encoding element for XAR data stream. */ +#define VERR_XAR_NO_ENCODING (-22727) +/** Bad timestamp for XAR file. */ +#define VERR_XAR_BAD_FILE_TIMESTAMP (-22728) +/** Bad file mode for XAR file. */ +#define VERR_XAR_BAD_FILE_MODE (-22729) +/** Bad file user id for XAR file. */ +#define VERR_XAR_BAD_FILE_UID (-22730) +/** Bad file group id for XAR file. */ +#define VERR_XAR_BAD_FILE_GID (-22731) +/** Bad file inode device number for XAR file. */ +#define VERR_XAR_BAD_FILE_DEVICE_NO (-22732) +/** Bad file inode number for XAR file. */ +#define VERR_XAR_BAD_FILE_INODE (-22733) +/** Invalid name for XAR file. */ +#define VERR_XAR_INVALID_FILE_NAME (-22734) +/** The message digest of the extracted data does not match the one supplied. */ +#define VERR_XAR_EXTRACTED_HASH_MISMATCH (-22735) +/** The extracted data has exceeded the expected size. */ +#define VERR_XAR_EXTRACTED_SIZE_EXCEEDED (-22736) +/** The message digest of the archived data does not match the one supplied. */ +#define VERR_XAR_ARCHIVED_HASH_MISMATCH (-22737) +/** The decompressor completed without using all the input data. */ +#define VERR_XAR_UNUSED_ARCHIVED_DATA (-22738) +/** Expected the archived and extracted XAR data sizes to be the same for + * uncompressed data. */ +#define VERR_XAR_ARCHIVED_AND_EXTRACTED_SIZES_MISMATCH (-22739) +/** @} */ + +/** @name RTX509 status codes + * @{ */ +/** Error reading a certificate in PEM format from BIO. */ +#define VERR_X509_READING_CERT_FROM_BIO (-23100) +/** Error extracting a public key from the certificate. */ +#define VERR_X509_EXTRACT_PUBKEY_FROM_CERT (-23101) +/** Error extracting RSA from the public key. */ +#define VERR_X509_EXTRACT_RSA_FROM_PUBLIC_KEY (-23102) +/** Signature verification failed. */ +#define VERR_X509_RSA_VERIFICATION_FUILURE (-23103) +/** Basic constraints were not found. */ +#define VERR_X509_NO_BASIC_CONSTARAINTS (-23104) +/** Error getting extensions from the certificate. */ +#define VERR_X509_GETTING_EXTENSION_FROM_CERT (-23105) +/** Error getting a data from the extension. */ +#define VERR_X509_GETTING_DATA_FROM_EXTENSION (-23106) +/** Error formatting an extension. */ +#define VERR_X509_PRINT_EXTENSION_TO_BIO (-23107) +/** X509 certificate verification error. */ +#define VERR_X509_CERTIFICATE_VERIFICATION_FAILURE (-23108) +/** X509 certificate isn't self signed. */ +#define VERR_X509_NOT_SELFSIGNED_CERTIFICATE (-23109) +/** Warning X509 certificate isn't self signed. */ +#define VINF_X509_NOT_SELFSIGNED_CERTIFICATE 23109 +/** @} */ + +/** @name RTAsn1 status codes + * @{ */ +/** Temporary place holder. */ +#define VERR_ASN1_ERROR (-22800) +/** Encountered an ASN.1 string type that is not supported. */ +#define VERR_ASN1_STRING_TYPE_NOT_IMPLEMENTED (-22801) +/** Invalid ASN.1 UTF-8 STRING encoding. */ +#define VERR_ASN1_INVALID_UTF8_STRING_ENCODING (-22802) +/** Invalid ASN.1 NUMERIC STRING encoding. */ +#define VERR_ASN1_INVALID_NUMERIC_STRING_ENCODING (-22803) +/** Invalid ASN.1 PRINTABLE STRING encoding. */ +#define VERR_ASN1_INVALID_PRINTABLE_STRING_ENCODING (-22804) +/** Invalid ASN.1 T61/TELETEX STRING encoding. */ +#define VERR_ASN1_INVALID_T61_STRING_ENCODING (-22805) +/** Invalid ASN.1 VIDEOTEX STRING encoding. */ +#define VERR_ASN1_INVALID_VIDEOTEX_STRING_ENCODING (-22806) +/** Invalid ASN.1 IA5 STRING encoding. */ +#define VERR_ASN1_INVALID_IA5_STRING_ENCODING (-22807) +/** Invalid ASN.1 GRAPHIC STRING encoding. */ +#define VERR_ASN1_INVALID_GRAPHIC_STRING_ENCODING (-22808) +/** Invalid ASN.1 ISO-646/VISIBLE STRING encoding. */ +#define VERR_ASN1_INVALID_VISIBLE_STRING_ENCODING (-22809) +/** Invalid ASN.1 GENERAL STRING encoding. */ +#define VERR_ASN1_INVALID_GENERAL_STRING_ENCODING (-22810) +/** Invalid ASN.1 UNIVERSAL STRING encoding. */ +#define VERR_ASN1_INVALID_UNIVERSAL_STRING_ENCODING (-22811) +/** Invalid ASN.1 BMP STRING encoding. */ +#define VERR_ASN1_INVALID_BMP_STRING_ENCODING (-22812) +/** Invalid ASN.1 OBJECT IDENTIFIER encoding. */ +#define VERR_ASN1_INVALID_OBJID_ENCODING (-22813) +/** A component value of an ASN.1 OBJECT IDENTIFIER is too big for our + * internal representation (32-bits). */ +#define VERR_ASN1_OBJID_COMPONENT_TOO_BIG (-22814) +/** Too many components in an ASN.1 OBJECT IDENTIFIER for our internal + * representation. */ +#define VERR_ASN1_OBJID_TOO_MANY_COMPONENTS (-22815) +/** The dotted-string representation of an ASN.1 OBJECT IDENTIFIER would be too + * long for our internal representation. */ +#define VERR_ASN1_OBJID_TOO_LONG_STRING_FORM (-22816) +/** Invalid dotted string. */ +#define VERR_ASN1_OBJID_INVALID_DOTTED_STRING (-22817) +/** Constructed string type not implemented. */ +#define VERR_ASN1_CONSTRUCTED_STRING_NOT_IMPL (-22818) +/** Expected a different string tag. */ +#define VERR_ASN1_STRING_TAG_MISMATCH (-22819) +/** Expected a different time tag. */ +#define VERR_ASN1_TIME_TAG_MISMATCH (-22820) +/** More unconsumed data available. */ +#define VINF_ASN1_MORE_DATA (22821) +/** RTAsnEncodeWriteHeader return code indicating that nothing was written + * and the content should be skipped as well. */ +#define VINF_ASN1_NOT_ENCODED (22822) +/** Unknown escape sequence encountered in TeletexString. */ +#define VERR_ASN1_TELETEX_UNKNOWN_ESC_SEQ (-22823) +/** Unsupported escape sequence encountered in TeletexString. */ +#define VERR_ASN1_TELETEX_UNSUPPORTED_ESC_SEQ (-22824) +/** Unsupported character set. */ +#define VERR_ASN1_TELETEX_UNSUPPORTED_CHARSET (-22825) +/** ASN.1 object has no virtual method table. */ +#define VERR_ASN1_NO_VTABLE (-22826) +/** ASN.1 object has no pfnCheckSanity method. */ +#define VERR_ASN1_NO_CHECK_SANITY_METHOD (-22827) +/** ASN.1 object is not present */ +#define VERR_ASN1_NOT_PRESENT (-22828) +/** There are unconsumed bytes after decoding an ASN.1 object. */ +#define VERR_ASN1_CURSOR_NOT_AT_END (-22829) +/** Long ASN.1 tag form is not implemented. */ +#define VERR_ASN1_CURSOR_LONG_TAG (-22830) +/** Bad ASN.1 object length encoding. */ +#define VERR_ASN1_CURSOR_BAD_LENGTH_ENCODING (-22831) +/** Indefinite length form is against the rules. */ +#define VERR_ASN1_CURSOR_ILLEGAL_INDEFINITE_LENGTH (-22832) +/** Malformed indefinite length encoding. */ +#define VERR_ASN1_CURSOR_BAD_INDEFINITE_LENGTH (-22833) +/** ASN.1 object length goes beyond the end of the byte stream being decoded. */ +#define VERR_ASN1_CURSOR_BAD_LENGTH (-22834) +/** Not more data in ASN.1 byte stream. */ +#define VERR_ASN1_CURSOR_NO_MORE_DATA (-22835) +/** Too little data in ASN.1 byte stream. */ +#define VERR_ASN1_CURSOR_TOO_LITTLE_DATA_LEFT (-22836) +/** Constructed string is not according to the encoding rules. */ +#define VERR_ASN1_CURSOR_ILLEGAL_CONSTRUCTED_STRING (-22837) +/** Unexpected ASN.1 tag encountered while decoding. */ +#define VERR_ASN1_CURSOR_TAG_MISMATCH (-22838) +/** Unexpected ASN.1 tag class/flag encountered while decoding. */ +#define VERR_ASN1_CURSOR_TAG_FLAG_CLASS_MISMATCH (-22839) +/** ASN.1 bit string object is out of bounds. */ +#define VERR_ASN1_BITSTRING_OUT_OF_BOUNDS (-22840) +/** Bad ASN.1 time object. */ +#define VERR_ASN1_TIME_BAD_NORMALIZE_INPUT (-22841) +/** Failed to normalize ASN.1 time object. */ +#define VERR_ASN1_TIME_NORMALIZE_ERROR (-22842) +/** Normalization of ASN.1 time object didn't work out. */ +#define VERR_ASN1_TIME_NORMALIZE_MISMATCH (-22843) +/** Invalid ASN.1 UTC TIME encoding. */ +#define VERR_ASN1_INVALID_UTC_TIME_ENCODING (-22844) +/** Invalid ASN.1 GENERALIZED TIME encoding. */ +#define VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING (-22845) +/** Invalid ASN.1 BOOLEAN encoding. */ +#define VERR_ASN1_INVALID_BOOLEAN_ENCODING (-22846) +/** Invalid ASN.1 NULL encoding. */ +#define VERR_ASN1_INVALID_NULL_ENCODING (-22847) +/** Invalid ASN.1 BIT STRING encoding. */ +#define VERR_ASN1_INVALID_BITSTRING_ENCODING (-22848) +/** Unimplemented ASN.1 tag reached the RTAsn1DynType code. */ +#define VERR_ASN1_DYNTYPE_TAG_NOT_IMPL (-22849) +/** ASN.1 tag and flags/class mismatch in RTAsn1DynType code. */ +#define VERR_ASN1_DYNTYPE_BAD_TAG (-22850) +/** Unexpected ASN.1 fake/dummy object. */ +#define VERR_ASN1_DUMMY_OBJECT (-22851) +/** ASN.1 object is too long. */ +#define VERR_ASN1_TOO_LONG (-22852) +/** Expected primitive ASN.1 object. */ +#define VERR_ASN1_EXPECTED_PRIMITIVE (-22853) +/** Expected valid data pointer for ASN.1 object. */ +#define VERR_ASN1_INVALID_DATA_POINTER (-22854) +/** The ASN.1 encoding is too deeply nested for the decoder. */ +#define VERR_ASN1_TOO_DEEPLY_NESTED (-22855) +/** Generic unexpected object ID error. */ +#define VERR_ASN1_UNEXPECTED_OBJ_ID (-22856) +/** Invalid ASN.1 INTEGER encoding. */ +#define VERR_ASN1_INVALID_INTEGER_ENCODING (-22857) + +/** ANS.1 internal error 1. */ +#define VERR_ASN1_INTERNAL_ERROR_1 (-22895) +/** ANS.1 internal error 2. */ +#define VERR_ASN1_INTERNAL_ERROR_2 (-22896) +/** ANS.1 internal error 3. */ +#define VERR_ASN1_INTERNAL_ERROR_3 (-22897) +/** ANS.1 internal error 4. */ +#define VERR_ASN1_INTERNAL_ERROR_4 (-22898) +/** ANS.1 internal error 5. */ +#define VERR_ASN1_INTERNAL_ERROR_5 (-22899) +/** @} */ + +/** @name More RTLdr status codes. + * @{ */ +/** Image Verification Failure: No Authenticode Signature. */ +#define VERR_LDRVI_NOT_SIGNED (-22900) +/** Image Verification Warning: No Authenticode Signature, but on whitelist. */ +#define VINF_LDRVI_NOT_SIGNED (22900) +/** Image Verification Failure: Error reading image headers. */ +#define VERR_LDRVI_READ_ERROR_HDR (-22901) +/** Image Verification Failure: Error reading section headers. */ +#define VERR_LDRVI_READ_ERROR_SHDRS (-22902) +/** Image Verification Failure: Error reading authenticode signature data. */ +#define VERR_LDRVI_READ_ERROR_SIGNATURE (-22903) +/** Image Verification Failure: Error reading file for hashing. */ +#define VERR_LDRVI_READ_ERROR_HASH (-22904) +/** Image Verification Failure: Error determining the file length. */ +#define VERR_LDRVI_FILE_LENGTH_ERROR (-22905) +/** Image Verification Failure: Error allocating memory for state data. */ +#define VERR_LDRVI_NO_MEMORY_STATE (-22906) +/** Image Verification Failure: Error allocating memory for authenticode + * signature data. */ +#define VERR_LDRVI_NO_MEMORY_SIGNATURE (-22907) +/** Image Verification Failure: Error allocating memory for section headers. */ +#define VERR_LDRVI_NO_MEMORY_SHDRS (-22908) +/** Image Verification Failure: Authenticode parsing output. */ +#define VERR_LDRVI_NO_MEMORY_PARSE_OUTPUT (-22909) +/** Image Verification Failure: Invalid security directory entry. */ +#define VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY (-22910) +/** Image Verification Failure: */ +#define VERR_LDRVI_BAD_CERT_HDR_LENGTH (-22911) +/** Image Verification Failure: */ +#define VERR_LDRVI_BAD_CERT_HDR_REVISION (-22912) +/** Image Verification Failure: */ +#define VERR_LDRVI_BAD_CERT_HDR_TYPE (-22913) +/** Image Verification Failure: More than one certificate table entry. */ +#define VERR_LDRVI_BAD_CERT_MULTIPLE (-22914) + +/** Image Verification Failure: */ +#define VERR_LDRVI_BAD_MZ_OFFSET (-22915) +/** Image Verification Failure: Invalid section count. */ +#define VERR_LDRVI_INVALID_SECTION_COUNT (-22916) +/** Image Verification Failure: Raw data offsets and sizes are out of range. */ +#define VERR_LDRVI_SECTION_RAW_DATA_VALUES (-22917) +/** Optional header magic and target machine does not match. */ +#define VERR_LDRVI_MACHINE_OPT_HDR_MAGIC_MISMATCH (-22918) +/** Unsupported image target architecture. */ +#define VERR_LDRVI_UNSUPPORTED_ARCH (-22919) + +/** Image Verification Failure: Internal error in signature parser. */ +#define VERR_LDRVI_PARSE_IPE (-22921) +/** Generic BER parse error. Will be refined later. */ +#define VERR_LDRVI_PARSE_BER_ERROR (-22922) + +/** Expected the signed data content to be the object ID of + * SpcIndirectDataContent, found something else instead. */ +#define VERR_LDRVI_EXPECTED_INDIRECT_DATA_CONTENT_OID (-22923) +/** Page hash table size overflow. */ +#define VERR_LDRVI_PAGE_HASH_TAB_SIZE_OVERFLOW (-22924) +/** Page hash table is too long (covers signature data, i.e. itself). */ +#define VERR_LDRVI_PAGE_HASH_TAB_TOO_LONG (-22925) +/** The page hash table is not strictly ordered by offset. */ +#define VERR_LDRVI_PAGE_HASH_TAB_NOT_STRICTLY_SORTED (-22926) +/** The page hash table hashes data outside the defined and implicit sections. */ +#define VERR_PAGE_HASH_TAB_HASHES_NON_SECTION_DATA (-22927) +/** Page hash mismatch. */ +#define VERR_LDRVI_PAGE_HASH_MISMATCH (-22928) +/** Image hash mismatch. */ +#define VERR_LDRVI_IMAGE_HASH_MISMATCH (-22929) +/** Malformed code signing structure. */ +#define VERR_LDRVI_BAD_CERT_FORMAT (-22930) + +/** Cannot resolve symbol because it's a forwarder. */ +#define VERR_LDR_FORWARDER (-22950) +/** The symbol is not a forwarder. */ +#define VERR_LDR_NOT_FORWARDER (-22951) +/** Malformed forwarder entry. */ +#define VERR_LDR_BAD_FORWARDER (-22952) +/** Too long forwarder chain or there is a loop. */ +#define VERR_LDR_FORWARDER_CHAIN_TOO_LONG (-22953) +/** Support for forwarders has not been implemented. */ +#define VERR_LDR_FORWARDERS_NOT_SUPPORTED (-22954) +/** Only native endian Mach-O files are supported. */ +#define VERR_LDRMACHO_OTHER_ENDIAN_NOT_SUPPORTED (-22955) +/** The Mach-O header is bad or contains new and unsupported features. */ +#define VERR_LDRMACHO_BAD_HEADER (-22956) +/** The file type isn't supported. */ +#define VERR_LDRMACHO_UNSUPPORTED_FILE_TYPE (-22957) +/** The machine (cputype / cpusubtype combination) isn't supported. */ +#define VERR_LDRMACHO_UNSUPPORTED_MACHINE (-22958) +/** Bad load command(s). */ +#define VERR_LDRMACHO_BAD_LOAD_COMMAND (-22959) +/** Encountered an unknown load command.*/ +#define VERR_LDRMACHO_UNKNOWN_LOAD_COMMAND (-22960) +/** Encountered a load command that's not implemented.*/ +#define VERR_LDRMACHO_UNSUPPORTED_LOAD_COMMAND (-22961) +/** Bad section. */ +#define VERR_LDRMACHO_BAD_SECTION (-22962) +/** Encountered a section type that's not implemented.*/ +#define VERR_LDRMACHO_UNSUPPORTED_SECTION (-22963) +/** Encountered a init function section. */ +#define VERR_LDRMACHO_UNSUPPORTED_INIT_SECTION (-22964) +/** Encountered a term function section. */ +#define VERR_LDRMACHO_UNSUPPORTED_TERM_SECTION (-22965) +/** Encountered a section type that's not known to the loader. (probably invalid) */ +#define VERR_LDRMACHO_UNKNOWN_SECTION (-22966) +/** The sections aren't ordered by segment as expected by the loader. */ +#define VERR_LDRMACHO_BAD_SECTION_ORDER (-22967) +/** The image is 32-bit and contains 64-bit load commands or vise versa. */ +#define VERR_LDRMACHO_BIT_MIX (-22968) +/** Bad MH_OBJECT file. */ +#define VERR_LDRMACHO_BAD_OBJECT_FILE (-22969) +/** Bad symbol table entry. */ +#define VERR_LDRMACHO_BAD_SYMBOL (-22970) +/** Unsupported fixup type. */ +#define VERR_LDRMACHO_UNSUPPORTED_FIXUP_TYPE (-22971) +/** Both debug and non-debug sections in segment. */ +#define VERR_LDRMACHO_MIXED_DEBUG_SECTION_FLAGS (-22972) +/** The segment bits are non-contiguous in the file. */ +#define VERR_LDRMACHO_NON_CONT_SEG_BITS (-22973) +/** Hit a todo in the mach-o loader. */ +#define VERR_LDRMACHO_TODO (-22974) +/** Bad symbol table size in Mach-O image. */ +#define VERR_LDRMACHO_BAD_SYMTAB_SIZE (-22975) +/** Duplicate segment name. */ +#define VERR_LDR_DUPLICATE_SEGMENT_NAME (-22976) +/** No image UUID. */ +#define VERR_LDR_NO_IMAGE_UUID (-22977) +/** Bad image relocation. */ +#define VERR_LDR_BAD_FIXUP (-22978) +/** Address overflow. */ +#define VERR_LDR_ADDRESS_OVERFLOW (-22979) +/** validation of LX header failed. */ +#define VERR_LDRLX_BAD_HEADER (-22980) +/** validation of the loader section (in the LX header) failed. */ +#define VERR_LDRLX_BAD_LOADER_SECTION (-22981) +/** validation of the fixup section (in the LX header) failed. */ +#define VERR_LDRLX_BAD_FIXUP_SECTION (-22982) +/** validation of the LX object table failed. */ +#define VERR_LDRLX_BAD_OBJECT_TABLE (-22983) +/** A bad page map entry was encountered. */ +#define VERR_LDRLX_BAD_PAGE_MAP (-22984) +/** Bad iterdata (EXEPACK) data. */ +#define VERR_LDRLX_BAD_ITERDATA (-22985) +/** Bad iterdata2 (EXEPACK2) data. */ +#define VERR_LDRLX_BAD_ITERDATA2 (-22986) +/** Bad bundle data. */ +#define VERR_LDRLX_BAD_BUNDLE (-22987) +/** No soname. */ +#define VERR_LDRLX_NO_SONAME (-22988) +/** Bad soname. */ +#define VERR_LDRLX_BAD_SONAME (-22989) +/** Bad forwarder entry. */ +#define VERR_LDRLX_BAD_FORWARDER (-22990) +/** internal fixup chain isn't implemented yet. */ +#define VERR_LDRLX_NRICHAIN_NOT_SUPPORTED (-22991) +/** Import module ordinal is out of bounds. */ +#define VERR_LDRLX_IMPORT_ORDINAL_OUT_OF_BOUNDS (-22992) +/** @} */ + +/** @name RTCrX509 status codes. + * @{ */ +/** Generic X.509 error. */ +#define VERR_CR_X509_GENERIC_ERROR (-23000) +/** Internal error in the X.509 code. */ +#define VERR_CR_X509_INTERNAL_ERROR (-23001) +/** Internal error in the X.509 certificate path building and verification + * code. */ +#define VERR_CR_X509_CERTPATHS_INTERNAL_ERROR (-23002) +/** Path not verified yet. */ +#define VERR_CR_X509_NOT_VERIFIED (-23003) +/** The certificate path has no trust anchor. */ +#define VERR_CR_X509_NO_TRUST_ANCHOR (-23004) +/** Unknown X.509 certificate signature algorithm. */ +#define VERR_CR_X509_UNKNOWN_CERT_SIGN_ALGO (-23005) +/** Certificate signature algorithm mismatch. */ +#define VERR_CR_X509_CERT_SIGN_ALGO_MISMATCH (-23006) +/** The signature algorithm in the to-be-signed certificate part does not match + * the one associated with the signature. */ +#define VERR_CR_X509_CERT_TBS_SIGN_ALGO_MISMATCH (-23007) +/** Certificate extensions requires certificate version 3 or later. */ +#define VERR_CR_X509_TBSCERT_EXTS_REQ_V3 (-23008) +/** Unique issuer and subject IDs require version certificate 2. */ +#define VERR_CR_X509_TBSCERT_UNIQUE_IDS_REQ_V2 (-23009) +/** Certificate serial number length is out of bounds. */ +#define VERR_CR_X509_TBSCERT_SERIAL_NUMBER_OUT_OF_BOUNDS (-23010) +/** Unsupported X.509 certificate version. */ +#define VERR_CR_X509_TBSCERT_UNSUPPORTED_VERSION (-23011) +/** Public key is too small. */ +#define VERR_CR_X509_PUBLIC_KEY_TOO_SMALL (-23012) +/** Invalid string tag for a X.509 name object. */ +#define VERR_CR_X509_INVALID_NAME_STRING_TAG (-23013) +/** Empty string in X.509 name object. */ +#define VERR_CR_X509_NAME_EMPTY_STRING (-23014) +/** Non-string object inside X.509 name object. */ +#define VERR_CR_X509_NAME_NOT_STRING (-23015) +/** Empty set inside X.509 name. */ +#define VERR_CR_X509_NAME_EMPTY_SET (-23016) +/** Empty sub-string set inside X.509 name. */ +#define VERR_CR_X509_NAME_EMPTY_SUB_SET (-23017) +/** The NotBefore and NotAfter values of an X.509 Validity object seems to + * have been swapped around. */ +#define VERR_CR_X509_VALIDITY_SWAPPED (-23018) +/** Duplicate certificate extension. */ +#define VERR_CR_X509_TBSCERT_DUPLICATE_EXTENSION (-23019) +/** Missing relative distinguished name map entry. */ +#define VERR_CR_X509_NAME_MISSING_RDN_MAP_ENTRY (-23020) +/** Certificate path validator: No trusted certificate paths. */ +#define VERR_CR_X509_CPV_NO_TRUSTED_PATHS (-23021) +/** Certificate path validator: No valid certificate policy. */ +#define VERR_CR_X509_CPV_NO_VALID_POLICY (-23022) +/** Certificate path validator: Unknown critical certificate extension. */ +#define VERR_CR_X509_CPV_UNKNOWN_CRITICAL_EXTENSION (-23023) +/** Certificate path validator: Intermediate certificate is missing the + * KeyCertSign usage flag. */ +#define VERR_CR_X509_CPV_MISSING_KEY_CERT_SIGN (-23024) +/** Certificate path validator: Hit the max certificate path length before + * reaching trust anchor. */ +#define VERR_CR_X509_CPV_MAX_PATH_LENGTH (-23025) +/** Certificate path validator: Intermediate certificate is not marked as a + * certificate authority (CA). */ +#define VERR_CR_X509_CPV_NOT_CA_CERT (-23026) +/** Certificate path validator: Intermediate certificate is not a version 3 + * certificate. */ +#define VERR_CR_X509_CPV_NOT_V3_CERT (-23027) +/** Certificate path validator: Invalid policy mapping (to/from anyPolicy). */ +#define VERR_CR_X509_CPV_INVALID_POLICY_MAPPING (-23028) +/** Certificate path validator: Name constraints permits no names. */ +#define VERR_CR_X509_CPV_NO_PERMITTED_NAMES (-23029) +/** Certificate path validator: Name constraints does not permits the + * certificate name. */ +#define VERR_CR_X509_CPV_NAME_NOT_PERMITTED (-23030) +/** Certificate path validator: Name constraints does not permits the + * alternative certificate name. */ +#define VERR_CR_X509_CPV_ALT_NAME_NOT_PERMITTED (-23031) +/** Certificate path validator: Intermediate certificate subject does not + * match child issuer property. */ +#define VERR_CR_X509_CPV_ISSUER_MISMATCH (-23032) +/** Certificate path validator: The certificate is not valid at the + * specified time. */ +#define VERR_CR_X509_CPV_NOT_VALID_AT_TIME (-23033) +/** Certificate path validator: Unexpected choice found in general subtree + * object (name constraints). */ +#define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_CHOICE (-23034) +/** Certificate path validator: Unexpected minimum value found in general + * subtree object (name constraints). */ +#define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MIN (-23035) +/** Certificate path validator: Unexpected maximum value found in + * general subtree object (name constraints). */ +#define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MAX (-23036) +/** Certificate path builder: Encountered bad certificate context. */ +#define VERR_CR_X509_CPB_BAD_CERT_CTX (-23037) +/** OpenSSL d2i_X509 failed. */ +#define VERR_CR_X509_OSSL_D2I_FAILED (-23090) +/** @} */ + +/** @name RTCrPkcs7 status codes. + * @{ */ +/** Generic PKCS \#7 error. */ +#define VERR_CR_PKCS7_GENERIC_ERROR (-23300) +/** Signed data verification failed because there are zero signer infos. */ +#define VERR_CR_PKCS7_NO_SIGNER_INFOS (-23301) +/** Signed data certificate not found. */ +#define VERR_CR_PKCS7_SIGNED_DATA_CERT_NOT_FOUND (-23302) +/** Signed data verification failed due to key usage issues. */ +#define VERR_CR_PKCS7_KEY_USAGE_MISMATCH (-23303) +/** Signed data verification failed because of missing (or duplicate) + * authenticated content-type attribute. */ +#define VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB (-23304) +/** Signed data verification failed because of the authenticated content-type + * attribute did not match. */ +#define VERR_CR_PKCS7_CONTENT_TYPE_ATTRIB_MISMATCH (-23305) +/** Signed data verification failed because of a malformed authenticated + * content-type attribute. */ +#define VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB (-23306) +/** Signed data verification failed because of missing (or duplicate) + * authenticated message-digest attribute. */ +#define VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB (-23307) +/** Signed data verification failed because the authenticated message-digest + * attribute did not match. */ +#define VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH (-23308) +/** Signed data verification failed because of a malformed authenticated + * message-digest attribute. */ +#define VERR_CR_PKCS7_BAD_MESSAGE_DIGEST_ATTRIB (-23309) +/** Signature verification failed. */ +#define VERR_CR_PKCS7_SIGNATURE_VERIFICATION_FAILED (-23310) +/** Internal PKCS \#7 error. */ +#define VERR_CR_PKCS7_INTERNAL_ERROR (-22311) +/** OpenSSL d2i_PKCS7 failed. */ +#define VERR_CR_PKCS7_OSSL_D2I_FAILED (-22312) +/** OpenSSL PKCS \#7 verification failed. */ +#define VERR_CR_PKCS7_OSSL_VERIFY_FAILED (-22313) +/** Digest algorithm parameters are not supported by the PKCS \#7 code. */ +#define VERR_CR_PKCS7_DIGEST_PARAMS_NOT_IMPL (-22314) +/** The digest algorithm of a signer info entry was not found in the list of + * digest algorithms in the signed data. */ +#define VERR_CR_PKCS7_DIGEST_ALGO_NOT_FOUND_IN_LIST (-22315) +/** The PKCS \#7 content is not signed data. */ +#define VERR_CR_PKCS7_NOT_SIGNED_DATA (-22316) +/** No digest algorithms listed in PKCS \#7 signed data. */ +#define VERR_CR_PKCS7_NO_DIGEST_ALGORITHMS (-22317) +/** Too many digest algorithms used by PKCS \#7 signed data. This is an + * internal limitation of the code that aims at saving kernel stack space. */ +#define VERR_CR_PKCS7_TOO_MANY_DIGEST_ALGORITHMS (-22318) +/** Error creating digest algorithm calculator. */ +#define VERR_CR_PKCS7_DIGEST_CREATE_ERROR (-22319) +/** Error while calculating a digest for a PKCS \#7 verification operation. */ +#define VERR_CR_PKCS7_DIGEST_CALC_ERROR (-22320) +/** Unsupported PKCS \#7 signed data version. */ +#define VERR_CR_PKCS7_SIGNED_DATA_VERSION (-22350) +/** PKCS \#7 signed data has no digest algorithms listed. */ +#define VERR_CR_PKCS7_SIGNED_DATA_NO_DIGEST_ALGOS (-22351) +/** Unknown digest algorithm used by PKCS \#7 object. */ +#define VERR_CR_PKCS7_UNKNOWN_DIGEST_ALGORITHM (-22352) +/** Expected PKCS \#7 object to ship at least one certificate. */ +#define VERR_CR_PKCS7_NO_CERTIFICATES (-22353) +/** Expected PKCS \#7 object to not contain any CRLs. */ +#define VERR_CR_PKCS7_EXPECTED_NO_CRLS (-22354) +/** Expected PKCS \#7 object to contain exactly on signer info entry. */ +#define VERR_CR_PKCS7_EXPECTED_ONE_SIGNER_INFO (-22355) +/** Unsupported PKCS \#7 signer info version. */ +#define VERR_CR_PKCS7_SIGNER_INFO_VERSION (-22356) +/** PKCS \#7 singer info contains no issuer serial number. */ +#define VERR_CR_PKCS7_SIGNER_INFO_NO_ISSUER_SERIAL_NO (-22357) +/** Expected PKCS \#7 object to ship the signer certificate(s). */ +#define VERR_CR_PKCS7_SIGNER_CERT_NOT_SHIPPED (-22358) +/** The encrypted digest algorithm does not match the one in the certificate. */ +#define VERR_CR_PKCS7_SIGNER_INFO_DIGEST_ENCRYPT_MISMATCH (-22359) +/** The PKCS \#7 content is not data. */ +#define VERR_CR_PKCS7_NOT_DATA (-22360) +/** @} */ + +/** @name RTCrSpc status codes. + * @{ */ +/** Generic SPC error. */ +#define VERR_CR_SPC_GENERIC_ERROR (-23400) +/** SPC requires there to be exactly one SignerInfo entry. */ +#define VERR_CR_SPC_NOT_EXACTLY_ONE_SIGNER_INFOS (-23401) +/** There shall be exactly one digest algorithm to go with the single + * SingerInfo entry required by SPC. */ +#define VERR_CR_SPC_NOT_EXACTLY_ONE_DIGEST_ALGO (-23402) +/** The digest algorithm in the SignerInfo does not match the one in the + * indirect data. */ +#define VERR_CR_SPC_SIGNED_IND_DATA_DIGEST_ALGO_MISMATCH (-23403) +/** The digest algorithm in the indirect data was not found in the list of + * digest algorithms in the signed data structure. */ +#define VERR_CR_SPC_IND_DATA_DIGEST_ALGO_NOT_IN_DIGEST_ALGOS (-23404) +/** The digest algorithm is not known to us. */ +#define VERR_CR_SPC_UNKNOWN_DIGEST_ALGO (-23405) +/** The indirect data digest size does not match the digest algorithm. */ +#define VERR_CR_SPC_IND_DATA_DIGEST_SIZE_MISMATCH (-23406) +/** Expected PE image data inside indirect data object. */ +#define VERR_CR_SPC_EXPECTED_PE_IMAGE_DATA (-23407) +/** Internal SPC error: The PE image data is missing. */ +#define VERR_CR_SPC_PEIMAGE_DATA_NOT_PRESENT (-23408) +/** Bad SPC object moniker UUID field. */ +#define VERR_CR_SPC_BAD_MONIKER_UUID (-23409) +/** Unknown SPC object moniker UUID. */ +#define VERR_CR_SPC_UNKNOWN_MONIKER_UUID (-23410) +/** Internal SPC error: Bad object moniker choice value. */ +#define VERR_CR_SPC_BAD_MONIKER_CHOICE (-23411) +/** Internal SPC error: Bad object moniker data pointer. */ +#define VERR_CR_SPC_MONIKER_BAD_DATA (-23412) +/** Multiple PE image page hash tables. */ +#define VERR_CR_SPC_PEIMAGE_MULTIPLE_HASH_TABS (-23413) +/** Unknown SPC PE image attribute. */ +#define VERR_CR_SPC_PEIMAGE_UNKNOWN_ATTRIBUTE (-23414) +/** URL not expected in SPC PE image data. */ +#define VERR_CR_SPC_PEIMAGE_URL_UNEXPECTED (-23415) +/** PE image data without any valid content was not expected. */ +#define VERR_CR_SPC_PEIMAGE_NO_CONTENT (-23416) +/** @} */ + +/** @name RTCrPkix status codes. + * @{ */ +/** Generic PKCS \#7 error. */ +#define VERR_CR_PKIX_GENERIC_ERROR (-23500) +/** Parameters was presented to a signature schema that does not take any. */ +#define VERR_CR_PKIX_SIGNATURE_TAKES_NO_PARAMETERS (-23501) +/** Unknown hash digest type. */ +#define VERR_CR_PKIX_UNKNOWN_DIGEST_TYPE (-23502) +/** Internal error. */ +#define VERR_CR_PKIX_INTERNAL_ERROR (-23503) +/** The hash is too long for the key used when signing/verifying. */ +#define VERR_CR_PKIX_HASH_TOO_LONG_FOR_KEY (-23504) +/** The signature is too long for the scratch buffer. */ +#define VERR_CR_PKIX_SIGNATURE_TOO_LONG (-23505) +/** The signature is greater than or equal to the key. */ +#define VERR_CR_PKIX_SIGNATURE_GE_KEY (-23506) +/** The signature is negative. */ +#define VERR_CR_PKIX_SIGNATURE_NEGATIVE (-23507) +/** Invalid signature length. */ +#define VERR_CR_PKIX_INVALID_SIGNATURE_LENGTH (-23508) +/** PKIX signature no does not match up to the current data. */ +#define VERR_CR_PKIX_SIGNATURE_MISMATCH (-23509) +/** PKIX cipher algorithm parameters are not implemented. */ +#define VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL (-23510) +/** Cipher algorithm is not known to us. */ +#define VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN (-23511) +/** PKIX cipher algorithm is not known to OpenSSL. */ +#define VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN (-23512) +/** PKIX cipher algorithm is not known to OpenSSL EVP API. */ +#define VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP (-23513) +/** OpenSSL failed to init PKIX cipher algorithm context. */ +#define VERR_CR_PKIX_OSSL_CIPHER_ALOG_INIT_FAILED (-23514) +/** Final OpenSSL PKIX verification failed. */ +#define VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED (-23515) +/** OpenSSL failed to decode the public key. */ +#define VERR_CR_PKIX_OSSL_D2I_PUBLIC_KEY_FAILED (-23516) +/** The EVP_PKEY_type API in OpenSSL failed. */ +#define VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR (-23517) +/** OpenSSL failed to decode the public key. */ +#define VERR_CR_PKIX_OSSL_D2I_PRIVATE_KEY_FAILED (-23518) +/** The EVP_PKEY_CTX_set_rsa_padding API in OpenSSL failed. */ +#define VERR_CR_PKIX_OSSL_EVP_PKEY_RSA_PAD_ERROR (-23519) +/** Final OpenSSL PKIX signing failed. */ +#define VERR_CR_PKIX_OSSL_SIGN_FINAL_FAILED (-23520) +/** OpenSSL and IPRT disagree on the signature size. */ +#define VERR_CR_PKIX_OSSL_VS_IPRT_SIGNATURE_SIZE (-23521) +/** OpenSSL and IPRT disagree on the signature. */ +#define VERR_CR_PKIX_OSSL_VS_IPRT_SIGNATURE (-23522) +/** Expected RSA private key. */ +#define VERR_CR_PKIX_NOT_RSA_PRIVATE_KEY (-23523) +/** Expected RSA public key. */ +#define VERR_CR_PKIX_NOT_RSA_PUBLIC_KEY (-23524) +/** @} */ + +/** @name RTCrStore status codes. + * @{ */ +/** Generic store error. */ +#define VERR_CR_STORE_GENERIC_ERROR (-23700) +/** @} */ + +/** @name RTCrKey status codes. + * @{ */ +/** Could not recognize the key type. */ +#define VERR_CR_KEY_UNKNOWN_TYPE (-23800) +/** Unsupported key format. */ +#define VERR_CR_KEY_FORMAT_NOT_SUPPORTED (-23801) +/** Key encrypted but no password was given. */ +#define VERR_CR_KEY_ENCRYPTED (-23802) +/** The key was marked as encrypted by no DEK-Info field with the encryption + * algortihms was found. */ +#define VERR_CR_KEY_NO_DEK_INFO (-23803) +/** The algorithms part of the DEK-Info field is too long. */ +#define VERR_CR_KEY_DEK_INFO_TOO_LONG (-23804) +/** Key decryption is not supported. */ +#define VERR_CR_KEY_DECRYPTION_NOT_SUPPORTED (-23805) +/** Unsupported key encryption cipher. */ +#define VERR_CR_KEY_UNSUPPORTED_CIPHER (-23806) +/** Found unexpected cipher parameters for encrypted key. */ +#define VERR_CR_KEY_UNEXPECTED_CIPHER_PARAMS (-23807) +/** Missing ciper parameters for encrypted key. */ +#define VERR_CR_KEY_MISSING_CIPHER_PARAMS (-23808) +/** To short initialization vector for encrypted key ciper. */ +#define VERR_CR_KEY_TOO_SHORT_CIPHER_IV (-23809) +/** Malformed initialization vector for encrypted key ciper. */ +#define VERR_CR_KEY_MALFORMED_CIPHER_IV (-23810) +/** Error encoding the password for key decryption. */ +#define VERR_CR_KEY_PASSWORD_ENCODING (-23811) +/** EVP_DecryptInit_ex failed. */ +#define VERR_CR_KEY_OSSL_DECRYPT_INIT_ERROR (-23812) +/** Key decryption failed, perhaps due to an incorrect password. */ +#define VERR_CR_KEY_DECRYPTION_FAILED (-23813) +/** The key was decrypted. */ +#define VINF_CR_KEY_WAS_DECRYPTED (23814) +/** Failed to generate RSA key. */ +#define VERR_CR_KEY_GEN_FAILED_RSA (-23815) +/** @} */ + +/** @name RTCrRsa status codes. + * @{ */ +/** Generic RSA error. */ +#define VERR_CR_RSA_GENERIC_ERROR (-23900) +/** @} */ + +/** @name RTBigNum status codes. + * @{ */ +/** Sensitive input requires the result(s) to be initialized as sensitive. */ +#define VERR_BIGNUM_SENSITIVE_INPUT (-24000) +/** Attempt to divide by zero. */ +#define VERR_BIGNUM_DIV_BY_ZERO (-24001) +/** Negative exponent makes no sense to integer math. */ +#define VERR_BIGNUM_NEGATIVE_EXPONENT (-24002) +/** @} */ + +/** @name RTCrDigest status codes. + * @{ */ +/** OpenSSL failed to initialize the digest algorithm context. */ +#define VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR (-24200) +/** OpenSSL failed to clone the digest algorithm context. */ +#define VERR_CR_DIGEST_OSSL_DIGEST_CTX_COPY_ERROR (-24201) +/** Deprecated digest. */ +#define VINF_CR_DIGEST_DEPRECATED (24202) +/** Deprecated digest. */ +#define VERR_CR_DIGEST_DEPRECATED (-24202) +/** Compromised digest. */ +#define VINF_CR_DIGEST_COMPROMISED (24203) +/** Compromised digest. */ +#define VERR_CR_DIGEST_COMPROMISED (-24203) +/** Severely compromised digest. */ +#define VINF_CR_DIGEST_SEVERELY_COMPROMISED (24204) +/** Severely compromised digest. */ +#define VERR_CR_DIGEST_SEVERELY_COMPROMISED (-24204) +/** Specified digest not supported in this context. */ +#define VERR_CR_DIGEST_NOT_SUPPORTED (-24205) +/** @} */ + +/** @name RTCr misc status codes. + * @{ */ +/** Failed to derivate key from password. */ +#define VERR_CR_PASSWORD_2_KEY_DERIVIATION_FAILED (-24396) +/** Failed getting cryptographically strong random bytes. */ +#define VERR_CR_RANDOM_SETUP_FAILED (-24397) +/** Failed getting cryptographically strong random bytes. */ +#define VERR_CR_RANDOM_FAILED (-24398) +/** Malformed or failed to parse PEM formatted data. */ +#define VERR_CR_MALFORMED_PEM_HEADER (-24399) +/** @} */ + +/** @name RTPath status codes. + * @{ */ +/** Unknown glob variable. */ +#define VERR_PATH_MATCH_UNKNOWN_VARIABLE (-24400) +/** The specified glob variable must be first in the pattern. */ +#define VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST (-24401) +/** Hit unimplemented glob pattern matching feature. */ +#define VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED (-24402) +/** Unknown character class in glob pattern. */ +#define VERR_PATH_GLOB_UNKNOWN_CHAR_CLASS (-24403) +/** @} */ + +/** @name RTUri status codes. + * @{ */ +/** The URI is empty */ +#define VERR_URI_EMPTY (-24600) +/** The URI is too short to be a valid URI. */ +#define VERR_URI_TOO_SHORT (-24601) +/** Invalid scheme. */ +#define VERR_URI_INVALID_SCHEME (-24602) +/** Invalid port number. */ +#define VERR_URI_INVALID_PORT_NUMBER (-24603) +/** Invalid escape sequence. */ +#define VERR_URI_INVALID_ESCAPE_SEQ (-24604) +/** Escape URI char decodes as zero (the C string terminator). */ +#define VERR_URI_ESCAPED_ZERO (-24605) +/** Escaped URI characters does not decode to valid UTF-8. */ +#define VERR_URI_ESCAPED_CHARS_NOT_VALID_UTF8 (-24606) +/** Escaped URI character is not a valid UTF-8 lead byte. */ +#define VERR_URI_INVALID_ESCAPED_UTF8_LEAD_BYTE (-24607) +/** Escaped URI character sequence with invalid UTF-8 continutation byte. */ +#define VERR_URI_INVALID_ESCAPED_UTF8_CONTINUATION_BYTE (-24608) +/** Missing UTF-8 continutation in escaped URI character sequence. */ +#define VERR_URI_MISSING_UTF8_CONTINUATION_BYTE (-24609) +/** Expected URI using the 'file:' scheme. */ +#define VERR_URI_NOT_FILE_SCHEME (-24610) +/** @} */ + +/** @name RTJson status codes. + * @{ */ +/** The called method does not work with the value type of the given JSON value. */ +#define VERR_JSON_VALUE_INVALID_TYPE (-24700) +/** The iterator reached the end. */ +#define VERR_JSON_ITERATOR_END (-24701) +/** The JSON document is malformed. */ +#define VERR_JSON_MALFORMED (-24702) +/** Object or array is empty. */ +#define VERR_JSON_IS_EMPTY (-24703) +/** Invalid UTF-16 escape sequence. */ +#define VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE (-24704) +/** Missing UTF-16 surrogate pair. */ +#define VERR_JSON_MISSING_SURROGATE_PAIR (-24705) +/** Bad UTF-16 surrogate pair sequence. */ +#define VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE (-24706) +/** Invalid codepoint. */ +#define VERR_JSON_INVALID_CODEPOINT (-24707) +/** @} */ + +/** @name RTVfs status codes. + * @{ */ +/** Unknown file system format. */ +#define VERR_VFS_UNKNOWN_FORMAT (-24800) +/** Found bogus values in the file system. */ +#define VERR_VFS_BOGUS_FORMAT (-24801) +/** Found bogus offset in the file system. */ +#define VERR_VFS_BOGUS_OFFSET (-24802) +/** Unsupported file system format. */ +#define VERR_VFS_UNSUPPORTED_FORMAT (-24803) +/** Unsupported create type in an RTVfsObjOpen or RTVfsDirOpenObj call. */ +#define VERR_VFS_UNSUPPORTED_CREATE_TYPE (-24804) +/** @} */ + +/** @name RTFsIsoMaker status codes. + * @{ */ +/** No validation entry in the boot catalog. */ +#define VERR_ISOMK_BOOT_CAT_NO_VALIDATION_ENTRY (-25000) +/** No default entry in the boot catalog. */ +#define VERR_ISOMK_BOOT_CAT_NO_DEFAULT_ENTRY (-25001) +/** Expected section header. */ +#define VERR_ISOMK_BOOT_CAT_EXPECTED_SECTION_HEADER (-25002) +/** Entry in a boot catalog section is empty. */ +#define VERR_ISOMK_BOOT_CAT_EMPTY_ENTRY (-25003) +/** Entry in a boot catalog section is another section. */ +#define VERR_ISOMK_BOOT_CAT_INVALID_SECTION_SIZE (-25004) +/** Unsectioned boot catalog entry. */ +#define VERR_ISOMK_BOOT_CAT_ERRATIC_ENTRY (-25005) +/** The file is too big for the current ISO level (4GB+ sized files + * requires ISO level 3). */ +#define VERR_ISOMK_FILE_TOO_BIG_REQ_ISO_LEVEL_3 (-25006) +/** Cannot add symbolic link to namespace which isn't configured to support it. */ +#define VERR_ISOMK_SYMLINK_REQ_ROCK_RIDGE (-25007) +/** Cannot add symbolic link to one of the selected namespaces. */ +#define VINF_ISOMK_SYMLINK_REQ_ROCK_RIDGE (25007) +/** Cannot add symbolic link because no namespace is configured to support it. */ +#define VERR_ISOMK_SYMLINK_SUPPORT_DISABLED (-25008) +/** No space for rock ridge 'CE' entry in directory record. */ +#define VERR_ISOMK_RR_NO_SPACE_FOR_CE (-25009) +/** Internal ISO maker error: Rock ridge read problem. */ +#define VERR_ISOMK_IPE_RR_READ (-25010) +/** Internal ISO maker error: Buggy namespace table. */ +#define VERR_ISOMK_IPE_TABLE (-25011) +/** Internal ISO maker error: Namespace problem \#1. */ +#define VERR_ISOMK_IPE_NAMESPACE_1 (-25012) +/** Internal ISO maker error: Namespace problem \#2. */ +#define VERR_ISOMK_IPE_NAMESPACE_2 (-25013) +/** Internal ISO maker error: Namespace problem \#3. */ +#define VERR_ISOMK_IPE_NAMESPACE_3 (-25014) +/** Internal ISO maker error: Namespace problem \#4. */ +#define VERR_ISOMK_IPE_NAMESPACE_4 (-25015) +/** Internal ISO maker error: Namespace problem \#5. */ +#define VERR_ISOMK_IPE_NAMESPACE_5 (-25016) +/** Internal ISO maker error: Namespace problem \#6. */ +#define VERR_ISOMK_IPE_NAMESPACE_6 (-25017) +/** Internal ISO maker error: Empty path. */ +#define VERR_ISOMK_IPE_EMPTY_PATH (-25018) +/** Internal ISO maker error: Unexpected empty component. */ +#define VERR_ISOMK_IPE_EMPTY_COMPONENT (-25019) +/** Internal ISO maker error: Expected path to start with root slash. */ +#define VERR_ISOMK_IPE_ROOT_SLASH (-25020) +/** Internal ISO maker error: Descriptor miscounting. */ +#define VERR_ISOMK_IPE_DESC_COUNT (-25021) +/** Internal ISO maker error: Buffer size. */ +#define VERR_ISOMK_IPE_BUFFER_SIZE (-25022) +/** Internal ISO maker error: Boot catalog file handle problem. */ +#define VERR_ISOMK_IPE_BOOT_CAT_FILE (-25023) +/** Internal ISO maker error: Inconsistency produing trans.tbl file. */ +#define VERR_ISOMK_IPE_PRODUCE_TRANS_TBL (-25024) +/** Internal ISO maker error: Read file data probem \#1. */ +#define VERR_ISOMK_IPE_READ_FILE_DATA_1 (-25025) +/** Internal ISO maker error: Read file data probem \#2. */ +#define VERR_ISOMK_IPE_READ_FILE_DATA_2 (-25026) +/** Internal ISO maker error: Read file data probem \#3. */ +#define VERR_ISOMK_IPE_READ_FILE_DATA_3 (-25027) +/** Internal ISO maker error: Finalization problem \#1. */ +#define VERR_ISOMK_IPE_FINALIZE_1 (-25028) +/** The spill file grew larger than 4GB. */ +#define VERR_ISOMK_RR_SPILL_FILE_FULL (-25029) + +/** Requested to import an unknown ISO format. */ +#define VERR_ISOMK_IMPORT_UNKNOWN_FORMAT (-25100) +/** Too many volume descriptors in the import ISO. */ +#define VERR_ISOMK_IMPORT_TOO_MANY_VOL_DESCS (-25101) +/** Import ISO contains a bad volume descriptor header. */ +#define VERR_ISOMK_IMPORT_INVALID_VOL_DESC_HDR (-25102) +/** Import ISO contains more than one primary volume descriptor. */ +#define VERR_ISOMK_IMPORT_MULTIPLE_PRIMARY_VOL_DESCS (-25103) +/** Import ISO contains more than one el torito descriptor. */ +#define VERR_ISOMK_IMPORT_MULTIPLE_EL_TORITO_DESCS (-25104) +/** Import ISO contains more than one joliet volume descriptor. */ +#define VERR_ISOMK_IMPORT_MULTIPLE_JOLIET_VOL_DESCS (-25105) +/** Import ISO starts with supplementary volume descriptor before any + * primary ones. */ +#define VERR_ISOMK_IMPORT_SUPPLEMENTARY_BEFORE_PRIMARY (-25106) +/** Import ISO contains an unsupported primary volume descriptor version. */ +#define VERR_IOSMK_IMPORT_PRIMARY_VOL_DESC_VER (-25107) +/** Import ISO contains a bad primary volume descriptor. */ +#define VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC (-25108) +/** Import ISO contains an unsupported supplementary volume descriptor + * version. */ +#define VERR_IOSMK_IMPORT_SUP_VOL_DESC_VER (-25109) +/** Import ISO contains a bad supplementary volume descriptor. */ +#define VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC (-25110) +/** Import ISO uses a logical block size other than 2KB. */ +#define VERR_ISOMK_IMPORT_LOGICAL_BLOCK_SIZE_NOT_2KB (-25111) +/** Import ISO contains more than volume. */ +#define VERR_ISOMK_IMPORT_MORE_THAN_ONE_VOLUME_IN_SET (-25112) +/** Import ISO uses invalid volume sequence number. */ +#define VERR_ISOMK_IMPORT_INVALID_VOLUMNE_SEQ_NO (-25113) +/** Import ISO has different volume space sizes of primary and supplementary + * volume descriptors. */ +#define VERR_ISOMK_IMPORT_VOLUME_SPACE_SIZE_MISMATCH (-25114) +/** Import ISO has different volume set sizes of primary and supplementary + * volume descriptors. */ +#define VERR_ISOMK_IMPORT_VOLUME_IN_SET_MISMATCH (-25115) +/** Import ISO contains a bad root directory record. */ +#define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC (-25116) +/** Import ISO contains a zero sized root directory. */ +#define VERR_ISOMK_IMPORT_ZERO_SIZED_ROOT_DIR (-25117) +/** Import ISO contains a root directory with a mismatching volume sequence + * number. */ +#define VERR_ISOMK_IMPORT_ROOT_VOLUME_SEQ_NO (-25118) +/** Import ISO contains a root directory with an out of bounds data extent. */ +#define VERR_ISOMK_IMPORT_ROOT_DIR_EXTENT_OUT_OF_BOUNDS (-25119) +/** Import ISO contains a root directory with a bad record length. */ +#define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC_LENGTH (-25120) +/** Import ISO contains a root directory without the directory flag set. */ +#define VERR_ISOMK_IMPORT_ROOT_DIR_WITHOUT_DIR_FLAG (-25121) +/** Import ISO contains a root directory with multiple extents. */ +#define VERR_ISOMK_IMPORT_ROOT_DIR_IS_MULTI_EXTENT (-25122) +/** Import ISO contains a too deep directory subtree. */ +#define VERR_ISOMK_IMPORT_TOO_DEEP_DIR_TREE (-25123) +/** Import ISO contains a bad directory record. */ +#define VERR_ISOMK_IMPORT_BAD_DIR_REC (-25124) +/** Import ISO contains a directory record with a mismatching volume sequence + * number. */ +#define VERR_ISOMK_IMPORT_DIR_REC_VOLUME_SEQ_NO (-25125) +/** Import ISO contains a directory with an extent that is out of bounds. */ +#define VERR_ISOMK_IMPORT_DIR_REC_EXTENT_OUT_OF_BOUNDS (-25126) +/** Import ISO contains a directory with a bad record length. */ +#define VERR_ISOMK_IMPORT_BAD_DIR_REC_LENGTH (-25127) +/** Import ISO contains a '.' or '..' directory record with a bad name + * length. */ +#define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME_LENGTH (-25128) +/** Import ISO contains a '.' or '..' directory record with a bad name. */ +#define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME (-25129) +/** Import ISO contains a directory with a more than one extent, that's + * currently not supported. */ +#define VERR_ISOMK_IMPORT_DIR_WITH_MORE_EXTENTS (-25130) +/** Import ISO contains a multi-extent directory record that differs + * significantly from first record. */ +#define VERR_ISOMK_IMPORT_MISMATCHING_MULTI_EXTENT_REC (-25131) +/** Import ISO contains a non-final multi-extent directory record with a + * size that isn't block aligned. */ +#define VERR_ISOMK_IMPORT_MISALIGNED_MULTI_EXTENT (-25132) +/** Import ISO contains a non-contigiuous multi-extent data, this is + * currently not supported. */ +#define VERR_ISOMK_IMPORT_NON_CONTIGUOUS_MULTI_EXTENT (-25133) + +/** The boot catalog block in the import ISO is out of bounds. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_OUT_OF_BOUNDS (-25140) +/** The boot catalog block in the import ISO has an incorrect validation + * header ID. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_HEADER_ID (-25141) +/** The boot catalog validation entry in the import ISO has incorrect keys. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_KEYS (-25142) +/** The boot catalog validation entry in the import ISO has an incorrect checksum. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_CHECKSUM (-25143) +/** A boot catalog entry in the import ISO has an unknown type. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_UNKNOWN_HEADER_ID (-25144) +/** A boot catalog entry in the import ISO has an invalid boot media type. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_INVALID_BOOT_MEDIA_TYPE (-25145) +/** The default boot catalog entry in the import ISO has invalid flags set. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_DEF_ENTRY_INVALID_FLAGS (-25146) +/** A boot catalog entry in the import ISO has reserved flag set. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_RESERVED_FLAG (-25147) +/** A boot catalog entry in the import ISO is using the unused field. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_USES_UNUSED_FIELD (-25148) +/** A boot catalog entry in the import ISO points to a block after the end of + * the image input file. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_IMAGE_OUT_OF_BOUNDS (-25149) +/** A boot catalog entry in the import ISO has an image with an + * indeterminate size. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_UNKNOWN_IMAGE_SIZE (-25150) +/** The boot catalog in the import ISO is larger than a sector or it is + * missing the final section header entry. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_MISSING_FINAL_OR_TOO_BIG (-25151) +/** The default boot catalog entry in the import ISO an invalid boot + * indicator value. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_DEF_ENTRY_INVALID_BOOT_IND (-25152) +/** A boot catalog extension entry in the import ISO was either flagged + * incorrectly in the previous entry or has an invalid header ID. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_INVALID_ID (-25153) +/** A boot catalog extension entry in the import ISO uses undefined flags + * which will be lost. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_UNDEFINED_FLAGS (-25154) +/** A boot catalog extension entry in the import ISO indicates more entries when + * we reached the end of the boot catalog sector. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_END_OF_SECTOR (-25155) +/** A boot catalog entry in the import ISO sets the continuation flag when using + * NONE as the selection criteria type. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_CONTINUATION_WITH_NONE (-25156) +/** A boot catalog entry in the import ISO sets the continuation flag when + * we reached the ned of the boot catalog secotr. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_CONTINUATION_EOS (-25157) +/** @} */ + + +/** @name RTFsIsoVol status codes + * @{ */ +/** Descriptor tag is all zeros. */ +#define VERR_ISOFS_TAG_IS_ALL_ZEROS (-25300) +/** Unsupported descriptor tag version. */ +#define VERR_ISOFS_UNSUPPORTED_TAG_VERSION (-25301) +/** Bad descriptor tag checksum. */ +#define VERR_ISOFS_BAD_TAG_CHECKSUM (-25302) +/** Descriptor tag sector number mismatch. */ +#define VERR_ISOFS_TAG_SECTOR_MISMATCH (-25303) +/** Descriptor CRC mismatch. */ +#define VERR_ISOFS_DESC_CRC_MISMATCH (-25304) +/** Insufficient data to check descriptor CRC. */ +#define VERR_ISOFS_INSUFFICIENT_DATA_FOR_DESC_CRC (-25305) +/** Unexpected/unknown/bad descriptor in volume descriptor sequence. */ +#define VERR_ISOFS_UNEXPECTED_VDS_DESC (-25306) +/** Too many primary volume descriptors. */ +#define VERR_ISOFS_TOO_MANY_PVDS (-25307) +/** Too many logical volume descriptors. */ +#define VERR_ISOFS_TOO_MANY_LVDS (-25308) +/** Too many partition descriptors. */ +#define VERR_ISOFS_TOO_MANY_PDS (-25309) +/** The logical volume descriptor has a too big partition map. */ +#define VERR_ISOFS_TOO_BIT_PARTMAP_IN_LVD (-25310) +/** No primary volume descriptors found. */ +#define VERR_ISOFS_NO_PVD (-25311) +/** No logical volume descriptors found. */ +#define VERR_ISOFS_NO_LVD (-25312) +/** No partition descriptors found. */ +#define VERR_ISOFS_NO_PD (-25313) +/** Multiple primary volume descriptors found, we can only deal with one. */ +#define VERR_ISOFS_MULTIPLE_PVDS (-25314) +/** Multiple logical volume descriptors found, we can only deal with one. */ +#define VERR_ISOFS_MULTIPLE_LVDS (-25315) +/** Too many partition maps in the logical volume descriptor. */ +#define VERR_ISOFS_TOO_MANY_PART_MAPS (-25316) +/** Malformed partition map table in the logical volume descriptor. */ +#define VERR_ISOFS_MALFORMED_PART_MAP_TABLE (-25317) +/** Unable to find partition descriptor for a partition map table entry. */ +#define VERR_ISOFS_PARTITION_NOT_FOUND (-25318) +/** Partition mapping table is shorted than described. */ +#define VERR_ISOFS_INCOMPLETE_PART_MAP_TABLE (-25319) +/** Unknown partition map entry type. */ +#define VERR_ISOFS_UNKNOWN_PART_MAP_ENTRY_TYPE (-25320) +/** Unkonwn paritition ID found in the partition map table. */ +#define VERR_ISOFS_UNKNOWN_PART_MAP_TYPE_ID (-25321) +/** Support for virtual partitions as not yet been implemented. */ +#define VERR_ISOFS_VPM_NOT_SUPPORTED (-25322) +/** Support for sparable partitions as not yet been implemented. */ +#define VERR_ISOFS_SPM_NOT_SUPPORTED (-25323) +/** Support for metadata partitions as not yet been implemented. */ +#define VERR_ISOFS_MPM_NOT_SUPPORTED (-25324) +/** Invalid or unsupported logical block size. */ +#define VERR_ISOFS_UNSUPPORTED_LOGICAL_BLOCK_SIZE (-25325) +/** Unsupported domain ID in logical volume descriptor. */ +#define VERR_ISOFS_BAD_LVD_DOMAIN_ID (-25326) +/** Malformed or invalid file set descriptor location. */ +#define VERR_ISOFS_BAD_LVD_FILE_SET_DESC_LOCATION (-25327) +/** Non-standard descriptor character set in the logical volume descriptor. */ +#define VERR_ISOFS_BAD_LVD_DESC_CHAR_SET (-25329) +/** Invalid partition index in a location. */ +#define VERR_ISOFS_INVALID_PARTITION_INDEX (-25330) +/** Unsupported file system charset. */ +#define VERR_ISOFS_FSD_UNSUPPORTED_CHAR_SET (-25331) +/** File set descriptor has an zero length or invalid root dir extent. */ +#define VERR_ISOFS_FSD_ZERO_ROOT_DIR (-25332) +/** File set descriptor has a next extent member. */ +#define VERR_ISOFS_FSD_NEXT_EXTENT (-25333) +/** The ICB for is too big. */ +#define VERR_ISOFS_ICB_TOO_BIG (-25334) +/** The ICB for is too small. */ +#define VERR_ISOFS_ICB_TOO_SMALL (-25335) +/** No direct ICB entries found. */ +#define VERR_ISOFS_NO_DIRECT_ICB_ENTRIES (-25336) +/** Too many ICB indirections, possibly a loop. */ +#define VERR_ISOFS_TOO_MANY_ICB_INDIRECTIONS (-25337) +/** Too deep ICB recursion. */ +#define VERR_ISOFS_TOO_DEEP_ICB_RECURSION (-25338) +/** ICB is too small to contain anything useful. */ +#define VERR_ISOFS_ICB_ENTRY_TOO_SMALL (-25339) +/** Unsupported tag encountered in ICB. */ +#define VERR_ISOFS_UNSUPPORTED_ICB (-25340) +/** Bad file entry (ICB). */ +#define VERR_ISOFS_BAD_FILE_ENTRY (-25341) +/** Unknown allocation descriptor type. */ +#define VERR_ISO_FS_UNKNOWN_AD_TYPE (-25342) +/** Malformed extended allocation descriptor. */ +#define VERR_ISOFS_BAD_EXTAD (-25343) +/** Wrong file type. */ +#define VERR_ISOFS_WRONG_FILE_TYPE (-25344) +/** Unknow file type. */ +#define VERR_ISOFS_UNKNOWN_FILE_TYPE (-25345) + +/** Not implemented for UDF. */ +#define VERR_ISOFS_UDF_NOT_IMPLEMENTED (-25390) +/** Internal processing error \#1. */ +#define VERR_ISOFS_IPE_1 (-25391) +/** Internal processing error \#2. */ +#define VERR_ISOFS_IPE_2 (-25392) +/** Internal processing error \#3. */ +#define VERR_ISOFS_IPE_3 (-25393) +/** Internal processing error \#4. */ +#define VERR_ISOFS_IPE_4 (-25394) +/** Internal processing error \#5. */ +#define VERR_ISOFS_IPE_5 (-25395) +/** @} */ + + +/** @name RTSerialPort status codes + * @{ */ +/** A break was detected until all requested data could be received. */ +#define VERR_SERIALPORT_BREAK_DETECTED (-25500) +/** The chosen baudrate is invalid or not supported by the given serial port. */ +#define VERR_SERIALPORT_INVALID_BAUDRATE (-25501) +/** @} */ + + +/** @name RTCRest status codes + * @{ */ +/** Do not know how to handle the content type in the server response. */ +#define VERR_REST_RESPONSE_CONTENT_TYPE_NOT_SUPPORTED (-25700) +/** Invalid UTF-8 encoding in the response. */ +#define VERR_REST_RESPONSE_INVALID_UTF8_ENCODING (-25701) +/** Server response contains embedded zero character(s). */ +#define VERR_REST_RESPONSE_EMBEDDED_ZERO_CHAR (-25702) +/** Server response contains unexpected repetitive header field. */ +#define VERR_REST_RESPONSE_REPEAT_HEADER_FIELD (-25703) +/** Unable to decode date value. */ +#define VWRN_REST_UNABLE_TO_DECODE_DATE (25704) +/** Unable to decode date value. */ +#define VERR_REST_UNABLE_TO_DECODE_DATE (-25704) +/** Wrong JSON type for bool value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_BOOL (-25705) +/** Wrong JSON type for integer value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER (-25706) +/** Wrong JSON type for double value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_DOUBLE (-25707) +/** Wrong JSON type for string value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_STRING (-25708) +/** Wrong JSON type for date value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_DATE (-25709) +/** Unable to parse string as bool. */ +#define VERR_REST_UNABLE_TO_PARSE_STRING_AS_BOOL (-25710) +/** A path parameter was not set. */ +#define VERR_REST_PATH_PARAMETER_NOT_SET (-25711) +/** A required query parameter was not set. */ +#define VERR_REST_REQUIRED_QUERY_PARAMETER_NOT_SET (-25712) +/** A required header parmaeter was not set. */ +#define VERR_REST_REQUIRED_HEADER_PARAMETER_NOT_SET (-25713) + +/** Internal error \#1. */ +#define VERR_REST_INTERNAL_ERROR_1 (-25791) +/** Internal error \#2. */ +#define VERR_REST_INTERNAL_ERROR_2 (-25792) +/** Internal error \#3. */ +#define VERR_REST_INTERNAL_ERROR_3 (-25793) +/** Internal error \#4. */ +#define VERR_REST_INTERNAL_ERROR_4 (-25794) +/** Internal error \#5. */ +#define VERR_REST_INTERNAL_ERROR_5 (-25795) +/** Internal error \#6. */ +#define VERR_REST_INTERNAL_ERROR_6 (-25796) +/** Internal error \#7. */ +#define VERR_REST_INTERNAL_ERROR_7 (-25797) +/** Internal error \#8. */ +#define VERR_REST_INTERNAL_ERROR_8 (-25798) +/** Internal error \#9. */ +#define VERR_REST_INTERNAL_ERROR_9 (-25799) +/** @} */ + + +/** @name RTCrCipher status codes + * @{ */ +/** Unsupported cipher. */ +#define VERR_CR_CIPHER_NOT_SUPPORTED (-25800) +/** EVP_EncryptInit failed. */ +#define VERR_CR_CIPHER_OSSL_ENCRYPT_INIT_FAILED (-25801) +/** EVP_EncryptUpdate failed. */ +#define VERR_CR_CIPHER_OSSL_ENCRYPT_UPDATE_FAILED (-25802) +/** EVP_EncryptFinal failed. */ +#define VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED (-25803) +/** EVP_DecryptInit failed. */ +#define VERR_CR_CIPHER_OSSL_DECRYPT_INIT_FAILED (-25804) +/** EVP_DecryptUpdate failed. */ +#define VERR_CR_CIPHER_OSSL_DECRYPT_UPDATE_FAILED (-25805) +/** EVP_DecryptFinal failed. */ +#define VERR_CR_CIPHER_OSSL_DECRYPT_FINAL_FAILED (-25806) +/** Invalid key length. */ +#define VERR_CR_CIPHER_INVALID_KEY_LENGTH (-25807) +/** Invalid initialization vector length. */ +#define VERR_CR_CIPHER_INVALID_INITIALIZATION_VECTOR_LENGTH (-25808) +/** Invalid tag length. */ +#define VERR_CR_CIPHER_INVALID_TAG_LENGTH (-25809) +/** EVP_CIPHER_CTX_ctrl EVP_CTRL_AEAD_GET_TAG failed. */ +#define VERR_CR_CIPHER_OSSL_GET_TAG_FAILED (-25810) +/** EVP_CIPHER_CTX_ctrl EVP_CTRL_AEAD_SET_TAG failed. */ +#define VERR_CR_CIPHER_OSSL_SET_TAG_FAILED (-25811) +/** @} */ + + +/** @name RTShMem status codes + * @{ */ +/** Maximum number of mappings reached. */ +#define VERR_SHMEM_MAXIMUM_MAPPINGS_REACHED (-26000) +/** @} */ + + +/** @name RTIoQueue status codes + * @{ */ +/** The handle was not registered for use with the I/O queue. */ +#define VERR_IOQUEUE_HANDLE_NOT_REGISTERED (-26200) +/** The I/O queue is full and can't accept more requests. */ +#define VERR_IOQUEUE_FULL (-26201) +/** The I/O queue doesn't contain any prepared requests to commit or wait for completion. */ +#define VERR_IOQUEUE_EMPTY (-26202) +/** The I/O queue has requests pending which need complete first. */ +#define VERR_IOQUEUE_BUSY (-26203) +/** @} */ + + +/** @name FTP status codes + * @{ */ +/** FTP Internal Server Error. */ +#define VERR_FTP_STATUS_SERVER_ERROR (-26400) +/** FTP initialization failed. */ +#define VERR_FTP_INIT_FAILED (-26401) +/** Data connection not found. */ +#define VERR_FTP_DATA_CONN_INIT_FAILED (-26402) +/** Data connection not found. */ +#define VERR_FTP_DATA_CONN_NOT_FOUND (-26403) +/** Data connection limit has been reached. */ +#define VERR_FTP_DATA_CONN_LIMIT_REACHED (-26404) +/** Client not found. */ +#define VERR_FTP_CLIENT_NOT_FOUND (-26405) +/** Client limit has been reached. */ +#define VERR_FTP_CLIENT_LIMIT_REACHED (-26406) +/** @} */ + + +/** @name Trace Log status codes. + * @{ */ +/** The trace log is malformed. */ +#define VERR_TRACELOG_READER_MALFORMED_LOG (-26600) +/** The trace log version is not supported. */ +#define VERR_TRACELOG_READER_LOG_UNSUPPORTED (-26601) +/** The trace log reader iterator reached the end of the event list. */ +#define VERR_TRACELOG_READER_ITERATOR_END (-26602) +/** @} */ + + +/** @name Hardened AVL tree status codes. + * @{ */ +/** Node index is out of bounds. */ +#define VERR_HARDAVL_INDEX_OUT_OF_BOUNDS (-26801) +/** Node pointer is not within the memory allocated for nodes. */ +#define VERR_HARDAVL_POINTER_OUT_OF_BOUNDS (-26802) +/** Node pointer does not point to the start of a node. */ +#define VERR_HARDAVL_MISALIGNED_POINTER (-26803) +/** Bogus reference to freed node. */ +#define VERR_HARDAVL_NODE_IS_FREE (-26804) +/** Stack overflow during AVL tree operation. */ +#define VERR_HARDAVL_STACK_OVERFLOW (-26810) +/** Attempted to insert mode with invalid key range. */ +#define VERR_HARDAVL_INSERT_INVALID_KEY_RANGE (-26811) +/** Bad left tree height. */ +#define VERR_HARDAVL_BAD_LEFT_HEIGHT (-26812) +/** Bad left right height. */ +#define VERR_HARDAVL_BAD_RIGHT_HEIGHT (-26813) +/** Bad new tree height. */ +#define VERR_HARDAVL_BAD_NEW_HEIGHT (-26814) +/** Unexpected NULL pointer to left subtree. */ +#define VERR_HARDAVL_UNEXPECTED_NULL_LEFT (-26815) +/** Unexpected NULL pointer to right subtree. */ +#define VERR_HARDAVL_UNEXPECTED_NULL_RIGHT (-26816) +/** Tree traversal encountered more nodes than available in the allocator. */ +#define VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES (-26817) +/** Too deep walk during lookup. */ +#define VERR_HARDAVL_LOOKUP_TOO_DEEP (-26818) +/** Bad tree height. */ +#define VERR_HARDAVL_BAD_HEIGHT (-26819) +/** Unbalanced tree. */ +#define VERR_HARDAVL_UNBALANCED (-26820) +/** @} */ + +/* SED-END */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_err_h */ + diff --git a/include/iprt/err.mac b/include/iprt/err.mac new file mode 100644 index 00000000..5bc57b9b --- /dev/null +++ b/include/iprt/err.mac @@ -0,0 +1,1201 @@ +;; @file +; IPRT - Status Codes. +; +; Automatically generated by err.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%define VINF_SUCCESS 0 +%define VERR_GENERAL_FAILURE (-1) +%define VERR_INVALID_PARAMETER (-2) +%define VWRN_INVALID_PARAMETER 2 +%define VERR_INVALID_MAGIC (-3) +%define VWRN_INVALID_MAGIC 3 +%define VERR_INVALID_HANDLE (-4) +%define VWRN_INVALID_HANDLE 4 +%define VERR_LOCK_FAILED (-5) +%define VERR_INVALID_POINTER (-6) +%define VERR_IDT_FAILED (-7) +%define VERR_NO_MEMORY (-8) +%define VERR_ALREADY_LOADED (-9) +%define VERR_PERMISSION_DENIED (-10) +%define VINF_PERMISSION_DENIED 10 +%define VERR_VERSION_MISMATCH (-11) +%define VERR_NOT_IMPLEMENTED (-12) +%define VINF_NOT_IMPLEMENTED 12 +%define VERR_INVALID_FLAGS (-13) +%define VERR_NOT_EQUAL (-18) +%define VERR_NOT_SYMLINK (-19) +%define VERR_NO_TMP_MEMORY (-20) +%define VERR_INVALID_FMODE (-21) +%define VERR_WRONG_ORDER (-22) +%define VERR_NO_TLS_FOR_SELF (-23) +%define VERR_FAILED_TO_SET_SELF_TLS (-24) +%define VERR_NO_CONT_MEMORY (-26) +%define VERR_NO_PAGE_MEMORY (-27) +%define VINF_ALREADY_INITIALIZED 28 +%define VERR_ALREADY_INITIALIZED (-28) +%define VERR_THREAD_IS_DEAD (-29) +%define VERR_THREAD_NOT_WAITABLE (-30) +%define VERR_PAGE_TABLE_NOT_PRESENT (-31) +%define VERR_INVALID_CONTEXT (-32) +%define VERR_TIMER_BUSY (-33) +%define VERR_ADDRESS_CONFLICT (-34) +%define VERR_UNRESOLVED_ERROR (-35) +%define VERR_INVALID_FUNCTION (-36) +%define VERR_NOT_SUPPORTED (-37) +%define VINF_NOT_SUPPORTED 37 +%define VERR_ACCESS_DENIED (-38) +%define VERR_INTERRUPTED (-39) +%define VINF_INTERRUPTED 39 +%define VERR_TIMEOUT (-40) +%define VINF_TIMEOUT 40 +%define VERR_BUFFER_OVERFLOW (-41) +%define VINF_BUFFER_OVERFLOW 41 +%define VERR_TOO_MUCH_DATA (-42) +%define VERR_MAX_THRDS_REACHED (-43) +%define VERR_MAX_PROCS_REACHED (-44) +%define VERR_SIGNAL_REFUSED (-45) +%define VERR_SIGNAL_PENDING (-46) +%define VERR_SIGNAL_INVALID (-47) +%define VERR_STATE_CHANGED (-48) +%define VWRN_STATE_CHANGED 48 +%define VERR_INVALID_UUID_FORMAT (-49) +%define VERR_PROCESS_NOT_FOUND (-50) +%define VERR_PROCESS_RUNNING (-51) +%define VERR_TRY_AGAIN (-52) +%define VINF_TRY_AGAIN 52 +%define VERR_PARSE_ERROR (-53) +%define VERR_OUT_OF_RANGE (-54) +%define VERR_NUMBER_TOO_BIG (-55) +%define VWRN_NUMBER_TOO_BIG 55 +%define VERR_NO_DIGITS (-56) +%define VWRN_NO_DIGITS 56 +%define VERR_NEGATIVE_UNSIGNED (-57) +%define VWRN_NEGATIVE_UNSIGNED 57 +%define VERR_NO_TRANSLATION (-58) +%define VWRN_NO_TRANSLATION 58 +%define VERR_CODE_POINT_ENDIAN_INDICATOR (-59) +%define VERR_CODE_POINT_SURROGATE (-60) +%define VERR_INVALID_UTF8_ENCODING (-61) +%define VERR_INVALID_UTF16_ENCODING (-62) +%define VERR_CANT_RECODE_AS_UTF16 (-63) +%define VERR_NO_STR_MEMORY (-64) +%define VERR_NO_UTF16_MEMORY (-65) +%define VERR_NO_CODE_POINT_MEMORY (-66) +%define VERR_MEMORY_BUSY (-67) +%define VERR_TIMER_ACTIVE (-68) +%define VERR_TIMER_SUSPENDED (-69) +%define VERR_CANCELLED (-70) +%define VERR_MEMOBJ_INIT_FAILED (-71) +%define VERR_NO_LOW_MEMORY (-72) +%define VERR_NO_PHYS_MEMORY (-73) +%define VERR_ADDRESS_TOO_BIG (-74) +%define VERR_MAP_FAILED (-75) +%define VERR_TRAILING_CHARS (-76) +%define VWRN_TRAILING_CHARS 76 +%define VERR_TRAILING_SPACES (-77) +%define VWRN_TRAILING_SPACES 77 +%define VERR_NOT_FOUND (-78) +%define VWRN_NOT_FOUND 78 +%define VERR_INVALID_STATE (-79) +%define VWRN_INVALID_STATE 79 +%define VERR_OUT_OF_RESOURCES (-80) +%define VWRN_OUT_OF_RESOURCES 80 +%define VERR_NO_MORE_HANDLES (-81) +%define VERR_PREEMPT_DISABLED (-82) +%define VERR_END_OF_STRING (-83) +%define VINF_END_OF_STRING 83 +%define VERR_PAGE_COUNT_OUT_OF_RANGE (-84) +%define VERR_OBJECT_DESTROYED (-85) +%define VINF_OBJECT_DESTROYED 85 +%define VERR_DANGLING_OBJECTS (-86) +%define VWRN_DANGLING_OBJECTS 86 +%define VERR_INVALID_BASE64_ENCODING (-87) +%define VERR_CALLBACK_RETURN (-88) +%define VINF_CALLBACK_RETURN 88 +%define VERR_AUTHENTICATION_FAILURE (-89) +%define VERR_NOT_POWER_OF_TWO (-90) +%define VERR_IGNORED (-91) +%define VERR_CONCURRENT_ACCESS (-92) +%define VERR_CALLER_NO_REFERENCE (-93) +%define VERR_NO_CHANGE (-95) +%define VINF_NO_CHANGE 95 +%define VERR_NO_EXEC_MEMORY (-96) +%define VERR_UNSUPPORTED_ALIGNMENT (-97) +%define VINF_UNSUPPORTED_ALIGNMENT 97 +%define VERR_DUPLICATE (-98) +%define VERR_MISSING (-99) +%define VERR_UNEXPECTED_EXCEPTION (-22400) +%define VERR_BUFFER_UNDERFLOW (-22401) +%define VINF_BUFFER_UNDERFLOW 22401 +%define VERR_UNEVEN_INPUT (-22402) +%define VERR_NOT_AVAILABLE (-22403) +%define VERR_PROC_DETACH_NOT_SUPPORTED (-22404) +%define VERR_ACCOUNT_RESTRICTED (-22405) +%define VINF_ACCOUNT_RESTRICTED 22405 +%define VERR_UNABLE_TO_SATISFY_REQUIREMENTS (-22406) +%define VWRN_UNABLE_TO_SATISFY_REQUIREMENTS 22406 +%define VERR_ALLOCATION_TOO_BIG (-22407) +%define VERR_MISMATCH (-22408) +%define VERR_WRONG_TYPE (-22409) +%define VWRN_WRONG_TYPE (22409) +%define VERR_PRIVILEGE_NOT_HELD (-22410) +%define VERR_PROC_TCB_PRIV_NOT_HELD (-22411) +%define VERR_PROC_APT_PRIV_NOT_HELD (-22412) +%define VERR_PROC_IQ_PRIV_NOT_HELD (-22413) +%define VERR_MP_TOO_MANY_CPUS (-22414) +%define VERR_WRONG_PARAMETER_COUNT (-22415) +%define VERR_WRONG_PARAMETER_TYPE (-22416) +%define VERR_INVALID_CLIENT_ID (-22417) +%define VERR_INVALID_SESSION_ID (-22418) +%define VERR_PROC_ELEVATION_REQUIRED (-22419) +%define VERR_INCOMPATIBLE_CONFIG (-22420) +%define VERR_NO_STRING_TERMINATOR (-22421) +%define VERR_EMPTY_STRING (-22422) +%define VERR_TOO_MANY_REFERENCES (-22423) +%define VINF_THREAD_IS_TERMINATING (22424) +%define VERR_THREAD_IS_TERMINATING (-22424) +%define VERR_PROC_NO_ARG_TRANSLATION (-22425) +%define VERR_FLOAT_UNDERFLOW (-22426) +%define VWRN_FLOAT_UNDERFLOW (22426) +%define VERR_FLOAT_OVERFLOW (-22427) +%define VWRN_FLOAT_OVERFLOW (22427) +%define VERR_FILE_IO_ERROR (-100) +%define VERR_OPEN_FAILED (-101) +%define VERR_FILE_NOT_FOUND (-102) +%define VERR_PATH_NOT_FOUND (-103) +%define VERR_INVALID_NAME (-104) +%define VERR_ALREADY_EXISTS (-105) +%define VWRN_ALREADY_EXISTS 105 +%define VERR_TOO_MANY_OPEN_FILES (-106) +%define VERR_SEEK (-107) +%define VERR_NEGATIVE_SEEK (-108) +%define VERR_SEEK_ON_DEVICE (-109) +%define VERR_EOF (-110) +%define VINF_EOF 110 +%define VERR_READ_ERROR (-111) +%define VERR_WRITE_ERROR (-112) +%define VERR_WRITE_PROTECT (-113) +%define VERR_SHARING_VIOLATION (-114) +%define VERR_FILE_LOCK_FAILED (-115) +%define VERR_FILE_LOCK_VIOLATION (-116) +%define VERR_CANT_CREATE (-117) +%define VERR_CANT_DELETE_DIRECTORY (-118) +%define VERR_NOT_SAME_DEVICE (-119) +%define VERR_FILENAME_TOO_LONG (-120) +%define VERR_MEDIA_NOT_PRESENT (-121) +%define VERR_MEDIA_NOT_RECOGNIZED (-122) +%define VERR_FILE_NOT_LOCKED (-123) +%define VERR_FILE_LOCK_LOST (-124) +%define VERR_DIR_NOT_EMPTY (-125) +%define VERR_NOT_A_DIRECTORY (-126) +%define VERR_IS_A_DIRECTORY (-127) +%define VERR_FILE_TOO_BIG (-128) +%define VERR_FILE_AIO_NO_REQUEST (-129) +%define VERR_FILE_AIO_IN_PROGRESS (-130) +%define VERR_FILE_AIO_COMPLETED (-131) +%define VERR_FILE_AIO_BUSY (-132) +%define VERR_FILE_AIO_LIMIT_EXCEEDED (-133) +%define VERR_FILE_AIO_CANCELED (-134) +%define VERR_FILE_AIO_NOT_SUBMITTED (-135) +%define VERR_FILE_AIO_NOT_PREPARED (-136) +%define VERR_FILE_AIO_INSUFFICIENT_RESSOURCES (-137) +%define VERR_RESOURCE_BUSY (-138) +%define VERR_NOT_A_FILE (-139) +%define VERR_IS_A_FILE (-140) +%define VERR_UNEXPECTED_FS_OBJ_TYPE (-141) +%define VERR_PATH_DOES_NOT_START_WITH_ROOT (-142) +%define VERR_PATH_IS_RELATIVE (-143) +%define VERR_PATH_IS_NOT_RELATIVE (-144) +%define VERR_PATH_ZERO_LENGTH (-145) +%define VERR_FILE_AIO_INSUFFICIENT_EVENTS (-146) +%define VERR_STALE_FILE_HANDLE (-147) +%define VERR_DISK_IO_ERROR (-150) +%define VERR_INVALID_DRIVE (-151) +%define VERR_DISK_FULL (-152) +%define VERR_DISK_CHANGE (-153) +%define VERR_DRIVE_LOCKED (-154) +%define VERR_DISK_INVALID_FORMAT (-155) +%define VERR_TOO_MANY_SYMLINKS (-156) +%define VERR_NS_SYMLINK_SET_TIME (-157) +%define VERR_NS_SYMLINK_CHANGE_OWNER (-158) +%define VERR_SYMLINK_NOT_ALLOWED (-159) +%define VERR_IS_A_SYMLINK (-160) +%define VERR_IS_A_FIFO (-161) +%define VERR_IS_A_SOCKET (-162) +%define VERR_IS_A_BLOCK_DEVICE (-163) +%define VERR_IS_A_CHAR_DEVICE (-164) +%define VERR_DRIVE_IS_EMPTY (-165) +%define VERR_SEARCH_ERROR (-200) +%define VERR_NO_MORE_FILES (-201) +%define VERR_NO_MORE_SEARCH_HANDLES (-202) +%define VWRN_NO_DIRENT_INFO 203 +%define VERR_INTERNAL_ERROR (-225) +%define VERR_INTERNAL_ERROR_2 (-226) +%define VERR_INTERNAL_ERROR_3 (-227) +%define VERR_INTERNAL_ERROR_4 (-228) +%define VERR_INTERNAL_ERROR_5 (-229) +%define VERR_IPE_UNEXPECTED_STATUS (-230) +%define VERR_IPE_UNEXPECTED_INFO_STATUS (-231) +%define VERR_IPE_UNEXPECTED_ERROR_STATUS (-232) +%define VERR_IPE_UNINITIALIZED_STATUS (-233) +%define VERR_IPE_NOT_REACHED_DEFAULT_CASE (-234) +%define VERR_DEV_IO_ERROR (-250) +%define VERR_IO_BAD_UNIT (-251) +%define VERR_IO_NOT_READY (-252) +%define VERR_IO_BAD_COMMAND (-253) +%define VERR_IO_CRC (-254) +%define VERR_IO_BAD_LENGTH (-255) +%define VERR_IO_SECTOR_NOT_FOUND (-256) +%define VERR_IO_GEN_FAILURE (-257) +%define VERR_PIPE_IO_ERROR (-300) +%define VERR_BROKEN_PIPE (-301) +%define VERR_BAD_PIPE (-302) +%define VERR_PIPE_BUSY (-303) +%define VERR_NO_DATA (-304) +%define VERR_PIPE_NOT_CONNECTED (-305) +%define VERR_MORE_DATA (-306) +%define VERR_PIPE_NOT_READ (-307) +%define VERR_PIPE_NOT_WRITE (-308) +%define VERR_SEM_ERROR (-350) +%define VERR_TOO_MANY_SEMAPHORES (-351) +%define VERR_EXCL_SEM_ALREADY_OWNED (-352) +%define VERR_SEM_IS_SET (-353) +%define VERR_TOO_MANY_SEM_REQUESTS (-354) +%define VERR_NOT_OWNER (-355) +%define VERR_TOO_MANY_OPENS (-356) +%define VERR_TOO_MANY_POSTS (-357) +%define VERR_ALREADY_POSTED (-358) +%define VINF_ALREADY_POSTED (358) +%define VERR_ALREADY_RESET (-359) +%define VERR_SEM_BUSY (-360) +%define VERR_SEM_OWNER_DIED (-361) +%define VERR_SEM_NOT_FOUND (-362) +%define VERR_SEM_DESTROYED (-363) +%define VERR_SEM_NESTED (-364) +%define VINF_SEM_NESTED (364) +%define VERR_DEADLOCK (-365) +%define VERR_SEM_OUT_OF_TURN (-366) +%define VERR_SEM_BAD_CONTEXT (-367) +%define VINF_SEM_BAD_CONTEXT (367) +%define VERR_SEM_LV_WRONG_ORDER (-368) +%define VERR_SEM_LV_WRONG_RELEASE_ORDER (-369) +%define VERR_SEM_LV_NESTED (-370) +%define VERR_SEM_LV_INVALID_PARAMETER (-371) +%define VERR_SEM_LV_DEADLOCK (-372) +%define VERR_SEM_LV_EXISTING_DEADLOCK (-373) +%define VERR_SEM_LV_NOT_OWNER (-374) +%define VERR_SEM_LV_ILLEGAL_UPGRADE (-375) +%define VERR_SEM_LV_NOT_SIGNALLER (-376) +%define VERR_SEM_LV_INTERNAL_ERROR (-377) +%define VERR_NET_IO_ERROR (-400) +%define VERR_NET_OUT_OF_RESOURCES (-401) +%define VERR_NET_HOST_NOT_FOUND (-402) +%define VERR_NET_PATH_NOT_FOUND (-403) +%define VERR_NET_PRINT_ERROR (-404) +%define VERR_NET_NO_NETWORK (-405) +%define VERR_NET_NOT_UNIQUE_NAME (-406) +%define VERR_NET_IN_PROGRESS (-436) +%define VERR_NET_ALREADY_IN_PROGRESS (-437) +%define VERR_NET_NOT_SOCKET (-438) +%define VERR_NET_DEST_ADDRESS_REQUIRED (-439) +%define VERR_NET_MSG_SIZE (-440) +%define VERR_NET_PROTOCOL_TYPE (-441) +%define VERR_NET_PROTOCOL_NOT_AVAILABLE (-442) +%define VERR_NET_PROTOCOL_NOT_SUPPORTED (-443) +%define VERR_NET_SOCKET_TYPE_NOT_SUPPORTED (-444) +%define VERR_NET_OPERATION_NOT_SUPPORTED (-445) +%define VERR_NET_PROTOCOL_FAMILY_NOT_SUPPORTED (-446) +%define VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED (-447) +%define VERR_NET_ADDRESS_IN_USE (-448) +%define VERR_NET_ADDRESS_NOT_AVAILABLE (-449) +%define VERR_NET_DOWN (-450) +%define VERR_NET_UNREACHABLE (-451) +%define VERR_NET_CONNECTION_RESET (-452) +%define VERR_NET_CONNECTION_ABORTED (-453) +%define VERR_NET_CONNECTION_RESET_BY_PEER (-454) +%define VERR_NET_NO_BUFFER_SPACE (-455) +%define VERR_NET_ALREADY_CONNECTED (-456) +%define VERR_NET_NOT_CONNECTED (-457) +%define VERR_NET_SHUTDOWN (-458) +%define VERR_NET_TOO_MANY_REFERENCES (-459) +%define VERR_NET_CONNECTION_TIMED_OUT (-460) +%define VERR_NET_CONNECTION_REFUSED (-461) +%define VERR_NET_HOST_DOWN (-464) +%define VERR_NET_HOST_UNREACHABLE (-465) +%define VERR_NET_PROTOCOL_ERROR (-466) +%define VERR_NET_INCOMPLETE_TX_PACKET (-467) +%define VERR_NET_INIT_FAILED (-468) +%define VERR_NET_NOT_UNSUPPORTED (-469) +%define VERR_TCP_SERVER_STOP (-500) +%define VINF_TCP_SERVER_STOP 500 +%define VERR_TCP_SERVER_SHUTDOWN (-501) +%define VERR_TCP_SERVER_DESTROYED (-502) +%define VINF_TCP_SERVER_NO_CLIENT 503 +%define VERR_UDP_SERVER_STOP (-520) +%define VINF_UDP_SERVER_STOP 520 +%define VERR_UDP_SERVER_SHUTDOWN (-521) +%define VERR_UDP_SERVER_DESTROYED (-522) +%define VINF_UDP_SERVER_NO_CLIENT 523 +%define VERR_L4_INVALID_DS_OFFSET (-550) +%define VERR_IPC (-551) +%define VERR_RESOURCE_IN_USE (-552) +%define VERR_IPC_PROCESS_NOT_FOUND (-553) +%define VERR_IPC_RECEIVE_TIMEOUT (-554) +%define VERR_IPC_SEND_TIMEOUT (-555) +%define VERR_IPC_RECEIVE_CANCELLED (-556) +%define VERR_IPC_SEND_CANCELLED (-557) +%define VERR_IPC_RECEIVE_ABORTED (-558) +%define VERR_IPC_SEND_ABORTED (-559) +%define VERR_IPC_RECEIVE_MAP_FAILED (-560) +%define VERR_IPC_SEND_MAP_FAILED (-561) +%define VERR_IPC_RECEIVE_SEND_PF_TIMEOUT (-562) +%define VERR_IPC_SEND_SEND_PF_TIMEOUT (-563) +%define VINF_IPC_RECEIVE_MSG_CUT 564 +%define VINF_IPC_SEND_MSG_CUT 565 +%define VERR_L4_DS_MANAGER_NOT_FOUND (-566) +%define VERR_INVALID_EXE_SIGNATURE (-600) +%define VERR_ELF_EXE_NOT_SUPPORTED (-601) +%define VERR_PE_EXE_NOT_SUPPORTED (-602) +%define VERR_LX_EXE_NOT_SUPPORTED (-603) +%define VERR_LE_EXE_NOT_SUPPORTED (-604) +%define VERR_NE_EXE_NOT_SUPPORTED (-605) +%define VERR_MZ_EXE_NOT_SUPPORTED (-606) +%define VERR_AOUT_EXE_NOT_SUPPORTED (-607) +%define VERR_BAD_EXE_FORMAT (-608) +%define VERR_SYMBOL_NOT_FOUND (-609) +%define VERR_MODULE_NOT_FOUND (-610) +%define VERR_SYMBOL_VALUE_TOO_BIG (-611) +%define VERR_IMAGE_TOO_BIG (-612) +%define VERR_IMAGE_BASE_TOO_HIGH (-614) +%define VERR_LDR_ARCH_MISMATCH (-615) +%define VERR_LDR_MISMATCH_NATIVE (-616) +%define VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND (-617) +%define VERR_LDR_GENERAL_FAILURE (-618) +%define VERR_LDR_IMAGE_HASH (-619) +%define VERR_LDRPE_DELAY_IMPORT (-620) +%define VERR_LDRPE_CERT_MALFORMED (-621) +%define VERR_LDRPE_CERT_UNSUPPORTED (-622) +%define VERR_LDRPE_GLOBALPTR (-623) +%define VERR_LDRPE_TLS (-624) +%define VERR_LDRPE_COM_DESCRIPTOR (-625) +%define VERR_LDRPE_LOAD_CONFIG_SIZE (-626) +%define VERR_LDRPE_LOCK_PREFIX_TABLE (-627) +%define VERR_LDRPE_GUARD_CF_STUFF (-628) +%define VERR_LDRELF_ODD_ENDIAN (-630) +%define VERR_LDRELF_DYN (-631) +%define VERR_LDRELF_EXEC (-632) +%define VERR_LDRELF_MACHINE (-633) +%define VERR_LDRELF_VERSION (-634) +%define VERR_LDRELF_MULTIPLE_SYMTABS (-635) +%define VERR_LDRELF_RELOCATION_NOT_SUPPORTED (-636) +%define VERR_LDRELF_INVALID_SYMBOL_INDEX (-637) +%define VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET (-638) +%define VERR_LDRELF_INVALID_RELOCATION_OFFSET (-639) +%define VERR_LDRELF_NO_SYMBOL_OR_NO_STRING_TABS (-640) +%define VERR_LDRELF_UNTERMINATED_STRING_TAB (-641) +%define VERR_LDR_INVALID_LINK_ADDRESS (-647) +%define VERR_LDR_INVALID_RVA (-648) +%define VERR_LDR_INVALID_SEG_OFFSET (-649) +%define VERR_DBG_NO_LINE_NUMBERS (-650) +%define VERR_DBG_NO_SYMBOLS (-651) +%define VERR_DBG_INVALID_ADDRESS (-652) +%define VERR_DBG_INVALID_SEGMENT_INDEX (-653) +%define VERR_DBG_INVALID_SEGMENT_OFFSET (-654) +%define VERR_DBG_INVALID_RVA (-655) +%define VERR_DBG_SPECIAL_SEGMENT (-656) +%define VERR_DBG_ADDRESS_CONFLICT (-657) +%define VERR_DBG_DUPLICATE_SYMBOL (-658) +%define VERR_DBG_SEGMENT_INDEX_CONFLICT (-659) +%define VERR_DBG_LINE_NOT_FOUND (-660) +%define VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE (-661) +%define VERR_DBG_FILE_NAME_OUT_OF_RANGE (-662) +%define VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE (-663) +%define VERR_DBG_ADDRESS_WRAP (-664) +%define VERR_DBG_NOT_NM_MAP_FILE (-665) +%define VERR_DBG_NOT_LINUX_KALLSYMS (-666) +%define VERR_DBG_NO_MATCHING_INTERPRETER (-667) +%define VERR_DWARF_BAD_LINE_NUMBER_HEADER (-668) +%define VERR_DWARF_UNEXPECTED_END (-669) +%define VERR_DWARF_LEB_OVERFLOW (-670) +%define VERR_DWARF_BAD_LNE (-671) +%define VERR_DWARF_BAD_STRING (-672) +%define VERR_DWARF_BAD_POS (-673) +%define VERR_DWARF_BAD_INFO (-674) +%define VERR_DWARF_BAD_ABBREV (-675) +%define VERR_DWARF_ABBREV_NOT_FOUND (-676) +%define VERR_DWARF_UNKNOWN_FORM (-677) +%define VERR_DWARF_UNEXPECTED_FORM (-678) +%define VERR_DWARF_TODO (-679) +%define VERR_DWARF_UNKNOWN_LOC_OPCODE (-680) +%define VERR_DWARF_STACK_OVERFLOW (-681) +%define VERR_DWARF_STACK_UNDERFLOW (-682) +%define VERR_DWARF_IPE (-683) +%define VERR_DBG_CFG_INVALID_VALUE (-684) +%define VERR_DBG_CFG_NOT_UINT_PROP (-685) +%define VERR_DBG_DEFERRED_LOAD_FAILED (-686) +%define VERR_DBG_TODO (-687) +%define VERR_DBG_FILE_MISMATCH (-688) +%define VERR_DBG_MOD_IPE (-689) +%define VINF_DBG_ADJUSTED_SYM_SIZE 690 +%define VERR_CV_BAD_FORMAT (-691) +%define VERR_CV_TODO (-692) +%define VERR_CV_IPE (-693) +%define VERR_DBG_NO_UNWIND_INFO (-694) +%define VERR_DBG_UNWIND_INFO_NOT_FOUND (-695) +%define VERR_DBG_MALFORMED_UNWIND_INFO (-696) +%define VERR_RT_REQUEST_INVALID_TYPE (-700) +%define VERR_RT_REQUEST_STATE (-701) +%define VERR_RT_REQUEST_INVALID_PACKAGE (-702) +%define VERR_RT_REQUEST_STATUS_STILL_PENDING (-703) +%define VERR_RT_REQUEST_STATUS_FREED (-704) +%define VERR_ENV_VAR_NOT_FOUND (-750) +%define VINF_ENV_VAR_NOT_FOUND (750) +%define VWRN_ENV_NOT_FULLY_TRANSLATED (751) +%define VERR_ENV_INVALID_VAR_NAME (-752) +%define VINF_ENV_VAR_UNSET (753) +%define VERR_ENV_VAR_UNSET (-753) +%define VERR_CPU_OFFLINE (-800) +%define VERR_CPU_NOT_FOUND (-801) +%define VERR_NOT_ALL_CPUS_SHOWED (-802) +%define VERR_CPU_IPE_1 (-803) +%define VERR_GETOPT_UNKNOWN_OPTION (-825) +%define VERR_GETOPT_REQUIRED_ARGUMENT_MISSING (-826) +%define VERR_GETOPT_INVALID_ARGUMENT_FORMAT (-827) +%define VINF_GETOPT_NOT_OPTION 828 +%define VERR_GETOPT_INDEX_MISSING (-829) +%define VERR_CACHE_FULL (-850) +%define VERR_CACHE_EMPTY (-851) +%define VERR_MEM_CACHE_MAX_SIZE (-855) +%define VERR_S3_ACCESS_DENIED (-875) +%define VERR_S3_NOT_FOUND (-876) +%define VERR_S3_BUCKET_ALREADY_EXISTS (-877) +%define VERR_S3_BUCKET_NOT_EMPTY (-878) +%define VERR_S3_CANCELED (-879) +%define VERR_HTTP_STATUS_SERVER_ERROR (-884) +%define VERR_HTTP_INIT_FAILED (-885) +%define VERR_HTTP_NOT_FOUND (-886) +%define VERR_HTTP_ACCESS_DENIED (-887) +%define VERR_HTTP_BAD_REQUEST (-888) +%define VERR_HTTP_COULDNT_CONNECT (-889) +%define VERR_HTTP_SSL_CONNECT_ERROR (-890) +%define VERR_HTTP_CACERT_WRONG_FORMAT (-891) +%define VERR_HTTP_CACERT_CANNOT_AUTHENTICATE (-892) +%define VERR_HTTP_ABORTED (-893) +%define VERR_HTTP_REDIRECTED (-894) +%define VERR_HTTP_PROXY_NOT_FOUND (-895) +%define VERR_HTTP_HOST_NOT_FOUND (-896) +%define VERR_HTTP_CURL_PROXY_CONFIG (-897) +%define VERR_HTTP_CURL_ERROR (-899) +%define VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE (-900) +%define VERR_MANIFEST_WRONG_FILE_FORMAT (-901) +%define VERR_MANIFEST_DIGEST_MISMATCH (-902) +%define VERR_MANIFEST_FILE_MISMATCH (-903) +%define VERR_MANIFEST_ATTR_NOT_FOUND (-904) +%define VERR_MANIFEST_ATTR_TYPE_MISMATCH (-905) +%define VERR_MANIFEST_ATTR_TYPE_NOT_FOUND (-906) +%define VERR_TAR_CHKSUM_MISMATCH (-925) +%define VERR_TAR_END_OF_FILE (-926) +%define VERR_TAR_UNEXPECTED_EOS (-927) +%define VERR_TAR_EOS_MORE_INPUT (-928) +%define VERR_TAR_BAD_NUM_FIELD (-929) +%define VERR_TAR_BAD_NUM_FIELD_TERM (-930) +%define VERR_TAR_BASE_256_NOT_SUPPORTED (-931) +%define VERR_TAR_NUM_VALUE_TOO_LARGE (-932) +%define VERR_TAR_DEV_VALUE_TOO_LARGE (-933) +%define VERR_TAR_BAD_MODE_FIELD (-934) +%define VERR_TAR_MODE_WITH_TYPE (-935) +%define VERR_TAR_SIZE_NOT_ZERO (-936) +%define VERR_TAR_UNKNOWN_TYPE_FLAG (-937) +%define VERR_TAR_ZERO_HEADER (-938) +%define VERR_TAR_NOT_USTAR_V00 (-939) +%define VERR_TAR_EMPTY_NAME (-940) +%define VERR_TAR_NON_DIR_ENDS_WITH_SLASH (-941) +%define VERR_TAR_UNSUPPORTED_PAX_TYPE (-942) +%define VERR_TAR_UNSUPPORTED_SOLARIS_HDR_TYPE (-943) +%define VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE (-944) +%define VERR_TAR_BAD_CHKSUM_FIELD (-945) +%define VERR_TAR_MALFORMED_GNU_LONGXXXX (-946) +%define VERR_TAR_NAME_TOO_LONG (-947) +%define VINF_TAR_DIR_PATH (948) +%define VERR_POLL_HANDLE_NOT_POLLABLE (-950) +%define VERR_POLL_HANDLE_ID_EXISTS (-951) +%define VERR_POLL_HANDLE_ID_NOT_FOUND (-952) +%define VERR_POLL_SET_IS_FULL (-953) +%define VERR_PKZIP_NO_EOCB (-960) +%define VERR_PKZIP_NAME_TOO_LONG (-961) +%define VERR_PKZIP_BAD_LF_HEADER (-962) +%define VERR_PKZIP_BAD_CDF_HEADER (-963) +%define VERR_PKZIP_UNKNOWN_TYPE_FLAG (-964) +%define VERR_PKZIP_ZIP64EX_IN_ZIP32 (-965) +%define VERR_ZIP_ERROR (-22000) +%define VERR_ZIP_CORRUPTED (-22001) +%define VERR_ZIP_NO_MEMORY (-22002) +%define VERR_ZIP_UNSUPPORTED_VERSION (-22003) +%define VERR_ZIP_UNSUPPORTED_METHOD (-22004) +%define VERR_ZIP_BAD_HEADER (-22005) +%define VERR_VFS_CHAIN_NO_PREFIX (-22100) +%define VERR_VFS_CHAIN_EMPTY (-22101) +%define VERR_VFS_CHAIN_EXPECTED_ELEMENT (-22102) +%define VERR_VFS_CHAIN_UNKNOWN_TYPE (-22103) +%define VERR_VFS_CHAIN_EXPECTED_LEFT_PARENTHESES (-22104) +%define VERR_VFS_CHAIN_EXPECTED_RIGHT_PARENTHESES (-22105) +%define VERR_VFS_CHAIN_EXPECTED_PROVIDER_NAME (-22106) +%define VERR_VFS_CHAIN_EXPECTED_SEPARATOR (-22107) +%define VERR_VFS_CHAIN_LEADING_SEPARATOR (-22108) +%define VERR_VFS_CHAIN_TRAILING_SEPARATOR (-22109) +%define VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT (-22110) +%define VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT (-22111) +%define VERR_VFS_CHAIN_CAST_FAILED (-22112) +%define VERR_VFS_CHAIN_IPE (-22113) +%define VERR_VFS_CHAIN_PROVIDER_NOT_FOUND (-22114) +%define VERR_VFS_CHAIN_FINAL_TYPE_MISMATCH (-22115) +%define VERR_VFS_CHAIN_NO_ARGS (-22116) +%define VERR_VFS_CHAIN_ONE_ARG (-22117) +%define VERR_VFS_CHAIN_AT_MOST_ONE_ARG (-22118) +%define VERR_VFS_CHAIN_AT_LEAST_ONE_ARG (-22119) +%define VERR_VFS_CHAIN_TWO_ARGS (-22120) +%define VERR_VFS_CHAIN_AT_LEAST_TWO_ARGS (-22121) +%define VERR_VFS_CHAIN_AT_MOST_TWO_ARGS (-22122) +%define VERR_VFS_CHAIN_THREE_ARGS (-22123) +%define VERR_VFS_CHAIN_AT_LEAST_THREE_ARGS (-22124) +%define VERR_VFS_CHAIN_AT_MOST_THREE_ARGS (-22125) +%define VERR_VFS_CHAIN_FOUR_ARGS (-22126) +%define VERR_VFS_CHAIN_AT_LEAST_FOUR_ARGS (-22127) +%define VERR_VFS_CHAIN_AT_MOST_FOUR_ARGS (-22128) +%define VERR_VFS_CHAIN_FIVE_ARGS (-22129) +%define VERR_VFS_CHAIN_AT_LEAST_FIVE_ARGS (-22130) +%define VERR_VFS_CHAIN_AT_MOST_FIVE_ARGS (-22131) +%define VERR_VFS_CHAIN_SIX_ARGS (-22132) +%define VERR_VFS_CHAIN_AT_LEAST_SIX_ARGS (-22133) +%define VERR_VFS_CHAIN_AT_MOST_SIX_ARGS (-22134) +%define VERR_VFS_CHAIN_TOO_FEW_ARGS (-22135) +%define VERR_VFS_CHAIN_TOO_MANY_ARGS (-22136) +%define VERR_VFS_CHAIN_EMPTY_ARG (-22137) +%define VERR_VFS_CHAIN_INVALID_ARGUMENT (-22138) +%define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS (-22139) +%define VERR_VFS_CHAIN_ONLY_IOS (-22140) +%define VERR_VFS_CHAIN_ONLY_DIR (-22141) +%define VERR_VFS_CHAIN_ONLY_FSS (-22142) +%define VERR_VFS_CHAIN_ONLY_VFS (-22143) +%define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS_OR_DIR (-22144) +%define VERR_VFS_CHAIN_ONLY_DIR_OR_VFS (-22145) +%define VERR_VFS_CHAIN_TAKES_FILE (-22146) +%define VERR_VFS_CHAIN_TAKES_FILE_OR_IOS (-22147) +%define VERR_VFS_CHAIN_TAKES_DIR (-22148) +%define VERR_VFS_CHAIN_TAKES_FSS (-22149) +%define VERR_VFS_CHAIN_TAKES_VFS (-22150) +%define VERR_VFS_CHAIN_TAKES_DIR_OR_VFS (-22151) +%define VERR_VFS_CHAIN_TAKES_DIR_OR_FSS_OR_VFS (-22152) +%define VERR_VFS_CHAIN_READ_ONLY_IOS (-22153) +%define VERR_VFS_CHAIN_WRITE_ONLY_IOS (-22154) +%define VERR_VFS_CHAIN_PATH_ONLY (-22155) +%define VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY (-22156) +%define VERR_VFS_CHAIN_NOT_PATH_ONLY (-22157) +%define VERR_VFS_CHAIN_TOO_SHORT_FOR_PARENT (-22158) +%define VERR_DVM_MAP_EMPTY (-22200) +%define VERR_DVM_MAP_NO_VOLUME (-22201) +%define VERR_LOG_REVISION_MISMATCH (-22300) +%define VINF_LOG_DISABLED (22301) +%define VINF_LOG_NO_LOGGER (22302) +%define VERR_SYS_CANNOT_POWER_OFF (-22500) +%define VINF_SYS_MAY_POWER_OFF (22501) +%define VERR_SYS_SHUTDOWN_FAILED (-22502) +%define VERR_SYS_UNSUPPORTED_FIRMWARE_PROPERTY (-22503) +%define VERR_FILESYSTEM_CORRUPT (-22600) +%define VERR_XAR_WRONG_MAGIC (-22700) +%define VERR_XAR_BAD_HDR_SIZE (-22701) +%define VERR_XAR_UNSUPPORTED_VERSION (-22702) +%define VERR_XAR_UNSUPPORTED_HASH_FUNCTION (-22703) +%define VERR_XAR_TOC_TOO_SMALL (-22704) +%define VERR_XAR_TOC_TOO_BIG (-22705) +%define VERR_XAR_TOC_TOO_BIG_COMPRESSED (-22706) +%define VERR_XAR_TOC_UNCOMP_SIZE_MISMATCH (-22707) +%define VERR_XAR_TOC_STRLEN_MISMATCH (-22708) +%define VERR_XAR_TOC_UTF8_ENCODING (-22709) +%define VERR_XAR_TOC_XML_PARSE_ERROR (-22710) +%define VERR_XML_TOC_ELEMENT_MISSING (-22711) +%define VERR_XML_TOC_ELEMENT_HAS_SIBLINGS (-22712) +%define VERR_XAR_TOC_DIGEST_MISMATCH (-22713) +%define VERR_XAR_BAD_CHECKSUM_ELEMENT (-22714) +%define VERR_XAR_HASH_FUNCTION_MISMATCH (-22715) +%define VERR_XAR_BAD_DIGEST_LENGTH (-22716) +%define VERR_XAR_NOT_STREAMBLE_ELEMENT_ORDER (-22717) +%define VERR_XAR_MISSING_OFFSET_ELEMENT (-22718) +%define VERR_XAR_BAD_OFFSET_ELEMENT (-22719) +%define VERR_XAR_MISSING_SIZE_ELEMENT (-22720) +%define VERR_XAR_BAD_SIZE_ELEMENT (-22721) +%define VERR_XAR_MISSING_LENGTH_ELEMENT (-22722) +%define VERR_XAR_BAD_LENGTH_ELEMENT (-22723) +%define VERR_XAR_BAD_FILE_ELEMENT (-22724) +%define VERR_XAR_MISSING_DATA_ELEMENT (-22725) +%define VERR_XAR_UNKNOWN_FILE_TYPE (-22726) +%define VERR_XAR_NO_ENCODING (-22727) +%define VERR_XAR_BAD_FILE_TIMESTAMP (-22728) +%define VERR_XAR_BAD_FILE_MODE (-22729) +%define VERR_XAR_BAD_FILE_UID (-22730) +%define VERR_XAR_BAD_FILE_GID (-22731) +%define VERR_XAR_BAD_FILE_DEVICE_NO (-22732) +%define VERR_XAR_BAD_FILE_INODE (-22733) +%define VERR_XAR_INVALID_FILE_NAME (-22734) +%define VERR_XAR_EXTRACTED_HASH_MISMATCH (-22735) +%define VERR_XAR_EXTRACTED_SIZE_EXCEEDED (-22736) +%define VERR_XAR_ARCHIVED_HASH_MISMATCH (-22737) +%define VERR_XAR_UNUSED_ARCHIVED_DATA (-22738) +%define VERR_XAR_ARCHIVED_AND_EXTRACTED_SIZES_MISMATCH (-22739) +%define VERR_X509_READING_CERT_FROM_BIO (-23100) +%define VERR_X509_EXTRACT_PUBKEY_FROM_CERT (-23101) +%define VERR_X509_EXTRACT_RSA_FROM_PUBLIC_KEY (-23102) +%define VERR_X509_RSA_VERIFICATION_FUILURE (-23103) +%define VERR_X509_NO_BASIC_CONSTARAINTS (-23104) +%define VERR_X509_GETTING_EXTENSION_FROM_CERT (-23105) +%define VERR_X509_GETTING_DATA_FROM_EXTENSION (-23106) +%define VERR_X509_PRINT_EXTENSION_TO_BIO (-23107) +%define VERR_X509_CERTIFICATE_VERIFICATION_FAILURE (-23108) +%define VERR_X509_NOT_SELFSIGNED_CERTIFICATE (-23109) +%define VINF_X509_NOT_SELFSIGNED_CERTIFICATE 23109 +%define VERR_ASN1_ERROR (-22800) +%define VERR_ASN1_STRING_TYPE_NOT_IMPLEMENTED (-22801) +%define VERR_ASN1_INVALID_UTF8_STRING_ENCODING (-22802) +%define VERR_ASN1_INVALID_NUMERIC_STRING_ENCODING (-22803) +%define VERR_ASN1_INVALID_PRINTABLE_STRING_ENCODING (-22804) +%define VERR_ASN1_INVALID_T61_STRING_ENCODING (-22805) +%define VERR_ASN1_INVALID_VIDEOTEX_STRING_ENCODING (-22806) +%define VERR_ASN1_INVALID_IA5_STRING_ENCODING (-22807) +%define VERR_ASN1_INVALID_GRAPHIC_STRING_ENCODING (-22808) +%define VERR_ASN1_INVALID_VISIBLE_STRING_ENCODING (-22809) +%define VERR_ASN1_INVALID_GENERAL_STRING_ENCODING (-22810) +%define VERR_ASN1_INVALID_UNIVERSAL_STRING_ENCODING (-22811) +%define VERR_ASN1_INVALID_BMP_STRING_ENCODING (-22812) +%define VERR_ASN1_INVALID_OBJID_ENCODING (-22813) +%define VERR_ASN1_OBJID_COMPONENT_TOO_BIG (-22814) +%define VERR_ASN1_OBJID_TOO_MANY_COMPONENTS (-22815) +%define VERR_ASN1_OBJID_TOO_LONG_STRING_FORM (-22816) +%define VERR_ASN1_OBJID_INVALID_DOTTED_STRING (-22817) +%define VERR_ASN1_CONSTRUCTED_STRING_NOT_IMPL (-22818) +%define VERR_ASN1_STRING_TAG_MISMATCH (-22819) +%define VERR_ASN1_TIME_TAG_MISMATCH (-22820) +%define VINF_ASN1_MORE_DATA (22821) +%define VINF_ASN1_NOT_ENCODED (22822) +%define VERR_ASN1_TELETEX_UNKNOWN_ESC_SEQ (-22823) +%define VERR_ASN1_TELETEX_UNSUPPORTED_ESC_SEQ (-22824) +%define VERR_ASN1_TELETEX_UNSUPPORTED_CHARSET (-22825) +%define VERR_ASN1_NO_VTABLE (-22826) +%define VERR_ASN1_NO_CHECK_SANITY_METHOD (-22827) +%define VERR_ASN1_NOT_PRESENT (-22828) +%define VERR_ASN1_CURSOR_NOT_AT_END (-22829) +%define VERR_ASN1_CURSOR_LONG_TAG (-22830) +%define VERR_ASN1_CURSOR_BAD_LENGTH_ENCODING (-22831) +%define VERR_ASN1_CURSOR_ILLEGAL_INDEFINITE_LENGTH (-22832) +%define VERR_ASN1_CURSOR_BAD_INDEFINITE_LENGTH (-22833) +%define VERR_ASN1_CURSOR_BAD_LENGTH (-22834) +%define VERR_ASN1_CURSOR_NO_MORE_DATA (-22835) +%define VERR_ASN1_CURSOR_TOO_LITTLE_DATA_LEFT (-22836) +%define VERR_ASN1_CURSOR_ILLEGAL_CONSTRUCTED_STRING (-22837) +%define VERR_ASN1_CURSOR_TAG_MISMATCH (-22838) +%define VERR_ASN1_CURSOR_TAG_FLAG_CLASS_MISMATCH (-22839) +%define VERR_ASN1_BITSTRING_OUT_OF_BOUNDS (-22840) +%define VERR_ASN1_TIME_BAD_NORMALIZE_INPUT (-22841) +%define VERR_ASN1_TIME_NORMALIZE_ERROR (-22842) +%define VERR_ASN1_TIME_NORMALIZE_MISMATCH (-22843) +%define VERR_ASN1_INVALID_UTC_TIME_ENCODING (-22844) +%define VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING (-22845) +%define VERR_ASN1_INVALID_BOOLEAN_ENCODING (-22846) +%define VERR_ASN1_INVALID_NULL_ENCODING (-22847) +%define VERR_ASN1_INVALID_BITSTRING_ENCODING (-22848) +%define VERR_ASN1_DYNTYPE_TAG_NOT_IMPL (-22849) +%define VERR_ASN1_DYNTYPE_BAD_TAG (-22850) +%define VERR_ASN1_DUMMY_OBJECT (-22851) +%define VERR_ASN1_TOO_LONG (-22852) +%define VERR_ASN1_EXPECTED_PRIMITIVE (-22853) +%define VERR_ASN1_INVALID_DATA_POINTER (-22854) +%define VERR_ASN1_TOO_DEEPLY_NESTED (-22855) +%define VERR_ASN1_UNEXPECTED_OBJ_ID (-22856) +%define VERR_ASN1_INVALID_INTEGER_ENCODING (-22857) +%define VERR_ASN1_INTERNAL_ERROR_1 (-22895) +%define VERR_ASN1_INTERNAL_ERROR_2 (-22896) +%define VERR_ASN1_INTERNAL_ERROR_3 (-22897) +%define VERR_ASN1_INTERNAL_ERROR_4 (-22898) +%define VERR_ASN1_INTERNAL_ERROR_5 (-22899) +%define VERR_LDRVI_NOT_SIGNED (-22900) +%define VINF_LDRVI_NOT_SIGNED (22900) +%define VERR_LDRVI_READ_ERROR_HDR (-22901) +%define VERR_LDRVI_READ_ERROR_SHDRS (-22902) +%define VERR_LDRVI_READ_ERROR_SIGNATURE (-22903) +%define VERR_LDRVI_READ_ERROR_HASH (-22904) +%define VERR_LDRVI_FILE_LENGTH_ERROR (-22905) +%define VERR_LDRVI_NO_MEMORY_STATE (-22906) +%define VERR_LDRVI_NO_MEMORY_SIGNATURE (-22907) +%define VERR_LDRVI_NO_MEMORY_SHDRS (-22908) +%define VERR_LDRVI_NO_MEMORY_PARSE_OUTPUT (-22909) +%define VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY (-22910) +%define VERR_LDRVI_BAD_CERT_HDR_LENGTH (-22911) +%define VERR_LDRVI_BAD_CERT_HDR_REVISION (-22912) +%define VERR_LDRVI_BAD_CERT_HDR_TYPE (-22913) +%define VERR_LDRVI_BAD_CERT_MULTIPLE (-22914) +%define VERR_LDRVI_BAD_MZ_OFFSET (-22915) +%define VERR_LDRVI_INVALID_SECTION_COUNT (-22916) +%define VERR_LDRVI_SECTION_RAW_DATA_VALUES (-22917) +%define VERR_LDRVI_MACHINE_OPT_HDR_MAGIC_MISMATCH (-22918) +%define VERR_LDRVI_UNSUPPORTED_ARCH (-22919) +%define VERR_LDRVI_PARSE_IPE (-22921) +%define VERR_LDRVI_PARSE_BER_ERROR (-22922) +%define VERR_LDRVI_EXPECTED_INDIRECT_DATA_CONTENT_OID (-22923) +%define VERR_LDRVI_PAGE_HASH_TAB_SIZE_OVERFLOW (-22924) +%define VERR_LDRVI_PAGE_HASH_TAB_TOO_LONG (-22925) +%define VERR_LDRVI_PAGE_HASH_TAB_NOT_STRICTLY_SORTED (-22926) +%define VERR_PAGE_HASH_TAB_HASHES_NON_SECTION_DATA (-22927) +%define VERR_LDRVI_PAGE_HASH_MISMATCH (-22928) +%define VERR_LDRVI_IMAGE_HASH_MISMATCH (-22929) +%define VERR_LDRVI_BAD_CERT_FORMAT (-22930) +%define VERR_LDR_FORWARDER (-22950) +%define VERR_LDR_NOT_FORWARDER (-22951) +%define VERR_LDR_BAD_FORWARDER (-22952) +%define VERR_LDR_FORWARDER_CHAIN_TOO_LONG (-22953) +%define VERR_LDR_FORWARDERS_NOT_SUPPORTED (-22954) +%define VERR_LDRMACHO_OTHER_ENDIAN_NOT_SUPPORTED (-22955) +%define VERR_LDRMACHO_BAD_HEADER (-22956) +%define VERR_LDRMACHO_UNSUPPORTED_FILE_TYPE (-22957) +%define VERR_LDRMACHO_UNSUPPORTED_MACHINE (-22958) +%define VERR_LDRMACHO_BAD_LOAD_COMMAND (-22959) +%define VERR_LDRMACHO_UNKNOWN_LOAD_COMMAND (-22960) +%define VERR_LDRMACHO_UNSUPPORTED_LOAD_COMMAND (-22961) +%define VERR_LDRMACHO_BAD_SECTION (-22962) +%define VERR_LDRMACHO_UNSUPPORTED_SECTION (-22963) +%define VERR_LDRMACHO_UNSUPPORTED_INIT_SECTION (-22964) +%define VERR_LDRMACHO_UNSUPPORTED_TERM_SECTION (-22965) +%define VERR_LDRMACHO_UNKNOWN_SECTION (-22966) +%define VERR_LDRMACHO_BAD_SECTION_ORDER (-22967) +%define VERR_LDRMACHO_BIT_MIX (-22968) +%define VERR_LDRMACHO_BAD_OBJECT_FILE (-22969) +%define VERR_LDRMACHO_BAD_SYMBOL (-22970) +%define VERR_LDRMACHO_UNSUPPORTED_FIXUP_TYPE (-22971) +%define VERR_LDRMACHO_MIXED_DEBUG_SECTION_FLAGS (-22972) +%define VERR_LDRMACHO_NON_CONT_SEG_BITS (-22973) +%define VERR_LDRMACHO_TODO (-22974) +%define VERR_LDRMACHO_BAD_SYMTAB_SIZE (-22975) +%define VERR_LDR_DUPLICATE_SEGMENT_NAME (-22976) +%define VERR_LDR_NO_IMAGE_UUID (-22977) +%define VERR_LDR_BAD_FIXUP (-22978) +%define VERR_LDR_ADDRESS_OVERFLOW (-22979) +%define VERR_LDRLX_BAD_HEADER (-22980) +%define VERR_LDRLX_BAD_LOADER_SECTION (-22981) +%define VERR_LDRLX_BAD_FIXUP_SECTION (-22982) +%define VERR_LDRLX_BAD_OBJECT_TABLE (-22983) +%define VERR_LDRLX_BAD_PAGE_MAP (-22984) +%define VERR_LDRLX_BAD_ITERDATA (-22985) +%define VERR_LDRLX_BAD_ITERDATA2 (-22986) +%define VERR_LDRLX_BAD_BUNDLE (-22987) +%define VERR_LDRLX_NO_SONAME (-22988) +%define VERR_LDRLX_BAD_SONAME (-22989) +%define VERR_LDRLX_BAD_FORWARDER (-22990) +%define VERR_LDRLX_NRICHAIN_NOT_SUPPORTED (-22991) +%define VERR_LDRLX_IMPORT_ORDINAL_OUT_OF_BOUNDS (-22992) +%define VERR_CR_X509_GENERIC_ERROR (-23000) +%define VERR_CR_X509_INTERNAL_ERROR (-23001) +%define VERR_CR_X509_CERTPATHS_INTERNAL_ERROR (-23002) +%define VERR_CR_X509_NOT_VERIFIED (-23003) +%define VERR_CR_X509_NO_TRUST_ANCHOR (-23004) +%define VERR_CR_X509_UNKNOWN_CERT_SIGN_ALGO (-23005) +%define VERR_CR_X509_CERT_SIGN_ALGO_MISMATCH (-23006) +%define VERR_CR_X509_CERT_TBS_SIGN_ALGO_MISMATCH (-23007) +%define VERR_CR_X509_TBSCERT_EXTS_REQ_V3 (-23008) +%define VERR_CR_X509_TBSCERT_UNIQUE_IDS_REQ_V2 (-23009) +%define VERR_CR_X509_TBSCERT_SERIAL_NUMBER_OUT_OF_BOUNDS (-23010) +%define VERR_CR_X509_TBSCERT_UNSUPPORTED_VERSION (-23011) +%define VERR_CR_X509_PUBLIC_KEY_TOO_SMALL (-23012) +%define VERR_CR_X509_INVALID_NAME_STRING_TAG (-23013) +%define VERR_CR_X509_NAME_EMPTY_STRING (-23014) +%define VERR_CR_X509_NAME_NOT_STRING (-23015) +%define VERR_CR_X509_NAME_EMPTY_SET (-23016) +%define VERR_CR_X509_NAME_EMPTY_SUB_SET (-23017) +%define VERR_CR_X509_VALIDITY_SWAPPED (-23018) +%define VERR_CR_X509_TBSCERT_DUPLICATE_EXTENSION (-23019) +%define VERR_CR_X509_NAME_MISSING_RDN_MAP_ENTRY (-23020) +%define VERR_CR_X509_CPV_NO_TRUSTED_PATHS (-23021) +%define VERR_CR_X509_CPV_NO_VALID_POLICY (-23022) +%define VERR_CR_X509_CPV_UNKNOWN_CRITICAL_EXTENSION (-23023) +%define VERR_CR_X509_CPV_MISSING_KEY_CERT_SIGN (-23024) +%define VERR_CR_X509_CPV_MAX_PATH_LENGTH (-23025) +%define VERR_CR_X509_CPV_NOT_CA_CERT (-23026) +%define VERR_CR_X509_CPV_NOT_V3_CERT (-23027) +%define VERR_CR_X509_CPV_INVALID_POLICY_MAPPING (-23028) +%define VERR_CR_X509_CPV_NO_PERMITTED_NAMES (-23029) +%define VERR_CR_X509_CPV_NAME_NOT_PERMITTED (-23030) +%define VERR_CR_X509_CPV_ALT_NAME_NOT_PERMITTED (-23031) +%define VERR_CR_X509_CPV_ISSUER_MISMATCH (-23032) +%define VERR_CR_X509_CPV_NOT_VALID_AT_TIME (-23033) +%define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_CHOICE (-23034) +%define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MIN (-23035) +%define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MAX (-23036) +%define VERR_CR_X509_CPB_BAD_CERT_CTX (-23037) +%define VERR_CR_X509_OSSL_D2I_FAILED (-23090) +%define VERR_CR_PKCS7_GENERIC_ERROR (-23300) +%define VERR_CR_PKCS7_NO_SIGNER_INFOS (-23301) +%define VERR_CR_PKCS7_SIGNED_DATA_CERT_NOT_FOUND (-23302) +%define VERR_CR_PKCS7_KEY_USAGE_MISMATCH (-23303) +%define VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB (-23304) +%define VERR_CR_PKCS7_CONTENT_TYPE_ATTRIB_MISMATCH (-23305) +%define VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB (-23306) +%define VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB (-23307) +%define VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH (-23308) +%define VERR_CR_PKCS7_BAD_MESSAGE_DIGEST_ATTRIB (-23309) +%define VERR_CR_PKCS7_SIGNATURE_VERIFICATION_FAILED (-23310) +%define VERR_CR_PKCS7_INTERNAL_ERROR (-22311) +%define VERR_CR_PKCS7_OSSL_D2I_FAILED (-22312) +%define VERR_CR_PKCS7_OSSL_VERIFY_FAILED (-22313) +%define VERR_CR_PKCS7_DIGEST_PARAMS_NOT_IMPL (-22314) +%define VERR_CR_PKCS7_DIGEST_ALGO_NOT_FOUND_IN_LIST (-22315) +%define VERR_CR_PKCS7_NOT_SIGNED_DATA (-22316) +%define VERR_CR_PKCS7_NO_DIGEST_ALGORITHMS (-22317) +%define VERR_CR_PKCS7_TOO_MANY_DIGEST_ALGORITHMS (-22318) +%define VERR_CR_PKCS7_DIGEST_CREATE_ERROR (-22319) +%define VERR_CR_PKCS7_DIGEST_CALC_ERROR (-22320) +%define VERR_CR_PKCS7_SIGNED_DATA_VERSION (-22350) +%define VERR_CR_PKCS7_SIGNED_DATA_NO_DIGEST_ALGOS (-22351) +%define VERR_CR_PKCS7_UNKNOWN_DIGEST_ALGORITHM (-22352) +%define VERR_CR_PKCS7_NO_CERTIFICATES (-22353) +%define VERR_CR_PKCS7_EXPECTED_NO_CRLS (-22354) +%define VERR_CR_PKCS7_EXPECTED_ONE_SIGNER_INFO (-22355) +%define VERR_CR_PKCS7_SIGNER_INFO_VERSION (-22356) +%define VERR_CR_PKCS7_SIGNER_INFO_NO_ISSUER_SERIAL_NO (-22357) +%define VERR_CR_PKCS7_SIGNER_CERT_NOT_SHIPPED (-22358) +%define VERR_CR_PKCS7_SIGNER_INFO_DIGEST_ENCRYPT_MISMATCH (-22359) +%define VERR_CR_PKCS7_NOT_DATA (-22360) +%define VERR_CR_SPC_GENERIC_ERROR (-23400) +%define VERR_CR_SPC_NOT_EXACTLY_ONE_SIGNER_INFOS (-23401) +%define VERR_CR_SPC_NOT_EXACTLY_ONE_DIGEST_ALGO (-23402) +%define VERR_CR_SPC_SIGNED_IND_DATA_DIGEST_ALGO_MISMATCH (-23403) +%define VERR_CR_SPC_IND_DATA_DIGEST_ALGO_NOT_IN_DIGEST_ALGOS (-23404) +%define VERR_CR_SPC_UNKNOWN_DIGEST_ALGO (-23405) +%define VERR_CR_SPC_IND_DATA_DIGEST_SIZE_MISMATCH (-23406) +%define VERR_CR_SPC_EXPECTED_PE_IMAGE_DATA (-23407) +%define VERR_CR_SPC_PEIMAGE_DATA_NOT_PRESENT (-23408) +%define VERR_CR_SPC_BAD_MONIKER_UUID (-23409) +%define VERR_CR_SPC_UNKNOWN_MONIKER_UUID (-23410) +%define VERR_CR_SPC_BAD_MONIKER_CHOICE (-23411) +%define VERR_CR_SPC_MONIKER_BAD_DATA (-23412) +%define VERR_CR_SPC_PEIMAGE_MULTIPLE_HASH_TABS (-23413) +%define VERR_CR_SPC_PEIMAGE_UNKNOWN_ATTRIBUTE (-23414) +%define VERR_CR_SPC_PEIMAGE_URL_UNEXPECTED (-23415) +%define VERR_CR_SPC_PEIMAGE_NO_CONTENT (-23416) +%define VERR_CR_PKIX_GENERIC_ERROR (-23500) +%define VERR_CR_PKIX_SIGNATURE_TAKES_NO_PARAMETERS (-23501) +%define VERR_CR_PKIX_UNKNOWN_DIGEST_TYPE (-23502) +%define VERR_CR_PKIX_INTERNAL_ERROR (-23503) +%define VERR_CR_PKIX_HASH_TOO_LONG_FOR_KEY (-23504) +%define VERR_CR_PKIX_SIGNATURE_TOO_LONG (-23505) +%define VERR_CR_PKIX_SIGNATURE_GE_KEY (-23506) +%define VERR_CR_PKIX_SIGNATURE_NEGATIVE (-23507) +%define VERR_CR_PKIX_INVALID_SIGNATURE_LENGTH (-23508) +%define VERR_CR_PKIX_SIGNATURE_MISMATCH (-23509) +%define VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL (-23510) +%define VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN (-23511) +%define VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN (-23512) +%define VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP (-23513) +%define VERR_CR_PKIX_OSSL_CIPHER_ALOG_INIT_FAILED (-23514) +%define VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED (-23515) +%define VERR_CR_PKIX_OSSL_D2I_PUBLIC_KEY_FAILED (-23516) +%define VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR (-23517) +%define VERR_CR_PKIX_OSSL_D2I_PRIVATE_KEY_FAILED (-23518) +%define VERR_CR_PKIX_OSSL_EVP_PKEY_RSA_PAD_ERROR (-23519) +%define VERR_CR_PKIX_OSSL_SIGN_FINAL_FAILED (-23520) +%define VERR_CR_PKIX_OSSL_VS_IPRT_SIGNATURE_SIZE (-23521) +%define VERR_CR_PKIX_OSSL_VS_IPRT_SIGNATURE (-23522) +%define VERR_CR_PKIX_NOT_RSA_PRIVATE_KEY (-23523) +%define VERR_CR_PKIX_NOT_RSA_PUBLIC_KEY (-23524) +%define VERR_CR_STORE_GENERIC_ERROR (-23700) +%define VERR_CR_KEY_UNKNOWN_TYPE (-23800) +%define VERR_CR_KEY_FORMAT_NOT_SUPPORTED (-23801) +%define VERR_CR_KEY_ENCRYPTED (-23802) +%define VERR_CR_KEY_NO_DEK_INFO (-23803) +%define VERR_CR_KEY_DEK_INFO_TOO_LONG (-23804) +%define VERR_CR_KEY_DECRYPTION_NOT_SUPPORTED (-23805) +%define VERR_CR_KEY_UNSUPPORTED_CIPHER (-23806) +%define VERR_CR_KEY_UNEXPECTED_CIPHER_PARAMS (-23807) +%define VERR_CR_KEY_MISSING_CIPHER_PARAMS (-23808) +%define VERR_CR_KEY_TOO_SHORT_CIPHER_IV (-23809) +%define VERR_CR_KEY_MALFORMED_CIPHER_IV (-23810) +%define VERR_CR_KEY_PASSWORD_ENCODING (-23811) +%define VERR_CR_KEY_OSSL_DECRYPT_INIT_ERROR (-23812) +%define VERR_CR_KEY_DECRYPTION_FAILED (-23813) +%define VINF_CR_KEY_WAS_DECRYPTED (23814) +%define VERR_CR_KEY_GEN_FAILED_RSA (-23815) +%define VERR_CR_RSA_GENERIC_ERROR (-23900) +%define VERR_BIGNUM_SENSITIVE_INPUT (-24000) +%define VERR_BIGNUM_DIV_BY_ZERO (-24001) +%define VERR_BIGNUM_NEGATIVE_EXPONENT (-24002) +%define VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR (-24200) +%define VERR_CR_DIGEST_OSSL_DIGEST_CTX_COPY_ERROR (-24201) +%define VINF_CR_DIGEST_DEPRECATED (24202) +%define VERR_CR_DIGEST_DEPRECATED (-24202) +%define VINF_CR_DIGEST_COMPROMISED (24203) +%define VERR_CR_DIGEST_COMPROMISED (-24203) +%define VINF_CR_DIGEST_SEVERELY_COMPROMISED (24204) +%define VERR_CR_DIGEST_SEVERELY_COMPROMISED (-24204) +%define VERR_CR_DIGEST_NOT_SUPPORTED (-24205) +%define VERR_CR_PASSWORD_2_KEY_DERIVIATION_FAILED (-24396) +%define VERR_CR_RANDOM_SETUP_FAILED (-24397) +%define VERR_CR_RANDOM_FAILED (-24398) +%define VERR_CR_MALFORMED_PEM_HEADER (-24399) +%define VERR_PATH_MATCH_UNKNOWN_VARIABLE (-24400) +%define VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST (-24401) +%define VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED (-24402) +%define VERR_PATH_GLOB_UNKNOWN_CHAR_CLASS (-24403) +%define VERR_URI_EMPTY (-24600) +%define VERR_URI_TOO_SHORT (-24601) +%define VERR_URI_INVALID_SCHEME (-24602) +%define VERR_URI_INVALID_PORT_NUMBER (-24603) +%define VERR_URI_INVALID_ESCAPE_SEQ (-24604) +%define VERR_URI_ESCAPED_ZERO (-24605) +%define VERR_URI_ESCAPED_CHARS_NOT_VALID_UTF8 (-24606) +%define VERR_URI_INVALID_ESCAPED_UTF8_LEAD_BYTE (-24607) +%define VERR_URI_INVALID_ESCAPED_UTF8_CONTINUATION_BYTE (-24608) +%define VERR_URI_MISSING_UTF8_CONTINUATION_BYTE (-24609) +%define VERR_URI_NOT_FILE_SCHEME (-24610) +%define VERR_JSON_VALUE_INVALID_TYPE (-24700) +%define VERR_JSON_ITERATOR_END (-24701) +%define VERR_JSON_MALFORMED (-24702) +%define VERR_JSON_IS_EMPTY (-24703) +%define VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE (-24704) +%define VERR_JSON_MISSING_SURROGATE_PAIR (-24705) +%define VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE (-24706) +%define VERR_JSON_INVALID_CODEPOINT (-24707) +%define VERR_VFS_UNKNOWN_FORMAT (-24800) +%define VERR_VFS_BOGUS_FORMAT (-24801) +%define VERR_VFS_BOGUS_OFFSET (-24802) +%define VERR_VFS_UNSUPPORTED_FORMAT (-24803) +%define VERR_VFS_UNSUPPORTED_CREATE_TYPE (-24804) +%define VERR_ISOMK_BOOT_CAT_NO_VALIDATION_ENTRY (-25000) +%define VERR_ISOMK_BOOT_CAT_NO_DEFAULT_ENTRY (-25001) +%define VERR_ISOMK_BOOT_CAT_EXPECTED_SECTION_HEADER (-25002) +%define VERR_ISOMK_BOOT_CAT_EMPTY_ENTRY (-25003) +%define VERR_ISOMK_BOOT_CAT_INVALID_SECTION_SIZE (-25004) +%define VERR_ISOMK_BOOT_CAT_ERRATIC_ENTRY (-25005) +%define VERR_ISOMK_FILE_TOO_BIG_REQ_ISO_LEVEL_3 (-25006) +%define VERR_ISOMK_SYMLINK_REQ_ROCK_RIDGE (-25007) +%define VINF_ISOMK_SYMLINK_REQ_ROCK_RIDGE (25007) +%define VERR_ISOMK_SYMLINK_SUPPORT_DISABLED (-25008) +%define VERR_ISOMK_RR_NO_SPACE_FOR_CE (-25009) +%define VERR_ISOMK_IPE_RR_READ (-25010) +%define VERR_ISOMK_IPE_TABLE (-25011) +%define VERR_ISOMK_IPE_NAMESPACE_1 (-25012) +%define VERR_ISOMK_IPE_NAMESPACE_2 (-25013) +%define VERR_ISOMK_IPE_NAMESPACE_3 (-25014) +%define VERR_ISOMK_IPE_NAMESPACE_4 (-25015) +%define VERR_ISOMK_IPE_NAMESPACE_5 (-25016) +%define VERR_ISOMK_IPE_NAMESPACE_6 (-25017) +%define VERR_ISOMK_IPE_EMPTY_PATH (-25018) +%define VERR_ISOMK_IPE_EMPTY_COMPONENT (-25019) +%define VERR_ISOMK_IPE_ROOT_SLASH (-25020) +%define VERR_ISOMK_IPE_DESC_COUNT (-25021) +%define VERR_ISOMK_IPE_BUFFER_SIZE (-25022) +%define VERR_ISOMK_IPE_BOOT_CAT_FILE (-25023) +%define VERR_ISOMK_IPE_PRODUCE_TRANS_TBL (-25024) +%define VERR_ISOMK_IPE_READ_FILE_DATA_1 (-25025) +%define VERR_ISOMK_IPE_READ_FILE_DATA_2 (-25026) +%define VERR_ISOMK_IPE_READ_FILE_DATA_3 (-25027) +%define VERR_ISOMK_IPE_FINALIZE_1 (-25028) +%define VERR_ISOMK_RR_SPILL_FILE_FULL (-25029) +%define VERR_ISOMK_IMPORT_UNKNOWN_FORMAT (-25100) +%define VERR_ISOMK_IMPORT_TOO_MANY_VOL_DESCS (-25101) +%define VERR_ISOMK_IMPORT_INVALID_VOL_DESC_HDR (-25102) +%define VERR_ISOMK_IMPORT_MULTIPLE_PRIMARY_VOL_DESCS (-25103) +%define VERR_ISOMK_IMPORT_MULTIPLE_EL_TORITO_DESCS (-25104) +%define VERR_ISOMK_IMPORT_MULTIPLE_JOLIET_VOL_DESCS (-25105) +%define VERR_ISOMK_IMPORT_SUPPLEMENTARY_BEFORE_PRIMARY (-25106) +%define VERR_IOSMK_IMPORT_PRIMARY_VOL_DESC_VER (-25107) +%define VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC (-25108) +%define VERR_IOSMK_IMPORT_SUP_VOL_DESC_VER (-25109) +%define VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC (-25110) +%define VERR_ISOMK_IMPORT_LOGICAL_BLOCK_SIZE_NOT_2KB (-25111) +%define VERR_ISOMK_IMPORT_MORE_THAN_ONE_VOLUME_IN_SET (-25112) +%define VERR_ISOMK_IMPORT_INVALID_VOLUMNE_SEQ_NO (-25113) +%define VERR_ISOMK_IMPORT_VOLUME_SPACE_SIZE_MISMATCH (-25114) +%define VERR_ISOMK_IMPORT_VOLUME_IN_SET_MISMATCH (-25115) +%define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC (-25116) +%define VERR_ISOMK_IMPORT_ZERO_SIZED_ROOT_DIR (-25117) +%define VERR_ISOMK_IMPORT_ROOT_VOLUME_SEQ_NO (-25118) +%define VERR_ISOMK_IMPORT_ROOT_DIR_EXTENT_OUT_OF_BOUNDS (-25119) +%define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC_LENGTH (-25120) +%define VERR_ISOMK_IMPORT_ROOT_DIR_WITHOUT_DIR_FLAG (-25121) +%define VERR_ISOMK_IMPORT_ROOT_DIR_IS_MULTI_EXTENT (-25122) +%define VERR_ISOMK_IMPORT_TOO_DEEP_DIR_TREE (-25123) +%define VERR_ISOMK_IMPORT_BAD_DIR_REC (-25124) +%define VERR_ISOMK_IMPORT_DIR_REC_VOLUME_SEQ_NO (-25125) +%define VERR_ISOMK_IMPORT_DIR_REC_EXTENT_OUT_OF_BOUNDS (-25126) +%define VERR_ISOMK_IMPORT_BAD_DIR_REC_LENGTH (-25127) +%define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME_LENGTH (-25128) +%define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME (-25129) +%define VERR_ISOMK_IMPORT_DIR_WITH_MORE_EXTENTS (-25130) +%define VERR_ISOMK_IMPORT_MISMATCHING_MULTI_EXTENT_REC (-25131) +%define VERR_ISOMK_IMPORT_MISALIGNED_MULTI_EXTENT (-25132) +%define VERR_ISOMK_IMPORT_NON_CONTIGUOUS_MULTI_EXTENT (-25133) +%define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_OUT_OF_BOUNDS (-25140) +%define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_HEADER_ID (-25141) +%define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_KEYS (-25142) +%define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_CHECKSUM (-25143) +%define VERR_ISOMK_IMPORT_BOOT_CAT_UNKNOWN_HEADER_ID (-25144) +%define VERR_ISOMK_IMPORT_BOOT_CAT_INVALID_BOOT_MEDIA_TYPE (-25145) +%define VERR_ISOMK_IMPORT_BOOT_CAT_DEF_ENTRY_INVALID_FLAGS (-25146) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_RESERVED_FLAG (-25147) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_USES_UNUSED_FIELD (-25148) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_IMAGE_OUT_OF_BOUNDS (-25149) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_UNKNOWN_IMAGE_SIZE (-25150) +%define VERR_ISOMK_IMPORT_BOOT_CAT_MISSING_FINAL_OR_TOO_BIG (-25151) +%define VERR_ISOMK_IMPORT_BOOT_CAT_DEF_ENTRY_INVALID_BOOT_IND (-25152) +%define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_INVALID_ID (-25153) +%define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_UNDEFINED_FLAGS (-25154) +%define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_END_OF_SECTOR (-25155) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_CONTINUATION_WITH_NONE (-25156) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_CONTINUATION_EOS (-25157) +%define VERR_ISOFS_TAG_IS_ALL_ZEROS (-25300) +%define VERR_ISOFS_UNSUPPORTED_TAG_VERSION (-25301) +%define VERR_ISOFS_BAD_TAG_CHECKSUM (-25302) +%define VERR_ISOFS_TAG_SECTOR_MISMATCH (-25303) +%define VERR_ISOFS_DESC_CRC_MISMATCH (-25304) +%define VERR_ISOFS_INSUFFICIENT_DATA_FOR_DESC_CRC (-25305) +%define VERR_ISOFS_UNEXPECTED_VDS_DESC (-25306) +%define VERR_ISOFS_TOO_MANY_PVDS (-25307) +%define VERR_ISOFS_TOO_MANY_LVDS (-25308) +%define VERR_ISOFS_TOO_MANY_PDS (-25309) +%define VERR_ISOFS_TOO_BIT_PARTMAP_IN_LVD (-25310) +%define VERR_ISOFS_NO_PVD (-25311) +%define VERR_ISOFS_NO_LVD (-25312) +%define VERR_ISOFS_NO_PD (-25313) +%define VERR_ISOFS_MULTIPLE_PVDS (-25314) +%define VERR_ISOFS_MULTIPLE_LVDS (-25315) +%define VERR_ISOFS_TOO_MANY_PART_MAPS (-25316) +%define VERR_ISOFS_MALFORMED_PART_MAP_TABLE (-25317) +%define VERR_ISOFS_PARTITION_NOT_FOUND (-25318) +%define VERR_ISOFS_INCOMPLETE_PART_MAP_TABLE (-25319) +%define VERR_ISOFS_UNKNOWN_PART_MAP_ENTRY_TYPE (-25320) +%define VERR_ISOFS_UNKNOWN_PART_MAP_TYPE_ID (-25321) +%define VERR_ISOFS_VPM_NOT_SUPPORTED (-25322) +%define VERR_ISOFS_SPM_NOT_SUPPORTED (-25323) +%define VERR_ISOFS_MPM_NOT_SUPPORTED (-25324) +%define VERR_ISOFS_UNSUPPORTED_LOGICAL_BLOCK_SIZE (-25325) +%define VERR_ISOFS_BAD_LVD_DOMAIN_ID (-25326) +%define VERR_ISOFS_BAD_LVD_FILE_SET_DESC_LOCATION (-25327) +%define VERR_ISOFS_BAD_LVD_DESC_CHAR_SET (-25329) +%define VERR_ISOFS_INVALID_PARTITION_INDEX (-25330) +%define VERR_ISOFS_FSD_UNSUPPORTED_CHAR_SET (-25331) +%define VERR_ISOFS_FSD_ZERO_ROOT_DIR (-25332) +%define VERR_ISOFS_FSD_NEXT_EXTENT (-25333) +%define VERR_ISOFS_ICB_TOO_BIG (-25334) +%define VERR_ISOFS_ICB_TOO_SMALL (-25335) +%define VERR_ISOFS_NO_DIRECT_ICB_ENTRIES (-25336) +%define VERR_ISOFS_TOO_MANY_ICB_INDIRECTIONS (-25337) +%define VERR_ISOFS_TOO_DEEP_ICB_RECURSION (-25338) +%define VERR_ISOFS_ICB_ENTRY_TOO_SMALL (-25339) +%define VERR_ISOFS_UNSUPPORTED_ICB (-25340) +%define VERR_ISOFS_BAD_FILE_ENTRY (-25341) +%define VERR_ISO_FS_UNKNOWN_AD_TYPE (-25342) +%define VERR_ISOFS_BAD_EXTAD (-25343) +%define VERR_ISOFS_WRONG_FILE_TYPE (-25344) +%define VERR_ISOFS_UNKNOWN_FILE_TYPE (-25345) +%define VERR_ISOFS_UDF_NOT_IMPLEMENTED (-25390) +%define VERR_ISOFS_IPE_1 (-25391) +%define VERR_ISOFS_IPE_2 (-25392) +%define VERR_ISOFS_IPE_3 (-25393) +%define VERR_ISOFS_IPE_4 (-25394) +%define VERR_ISOFS_IPE_5 (-25395) +%define VERR_SERIALPORT_BREAK_DETECTED (-25500) +%define VERR_SERIALPORT_INVALID_BAUDRATE (-25501) +%define VERR_REST_RESPONSE_CONTENT_TYPE_NOT_SUPPORTED (-25700) +%define VERR_REST_RESPONSE_INVALID_UTF8_ENCODING (-25701) +%define VERR_REST_RESPONSE_EMBEDDED_ZERO_CHAR (-25702) +%define VERR_REST_RESPONSE_REPEAT_HEADER_FIELD (-25703) +%define VWRN_REST_UNABLE_TO_DECODE_DATE (25704) +%define VERR_REST_UNABLE_TO_DECODE_DATE (-25704) +%define VERR_REST_WRONG_JSON_TYPE_FOR_BOOL (-25705) +%define VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER (-25706) +%define VERR_REST_WRONG_JSON_TYPE_FOR_DOUBLE (-25707) +%define VERR_REST_WRONG_JSON_TYPE_FOR_STRING (-25708) +%define VERR_REST_WRONG_JSON_TYPE_FOR_DATE (-25709) +%define VERR_REST_UNABLE_TO_PARSE_STRING_AS_BOOL (-25710) +%define VERR_REST_PATH_PARAMETER_NOT_SET (-25711) +%define VERR_REST_REQUIRED_QUERY_PARAMETER_NOT_SET (-25712) +%define VERR_REST_REQUIRED_HEADER_PARAMETER_NOT_SET (-25713) +%define VERR_REST_INTERNAL_ERROR_1 (-25791) +%define VERR_REST_INTERNAL_ERROR_2 (-25792) +%define VERR_REST_INTERNAL_ERROR_3 (-25793) +%define VERR_REST_INTERNAL_ERROR_4 (-25794) +%define VERR_REST_INTERNAL_ERROR_5 (-25795) +%define VERR_REST_INTERNAL_ERROR_6 (-25796) +%define VERR_REST_INTERNAL_ERROR_7 (-25797) +%define VERR_REST_INTERNAL_ERROR_8 (-25798) +%define VERR_REST_INTERNAL_ERROR_9 (-25799) +%define VERR_CR_CIPHER_NOT_SUPPORTED (-25800) +%define VERR_CR_CIPHER_OSSL_ENCRYPT_INIT_FAILED (-25801) +%define VERR_CR_CIPHER_OSSL_ENCRYPT_UPDATE_FAILED (-25802) +%define VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED (-25803) +%define VERR_CR_CIPHER_OSSL_DECRYPT_INIT_FAILED (-25804) +%define VERR_CR_CIPHER_OSSL_DECRYPT_UPDATE_FAILED (-25805) +%define VERR_CR_CIPHER_OSSL_DECRYPT_FINAL_FAILED (-25806) +%define VERR_CR_CIPHER_INVALID_KEY_LENGTH (-25807) +%define VERR_CR_CIPHER_INVALID_INITIALIZATION_VECTOR_LENGTH (-25808) +%define VERR_CR_CIPHER_INVALID_TAG_LENGTH (-25809) +%define VERR_CR_CIPHER_OSSL_GET_TAG_FAILED (-25810) +%define VERR_CR_CIPHER_OSSL_SET_TAG_FAILED (-25811) +%define VERR_SHMEM_MAXIMUM_MAPPINGS_REACHED (-26000) +%define VERR_IOQUEUE_HANDLE_NOT_REGISTERED (-26200) +%define VERR_IOQUEUE_FULL (-26201) +%define VERR_IOQUEUE_EMPTY (-26202) +%define VERR_IOQUEUE_BUSY (-26203) +%define VERR_FTP_STATUS_SERVER_ERROR (-26400) +%define VERR_FTP_INIT_FAILED (-26401) +%define VERR_FTP_DATA_CONN_INIT_FAILED (-26402) +%define VERR_FTP_DATA_CONN_NOT_FOUND (-26403) +%define VERR_FTP_DATA_CONN_LIMIT_REACHED (-26404) +%define VERR_FTP_CLIENT_NOT_FOUND (-26405) +%define VERR_FTP_CLIENT_LIMIT_REACHED (-26406) +%define VERR_TRACELOG_READER_MALFORMED_LOG (-26600) +%define VERR_TRACELOG_READER_LOG_UNSUPPORTED (-26601) +%define VERR_TRACELOG_READER_ITERATOR_END (-26602) +%define VERR_HARDAVL_INDEX_OUT_OF_BOUNDS (-26801) +%define VERR_HARDAVL_POINTER_OUT_OF_BOUNDS (-26802) +%define VERR_HARDAVL_MISALIGNED_POINTER (-26803) +%define VERR_HARDAVL_NODE_IS_FREE (-26804) +%define VERR_HARDAVL_STACK_OVERFLOW (-26810) +%define VERR_HARDAVL_INSERT_INVALID_KEY_RANGE (-26811) +%define VERR_HARDAVL_BAD_LEFT_HEIGHT (-26812) +%define VERR_HARDAVL_BAD_RIGHT_HEIGHT (-26813) +%define VERR_HARDAVL_BAD_NEW_HEIGHT (-26814) +%define VERR_HARDAVL_UNEXPECTED_NULL_LEFT (-26815) +%define VERR_HARDAVL_UNEXPECTED_NULL_RIGHT (-26816) +%define VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES (-26817) +%define VERR_HARDAVL_LOOKUP_TOO_DEEP (-26818) +%define VERR_HARDAVL_BAD_HEIGHT (-26819) +%define VERR_HARDAVL_UNBALANCED (-26820) diff --git a/include/iprt/err.sed b/include/iprt/err.sed new file mode 100644 index 00000000..e094b083 --- /dev/null +++ b/include/iprt/err.sed @@ -0,0 +1,55 @@ +## @file +# IPRT - SED script for converting VBox/err.h to .mac. +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# 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, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +# in the VirtualBox distribution, in which case the provisions of the +# CDDL are applicable instead of those of the GPL. +# +# You may elect to license modified versions of this file under the +# terms and conditions of either the GPL or the CDDL or both. +# +# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +# + +# Handle text inside the markers. +/SED-START/,/SED-END/{ + +# if (#define) goto defines +/^[[:space:]]*#[[:space:]]*define/b defines + +} + +# Everything else is deleted! +d +b end + +## +# Convert the defines +:defines +s/^[[:space:]]*#[[:space:]]*define[[:space:]]*\([[:alnum:]_]*\)[[:space:]]*\(.*\)[[:space:]]*$/%define \1 \2/ +b end + +# next expression +:end diff --git a/include/iprt/errcore.h b/include/iprt/errcore.h new file mode 100644 index 00000000..12a09c1c --- /dev/null +++ b/include/iprt/errcore.h @@ -0,0 +1,947 @@ +/** @file + * IPRT - Status Codes Core. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_errcore_h +#define IPRT_INCLUDED_errcore_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @defgroup grp_rt_err_core Status Codes Core + * @ingroup grp_rt_err + * @{ + */ + +/** @def RTERR_STRICT_RC + * Indicates that RT_SUCCESS_NP, RT_SUCCESS, RT_FAILURE_NP and RT_FAILURE should + * make type enforcing at compile time. + * + * @remarks Only define this for C++ code. + */ +#if defined(__cplusplus) \ + && !defined(RTERR_STRICT_RC) \ + && !defined(RTERR_NO_STRICT_RC) \ + && ( defined(DOXYGEN_RUNNING) \ + || defined(DEBUG) \ + || defined(RT_STRICT) ) +# define RTERR_STRICT_RC 1 +#endif + + +/** @def RT_SUCCESS + * Check for success. We expect success in normal cases, that is the code path depending on + * this check is normally taken. To prevent any prediction use RT_SUCCESS_NP instead. + * + * @returns true if rc indicates success. + * @returns false if rc indicates failure. + * + * @param rc The iprt status code to test. + */ +#define RT_SUCCESS(rc) ( RT_LIKELY(RT_SUCCESS_NP(rc)) ) + +/** @def RT_SUCCESS_NP + * Check for success. Don't predict the result. + * + * @returns true if rc indicates success. + * @returns false if rc indicates failure. + * + * @param rc The iprt status code to test. + */ +#ifdef RTERR_STRICT_RC +# define RT_SUCCESS_NP(rc) ( RTErrStrictType(rc).success() ) +#else +# define RT_SUCCESS_NP(rc) ( (int)(rc) >= VINF_SUCCESS ) +#endif + +/** @def RT_FAILURE + * Check for failure, predicting unlikely. + * + * We don't expect in normal cases, that is the code path depending on this + * check is normally NOT taken. To prevent any prediction use RT_FAILURE_NP + * instead. + * + * @returns true if rc indicates failure. + * @returns false if rc indicates success. + * + * @param rc The iprt status code to test. + * + * @remarks Please structure your code to use the RT_SUCCESS() macro instead of + * RT_FAILURE() where possible, as that gives us a better shot at good + * code with the windows compilers. + */ +#define RT_FAILURE(rc) ( RT_UNLIKELY(!RT_SUCCESS_NP(rc)) ) + +/** @def RT_FAILURE_NP + * Check for failure, no prediction. + * + * @returns true if rc indicates failure. + * @returns false if rc indicates success. + * + * @param rc The iprt status code to test. + */ +#define RT_FAILURE_NP(rc) ( !RT_SUCCESS_NP(rc) ) + + +#ifdef __cplusplus +/** + * Strict type validation class. + * + * This is only really useful for type checking the arguments to RT_SUCCESS, + * RT_SUCCESS_NP, RT_FAILURE and RT_FAILURE_NP. The RTErrStrictType2 + * constructor is for integration with external status code strictness regimes. + */ +class RTErrStrictType +{ +protected: + int32_t m_rc; + +public: + /** + * Constructor for interaction with external status code strictness regimes. + * + * This is a special constructor for helping external return code validator + * classes interact cleanly with RT_SUCCESS, RT_SUCCESS_NP, RT_FAILURE and + * RT_FAILURE_NP while barring automatic cast to integer. + * + * @param rcObj IPRT status code object from an automatic cast. + */ + RTErrStrictType(RTErrStrictType2 const rcObj) RT_NO_THROW_DEF + : m_rc(rcObj.getValue()) + { + } + + /** + * Integer constructor used by RT_SUCCESS_NP. + * + * @param rc IPRT style status code. + */ + RTErrStrictType(int32_t rc) RT_NO_THROW_DEF + : m_rc(rc) + { + } + +#if 0 /** @todo figure where int32_t is long instead of int. */ + /** + * Integer constructor used by RT_SUCCESS_NP. + * + * @param rc IPRT style status code. + */ + RTErrStrictType(signed int rc) + : m_rc(rc) + { + } +#endif + + /** + * Test for success. + */ + bool success() const RT_NO_THROW_DEF + { + return m_rc >= 0; + } + +private: + /** @name Try ban a number of wrong types. + * @{ */ + RTErrStrictType(uint8_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(uint16_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(uint32_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(uint64_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(int8_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(int16_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(int64_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + /** @todo fight long here - clashes with int32_t/int64_t on some platforms. */ + /** @} */ +}; +#endif /* __cplusplus */ + + +RT_C_DECLS_BEGIN + +/** + * Converts a Darwin HRESULT error to an iprt status code. + * + * @returns iprt status code. + * @param iNativeCode HRESULT error code. + * @remark Darwin ring-3 only. + */ +RTDECL(int) RTErrConvertFromDarwinCOM(int32_t iNativeCode); + +/** + * Converts a Darwin IOReturn error to an iprt status code. + * + * @returns iprt status code. + * @param iNativeCode IOReturn error code. + * @remark Darwin only. + */ +RTDECL(int) RTErrConvertFromDarwinIO(int iNativeCode); + +/** + * Converts a Darwin kern_return_t error to an iprt status code. + * + * @returns iprt status code. + * @param iNativeCode kern_return_t error code. + * @remark Darwin only. + */ +RTDECL(int) RTErrConvertFromDarwinKern(int iNativeCode); + +/** + * Converts a Darwin error to an iprt status code. + * + * This will consult RTErrConvertFromDarwinKern, RTErrConvertFromDarwinIO + * and RTErrConvertFromDarwinCOM in this order. The latter is ring-3 only as it + * doesn't apply elsewhere. + * + * @returns iprt status code. + * @param iNativeCode Darwin error code. + * @remarks Darwin only. + * @remarks This is recommended over RTErrConvertFromDarwinKern and RTErrConvertFromDarwinIO + * since these are really just subsets of the same error space. + */ +RTDECL(int) RTErrConvertFromDarwin(int iNativeCode); + +/** + * Converts errno to iprt status code. + * + * @returns iprt status code. + * @param iNativeCode errno code. + */ +RTDECL(int) RTErrConvertFromErrno(int iNativeCode); + +/** + * Converts a L4 errno to a iprt status code. + * + * @returns iprt status code. + * @param uNativeCode l4 errno. + * @remark L4 only. + */ +RTDECL(int) RTErrConvertFromL4Errno(unsigned uNativeCode); + +/** + * Converts NT status code to iprt status code. + * + * Needless to say, this is only available on NT and winXX targets. + * + * @returns iprt status code. + * @param lNativeCode NT status code. + * @remark Windows only. + */ +RTDECL(int) RTErrConvertFromNtStatus(long lNativeCode); + +/** + * Converts OS/2 error code to iprt status code. + * + * @returns iprt status code. + * @param uNativeCode OS/2 error code. + * @remark OS/2 only. + */ +RTDECL(int) RTErrConvertFromOS2(unsigned uNativeCode); + +/** + * Converts Win32 error code to iprt status code. + * + * @returns iprt status code. + * @param uNativeCode Win32 error code. + * @remark Windows only. + */ +RTDECL(int) RTErrConvertFromWin32(unsigned uNativeCode); + +/** + * Converts an iprt status code to a errno status code. + * + * @returns errno status code. + * @param iErr iprt status code. + */ +RTDECL(int) RTErrConvertToErrno(int iErr); + + +#ifndef DECLARED_FNRTSTROUTPUT /* duplicated in iprt/string.h & iprt/log.h */ +#define DECLARED_FNRTSTROUTPUT +/** + * Output callback. + * + * @returns number of bytes written. + * @param pvArg User argument. + * @param pachChars Pointer to an array of utf-8 characters. + * @param cbChars Number of bytes in the character array pointed to by pachChars. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSTROUTPUT,(void *pvArg, const char *pachChars, size_t cbChars)); +/** Pointer to callback function. */ +typedef FNRTSTROUTPUT *PFNRTSTROUTPUT; +#endif + +#ifdef IN_RING3 + +RTDECL(bool) RTErrIsKnown(int rc); +RTDECL(ssize_t) RTErrQueryDefine(int rc, char *pszBuf, size_t cbBuf, bool fFailIfUnknown); +RTDECL(ssize_t) RTErrQueryMsgShort(int rc, char *pszBuf, size_t cbBuf, bool fFailIfUnknown); +RTDECL(ssize_t) RTErrQueryMsgFull(int rc, char *pszBuf, size_t cbBuf, bool fFailIfUnknown); + +/** @name Error formatters used internally by RTStrFormat. + * @internal + * @{ */ +RTDECL(size_t) RTErrFormatDefine( int rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrFormatMsgShort(int rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrFormatMsgFull( int rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrFormatMsgAll( int rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +/** @} */ + + +# ifdef RT_OS_WINDOWS +/** + * Windows error code message. + */ +typedef struct RTWINERRMSG +{ + /** Pointer to the full message string. */ + const char *pszMsgFull; + /** Pointer to the define string. */ + const char *pszDefine; + /** Error code number. */ + long iCode; +} RTWINERRMSG; +/** Pointer to Windows error code message. */ +typedef RTWINERRMSG *PRTWINERRMSG; +/** Pointer to const Windows error code message. */ +typedef const RTWINERRMSG *PCRTWINERRMSG; + +RTDECL(bool) RTErrWinIsKnown(long rc); +RTDECL(ssize_t) RTErrWinQueryDefine(long rc, char *pszBuf, size_t cbBuf, bool fFailIfUnknown); + +/** @name Error formatters used internally by RTStrFormat. + * @internal + * @{ */ +RTDECL(size_t) RTErrWinFormatDefine(long rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrWinFormatMsg( long rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrWinFormatMsgAll(long rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +/** @} */ + +# else /* !RT_OS_WINDOWS */ + +/** + * COM/XPCOM error code message. + */ +typedef struct RTCOMERRMSG +{ + /** Pointer to the full message string. */ + const char *pszMsgFull; + /** Pointer to the define string. */ + const char *pszDefine; + /** Error code number. */ + uint32_t iCode; +} RTCOMERRMSG; +/** Pointer to a XPCOM/COM error code message. */ +typedef RTCOMERRMSG *PRTCOMERRMSG; +/** Pointer to const a XPCOM/COM error code message. */ +typedef const RTCOMERRMSG *PCRTCOMERRMSG; + +/** + * Get the message structure corresponding to a given COM/XPCOM error code. + * + * @returns Pointer to read-only message description. + * @param rc The status code. + */ +RTDECL(PCRTCOMERRMSG) RTErrCOMGet(uint32_t rc); + +# endif /* !RT_OS_WINDOWS */ + +#endif /* IN_RING3 */ + +/** @defgroup RTERRINFO_FLAGS_XXX RTERRINFO::fFlags + * @{ */ +/** Custom structure (the default). */ +#define RTERRINFO_FLAGS_T_CUSTOM UINT32_C(0) +/** Static structure (RTERRINFOSTATIC). */ +#define RTERRINFO_FLAGS_T_STATIC UINT32_C(1) +/** Allocated structure (RTErrInfoAlloc). */ +#define RTERRINFO_FLAGS_T_ALLOC UINT32_C(2) +/** Reserved type. */ +#define RTERRINFO_FLAGS_T_RESERVED UINT32_C(3) +/** Type mask. */ +#define RTERRINFO_FLAGS_T_MASK UINT32_C(3) +/** Error info is set. */ +#define RTERRINFO_FLAGS_SET RT_BIT_32(2) +/** Fixed flags (magic). */ +#define RTERRINFO_FLAGS_MAGIC UINT32_C(0xbabe0000) +/** The bit mask for the magic value. */ +#define RTERRINFO_FLAGS_MAGIC_MASK UINT32_C(0xffff0000) +/** @} */ + +/** + * Initializes an error info structure. + * + * @returns @a pErrInfo. + * @param pErrInfo The error info structure to init. + * @param pszMsg The message buffer. Must be at least one byte. + * @param cbMsg The size of the message buffer. + */ +DECLINLINE(PRTERRINFO) RTErrInfoInit(PRTERRINFO pErrInfo, char *pszMsg, size_t cbMsg) +{ + *pszMsg = '\0'; + + pErrInfo->fFlags = RTERRINFO_FLAGS_T_CUSTOM | RTERRINFO_FLAGS_MAGIC; + pErrInfo->rc = /*VINF_SUCCESS*/ 0; + pErrInfo->pszMsg = pszMsg; + pErrInfo->cbMsg = cbMsg; + pErrInfo->apvReserved[0] = NULL; + pErrInfo->apvReserved[1] = NULL; + + return pErrInfo; +} + +/** + * Initialize a static error info structure. + * + * @returns Pointer to the core error info structure. + * @param pStaticErrInfo The static error info structure to init. + */ +DECLINLINE(PRTERRINFO) RTErrInfoInitStatic(PRTERRINFOSTATIC pStaticErrInfo) +{ + RTErrInfoInit(&pStaticErrInfo->Core, pStaticErrInfo->szMsg, sizeof(pStaticErrInfo->szMsg)); + pStaticErrInfo->Core.fFlags = RTERRINFO_FLAGS_T_STATIC | RTERRINFO_FLAGS_MAGIC; + return &pStaticErrInfo->Core; +} + +/** + * Allocates a error info structure with a buffer at least the given size. + * + * @returns Pointer to an error info structure on success, NULL on failure. + * + * @param cbMsg The minimum message buffer size. Use 0 to get + * the default buffer size. + */ +RTDECL(PRTERRINFO) RTErrInfoAlloc(size_t cbMsg); + +/** + * Same as RTErrInfoAlloc, except that an IPRT status code is returned. + * + * @returns IPRT status code. + * + * @param cbMsg The minimum message buffer size. Use 0 to get + * the default buffer size. + * @param ppErrInfo Where to store the pointer to the allocated + * error info structure on success. This is + * always set to NULL. + */ +RTDECL(int) RTErrInfoAllocEx(size_t cbMsg, PRTERRINFO *ppErrInfo); + +/** + * Frees an error info structure allocated by RTErrInfoAlloc or + * RTErrInfoAllocEx. + * + * @param pErrInfo The error info structure. + */ +RTDECL(void) RTErrInfoFree(PRTERRINFO pErrInfo); + +/** + * Fills in the error info details. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszMsg The error message string. + */ +RTDECL(int) RTErrInfoSet(PRTERRINFO pErrInfo, int rc, const char *pszMsg); + +/** + * Fills in the error info details, with a sprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszFormat The format string. + * @param ... The format arguments. + */ +RTDECL(int) RTErrInfoSetF(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Fills in the error info details, with a vsprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszFormat The format string. + * @param va The format arguments. + */ +RTDECL(int) RTErrInfoSetV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Adds more error info details. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszMsg The error message string to add. + */ +RTDECL(int) RTErrInfoAdd(PRTERRINFO pErrInfo, int rc, const char *pszMsg); + +/** + * Adds more error info details, with a sprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszFormat The format string to add. + * @param ... The format arguments. + */ +RTDECL(int) RTErrInfoAddF(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Adds more error info details, with a vsprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszFormat The format string to add. + * @param va The format arguments. + */ +RTDECL(int) RTErrInfoAddV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** @name RTERRINFO_LOG_F_XXX + * @{ */ +/** Both debug and release log. */ +#define RTERRINFO_LOG_F_RELEASE RT_BIT_32(0) +/** @} */ + +/** + * Fills in the error info details. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszMsg The error message string. + */ +RTDECL(int) RTErrInfoLogAndSet(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszMsg); + +/** + * Fills in the error info details, with a sprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszFormat The format string. + * @param ... The format arguments. + */ +RTDECL(int) RTErrInfoLogAndSetF(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Fills in the error info details, with a vsprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszFormat The format string. + * @param va The format arguments. + */ +RTDECL(int) RTErrInfoLogAndSetV(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * Adds more error info details. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszMsg The error message string to add. + */ +RTDECL(int) RTErrInfoLogAndAdd(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszMsg); + +/** + * Adds more error info details, with a sprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszFormat The format string to add. + * @param ... The format arguments. + */ +RTDECL(int) RTErrInfoLogAndAddF(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Adds more error info details, with a vsprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszFormat The format string to add. + * @param va The format arguments. + */ +RTDECL(int) RTErrInfoLogAndAddV(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + +/** @name Macros wrapping the RTErrInfoLog* functions. + * @{ */ +#ifndef LOG_DISABLED +# define RTERRINFO_LOG_SET( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoLogAndSet( a_pErrInfo, a_rc, LOG_GROUP, 0, a_pszMsg) +# define RTERRINFO_LOG_SET_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoLogAndSetV(a_pErrInfo, a_rc, LOG_GROUP, 0, a_pszMsg, a_va) +# define RTERRINFO_LOG_ADD( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoLogAndAdd( a_pErrInfo, a_rc, LOG_GROUP, 0, a_pszMsg) +# define RTERRINFO_LOG_ADD_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoLogAndAddV(a_pErrInfo, a_rc, LOG_GROUP, 0, a_pszMsg, a_va) +# ifdef RT_COMPILER_SUPPORTS_VA_ARGS +# define RTERRINFO_LOG_ADD_F(a_pErrInfo, a_rc, ...) RTErrInfoLogAndAddF(a_pErrInfo, a_rc, LOG_GROUP, 0, __VA_ARGS__) +# define RTERRINFO_LOG_SET_F(a_pErrInfo, a_rc, ...) RTErrInfoLogAndSetF(a_pErrInfo, a_rc, LOG_GROUP, 0, __VA_ARGS__) +# else +# define RTERRINFO_LOG_ADD_F RTErrInfoAddF +# define RTERRINFO_LOG_SET_F RTErrInfoSetF +# endif +#else +# define RTERRINFO_LOG_SET( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoSet( a_pErrInfo, a_rc, a_pszMsg) +# define RTERRINFO_LOG_SET_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoSetV(a_pErrInfo, a_rc, a_pszMsg, a_va) +# define RTERRINFO_LOG_ADD( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoAdd( a_pErrInfo, a_rc, a_pszMsg) +# define RTERRINFO_LOG_ADD_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoAddV(a_pErrInfo, a_rc, a_pszMsg, a_va) +# define RTERRINFO_LOG_ADD_F RTErrInfoAddF +# define RTERRINFO_LOG_SET_F RTErrInfoSetF +#endif + +#define RTERRINFO_LOG_REL_SET( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoLogAndSet( a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, a_pszMsg) +#define RTERRINFO_LOG_REL_SET_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoLogAndSetV(a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, a_pszMsg, a_va) +#define RTERRINFO_LOG_REL_ADD( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoLogAndAdd( a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, a_pszMsg) +#define RTERRINFO_LOG_REL_ADD_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoLogAndAddV(a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, a_pszMsg, a_va) +#ifdef RT_COMPILER_SUPPORTS_VA_ARGS +# define RTERRINFO_LOG_REL_ADD_F(a_pErrInfo, a_rc, ...) RTErrInfoLogAndAddF(a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, __VA_ARGS__) +# define RTERRINFO_LOG_REL_SET_F(a_pErrInfo, a_rc, ...) RTErrInfoLogAndSetF(a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, __VA_ARGS__) +#else +# define RTERRINFO_LOG_REL_ADD_F RTErrInfoAddF +# define RTERRINFO_LOG_REL_SET_F RTErrInfoSetF +#endif +/** @} */ + + +/** + * Checks if the error info is set. + * + * @returns true if set, false if not. + * @param pErrInfo The error info structure. NULL is OK. + */ +DECLINLINE(bool) RTErrInfoIsSet(PCRTERRINFO pErrInfo) +{ + if (!pErrInfo) + return false; + return (pErrInfo->fFlags & (RTERRINFO_FLAGS_MAGIC_MASK | RTERRINFO_FLAGS_SET)) + == (RTERRINFO_FLAGS_MAGIC | RTERRINFO_FLAGS_SET); +} + +/** + * Clears the error info structure. + * + * @param pErrInfo The error info structure. NULL is OK. + */ +DECLINLINE(void) RTErrInfoClear(PRTERRINFO pErrInfo) +{ + if (pErrInfo) + { + pErrInfo->fFlags &= ~RTERRINFO_FLAGS_SET; + pErrInfo->rc = /*VINF_SUCCESS*/0; + *pErrInfo->pszMsg = '\0'; + } +} + +/** + * Storage for error variables. + * + * @remarks Do NOT touch the members! They are platform specific and what's + * where may change at any time! + */ +typedef union RTERRVARS +{ + int8_t ai8Vars[32]; + int16_t ai16Vars[16]; + int32_t ai32Vars[8]; + int64_t ai64Vars[4]; +} RTERRVARS; +/** Pointer to an error variable storage union. */ +typedef RTERRVARS *PRTERRVARS; +/** Pointer to a const error variable storage union. */ +typedef RTERRVARS const *PCRTERRVARS; + +/** + * Saves the error variables. + * + * @returns @a pVars. + * @param pVars The variable storage union. + */ +RTDECL(PRTERRVARS) RTErrVarsSave(PRTERRVARS pVars); + +/** + * Restores the error variables. + * + * @param pVars The variable storage union. + */ +RTDECL(void) RTErrVarsRestore(PCRTERRVARS pVars); + +/** + * Checks if the first variable set equals the second. + * + * @returns true if they are equal, false if not. + * @param pVars1 The first variable storage union. + * @param pVars2 The second variable storage union. + */ +RTDECL(bool) RTErrVarsAreEqual(PCRTERRVARS pVars1, PCRTERRVARS pVars2); + +/** + * Checks if the (live) error variables have changed since we saved them. + * + * @returns @c true if they have changed, @c false if not. + * @param pVars The saved variables to compare the current state + * against. + */ +RTDECL(bool) RTErrVarsHaveChanged(PCRTERRVARS pVars); + +RT_C_DECLS_END + + +/* We duplicate a handful of very commonly used status codes from err.h here. + Needless to say, these needs to match the err.h definition exactly: */ + +/** Success. + * @ingroup grp_rt_err */ +#define VINF_SUCCESS 0 + +/** General failure - DON'T USE THIS!!! + * @ingroup grp_rt_err */ +#define VERR_GENERAL_FAILURE (-1) +/** Invalid parameter. + * @ingroup grp_rt_err */ +#define VERR_INVALID_PARAMETER (-2) +/** Invalid parameter. + * @ingroup grp_rt_err */ +#define VWRN_INVALID_PARAMETER 2 +/** Invalid magic or cookie. + * @ingroup grp_rt_err */ +#define VERR_INVALID_MAGIC (-3) +/** Invalid magic or cookie. + * @ingroup grp_rt_err */ +#define VWRN_INVALID_MAGIC 3 +/** Invalid loader handle. + * @ingroup grp_rt_err */ +#define VERR_INVALID_HANDLE (-4) +/** Invalid loader handle. + * @ingroup grp_rt_err */ +#define VWRN_INVALID_HANDLE 4 +/** Invalid memory pointer. */ +#define VERR_INVALID_POINTER (-6) +/** Memory allocation failed. + * @ingroup grp_rt_err */ +#define VERR_NO_MEMORY (-8) +/** Permission denied. + * @ingroup grp_rt_err */ +#define VERR_PERMISSION_DENIED (-10) +/** Permission denied. + * @ingroup grp_rt_err */ +#define VINF_PERMISSION_DENIED 10 +/** Version mismatch. + * @ingroup grp_rt_err */ +#define VERR_VERSION_MISMATCH (-11) +/** The request function is not implemented. + * @ingroup grp_rt_err */ +#define VERR_NOT_IMPLEMENTED (-12) +/** Invalid flags was given. + * @ingroup grp_rt_err */ +#define VERR_INVALID_FLAGS (-13) +/** Incorrect call order. + * @ingroup grp_rt_err */ +#define VERR_WRONG_ORDER (-22) +/** Invalid function. + * @ingroup grp_rt_err */ +#define VERR_INVALID_FUNCTION (-36) +/** Not supported. + * @ingroup grp_rt_err */ +#define VERR_NOT_SUPPORTED (-37) +/** Not supported. + * @ingroup grp_rt_err */ +#define VINF_NOT_SUPPORTED 37 +/** Access denied. + * @ingroup grp_rt_err */ +#define VERR_ACCESS_DENIED (-38) +/** Call interrupted. + * @ingroup grp_rt_err */ +#define VERR_INTERRUPTED (-39) +/** Call interrupted. + * @ingroup grp_rt_err */ +#define VINF_INTERRUPTED 39 +/** Timeout. + * @ingroup grp_rt_err */ +#define VERR_TIMEOUT (-40) +/** Timeout. + * @ingroup grp_rt_err */ +#define VINF_TIMEOUT 40 +/** Buffer too small to save result. + * @ingroup grp_rt_err */ +#define VERR_BUFFER_OVERFLOW (-41) +/** Buffer too small to save result. + * @ingroup grp_rt_err */ +#define VINF_BUFFER_OVERFLOW 41 +/** Data size overflow. + * @ingroup grp_rt_err */ +#define VERR_TOO_MUCH_DATA (-42) +/** Retry the operation. + * @ingroup grp_rt_err */ +#define VERR_TRY_AGAIN (-52) +/** Retry the operation. + * @ingroup grp_rt_err */ +#define VINF_TRY_AGAIN 52 +/** Generic parse error. + * @ingroup grp_rt_err */ +#define VERR_PARSE_ERROR (-53) +/** Value out of range. + * @ingroup grp_rt_err */ +#define VERR_OUT_OF_RANGE (-54) +/** A numeric conversion encountered a value which was too big for the target. + * @ingroup grp_rt_err */ +#define VERR_NUMBER_TOO_BIG (-55) +/** A numeric conversion encountered a value which was too big for the target. + * @ingroup grp_rt_err */ +#define VWRN_NUMBER_TOO_BIG 55 +/** The operation was cancelled by the user (copy) or another thread (local ipc). + * @ingroup grp_rt_err */ +#define VERR_CANCELLED (-70) +/** Trailing characters. + * @ingroup grp_rt_err */ +#define VERR_TRAILING_CHARS (-76) +/** Trailing characters. + * @ingroup grp_rt_err */ +#define VWRN_TRAILING_CHARS 76 +/** Trailing spaces. + * @ingroup grp_rt_err */ +#define VERR_TRAILING_SPACES (-77) +/** Trailing spaces. + * @ingroup grp_rt_err */ +#define VWRN_TRAILING_SPACES 77 +/** Generic not found error. + * @ingroup grp_rt_err */ +#define VERR_NOT_FOUND (-78) +/** Generic not found warning. + * @ingroup grp_rt_err */ +#define VWRN_NOT_FOUND 78 +/** Generic invalid state error. + * @ingroup grp_rt_err */ +#define VERR_INVALID_STATE (-79) +/** Generic invalid state warning. + * @ingroup grp_rt_err */ +#define VWRN_INVALID_STATE 79 +/** Generic out of resources error. + * @ingroup grp_rt_err */ +#define VERR_OUT_OF_RESOURCES (-80) +/** Generic out of resources warning. + * @ingroup grp_rt_err */ +#define VWRN_OUT_OF_RESOURCES 80 +/** End of string. + * @ingroup grp_rt_err */ +#define VERR_END_OF_STRING (-83) +/** Return instigated by a callback or similar. + * @ingroup grp_rt_err */ +#define VERR_CALLBACK_RETURN (-88) +/** Return instigated by a callback or similar. + * @ingroup grp_rt_err */ +#define VINF_CALLBACK_RETURN 88 +/** Duplicate something. + * @ingroup grp_rt_err */ +#define VERR_DUPLICATE (-98) +/** Something is missing. + * @ingroup grp_rt_err */ +#define VERR_MISSING (-99) +/** Buffer underflow. + * @ingroup grp_rt_err */ +#define VERR_BUFFER_UNDERFLOW (-22401) +/** Buffer underflow. + * @ingroup grp_rt_err */ +#define VINF_BUFFER_UNDERFLOW 22401 +/** Something is not available or not working properly. + * @ingroup grp_rt_err */ +#define VERR_NOT_AVAILABLE (-22403) +/** Mismatch. + * @ingroup grp_rt_err */ +#define VERR_MISMATCH (-22408) +/** Wrong type. + * @ingroup grp_rt_err */ +#define VERR_WRONG_TYPE (-22409) +/** Wrong type. + * @ingroup grp_rt_err */ +#define VWRN_WRONG_TYPE (22409) +/** Wrong parameter count. + * @ingroup grp_rt_err */ +#define VERR_WRONG_PARAMETER_COUNT (-22415) +/** Wrong parameter type. + * @ingroup grp_rt_err */ +#define VERR_WRONG_PARAMETER_TYPE (-22416) +/** Invalid client ID. + * @ingroup grp_rt_err */ +#define VERR_INVALID_CLIENT_ID (-22417) +/** Invalid session ID. + * @ingroup grp_rt_err */ +#define VERR_INVALID_SESSION_ID (-22418) +/** Incompatible configuration requested. + * @ingroup grp_rt_err */ +#define VERR_INCOMPATIBLE_CONFIG (-22420) +/** Internal error - this should never happen. + * @ingroup grp_rt_err */ +#define VERR_INTERNAL_ERROR (-225) +/** RTGetOpt: Not an option. + * @ingroup grp_rt_err */ +#define VINF_GETOPT_NOT_OPTION 828 +/** RTGetOpt: Command line option not recognized. + * @ingroup grp_rt_err */ +#define VERR_GETOPT_UNKNOWN_OPTION (-825) + +/** @} */ + +#endif /* !IPRT_INCLUDED_errcore_h */ + diff --git a/include/iprt/errno.h b/include/iprt/errno.h new file mode 100644 index 00000000..f41e677b --- /dev/null +++ b/include/iprt/errno.h @@ -0,0 +1,441 @@ +/** @file + * IPRT - errno.h wrapper. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_errno_h +#define IPRT_INCLUDED_errno_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef IPRT_NO_CRT +# if defined(RT_OS_DARWIN) && defined(KERNEL) +# include +# elif defined(RT_OS_LINUX) && defined(__KERNEL__) +# include +# elif defined(RT_OS_FREEBSD) && defined(_KERNEL) +# include +# elif defined(RT_OS_NETBSD) && defined(_KERNEL) +# include +# else +# include +# endif +#endif + + +/* + * Supply missing errno values according to the current RT_OS_XXX definition. + * + * Note! These supplements are for making no-CRT mode, as well as making UNIXy + * code that makes used of odd errno defines internally, work smoothly. + * + * When adding more error codes, always check the following errno.h sources: + * - RT_OS_DARWIN: http://fxr.watson.org/fxr/source/bsd/sys/errno.h?v=xnu-1699.24.8 + * - RT_OS_FREEBSD: http://fxr.watson.org/fxr/source/sys/errno.h?v=DFBSD + * - RT_OS_NETBSD: http://fxr.watson.org/fxr/source/sys/errno.h?v=NETBSD + * - RT_OS_OPENBSD: http://fxr.watson.org/fxr/source/sys/errno.h?v=OPENBSD + * - RT_OS_OS2: http://svn.netlabs.org/libc/browser/trunk/libc/include/sys/errno.h + * - RT_OS_LINUX: http://fxr.watson.org/fxr/source/include/asm-generic/errno.h?v=linux-2.6 + * - RT_OS_SOLARIS: http://fxr.watson.org/fxr/source/common/sys/errno.h?v=OPENSOLARIS + * - RT_OS_WINDOWS: tools/win.x86/vcc/v8sp1/include/errno.h + */ + +#if defined(RT_OS_DARWIN) \ + || defined(RT_OS_FREEBSD) \ + || defined(RT_OS_NETBSD) \ + || defined(RT_OS_OPENBSD) \ + || defined(RT_OS_OS2) +# define RT_ERRNO_OS_BSD +#endif +#ifdef RT_OS_SOLARIS +# define RT_ERRNO_OS_SYSV_HARDCORE /* ?? */ +#endif + +/* The relatively similar part. */ +#ifndef EPERM +# define EPERM (1) +#endif +#ifndef ENOENT +# define ENOENT (2) +#endif +#ifndef ESRCH +# define ESRCH (3) +#endif +#ifndef EINTR +# define EINTR (4) +#endif +#ifndef EIO +# define EIO (5) +#endif +#ifndef ENXIO +# define ENXIO (6) +#endif +#ifndef E2BIG +# define E2BIG (7) +#endif +#ifndef ENOEXEC +# define ENOEXEC (8) +#endif +#ifndef EBADF +# define EBADF (9) +#endif +#ifndef ECHILD +# define ECHILD (10) +#endif +#ifndef EAGAIN +# if defined(RT_ERRNO_OS_BSD) +# define EAGAIN (35) +# else +# define EAGAIN (11) +# endif +#endif +#ifndef EWOULDBLOCK +# define EWOULDBLOCK EAGAIN +#endif +#ifndef EDEADLK +# if defined(RT_ERRNO_OS_BSD) +# define EDEADLK (11) +# elif defined(RT_OS_LINUX) +# define EDEADLK (35) +# elif defined(RT_OS_WINDOWS) +# define EDEADLK (36) +# else +# define EDEADLK (45) /* solaris */ +# endif +#endif +#ifndef EDEADLOCK +# define EDEADLOCK EDEADLK +#endif +#ifndef ENOMEM +# define ENOMEM (12) +#endif +#ifndef EACCES +# define EACCES (13) +#endif +#ifndef EFAULT +# define EFAULT (14) +#endif +#ifndef ENOTBLK +# define ENOTBLK (15) +#endif +#ifndef EBUSY +# define EBUSY (16) +#endif +#ifndef EEXIST +# define EEXIST (17) +#endif +#ifndef EXDEV +# define EXDEV (18) +#endif +#ifndef ENODEV +# define ENODEV (19) +#endif +#ifndef ENOTDIR +# define ENOTDIR (20) +#endif +#ifndef EISDIR +# define EISDIR (21) +#endif +#ifndef EINVAL +# define EINVAL (22) +#endif +#ifndef ENFILE +# define ENFILE (23) +#endif +#ifndef EMFILE +# define EMFILE (24) +#endif +#ifndef ENOTTY +# define ENOTTY (25) +#endif +#ifndef ETXTBSY +# define ETXTBSY (26) +#endif +#ifndef EFBIG +# define EFBIG (27) +#endif +#ifndef ENOSPC +# define ENOSPC (28) +#endif +#ifndef ESPIPE +# define ESPIPE (29) +#endif +#ifndef EROFS +# define EROFS (30) +#endif +#ifndef EMLINK +# define EMLINK (31) +#endif +#ifndef EPIPE +# define EPIPE (32) +#endif +#ifndef EDOM +# define EDOM (33) +#endif +#ifndef ERANGE +# define ERANGE (34) +#endif + +/* 35 - also EAGAIN on BSD and EDEADLK on Linux. */ +#ifndef ENOMSG +# if defined(RT_OS_DARWIN) +# define ENOMSG (91) +# elif defined(RT_OS_FREEBSD) +# define ENOMSG (83) +# elif defined(RT_OS_LINUX) +# define ENOMSG (42) +# elif defined(RT_OS_WINDOWS) +# define ENOMSG (122) +# else +# define ENOMSG (35) +# endif +#endif + +/* 36 - Also EDEADLK on Windows. */ +#ifndef EIDRM +# if defined(RT_OS_DARWIN) +# define EIDRM (90) +# elif defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) +# define EIDRM (82) +# elif defined(RT_OS_OPENBSD) +# define EIDRM (89) +# elif defined(RT_OS_LINUX) +# define EIDRM (43) +# elif defined(RT_OS_WINDOWS) +# define EIDRM (111) +# else +# define EIDRM (36) +# endif +#endif +#ifndef EINPROGRESS +# if defined(RT_ERRNO_OS_BSD) +# define EINPROGRESS (36) +# elif defined(RT_OS_LINUX) +# define EINPROGRESS (115) +# elif defined(RT_OS_WINDOWS) +# define EINPROGRESS (112) +# else +# define EINPROGRESS (150) /* solaris */ +# endif +#endif +#ifndef ENAMETOOLONG +# if defined(RT_ERRNO_OS_BSD) +# define ENAMETOOLONG (63) +# elif defined(RT_OS_LINUX) +# define ENAMETOOLONG (36) +# elif defined(RT_OS_WINDOWS) +# define ENAMETOOLONG (38) +# else +# define ENAMETOOLONG (78) /* solaris */ +# endif +#endif + +/* 37 */ +#ifndef ECHRNG +# if defined(RT_ERRNO_OS_SYSV_HARDCORE) +# define ECHRNG (37) +# else +# define ECHRNG (599) +# endif +#endif +#ifndef ENOLCK +# if defined(RT_ERRNO_OS_BSD) +# define ENOLCK (77) +# elif defined(RT_OS_LINUX) +# define ENOLCK (37) +# elif defined(RT_OS_WINDOWS) +# define ENOLCK (39) +# else +# define ENOLCK (46) +# endif +#endif +#ifndef EALREADY +# if defined(RT_ERRNO_OS_BSD) +# define EALREADY (37) +# elif defined(RT_OS_LINUX) +# define EALREADY (114) +# elif defined(RT_OS_WINDOWS) +# define EALREADY (103) +# else +# define EALREADY (149) +# endif +#endif + +/* 38 - Also ENAMETOOLONG on Windows. */ +#ifndef ENOSYS +# if defined(RT_ERRNO_OS_BSD) +# define ENOSYS (78) +# elif defined(RT_OS_LINUX) +# define ENOSYS (38) +# elif defined(RT_OS_WINDOWS) +# define ENOSYS (40) +# else +# define ENOSYS (89) /* solaris */ +# endif +#endif +#ifndef ENOTSOCK +# if defined(RT_ERRNO_OS_BSD) +# define ENOTSOCK (38) +# elif defined(RT_OS_LINUX) +# define ENOTSOCK (88) +# elif defined(RT_OS_WINDOWS) +# define ENOTSOCK (128) +# else +# define ENOTSOCK (95) /* solaris */ +# endif +#endif +#ifndef EL2NSYNC +# if defined(RT_OS_LINUX) +# define EL2NSYNC (45) +# elif defined(RT_ERRNO_OS_SYSV_HARDCORE) +# define EL2NSYNC (38) /* solaris */ +# endif +#endif + +/* 39 - Also ENOLCK on Windows. */ +#ifndef ENOTEMPTY +# if defined(RT_ERRNO_OS_BSD) +# define ENOTEMPTY (66) +# elif defined(RT_OS_LINUX) +# define ENOTEMPTY (39) +# elif defined(RT_OS_WINDOWS) +# define ENOTEMPTY (41) +# else +# define ENOTEMPTY (93) /* solaris */ +# endif +#endif +#ifndef EDESTADDRREQ +# if defined(RT_ERRNO_OS_BSD) +# define EDESTADDRREQ (39) +# elif defined(RT_OS_LINUX) +# define EDESTADDRREQ (89) +# elif defined(RT_OS_WINDOWS) +# define EDESTADDRREQ (109) +# else +# define EDESTADDRREQ (96) /* solaris */ +# endif +#endif +#ifndef EL3HLT +# if defined(RT_OS_LINUX) +# define EL3HLT (46) +# elif defined(RT_ERRNO_OS_SYSV_HARDCORE) +# define EL3HLT (39) /* solaris */ +# endif +#endif + +/* 40 - Also ENOSYS on Windows. */ +#ifndef ELOOP +# if defined(RT_ERRNO_OS_BSD) +# define ELOOP (62) +# elif defined(RT_OS_LINUX) +# define ELOOP (40) +# elif defined(RT_OS_WINDOWS) +# define ELOOP (114) +# else +# define ELOOP (90) /* solaris */ +# endif +#endif +#ifndef EMSGSIZE +# if defined(RT_ERRNO_OS_BSD) +# define EMSGSIZE (40) +# elif defined(RT_OS_LINUX) +# define EMSGSIZE (90) +# elif defined(RT_OS_WINDOWS) +# define EMSGSIZE (115) +# else +# define EMSGSIZE (97) /* solaris */ +# endif +#endif +#ifndef EL3RST +# if defined(RT_OS_LINUX) +# define EL3RST (47) +# elif defined(RT_ERRNO_OS_SYSV_HARDCORE) +# define EL3RST (40) /* solaris */ +# endif +#endif + +/** @todo errno constants {41..44}. */ + +/* 45 - also EDEADLK on Solaris, EL2NSYNC on Linux. */ +#ifndef ENOTSUP +# if defined(RT_ERRNO_OS_BSD) +# define ENOTSUP (45) +# elif defined(RT_OS_LINUX) +# define ENOTSUP (95) +# elif defined(RT_OS_WINDOWS) +# define ENOTSUP (129) +# else +# define ENOTSUP (48) +# endif +#endif +#ifndef EOPNOTSUPP +# if defined(RT_ERRNO_OS_BSD) +# define EOPNOTSUPP ENOTSUP +# elif defined(RT_OS_LINUX) +# define EOPNOTSUPP ENOTSUP +# elif defined(RT_OS_WINDOWS) +# define EOPNOTSUPP (130) +# else +# define EOPNOTSUPP (122) +# endif +#endif + +/** @todo errno constants {46..74}. */ + +/* 75 - note that Solaris has constant with value 75. */ +#ifndef EOVERFLOW +# if defined(RT_OS_OPENBSD) +# define EOVERFLOW (87) +# elif defined(RT_ERRNO_OS_BSD) +# define EOVERFLOW (84) +# elif defined(RT_OS_LINUX) +# define EOVERFLOW (75) +# elif defined(RT_OS_WINDOWS) +# define EOVERFLOW (132) +# else +# define EOVERFLOW (79) +# endif +#endif +#ifndef EPROGMISMATCH +# if defined(RT_ERRNO_OS_BSD) +# define EPROGMISMATCH (75) +# else +# define EPROGMISMATCH (598) +# endif +#endif + +/** @todo errno constants {76..}. */ + + +#endif /* !IPRT_INCLUDED_errno_h */ diff --git a/include/iprt/expreval.h b/include/iprt/expreval.h new file mode 100644 index 00000000..0ec98a59 --- /dev/null +++ b/include/iprt/expreval.h @@ -0,0 +1,159 @@ +/* $Id: expreval.h $ */ +/** @file + * IPRT - Expression Evaluator. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_expreval_h +#define IPRT_INCLUDED_expreval_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_expr_eval RTExprEval - Expression Evaluator + * @{ */ + +/** Handle to an expression evaluator. */ +typedef struct RTEXPREVALINT *RTEXPREVAL; +/** Pointer to an expression evaluator handle. */ +typedef RTEXPREVAL *PRTEXPREVAL; +/** NIL expression evaluator handle. */ +#define NIL_RTEXPREVAL ((RTEXPREVAL)~(uintptr_t)0) + +/** + * Variable getter (supplied by user). + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the variable does not exist. + */ +typedef DECLCALLBACKTYPE(int, FNRTEXPREVALQUERYVARIABLE,(const char *pchName, size_t cchName, void *pvUser, char **ppszValue)); +/** Pointer to a variable getter. */ +typedef FNRTEXPREVALQUERYVARIABLE *PFNRTEXPREVALQUERYVARIABLE; + +/** @name Expression evaluator flags. + * @sa RTExprEvalCreate + * @{ */ +/** Default to hexadecimal instead of decimal numbers. */ +#define RTEXPREVAL_F_DEFAULT_BASE_16 RT_BIT_64(0) +/** Enables C-ish octal style, i.e. 0777 be read as 0x1ff (in hex). */ +#define RTEXPREVAL_F_C_OCTAL RT_BIT_64(1) +/** Enables the 'exists' operator that can be used to check if a path exists. + * @sa RTPathExists */ +#define RTEXPREVAL_F_EXISTS_OP RT_BIT_64(2) +/** Valid mask. */ +#define RTEXPREVAL_F_VALID_MASK UINT64_MAX(3) +/** @} */ + +/** + * Creates an expression evaluator. + * + * @returns IPRT status code. + * @param phEval Where to return the handle to the evaluator. + * @param fFlags RTEXPREVAL_F_XXX. + * @param pszName The evaluator name (for logging). + * @param pvUser User argument for callbacks. + * @param pfnQueryVariable Callback for querying variables. Optional. + */ +RTDECL(int) RTExprEvalCreate(PRTEXPREVAL phEval, uint64_t fFlags, const char *pszName, + void *pvUser, PFNRTEXPREVALQUERYVARIABLE pfnQueryVariable); + +/** + * Retains a reference to the evaluator. + * + * @returns New reference count, UINT32_MAX if @a hEval is not valid. + * @param hEval Handle to the evaluator. + */ +RTDECL(uint32_t) RTExprEvalRetain(RTEXPREVAL hEval); + +/** + * Releases a reference to the evaluator. + * + * @returns New reference count, UINT32_MAX if @a hEval is not valid. (The + * evaluator was destroyed when 0 is returned.) + * @param hEval Handle to the evaluator. + */ +RTDECL(uint32_t) RTExprEvalRelease(RTEXPREVAL hEval); + +/** + * Evaluates the given if expression to a boolean result. + * + * @returns IPRT status code + * @param hEval Handle to the evaluator. + * @param pch The expression string. Does not need to be zero + * terminated. + * @param cch The length of the expression. Pass RTSTR_MAX if not + * known. + * @param pfResult Where to return the result. + * @param pErrInfo Where to return additional error info. + */ +RTDECL(int) RTExprEvalToBool(RTEXPREVAL hEval, const char *pch, size_t cch, bool *pfResult, PRTERRINFO pErrInfo); + +/** + * Evaluates the given if expression to an integer (signed 64-bit) result. + * + * @returns IPRT status code + * @param hEval Handle to the evaluator. + * @param pch The expression string. Does not need to be zero + * terminated. + * @param cch The length of the expression. Pass RTSTR_MAX if not + * known. + * @param piResult Where to return the result. + * @param pErrInfo Where to return additional error info. + */ +RTDECL(int) RTExprEvalToInteger(RTEXPREVAL hEval, const char *pch, size_t cch, int64_t *piResult, PRTERRINFO pErrInfo); + +/** + * Evaluates the given if expression to a string result. + * + * @returns IPRT status code + * @param hEval Handle to the evaluator. + * @param pch The expression string. Does not need to be zero + * terminated. + * @param cch The length of the expression. Pass RTSTR_MAX if not + * known. + * @param ppszResult Where to return the result. This must be freed using + * RTStrFree. + * @param pErrInfo Where to return additional error info. + */ +RTDECL(int) RTExprEvalToString(RTEXPREVAL hEval, const char *pch, size_t cch, char **ppszResult, PRTERRINFO pErrInfo); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_expreval_h */ + diff --git a/include/iprt/file.h b/include/iprt/file.h new file mode 100644 index 00000000..6b36bfae --- /dev/null +++ b/include/iprt/file.h @@ -0,0 +1,1826 @@ +/** @file + * IPRT - File I/O. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_file_h +#define IPRT_INCLUDED_file_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fileio RTFile - File I/O + * @ingroup grp_rt + * @{ + */ + +/** Platform specific text line break. + * @deprecated Use text I/O streams and '\\n'. See iprt/stream.h. */ +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# define RTFILE_LINEFEED "\r\n" +#else +# define RTFILE_LINEFEED "\n" +#endif + +/** Platform specific native standard input "handle". */ +#ifdef RT_OS_WINDOWS +# define RTFILE_NATIVE_STDIN ((uint32_t)-10) +#else +# define RTFILE_NATIVE_STDIN 0 +#endif + +/** Platform specific native standard out "handle". */ +#ifdef RT_OS_WINDOWS +# define RTFILE_NATIVE_STDOUT ((uint32_t)-11) +#else +# define RTFILE_NATIVE_STDOUT 1 +#endif + +/** Platform specific native standard error "handle". */ +#ifdef RT_OS_WINDOWS +# define RTFILE_NATIVE_STDERR ((uint32_t)-12) +#else +# define RTFILE_NATIVE_STDERR 2 +#endif + + +/** + * Checks if the specified file name exists and is a regular file. + * + * Symbolic links will be resolved. + * + * @returns true if it's a regular file, false if it isn't. + * @param pszPath The path to the file. + * + * @sa RTDirExists, RTPathExists, RTSymlinkExists. + */ +RTDECL(bool) RTFileExists(const char *pszPath); + +/** + * Queries the size of a file, given the path to it. + * + * Symbolic links will be resolved. + * + * @returns IPRT status code. + * @param pszPath The path to the file. + * @param pcbFile Where to return the file size (bytes). + * + * @sa RTFileQuerySize, RTPathQueryInfoEx. + */ +RTDECL(int) RTFileQuerySizeByPath(const char *pszPath, uint64_t *pcbFile); + + +/** @name Open flags + * @{ */ +/** Attribute access only. + * @remarks Only accepted on windows, requires RTFILE_O_ACCESS_ATTR_MASK + * to yield a non-zero result. Otherwise, this is invalid. */ +#define RTFILE_O_ATTR_ONLY UINT32_C(0x00000000) +/** Open the file with read access. */ +#define RTFILE_O_READ UINT32_C(0x00000001) +/** Open the file with write access. */ +#define RTFILE_O_WRITE UINT32_C(0x00000002) +/** Open the file with read & write access. */ +#define RTFILE_O_READWRITE UINT32_C(0x00000003) +/** The file access mask. + * @remarks The value 0 is invalid, except for windows special case. */ +#define RTFILE_O_ACCESS_MASK UINT32_C(0x00000003) + +/** Open file in APPEND mode, so all writes to the file handle will + * append data at the end of the file. + * @remarks It is ignored if write access is not requested, that is + * RTFILE_O_WRITE is not set. + * @note Behaviour of functions differ between hosts: See RTFileWriteAt, as + * well as ticketref:19003 (RTFileSetSize). */ +#define RTFILE_O_APPEND UINT32_C(0x00000004) + /* UINT32_C(0x00000008) is unused atm. */ + +/** Sharing mode: deny none. */ +#define RTFILE_O_DENY_NONE UINT32_C(0x00000080) +/** Sharing mode: deny read. */ +#define RTFILE_O_DENY_READ UINT32_C(0x00000010) +/** Sharing mode: deny write. */ +#define RTFILE_O_DENY_WRITE UINT32_C(0x00000020) +/** Sharing mode: deny read and write. */ +#define RTFILE_O_DENY_READWRITE UINT32_C(0x00000030) +/** Sharing mode: deny all. */ +#define RTFILE_O_DENY_ALL RTFILE_O_DENY_READWRITE +/** Sharing mode: do NOT deny delete (NT). + * @remarks This might not be implemented on all platforms, and will be + * defaulted & ignored on those. + */ +#define RTFILE_O_DENY_NOT_DELETE UINT32_C(0x00000040) +/** Sharing mode mask. */ +#define RTFILE_O_DENY_MASK UINT32_C(0x000000f0) + +/** Action: Open an existing file. */ +#define RTFILE_O_OPEN UINT32_C(0x00000700) +/** Action: Create a new file or open an existing one. */ +#define RTFILE_O_OPEN_CREATE UINT32_C(0x00000100) +/** Action: Create a new a file. */ +#define RTFILE_O_CREATE UINT32_C(0x00000200) +/** Action: Create a new file or replace an existing one. */ +#define RTFILE_O_CREATE_REPLACE UINT32_C(0x00000300) +/** Action mask. */ +#define RTFILE_O_ACTION_MASK UINT32_C(0x00000700) + +/** Turns off indexing of files on Windows hosts, *CREATE* only. + * @remarks Window only. */ +#define RTFILE_O_NOT_CONTENT_INDEXED UINT32_C(0x00000800) +/** Truncate the file. + * @remarks This will not truncate files opened for read-only. + * @remarks The truncation doesn't have to be atomically, so anyone else opening + * the file may be racing us. The caller is responsible for not causing + * this race. */ +#define RTFILE_O_TRUNCATE UINT32_C(0x00001000) +/** Make the handle inheritable on RTProcessCreate(/exec). */ +#define RTFILE_O_INHERIT UINT32_C(0x00002000) +/** Open file in non-blocking mode - non-portable. + * @remarks This flag may not be supported on all platforms, in which case it's + * considered an invalid parameter. */ +#define RTFILE_O_NON_BLOCK UINT32_C(0x00004000) +/** Write through directly to disk. Workaround to avoid iSCSI + * initiator deadlocks on Windows hosts. + * @remarks This might not be implemented on all platforms, and will be ignored + * on those. */ +#define RTFILE_O_WRITE_THROUGH UINT32_C(0x00008000) + +/** Attribute access: Attributes can be read if the file is being opened with + * read access, and can be written with write access. */ +#define RTFILE_O_ACCESS_ATTR_DEFAULT UINT32_C(0x00000000) +/** Attribute access: Attributes can be read. + * @remarks Windows only. */ +#define RTFILE_O_ACCESS_ATTR_READ UINT32_C(0x00010000) +/** Attribute access: Attributes can be written. + * @remarks Windows only. */ +#define RTFILE_O_ACCESS_ATTR_WRITE UINT32_C(0x00020000) +/** Attribute access: Attributes can be both read & written. + * @remarks Windows only. */ +#define RTFILE_O_ACCESS_ATTR_READWRITE UINT32_C(0x00030000) +/** Attribute access: The file attributes access mask. + * @remarks Windows only. */ +#define RTFILE_O_ACCESS_ATTR_MASK UINT32_C(0x00030000) + +/** Open file for async I/O + * @remarks This flag may not be needed on all platforms, and will be ignored on + * those. */ +#define RTFILE_O_ASYNC_IO UINT32_C(0x00040000) + +/** Disables caching. + * + * Useful when using very big files which might bring the host I/O scheduler to + * its knees during high I/O load. + * + * @remarks This flag might impose restrictions + * on the buffer alignment, start offset and/or transfer size. + * + * On Linux the buffer needs to be aligned to the 512 sector + * boundary. + * + * On Windows the FILE_FLAG_NO_BUFFERING is used (see + * http://msdn.microsoft.com/en-us/library/cc644950(VS.85).aspx ). + * The buffer address, the transfer size and offset needs to be aligned + * to the sector size of the volume. Furthermore FILE_APPEND_DATA is + * disabled. To write beyond the size of file use RTFileSetSize prior + * writing the data to the file. + * + * This flag does not work on Solaris if the target filesystem is ZFS. + * RTFileOpen will return an error with that configuration. When used + * with UFS the same alginment restrictions apply like Linux and + * Windows. + * + * @remarks This might not be implemented on all platforms, and will be ignored + * on those. + */ +#define RTFILE_O_NO_CACHE UINT32_C(0x00080000) + +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTFILE_O_NO_SYMLINKS UINT32_C(0x20000000) + +/** Unix file mode mask for use when creating files. */ +#define RTFILE_O_CREATE_MODE_MASK UINT32_C(0x1ff00000) +/** The number of bits to shift to get the file mode mask. + * To extract it: (fFlags & RTFILE_O_CREATE_MODE_MASK) >> RTFILE_O_CREATE_MODE_SHIFT. + */ +#define RTFILE_O_CREATE_MODE_SHIFT 20 + +/** Temporary file that should be automatically deleted when closed. + * If not supported by the OS, the open call will fail with VERR_NOT_SUPPORTED + * to prevent leaving undeleted files behind. + * @note On unix the file wont be visible and cannot be accessed by it's path. + * On Windows it will be visible but only accessible of deletion is + * shared. Not implemented on OS/2. */ +#define RTFILE_O_TEMP_AUTO_DELETE UINT32_C(0x40000000) + + /* UINT32_C(0x80000000) is unused atm. */ + +/** Mask of all valid flags. + * @remark This doesn't validate the access mode properly. + */ +#define RTFILE_O_VALID_MASK UINT32_C(0x7ffffff7) + +/** @} */ + + +/** Action taken by RTFileOpenEx. */ +typedef enum RTFILEACTION +{ + /** Invalid zero value. */ + RTFILEACTION_INVALID = 0, + /** Existing file was opened (returned by RTFILE_O_OPEN and + * RTFILE_O_OPEN_CREATE). */ + RTFILEACTION_OPENED, + /** New file was created (returned by RTFILE_O_CREATE and + * RTFILE_O_OPEN_CREATE). */ + RTFILEACTION_CREATED, + /** Existing file was replaced (returned by RTFILE_O_CREATE_REPLACE). */ + RTFILEACTION_REPLACED, + /** Existing file was truncated (returned if RTFILE_O_TRUNCATE take effect). */ + RTFILEACTION_TRUNCATED, + /** The file already exists (returned by RTFILE_O_CREATE on failure). */ + RTFILEACTION_ALREADY_EXISTS, + /** End of valid values. */ + RTFILEACTION_END, + /** Type size hack. */ + RTFILEACTION_32BIT_HACK = 0x7fffffff +} RTFILEACTION; +/** Pointer to action taken value (RTFileOpenEx). */ +typedef RTFILEACTION *PRTFILEACTION; + + +#ifdef IN_RING3 +/** + * Force the use of open flags for all files opened after the setting is + * changed. The caller is responsible for not causing races with RTFileOpen(). + * + * @returns iprt status code. + * @param fOpenForAccess Access mode to which the set/mask settings apply. + * @param fSet Open flags to be forced set. + * @param fMask Open flags to be masked out. + */ +RTR3DECL(int) RTFileSetForceFlags(unsigned fOpenForAccess, unsigned fSet, unsigned fMask); +#endif /* IN_RING3 */ + +/** + * Open a file. + * + * @returns iprt status code. + * @param pFile Where to store the handle to the opened file. + * @param pszFilename Path to the file which is to be opened. (UTF-8) + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + */ +RTDECL(int) RTFileOpen(PRTFILE pFile, const char *pszFilename, uint64_t fOpen); + +/** + * Open a file given as a format string. + * + * @returns iprt status code. + * @param pFile Where to store the handle to the opened file. + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + * @param pszFilenameFmt Format string givin the path to the file which is to + * be opened. (UTF-8) + * @param ... Arguments to the format string. + */ +RTDECL(int) RTFileOpenF(PRTFILE pFile, uint64_t fOpen, const char *pszFilenameFmt, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Open a file given as a format string. + * + * @returns iprt status code. + * @param pFile Where to store the handle to the opened file. + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + * @param pszFilenameFmt Format string givin the path to the file which is to + * be opened. (UTF-8) + * @param va Arguments to the format string. + */ +RTDECL(int) RTFileOpenV(PRTFILE pFile, uint64_t fOpen, const char *pszFilenameFmt, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Open a file, extended version. + * + * @returns iprt status code. + * @param pszFilename Path to the file which is to be opened. (UTF-8) + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + * @param phFile Where to store the handle to the opened file. + * @param penmActionTaken Where to return an indicator of which action was + * taken. This is optional and it is recommended to + * pass NULL when not strictly needed as it adds + * complexity (slower) on posix systems. + */ +RTDECL(int) RTFileOpenEx(const char *pszFilename, uint64_t fOpen, PRTFILE phFile, PRTFILEACTION penmActionTaken); + +/** + * Open the bit bucket (aka /dev/null or nul). + * + * @returns IPRT status code. + * @param phFile Where to store the handle to the opened file. + * @param fAccess The desired access only, i.e. read, write or both. + */ +RTDECL(int) RTFileOpenBitBucket(PRTFILE phFile, uint64_t fAccess); + +/** + * Duplicates a file handle. + * + * @returns IPRT status code. + * @param hFileSrc The handle to duplicate. + * @param fFlags RTFILE_O_INHERIT or zero. + * @param phFileNew Where to return the new file handle + */ +RTDECL(int) RTFileDup(RTFILE hFileSrc, uint64_t fFlags, PRTFILE phFileNew); + +/** + * Close a file opened by RTFileOpen(). + * + * @returns iprt status code. + * @param File The file handle to close. + */ +RTDECL(int) RTFileClose(RTFILE File); + +/** + * Creates an IPRT file handle from a native one. + * + * @returns IPRT status code. + * @param pFile Where to store the IPRT file handle. + * @param uNative The native handle. + */ +RTDECL(int) RTFileFromNative(PRTFILE pFile, RTHCINTPTR uNative); + +/** + * Gets the native handle for an IPRT file handle. + * + * @return The native handle. + * @param File The IPRT file handle. + */ +RTDECL(RTHCINTPTR) RTFileToNative(RTFILE File); + +/** + * Delete a file. + * + * @returns iprt status code. + * @param pszFilename Path to the file which is to be deleted. (UTF-8) + * @todo This is a RTPath api! + */ +RTDECL(int) RTFileDelete(const char *pszFilename); + +/** @name Seek flags. + * @{ */ +/** Seek from the start of the file. */ +#define RTFILE_SEEK_BEGIN 0x00 +/** Seek from the current file position. */ +#define RTFILE_SEEK_CURRENT 0x01 +/** Seek from the end of the file. */ +#define RTFILE_SEEK_END 0x02 +/** @internal */ +#define RTFILE_SEEK_FIRST RTFILE_SEEK_BEGIN +/** @internal */ +#define RTFILE_SEEK_LAST RTFILE_SEEK_END +/** @} */ + + +/** + * Changes the read & write position in a file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param offSeek Offset to seek. + * @param uMethod Seek method, i.e. one of the RTFILE_SEEK_* defines. + * @param poffActual Where to store the new file position. + * NULL is allowed. + */ +RTDECL(int) RTFileSeek(RTFILE File, int64_t offSeek, unsigned uMethod, uint64_t *poffActual); + +/** + * Read bytes from a file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. + * @param pcbRead How much we actually read . + * If NULL an error will be returned for a partial read. + */ +RTDECL(int) RTFileRead(RTFILE File, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Read bytes from a file at a given offset. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param off Where to read. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. + * @param pcbRead How much we actually read . + * If NULL an error will be returned for a partial read. + * + * @note OS/2 requires separate seek and write calls. + * + * @note Whether the file position is modified or not is host specific. + */ +RTDECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Read bytes from a file at a given offset into a S/G buffer. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param pSgBuf Pointer to the S/G buffer to read into. + * @param cbToRead How much to read. + * @param pcbRead How much we actually read . + * If NULL an error will be returned for a partial read. + * + * @note It is not possible to guarantee atomicity on all platforms, so + * caller must take care wrt concurrent access to @a hFile. + */ +RTDECL(int) RTFileSgRead(RTFILE hFile, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Read bytes from a file at a given offset into a S/G buffer. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param off Where to read. + * @param pSgBuf Pointer to the S/G buffer to read into. + * @param cbToRead How much to read. + * @param pcbRead How much we actually read . + * If NULL an error will be returned for a partial read. + * + * @note Whether the file position is modified or not is host specific. + * + * @note It is not possible to guarantee atomicity on all platforms, so + * caller must take care wrt concurrent access to @a hFile. + */ +RTDECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Write bytes to a file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How much we actually wrote. + * If NULL an error will be returned for a partial write. + */ +RTDECL(int) RTFileWrite(RTFILE File, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Write bytes to a file at a given offset. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param off Where to write. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How much we actually wrote. + * If NULL an error will be returned for a partial write. + * + * @note OS/2 requires separate seek and write calls. + * + * @note Whether the file position is modified or not is host specific. + * + * @note Whether @a off is used when @a hFile was opened with RTFILE_O_APPEND + * is also host specific. Currently Linux is the the only one + * documented to ignore @a off. + */ +RTDECL(int) RTFileWriteAt(RTFILE hFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Write bytes from a S/G buffer to a file. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param pSgBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How much we actually wrote. + * If NULL an error will be returned for a partial write. + * + * @note It is not possible to guarantee atomicity on all platforms, so + * caller must take care wrt concurrent access to @a hFile. + */ +RTDECL(int) RTFileSgWrite(RTFILE hFile, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Write bytes from a S/G buffer to a file at a given offset. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param off Where to write. + * @param pSgBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How much we actually wrote. + * If NULL an error will be returned for a partial write. + * + * @note It is not possible to guarantee atomicity on all platforms, so + * caller must take care wrt concurrent access to @a hFile. + * + * @note Whether the file position is modified or not is host specific. + * + * @note Whether @a off is used when @a hFile was opened with RTFILE_O_APPEND + * is also host specific. Currently Linux is the the only one + * documented to ignore @a off. + */ +RTDECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Flushes the buffers for the specified file. + * + * @returns iprt status code. + * @retval VINF_NOT_SUPPORTED if it is a special file that does not support + * flushing. This is reported as a informational status since in most + * cases this is entirely harmless (e.g. tty) and simplifies the usage. + * @param File Handle to the file. + */ +RTDECL(int) RTFileFlush(RTFILE File); + +/** + * Set the size of the file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param cbSize The new file size. + */ +RTDECL(int) RTFileSetSize(RTFILE File, uint64_t cbSize); + +/** + * Query the size of the file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pcbSize Where to store the filesize. + */ +RTDECL(int) RTFileQuerySize(RTFILE File, uint64_t *pcbSize); + +/** + * Determine the maximum file size. + * + * @returns The max size of the file. + * -1 on failure, the file position is undefined. + * @param File Handle to the file. + * @see RTFileQueryMaxSizeEx. + */ +RTDECL(RTFOFF) RTFileGetMaxSize(RTFILE File); + +/** + * Determine the maximum file size. + * + * @returns IPRT status code. + * @param File Handle to the file. + * @param pcbMax Where to store the max file size. + * @see RTFileGetMaxSize. + */ +RTDECL(int) RTFileQueryMaxSizeEx(RTFILE File, PRTFOFF pcbMax); + +/** + * Queries the sector size (/ logical block size) for a disk or similar. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if not a disk/similar. Could also be returned + * if not really implemented. + * @param hFile Handle to the disk. This must typically be a device + * rather than a file or directory, though this may vary + * from OS to OS. + * @param pcbSector Where to store the sector size. + */ +RTDECL(int) RTFileQuerySectorSize(RTFILE hFile, uint32_t *pcbSector); + +/** + * Gets the current file position. + * + * @returns File offset. + * @returns ~0UUL on failure. + * @param File Handle to the file. + */ +RTDECL(uint64_t) RTFileTell(RTFILE File); + +/** + * Checks if the supplied handle is valid. + * + * @returns true if valid. + * @returns false if invalid. + * @param File The file handle + */ +RTDECL(bool) RTFileIsValid(RTFILE File); + +/** + * Copies a file. + * + * @returns IPRT status code + * @retval VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + */ +RTDECL(int) RTFileCopy(const char *pszSrc, const char *pszDst); + +/** + * Copies a file given the handles to both files. + * + * @returns IPRT status code + * + * @param FileSrc The source file. The file position is unaltered. + * @param FileDst The destination file. + * On successful returns the file position is at the end of the file. + * On failures the file position and size is undefined. + */ +RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst); + +/** Flags for RTFileCopyEx(). + * @{ */ +/** Do not use RTFILE_O_DENY_WRITE on the source file to allow for copying files opened for writing. */ +#define RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE RT_BIT(0) +/** Do not use RTFILE_O_DENY_WRITE on the target file. */ +#define RTFILECOPY_FLAGS_NO_DST_DENY_WRITE RT_BIT(1) +/** Do not use RTFILE_O_DENY_WRITE on either of the two files. */ +#define RTFILECOPY_FLAGS_NO_DENY_WRITE ( RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE | RTFILECOPY_FLAGS_NO_DST_DENY_WRITE ) +/** */ +#define RTFILECOPY_FLAGS_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Copies a file. + * + * @returns IPRT status code + * @retval VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + * @param fFlags Flags (RTFILECOPY_*). + * @param pfnProgress Pointer to callback function for reporting progress. + * @param pvUser User argument to pass to pfnProgress along with the completion percentage. + */ +RTDECL(int) RTFileCopyEx(const char *pszSrc, const char *pszDst, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser); + +/** + * Copies a file given the handles to both files and + * provide progress callbacks. + * + * @returns IPRT status code. + * + * @param FileSrc The source file. The file position is unaltered. + * @param FileDst The destination file. + * On successful returns the file position is at the end of the file. + * On failures the file position and size is undefined. + * @param pfnProgress Pointer to callback function for reporting progress. + * @param pvUser User argument to pass to pfnProgress along with the completion percentage. + */ +RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser); + +/** + * Copies a part of a file to another one. + * + * @returns IPRT status code. + * @retval VERR_EOF if @a pcbCopied is NULL and the end-of-file is reached + * before @a cbToCopy bytes have been copied. + * + * @param hFileSrc Handle to the source file. Must be readable. + * @param offSrc The source file offset. + * @param hFileDst Handle to the destination file. Must be writable and + * RTFILE_O_APPEND must be be in effect. + * @param offDst The destination file offset. + * @param cbToCopy How many bytes to copy. + * @param fFlags Reserved for the future, must be zero. + * @param pcbCopied Where to return the exact number of bytes copied. + * Optional. + * + * @note The file positions of @a hFileSrc and @a hFileDst are undefined + * upon return of this function. + * + * @sa RTFileCopyPartEx. + */ +RTDECL(int) RTFileCopyPart(RTFILE hFileSrc, RTFOFF offSrc, RTFILE hFileDst, RTFOFF offDst, uint64_t cbToCopy, + uint32_t fFlags, uint64_t *pcbCopied); + + +/** Copy buffer state for RTFileCopyPartEx. + * @note The fields are considered internal! + */ +typedef struct RTFILECOPYPARTBUFSTATE +{ + /** Magic value (RTFILECOPYPARTBUFSTATE_MAGIC). + * @internal */ + uint32_t uMagic; + /** Allocation type (internal). + * @internal */ + int32_t iAllocType; + /** Buffer pointer. + * @internal */ + uint8_t *pbBuf; + /** Buffer size. + * @internal */ + size_t cbBuf; + /** Reserved. + * @internal */ + void *papReserved[3]; +} RTFILECOPYPARTBUFSTATE; +/** Pointer to copy buffer state for RTFileCopyPartEx(). */ +typedef RTFILECOPYPARTBUFSTATE *PRTFILECOPYPARTBUFSTATE; +/** Magic value for the RTFileCopyPartEx() buffer state structure (Stephen John Fry). */ +#define RTFILECOPYPARTBUFSTATE_MAGIC UINT32_C(0x19570857) + +/** + * Prepares buffer state for one or more RTFileCopyPartEx() calls. + * + * Caller must call RTFileCopyPartCleanup() after the final RTFileCopyPartEx() + * call. + * + * @returns IPRT status code. + * @param pBufState The buffer state to prepare. + * @param cbToCopy The number of bytes we typically to copy in one + * RTFileCopyPartEx call. + */ +RTDECL(int) RTFileCopyPartPrep(PRTFILECOPYPARTBUFSTATE pBufState, uint64_t cbToCopy); + +/** + * Cleans up after RTFileCopyPartPrep() once the final RTFileCopyPartEx() + * call has been made. + * + * @param pBufState The buffer state to clean up. + */ +RTDECL(void) RTFileCopyPartCleanup(PRTFILECOPYPARTBUFSTATE pBufState); + +/** + * Copies a part of a file to another one, extended version. + * + * @returns IPRT status code. + * @retval VERR_EOF if @a pcbCopied is NULL and the end-of-file is reached + * before @a cbToCopy bytes have been copied. + * + * @param hFileSrc Handle to the source file. Must be readable. + * @param offSrc The source file offset. + * @param hFileDst Handle to the destination file. Must be writable and + * RTFILE_O_APPEND must be be in effect. + * @param offDst The destination file offset. + * @param cbToCopy How many bytes to copy. + * @param fFlags Reserved for the future, must be zero. + * @param pBufState Copy buffer state prepared by RTFileCopyPartPrep(). + * @param pcbCopied Where to return the exact number of bytes copied. + * Optional. + * + * @note The file positions of @a hFileSrc and @a hFileDst are undefined + * upon return of this function. + * + * @sa RTFileCopyPart. + */ +RTDECL(int) RTFileCopyPartEx(RTFILE hFileSrc, RTFOFF offSrc, RTFILE hFileDst, RTFOFF offDst, uint64_t cbToCopy, + uint32_t fFlags, PRTFILECOPYPARTBUFSTATE pBufState, uint64_t *pcbCopied); + +/** + * Copy file attributes from @a hFileSrc to @a hFileDst. + * + * @returns IPRT status code. + * @param hFileSrc Handle to the source file. + * @param hFileDst Handle to the destination file. + * @param fFlags Reserved, pass zero. + */ +RTDECL(int) RTFileCopyAttributes(RTFILE hFileSrc, RTFILE hFileDst, uint32_t fFlags); + +/** + * Compares two file given the paths to both files. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param pszFile1 The path to the first file. + * @param pszFile2 The path to the second file. + */ +RTDECL(int) RTFileCompare(const char *pszFile1, const char *pszFile2); + +/** + * Compares two file given the handles to both files. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param hFile1 The first file. Undefined return position. + * @param hFile2 The second file. Undefined return position. + */ +RTDECL(int) RTFileCompareByHandles(RTFILE hFile1, RTFILE hFile2); + +/** Flags for RTFileCompareEx(). + * @{ */ +/** Do not use RTFILE_O_DENY_WRITE on the first file. */ +#define RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 RT_BIT(0) +/** Do not use RTFILE_O_DENY_WRITE on the second file. */ +#define RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 RT_BIT(1) +/** Do not use RTFILE_O_DENY_WRITE on either of the two files. */ +#define RTFILECOMP_FLAGS_NO_DENY_WRITE ( RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 | RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 ) +/** */ +#define RTFILECOMP_FLAGS_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Compares two files, extended version with progress callback. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param pszFile1 The path to the source file. + * @param pszFile2 The path to the destination file. This file will be + * created. + * @param fFlags Flags, any of the RTFILECOMP_FLAGS_ \#defines. + * @param pfnProgress Pointer to callback function for reporting progress. + * @param pvUser User argument to pass to pfnProgress along with the completion percentage. + */ +RTDECL(int) RTFileCompareEx(const char *pszFile1, const char *pszFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser); + +/** + * Compares two files given their handles, extended version with progress + * callback. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param hFile1 The first file. Undefined return position. + * @param hFile2 The second file. Undefined return position. + * + * @param fFlags Flags, any of the RTFILECOMP_FLAGS_ \#defines, flags + * related to opening of the files will be ignored. + * @param pfnProgress Pointer to callback function for reporting progress. + * @param pvUser User argument to pass to pfnProgress along with the completion percentage. + */ +RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser); + +/** + * Renames a file. + * + * Identical to RTPathRename except that it will ensure that the source is not a directory. + * + * @returns IPRT status code. + * @returns VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + * @param fRename See RTPathRename. + */ +RTDECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename); + + +/** @name RTFileMove flags (bit masks). + * @{ */ +/** Replace destination file if present. */ +#define RTFILEMOVE_FLAGS_REPLACE 0x1 +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTFILEMOVE_FLAGS_NO_SYMLINKS 0x2 +/** @} */ + +/** + * Converts file opening modes (used by fopen, for example) to IPRT + * compatible flags, which then can be used with RTFileOpen* APIs. + * + * @note Handling sharing modes is not supported yet, so RTFILE_O_DENY_NONE + * will always be used. + * + * @return IPRT status code. + * @param pszMode Mode string to convert. + * @param pfMode Where to store the converted mode flags on + * success. + */ +RTDECL(int) RTFileModeToFlags(const char *pszMode, uint64_t *pfMode); + +/** + * Converts file opening modes along with a separate disposition command + * to IPRT compatible flags, which then can be used with RTFileOpen* APIs. + * + * Access modes: + * - "r": Opens a file for reading. + * - "r+": Opens a file for reading and writing. + * - "w": Opens a file for writing. + * - "w+": Opens a file for writing and reading. + * + * Disposition modes: + * - "oe", "open": Opens an existing file or fail if it does not exist. + * - "oc", "open-create": Opens an existing file or create it if it does + * not exist. + * - "oa", "open-append": Opens an existing file and places the file + * pointer at the end of the file, if opened with write access. Create + * the file if it does not exist. + * - "ot", "open-truncate": Opens and truncate an existing file or fail if + * it does not exist. + * - "ce", "create": Creates a new file if it does not exist. Fail if + * exist. + * - "ca", "create-replace": Creates a new file, always. Overwrites an + * existing file. + * + * Sharing mode: + * - "nr": Deny read. + * - "nw": Deny write. + * - "nrw": Deny both read and write. + * - "d": Allow delete. + * - "", NULL: Deny none, except delete. + * + * @return IPRT status code. + * @param pszAccess Access mode string to convert. + * @param pszDisposition Disposition mode string to convert. + * @param pszSharing Sharing mode string to convert. + * @param pfMode Where to store the converted mode flags on success. + */ +RTDECL(int) RTFileModeToFlagsEx(const char *pszAccess, const char *pszDisposition, const char *pszSharing, uint64_t *pfMode); + +/** + * Moves a file. + * + * RTFileMove differs from RTFileRename in that it works across volumes. + * + * @returns IPRT status code. + * @returns VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + * @param fMove A combination of the RTFILEMOVE_* flags. + */ +RTDECL(int) RTFileMove(const char *pszSrc, const char *pszDst, unsigned fMove); + + +/** + * Creates a new file with a unique name using the given template, returning a + * handle to it. + * + * One or more trailing X'es in the template will be replaced by random alpha + * numeric characters until a RTFileOpen with RTFILE_O_CREATE succeeds or we + * run out of patience. + * For instance: + * "/tmp/myprog-XXXXXX" + * + * As an alternative to trailing X'es, it is possible to put 3 or more X'es + * somewhere inside the file name. In the following string only the last + * bunch of X'es will be modified: + * "/tmp/myprog-XXX-XXX.tmp" + * + * @returns IPRT status code. + * @param phFile Where to return the file handle on success. Set to + * NIL on failure. + * @param pszTemplate The file name template on input. The actual file + * name on success. Empty string on failure. + * @param fOpen The RTFILE_O_XXX flags to open the file with. + * RTFILE_O_CREATE is mandatory. + * @see RTFileCreateTemp + */ +RTDECL(int) RTFileCreateUnique(PRTFILE phFile, char *pszTemplate, uint64_t fOpen); + +/** + * Creates a new file with a unique name using the given template. + * + * One or more trailing X'es in the template will be replaced by random alpha + * numeric characters until a RTFileOpen with RTFILE_O_CREATE succeeds or we + * run out of patience. + * For instance: + * "/tmp/myprog-XXXXXX" + * + * As an alternative to trailing X'es, it is possible to put 3 or more X'es + * somewhere inside the file name. In the following string only the last + * bunch of X'es will be modified: + * "/tmp/myprog-XXX-XXX.tmp" + * + * @returns iprt status code. + * @param pszTemplate The file name template on input. The actual file + * name on success. Empty string on failure. + * @param fMode The mode to create the file with. Use 0600 unless + * you have reason not to. + * @see RTFileCreateUnique + */ +RTDECL(int) RTFileCreateTemp(char *pszTemplate, RTFMODE fMode); + +/** + * Secure version of @a RTFileCreateTemp with a fixed mode of 0600. + * + * This function behaves in the same way as @a RTFileCreateTemp with two + * additional points. Firstly the mode is fixed to 0600. Secondly it will + * fail if it is not possible to perform the operation securely. Possible + * reasons include that the file could be removed by another unprivileged + * user before it is used (e.g. if is created in a non-sticky /tmp directory) + * or that the path contains symbolic links which another unprivileged user + * could manipulate; however the exact criteria will be specified on a + * platform-by-platform basis as platform support is added. + * @see RTPathIsSecure for the current list of criteria. + * + * @returns iprt status code. + * @returns VERR_NOT_SUPPORTED if the interface can not be supported on the + * current platform at this time. + * @returns VERR_INSECURE if the file could not be created securely. + * @param pszTemplate The file name template on input. The actual + * file name on success. Empty string on failure. + * @see RTFileCreateUnique + */ +RTDECL(int) RTFileCreateTempSecure(char *pszTemplate); + +/** + * Opens a new file with a unique name in the temp directory. + * + * Unlike the other temp file creation APIs, this does not allow you any control + * over the name. Nor do you have to figure out where the temporary directory + * is. + * + * @returns iprt status code. + * @param phFile Where to return the handle to the file. + * @param pszFilename Where to return the name (+path) of the file . + * @param cbFilename The size of the buffer @a pszFilename points to. + * @param fOpen The RTFILE_O_XXX flags to open the file with. + * + * @remarks If actual control over the filename or location is required, we'll + * create an extended edition of this API. + */ +RTDECL(int) RTFileOpenTemp(PRTFILE phFile, char *pszFilename, size_t cbFilename, uint64_t fOpen); + + +/** @page pg_rt_filelock RT File locking API description + * + * File locking general rules: + * + * Region to lock or unlock can be located beyond the end of file, this can be used for + * growing files. + * Read (or Shared) locks can be acquired held by an unlimited number of processes at the + * same time, but a Write (or Exclusive) lock can only be acquired by one process, and + * cannot coexist with a Shared lock. To acquire a Read lock, a process must wait until + * there are no processes holding any Write locks. To acquire a Write lock, a process must + * wait until there are no processes holding either kind of lock. + * By default, RTFileLock and RTFileChangeLock calls returns error immediately if the lock + * can't be acquired due to conflict with other locks, however they can be called in wait mode. + * + * Differences in implementation: + * + * Win32, OS/2: Locking is mandatory, since locks are enforced by the operating system. + * I.e. when file region is locked in Read mode, any write in it will fail; in case of Write + * lock - region can be read and writed only by lock's owner. + * + * Win32: File size change (RTFileSetSize) is not controlled by locking at all (!) in the + * operation system. Also see comments to RTFileChangeLock API call. + * + * Linux/Posix: By default locks in Unixes are advisory. This means that cooperating processes + * may use locks to coordinate access to a file between themselves, but programs are also free + * to ignore locks and access the file in any way they choose to. + * + * Additional reading: + * http://en.wikipedia.org/wiki/File_locking + * http://unixhelp.ed.ac.uk/CGI/man-cgi?fcntl+2 + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/lockfileex.asp + */ + +/** @name Lock flags (bit masks). + * @{ */ +/** Read access, can be shared with others. */ +#define RTFILE_LOCK_READ 0x00 +/** Write access, one at a time. */ +#define RTFILE_LOCK_WRITE 0x01 +/** Don't wait for other locks to be released. */ +#define RTFILE_LOCK_IMMEDIATELY 0x00 +/** Wait till conflicting locks have been released. */ +#define RTFILE_LOCK_WAIT 0x02 +/** Valid flags mask */ +#define RTFILE_LOCK_MASK 0x03 +/** @} */ + + +/** + * Locks a region of file for read (shared) or write (exclusive) access. + * + * @returns iprt status code. + * @returns VERR_FILE_LOCK_VIOLATION if lock can't be acquired. + * @param File Handle to the file. + * @param fLock Lock method and flags, see RTFILE_LOCK_* defines. + * @param offLock Offset of lock start. + * @param cbLock Length of region to lock, may overlap the end of file. + */ +RTDECL(int) RTFileLock(RTFILE File, unsigned fLock, int64_t offLock, uint64_t cbLock); + +/** + * Changes a lock type from read to write or from write to read. + * The region to type change must correspond exactly to an existing locked region. + * If change can't be done due to locking conflict and non-blocking mode is used, error is + * returned and lock keeps its state (see next warning). + * + * WARNING: win32 implementation of this call is not atomic, it transforms to a pair of + * calls RTFileUnlock and RTFileLock. Potentially the previously acquired lock can be + * lost, i.e. function is called in non-blocking mode, previous lock is freed, new lock can't + * be acquired, and old lock (previous state) can't be acquired back too. This situation + * may occurs _only_ if the other process is acquiring a _write_ lock in blocking mode or + * in race condition with the current call. + * In this very bad case special error code VERR_FILE_LOCK_LOST will be returned. + * + * @returns iprt status code. + * @returns VERR_FILE_NOT_LOCKED if region was not locked. + * @returns VERR_FILE_LOCK_VIOLATION if lock type can't be changed, lock remains its type. + * @returns VERR_FILE_LOCK_LOST if lock was lost, we haven't this lock anymore :( + * @param File Handle to the file. + * @param fLock Lock method and flags, see RTFILE_LOCK_* defines. + * @param offLock Offset of lock start. + * @param cbLock Length of region to lock, may overlap the end of file. + */ +RTDECL(int) RTFileChangeLock(RTFILE File, unsigned fLock, int64_t offLock, uint64_t cbLock); + +/** + * Unlocks previously locked region of file. + * The region to unlock must correspond exactly to an existing locked region. + * + * @returns iprt status code. + * @returns VERR_FILE_NOT_LOCKED if region was not locked. + * @param File Handle to the file. + * @param offLock Offset of lock start. + * @param cbLock Length of region to unlock, may overlap the end of file. + */ +RTDECL(int) RTFileUnlock(RTFILE File, int64_t offLock, uint64_t cbLock); + + +/** + * Query information about an open file. + * + * @returns iprt status code. + * + * @param File Handle to the file. + * @param pObjInfo Object information structure to be filled on successful return. + * @param enmAdditionalAttribs Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + */ +RTDECL(int) RTFileQueryInfo(RTFILE File, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs); + +/** + * Changes one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @retval VERR_NOT_SUPPORTED is returned if the operation isn't supported by + * the OS. + * + * @param File Handle to the file. + * @param pAccessTime Pointer to the new access time. NULL if not to be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if not to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + */ +RTDECL(int) RTFileSetTimes(RTFILE File, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + +/** + * Gets one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pAccessTime Where to store the access time. NULL is ok. + * @param pModificationTime Where to store the modifcation time. NULL is ok. + * @param pChangeTime Where to store the change time. NULL is ok. + * @param pBirthTime Where to store the time of birth. NULL is ok. + * + * @remark This is wrapper around RTFileQueryInfo() and exists to complement RTFileSetTimes(). + */ +RTDECL(int) RTFileGetTimes(RTFILE File, PRTTIMESPEC pAccessTime, PRTTIMESPEC pModificationTime, + PRTTIMESPEC pChangeTime, PRTTIMESPEC pBirthTime); + +/** + * Changes the mode flags of an open file. + * + * The API requires at least one of the mode flag sets (Unix/Dos) to + * be set. The type is ignored. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param fMode The new file mode, see @ref grp_rt_fs for details. + */ +RTDECL(int) RTFileSetMode(RTFILE File, RTFMODE fMode); + +/** + * Gets the mode flags of an open file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pfMode Where to store the file mode, see @ref grp_rt_fs for details. + * + * @remark This is wrapper around RTFileQueryInfo() + * and exists to complement RTFileSetMode(). + */ +RTDECL(int) RTFileGetMode(RTFILE File, uint32_t *pfMode); + +/** + * Changes the owner and/or group of an open file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param uid The new file owner user id. Pass NIL_RTUID to leave + * this unchanged. + * @param gid The new group id. Pass NIL_RTGID to leave this + * unchanged. + */ +RTDECL(int) RTFileSetOwner(RTFILE File, uint32_t uid, uint32_t gid); + +/** + * Gets the owner and/or group of an open file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pUid Where to store the owner user id. NULL is ok. + * @param pGid Where to store the group id. NULL is ok. + * + * @remark This is wrapper around RTFileQueryInfo() and exists to complement RTFileGetOwner(). + */ +RTDECL(int) RTFileGetOwner(RTFILE File, uint32_t *pUid, uint32_t *pGid); + +/** + * Executes an IOCTL on a file descriptor. + * + * This function is currently only available in L4 and posix environments. + * Attemps at calling it from code shared with any other platforms will break things! + * + * The rational for defining this API is to simplify L4 porting of audio drivers, + * and to remove some of the assumptions on RTFILE being a file descriptor on + * platforms using the posix file implementation. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param ulRequest IOCTL request to carry out. + * @param pvData IOCTL data. + * @param cbData Size of the IOCTL data. + * @param piRet Return value of the IOCTL request. + */ +RTDECL(int) RTFileIoCtl(RTFILE File, unsigned long ulRequest, void *pvData, unsigned cbData, int *piRet); + +/** + * Query the sizes of a filesystem. + * + * @returns iprt status code. + * @retval VERR_NOT_SUPPORTED is returned if the operation isn't supported by + * the OS. + * + * @param hFile The file handle. + * @param pcbTotal Where to store the total filesystem space. (Optional) + * @param pcbFree Where to store the remaining free space in the filesystem. (Optional) + * @param pcbBlock Where to store the block size. (Optional) + * @param pcbSector Where to store the sector size. (Optional) + * + * @sa RTFsQuerySizes + */ +RTDECL(int) RTFileQueryFsSizes(RTFILE hFile, PRTFOFF pcbTotal, RTFOFF *pcbFree, + uint32_t *pcbBlock, uint32_t *pcbSector); + +/** + * Reads the file into memory. + * + * The caller must free the memory using RTFileReadAllFree(). + * + * @returns IPRT status code. + * @param pszFilename The name of the file. + * @param ppvFile Where to store the pointer to the memory on successful return. + * @param pcbFile Where to store the size of the returned memory. + * + * @remarks Note that this function may be implemented using memory mapping, which means + * that the file may remain open until RTFileReadAllFree() is called. It also + * means that the return memory may reflect the state of the file when it's + * accessed instead of when this call was done. So, in short, don't use this + * API for volatile files, then rather use the extended variant with a + * yet-to-be-defined flag. + */ +RTDECL(int) RTFileReadAll(const char *pszFilename, void **ppvFile, size_t *pcbFile); + +/** + * Reads the file into memory. + * + * The caller must free the memory using RTFileReadAllFree(). + * + * @returns IPRT status code. + * @param pszFilename The name of the file. + * @param off The offset to start reading at. + * @param cbMax The maximum number of bytes to read into memory. Specify RTFOFF_MAX + * to read to the end of the file. + * @param fFlags See RTFILE_RDALL_*. + * @param ppvFile Where to store the pointer to the memory on successful return. + * @param pcbFile Where to store the size of the returned memory. + * + * @remarks See the remarks for RTFileReadAll. + */ +RTDECL(int) RTFileReadAllEx(const char *pszFilename, RTFOFF off, RTFOFF cbMax, uint32_t fFlags, void **ppvFile, size_t *pcbFile); + +/** + * Reads the file into memory. + * + * The caller must free the memory using RTFileReadAllFree(). + * + * @returns IPRT status code. + * @param File The handle to the file. + * @param ppvFile Where to store the pointer to the memory on successful return. + * @param pcbFile Where to store the size of the returned memory. + * + * @remarks See the remarks for RTFileReadAll. + */ +RTDECL(int) RTFileReadAllByHandle(RTFILE File, void **ppvFile, size_t *pcbFile); + +/** + * Reads the file into memory. + * + * The caller must free the memory using RTFileReadAllFree(). + * + * @returns IPRT status code. + * @param File The handle to the file. + * @param off The offset to start reading at. + * @param cbMax The maximum number of bytes to read into memory. Specify RTFOFF_MAX + * to read to the end of the file. + * @param fFlags See RTFILE_RDALL_*. + * @param ppvFile Where to store the pointer to the memory on successful return. + * @param pcbFile Where to store the size of the returned memory. + * + * @remarks See the remarks for RTFileReadAll. + */ +RTDECL(int) RTFileReadAllByHandleEx(RTFILE File, RTFOFF off, RTFOFF cbMax, uint32_t fFlags, void **ppvFile, size_t *pcbFile); + +/** + * Frees the memory returned by one of the RTFileReadAll(), RTFileReadAllEx(), + * RTFileReadAllByHandle() and RTFileReadAllByHandleEx() functions. + * + * @param pvFile Pointer to the memory. + * @param cbFile The size of the memory. + */ +RTDECL(void) RTFileReadAllFree(void *pvFile, size_t cbFile); + +/** @name RTFileReadAllEx and RTFileReadAllHandleEx flags + * The open flags are ignored by RTFileReadAllHandleEx. + * @{ */ +#define RTFILE_RDALL_O_DENY_NONE RTFILE_O_DENY_NONE +#define RTFILE_RDALL_O_DENY_READ RTFILE_O_DENY_READ +#define RTFILE_RDALL_O_DENY_WRITE RTFILE_O_DENY_WRITE +#define RTFILE_RDALL_O_DENY_READWRITE RTFILE_O_DENY_READWRITE +#define RTFILE_RDALL_O_DENY_ALL RTFILE_O_DENY_ALL +#define RTFILE_RDALL_O_DENY_NOT_DELETE RTFILE_O_DENY_NOT_DELETE +#define RTFILE_RDALL_O_DENY_MASK RTFILE_O_DENY_MASK +/** Fail with VERR_OUT_OF_RANGE if the file size exceeds the specified maximum + * size. The default behavior is to cap the size at cbMax. */ +#define RTFILE_RDALL_F_FAIL_ON_MAX_SIZE RT_BIT_32(30) +/** Add a trailing zero byte to facilitate reading text files. */ +#define RTFILE_RDALL_F_TRAILING_ZERO_BYTE RT_BIT_32(31) +/** Mask of valid flags. */ +#define RTFILE_RDALL_VALID_MASK (RTFILE_RDALL_O_DENY_MASK | UINT32_C(0xc0000000)) +/** @} */ + +/** + * Sets the current size of the file ensuring that all required blocks + * are allocated on the underlying medium. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if either this operation is not supported on the + * current host in an efficient manner or the given combination of + * flags is not supported. + * @param hFile The handle to the file. + * @param cbSize The new size of the file to allocate. + * @param fFlags Combination of RTFILE_ALLOC_SIZE_F_* + */ +RTDECL(int) RTFileSetAllocationSize(RTFILE hFile, uint64_t cbSize, uint32_t fFlags); + +/** @name RTFILE_ALLOC_SIZE_F_XXX - RTFileSetAllocationSize flags + * @{ */ +/** Default flags. */ +#define RTFILE_ALLOC_SIZE_F_DEFAULT 0 +/** Do not change the size of the file if the given size is bigger than the + * current file size. + * + * Useful to preallocate blocks beyond the current size for appending data in an + * efficient manner. Might not be supported on all hosts and will return + * VERR_NOT_SUPPORTED in that case. */ +#define RTFILE_ALLOC_SIZE_F_KEEP_SIZE RT_BIT(0) +/** Mask of valid flags. */ +#define RTFILE_ALLOC_SIZE_F_VALID (RTFILE_ALLOC_SIZE_F_KEEP_SIZE) +/** @} */ + + +#ifdef IN_RING3 + +/** @page pg_rt_asyncio RT File async I/O API + * + * File operations are usually blocking the calling thread until + * they completed making it impossible to let the thread do anything + * else in-between. + * The RT File async I/O API provides an easy and efficient way to + * access files asynchronously using the native facilities provided + * by each operating system. + * + * @section sec_rt_asyncio_objects Objects + * + * There are two objects used in this API. + * The first object is the request. A request contains every information + * needed two complete the file operation successfully like the start offset + * and pointer to the source or destination buffer. + * Requests are created with RTFileAioReqCreate() and destroyed with + * RTFileAioReqDestroy(). + * Because creating a request may require allocating various operating + * system dependent resources and may be quite expensive it is possible + * to use a request more than once to save CPU cycles. + * A request is constructed with either RTFileAioReqPrepareRead() + * which will set up a request to read from the given file or + * RTFileAioReqPrepareWrite() which will write to a given file. + * + * The second object is the context. A file is associated with a context + * and requests for this file may complete only on the context the file + * was associated with and not on the context given in RTFileAioCtxSubmit() + * (see below for further information). + * RTFileAioCtxWait() is used to wait for completion of requests which were + * associated with the context. While waiting for requests the thread can not + * respond to global state changes. That's why the API provides a way to let + * RTFileAioCtxWait() return immediately no matter how many requests + * have finished through RTFileAioCtxWakeup(). The return code is + * VERR_INTERRUPTED to let the thread know that he got interrupted. + * + * @section sec_rt_asyncio_request_states Request states + * + * Created: + * After a request was created with RTFileAioReqCreate() it is in the same state + * like it just completed successfully. RTFileAioReqGetRC() will return VINF_SUCCESS + * and a transfer size of 0. RTFileAioReqGetUser() will return NULL. The request can be + * destroyed RTFileAioReqDestroy(). It is also allowed to prepare a the request + * for a data transfer with the RTFileAioReqPrepare* methods. + * Calling any other method like RTFileAioCtxSubmit() will return VERR_FILE_AIO_NOT_PREPARED + * and RTFileAioReqCancel() returns VERR_FILE_AIO_NOT_SUBMITTED. + * + * Prepared: + * A request will enter this state if one of the RTFileAioReqPrepare* methods + * is called. In this state you can still destroy and retrieve the user data + * associated with the request but trying to cancel the request or getting + * the result of the operation will return VERR_FILE_AIO_NOT_SUBMITTED. + * + * Submitted: + * A prepared request can be submitted with RTFileAioCtxSubmit(). If the operation + * succeeds it is not allowed to touch the request or free any resources until + * it completed through RTFileAioCtxWait(). The only allowed method is RTFileAioReqCancel() + * which tries to cancel the request. The request will go into the completed state + * and RTFileAioReqGetRC() will return VERR_FILE_AIO_CANCELED. + * If the request completes not matter if successfully or with an error it will + * switch into the completed state. RTFileReqDestroy() fails if the given request + * is in this state. + * + * Completed: + * The request will be in this state after it completed and returned through + * RTFileAioCtxWait(). RTFileAioReqGetRC() returns the final result code + * and the number of bytes transferred. + * The request can be used for new data transfers. + * + * @section sec_rt_asyncio_threading Threading + * + * The API is a thin wrapper around the specific host OS APIs and therefore + * relies on the thread safety of the underlying API. + * The interesting functions with regards to thread safety are RTFileAioCtxSubmit() + * and RTFileAioCtxWait(). RTFileAioCtxWait() must not be called from different + * threads at the same time with the same context handle. The same applies to + * RTFileAioCtxSubmit(). However it is possible to submit new requests from a different + * thread while waiting for completed requests on another thread with RTFileAioCtxWait(). + * + * @section sec_rt_asyncio_implementations Differences in implementation + * + * Because the host APIs are quite different on every OS and every API has other limitations + * there are some things to consider to make the code as portable as possible. + * + * The first restriction at the moment is that every buffer has to be aligned to a 512 byte boundary. + * This limitation comes from the Linux io_* interface. To use the interface the file + * must be opened with O_DIRECT. This flag disables the kernel cache too which may + * degrade performance but is unfortunately the only way to make asynchronous + * I/O work till today (if O_DIRECT is omitted io_submit will revert to sychronous behavior + * and will return when the requests finished and when they are queued). + * It is mostly used by DBMS which do theire own caching. + * Furthermore there is no filesystem independent way to discover the restrictions at least + * for the 2.4 kernel series. Since 2.6 the 512 byte boundary seems to be used by all + * file systems. So Linus comment about this flag is comprehensible but Linux + * lacks an alternative at the moment. + * + * The next limitation applies only to Windows. Requests are not associated with the + * I/O context they are associated with but with the file the request is for. + * The file needs to be associated with exactly one I/O completion port and requests + * for this file will only arrive at that context after they completed and not on + * the context the request was submitted. + * To associate a file with a specific context RTFileAioCtxAssociateWithFile() is + * used. It is only implemented on Windows and does nothing on the other platforms. + * If the file needs to be associated with different context for some reason + * the file must be closed first. After it was opened again the new context + * can be associated with the other context. + * This can't be done by the API because there is no way to retrieve the flags + * the file was opened with. + */ + +/** + * Global limits for the AIO API. + */ +typedef struct RTFILEAIOLIMITS +{ + /** Global number of simultaneous outstanding requests allowed. + * RTFILEAIO_UNLIMITED_REQS means no limit. */ + uint32_t cReqsOutstandingMax; + /** The alignment data buffers need to have. + * 0 means no alignment restrictions. */ + uint32_t cbBufferAlignment; +} RTFILEAIOLIMITS; +/** A pointer to a AIO limits structure. */ +typedef RTFILEAIOLIMITS *PRTFILEAIOLIMITS; + +/** + * Returns the global limits for the AIO API. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the host does not support the async I/O API. + * + * @param pAioLimits Where to store the global limit information. + */ +RTDECL(int) RTFileAioGetLimits(PRTFILEAIOLIMITS pAioLimits); + +/** + * Creates an async I/O request handle. + * + * @returns IPRT status code. + * @param phReq Where to store the request handle. + */ +RTDECL(int) RTFileAioReqCreate(PRTFILEAIOREQ phReq); + +/** + * Destroys an async I/O request handle. + * + * @returns IPRT status code. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request is still in progress. + * + * @param hReq The request handle. + */ +RTDECL(int) RTFileAioReqDestroy(RTFILEAIOREQ hReq); + +/** + * Prepares an async read request. + * + * @returns IPRT status code. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request is still in progress. + * + * @param hReq The request handle. + * @param hFile The file to read from. + * @param off The offset to start reading at. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. + * @param pvUser Opaque user data associated with this request which + * can be retrieved with RTFileAioReqGetUser(). + */ +RTDECL(int) RTFileAioReqPrepareRead(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off, + void *pvBuf, size_t cbRead, void *pvUser); + +/** + * Prepares an async write request. + * + * @returns IPRT status code. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request is still in progress. + * + * @param hReq The request handle. + * @param hFile The file to write to. + * @param off The offset to start writing at. + * @param pvBuf The bits to write. + * @param cbWrite Number of bytes to write. + * @param pvUser Opaque user data associated with this request which + * can be retrieved with RTFileAioReqGetUser(). + */ +RTDECL(int) RTFileAioReqPrepareWrite(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off, + void const *pvBuf, size_t cbWrite, void *pvUser); + +/** + * Prepares an async flush of all cached data associated with a file handle. + * + * @returns IPRT status code. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request is still in progress. + * + * @param hReq The request handle. + * @param hFile The file to flush. + * @param pvUser Opaque user data associated with this request which + * can be retrieved with RTFileAioReqGetUser(). + * + * @remarks May also flush other caches on some platforms. + */ +RTDECL(int) RTFileAioReqPrepareFlush(RTFILEAIOREQ hReq, RTFILE hFile, void *pvUser); + +/** + * Gets the opaque user data associated with the given request. + * + * @returns Opaque user data. + * @retval NULL if the request hasn't been prepared yet. + * + * @param hReq The request handle. + */ +RTDECL(void *) RTFileAioReqGetUser(RTFILEAIOREQ hReq); + +/** + * Cancels a pending request. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS If the request was canceled. + * @retval VERR_FILE_AIO_NOT_SUBMITTED If the request wasn't submitted yet. + * @retval VERR_FILE_AIO_IN_PROGRESS If the request could not be canceled because it is already processed. + * @retval VERR_FILE_AIO_COMPLETED If the request could not be canceled because it already completed. + * + * @param hReq The request to cancel. + */ +RTDECL(int) RTFileAioReqCancel(RTFILEAIOREQ hReq); + +/** + * Gets the status of a completed request. + * + * @returns The IPRT status code of the given request. + * @retval VERR_FILE_AIO_NOT_SUBMITTED if the request wasn't submitted yet. + * @retval VERR_FILE_AIO_CANCELED if the request was canceled. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request isn't yet completed. + * + * @param hReq The request handle. + * @param pcbTransferred Where to store the number of bytes transferred. + * Optional since it is not relevant for all kinds of + * requests. + */ +RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransferred); + + + +/** + * Creates an async I/O context. + * + * @todo briefly explain what an async context is here or in the page + * above. + * + * @returns IPRT status code. + * @param phAioCtx Where to store the async I/O context handle. + * @param cAioReqsMax How many async I/O requests the context should be capable + * to handle. Pass RTFILEAIO_UNLIMITED_REQS if the + * context should support an unlimited number of + * requests. + * @param fFlags Combination of RTFILEAIOCTX_FLAGS_*. + */ +RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax, + uint32_t fFlags); + +/** Unlimited number of requests. + * Used with RTFileAioCtxCreate and RTFileAioCtxGetMaxReqCount. */ +#define RTFILEAIO_UNLIMITED_REQS UINT32_MAX + +/** When set RTFileAioCtxWait() will always wait for completing requests, + * even when there is none waiting currently, instead of returning + * VERR_FILE_AIO_NO_REQUEST. */ +#define RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS RT_BIT_32(0) +/** mask of valid flags. */ +#define RTFILEAIOCTX_FLAGS_VALID_MASK (RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS) + +/** + * Destroys an async I/O context. + * + * @returns IPRT status code. + * @param hAioCtx The async I/O context handle. + */ +RTDECL(int) RTFileAioCtxDestroy(RTFILEAIOCTX hAioCtx); + +/** + * Get the maximum number of requests one aio context can handle. + * + * @returns Maximum number of tasks the context can handle. + * RTFILEAIO_UNLIMITED_REQS if there is no limit. + * + * @param hAioCtx The async I/O context handle. + * If NIL_RTAIOCONTEXT is passed the maximum value + * which can be passed to RTFileAioCtxCreate() + * is returned. + */ +RTDECL(uint32_t) RTFileAioCtxGetMaxReqCount(RTFILEAIOCTX hAioCtx); + +/** + * Associates a file with an async I/O context. + * Requests for this file will arrive at the completion port + * associated with the file. + * + * @returns IPRT status code. + * + * @param hAioCtx The async I/O context handle. + * @param hFile The file handle. + */ +RTDECL(int) RTFileAioCtxAssociateWithFile(RTFILEAIOCTX hAioCtx, RTFILE hFile); + +/** + * Submits a set of requests to an async I/O context for processing. + * + * @returns IPRT status code. + * @returns VERR_FILE_AIO_INSUFFICIENT_RESSOURCES if the maximum number of + * simultaneous outstanding requests would be exceeded. + * + * @param hAioCtx The async I/O context handle. + * @param pahReqs Pointer to an array of request handles. + * @param cReqs The number of entries in the array. + * + * @remarks It is possible that some requests could be submitted successfully + * even if the method returns an error code. In that case RTFileAioReqGetRC() + * can be used to determine the status of a request. + * If it returns VERR_FILE_AIO_IN_PROGRESS it was submitted successfully. + * Any other error code may indicate why the request failed. + * VERR_FILE_AIO_NOT_SUBMITTED indicates that a request wasn't submitted + * probably because the previous request encountered an error. + * + * @remarks @a cReqs uses the type size_t while it really is a uint32_t, this is + * to avoid annoying warnings when using RT_ELEMENTS and similar + * macros. + */ +RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs); + +/** + * Waits for request completion. + * + * Only one thread at a time may call this API on a context. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER If pcReqs or/and pahReqs are invalid. + * @retval VERR_INVALID_HANDLE If hAioCtx is invalid. + * @retval VERR_OUT_OF_RANGE If cMinReqs is larger than cReqs. + * @retval VERR_INVALID_PARAMETER If cReqs is 0. + * @retval VERR_TIMEOUT If cMinReqs didn't complete before the + * timeout expired. + * @retval VERR_INTERRUPTED If the completion context was interrupted + * by RTFileAioCtxWakeup(). + * @retval VERR_FILE_AIO_NO_REQUEST If there are no pending request. + * + * @param hAioCtx The async I/O context handle to wait and get + * completed requests from. + * @param cMinReqs The minimum number of requests which have to + * complete before this function returns. + * @param cMillies The number of milliseconds to wait before returning + * VERR_TIMEOUT. Use RT_INDEFINITE_WAIT to wait + * forever. + * @param pahReqs Pointer to an array where the handles of the + * completed requests will be stored on success. + * @param cReqs The number of entries @a pahReqs can hold. + * @param pcReqs Where to store the number of returned (complete) + * requests. This will always be set. + * + * @remarks The wait will be resume if interrupted by a signal. An + * RTFileAioCtxWaitNoResume variant can be added later if it becomes + * necessary. + * + * @remarks @a cMinReqs and @a cReqs use the type size_t while they really are + * uint32_t's, this is to avoid annoying warnings when using + * RT_ELEMENTS and similar macros. + */ +RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL cMillies, + PRTFILEAIOREQ pahReqs, size_t cReqs, uint32_t *pcReqs); + +/** + * Forces any RTFileAioCtxWait() call on another thread to return immediately. + * + * @returns IPRT status code. + * + * @param hAioCtx The handle of the async I/O context to wakeup. + */ +RTDECL(int) RTFileAioCtxWakeup(RTFILEAIOCTX hAioCtx); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_file_h */ + diff --git a/include/iprt/formats/Makefile.kup b/include/iprt/formats/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/formats/apfs.h b/include/iprt/formats/apfs.h new file mode 100644 index 00000000..f45a37df --- /dev/null +++ b/include/iprt/formats/apfs.h @@ -0,0 +1,244 @@ +/* $Id: apfs.h $ */ +/** @file + * IPRT, APFS (Apple File System) format. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_apfs_h +#define IPRT_INCLUDED_formats_apfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_apfs Apple File System structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/* + * The filesystem structures were retrieved from: + * https://developer.apple.com/support/downloads/Apple-File-System-Reference.pdf + */ + +/** Physical address of an on-disk block. */ +typedef int64_t APFSPADDR; +/** Object identifier. */ +typedef uint64_t APFSOID; +/** Transaction identifier. */ +typedef uint64_t APFSXID; + +/** Invalid object ID. */ +#define APFS_OID_INVALID UINT64_C(0) +/** Number of reserved object IDs for special structures. */ +#define APFS_OID_RSVD_CNT 1024 +/** Object ID of a super block. */ +#define APFS_OID_NX_SUPERBLOCK UINT64_C(1) + + +/** + * Range of physical addresses. + */ +typedef struct +{ + /** Start address of the range. */ + APFSPADDR PAddrStart; + /** Size of the range in blocks.*/ + uint64_t cBlocks; +} APFSPRANGE; +/** Pointer to a APFS range. */ +typedef APFSPRANGE *PAPFSPRANGE; +/** Pointer to a const APFS range. */ +typedef const APFSPRANGE *PCAPFSPRANGE; + +/** APFS UUID (compatible with our UUID definition). */ +typedef RTUUID APFSUUID; + +/** Maximum object checksum size. */ +#define APFS_OBJ_MAX_CHKSUM_SZ 8 + +/** + * APFS Object header. + */ +typedef struct APFSOBJPHYS +{ + /** The stored checksum of the object. */ + uint8_t abChkSum[APFS_OBJ_MAX_CHKSUM_SZ]; + /** Object ID. */ + APFSOID Oid; + /** Transaction ID. */ + APFSXID Xid; + /** Object type. */ + uint32_t u32Type; + /** Object sub type. */ + uint32_t u32SubType; +} APFSOBJPHYS; +/** Pointer to an APFS object header. */ +typedef APFSOBJPHYS *PAPFSOBJPHYS; +/** Pointer to a const APFS object header. */ +typedef const APFSOBJPHYS *PCAPFSOBJPHYS; + +#define APFS_OBJECT_TYPE_MASK UINT32_C(0x0000ffff) +#define APFS_OBJECT_TYPE_FLAGS_MASK UINT32_C(0xffff0000) + +/** + * APFS EFI jumpstart information. + */ +typedef struct APFSEFIJMPSTART +{ + /** Object header. */ + APFSOBJPHYS ObjHdr; + /** The magic value. */ + uint32_t u32Magic; + /** The version of the structure. */ + uint32_t u32Version; + /** EFI file length in bytes. */ + uint32_t cbEfiFile; + /** Number of extents describing the on disk blocks the file is stored in. */ + uint32_t cExtents; + /** Reserved. */ + uint64_t au64Rsvd0[16]; + /** After this comes a variable size of APFSPRANGE extent structures. */ +} APFSEFIJMPSTART; +/** Pointer to an APFS EFI jumpstart structure. */ +typedef APFSEFIJMPSTART *PAPFSEFIJMPSTART; +/** Pointer to a const APFS EFI jumpstart structure. */ +typedef const APFSEFIJMPSTART *PCAPFSEFIJMPSTART; + +/** EFI jumpstart magic ('RDSJ'). */ +#define APFS_EFIJMPSTART_MAGIC RT_MAKE_U32_FROM_U8('J', 'S', 'D', 'R') +/** EFI jumpstart version. */ +#define APFS_EFIJMPSTART_VERSION UINT32_C(1) + +/** Maximum number of filesystems supported in a single container. */ +#define APFS_NX_SUPERBLOCK_FS_MAX UINT32_C(100) +/** Maximum number of counters in the superblock. */ +#define APFS_NX_SUPERBLOCK_COUNTERS_MAX UINT32_C(32) +/** Number of entries in the ephemeral information array. */ +#define APFS_NX_SUPERBLOCK_EPH_INFO_COUNT UINT32_C(4) + +/** + * APFS super block. + */ +typedef struct +{ + /** Object header. */ + APFSOBJPHYS ObjHdr; + /** The magic value. */ + uint32_t u32Magic; + /** Block size in bytes. */ + uint32_t cbBlock; + /** Number of blocks in the volume. */ + uint64_t cBlocks; + /** Feature flags of the volume. */ + uint64_t fFeatures; + /** Readonly compatible features. */ + uint64_t fRdOnlyCompatFeatures; + /** Incompatible features. */ + uint64_t fIncompatFeatures; + /** UUID of the volume. */ + APFSUUID Uuid; + /** Next free object identifier to use for new objects. */ + APFSOID OidNext; + /** Next free transaction identifier to use for new transactions. */ + APFSOID XidNext; + /** Number of blocks used by the checkpoint descriptor area. */ + uint32_t cXpDescBlocks; + /** Number of blocks used by the checkpoint data area. */ + uint32_t cXpDataBlocks; + /** Base address of checkpoint descriptor area. */ + APFSPADDR PAddrXpDescBase; + /** Base address of checkpoint data area. */ + APFSPADDR PAddrXpDataBase; + /** Next index to use in the checkpoint descriptor area. */ + uint32_t idxXpDescNext; + /** Next index to use in the checkpoint data area. */ + uint32_t idxXpDataNext; + /** Number of blocks in the checkpoint descriptor area used by the checkpoint that this superblock belongs to. */ + uint32_t cXpDescLen; + /** Index of the first valid item in the checkpoint data area. */ + uint32_t idxXpDataFirst; + /** Number of blocks in the checkpoint data area used by the checkpoint that this superblock belongs to. */ + uint32_t cXpDataLen; + /** Ephemeral object identifer of the space manager. */ + APFSOID OidSpaceMgr; + /** Physical object identifier for the containers object map. */ + APFSOID OidOMap; + /** Ephemeral object identifer for the reaper. */ + APFSOID OidReaper; + /** Reserved for testing should be always zero on disk. */ + uint32_t u32TestType; + /** Maximum number of filesystems which can be stored in this container. */ + uint32_t cFsMax; + /** Array of filesystem object identifiers. */ + APFSOID aFsOids[APFS_NX_SUPERBLOCK_FS_MAX]; + /** Array of counters primarily used during debugging. */ + uint64_t aCounters[APFS_NX_SUPERBLOCK_COUNTERS_MAX]; + /** Range of blocks where no space will be allocated, used for shrinking a partition. */ + APFSPRANGE RangeBlocked; + /** Physical object identifier of a tree keeping track of objects needing to be moved out of the block range. */ + APFSOID OidTreeEvictMapping; + /** Container flags. */ + uint64_t fFlags; + /** Address of the EFI jumpstart structure. */ + APFSPADDR PAddrEfiJmpStart; + /** UUID of the containers Fusion set if available. */ + APFSUUID UuidFusion; + /** Address of the containers keybag. */ + APFSPADDR PAddrKeyLocker; + /** Array of fields used in the management of ephemeral data. */ + uint64_t au64EphemeralInfo[APFS_NX_SUPERBLOCK_EPH_INFO_COUNT]; + /** Reserved for testing. */ + APFSOID OidTest; + /** Physical object identifier of the Fusion middle tree. */ + APFSOID OidFusionMt; + /** Ephemeral object identifier of the Fusion write-back cache state. */ + APFSOID OidFusionWbc; + /** Blocks used for the Fusion write-back cache area. */ + APFSPRANGE RangeFusionWbc; +} APFSNXSUPERBLOCK; +/** Pointer to a APFS super block structure. */ +typedef APFSNXSUPERBLOCK *PAPFSNXSUPERBLOCK; +/** Pointer to a const APFS super block structure. */ +typedef const APFSNXSUPERBLOCK *PCAPFSNXSUPERBLOCK; + +/** Superblock magic value ('BSXN'). */ +#define APFS_NX_SUPERBLOCK_MAGIC RT_MAKE_U32_FROM_U8('N', 'X', 'S', 'B') + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_apfs_h */ + diff --git a/include/iprt/formats/asn1.h b/include/iprt/formats/asn1.h new file mode 100644 index 00000000..d1ba8f80 --- /dev/null +++ b/include/iprt/formats/asn1.h @@ -0,0 +1,107 @@ +/** @file + * IPRT - Abstract Syntax Notation One (ASN.1) Definitions. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_asn1_h +#define IPRT_INCLUDED_formats_asn1_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_rt_formats_asn1 ASN.1 definitions + * @ingroup grp_rt_formats + * + * @{ */ + +/** @name Tag classes. + * @{ */ +#define ASN1_TAGCLASS_UNIVERSAL UINT8_C(0x00) +#define ASN1_TAGCLASS_APPLICATION UINT8_C(0x40) +#define ASN1_TAGCLASS_CONTEXT UINT8_C(0x80) +#define ASN1_TAGCLASS_PRIVATE UINT8_C(0xc0) +#define ASN1_TAGCLASS_MASK UINT8_C(0xc0) +/** @} */ + +/** Primitive encoding. */ +#define ASN1_TAGFLAG_PRIMITIVE UINT8_C(0x00) +/** Constructed encoding, as opposed to primitive. */ +#define ASN1_TAGFLAG_CONSTRUCTED UINT8_C(0x20) + +/** The tag value mask. */ +#define ASN1_TAG_MASK UINT8_C(0x1f) + +/** @name ASN.1 universal tags. + * @{ */ +#define ASN1_TAG_EOC UINT8_C(0x00) +#define ASN1_TAG_BOOLEAN UINT8_C(0x01) +#define ASN1_TAG_INTEGER UINT8_C(0x02) +#define ASN1_TAG_BIT_STRING UINT8_C(0x03) +#define ASN1_TAG_OCTET_STRING UINT8_C(0x04) +#define ASN1_TAG_NULL UINT8_C(0x05) +#define ASN1_TAG_OID UINT8_C(0x06) +#define ASN1_TAG_OBJECT_DESCRIPTOR UINT8_C(0x07) +#define ASN1_TAG_EXTERNAL UINT8_C(0x08) +#define ASN1_TAG_REAL UINT8_C(0x09) +#define ASN1_TAG_ENUMERATED UINT8_C(0x0a) +#define ASN1_TAG_EMBEDDED_PDV UINT8_C(0x0b) +#define ASN1_TAG_UTF8_STRING UINT8_C(0x0c) +#define ASN1_TAG_RELATIVE_OID UINT8_C(0x0d) +#define ASN1_TAG_RESERVED_14 UINT8_C(0x0e) +#define ASN1_TAG_RESERVED_15 UINT8_C(0x0f) +#define ASN1_TAG_SEQUENCE UINT8_C(0x10) +#define ASN1_TAG_SET UINT8_C(0x11) +#define ASN1_TAG_NUMERIC_STRING UINT8_C(0x12) +#define ASN1_TAG_PRINTABLE_STRING UINT8_C(0x13) +#define ASN1_TAG_T61_STRING UINT8_C(0x14) +#define ASN1_TAG_VIDEOTEX_STRING UINT8_C(0x15) +#define ASN1_TAG_IA5_STRING UINT8_C(0x16) +#define ASN1_TAG_UTC_TIME UINT8_C(0x17) /**< Century seems to be 1900 if YY < 50, otherwise 2000. Baka ASN.1! */ +#define ASN1_TAG_GENERALIZED_TIME UINT8_C(0x18) +#define ASN1_TAG_GRAPHIC_STRING UINT8_C(0x19) +#define ASN1_TAG_VISIBLE_STRING UINT8_C(0x1a) +#define ASN1_TAG_GENERAL_STRING UINT8_C(0x1b) +#define ASN1_TAG_UNIVERSAL_STRING UINT8_C(0x1c) +#define ASN1_TAG_CHARACTER_STRING UINT8_C(0x1d) +#define ASN1_TAG_BMP_STRING UINT8_C(0x1e) +#define ASN1_TAG_USE_LONG_FORM UINT8_C(0x1f) +/** @} */ + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_asn1_h */ + diff --git a/include/iprt/formats/bmp.h b/include/iprt/formats/bmp.h new file mode 100644 index 00000000..1a1625df --- /dev/null +++ b/include/iprt/formats/bmp.h @@ -0,0 +1,192 @@ +/* $Id: bmp.h $ */ +/** @file + * IPRT - Microsoft Bitmap Formats (BMP). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_bmp_h +#define IPRT_INCLUDED_formats_bmp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_fmt_bmp Microsoft Bitmaps Formats (BMP) + * @ingroup grp_rt_formats + * @{ + */ + +/** @name BMP header sizes (in bytes). + * @{ */ +#define BMP_HDR_SIZE_FILE 14 +#define BMP_HDR_SIZE_OS21 12 +#define BMP_HDR_SIZE_OS22 64 +#define BMP_HDR_SIZE_WIN3X 40 +/** @} */ + + +/** BMP format file header. */ +#pragma pack(1) +typedef struct BMPFILEHDR +{ + /** File type identifier ("magic"). */ + uint16_t uType; + /** Size of file in bytes. */ + uint32_t cbFileSize; + /** Reserved (should be 0). */ + uint16_t Reserved1; + /** Reserved (should be 0). */ + uint16_t Reserved2; + /** Offset (in bytes) to bitmap data. */ + uint32_t offBits; +} BMPFILEHDR; +#pragma pack() +AssertCompileSize(BMPFILEHDR, BMP_HDR_SIZE_FILE); +/** Pointer to a BMP format file header. */ +typedef BMPFILEHDR *PBMPFILEHDR; + +/** BMP file magic number for BMP / DIB. */ +#define BMP_HDR_MAGIC (RT_H2LE_U16_C(0x4d42)) + +/** OS/2 1.x BMP core header, + * also known as BITMAPCOREHEADER. */ +typedef struct BMPOS2COREHDR +{ + /** Size (in bytes) of remaining header. */ + uint32_t cbSize; + /** Width of bitmap in pixels. */ + uint16_t uWidth; + /** Height of bitmap in pixels. */ + uint16_t uHeight; + /** Number of planes. */ + uint16_t cPlanes; + /** Color bits per pixel. */ + uint16_t cBits; +} BMPOS2COREHDR; +AssertCompileSize(BMPOS2COREHDR, BMP_HDR_SIZE_OS21); +/** Pointer to a OS/2 1.x BMP core header. */ +typedef BMPOS2COREHDR *PBMPOS2COREHDR; + +/** OS/2 2.0 BMP core header, version 2, + * also known as BITMAPCOREHEADER2. */ +typedef struct BMPOS2COREHDR2 +{ + /** Size (in bytes) of remaining header. */ + uint32_t cbSize; + /** Width of bitmap in pixels. */ + uint32_t uWidth; + /** Height of bitmap in pixels. */ + uint32_t uHeight; + /** Number of planes. */ + uint16_t cPlanes; + /** Color bits per pixel. */ + uint16_t cBits; + /** Compression scheme of type BMP_COMPRESSION_TYPE. */ + uint32_t enmCompression; + /** Size of bitmap in bytes. */ + uint32_t cbSizeImage; + /** Horz. resolution in pixels/meter. */ + uint32_t uXPelsPerMeter; + /** Vert. resolution in pixels/meter. */ + uint32_t uYPelsPerMeter; + /** Number of colors in color table. */ + uint32_t cClrUsed; + /** Number of important colors. */ + uint32_t cClrImportant; + /** Resolution measurement Used. */ + uint16_t uUnits; + /** Reserved fields (always 0). */ + uint16_t Reserved; + /** Orientation of bitmap. */ + uint16_t uRecording; + /** Halftone algorithm used on image. */ + uint16_t enmHalftone; + /** Halftone algorithm data. */ + uint32_t uHalftoneParm1; + /** Halftone algorithm data. */ + uint32_t uHalftoneParm2; + /** Color table format (always 0). */ + uint32_t uColorEncoding; + /** Misc. field for application use . */ + uint32_t uIdentifier; +} BMPOS2COREHDR2; +AssertCompileSize(BMPOS2COREHDR2, BMP_HDR_SIZE_OS22); +/** Pointer to an OS/2 2.0 BMP core header version 2. */ +typedef BMPOS2COREHDR2 *PBMPOS2COREHDR2; + +/** Windows 3.x BMP information header Format. */ +typedef struct BMPWIN3XINFOHDR +{ + /** Size (in bytes) of remaining header. */ + uint32_t cbSize; + /** Width of bitmap in pixels. */ + uint32_t uWidth; + /** Height of bitmap in pixels. */ + uint32_t uHeight; + /** Number of planes. */ + uint16_t cPlanes; + /** Color bits per pixel. */ + uint16_t cBits; + /** Compression scheme of type BMP_COMPRESSION_TYPE. */ + uint32_t enmCompression; + /** Size of bitmap in bytes. */ + uint32_t cbSizeImage; + /** Horz. resolution in pixels/meter. */ + uint32_t uXPelsPerMeter; + /** Vert. resolution in pixels/meter. */ + uint32_t uYPelsPerMeter; + /** Number of colors in color table. */ + uint32_t cClrUsed; + /** Number of important colors. */ + uint32_t cClrImportant; +} BMPWIN3XINFOHDR; +AssertCompileSize(BMPWIN3XINFOHDR, BMP_HDR_SIZE_WIN3X); +/** Pointer to a Windows 3.x BMP information header. */ +typedef BMPWIN3XINFOHDR *PBMPWIN3XINFOHDR; + + + +/** @name BMP compression types. + * @{ */ +#define BMP_COMPRESSION_TYPE_NONE 0 +#define BMP_COMPRESSION_TYPE_RLE8 1 +#define BMP_COMPRESSION_TYPE_RLE4 2 +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_bmp_h */ + diff --git a/include/iprt/formats/codeview.h b/include/iprt/formats/codeview.h new file mode 100644 index 00000000..f8cf66ab --- /dev/null +++ b/include/iprt/formats/codeview.h @@ -0,0 +1,870 @@ +/** @file + * IPRT - Microsoft CodeView Debug Information. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_codeview_h +#define IPRT_INCLUDED_formats_codeview_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#include + + +/** @defgroup grp_rt_fmt_codeview Microsoft CodeView Debug Information + * @{ + */ + + +/** + * CodeView Header. There are two of this, base header at the start of the debug + * information and a trailing header at the end. + */ +typedef struct RTCVHDR +{ + /** The magic ('NBxx'), see RTCVHDR_MAGIC_XXX. */ + uint32_t u32Magic; + /** + * Base header: Subsection directory offset relative to this header (start). + * Trailing header: Offset of the base header relative to the end of the file. + * + * Called lfoBase, lfaBase, lfoDirectory, lfoDir and probably other things in + * the various specs/docs available. */ + uint32_t off; +} RTCVHDR; +/** Pointer to a CodeView header. */ +typedef RTCVHDR *PRTCVHDR; + +/** @name CodeView magic values (RTCVHDR::u32Magic). + * @{ */ +/** CodeView from Visual C++ 5.0. Specified in the 2001 MSDN specs.chm file. */ +#define RTCVHDR_MAGIC_NB11 RT_MAKE_U32_FROM_U8('N', 'B', '1', '1') +/** External PDB reference (often referred to as PDB 2.0). */ +#define RTCVHDR_MAGIC_NB10 RT_MAKE_U32_FROM_U8('N', 'B', '1', '0') +/** CodeView v4.10, packed. Specified in the TIS document. */ +#define RTCVHDR_MAGIC_NB09 RT_MAKE_U32_FROM_U8('N', 'B', '0', '9') +/** CodeView v4.00 thru v4.05. Specified in the TIS document? */ +#define RTCVHDR_MAGIC_NB08 RT_MAKE_U32_FROM_U8('N', 'B', '0', '8') +/** Quick C for Windows 1.0 debug info. */ +#define RTCVHDR_MAGIC_NB07 RT_MAKE_U32_FROM_U8('N', 'B', '0', '7') +/** Emitted by ILINK indicating incremental link. Comparable to NB05? */ +#define RTCVHDR_MAGIC_NB06 RT_MAKE_U32_FROM_U8('N', 'B', '0', '6') +/** Emitted by LINK version 5.20 and later before packing. */ +#define RTCVHDR_MAGIC_NB05 RT_MAKE_U32_FROM_U8('N', 'B', '0', '5') +/** Emitted by IBM ILINK for HLL (similar to NB02 in many ways). */ +#define RTCVHDR_MAGIC_NB04 RT_MAKE_U32_FROM_U8('N', 'B', '0', '4') +/** Emitted by LINK version 5.10 (or similar OMF linkers), as shipped with + * Microsoft C v6.0 for example. More or less entirely 16-bit. */ +#define RTCVHDR_MAGIC_NB02 RT_MAKE_U32_FROM_U8('N', 'B', '0', '2') +/* No idea what NB03 might have been. */ +/** AIX debugger format according to "IBM OS/2 16/32-bit Object Module Format + * (OMF) and Linear eXecutable Module Format (LX)" revision 10 (LXOMF.PDF). */ +#define RTCVHDR_MAGIC_NB01 RT_MAKE_U32_FROM_U8('N', 'B', '0', '1') +/** Ancient CodeView format according to LXOMF.PDF. */ +#define RTCVHDR_MAGIC_NB00 RT_MAKE_U32_FROM_U8('N', 'B', '0', '0') +/** @} */ + + +/** @name CV directory headers. + * @{ */ + +/** + * Really old CV directory header used with NB00 and NB02. + * + * Uses 16-bit directory entires (RTCVDIRENT16). + */ +typedef struct RTCVDIRHDR16 +{ + /** The number of directory entries. */ + uint16_t cEntries; +} RTCVDIRHDR16; +/** Pointer to a old CV directory header. */ +typedef RTCVDIRHDR16 *PRTCVDIRHDR16; + +/** + * Simple 32-bit CV directory base header, used by NB04 (aka IBM HLL). + */ +typedef struct RTCVDIRHDR32 +{ + /** The number of bytes of this header structure. */ + uint16_t cbHdr; + /** The number of bytes per entry. */ + uint16_t cbEntry; + /** The number of directory entries. */ + uint32_t cEntries; +} RTCVDIRHDR32; +/** Pointer to a 32-bit CV directory header. */ +typedef RTCVDIRHDR32 *PRTCVDIRHDR32; + +/** + * Extended 32-bit CV directory header as specified in the TIS doc. + * The two extra fields seems to never have been assigned any official purpose. + */ +typedef struct RTCVDIRHDR32EX +{ + /** This starts the same way as the NB04 header. */ + RTCVDIRHDR32 Core; + /** Tentatively decleared as the offset to the next directory generated by + * the incremental linker. Haven't seen this used yet. */ + uint32_t offNextDir; + /** Flags, non defined apparently, so MBZ. */ + uint32_t fFlags; +} RTCVDIRHDR32EX; +/** Pointer to an extended 32-bit CV directory header. */ +typedef RTCVDIRHDR32EX *PRTCVDIRHDR32EX; + +/** @} */ + + +/** + * 16-bit CV directory entry used with NB00 and NB02. + */ +typedef struct RTCVDIRENT16 +{ + /** Subsection type (RTCVSST). */ + uint16_t uSubSectType; + /** Which module (1-based, 0xffff is special). */ + uint16_t iMod; + /** The lowe offset of this subsection relative to the base CV header. */ + uint16_t offLow; + /** The high part of the subsection offset. */ + uint16_t offHigh; + /** The size of the subsection. */ + uint16_t cb; +} RTCVDIRENT16; +AssertCompileSize(RTCVDIRENT16, 10); +/** Pointer to a 16-bit CV directory entry. */ +typedef RTCVDIRENT16 *PRTCVDIRENT16; + + +/** + * 32-bit CV directory entry used starting with NB04. + */ +typedef struct RTCVDIRENT32 +{ + /** Subsection type (RTCVSST). */ + uint16_t uSubSectType; + /** Which module (1-based, 0xffff is special). */ + uint16_t iMod; + /** The offset of this subsection relative to the base CV header. */ + uint32_t off; + /** The size of the subsection. */ + uint32_t cb; +} RTCVDIRENT32; +AssertCompileSize(RTCVDIRENT32, 12); +/** Pointer to a 32-bit CV directory entry. */ +typedef RTCVDIRENT32 *PRTCVDIRENT32; +/** Pointer to a const 32-bit CV directory entry. */ +typedef RTCVDIRENT32 const *PCRTCVDIRENT32; + + +/** + * CodeView subsection types. + */ +typedef enum RTCVSST +{ + /** @name NB00, NB02 and NB04 subsection types. + * The actual format of each subsection varies between NB04 and the others, + * and it may further vary in NB04 depending on the module type. + * @{ */ + kCvSst_OldModule = 0x101, + kCvSst_OldPublic, + kCvSst_OldTypes, + kCvSst_OldSymbols, + kCvSst_OldSrcLines, + kCvSst_OldLibraries, + kCvSst_OldImports, + kCvSst_OldCompacted, + kCvSst_OldSrcLnSeg = 0x109, + kCvSst_OldSrcLines3 = 0x10b, + /** @} */ + + /** @name NB09, NB11 (and possibly NB05, NB06, NB07, and NB08) subsection types. + * @{ */ + kCvSst_Module = 0x120, + kCvSst_Types, + kCvSst_Public, + kCvSst_PublicSym, + kCvSst_Symbols, + kCvSst_AlignSym, + kCvSst_SrcLnSeg, + kCvSst_SrcModule, + kCvSst_Libraries, + kCvSst_GlobalSym, + kCvSst_GlobalPub, + kCvSst_GlobalTypes, + kCvSst_MPC, + kCvSst_SegMap, + kCvSst_SegName, + kCvSst_PreComp, + kCvSst_PreCompMap, + kCvSst_OffsetMap16, + kCvSst_OffsetMap32, + kCvSst_FileIndex = 0x133, + kCvSst_StaticSym + /** @} */ +} RTCVSST; +/** Pointer to a CV subsection type value. */ +typedef RTCVSST *PRTCVSST; +/** Pointer to a const CV subsection type value. */ +typedef RTCVSST const *PCRTCVSST; + + +/** + * CV4 module segment info. + */ +typedef struct RTCVMODSEGINFO32 +{ + /** The segment number. */ + uint16_t iSeg; + /** Explicit padding. */ + uint16_t u16Padding; + /** Offset into the segment. */ + uint32_t off; + /** The size of the contribution. */ + uint32_t cb; +} RTCVMODSEGINFO32; +typedef RTCVMODSEGINFO32 *PRTCVMODSEGINFO32; +typedef RTCVMODSEGINFO32 const *PCRTCVMODSEGINFO32; + + +/** + * CV4 segment map header. + */ +typedef struct RTCVSEGMAPHDR +{ + /** Number of segments descriptors in the table. */ + uint16_t cSegs; + /** Number of logical segment descriptors. */ + uint16_t cLogSegs; +} RTCVSEGMAPHDR; +/** Pointer to a CV4 segment map header. */ +typedef RTCVSEGMAPHDR *PRTCVSEGMAPHDR; +/** Pointer to a const CV4 segment map header. */ +typedef RTCVSEGMAPHDR const *PCRTCVSEGMAPHDR; + +/** + * CV4 Segment map descriptor entry. + */ +typedef struct RTCVSEGMAPDESC +{ + /** Segment flags. */ + uint16_t fFlags; + /** The overlay number. */ + uint16_t iOverlay; + /** Group index into this segment descriptor array. 0 if not relevant. + * The group descriptors are found in the second half of the table. */ + uint16_t iGroup; + /** Complicated. */ + uint16_t iFrame; + /** Offset (byte) into the kCvSst_SegName table of the segment name, or + * 0xffff. */ + uint16_t offSegName; + /** Offset (byte) into the kCvSst_SegName table of the class name, or 0xffff. */ + uint16_t offClassName; + /** Offset into the physical segment. */ + uint32_t off; + /** Size of segment. */ + uint32_t cb; +} RTCVSEGMAPDESC; +/** Pointer to a segment map descriptor entry. */ +typedef RTCVSEGMAPDESC *PRTCVSEGMAPDESC; +/** Pointer to a const segment map descriptor entry. */ +typedef RTCVSEGMAPDESC const *PCRTCVSEGMAPDESC; + +/** @name RTCVSEGMAPDESC_F_XXX - RTCVSEGMAPDESC::fFlags values. + * @{ */ +#define RTCVSEGMAPDESC_F_READ UINT16_C(0x0001) +#define RTCVSEGMAPDESC_F_WRITE UINT16_C(0x0002) +#define RTCVSEGMAPDESC_F_EXECUTE UINT16_C(0x0004) +#define RTCVSEGMAPDESC_F_32BIT UINT16_C(0x0008) +#define RTCVSEGMAPDESC_F_SEL UINT16_C(0x0100) +#define RTCVSEGMAPDESC_F_ABS UINT16_C(0x0200) +#define RTCVSEGMAPDESC_F_GROUP UINT16_C(0x1000) +#define RTCVSEGMAPDESC_F_RESERVED UINT16_C(0xecf0) +/** @} */ + +/** + * CV4 segment map subsection. + */ +typedef struct RTCVSEGMAP +{ + /** The header. */ + RTCVSEGMAPHDR Hdr; + /** Descriptor array. */ + RTCVSEGMAPDESC aDescs[1]; +} RTCVSEGMAP; +/** Pointer to a segment map subsection. */ +typedef RTCVSEGMAP *PRTCVSEGMAP; +/** Pointer to a const segment map subsection. */ +typedef RTCVSEGMAP const *PCRTCVSEGMAP; + + +/** + * CV4 line number segment contribution start/end table entry. + * Part of RTCVSRCMODULE. + */ +typedef struct RTCVSRCRANGE +{ + /** Start segment offset. */ + uint32_t offStart; + /** End segment offset (inclusive?). */ + uint32_t offEnd; +} RTCVSRCRANGE; +/** Pointer to a line number segment contributation. */ +typedef RTCVSRCRANGE *PRTCVSRCRANGE; +/** Pointer to a const line number segment contributation. */ +typedef RTCVSRCRANGE const *PCRTCVSRCRANGE; + +/** + * CV4 header for a line number subsection, used by kCvSst_SrcModule. + * + * The aoffSrcFiles member is followed by an array of segment ranges + * (RTCVSRCRANGE), cSegs in length. This may contain zero entries if the + * information is not known or not possible to express in this manner. + * + * After the range table, a segment index (uint16_t) mapping table follows, also + * cSegs in length. + */ +typedef struct RTCVSRCMODULE +{ + /** The number of files described in this subsection. */ + uint16_t cFiles; + /** The number of code segments this module contributes to. */ + uint16_t cSegs; + /** Offsets of the RTCVSRCFILE entries in this subsection, length given by + * the above cFiles member. */ + uint32_t aoffSrcFiles[1 /*cFiles*/]; + /* RTCVSRCRANGE aSegRanges[cSegs]; */ + /* uint16_t aidxSegs[cSegs]; */ +} RTCVSRCMODULE; +/** Pointer to a source module subsection header. */ +typedef RTCVSRCMODULE *PRTCVSRCMODULE; +/** Pointer to a const source module subsection header. */ +typedef RTCVSRCMODULE const *PCRTCVSRCMODULE; + +/** + * CV4 source file, inside a kCvSst_SrcModule (see RTCVSRCMODULE::aoffSrcFiles) + * + * The aoffSrcLines member is followed by an array of segment ranges + * (RTCVSRCRANGE), cSegs in length. Just like for RTCVSRCMODULE this may + * contain zero entries. + * + * After the range table is the filename, which is preceeded by a 8-bit length + * (actually documented to be 16-bit, but seeing 8-bit here with wlink). + */ +typedef struct RTCVSRCFILE +{ + /** The number segments that this source file contributed to. */ + uint16_t cSegs; + /** Alignment padding. */ + uint16_t uPadding; + /** Offsets of the RTCVSRCLN entries for this source file, length given by + * the above cSegs member. Relative to the start of the subsection. */ + uint32_t aoffSrcLines[1 /*cSegs*/]; + /* RTCVSRCRANGE aSegRanges[cSegs]; */ + /* uint8_t/uint16_t cchName; */ + /* char achName[cchName]; */ +} RTCVSRCFILE; +/** Pointer to a source file. */ +typedef RTCVSRCFILE *PRTCVSRCFILE; +/** Pointer to a const source file. */ +typedef RTCVSRCFILE const *PCRTCVSRCFILE; + +/** + * CV4 line numbers header. + * + * The aoffLines member is followed by an array of line numbers (uint16_t). + */ +typedef struct RTCVSRCLINE +{ + /** The index of the segment these line numbers belong to. */ + uint16_t idxSeg; + /** The number of line number pairs the two following tables. */ + uint16_t cPairs; + /** Segment offsets, cPairs long. */ + uint32_t aoffLines[1 /*cPairs*/]; + /* uint16_t aiLines[cPairs]; */ +} RTCVSRCLINE; +/** Pointer to a line numbers header. */ +typedef RTCVSRCLINE *PRTCVSRCLINE; +/** Pointer to a const line numbers header. */ +typedef RTCVSRCLINE const *PCRTCVSRCLINE; + + +/** + * Global symbol table header, used by kCvSst_GlobalSym and kCvSst_GlobalPub. + */ +typedef struct RTCVGLOBALSYMTABHDR +{ + /** The symbol hash function. */ + uint16_t uSymHash; + /** The address hash function. */ + uint16_t uAddrHash; + /** The amount of symbol information following immediately after the header. */ + uint32_t cbSymbols; + /** The amount of symbol hash tables following the symbols. */ + uint32_t cbSymHash; + /** The amount of address hash tables following the symbol hash tables. */ + uint32_t cbAddrHash; +} RTCVGLOBALSYMTABHDR; +/** Pointer to a global symbol table header. */ +typedef RTCVGLOBALSYMTABHDR *PRTCVGLOBALSYMTABHDR; +/** Pointer to a const global symbol table header. */ +typedef RTCVGLOBALSYMTABHDR const *PCRTCVGLOBALSYMTABHDR; + + +typedef enum RTCVSYMTYPE +{ + /** @name Symbols that doesn't change with compilation model or target machine. + * @{ */ + kCvSymType_Compile = 0x0001, + kCvSymType_Register, + kCvSymType_Constant, + kCvSymType_UDT, + kCvSymType_SSearch, + kCvSymType_End, + kCvSymType_Skip, + kCvSymType_CVReserve, + kCvSymType_ObjName, + kCvSymType_EndArg, + kCvSymType_CobolUDT, + kCvSymType_ManyReg, + kCvSymType_Return, + kCvSymType_EntryThis, + /** @} */ + + /** @name Symbols with 16:16 addresses. + * @{ */ + kCvSymType_BpRel16 = 0x0100, + kCvSymType_LData16, + kCvSymType_GData16, + kCvSymType_Pub16, + kCvSymType_LProc16, + kCvSymType_GProc16, + kCvSymType_Thunk16, + kCvSymType_BLock16, + kCvSymType_With16, + kCvSymType_Label16, + kCvSymType_CExModel16, + kCvSymType_VftPath16, + kCvSymType_RegRel16, + /** @} */ + + /** @name Symbols with 16:32 addresses. + * @{ */ + kCvSymType_BpRel32 = 0x0200, + kCvSymType_LData32, + kCvSymType_GData32, + kCvSymType_Pub32, + kCvSymType_LProc32, + kCvSymType_GProc32, + kCvSymType_Thunk32, + kCvSymType_Block32, + kCvSymType_With32, + kCvSymType_Label32, + kCvSymType_CExModel32, + kCvSymType_VftPath32, + kCvSymType_RegRel32, + kCvSymType_LThread32, + kCvSymType_GThread32, + /** @} */ + + /** @name Symbols for MIPS. + * @{ */ + kCvSymType_LProcMips = 0x0300, + kCvSymType_GProcMips, + /** @} */ + + /** @name Symbols for Microsoft CodeView. + * @{ */ + kCvSymType_ProcRef = 0x0400, + kCvSymType_DataRef, + kCvSymType_Align, + kCvSymType_LProcRef, + /** @} */ + + /** @name Symbols with 32-bit address (I think) and 32-bit type indices. + * @{ */ + kCvSymType_V2_Register = 0x1001, + kCvSymType_V2_Constant, + kCvSymType_V2_Udt, + kCvSymType_V2_CobolUdt, + kCvSymType_V2_ManyReg, + kCvSymType_V2_BpRel, + kCvSymType_V2_LData, + kCvSymType_V2_GData, + kCvSymType_V2_Pub, + kCvSymType_V2_LProc, + kCvSymType_V2_GProc, + kCvSymType_V2_VftTable, + kCvSymType_V2_RegRel, + kCvSymType_V2_LThread, + kCvSymType_V2_GThread, + kCvSymType_V2_Unknown_1010, + kCvSymType_V2_Unknown_1011, + kCvSymType_V2_FrameInfo, + kCvSymType_V2_Compliand, + /** @} */ + + /** @name Version 3 symbol types. + * @{ */ + /** Name of the object file, preceded by a 4-byte language type (ASM=0) */ + kCvSymType_V3_Compliand = 0x1101, + kCvSymType_V3_Thunk, + kCvSymType_V3_Block, + kCvSymType_V3_Unknown_1104, + kCvSymType_V3_Label, /**< RTCVSYMV3LABEL */ + kCvSymType_V3_Register, + kCvSymType_V3_Constant, + kCvSymType_V3_Udt, + kCvSymType_V3_Unknown_1109, + kCvSymType_V3_Unknown_110a, + kCvSymType_V3_BpRel, + kCvSymType_V3_LData, /**< RTCVSYMV3TYPEDNAME */ + kCvSymType_V3_GData, /**< RTCVSYMV3TYPEDNAME */ + kCvSymType_V3_Pub, + kCvSymType_V3_LProc, + kCvSymType_V3_GProc, + kCvSymType_V3_RegRel, + kCvSymType_V3_LThread, + kCvSymType_V3_GThread, + kCvSymType_V3_Unknown_1114, + kCvSymType_V3_Unknown_1115, + kCvSymType_V3_MSTool, /**< RTCVSYMV3MSTOOL */ + + kCvSymType_V3_PubFunc1 = 0x1125, + kCvSymType_V3_PubFunc2 = 0x1127, + kCvSymType_V3_SectInfo = 0x1136, + kCvSymType_V3_SubSectInfo, + kCvSymType_V3_Entrypoint, + kCvSymType_V3_Unknown_1139, + kCvSymType_V3_SecuCookie, + kCvSymType_V3_Unknown_113b, + kCvSymType_V3_MsToolInfo, + kCvSymType_V3_MsToolEnv, + + kCvSymType_VS2013_Local, + kCvSymType_VS2013_FpOff = 0x1144, + kCvSymType_VS2013_LProc32 = 0x1146, + kCvSymType_VS2013_GProc32, + /** @} */ + + kCvSymType_EndOfValues +} RTCVSYMTYPE; +AssertCompile(kCvSymType_V3_Udt == 0x1108); +AssertCompile(kCvSymType_V3_GProc == 0x1110); +AssertCompile(kCvSymType_V3_MSTool == 0x1116); +AssertCompile(kCvSymType_VS2013_Local == 0x113E); +typedef RTCVSYMTYPE *PRTCVSYMTYPE; +typedef RTCVSYMTYPE const *PCRTCVSYMTYPE; + + +/** + * kCvSymType_V3_MSTool format. + */ +typedef struct RTCVSYMV3MSTOOL +{ + /** Language or tool ID (3 == masm). */ + uint32_t uLanguage; + /** Target CPU (0xd0 == AMD64). */ + uint32_t uTargetCpu; + /** Flags. */ + uint32_t fFlags; + /** Version. */ + uint32_t uVersion; + /** The creator name, zero terminated. + * + * It is followed by key/value pairs of zero terminated strings giving more + * details about the current directory ('cwd'), compiler executable ('cl'), + * full command line ('cmd'), source path relative to cwd ('src'), the + * full program database path ('pdb'), and possibly others. Terminated by a + * pair of empty strings, usually. */ + char szCreator[1]; +} RTCVSYMV3MSTOOL; +typedef RTCVSYMV3MSTOOL *PRTCVSYMV3MSTOOL; +typedef RTCVSYMV3MSTOOL const *PCRTCVSYMV3MSTOOL; + +/** + * kCvSymType_V3_Label format. + */ +typedef struct RTCVSYMV3LABEL +{ + /** Offset into iSection of this symbol. */ + uint32_t offSection; + /** The index of the section where the symbol lives. */ + uint16_t iSection; + /** Flags or something. */ + uint8_t fFlags; + /** Zero terminated symbol name (variable length). */ + char szName[1]; +} RTCVSYMV3LABEL; +AssertCompileSize(RTCVSYMV3LABEL, 8); +typedef RTCVSYMV3LABEL *PRTCVSYMV3LABEL; +typedef RTCVSYMV3LABEL const *PCRTCVSYMV3LABEL; + +/** + * kCvSymType_V3_LData and kCvSymType_V3_GData format. + */ +typedef struct RTCVSYMV3TYPEDNAME +{ + /** The type ID. */ + uint32_t idType; + /** Offset into iSection of this symbol. */ + uint32_t offSection; + /** The index of the section where the symbol lives. */ + uint16_t iSection; + /** Zero terminated symbol name (variable length). */ + char szName[2]; +} RTCVSYMV3TYPEDNAME; +AssertCompileSize(RTCVSYMV3TYPEDNAME, 12); +typedef RTCVSYMV3TYPEDNAME *PRTCVSYMV3TYPEDNAME; +typedef RTCVSYMV3TYPEDNAME const *PCRTCVSYMV3TYPEDNAME; + +/** + * kCvSymType_V3_LProc and kCvSymType_V3_GProc format. + */ +typedef struct RTCVSYMV3PROC +{ + /** Lexical scope linking: Parent. */ + uint32_t uParent; + /** Lexical scope linking: End. */ + uint32_t uEnd; + /** Lexical scope linking: Next. */ + uint32_t uNext; + /** The procedure length. */ + uint32_t cbProc; + /** Offset into the procedure where the stack frame has been setup and is an + * excellent position for a function breakpoint. */ + uint32_t offDebugStart; + /** Offset into the procedure where the procedure is ready to return and has a + * return value (if applicable). */ + uint32_t offDebugEnd; + /** The type ID for the procedure. */ + uint32_t idType; + /** Offset into iSection of this procedure. */ + uint32_t offSection; + /** The index of the section where the procedure lives. */ + uint16_t iSection; + /** Flags. */ + uint8_t fFlags; + /** Zero terminated procedure name (variable length). */ + char szName[1]; +} RTCVSYMV3PROC; +AssertCompileSize(RTCVSYMV3PROC, 36); +typedef RTCVSYMV3PROC *PRTCVSYMV3PROC; +typedef RTCVSYMV3PROC const *PCRTCVSYMV3PROC; + + +/** @name $$SYMBOLS signatures. + * @{ */ +/** The $$SYMBOL table signature for CV4. */ +#define RTCVSYMBOLS_SIGNATURE_CV4 UINT32_C(0x00000001) +/** The $$SYMBOL table signature for CV8 (MSVC 8/2005). + * Also seen with MSVC 2010 using -Z7, so maybe more appropriate to call it + * CV7? */ +#define RTCVSYMBOLS_SIGNATURE_CV8 UINT32_C(0x00000004) +/** @} */ + + +/** + * CV8 $$SYMBOLS block header. + */ +typedef struct RTCV8SYMBOLSBLOCK +{ + /** BLock type (RTCV8SYMBLOCK_TYPE_XXX). */ + uint32_t uType; + /** The block length, including this header? */ + uint32_t cb; +} RTCV8SYMBOLSBLOCK; +AssertCompileSize(RTCV8SYMBOLSBLOCK, 8); +typedef RTCV8SYMBOLSBLOCK *PRTCV8SYMBOLSBLOCK; +typedef RTCV8SYMBOLSBLOCK const *PCRTCV8SYMBOLSBLOCK; + +/** @name RTCV8SYMBLOCK_TYPE_XXX - CV8 (MSVC 8/2005) $$SYMBOL table types. + * @{ */ +/** Symbol information. + * Sequence of types. Each type entry starts with a 16-bit length followed + * by a 16-bit RTCVSYMTYPE value. Just like CV4/5, but with C-strings + * instead of pascal. */ +#define RTCV8SYMBLOCK_TYPE_SYMBOLS UINT32_C(0x000000f1) +/** Line numbers for a section. */ +#define RTCV8SYMBLOCK_TYPE_SECT_LINES UINT32_C(0x000000f2) +/** Source file string table. + * The strings are null terminated. Indexed by RTCV8SYMBLOCK_TYPE_SRC_INFO. */ +#define RTCV8SYMBLOCK_TYPE_SRC_STR UINT32_C(0x000000f3) +/** Source file information. */ +#define RTCV8SYMBLOCK_TYPE_SRC_INFO UINT32_C(0x000000f4) +/** @} */ + +/** + * Line number header found in a RTCV8SYMBLOCK_TYPE_SECT_LINES block. + * + * This is followed by a sequence of RTCV8LINESSRCMAP structures. + */ +typedef struct RTCV8LINESHDR +{ + /** Offset into the section. */ + uint32_t offSection; + /** The section number. */ + uint16_t iSection; + /** Padding/zero/maybe-previous-member-is-a-32-bit-value. */ + uint16_t u16Padding; + /** Number of bytes covered by this table, starting at offSection. */ + uint32_t cbSectionCovered; +} RTCV8LINESHDR; +AssertCompileSize(RTCV8LINESHDR, 12); +typedef RTCV8LINESHDR *PRTCV8LINESHDR; +typedef RTCV8LINESHDR const *PCRTCV8LINESHDR; + +/** + * CV8 (MSVC 8/2005) line number source map. + * + * This is followed by an array of RTCV8LINEPAIR. + */ +typedef struct RTCV8LINESSRCMAP +{ + /** The source file, given as an offset (byte) into the source file + * information table (RTCV8SYMBLOCK_TYPE_SRC_INFO). */ + uint32_t offSourceInfo; + /** Number of line numbers following this structure. */ + uint32_t cLines; + /** The size of this source map. */ + uint32_t cb; +} RTCV8LINESSRCMAP; +AssertCompileSize(RTCV8LINESSRCMAP, 12); +typedef RTCV8LINESSRCMAP *PRTCV8LINESSRCMAP; +typedef RTCV8LINESSRCMAP const *PCRTCV8LINESSRCMAP; + +/** + * One line number. + */ +typedef struct RTCV8LINEPAIR +{ + /** Offset into the section of this line number. */ + uint32_t offSection; + /** The line number. */ + uint32_t uLineNumber : 30; + /** Indicates that it's not possible to set breakpoint? */ + uint32_t fEndOfStatement : 1; +} RTCV8LINEPAIR; +AssertCompileSize(RTCV8LINEPAIR, 8); +typedef RTCV8LINEPAIR *PRTCV8LINEPAIR; +typedef RTCV8LINEPAIR const *PCRTCV8LINEPAIR; + +/** + * Source file information found in a RTCV8SYMBLOCK_TYPE_SRC_INFO block. + */ +typedef struct RTCV8SRCINFO +{ + /** The source file name, given as an offset into the string table + * (RTCV8SYMBLOCK_TYPE_SRC_STR). */ + uint32_t offSourceName; + /** Digest/checksum type. */ + uint16_t uDigestType; + union + { + /** RTCV8SRCINFO_DIGEST_TYPE_MD5. */ + struct + { + /** The digest. */ + uint8_t ab[16]; + /** Structur alignment padding. */ + uint8_t abPadding[2]; + } md5; + /** RTCV8SRCINFO_DIGEST_TYPE_NONE: Padding. */ + uint8_t abNone[2]; + } Digest; +} RTCV8SRCINFO; +AssertCompileSize(RTCV8SRCINFO, 24); +typedef RTCV8SRCINFO *PRTCV8SRCINFO; +typedef RTCV8SRCINFO const *PCRTCV8SRCINFO; + +/** @name RTCV8SRCINFO_DIGEST_TYPE_XXX - CV8 source digest types. + * Used by RTCV8SRCINFO::uDigestType. + * @{ */ +#define RTCV8SRCINFO_DIGEST_TYPE_NONE UINT16_C(0x0000) +#define RTCV8SRCINFO_DIGEST_TYPE_MD5 UINT16_C(0x0110) +/** @} */ + + + +/** + * PDB v2.0 in image debug info. + * The URL is constructed from the timestamp and age? + */ +typedef struct CVPDB20INFO +{ + uint32_t u32Magic; /**< CVPDB20INFO_SIGNATURE. */ + int32_t offDbgInfo; /**< Always 0. Used to be the offset to the real debug info. */ + uint32_t uTimestamp; + uint32_t uAge; + uint8_t szPdbFilename[4]; +} CVPDB20INFO; +/** Pointer to in executable image PDB v2.0 info. */ +typedef CVPDB20INFO *PCVPDB20INFO; +/** Pointer to read only in executable image PDB v2.0 info. */ +typedef CVPDB20INFO const *PCCVPDB20INFO; +/** The CVPDB20INFO magic value. */ +#define CVPDB20INFO_MAGIC RT_MAKE_U32_FROM_U8('N','B','1','0') + +/** + * PDB v7.0 in image debug info. + * The URL is constructed from the signature and the age. + */ +#pragma pack(4) +typedef struct CVPDB70INFO +{ + uint32_t u32Magic; /**< CVPDB70INFO_SIGNATURE. */ + RTUUID PdbUuid; + uint32_t uAge; + uint8_t szPdbFilename[4]; +} CVPDB70INFO; +#pragma pack() +AssertCompileMemberOffset(CVPDB70INFO, PdbUuid, 4); +AssertCompileMemberOffset(CVPDB70INFO, uAge, 4 + 16); +/** Pointer to in executable image PDB v7.0 info. */ +typedef CVPDB70INFO *PCVPDB70INFO; +/** Pointer to read only in executable image PDB v7.0 info. */ +typedef CVPDB70INFO const *PCCVPDB70INFO; +/** The CVPDB70INFO magic value. */ +#define CVPDB70INFO_MAGIC RT_MAKE_U32_FROM_U8('R','S','D','S') + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_codeview_h */ + diff --git a/include/iprt/formats/cpio.h b/include/iprt/formats/cpio.h new file mode 100644 index 00000000..a202a0a6 --- /dev/null +++ b/include/iprt/formats/cpio.h @@ -0,0 +1,210 @@ +/** @file + * IPRT - CPIO archive format. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_cpio_h +#define IPRT_INCLUDED_formats_cpio_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_cpio CPIO Archive format + * @ingroup grp_rt_formats + * + * @{ */ + +/** This denotes the end of the archive (record with this filename, zero size and + * a zero mode). */ +#define CPIO_EOS_FILE_NAME "TRAILER!!!" + + +/** + * The old binary header. + */ +typedef struct CPIOHDRBIN +{ + /** 0x00: Magic identifying the old header. */ + uint16_t u16Magic; + /** 0x02: Device number. */ + uint16_t u16Dev; + /** 0x04: Inode number. */ + uint16_t u16Inode; + /** 0x06: Mode. */ + uint16_t u16Mode; + /** 0x08: User ID. */ + uint16_t u16Uid; + /** 0x0a: Group ID. */ + uint16_t u16Gid; + /** 0x0c: Number of links to this file. */ + uint16_t u16NLinks; + /** 0x0e: Associated device number for block and character device entries. */ + uint16_t u16RDev; + /** 0x10: Modification time stored as two independent 16bit integers. */ + uint16_t au16MTime[2]; + /** 0x14: Number of bytes in the path name (including zero terminator) following the header. */ + uint16_t u16NameSize; + /** 0x16: Size of the file stored as two independent 16bit integers. */ + uint16_t au16FileSize[2]; +} CPIOHDRBIN; +AssertCompileSize(CPIOHDRBIN, 13 * 2); +typedef CPIOHDRBIN *PCPIOHDRBIN; +typedef const CPIOHDRBIN *PCCPIOHDRBIN; + + +/** The magic for the binary header. */ +#define CPIO_HDR_BIN_MAGIC UINT16_C(070707) + + +/** + * Portable ASCII format header as defined by SUSv2. + */ +typedef struct CPIOHDRSUSV2 +{ + /** 0x00: Magic identifying the header. */ + char achMagic[6]; + /** 0x06: Device number. */ + char achDev[6]; + /** 0x0c: Inode number. */ + char achInode[6]; + /** 0x12: Mode. */ + char achMode[6]; + /** 0x18: User ID. */ + char achUid[6]; + /** 0x1e: Group ID. */ + char achGid[6]; + /** 0x24: Number of links to this file. */ + char achNLinks[6]; + /** 0x2a: Associated device number for block and character device entries. */ + char achRDev[6]; + /** 0x30: Modification time stored as two independent 16bit integers. */ + char achMTime[11]; + /** 0x36: Number of bytes in the path name (including zero terminator) following the header. */ + char achNameSize[6]; + /** 0x3c: Size of the file stored as two independent 16bit integers. */ + char achFileSize[11]; +} CPIOHDRSUSV2; +AssertCompileSize(CPIOHDRSUSV2, 9 * 6 + 2 * 11); +typedef CPIOHDRSUSV2 *PCPIOHDRSUSV2; +typedef const CPIOHDRSUSV2 *PCCPIOHDRSUSV2; + + +/** The magic for the SuSv2 CPIO header. */ +#define CPIO_HDR_SUSV2_MAGIC "070707" + + +/** + * New ASCII format header. + */ +typedef struct CPIOHDRNEW +{ + /** 0x00: Magic identifying the header. */ + char achMagic[6]; + /** 0x06: Inode number. */ + char achInode[8]; + /** 0x0e: Mode. */ + char achMode[8]; + /** 0x16: User ID. */ + char achUid[8]; + /** 0x1e: Group ID. */ + char achGid[8]; + /** 0x26: Number of links to this file. */ + char achNLinks[8]; + /** 0x2e: Modification time. */ + char achMTime[8]; + /** 0x36: Size of the file stored as two independent 16bit integers. */ + char achFileSize[8]; + /** 0x3e: Device major number. */ + char achDevMajor[8]; + /** 0x46: Device minor number. */ + char achDevMinor[8]; + /** 0x4e: Assigned device major number for block or character device files. */ + char achRDevMajor[8]; + /** 0x56: Assigned device minor number for block or character device files. */ + char achRDevMinor[8]; + /** 0x5e: Number of bytes in the path name (including zero terminator) following the header. */ + char achNameSize[8]; + /** 0x66: Checksum of the file data if used. */ + char achCheck[8]; +} CPIOHDRNEW; +AssertCompileSize(CPIOHDRNEW, 6 + 13 * 8); +AssertCompileMemberOffset(CPIOHDRNEW, achMagic, 0x00); +AssertCompileMemberOffset(CPIOHDRNEW, achInode, 0x06); +AssertCompileMemberOffset(CPIOHDRNEW, achMode, 0x0e); +AssertCompileMemberOffset(CPIOHDRNEW, achUid, 0x16); +AssertCompileMemberOffset(CPIOHDRNEW, achGid, 0x1e); +AssertCompileMemberOffset(CPIOHDRNEW, achNLinks, 0x26); +AssertCompileMemberOffset(CPIOHDRNEW, achMTime, 0x2e); +AssertCompileMemberOffset(CPIOHDRNEW, achFileSize, 0x36); +AssertCompileMemberOffset(CPIOHDRNEW, achDevMajor, 0x3e); +AssertCompileMemberOffset(CPIOHDRNEW, achDevMinor, 0x46); +AssertCompileMemberOffset(CPIOHDRNEW, achRDevMajor, 0x4e); +AssertCompileMemberOffset(CPIOHDRNEW, achRDevMinor, 0x56); +AssertCompileMemberOffset(CPIOHDRNEW, achNameSize, 0x5e); +AssertCompileMemberOffset(CPIOHDRNEW, achCheck, 0x66); +typedef CPIOHDRNEW *PCPIOHDRNEW; +typedef const CPIOHDRNEW *PCCPIOHDRNEW; + + +/** The magic for the new ASCII CPIO header. */ +#define CPIO_HDR_NEW_MAGIC "070701" +/** The magic for the new ASCII CPIO header + checksum. */ +#define CPIO_HDR_NEW_CHKSUM_MAGIC "070702" + + +/** + * CPIO header union. + */ +typedef union CPIOHDR +{ + /** byte view. */ + uint8_t ab[110]; + /** The ancient binary header. */ + CPIOHDRBIN AncientBin; + /** The SuSv2 ASCII header. */ + CPIOHDRSUSV2 AsciiSuSv2; + /** The new ASCII header format. */ + CPIOHDRNEW AsciiNew; +} CPIOHDR; +typedef CPIOHDR *PCPIOHDR; +typedef const CPIOHDR *PCCPIOHDR; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_cpio_h */ + diff --git a/include/iprt/formats/dwarf.h b/include/iprt/formats/dwarf.h new file mode 100644 index 00000000..45a58ad9 --- /dev/null +++ b/include/iprt/formats/dwarf.h @@ -0,0 +1,542 @@ +/** @file + * IPRT - DWARF constants. + * + * @note dwarf.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_dwarf_h +#define IPRT_INCLUDED_formats_dwarf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/** @name Standard DWARF Line Number Opcodes + * @{ */ +#define DW_LNS_extended UINT8_C(0x00) +#define DW_LNS_copy UINT8_C(0x01) +#define DW_LNS_advance_pc UINT8_C(0x02) +#define DW_LNS_advance_line UINT8_C(0x03) +#define DW_LNS_set_file UINT8_C(0x04) +#define DW_LNS_set_column UINT8_C(0x05) +#define DW_LNS_negate_stmt UINT8_C(0x06) +#define DW_LNS_set_basic_block UINT8_C(0x07) +#define DW_LNS_const_add_pc UINT8_C(0x08) +#define DW_LNS_fixed_advance_pc UINT8_C(0x09) +#define DW_LNS_set_prologue_end UINT8_C(0x0a) +#define DW_LNS_set_epilogue_begin UINT8_C(0x0b) +#define DW_LNS_set_isa UINT8_C(0x0c) +#define DW_LNS_what_question_mark UINT8_C(0x0d) +/** @} */ + + +/** @name Extended DWARF Line Number Opcodes + * @{ */ +#define DW_LNE_end_sequence UINT8_C(1) +#define DW_LNE_set_address UINT8_C(2) +#define DW_LNE_define_file UINT8_C(3) +#define DW_LNE_set_descriminator UINT8_C(4) +/** @} */ + + +/** @name DIE Tags. + * @{ */ +#define DW_TAG_array_type UINT16_C(0x0001) +#define DW_TAG_class_type UINT16_C(0x0002) +#define DW_TAG_entry_point UINT16_C(0x0003) +#define DW_TAG_enumeration_type UINT16_C(0x0004) +#define DW_TAG_formal_parameter UINT16_C(0x0005) +#define DW_TAG_imported_declaration UINT16_C(0x0008) +#define DW_TAG_label UINT16_C(0x000a) +#define DW_TAG_lexical_block UINT16_C(0x000b) +#define DW_TAG_member UINT16_C(0x000d) +#define DW_TAG_pointer_type UINT16_C(0x000f) +#define DW_TAG_reference_type UINT16_C(0x0010) +#define DW_TAG_compile_unit UINT16_C(0x0011) +#define DW_TAG_string_type UINT16_C(0x0012) +#define DW_TAG_structure_type UINT16_C(0x0013) +#define DW_TAG_subroutine_type UINT16_C(0x0015) +#define DW_TAG_typedef UINT16_C(0x0016) +#define DW_TAG_union_type UINT16_C(0x0017) +#define DW_TAG_unspecified_parameters UINT16_C(0x0018) +#define DW_TAG_variant UINT16_C(0x0019) +#define DW_TAG_common_block UINT16_C(0x001a) +#define DW_TAG_common_inclusion UINT16_C(0x001b) +#define DW_TAG_inheritance UINT16_C(0x001c) +#define DW_TAG_inlined_subroutine UINT16_C(0x001d) +#define DW_TAG_module UINT16_C(0x001e) +#define DW_TAG_ptr_to_member_type UINT16_C(0x001f) +#define DW_TAG_set_type UINT16_C(0x0020) +#define DW_TAG_subrange_type UINT16_C(0x0021) +#define DW_TAG_with_stmt UINT16_C(0x0022) +#define DW_TAG_access_declaration UINT16_C(0x0023) +#define DW_TAG_base_type UINT16_C(0x0024) +#define DW_TAG_catch_block UINT16_C(0x0025) +#define DW_TAG_const_type UINT16_C(0x0026) +#define DW_TAG_constant UINT16_C(0x0027) +#define DW_TAG_enumerator UINT16_C(0x0028) +#define DW_TAG_file_type UINT16_C(0x0029) +#define DW_TAG_friend UINT16_C(0x002a) +#define DW_TAG_namelist UINT16_C(0x002b) +#define DW_TAG_namelist_item UINT16_C(0x002c) +#define DW_TAG_packed_type UINT16_C(0x002d) +#define DW_TAG_subprogram UINT16_C(0x002e) +#define DW_TAG_template_type_parameter UINT16_C(0x002f) +#define DW_TAG_template_value_parameter UINT16_C(0x0030) +#define DW_TAG_thrown_type UINT16_C(0x0031) +#define DW_TAG_try_block UINT16_C(0x0032) +#define DW_TAG_variant_part UINT16_C(0x0033) +#define DW_TAG_variable UINT16_C(0x0034) +#define DW_TAG_volatile_type UINT16_C(0x0035) +#define DW_TAG_dwarf_procedure UINT16_C(0x0036) +#define DW_TAG_restrict_type UINT16_C(0x0037) +#define DW_TAG_interface_type UINT16_C(0x0038) +#define DW_TAG_namespace UINT16_C(0x0039) +#define DW_TAG_imported_module UINT16_C(0x003a) +#define DW_TAG_unspecified_type UINT16_C(0x003b) +#define DW_TAG_partial_unit UINT16_C(0x003c) +#define DW_TAG_imported_unit UINT16_C(0x003d) +#define DW_TAG_condition UINT16_C(0x003f) +#define DW_TAG_shared_type UINT16_C(0x0040) +#define DW_TAG_type_unit UINT16_C(0x0041) +#define DW_TAG_rvalue_reference_type UINT16_C(0x0042) +#define DW_TAG_template_alias UINT16_C(0x0043) +#define DW_TAG_lo_user UINT16_C(0x4080) +#define DW_TAG_GNU_call_site UINT16_C(0x4109) +#define DW_TAG_GNU_call_site_parameter UINT16_C(0x410a) +#define DW_TAG_WATCOM_address_class_type UINT16_C(0x4100) /**< Watcom extension. */ +#define DW_TAG_WATCOM_namespace UINT16_C(0x4101) /**< Watcom extension. */ +#define DW_TAG_hi_user UINT16_C(0xffff) +/** @} */ + + +/** @name Has children or not (follows DW_TAG_xxx in .debug_abbrev). + * @{ */ +#define DW_CHILDREN_yes 1 +#define DW_CHILDREN_no 0 +/** @} */ + + +/** @name DIE Attributes. + * @{ */ +#define DW_AT_sibling UINT16_C(0x0001) +#define DW_AT_location UINT16_C(0x0002) +#define DW_AT_name UINT16_C(0x0003) +#define DW_AT_ordering UINT16_C(0x0009) +#define DW_AT_byte_size UINT16_C(0x000b) +#define DW_AT_bit_offset UINT16_C(0x000c) +#define DW_AT_bit_size UINT16_C(0x000d) +#define DW_AT_stmt_list UINT16_C(0x0010) +#define DW_AT_low_pc UINT16_C(0x0011) +#define DW_AT_high_pc UINT16_C(0x0012) +#define DW_AT_language UINT16_C(0x0013) +#define DW_AT_discr UINT16_C(0x0015) +#define DW_AT_discr_value UINT16_C(0x0016) +#define DW_AT_visibility UINT16_C(0x0017) +#define DW_AT_import UINT16_C(0x0018) +#define DW_AT_string_length UINT16_C(0x0019) +#define DW_AT_common_reference UINT16_C(0x001a) +#define DW_AT_comp_dir UINT16_C(0x001b) +#define DW_AT_const_value UINT16_C(0x001c) +#define DW_AT_containing_type UINT16_C(0x001d) +#define DW_AT_default_value UINT16_C(0x001e) +#define DW_AT_inline UINT16_C(0x0020) +#define DW_AT_is_optional UINT16_C(0x0021) +#define DW_AT_lower_bound UINT16_C(0x0022) +#define DW_AT_producer UINT16_C(0x0025) +#define DW_AT_prototyped UINT16_C(0x0027) +#define DW_AT_return_addr UINT16_C(0x002a) +#define DW_AT_start_scope UINT16_C(0x002c) +#define DW_AT_bit_stride UINT16_C(0x002e) +#define DW_AT_upper_bound UINT16_C(0x002f) +#define DW_AT_abstract_origin UINT16_C(0x0031) +#define DW_AT_accessibility UINT16_C(0x0032) +#define DW_AT_address_class UINT16_C(0x0033) +#define DW_AT_artificial UINT16_C(0x0034) +#define DW_AT_base_types UINT16_C(0x0035) +#define DW_AT_calling_convention UINT16_C(0x0036) +#define DW_AT_count UINT16_C(0x0037) +#define DW_AT_data_member_location UINT16_C(0x0038) +#define DW_AT_decl_column UINT16_C(0x0039) +#define DW_AT_decl_file UINT16_C(0x003a) +#define DW_AT_decl_line UINT16_C(0x003b) +#define DW_AT_declaration UINT16_C(0x003c) +#define DW_AT_discr_list UINT16_C(0x003d) +#define DW_AT_encoding UINT16_C(0x003e) +#define DW_AT_external UINT16_C(0x003f) +#define DW_AT_frame_base UINT16_C(0x0040) +#define DW_AT_friend UINT16_C(0x0041) +#define DW_AT_identifier_case UINT16_C(0x0042) +#define DW_AT_macro_info UINT16_C(0x0043) +#define DW_AT_namelist_item UINT16_C(0x0044) +#define DW_AT_priority UINT16_C(0x0045) +#define DW_AT_segment UINT16_C(0x0046) +#define DW_AT_specification UINT16_C(0x0047) +#define DW_AT_static_link UINT16_C(0x0048) +#define DW_AT_type UINT16_C(0x0049) +#define DW_AT_use_location UINT16_C(0x004a) +#define DW_AT_variable_parameter UINT16_C(0x004b) +#define DW_AT_virtuality UINT16_C(0x004c) +#define DW_AT_vtable_elem_location UINT16_C(0x004d) +#define DW_AT_allocated UINT16_C(0x004e) +#define DW_AT_associated UINT16_C(0x004f) +#define DW_AT_data_location UINT16_C(0x0050) +#define DW_AT_byte_stride UINT16_C(0x0051) +#define DW_AT_entry_pc UINT16_C(0x0052) +#define DW_AT_use_UTF8 UINT16_C(0x0053) +#define DW_AT_extension UINT16_C(0x0054) +#define DW_AT_ranges UINT16_C(0x0055) +#define DW_AT_trampoline UINT16_C(0x0056) +#define DW_AT_call_column UINT16_C(0x0057) +#define DW_AT_call_file UINT16_C(0x0058) +#define DW_AT_call_line UINT16_C(0x0059) +#define DW_AT_description UINT16_C(0x005a) +#define DW_AT_binary_scale UINT16_C(0x005b) +#define DW_AT_decimal_scale UINT16_C(0x005c) +#define DW_AT_small UINT16_C(0x005d) +#define DW_AT_decimal_sign UINT16_C(0x005e) +#define DW_AT_digit_count UINT16_C(0x005f) +#define DW_AT_picture_string UINT16_C(0x0060) +#define DW_AT_mutable UINT16_C(0x0061) +#define DW_AT_threads_scaled UINT16_C(0x0062) +#define DW_AT_explicit UINT16_C(0x0063) +#define DW_AT_object_pointer UINT16_C(0x0064) +#define DW_AT_endianity UINT16_C(0x0065) +#define DW_AT_elemental UINT16_C(0x0066) +#define DW_AT_pure UINT16_C(0x0067) +#define DW_AT_recursive UINT16_C(0x0068) +#define DW_AT_signature UINT16_C(0x0069) +#define DW_AT_main_subprogram UINT16_C(0x006a) +#define DW_AT_data_bit_offset UINT16_C(0x006b) +#define DW_AT_const_expr UINT16_C(0x006c) +#define DW_AT_enum_class UINT16_C(0x006d) +#define DW_AT_linkage_name UINT16_C(0x006e) +#define DW_AT_lo_user UINT16_C(0x2000) +/** Used by GCC and others, same as DW_AT_linkage_name. See http://wiki.dwarfstd.org/index.php?title=DW_AT_linkage_name*/ +#define DW_AT_MIPS_linkage_name UINT16_C(0x2007) +#define DW_AT_WATCOM_memory_model UINT16_C(0x2082) /**< Watcom extension. */ +#define DW_AT_WATCOM_references_start UINT16_C(0x2083) /**< Watcom extension. */ +#define DW_AT_WATCOM_parm_entry UINT16_C(0x2084) /**< Watcom extension. */ +#define DW_AT_hi_user UINT16_C(0x3fff) +/** @} */ + +/** @name DIE Forms. + * @{ */ +#define DW_FORM_addr UINT16_C(0x01) +/* 0x02 was FORM_REF in DWARF v1, obsolete now. */ +#define DW_FORM_block2 UINT16_C(0x03) +#define DW_FORM_block4 UINT16_C(0x04) +#define DW_FORM_data2 UINT16_C(0x05) +#define DW_FORM_data4 UINT16_C(0x06) +#define DW_FORM_data8 UINT16_C(0x07) +#define DW_FORM_string UINT16_C(0x08) +#define DW_FORM_block UINT16_C(0x09) +#define DW_FORM_block1 UINT16_C(0x0a) +#define DW_FORM_data1 UINT16_C(0x0b) +#define DW_FORM_flag UINT16_C(0x0c) +#define DW_FORM_sdata UINT16_C(0x0d) +#define DW_FORM_strp UINT16_C(0x0e) +#define DW_FORM_udata UINT16_C(0x0f) +#define DW_FORM_ref_addr UINT16_C(0x10) +#define DW_FORM_ref1 UINT16_C(0x11) +#define DW_FORM_ref2 UINT16_C(0x12) +#define DW_FORM_ref4 UINT16_C(0x13) +#define DW_FORM_ref8 UINT16_C(0x14) +#define DW_FORM_ref_udata UINT16_C(0x15) +#define DW_FORM_indirect UINT16_C(0x16) +#define DW_FORM_sec_offset UINT16_C(0x17) +#define DW_FORM_exprloc UINT16_C(0x18) +#define DW_FORM_flag_present UINT16_C(0x19) +#define DW_FORM_ref_sig8 UINT16_C(0x20) +/** @} */ + +/** @name Address classes. + * @{ */ +#define DW_ADDR_none UINT8_C(0) +#define DW_ADDR_i386_near16 UINT8_C(1) +#define DW_ADDR_i386_far16 UINT8_C(2) +#define DW_ADDR_i386_huge16 UINT8_C(3) +#define DW_ADDR_i386_near32 UINT8_C(4) +#define DW_ADDR_i386_far32 UINT8_C(5) +/** @} */ + + +/** @name Location Expression Opcodes + * @{ */ +#define DW_OP_addr UINT8_C(0x03) /**< 1 operand, a constant address (size target specific). */ +#define DW_OP_deref UINT8_C(0x06) /**< 0 operands. */ +#define DW_OP_const1u UINT8_C(0x08) /**< 1 operand, a 1-byte constant. */ +#define DW_OP_const1s UINT8_C(0x09) /**< 1 operand, a 1-byte constant. */ +#define DW_OP_const2u UINT8_C(0x0a) /**< 1 operand, a 2-byte constant. */ +#define DW_OP_const2s UINT8_C(0x0b) /**< 1 operand, a 2-byte constant. */ +#define DW_OP_const4u UINT8_C(0x0c) /**< 1 operand, a 4-byte constant. */ +#define DW_OP_const4s UINT8_C(0x0d) /**< 1 operand, a 4-byte constant. */ +#define DW_OP_const8u UINT8_C(0x0e) /**< 1 operand, a 8-byte constant. */ +#define DW_OP_const8s UINT8_C(0x0f) /**< 1 operand, a 8-byte constant. */ +#define DW_OP_constu UINT8_C(0x10) /**< 1 operand, a ULEB128 constant. */ +#define DW_OP_consts UINT8_C(0x11) /**< 1 operand, a SLEB128 constant. */ +#define DW_OP_dup UINT8_C(0x12) /**< 0 operands. */ +#define DW_OP_drop UINT8_C(0x13) /**< 0 operands. */ +#define DW_OP_over UINT8_C(0x14) /**< 0 operands. */ +#define DW_OP_pick UINT8_C(0x15) /**< 1 operands, a 1-byte stack index. */ +#define DW_OP_swap UINT8_C(0x16) /**< 0 operands. */ +#define DW_OP_rot UINT8_C(0x17) /**< 0 operands. */ +#define DW_OP_xderef UINT8_C(0x18) /**< 0 operands. */ +#define DW_OP_abs UINT8_C(0x19) /**< 0 operands. */ +#define DW_OP_and UINT8_C(0x1a) /**< 0 operands. */ +#define DW_OP_div UINT8_C(0x1b) /**< 0 operands. */ +#define DW_OP_minus UINT8_C(0x1c) /**< 0 operands. */ +#define DW_OP_mod UINT8_C(0x1d) /**< 0 operands. */ +#define DW_OP_mul UINT8_C(0x1e) /**< 0 operands. */ +#define DW_OP_neg UINT8_C(0x1f) /**< 0 operands. */ +#define DW_OP_not UINT8_C(0x20) /**< 0 operands. */ +#define DW_OP_or UINT8_C(0x21) /**< 0 operands. */ +#define DW_OP_plus UINT8_C(0x22) /**< 0 operands. */ +#define DW_OP_plus_uconst UINT8_C(0x23) /**< 1 operands, a ULEB128 addend. */ +#define DW_OP_shl UINT8_C(0x24) /**< 0 operands. */ +#define DW_OP_shr UINT8_C(0x25) /**< 0 operands. */ +#define DW_OP_shra UINT8_C(0x26) /**< 0 operands. */ +#define DW_OP_xor UINT8_C(0x27) /**< 0 operands. */ +#define DW_OP_skip UINT8_C(0x2f) /**< 1 signed 2-byte constant. */ +#define DW_OP_bra UINT8_C(0x28) /**< 1 signed 2-byte constant. */ +#define DW_OP_eq UINT8_C(0x29) /**< 0 operands. */ +#define DW_OP_ge UINT8_C(0x2a) /**< 0 operands. */ +#define DW_OP_gt UINT8_C(0x2b) /**< 0 operands. */ +#define DW_OP_le UINT8_C(0x2c) /**< 0 operands. */ +#define DW_OP_lt UINT8_C(0x2d) /**< 0 operands. */ +#define DW_OP_ne UINT8_C(0x2e) /**< 0 operands. */ +#define DW_OP_lit0 UINT8_C(0x30) /**< 0 operands - literals 0..31 */ +#define DW_OP_lit31 UINT8_C(0x4f) /**< last litteral. */ +#define DW_OP_reg0 UINT8_C(0x50) /**< 0 operands - reg 0..31. */ +#define DW_OP_reg31 UINT8_C(0x6f) /**< last register. */ +#define DW_OP_breg0 UINT8_C(0x70) /**< 1 operand, a SLEB128 offset. */ +#define DW_OP_breg31 UINT8_C(0x8f) /**< last branch register. */ +#define DW_OP_regx UINT8_C(0x90) /**< 1 operand, a ULEB128 register. */ +#define DW_OP_fbreg UINT8_C(0x91) /**< 1 operand, a SLEB128 offset. */ +#define DW_OP_bregx UINT8_C(0x92) /**< 2 operands, a ULEB128 register followed by a SLEB128 offset. */ +#define DW_OP_piece UINT8_C(0x93) /**< 1 operand, a ULEB128 size of piece addressed. */ +#define DW_OP_deref_size UINT8_C(0x94) /**< 1 operand, a 1-byte size of data retrieved. */ +#define DW_OP_xderef_size UINT8_C(0x95) /**< 1 operand, a 1-byte size of data retrieved. */ +#define DW_OP_nop UINT8_C(0x96) /**< 0 operands. */ +#define DW_OP_lo_user UINT8_C(0xe0) /**< First user opcode */ +#define DW_OP_hi_user UINT8_C(0xff) /**< Last user opcode. */ +/** @} */ + +/** @name Exception Handler Pointer Encodings (GCC/LSB). + * @{ */ +#define DW_EH_PE_FORMAT_MASK UINT8_C(0x0f) /**< Format mask. */ +#define DW_EH_PE_APPL_MASK UINT8_C(0x70) /**< Application mask. */ +#define DW_EH_PE_indirect UINT8_C(0x80) /**< Flag: Indirect pointer. */ +#define DW_EH_PE_omit UINT8_C(0xff) /**< Special value: Omitted. */ +#define DW_EH_PE_ptr UINT8_C(0x00) /**< Format: pointer sized, unsigned. */ +#define DW_EH_PE_uleb128 UINT8_C(0x01) /**< Format: unsigned LEB128. */ +#define DW_EH_PE_udata2 UINT8_C(0x02) /**< Format: unsigned 16-bit. */ +#define DW_EH_PE_udata4 UINT8_C(0x03) /**< Format: unsigned 32-bit. */ +#define DW_EH_PE_udata8 UINT8_C(0x04) /**< Format: unsigned 64-bit. */ +#define DW_EH_PE_sleb128 UINT8_C(0x09) /**< Format: signed LEB128. */ +#define DW_EH_PE_sdata2 UINT8_C(0x0a) /**< Format: signed 16-bit. */ +#define DW_EH_PE_sdata4 UINT8_C(0x0b) /**< Format: signed 32-bit. */ +#define DW_EH_PE_sdata8 UINT8_C(0x0c) /**< Format: signed 64-bit. */ +#define DW_EH_PE_absptr UINT8_C(0x00) /**< Application: Absolute */ +#define DW_EH_PE_pcrel UINT8_C(0x10) /**< Application: PC relative, i.e. relative pointer address. */ +#define DW_EH_PE_textrel UINT8_C(0x20) /**< Application: text section relative. */ +#define DW_EH_PE_datarel UINT8_C(0x30) /**< Application: data section relative. */ +#define DW_EH_PE_funcrel UINT8_C(0x40) /**< Application: relative to start of function. */ +#define DW_EH_PE_aligned UINT8_C(0x50) /**< Application: aligned pointer. */ +/** @} */ + +/** @name Call frame instructions. + * @{ */ +/** Mask to use to identify DW_CFA_advance_loc, DW_CFA_offset and DW_CFA_restore. */ +#define DW_CFA_high_bit_mask UINT8_C(0xc0) + +#define DW_CFA_nop UINT8_C(0x00) /**< No operands. */ + +#define DW_CFA_advance_loc UINT8_C(0x40) /**< low 6 bits: delta to advance. */ +#define DW_CFA_set_loc UINT8_C(0x01) /**< op1: address. */ +#define DW_CFA_advance_loc1 UINT8_C(0x02) /**< op1: 1-byte delta. */ +#define DW_CFA_advance_loc2 UINT8_C(0x03) /**< op1: 2-byte delta. */ +#define DW_CFA_advance_loc4 UINT8_C(0x04) /**< op1: 4-byte delta. */ + +#define DW_CFA_offset UINT8_C(0x80) /**< low 6 bits: register; op1: ULEB128 offset. */ +#define DW_CFA_offset_extended UINT8_C(0x05) /**< op1: ULEB128 register; op2: ULEB128 offset. */ +#define DW_CFA_offset_extended_sf UINT8_C(0x11) /**< op1: ULEB128 register; op2: SLEB128 offset. */ +#define DW_CFA_restore UINT8_C(0xc0) /**< low 6 bits: register. */ +#define DW_CFA_restore_extended UINT8_C(0x06) /**< op1: ULEB128 register. */ +#define DW_CFA_undefined UINT8_C(0x07) /**< op1: ULEB128 register. */ +#define DW_CFA_same_value UINT8_C(0x08) /**< op1: ULEB128 register. */ +#define DW_CFA_register UINT8_C(0x09) /**< op1: ULEB128 destination register; op2: ULEB128 source register. */ +#define DW_CFA_expression UINT8_C(0x10) /**< op1: ULEB128 register; op2: BLOCK. */ + +#define DW_CFA_val_offset UINT8_C(0x14) /**< op1: ULEB128 register; op2: ULEB128. */ +#define DW_CFA_val_offset_sf UINT8_C(0x15) /**< op1: ULEB128 register; op2: SLEB128. */ +#define DW_CFA_val_expression UINT8_C(0x16) /**< op1: ULEB128 register; op2: BLOCK. */ + +#define DW_CFA_remember_state UINT8_C(0x0a) /**< No operands. */ +#define DW_CFA_restore_state UINT8_C(0x0b) /**< No operands. */ + +#define DW_CFA_def_cfa UINT8_C(0x0c) /**< op1: ULEB128 register; op2: ULEB128 offset. */ +#define DW_CFA_def_cfa_register UINT8_C(0x0d) /**< op1: ULEB128 register. */ +#define DW_CFA_def_cfa_offset UINT8_C(0x0e) /**< op1: ULEB128 offset. */ +#define DW_CFA_def_cfa_expression UINT8_C(0x0f) /**< op1: BLOCK. */ +#define DW_CFA_def_cfa_sf UINT8_C(0x12) /**< op1: ULEB128 register; op2: SLEB128 offset. */ +#define DW_CFA_def_cfa_offset_sf UINT8_C(0x13) /**< op1: SLEB128 offset. */ + +#define DW_CFA_lo_user UINT8_C(0x1c) /**< User defined operands. */ +#define DW_CFA_MIPS_advance_loc8 UINT8_C(0x1d) /**< op1: 8-byte delta? */ +#define DW_CFA_GNU_window_save UINT8_C(0x2d) /**< op1: ??; op2: ?? */ +#define DW_CFA_GNU_args_size UINT8_C(0x2e) /**< op1: ??; op2: ?? */ +#define DW_CFA_GNU_negative_offset_extended UINT8_C(0x2f) /**< op1: ??; op2: ?? */ +#define DW_CFA_hi_user UINT8_C(0x3f) /**< User defined operands. */ +/** @} */ + + +/** @name DWREG_X86_XXX - 386+ register number mappings. + * @{ */ +#define DWREG_X86_EAX 0 +#define DWREG_X86_ECX 1 +#define DWREG_X86_EDX 2 +#define DWREG_X86_EBX 3 +#define DWREG_X86_ESP 4 +#define DWREG_X86_EBP 5 +#define DWREG_X86_ESI 6 +#define DWREG_X86_EDI 7 +#define DWREG_X86_RA 8 /* return address (=EIP) */ +#define DWREG_X86_EFLAGS 9 +#define DWREG_X86_ST1 11 +#define DWREG_X86_ST2 12 +#define DWREG_X86_ST3 13 +#define DWREG_X86_ST4 14 +#define DWREG_X86_ST5 15 +#define DWREG_X86_ST6 16 +#define DWREG_X86_ST7 17 +#define DWREG_X86_XMM0 21 +#define DWREG_X86_XMM1 22 +#define DWREG_X86_XMM2 23 +#define DWREG_X86_XMM3 24 +#define DWREG_X86_XMM4 25 +#define DWREG_X86_XMM5 26 +#define DWREG_X86_XMM6 27 +#define DWREG_X86_XMM7 28 +#define DWREG_X86_MM0 29 +#define DWREG_X86_MM1 30 +#define DWREG_X86_MM2 31 +#define DWREG_X86_MM3 32 +#define DWREG_X86_MM4 33 +#define DWREG_X86_MM5 34 +#define DWREG_X86_MM6 35 +#define DWREG_X86_MM7 36 +#define DWREG_X86_MXCSR 39 +#define DWREG_X86_ES 40 +#define DWREG_X86_CS 41 +#define DWREG_X86_SS 42 +#define DWREG_X86_DS 43 +#define DWREG_X86_FS 44 +#define DWREG_X86_GS 45 +#define DWREG_X86_TR 48 +#define DWREG_X86_LDTR 49 +/** @} */ + + +/** @name DWREG_AMD64_XXX - AMD64 register number mappings. + * @note This for some braindead reason the first 8 GPR are in intel encoding + * order, unlike the DWREG_X86_XXX variant. Utter stupidity. + * @{ */ +#define DWREG_AMD64_RAX 0 +#define DWREG_AMD64_RDX 1 +#define DWREG_AMD64_RCX 2 +#define DWREG_AMD64_RBX 3 +#define DWREG_AMD64_RSI 4 +#define DWREG_AMD64_RDI 5 +#define DWREG_AMD64_RBP 6 +#define DWREG_AMD64_RSP 7 +#define DWREG_AMD64_R8 8 +#define DWREG_AMD64_R9 9 +#define DWREG_AMD64_R10 10 +#define DWREG_AMD64_R11 11 +#define DWREG_AMD64_R12 12 +#define DWREG_AMD64_R13 13 +#define DWREG_AMD64_R14 14 +#define DWREG_AMD64_R15 15 +#define DWREG_AMD64_RA 16 /* return address (=RIP) */ +#define DWREG_AMD64_XMM0 17 +#define DWREG_AMD64_XMM1 18 +#define DWREG_AMD64_XMM2 19 +#define DWREG_AMD64_XMM3 20 +#define DWREG_AMD64_XMM4 21 +#define DWREG_AMD64_XMM5 22 +#define DWREG_AMD64_XMM6 23 +#define DWREG_AMD64_XMM7 24 +#define DWREG_AMD64_XMM8 25 +#define DWREG_AMD64_XMM9 26 +#define DWREG_AMD64_XMM10 27 +#define DWREG_AMD64_XMM11 28 +#define DWREG_AMD64_XMM12 29 +#define DWREG_AMD64_XMM13 30 +#define DWREG_AMD64_XMM14 31 +#define DWREG_AMD64_XMM15 32 +#define DWREG_AMD64_ST0 33 +#define DWREG_AMD64_ST1 34 +#define DWREG_AMD64_ST2 35 +#define DWREG_AMD64_ST3 36 +#define DWREG_AMD64_ST4 37 +#define DWREG_AMD64_ST5 38 +#define DWREG_AMD64_ST6 39 +#define DWREG_AMD64_ST7 40 +#define DWREG_AMD64_MM0 41 +#define DWREG_AMD64_MM1 42 +#define DWREG_AMD64_MM2 43 +#define DWREG_AMD64_MM3 44 +#define DWREG_AMD64_MM4 45 +#define DWREG_AMD64_MM5 46 +#define DWREG_AMD64_MM6 47 +#define DWREG_AMD64_MM7 48 +#define DWREG_AMD64_RFLAGS 49 +#define DWREG_AMD64_ES 50 +#define DWREG_AMD64_CS 51 +#define DWREG_AMD64_SS 52 +#define DWREG_AMD64_DS 53 +#define DWREG_AMD64_FS 54 +#define DWREG_AMD64_GS 55 +#define DWREG_AMD64_FS_BASE 58 +#define DWREG_AMD64_GS_BASE 59 +#define DWREG_AMD64_TR 62 +#define DWREG_AMD64_LDTR 63 +#define DWREG_AMD64_MXCSR 64 +#define DWREG_AMD64_FCW 65 +#define DWREG_AMD64_FSW 66 +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_dwarf_h */ + diff --git a/include/iprt/formats/dwarf.mac b/include/iprt/formats/dwarf.mac new file mode 100644 index 00000000..a54b0965 --- /dev/null +++ b/include/iprt/formats/dwarf.mac @@ -0,0 +1,471 @@ +;; @file +; IPRT - DWARF constants. +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef IPRT_INCLUDED_formats_dwarf_h +%define IPRT_INCLUDED_formats_dwarf_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define DW_LNS_extended 0x00 +%define DW_LNS_copy 0x01 +%define DW_LNS_advance_pc 0x02 +%define DW_LNS_advance_line 0x03 +%define DW_LNS_set_file 0x04 +%define DW_LNS_set_column 0x05 +%define DW_LNS_negate_stmt 0x06 +%define DW_LNS_set_basic_block 0x07 +%define DW_LNS_const_add_pc 0x08 +%define DW_LNS_fixed_advance_pc 0x09 +%define DW_LNS_set_prologue_end 0x0a +%define DW_LNS_set_epilogue_begin 0x0b +%define DW_LNS_set_isa 0x0c +%define DW_LNS_what_question_mark 0x0d +%define DW_LNE_end_sequence 1 +%define DW_LNE_set_address 2 +%define DW_LNE_define_file 3 +%define DW_LNE_set_descriminator 4 +%define DW_TAG_array_type 0x0001 +%define DW_TAG_class_type 0x0002 +%define DW_TAG_entry_point 0x0003 +%define DW_TAG_enumeration_type 0x0004 +%define DW_TAG_formal_parameter 0x0005 +%define DW_TAG_imported_declaration 0x0008 +%define DW_TAG_label 0x000a +%define DW_TAG_lexical_block 0x000b +%define DW_TAG_member 0x000d +%define DW_TAG_pointer_type 0x000f +%define DW_TAG_reference_type 0x0010 +%define DW_TAG_compile_unit 0x0011 +%define DW_TAG_string_type 0x0012 +%define DW_TAG_structure_type 0x0013 +%define DW_TAG_subroutine_type 0x0015 +%define DW_TAG_typedef 0x0016 +%define DW_TAG_union_type 0x0017 +%define DW_TAG_unspecified_parameters 0x0018 +%define DW_TAG_variant 0x0019 +%define DW_TAG_common_block 0x001a +%define DW_TAG_common_inclusion 0x001b +%define DW_TAG_inheritance 0x001c +%define DW_TAG_inlined_subroutine 0x001d +%define DW_TAG_module 0x001e +%define DW_TAG_ptr_to_member_type 0x001f +%define DW_TAG_set_type 0x0020 +%define DW_TAG_subrange_type 0x0021 +%define DW_TAG_with_stmt 0x0022 +%define DW_TAG_access_declaration 0x0023 +%define DW_TAG_base_type 0x0024 +%define DW_TAG_catch_block 0x0025 +%define DW_TAG_const_type 0x0026 +%define DW_TAG_constant 0x0027 +%define DW_TAG_enumerator 0x0028 +%define DW_TAG_file_type 0x0029 +%define DW_TAG_friend 0x002a +%define DW_TAG_namelist 0x002b +%define DW_TAG_namelist_item 0x002c +%define DW_TAG_packed_type 0x002d +%define DW_TAG_subprogram 0x002e +%define DW_TAG_template_type_parameter 0x002f +%define DW_TAG_template_value_parameter 0x0030 +%define DW_TAG_thrown_type 0x0031 +%define DW_TAG_try_block 0x0032 +%define DW_TAG_variant_part 0x0033 +%define DW_TAG_variable 0x0034 +%define DW_TAG_volatile_type 0x0035 +%define DW_TAG_dwarf_procedure 0x0036 +%define DW_TAG_restrict_type 0x0037 +%define DW_TAG_interface_type 0x0038 +%define DW_TAG_namespace 0x0039 +%define DW_TAG_imported_module 0x003a +%define DW_TAG_unspecified_type 0x003b +%define DW_TAG_partial_unit 0x003c +%define DW_TAG_imported_unit 0x003d +%define DW_TAG_condition 0x003f +%define DW_TAG_shared_type 0x0040 +%define DW_TAG_type_unit 0x0041 +%define DW_TAG_rvalue_reference_type 0x0042 +%define DW_TAG_template_alias 0x0043 +%define DW_TAG_lo_user 0x4080 +%define DW_TAG_GNU_call_site 0x4109 +%define DW_TAG_GNU_call_site_parameter 0x410a +%define DW_TAG_WATCOM_address_class_type 0x4100 +%define DW_TAG_WATCOM_namespace 0x4101 +%define DW_TAG_hi_user 0xffff +%define DW_CHILDREN_yes 1 +%define DW_CHILDREN_no 0 +%define DW_AT_sibling 0x0001 +%define DW_AT_location 0x0002 +%define DW_AT_name 0x0003 +%define DW_AT_ordering 0x0009 +%define DW_AT_byte_size 0x000b +%define DW_AT_bit_offset 0x000c +%define DW_AT_bit_size 0x000d +%define DW_AT_stmt_list 0x0010 +%define DW_AT_low_pc 0x0011 +%define DW_AT_high_pc 0x0012 +%define DW_AT_language 0x0013 +%define DW_AT_discr 0x0015 +%define DW_AT_discr_value 0x0016 +%define DW_AT_visibility 0x0017 +%define DW_AT_import 0x0018 +%define DW_AT_string_length 0x0019 +%define DW_AT_common_reference 0x001a +%define DW_AT_comp_dir 0x001b +%define DW_AT_const_value 0x001c +%define DW_AT_containing_type 0x001d +%define DW_AT_default_value 0x001e +%define DW_AT_inline 0x0020 +%define DW_AT_is_optional 0x0021 +%define DW_AT_lower_bound 0x0022 +%define DW_AT_producer 0x0025 +%define DW_AT_prototyped 0x0027 +%define DW_AT_return_addr 0x002a +%define DW_AT_start_scope 0x002c +%define DW_AT_bit_stride 0x002e +%define DW_AT_upper_bound 0x002f +%define DW_AT_abstract_origin 0x0031 +%define DW_AT_accessibility 0x0032 +%define DW_AT_address_class 0x0033 +%define DW_AT_artificial 0x0034 +%define DW_AT_base_types 0x0035 +%define DW_AT_calling_convention 0x0036 +%define DW_AT_count 0x0037 +%define DW_AT_data_member_location 0x0038 +%define DW_AT_decl_column 0x0039 +%define DW_AT_decl_file 0x003a +%define DW_AT_decl_line 0x003b +%define DW_AT_declaration 0x003c +%define DW_AT_discr_list 0x003d +%define DW_AT_encoding 0x003e +%define DW_AT_external 0x003f +%define DW_AT_frame_base 0x0040 +%define DW_AT_friend 0x0041 +%define DW_AT_identifier_case 0x0042 +%define DW_AT_macro_info 0x0043 +%define DW_AT_namelist_item 0x0044 +%define DW_AT_priority 0x0045 +%define DW_AT_segment 0x0046 +%define DW_AT_specification 0x0047 +%define DW_AT_static_link 0x0048 +%define DW_AT_type 0x0049 +%define DW_AT_use_location 0x004a +%define DW_AT_variable_parameter 0x004b +%define DW_AT_virtuality 0x004c +%define DW_AT_vtable_elem_location 0x004d +%define DW_AT_allocated 0x004e +%define DW_AT_associated 0x004f +%define DW_AT_data_location 0x0050 +%define DW_AT_byte_stride 0x0051 +%define DW_AT_entry_pc 0x0052 +%define DW_AT_use_UTF8 0x0053 +%define DW_AT_extension 0x0054 +%define DW_AT_ranges 0x0055 +%define DW_AT_trampoline 0x0056 +%define DW_AT_call_column 0x0057 +%define DW_AT_call_file 0x0058 +%define DW_AT_call_line 0x0059 +%define DW_AT_description 0x005a +%define DW_AT_binary_scale 0x005b +%define DW_AT_decimal_scale 0x005c +%define DW_AT_small 0x005d +%define DW_AT_decimal_sign 0x005e +%define DW_AT_digit_count 0x005f +%define DW_AT_picture_string 0x0060 +%define DW_AT_mutable 0x0061 +%define DW_AT_threads_scaled 0x0062 +%define DW_AT_explicit 0x0063 +%define DW_AT_object_pointer 0x0064 +%define DW_AT_endianity 0x0065 +%define DW_AT_elemental 0x0066 +%define DW_AT_pure 0x0067 +%define DW_AT_recursive 0x0068 +%define DW_AT_signature 0x0069 +%define DW_AT_main_subprogram 0x006a +%define DW_AT_data_bit_offset 0x006b +%define DW_AT_const_expr 0x006c +%define DW_AT_enum_class 0x006d +%define DW_AT_linkage_name 0x006e +%define DW_AT_lo_user 0x2000 +%define DW_AT_MIPS_linkage_name 0x2007 +%define DW_AT_WATCOM_memory_model 0x2082 +%define DW_AT_WATCOM_references_start 0x2083 +%define DW_AT_WATCOM_parm_entry 0x2084 +%define DW_AT_hi_user 0x3fff +%define DW_FORM_addr 0x01 +%define DW_FORM_block2 0x03 +%define DW_FORM_block4 0x04 +%define DW_FORM_data2 0x05 +%define DW_FORM_data4 0x06 +%define DW_FORM_data8 0x07 +%define DW_FORM_string 0x08 +%define DW_FORM_block 0x09 +%define DW_FORM_block1 0x0a +%define DW_FORM_data1 0x0b +%define DW_FORM_flag 0x0c +%define DW_FORM_sdata 0x0d +%define DW_FORM_strp 0x0e +%define DW_FORM_udata 0x0f +%define DW_FORM_ref_addr 0x10 +%define DW_FORM_ref1 0x11 +%define DW_FORM_ref2 0x12 +%define DW_FORM_ref4 0x13 +%define DW_FORM_ref8 0x14 +%define DW_FORM_ref_udata 0x15 +%define DW_FORM_indirect 0x16 +%define DW_FORM_sec_offset 0x17 +%define DW_FORM_exprloc 0x18 +%define DW_FORM_flag_present 0x19 +%define DW_FORM_ref_sig8 0x20 +%define DW_ADDR_none 0 +%define DW_ADDR_i386_near16 1 +%define DW_ADDR_i386_far16 2 +%define DW_ADDR_i386_huge16 3 +%define DW_ADDR_i386_near32 4 +%define DW_ADDR_i386_far32 5 +%define DW_OP_addr 0x03 +%define DW_OP_deref 0x06 +%define DW_OP_const1u 0x08 +%define DW_OP_const1s 0x09 +%define DW_OP_const2u 0x0a +%define DW_OP_const2s 0x0b +%define DW_OP_const4u 0x0c +%define DW_OP_const4s 0x0d +%define DW_OP_const8u 0x0e +%define DW_OP_const8s 0x0f +%define DW_OP_constu 0x10 +%define DW_OP_consts 0x11 +%define DW_OP_dup 0x12 +%define DW_OP_drop 0x13 +%define DW_OP_over 0x14 +%define DW_OP_pick 0x15 +%define DW_OP_swap 0x16 +%define DW_OP_rot 0x17 +%define DW_OP_xderef 0x18 +%define DW_OP_abs 0x19 +%define DW_OP_and 0x1a +%define DW_OP_div 0x1b +%define DW_OP_minus 0x1c +%define DW_OP_mod 0x1d +%define DW_OP_mul 0x1e +%define DW_OP_neg 0x1f +%define DW_OP_not 0x20 +%define DW_OP_or 0x21 +%define DW_OP_plus 0x22 +%define DW_OP_plus_uconst 0x23 +%define DW_OP_shl 0x24 +%define DW_OP_shr 0x25 +%define DW_OP_shra 0x26 +%define DW_OP_xor 0x27 +%define DW_OP_skip 0x2f +%define DW_OP_bra 0x28 +%define DW_OP_eq 0x29 +%define DW_OP_ge 0x2a +%define DW_OP_gt 0x2b +%define DW_OP_le 0x2c +%define DW_OP_lt 0x2d +%define DW_OP_ne 0x2e +%define DW_OP_lit0 0x30 +%define DW_OP_lit31 0x4f +%define DW_OP_reg0 0x50 +%define DW_OP_reg31 0x6f +%define DW_OP_breg0 0x70 +%define DW_OP_breg31 0x8f +%define DW_OP_regx 0x90 +%define DW_OP_fbreg 0x91 +%define DW_OP_bregx 0x92 +%define DW_OP_piece 0x93 +%define DW_OP_deref_size 0x94 +%define DW_OP_xderef_size 0x95 +%define DW_OP_nop 0x96 +%define DW_OP_lo_user 0xe0 +%define DW_OP_hi_user 0xff +%define DW_EH_PE_FORMAT_MASK 0x0f +%define DW_EH_PE_APPL_MASK 0x70 +%define DW_EH_PE_indirect 0x80 +%define DW_EH_PE_omit 0xff +%define DW_EH_PE_ptr 0x00 +%define DW_EH_PE_uleb128 0x01 +%define DW_EH_PE_udata2 0x02 +%define DW_EH_PE_udata4 0x03 +%define DW_EH_PE_udata8 0x04 +%define DW_EH_PE_sleb128 0x09 +%define DW_EH_PE_sdata2 0x0a +%define DW_EH_PE_sdata4 0x0b +%define DW_EH_PE_sdata8 0x0c +%define DW_EH_PE_absptr 0x00 +%define DW_EH_PE_pcrel 0x10 +%define DW_EH_PE_textrel 0x20 +%define DW_EH_PE_datarel 0x30 +%define DW_EH_PE_funcrel 0x40 +%define DW_EH_PE_aligned 0x50 +%define DW_CFA_high_bit_mask 0xc0 +%define DW_CFA_nop 0x00 +%define DW_CFA_advance_loc 0x40 +%define DW_CFA_set_loc 0x01 +%define DW_CFA_advance_loc1 0x02 +%define DW_CFA_advance_loc2 0x03 +%define DW_CFA_advance_loc4 0x04 +%define DW_CFA_offset 0x80 +%define DW_CFA_offset_extended 0x05 +%define DW_CFA_offset_extended_sf 0x11 +%define DW_CFA_restore 0xc0 +%define DW_CFA_restore_extended 0x06 +%define DW_CFA_undefined 0x07 +%define DW_CFA_same_value 0x08 +%define DW_CFA_register 0x09 +%define DW_CFA_expression 0x10 +%define DW_CFA_val_offset 0x14 +%define DW_CFA_val_offset_sf 0x15 +%define DW_CFA_val_expression 0x16 +%define DW_CFA_remember_state 0x0a +%define DW_CFA_restore_state 0x0b +%define DW_CFA_def_cfa 0x0c +%define DW_CFA_def_cfa_register 0x0d +%define DW_CFA_def_cfa_offset 0x0e +%define DW_CFA_def_cfa_expression 0x0f +%define DW_CFA_def_cfa_sf 0x12 +%define DW_CFA_def_cfa_offset_sf 0x13 +%define DW_CFA_lo_user 0x1c +%define DW_CFA_MIPS_advance_loc8 0x1d +%define DW_CFA_GNU_window_save 0x2d +%define DW_CFA_GNU_args_size 0x2e +%define DW_CFA_GNU_negative_offset_extended 0x2f +%define DW_CFA_hi_user 0x3f +%define DWREG_X86_EAX 0 +%define DWREG_X86_ECX 1 +%define DWREG_X86_EDX 2 +%define DWREG_X86_EBX 3 +%define DWREG_X86_ESP 4 +%define DWREG_X86_EBP 5 +%define DWREG_X86_ESI 6 +%define DWREG_X86_EDI 7 +%define DWREG_X86_RA 8 +%define DWREG_X86_EFLAGS 9 +%define DWREG_X86_ST1 11 +%define DWREG_X86_ST2 12 +%define DWREG_X86_ST3 13 +%define DWREG_X86_ST4 14 +%define DWREG_X86_ST5 15 +%define DWREG_X86_ST6 16 +%define DWREG_X86_ST7 17 +%define DWREG_X86_XMM0 21 +%define DWREG_X86_XMM1 22 +%define DWREG_X86_XMM2 23 +%define DWREG_X86_XMM3 24 +%define DWREG_X86_XMM4 25 +%define DWREG_X86_XMM5 26 +%define DWREG_X86_XMM6 27 +%define DWREG_X86_XMM7 28 +%define DWREG_X86_MM0 29 +%define DWREG_X86_MM1 30 +%define DWREG_X86_MM2 31 +%define DWREG_X86_MM3 32 +%define DWREG_X86_MM4 33 +%define DWREG_X86_MM5 34 +%define DWREG_X86_MM6 35 +%define DWREG_X86_MM7 36 +%define DWREG_X86_MXCSR 39 +%define DWREG_X86_ES 40 +%define DWREG_X86_CS 41 +%define DWREG_X86_SS 42 +%define DWREG_X86_DS 43 +%define DWREG_X86_FS 44 +%define DWREG_X86_GS 45 +%define DWREG_X86_TR 48 +%define DWREG_X86_LDTR 49 +%define DWREG_AMD64_RAX 0 +%define DWREG_AMD64_RDX 1 +%define DWREG_AMD64_RCX 2 +%define DWREG_AMD64_RBX 3 +%define DWREG_AMD64_RSI 4 +%define DWREG_AMD64_RDI 5 +%define DWREG_AMD64_RBP 6 +%define DWREG_AMD64_RSP 7 +%define DWREG_AMD64_R8 8 +%define DWREG_AMD64_R9 9 +%define DWREG_AMD64_R10 10 +%define DWREG_AMD64_R11 11 +%define DWREG_AMD64_R12 12 +%define DWREG_AMD64_R13 13 +%define DWREG_AMD64_R14 14 +%define DWREG_AMD64_R15 15 +%define DWREG_AMD64_RA 16 +%define DWREG_AMD64_XMM0 17 +%define DWREG_AMD64_XMM1 18 +%define DWREG_AMD64_XMM2 19 +%define DWREG_AMD64_XMM3 20 +%define DWREG_AMD64_XMM4 21 +%define DWREG_AMD64_XMM5 22 +%define DWREG_AMD64_XMM6 23 +%define DWREG_AMD64_XMM7 24 +%define DWREG_AMD64_XMM8 25 +%define DWREG_AMD64_XMM9 26 +%define DWREG_AMD64_XMM10 27 +%define DWREG_AMD64_XMM11 28 +%define DWREG_AMD64_XMM12 29 +%define DWREG_AMD64_XMM13 30 +%define DWREG_AMD64_XMM14 31 +%define DWREG_AMD64_XMM15 32 +%define DWREG_AMD64_ST0 33 +%define DWREG_AMD64_ST1 34 +%define DWREG_AMD64_ST2 35 +%define DWREG_AMD64_ST3 36 +%define DWREG_AMD64_ST4 37 +%define DWREG_AMD64_ST5 38 +%define DWREG_AMD64_ST6 39 +%define DWREG_AMD64_ST7 40 +%define DWREG_AMD64_MM0 41 +%define DWREG_AMD64_MM1 42 +%define DWREG_AMD64_MM2 43 +%define DWREG_AMD64_MM3 44 +%define DWREG_AMD64_MM4 45 +%define DWREG_AMD64_MM5 46 +%define DWREG_AMD64_MM6 47 +%define DWREG_AMD64_MM7 48 +%define DWREG_AMD64_RFLAGS 49 +%define DWREG_AMD64_ES 50 +%define DWREG_AMD64_CS 51 +%define DWREG_AMD64_SS 52 +%define DWREG_AMD64_DS 53 +%define DWREG_AMD64_FS 54 +%define DWREG_AMD64_GS 55 +%define DWREG_AMD64_FS_BASE 58 +%define DWREG_AMD64_GS_BASE 59 +%define DWREG_AMD64_TR 62 +%define DWREG_AMD64_LDTR 63 +%define DWREG_AMD64_MXCSR 64 +%define DWREG_AMD64_FCW 65 +%define DWREG_AMD64_FSW 66 +%endif diff --git a/include/iprt/formats/efi-common.h b/include/iprt/formats/efi-common.h new file mode 100644 index 00000000..eb41ac89 --- /dev/null +++ b/include/iprt/formats/efi-common.h @@ -0,0 +1,102 @@ +/* $Id: efi-common.h $ */ +/** @file + * IPRT, EFI common definitions. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_common_h +#define IPRT_INCLUDED_formats_efi_common_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** + * EFI GUID. + */ +typedef struct EFI_GUID +{ + uint32_t u32Data1; + uint16_t u16Data2; + uint16_t u16Data3; + uint8_t abData4[8]; +} EFI_GUID; +AssertCompileSize(EFI_GUID, 16); +/** Pointer to an EFI GUID. */ +typedef EFI_GUID *PEFI_GUID; +/** Pointer to a const EFI GUID. */ +typedef const EFI_GUID *PCEFI_GUID; + + +/** A Null GUID. */ +#define EFI_NULL_GUID { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 }} +/** Global variable GUID. */ +#define EFI_GLOBAL_VARIABLE_GUID \ + { 0x8be4df61, 0x93ca, 0x11d2, { 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c }} +/** SecureBootEnable variable GUID. */ +#define EFI_SECURE_BOOT_ENABLE_DISABLE_GUID \ + { 0xf0a30bc7, 0xaf08, 0x4556, { 0x99, 0xc4, 0x0, 0x10, 0x9, 0xc9, 0x3a, 0x44 } } + + +/** + * EFI time value. + */ +typedef struct EFI_TIME +{ + uint16_t u16Year; + uint8_t u8Month; + uint8_t u8Day; + uint8_t u8Hour; + uint8_t u8Minute; + uint8_t u8Second; + uint8_t bPad0; + uint32_t u32Nanosecond; + int16_t iTimezone; + uint8_t u8Daylight; + uint8_t bPad1; +} EFI_TIME; +AssertCompileSize(EFI_TIME, 16); +/** Pointer to an EFI time abstraction. */ +typedef EFI_TIME *PEFI_TIME; +/** Pointer to a const EFI time abstraction. */ +typedef const EFI_TIME *PCEFI_TIME; + +#define EFI_TIME_TIMEZONE_UNSPECIFIED INT16_C(0x07ff) + +#define EFI_TIME_DAYLIGHT_ADJUST RT_BIT(0) +#define EFI_TIME_DAYLIGHT_INDST RT_BIT(1) + +#endif /* !IPRT_INCLUDED_formats_efi_common_h */ + diff --git a/include/iprt/formats/efi-fat.h b/include/iprt/formats/efi-fat.h new file mode 100644 index 00000000..975fe317 --- /dev/null +++ b/include/iprt/formats/efi-fat.h @@ -0,0 +1,92 @@ +/* $Id: efi-fat.h $ */ +/** @file + * IPRT, EFI FAT Binary (used by Apple, contains multiple architectures). + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_fat_h +#define IPRT_INCLUDED_formats_efi_fat_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/* + * Definitions come from http://refit.sourceforge.net/info/fat_binary.html + */ + +/** + * The header structure. + */ +typedef struct EFI_FATHDR +{ + /** The magic identifying the header .*/ + uint32_t u32Magic; + /** Number of files (one per architecture) embedded into the file. */ + uint32_t cFilesEmbedded; +} EFI_FATHDR; +AssertCompileSize(EFI_FATHDR, 8); +typedef EFI_FATHDR *PEFI_FATHDR; + +/** The magic identifying a FAT header. */ +#define EFI_FATHDR_MAGIC UINT32_C(0x0ef1fab9) + +/** + * The direcory entry. + */ +typedef struct EFI_FATDIRENTRY +{ + /** The CPU type the referenced file is for. */ + uint32_t u32CpuType; + /** The CPU sub-type the referenced file is for. */ + uint32_t u32CpuSubType; + /** Offset in bytes where the file is located. */ + uint32_t u32OffsetStart; + /** Length of the file in bytes. */ + uint32_t cbFile; + /** Alignment used for the file. */ + uint32_t u32Alignment; +} EFI_FATDIRENTRY; +AssertCompileSize(EFI_FATDIRENTRY, 20); +typedef EFI_FATDIRENTRY *PEFI_FATDIRENTRY; + +#define EFI_FATDIRENTRY_CPU_TYPE_X86 UINT32_C(0x7) +#define EFI_FATDIRENTRY_CPU_TYPE_AMD64 UINT32_C(0x01000007) + +#define EFI_FATDIRENTRY_CPU_SUB_TYPE_GENERIC UINT32_C(0x3) + + +#endif /* !IPRT_INCLUDED_formats_efi_fat_h */ + diff --git a/include/iprt/formats/efi-fv.h b/include/iprt/formats/efi-fv.h new file mode 100644 index 00000000..aa68189d --- /dev/null +++ b/include/iprt/formats/efi-fv.h @@ -0,0 +1,131 @@ +/* $Id: efi-fv.h $ */ +/** @file + * IPRT, EFI firmware volume (FV) definitions. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_fv_h +#define IPRT_INCLUDED_formats_efi_fv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/* + * Definitions come from the UEFI PI Spec 1.5 Volume 3 Firmware, chapter 3 "Firmware Storage Code Definitions" + */ + +/** + * The volume header. + */ +typedef struct EFI_FIRMWARE_VOLUME_HEADER +{ + /** Reserved data for the reset vector. */ + uint8_t abZeroVec[16]; + /** The filesystem GUID. */ + EFI_GUID GuidFilesystem; + /** The firmware volume length in bytes including this header. */ + uint64_t cbFv; + /** The signature of the firmware volume header (set to _FVH). */ + uint32_t u32Signature; + /** Firmware volume attributes. */ + uint32_t fAttr; + /** Size of the header in bytes. */ + uint16_t cbFvHdr; + /** Checksum of the header. */ + uint16_t u16Chksum; + /** Offset of the extended header (0 for no extended header). */ + uint16_t offExtHdr; + /** Reserved MBZ. */ + uint8_t bRsvd; + /** Revision of the header. */ + uint8_t bRevision; +} EFI_FIRMWARE_VOLUME_HEADER; +AssertCompileSize(EFI_FIRMWARE_VOLUME_HEADER, 56); +/** Pointer to a EFI firmware volume header. */ +typedef EFI_FIRMWARE_VOLUME_HEADER *PEFI_FIRMWARE_VOLUME_HEADER; +/** Pointer to a const EFI firmware volume header. */ +typedef const EFI_FIRMWARE_VOLUME_HEADER *PCEFI_FIRMWARE_VOLUME_HEADER; + +/** The signature for a firmware volume header. */ +#define EFI_FIRMWARE_VOLUME_HEADER_SIGNATURE RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H') +/** Revision of the firmware volume header. */ +#define EFI_FIRMWARE_VOLUME_HEADER_REVISION 2 + + +/** + * Firmware block map entry. + */ +typedef struct EFI_FW_BLOCK_MAP +{ + /** Number of blocks for this entry. */ + uint32_t cBlocks; + /** Block size in bytes. */ + uint32_t cbBlock; +} EFI_FW_BLOCK_MAP; +AssertCompileSize(EFI_FW_BLOCK_MAP, 8); +/** Pointer to a firmware volume block map entry. */ +typedef EFI_FW_BLOCK_MAP *PEFI_FW_BLOCK_MAP; +/** Pointer to a const firmware volume block map entry. */ +typedef const EFI_FW_BLOCK_MAP *PCEFI_FW_BLOCK_MAP; + + +/** + * Fault tolerant working block header. + */ +typedef struct EFI_FTW_BLOCK_HEADER +{ + /** GUID identifying the FTW block header. */ + EFI_GUID GuidSignature; + /** The checksum. */ + uint32_t u32Chksum; + /** Flags marking the working block area as valid/invalid. */ + uint32_t fWorkingBlockValid; + /** Size of the write queue. */ + uint64_t cbWriteQueue; +} EFI_FTW_BLOCK_HEADER; +/** Pointer to a fault tolerant working block header. */ +typedef EFI_FTW_BLOCK_HEADER *PEFI_FTW_BLOCK_HEADER; +/** Pointer to a const fault tolerant working block header. */ +typedef const EFI_FTW_BLOCK_HEADER *PCEFI_FTW_BLOCK_HEADER; + +/** The signature for the working block header. */ +#define EFI_WORKING_BLOCK_SIGNATURE_GUID \ + { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }} + +#endif /* !IPRT_INCLUDED_formats_efi_fv_h */ + diff --git a/include/iprt/formats/efi-signature.h b/include/iprt/formats/efi-signature.h new file mode 100644 index 00000000..73b4e524 --- /dev/null +++ b/include/iprt/formats/efi-signature.h @@ -0,0 +1,138 @@ +/* $Id: efi-signature.h $ */ +/** @file + * IPRT, EFI signature database definitions. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_signature_h +#define IPRT_INCLUDED_formats_efi_signature_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/* + * Definitions come from the UEFI 2.6 specification, chapter 30.4.1 + */ + +/** The GUID used for setting and retrieving variables from the variable store. */ +#define EFI_IMAGE_SECURITY_DATABASE_GUID \ + { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }} + + +/** + * Signature entry data. + */ +typedef struct EFI_SIGNATURE_DATA +{ + /** The GUID of the owner of the signature. */ + EFI_GUID GuidOwner; + /** The signature data follows (size varies depending on the signature type). */ +} EFI_SIGNATURE_DATA; +AssertCompileSize(EFI_SIGNATURE_DATA, 16); +/** Pointer to a signature entry. */ +typedef EFI_SIGNATURE_DATA *PEFI_SIGNATURE_DATA; +/** Pointer to a const signature entry. */ +typedef const EFI_SIGNATURE_DATA *PCEFI_SIGNATURE_DATA; + +/** Microsoft's GUID for signatures. */ +#define EFI_SIGNATURE_OWNER_GUID_MICROSOFT \ + { 0x77fa9abd, 0x0359, 0x4d32, { 0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b }} + +/** VirtualBox's GUID for signatures. */ +#define EFI_SIGNATURE_OWNER_GUID_VBOX \ + { 0x9400896a, 0x146c, 0x4f4c, { 0x96, 0x47, 0x2c, 0x73, 0x62, 0x0c, 0xa8, 0x94 }} + + +/** + * Signature list header. + */ +typedef struct EFI_SIGNATURE_LIST +{ + /** The signature type stored in this list. */ + EFI_GUID GuidSigType; + /** Size of the signature list in bytes. */ + uint32_t cbSigLst; + /** Size of the optional signature header following this header in bytes. */ + uint32_t cbSigHdr; + /** Size of each signature entry in bytes, must be at least the size of EFI_SIGNATURE_DATA. */ + uint32_t cbSig; + // uint8_t abSigHdr[]; + // EFI_SIGNATURE_DATA aSigs[]; +} EFI_SIGNATURE_LIST; +AssertCompileSize(EFI_SIGNATURE_LIST, 28); +/** Pointer to a signature list header. */ +typedef EFI_SIGNATURE_LIST *PEFI_SIGNATURE_LIST; +/** Pointer to a const signature list header. */ +typedef const EFI_SIGNATURE_LIST *PCEFI_SIGNATURE_LIST; + +/** Signature contains a SHA256 hash. */ +#define EFI_SIGNATURE_TYPE_GUID_SHA256 \ + { 0xc1c41626, 0x504c, 0x4092, { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 }} +/** Size of a SHA256 signature entry (GUID + 32 bytes for the hash). */ +#define EFI_SIGNATURE_TYPE_SZ_SHA256 UINT32_C(48) + +/** Signature contains a RSA2048 key. */ +#define EFI_SIGNATURE_TYPE_GUID_RSA2048 \ + { 0x3c5766e8, 0x269c, 0x4e34, { 0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6 }} +/** Size of a RSA2048 signature entry (GUID + 256 for the key). */ +#define EFI_SIGNATURE_TYPE_SZ_RSA2048 UINT32_C(272) + +/** Signature contains a RSA2048 signature of a SHA256 hash. */ +#define EFI_SIGNATURE_TYPE_GUID_RSA2048_SHA256 \ + { 0xe2b36190, 0x879b, 0x4a3d, { 0xad, 0x8d, 0xf2, 0xe7, 0xbb, 0xa3, 0x27, 0x84 }} +/** Size of a RSA2048 signature entry (GUID + 256 for the key). */ +#define EFI_SIGNATURE_TYPE_SZ_RSA2048_SHA256 UINT32_C(272) + +/** Signature contains a SHA1 hash. */ +#define EFI_SIGNATURE_TYPE_GUID_SHA1 \ + { 0x826ca512, 0xcf10, 0x4ac9, { 0xb1, 0x87, 0xbe, 0x01, 0x49, 0x66, 0x31, 0xbd }} +/** Size of a SHA1 signature entry (GUID + 20 bytes for the hash). */ +#define EFI_SIGNATURE_TYPE_SZ_SHA1 UINT32_C(36) + +/** Signature contains a RSA2048 signature of a SHA1 hash. */ +#define EFI_SIGNATURE_TYPE_GUID_RSA2048_SHA1 \ + { 0x67f8444f, 0x8743, 0x48f1, { 0xa3, 0x28, 0x1e, 0xaa, 0xb8, 0x73, 0x60, 0x80 }} +/** Size of a RSA2048 signature entry (GUID + 256 for the key). */ +#define EFI_SIGNATURE_TYPE_SZ_RSA2048_SHA1 UINT32_C(272) + +/** Signature contains a DER encoded X.509 certificate (size varies with each certificate). */ +#define EFI_SIGNATURE_TYPE_GUID_X509 \ + { 0xa5c059a1, 0x94e4, 0x4aa7, { 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 }} + +#endif /* !IPRT_INCLUDED_formats_efi_signature_h */ + diff --git a/include/iprt/formats/efi-varstore.h b/include/iprt/formats/efi-varstore.h new file mode 100644 index 00000000..9846ef5f --- /dev/null +++ b/include/iprt/formats/efi-varstore.h @@ -0,0 +1,160 @@ +/* $Id: efi-varstore.h $ */ +/** @file + * IPRT, EFI variable store (VarStore) definitions. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_varstore_h +#define IPRT_INCLUDED_formats_efi_varstore_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/* + * Definitions come from the EDK2 sources MdeModulePkg/Include/Guid/VariableFormat.h + */ + +/** The filesystem GUID for a variable store stored in a volume header. */ +#define EFI_VARSTORE_FILESYSTEM_GUID \ + { 0xfff12b8d, 0x7696, 0x4c8b, { 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b, 0x4f, 0x50 }} + + +/** + * The variable store header. + */ +typedef struct EFI_VARSTORE_HEADER +{ + /** The GUID identifying a variable store. */ + EFI_GUID GuidVarStore; + /** Size of the variable store including the header. */ + uint32_t cbVarStore; + /** The format state. */ + uint8_t bFmt; + /** The region health state. */ + uint8_t bState; + /** Reserved. */ + uint8_t abRsvd[6]; +} EFI_VARSTORE_HEADER; +AssertCompileSize(EFI_VARSTORE_HEADER, 28); +/** Pointer to a variable store header. */ +typedef EFI_VARSTORE_HEADER *PEFI_VARSTORE_HEADER; +/** Pointer to a const variable store header. */ +typedef const EFI_VARSTORE_HEADER *PCEFI_VARSTORE_HEADER; + +/** The GUID for a variable store using the authenticated variable header format. */ +#define EFI_VARSTORE_HEADER_GUID_AUTHENTICATED_VARIABLE \ + { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } } +/** The GUID for a variable store using the standard variable header format. */ +#define EFI_VARSTORE_HEADER_GUID_VARIABLE \ + { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } } + +/** The EFI_VARSTORE_HEADER::bFmt value when the store region is formatted. */ +#define EFI_VARSTORE_HEADER_FMT_FORMATTED 0x5a +/** The EFI_VARSTORE_HEADER::bState value when the store region is healthy. */ +#define EFI_VARSTORE_HEADER_STATE_HEALTHY 0xfe + + +/** + * Authenticated variable header. + */ +#pragma pack(1) +typedef struct EFI_AUTH_VAR_HEADER +{ + /** Contains EFI_AUTH_VAR_HEADER_START to identify the start of a new variable header. */ + uint16_t u16StartId; + /** Variable state. */ + uint8_t bState; + /** Reserved. */ + uint8_t bRsvd; + /** Variable attributes. */ + uint32_t fAttr; + /** Monotonic counter value increased with each change to protect against replay attacks. */ + uint64_t cMonotonic; + /** Timestamp value to protect against replay attacks. */ + EFI_TIME Timestamp; + /** Index of associated public key in database. */ + uint32_t idPubKey; + /** Size of the variable zero terminated unicode name in bytes. */ + uint32_t cbName; + /** Size of the variable data without this header. */ + uint32_t cbData; + /** Producer/Consumer GUID for this variable. */ + EFI_GUID GuidVendor; +} EFI_AUTH_VAR_HEADER; +#pragma pack() +AssertCompileSize(EFI_AUTH_VAR_HEADER, 60); +/** Pointer to a authenticated variable header. */ +typedef EFI_AUTH_VAR_HEADER *PEFI_AUTH_VAR_HEADER; +/** Pointer to a const authenticated variable header. */ +typedef const EFI_AUTH_VAR_HEADER *PCEFI_AUTH_VAR_HEADER; + +/** Value in EFI_AUTH_VAR_HEADER::u16StartId for a valid variable header. */ +#define EFI_AUTH_VAR_HEADER_START 0x55aa +/** @name Possible variable states. + * @{ */ +/** Variable is in the process of being deleted. */ +#define EFI_AUTH_VAR_HEADER_STATE_IN_DELETED_TRANSITION 0xfe +/** Variable was deleted. */ +#define EFI_AUTH_VAR_HEADER_STATE_DELETED 0xfd +/** Variable has only a valid header right now. */ +#define EFI_AUTH_VAR_HEADER_STATE_HDR_VALID_ONLY 0x7f +/** Variable header, name and data are all valid. */ +#define EFI_AUTH_VAR_HEADER_STATE_ADDED 0x3f +/** @} */ + + +/** @name Possible variable attributes. + * @{ */ +/** The variable is stored in non volatile memory. */ +#define EFI_VAR_HEADER_ATTR_NON_VOLATILE RT_BIT_32(0) +/** The variable is accessible by the EFI bootservice stage. */ +#define EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS RT_BIT_32(1) +/** The variable is accessible during runtime. */ +#define EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS RT_BIT_32(2) +/** The variable contains an hardware error record. */ +#define EFI_VAR_HEADER_ATTR_HW_ERROR_RECORD RT_BIT_32(3) +/** The variable can be modified only by an authenticated source. */ +#define EFI_AUTH_VAR_HEADER_ATTR_AUTH_WRITE_ACCESS RT_BIT_32(4) +/** The variable was written with a time based authentication. */ +#define EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS RT_BIT_32(5) +/** The variable can be appended. */ +#define EFI_AUTH_VAR_HEADER_ATTR_APPEND_WRITE RT_BIT_32(6) +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_efi_varstore_h */ + diff --git a/include/iprt/formats/elf-amd64.h b/include/iprt/formats/elf-amd64.h new file mode 100644 index 00000000..c0c7f0c1 --- /dev/null +++ b/include/iprt/formats/elf-amd64.h @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 1996-1997 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef IPRT_INCLUDED_formats_elf_amd64_h +#define IPRT_INCLUDED_formats_elf_amd64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* + * ELF definitions for the AMD64 architecture. + */ + +#if 0 /* later */ +/* + * Auxiliary vector entries for passing information to the interpreter. + * + * The i386 supplement to the SVR4 ABI specification names this "auxv_t", + * but POSIX lays claim to all symbols ending with "_t". + */ +typedef struct { /* Auxiliary vector entry on initial stack */ + int a_type; /* Entry type. */ + union { + int a_val; /* Integer value. */ + } a_un; +} Elf32_Auxinfo; + + +typedef struct { /* Auxiliary vector entry on initial stack */ + long a_type; /* Entry type. */ + union { + long a_val; /* Integer value. */ + void *a_ptr; /* Address. */ + void (*a_fcn)(void); /* Function pointer (not used). */ + } a_un; +} Elf64_Auxinfo; + +__ElfType(Auxinfo); + +/* Values for a_type. */ +#define AT_NULL 0 /* Terminates the vector. */ +#define AT_IGNORE 1 /* Ignored entry. */ +#define AT_EXECFD 2 /* File descriptor of program to load. */ +#define AT_PHDR 3 /* Program header of program already loaded. */ +#define AT_PHENT 4 /* Size of each program header entry. */ +#define AT_PHNUM 5 /* Number of program header entries. */ +#define AT_PAGESZ 6 /* Page size in bytes. */ +#define AT_BASE 7 /* Interpreter's base address. */ +#define AT_FLAGS 8 /* Flags (unused for i386). */ +#define AT_ENTRY 9 /* Where interpreter should transfer control. */ + +/* + * The following non-standard values are used for passing information + * from John Polstra's testbed program to the dynamic linker. These + * are expected to go away soon. + * + * Unfortunately, these overlap the Linux non-standard values, so they + * must not be used in the same context. + */ +#define AT_BRK 10 /* Starting point for sbrk and brk. */ +#define AT_DEBUG 11 /* Debugging level. */ + +/* + * The following non-standard values are used in Linux ELF binaries. + */ +#define AT_NOTELF 10 /* Program is not ELF ?? */ +#define AT_UID 11 /* Real uid. */ +#define AT_EUID 12 /* Effective uid. */ +#define AT_GID 13 /* Real gid. */ +#define AT_EGID 14 /* Effective gid. */ + +#define AT_COUNT 15 /* Count of defined aux entry types. */ + +#endif /* later */ + +/* + * Relocation types. + */ + +#define R_X86_64_NONE 0 /* No relocation. */ +#define R_X86_64_64 1 /* Add 64 bit symbol value. */ +#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */ +#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */ +#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */ +#define R_X86_64_COPY 5 /* Copy data from shared object. */ +#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */ +#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */ +#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */ +#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */ +#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */ +#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */ +#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */ +#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */ +#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */ +#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ +#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ + +#define R_X86_64_COUNT 24 /* Count of defined relocation types. */ + +#endif /* !IPRT_INCLUDED_formats_elf_amd64_h */ + diff --git a/include/iprt/formats/elf-common.h b/include/iprt/formats/elf-common.h new file mode 100644 index 00000000..992ebaed --- /dev/null +++ b/include/iprt/formats/elf-common.h @@ -0,0 +1,348 @@ +/*- + * Copyright (c) 1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef IPRT_INCLUDED_formats_elf_common_h +#define IPRT_INCLUDED_formats_elf_common_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* + * ELF definitions that are independent of architecture or word size. + */ + +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +typedef struct { + uint32_t n_namesz; /* Length of name. */ + uint32_t n_descsz; /* Length of descriptor. */ + uint32_t n_type; /* Type of this note. */ +} Elf_Note; + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developer/gabi/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_NONE ELFOSABI_SYSV /* symbol used in old spec */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ + +/* Values for e_machine. */ +#define EM_NONE 0 /* Unknown machine. */ +#define EM_M32 1 /* AT&T WE32100. */ +#define EM_SPARC 2 /* Sun SPARC. */ +#define EM_386 3 /* Intel i386. */ +#define EM_68K 4 /* Motorola 68000. */ +#define EM_88K 5 /* Motorola 88000. */ +#define EM_486 6 /* Intel i486. */ +#define EM_860 7 /* Intel i860. */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ + +/* Extensions. This list is not complete. */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ /* Depreciated */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* SPARC v8plus */ +#define EM_PPC 20 /* PowerPC 32-bit */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_ARM 40 /* ARM */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_IA_64 50 /* Intel IA-64 Processor */ +#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ +#define EM_AMD64 EM_X86_64 /* SunOS compatibility (added by Ramshankar) */ +#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKPROC 0xf0000000 /* Reserved for processor-specific. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ + +#define PT_COUNT 8 /* Number of defined p_type values. */ + +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +#define PT_GNU_EH_FRAME 0x6474e550 /**< GNU/Linux -> .eh_frame_hdr */ +#define PT_GNU_STACK 0x6474e551 /**< GNU/Linux -> stack prot (RWX or RW) */ +#define PT_GNU_RELRO 0x6474e552 /**< GNU/Linux -> make RO after relocations */ +#define PT_GNU_PROPERTY 0x6474e553 /**< GNU/Linux -> .note.gnu.property */ + + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +#define DT_NEEDED 1 /* String table offset of a needed shared + library. */ +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#define DT_HASH 4 /* Address of symbol hash table. */ +#define DT_STRTAB 5 /* Address of string table. */ +#define DT_SYMTAB 6 /* Address of symbol table. */ +#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +#define DT_SONAME 14 /* String table offset of shared object + name. */ +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +#define DT_TEXTREL 22 /* Indicates there may be relocations in + non-writable segments. [sup] */ +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +#define DT_INIT_ARRAY 25 /* Address of the array of pointers to + initialization functions */ +#define DT_FINI_ARRAY 26 /* Address of the array of pointers to + termination functions */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of + initialization functions. */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of + terminationfunctions. */ +#define DT_RUNPATH 29 /* String table offset of a null-terminated + library search path string. */ +#define DT_FLAGS 30 /* Object specific flag values. */ +#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ +#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to + pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of + pre-initialization functions. */ + +#define DT_COUNT 33 /* Number of defined d_tag values. */ + +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_HIOS 0x6fff0000 /* Last OS-specific */ +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for DT_FLAGS */ +#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may + make reference to the $ORIGIN substitution + string */ +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in + non-writable segments. */ +#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ +#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ + +/* Values for n_type. Used in core files. */ +#if defined(RT_OS_FREEBSD) +# define NT_PRSTATUS 1 /* Process status. */ +# define NT_FPREGSET 2 /* Floating point registers. */ +# define NT_PRPSINFO 3 /* Process state info. */ +#elif defined(RT_OS_SOLARIS) +# define NT_PRSTATUS 1 /* prstatus_t */ +# define NT_PRFPREG 2 /* prfpregset_t */ +# define NT_PRPSINFO 3 /* prpsinfo_t */ +# define NT_PRXREG 4 /* prxregset_t */ +# define NT_PLATFORM 5 /* string from sysinfo(SI_PLATFORM) */ +# define NT_AUXV 6 /* auxv_t array */ +# define NT_LDT 9 /* ssd array IA32 only */ +# define NT_PSTATUS 10 /* pstatus_t */ +# define NT_PSINFO 13 /* psinfo_t */ +# define NT_PRCRED 14 /* prcred_t */ +# define NT_UTSNAME 15 /* struct utsname */ +# define NT_LWPSTATUS 16 /* lwpstatus_t */ +# define NT_LWPSINFO 17 /* lwpsinfo_t */ +# define NT_PRPRIV 18 /* prpriv_t */ +# define NT_PRPRIVINFO 19 /* priv_impl_info_t */ +# define NT_CONTENT 20 /* core_content_t */ +# define NT_ZONENAME 21 /* string from getzonenamebyid(3C) */ +# define PF_SUNW_FAILURE 0x00100000 /* mapping absent due to failure */ +# define PN_XNUM 0xffff /* extended program header index */ +#elif defined(RT_OS_LINUX) +# define NT_PRSTATUS 1 /* Process status. */ +# define NT_PRFPREG 2 /* Floating point registers. */ +# define NT_PRPSINFO 3 /* Process state info. */ +# define NT_TASKSTRUCT 4 /* Task info. */ +# define NT_AUXV 6 /* Process auxiliary vectors. */ +# define NT_PRXFPREG 0x46e62b7f /* from gdb5.1/include/elf/common.h */ +#endif +/* GNU Build ID in a dedicated section. */ +#define NT_GNU_BUILD_ID 3 + +/* VirtualBox specific NOTE sections (added by Ramshankar) */ +#ifdef VBOX +# define NT_VBOXCORE 0xb00 +# define NT_VBOXCPU 0xb01 +#endif + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_NUM 7 /* Number of generic symbol types. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +#endif /* !IPRT_INCLUDED_formats_elf_common_h */ + diff --git a/include/iprt/formats/elf-i386.h b/include/iprt/formats/elf-i386.h new file mode 100644 index 00000000..4ebaafc6 --- /dev/null +++ b/include/iprt/formats/elf-i386.h @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 1996-1997 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef IPRT_INCLUDED_formats_elf_i386_h +#define IPRT_INCLUDED_formats_elf_i386_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if 0 /* later */ + +/* + * Auxiliary vector entries for passing information to the interpreter. + * + * The i386 supplement to the SVR4 ABI specification names this "auxv_t", + * but POSIX lays claim to all symbols ending with "_t". + */ + +typedef struct { /* Auxiliary vector entry on initial stack */ + int a_type; /* Entry type. */ + union { + long a_val; /* Integer value. */ + void *a_ptr; /* Address. */ + void (*a_fcn)(void); /* Function pointer (not used). */ + } a_un; +} Elf32_Auxinfo; + +#if __ELF_WORD_SIZE == 64 +/* Fake for amd64 loader support */ +typedef struct { + int fake; +} Elf64_Auxinfo; +#endif + +/* Values for a_type. */ +#define AT_NULL 0 /* Terminates the vector. */ +#define AT_IGNORE 1 /* Ignored entry. */ +#define AT_EXECFD 2 /* File descriptor of program to load. */ +#define AT_PHDR 3 /* Program header of program already loaded. */ +#define AT_PHENT 4 /* Size of each program header entry. */ +#define AT_PHNUM 5 /* Number of program header entries. */ +#define AT_PAGESZ 6 /* Page size in bytes. */ +#define AT_BASE 7 /* Interpreter's base address. */ +#define AT_FLAGS 8 /* Flags (unused for i386). */ +#define AT_ENTRY 9 /* Where interpreter should transfer control. */ + +/* + * The following non-standard values are used for passing information + * from John Polstra's testbed program to the dynamic linker. These + * are expected to go away soon. + * + * Unfortunately, these overlap the Linux non-standard values, so they + * must not be used in the same context. + */ +#define AT_BRK 10 /* Starting point for sbrk and brk. */ +#define AT_DEBUG 11 /* Debugging level. */ + +/* + * The following non-standard values are used in Linux ELF binaries. + */ +#define AT_NOTELF 10 /* Program is not ELF ?? */ +#define AT_UID 11 /* Real uid. */ +#define AT_EUID 12 /* Effective uid. */ +#define AT_GID 13 /* Real gid. */ +#define AT_EGID 14 /* Effective gid. */ + +#define AT_COUNT 15 /* Count of defined aux entry types. */ + +#endif /* later */ + + +/* + * Relocation types. + */ + +#define R_386_NONE 0 /* No relocation. */ +#define R_386_32 1 /* Add symbol value. */ +#define R_386_PC32 2 /* Add PC-relative symbol value. */ +#define R_386_GOT32 3 /* Add PC-relative GOT offset. */ +#define R_386_PLT32 4 /* Add PC-relative PLT offset. */ +#define R_386_COPY 5 /* Copy data from shared object. */ +#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_386_RELATIVE 8 /* Add load address of shared object. */ +#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ +#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ +#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ +#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ +#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ +#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ +#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ +#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ +#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ +#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ +#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ +#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ +#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ + +#define R_386_COUNT 38 /* Count of defined relocation types. */ + +#endif /* !IPRT_INCLUDED_formats_elf_i386_h */ + diff --git a/include/iprt/formats/elf.h b/include/iprt/formats/elf.h new file mode 100644 index 00000000..e7daab46 --- /dev/null +++ b/include/iprt/formats/elf.h @@ -0,0 +1,98 @@ +/* $Id: elf.h $ */ +/** @file + * ELF types, current architecture. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_elf_h +#define IPRT_INCLUDED_formats_elf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) +# include "elf64.h" +typedef Elf64_Addr Elf_Addr; +typedef Elf64_Half Elf_Half; +typedef Elf64_Off Elf_Off; +typedef Elf64_Sword Elf_Sword; +typedef Elf64_Word Elf_Word; +typedef Elf64_Size Elf_Size; +typedef Elf64_Hashelt Elf_Hashelt; +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Nhdr Elf_Nhdr; +typedef Elf64_Dyn Elf_Dyn; +typedef Elf64_Rel Elf_Rel; +typedef Elf64_Rela Elf_Rela; +typedef Elf64_Sym Elf_Sym; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_R_INFO ELF64_R_INFO +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE +#define ELF_ST_INFO ELF64_ST_INFO + +#elif defined(RT_ARCH_X86) +# include "elf32.h" +typedef Elf32_Addr Elf_Addr; +typedef Elf32_Half Elf_Half; +typedef Elf32_Off Elf_Off; +typedef Elf32_Sword Elf_Sword; +typedef Elf32_Word Elf_Word; +typedef Elf32_Size Elf_Size; +typedef Elf32_Hashelt Elf_Hashelt; +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Nhdr Elf_Nhdr; +typedef Elf32_Dyn Elf_Dyn; +typedef Elf32_Rel Elf_Rel; +typedef Elf32_Rela Elf_Rela; +typedef Elf32_Sym Elf_Sym; + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_R_INFO ELF32_R_INFO +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE +#define ELF_ST_INFO ELF32_ST_INFO + +#else +# error Unknown arch! +#endif + +#endif /* !IPRT_INCLUDED_formats_elf_h */ + diff --git a/include/iprt/formats/elf32.h b/include/iprt/formats/elf32.h new file mode 100644 index 00000000..ae322bb6 --- /dev/null +++ b/include/iprt/formats/elf32.h @@ -0,0 +1,200 @@ +/* $Id: elf32.h $ */ +/** @file + * IPRT - ELF 32-bit header. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_elf32_h +#define IPRT_INCLUDED_formats_elf32_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include "elf-common.h" + +/* + * ELF 32 standard types. + */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* + * Ensure type size correctness in accordance to . + * Portable Format Specification (for ELF), Version 1.1, fig 1-2. . + */ +AssertCompileSize(Elf32_Addr, 4); +AssertCompileSize(Elf32_Half, 2); +AssertCompileSize(Elf32_Off, 4); +AssertCompileSize(Elf32_Sword, 4); +AssertCompileSize(Elf32_Word, 4); + +/* + * ELF 32 non-standard types for convenience. + */ +typedef Elf32_Word Elf32_Size; +typedef Elf32_Word Elf32_Hashelt; + +/* + * ELF header. + */ +typedef struct +{ + unsigned char e_ident[16]; /* ELF identification. */ + Elf32_Half e_type; /* Object file type. */ + Elf32_Half e_machine; /* Machine type. */ + Elf32_Word e_version; /* Object file version. */ + Elf32_Addr e_entry; /* Entry point address. */ + Elf32_Off e_phoff; /* Program header offset. */ + Elf32_Off e_shoff; /* Section header offset. */ + Elf32_Word e_flags; /* Processor-specific flags. */ + Elf32_Half e_ehsize; /* ELF header size. */ + Elf32_Half e_phentsize; /* Size of program header entries. */ + Elf32_Half e_phnum; /* Number of program headers. */ + Elf32_Half e_shentsize; /* Size of section header entries. */ + Elf32_Half e_shnum; /* Number of section headers. */ + Elf32_Half e_shstrndx; /* Section name string table index. */ +} Elf32_Ehdr; + +/* + * Section header. + */ +typedef struct +{ + Elf32_Word sh_name; /* Section name. */ + Elf32_Word sh_type; /* Section type. */ + Elf32_Word sh_flags; /* Section attributes. */ + Elf32_Addr sh_addr; /* Virtual address in memory. */ + Elf32_Off sh_offset; /* Offset in file. */ + Elf32_Word sh_size; /* Size of section. */ + Elf32_Word sh_link; /* Link to other section. */ + Elf32_Word sh_info; /* Miscellaneous information. */ + Elf32_Word sh_addralign; /* Address alignment boundary. */ + Elf32_Word sh_entsize; /* Size of entries, if section has table. */ +} Elf32_Shdr; + + +/* + * Program header. + */ +typedef struct +{ + Elf32_Word p_type; /* Type of segment. */ + Elf32_Off p_offset; /* Offset in file. */ + Elf32_Addr p_vaddr; /* Virtual address in memory. */ + Elf32_Addr p_paddr; /* Physical address (reserved). */ + Elf32_Word p_filesz; /* Size of segment in file. */ + Elf32_Word p_memsz; /* Size of segment in memory. */ + Elf32_Word p_flags; /* Segment attributes. */ + Elf32_Word p_align; /* Alignment of segment. */ +} Elf32_Phdr; + + +/* + * Note header. + */ +typedef struct +{ + Elf32_Word n_namesz; /* Length of note's name. */ + Elf32_Word n_descsz; /* Length of note's description. */ + Elf32_Word n_type; /* Type of note. */ +} Elf32_Nhdr; + + +/* + * Symbol table entry. + */ +typedef struct +{ + Elf32_Word st_name; /* Symbol name. */ + Elf32_Addr st_value; /* Symbol value. */ + Elf32_Word st_size; /* Size associated with symbol. */ + unsigned char st_info; /* Type and binding attributes. */ + unsigned char st_other; /* Reserved. */ + Elf32_Half st_shndx; /* Section header table index. */ +} Elf32_Sym; + + +/* + * Relocations. + */ +typedef struct +{ + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Symbol index and type of relocation. */ +} Elf32_Rel; + +typedef struct +{ + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Symbol index and type of relocation. */ + Elf32_Sword r_addend; /* Constant part of expression. */ +} Elf32_Rela; + +/* + * Dynamic section entry. + * ".dynamic" section contains an array of this. + */ +typedef struct +{ + Elf32_Sword d_tag; /* Type of entry. */ + union + { + Elf32_Word d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Virtual address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Helper macros. + */ +/** The symbol's type. */ +#define ELF32_ST_TYPE(info) ((info) & 0xF) +/** The symbol's binding. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +/** Make st_info. given binding and type. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/** Relocation type. */ +#define ELF32_R_TYPE(info) ((unsigned char)(info)) +/** Relocation symbol index. */ +#define ELF32_R_SYM(info) ((info) >> 8) +/** Make r_info given the symbol index and type. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + + +#endif /* !IPRT_INCLUDED_formats_elf32_h */ + diff --git a/include/iprt/formats/elf64.h b/include/iprt/formats/elf64.h new file mode 100644 index 00000000..63d4b1cb --- /dev/null +++ b/include/iprt/formats/elf64.h @@ -0,0 +1,199 @@ +/* $Id: elf64.h $ */ +/** @file + * IPRT - ELF 64-bit header. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_elf64_h +#define IPRT_INCLUDED_formats_elf64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include "elf-common.h" + +/* + * ELF 64 standard types. + */ +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* + * Ensure type size correctness in accordance to ELF-64 Object File Format, Version 1.5 Draft 2, p2. + */ +AssertCompileSize(Elf64_Addr, 8); +AssertCompileSize(Elf64_Off, 8); +AssertCompileSize(Elf64_Half, 2); +AssertCompileSize(Elf64_Word, 4); +AssertCompileSize(Elf64_Sword, 4); +AssertCompileSize(Elf64_Xword, 8); +AssertCompileSize(Elf64_Sxword, 8); + +/* + * ELF 64 non-standard types for convenience. + */ +typedef Elf64_Xword Elf64_Size; +typedef Elf64_Word Elf64_Hashelt; + +/* + * ELF Header. + */ +typedef struct +{ + unsigned char e_ident[16]; /* ELF identification. */ + Elf64_Half e_type; /* Object file type. */ + Elf64_Half e_machine; /* Machine type. */ + Elf64_Word e_version; /* Object file version. */ + Elf64_Addr e_entry; /* Entry point address. */ + Elf64_Off e_phoff; /* Program header offset. */ + Elf64_Off e_shoff; /* Section header offset. */ + Elf64_Word e_flags; /* Processor-specific flags. */ + Elf64_Half e_ehsize; /* ELF header size. */ + Elf64_Half e_phentsize; /* Size of program header entry. */ + Elf64_Half e_phnum; /* Number of program header entries. */ + Elf64_Half e_shentsize; /* Size of section header entry. */ + Elf64_Half e_shnum; /* Number of section header entries. */ + Elf64_Half e_shstrndx; /* Section name string table index. */ +} Elf64_Ehdr; + +/* + * Section header. + */ +typedef struct +{ + Elf64_Word sh_name; /* Section name. */ + Elf64_Word sh_type; /* Section type. */ + Elf64_Xword sh_flags; /* Section attributes. */ + Elf64_Addr sh_addr; /* Virtual address in memory. */ + Elf64_Off sh_offset; /* Offset in file. */ + Elf64_Xword sh_size; /* Size of section. */ + Elf64_Word sh_link; /* Link to other section. */ + Elf64_Word sh_info; /* Miscellaneous information. */ + Elf64_Xword sh_addralign; /* Address alignment boundary. */ + Elf64_Xword sh_entsize; /* Size of entries, if section has table. */ +} Elf64_Shdr; + +/* + * Program header. + */ +typedef struct +{ + Elf64_Word p_type; /* Type of segment. */ + Elf64_Word p_flags; /* Segment attributes. */ + Elf64_Off p_offset; /* Offset in file. */ + Elf64_Addr p_vaddr; /* Virtual address in memory. */ + Elf64_Addr p_paddr; /* Physical address (reserved). */ + Elf64_Xword p_filesz; /* Size of segment in file. */ + Elf64_Xword p_memsz; /* Size of segment in memory. */ + Elf64_Xword p_align; /* Alignment of segment. */ +} Elf64_Phdr; + +/* + * Note header. + */ +typedef struct +{ + Elf64_Word n_namesz; /* Length of note's name. */ + Elf64_Word n_descsz; /* Length of note's description. */ + Elf64_Word n_type; /* Type of note. */ +} Elf64_Nhdr; + +/* + * Symbol table entry. + */ +typedef struct +{ + Elf64_Word st_name; /* Symbol name. */ + unsigned char st_info; /* Type and binding attributes. */ + unsigned char st_other; /* Reserved. */ + Elf64_Half st_shndx; /* Section header table index. */ + Elf64_Addr st_value; /* Symbol value. */ + Elf64_Xword st_size; /* Size associated with symbol. */ +} Elf64_Sym; + +/* + * Relocations. + */ +typedef struct +{ + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Symbol index and type of relocation. */ +} Elf64_Rel; + +typedef struct +{ + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Symbol index and type of relocation. */ + Elf64_Sxword r_addend; /* Constant part of expression. */ +} Elf64_Rela; + +/* + * Dynamic section entry. + * ".dynamic" section contains an array of this. + */ +typedef struct +{ + Elf64_Sxword d_tag; /* Type of entry. */ + union + { + Elf64_Xword d_val; /* Integer value. */ + Elf64_Addr d_ptr; /* Virtual address value. */ + } d_un; +} Elf64_Dyn; + +/* + * Helper macros. + */ +/** The symbol's type. */ +#define ELF64_ST_TYPE(info) ((info) & 0xF) +/** The symbol's binding. */ +#define ELF64_ST_BIND(info) ((info) >> 4) +/** Make st_info. given binding and type. */ +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/** Relocation type. */ +#define ELF64_R_TYPE(info) ((unsigned char)(info)) +/** Relocation symbol index. */ +#define ELF64_R_SYM(info) ((info) >> 32) +/** Make r_info given the symbol index and type. */ +#define ELF64_R_INFO(sym, type) (((sym) << 32) + (unsigned char)(type)) + + +#endif /* !IPRT_INCLUDED_formats_elf64_h */ + diff --git a/include/iprt/formats/ext.h b/include/iprt/formats/ext.h new file mode 100644 index 00000000..e9b137a4 --- /dev/null +++ b/include/iprt/formats/ext.h @@ -0,0 +1,998 @@ +/* $Id: ext.h $ */ +/** @file + * IPRT, Ext2/3/4 format. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_ext_h +#define IPRT_INCLUDED_formats_ext_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_ext Extended Filesystem (EXT2/3/4) structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/* + * The filesystem structures were retrieved from: + * https://www.kernel.org/doc/html/latest/filesystems/ext4/index.html + */ + +/** Offset where to find the first superblock on the disk, this is constant. */ +#define EXT_SB_OFFSET 1024 + +/** @name EXT_INODE_NR_XXX - Special inode numbers. + * @{ */ +#define EXT_INODE_NR_DEF_BLOCKS 1 /**< List of defective blocks. */ +#define EXT_INODE_NR_ROOT_DIR 2 /**< Root directory. */ +#define EXT_INODE_NR_USER_QUOTA 3 /**< User quota. */ +#define EXT_INODE_NR_GROUP_QUOTA 4 /**< Group quota. */ +#define EXT_INODE_NR_BOOT_LOADER 5 /**< Boot loader. */ +#define EXT_INODE_NR_UNDEL_DIR 6 /**< Undelete directory. */ +#define EXT_INODE_NR_RESV_GRP_DESC 7 /**< Reserved group descriptors inode. */ +#define EXT_INODE_NR_JOURNAL 8 /**< Journal. */ +#define EXT_INODE_NR_EXCLUDE 9 /**< Exclude inode. */ +#define EXT_INODE_NR_REPLICA 10 /**< Replica inode. */ +/** @} */ + +/** + * Ext superblock. + * + * Everything is stored little endian on the disk. + */ +typedef struct EXTSUPERBLOCK +{ + /** 0x00: Total number of inodes in the filesystem. */ + uint32_t cInodesTotal; + /** 0x04: Total number of blocks in the filesystem (low 32bits). */ + uint32_t cBlocksTotalLow; + /** 0x08: Number of blocks reserved for the super user (low 32bits). */ + uint32_t cBlocksRsvdForSuperUserLow; + /** 0x0c: Total number of free blocks (low 32bits). */ + uint32_t cBlocksFreeLow; + /** 0x10: Total number of free inodes. */ + uint32_t cInodesFree; + /** 0x14: First data block. */ + uint32_t iBlockOfSuperblock; + /** 0x18: Block size (calculated as 2^(10 + cBitsShiftLeftBlockSize)). */ + uint32_t cLogBlockSize; + /** 0x1c: Cluster size (calculated as 2^cLogClusterSize). */ + uint32_t cLogClusterSize; + /** 0x20: Number of blocks in each block group. */ + uint32_t cBlocksPerGroup; + /** 0x24: Number of clusters in each block group. */ + uint32_t cClustersPerBlockGroup; + /** 0x28: Number of inodes for each block group. */ + uint32_t cInodesPerBlockGroup; + /** 0x2c: Last mount time in seconds since epoch. */ + uint32_t u32LastMountTime; + /** 0x30: Last written time in seconds since epoch. */ + uint32_t u32LastWrittenTime; + /** 0x34: Number of times the volume was mounted since the last check. */ + uint16_t cMountsSinceLastCheck; + /** 0x36: Number of mounts allowed before a consistency check. */ + uint16_t cMaxMountsUntilCheck; + /** 0x38: Signature to identify a ext2 volume (EXT_SIGNATURE). */ + uint16_t u16Signature; + /** 0x3a: State of the filesystem (EXT_SB_STATE_XXX) */ + uint16_t u16FilesystemState; + /** 0x3c: What to do on an error. */ + uint16_t u16ActionOnError; + /** 0x3e: Minor revision level. */ + uint16_t u16RevLvlMinor; + /** 0x40: Time of last check in seconds since epoch. */ + uint32_t u32LastCheckTime; + /** 0x44: Interval between consistency checks in seconds. */ + uint32_t u32CheckInterval; + /** 0x48: Operating system ID of the filesystem creator (EXT_SB_OS_ID_CREATOR_XXX). */ + uint32_t u32OsIdCreator; + /** 0x4c: Revision level (EXT_SB_REV_XXX). */ + uint32_t u32RevLvl; + /** 0x50: User ID that is allowed to use reserved blocks. */ + uint16_t u16UidReservedBlocks; + /** 0x52: Group ID that is allowed to use reserved blocks. */ + uint16_t u16GidReservedBlocks; + /** 0x54: First non reserved inode number. */ + uint32_t iFirstInodeNonRsvd; + /** 0x58: Size of the inode structure in bytes. */ + uint16_t cbInode; + /** 0x5a: Block group number of this super block. */ + uint16_t iBlkGrpSb; + /** 0x5c: Compatible feature set flags (EXT_SB_FEAT_COMPAT_XXX). */ + uint32_t fFeaturesCompat; + /** 0x60: Incompatible feature set (EXT_SB_FEAT_INCOMPAT_XXX). */ + uint32_t fFeaturesIncompat; + /** 0x64: Readonly-compatible feature set (EXT_SB_FEAT_COMPAT_RO_XXX). */ + uint32_t fFeaturesCompatRo; + /** 0x68: 128bit UUID for the volume. */ + uint8_t au8Uuid[16]; + /** 0x78: Volume name. */ + char achVolumeName[16]; + /** 0x88: Directory were the filesystem was mounted last. */ + char achLastMounted[64]; + /** 0xc8: Bitmap usage algorithm (used for compression). */ + uint32_t u32AlgoUsageBitmap; + /** 0xcc: Number of blocks to try to preallocate for files(?). */ + uint8_t cBlocksPrealloc; + /** 0xcd: Number of blocks to try to preallocate for directories. */ + uint8_t cBlocksPreallocDirectory; + /** 0xce: Number of reserved group descriptor entries for future filesystem expansion. */ + uint16_t cGdtEntriesRsvd; + /** 0xd0: 128bit UUID for the journal superblock. */ + uint8_t au8JournalUuid[16]; + /** 0xe0: Inode number of the journal file. */ + uint32_t iJournalInode; + /** 0xe4: Device number of journal file (if the appropriate feature flag is set). */ + uint32_t u32JournalDev; + /** 0xe8: Start of list of orpaned inodes to delete. */ + uint32_t u32LastOrphan; + /** 0xec: HTREE hash seed. */ + uint32_t au32HashSeedHtree[4]; + /** 0xfc: Default hash algorithm to use for hashes (EXT_SB_HASH_VERSION_DEF_XXX). */ + uint8_t u8HashVersionDef; + /** 0xfd: Journal backup type. */ + uint8_t u8JnlBackupType; + /** 0xfe: Group descriptor size in bytes. */ + uint16_t cbGroupDesc; + /** 0x100: Default mount options (EXT_SB_MNT_OPTS_DEF_XXX). */ + uint32_t fMntOptsDef; + /** 0x104: First metablock block group (if feature is enabled). */ + uint32_t iFirstMetaBg; + /** 0x108: Filesystem creation time in seconds since epoch. */ + uint32_t u32TimeFsCreation; + /** 0x10c: Backup copy of journals inodes block array for the first elements. */ + uint32_t au32JnlBlocks[17]; + /** 0x150: Total number of blocks in the filesystem (high 32bits). */ + uint32_t cBlocksTotalHigh; + /** 0x154: Number of blocks reserved for the super user (high 32bits). */ + uint32_t cBlocksRsvdForSuperUserHigh; + /** 0x158: Total number of free blocks (high 32bits). */ + uint32_t cBlocksFreeHigh; + /** 0x15c: All inodes have at least this number of bytes. */ + uint16_t cbInodesExtraMin; + /** 0x15e: New inodes should reserve this number of bytes. */ + uint16_t cbNewInodesRsv; + /** 0x160: Miscellaneous flags (EXT_SB_F_XXX). */ + uint32_t fFlags; + /** 0x164: RAID stride, number of logical blocks read from or written to the disk + * before moving to the next disk. */ + uint16_t cRaidStride; + /** 0x166: Number of seconds between multi-mount prevention checking. */ + uint16_t cSecMmpInterval; + /** 0x168: Block number for the multi-mount protection data. */ + uint64_t iMmpBlock; + /** 0x170: Raid stride width. */ + uint32_t cRaidStrideWidth; + /** 0x174: Size of a flexible block group (calculated as 2^cLogGroupsPerFlex). */ + uint8_t cLogGroupsPerFlex; + /** 0x175: Metadata checksum algorithm type, only 1 is valid (for CRC32c). */ + uint8_t u8ChksumType; + /** 0x176: Padding. */ + uint16_t u16Padding; + /** 0x178: Number of KiB written to the filesystem so far. */ + uint64_t cKbWritten; + /** 0x180: Inode number of active snapshot. */ + uint32_t iSnapshotInode; + /** 0x184: Sequential ID of active snapshot. */ + uint32_t iSnapshotId; + /** 0x188: Number of blocks reserved for activ snapshot's future use. */ + uint64_t cSnapshotRsvdBlocks; + /** 0x190: Inode number of the head of the on-disk snapshot list. */ + uint32_t iSnapshotListInode; + /** 0x194: Number of errors seen so far. */ + uint32_t cErrorsSeen; + /** 0x198: First time an error happened in seconds since epoch. */ + uint32_t u32TimeFirstError; + /** 0x19c: Inode involved in the first error. */ + uint32_t iInodeFirstError; + /** 0x1a0: Number of block involved of first error. */ + uint64_t iBlkFirstError; + /** 0x1a8: Name of the function where the first error happened. */ + char achFuncFirstError[32]; + /** 0x1c8: Line number where the error happened. */ + uint32_t iLineFirstError; + /** 0x1cc: Time of the most receent error in seconds since epoch. */ + uint32_t u32TimeLastError; + /** 0x1d0: Inode involved in the most recent error. */ + uint32_t iInodeLastError; + /** 0x1d4: Line number where the most recent error happened. */ + uint32_t iLineLastError; + /** 0x1d8: Number of block involved of most recent error. */ + uint64_t iBlkLastError; + /** 0x1e0: Name of the function where the most recent error happened. */ + char achFuncLastError[32]; + /** 0x200: ASCIIz string of mount options. */ + char aszMntOpts[64]; + /** 0x240: Inode number of user quota file. */ + uint32_t iInodeUsrQuota; + /** 0x244: Inode number of group quota file. */ + uint32_t iInodeGrpQuota; + /** 0x248: Overhead blocks/clusters in filesystem. */ + uint32_t cOverheadBlocks; + /** 0x24c: Block groups containing superblock backups. */ + uint32_t aiBlkGrpSbBackups[2]; + /** 0x254: Encryption algorithms in use (EXT_SB_ENCRYPT_ALGO_XXX). */ + uint8_t au8EncryptAlgo[4]; + /** 0x258: Salt for the string2key algorithm for encryption. */ + uint8_t abEncryptPwSalt[16]; + /** 0x268: Inode number of lost+found. */ + uint32_t iInodeLostFound; + /** 0x26c: Inode that tracks project quotas. */ + uint32_t iInodeProjQuota; + /** 0x270: Checksum seed used for the metadata checksum calculations. + * Should be crc32c(~0, au8Uuid). */ + uint32_t u32ChksumSeed; + /** 0x274: Upper 8bits of the u32LastWrittenTime field. */ + uint8_t u32LastWrittenTimeHigh8Bits; + /** 0x275: Upper 8bits of the u32LastMountTime field. */ + uint8_t u32LastMountTimeHigh8Bits; + /** 0x276: Upper 8bits of the u32TimeFsCreation field. */ + uint8_t u32TimeFsCreationHigh8Bits; + /** 0x277: Upper 8bits of the u32LastCheckTime field. */ + uint8_t u32LastCheckTimeHigh8Bits; + /** 0x278: Upper 8bits of the u32TimeFirstError field. */ + uint8_t u32TimeFirstErrorHigh8Bits; + /** 0x279: Upper 8bits of the u32TimeLastError field. */ + uint8_t u32TimeLastErrorHigh8Bits; + /** 0x27a: Zero padding. */ + uint8_t au8Padding[2]; + /** 0x27c: Padding to the end of the block. */ + uint32_t au32Rsvd[96]; + /** 0x3fc: Superblock checksum. */ + uint32_t u32Chksum; +} EXTSUPERBLOCK; +AssertCompileMemberOffset(EXTSUPERBLOCK, u16UidReservedBlocks, 0x50); +AssertCompileMemberOffset(EXTSUPERBLOCK, u32AlgoUsageBitmap, 0xc8); +AssertCompileMemberOffset(EXTSUPERBLOCK, iJournalInode, 0xe0); +AssertCompileMemberOffset(EXTSUPERBLOCK, u8HashVersionDef, 0xfc); +AssertCompileMemberOffset(EXTSUPERBLOCK, fMntOptsDef, 0x100); +AssertCompileMemberOffset(EXTSUPERBLOCK, iBlkLastError, 0x1d8); +AssertCompileMemberOffset(EXTSUPERBLOCK, iInodeLostFound, 0x268); +AssertCompileSize(EXTSUPERBLOCK, 1024); +/** Pointer to an ext super block. */ +typedef EXTSUPERBLOCK *PEXTSUPERBLOCK; +/** Pointer to a const ext super block. */ +typedef EXTSUPERBLOCK const *PCEXTSUPERBLOCK; + +/** Ext signature. */ +#define EXT_SB_SIGNATURE UINT16_C(0xef53) + +/** @name EXT_SB_STATE_XXX - Filesystem state + * @{ */ +/** Clean filesystem state. */ +#define EXT_SB_STATE_CLEAN UINT16_C(0x0001) +/** Error filesystem state. */ +#define EXT_SB_STATE_ERRORS UINT16_C(0x0002) +/** Orphans being recovered state. */ +#define EXT_SB_STATE_ORPHANS_RECOVERING UINT16_C(0x0004) +/** @} */ + +/** @name EXT_SB_OS_ID_CREATOR_XXX - Filesystem creator + * @{ */ +/** Linux. */ +#define EXT_SB_OS_ID_CREATOR_LINUX 0 +/** Hurd. */ +#define EXT_SB_OS_ID_CREATOR_HURD 1 +/** Masix. */ +#define EXT_SB_OS_ID_CREATOR_MASIX 2 +/** FreeBSD. */ +#define EXT_SB_OS_ID_CREATOR_FREEBSD 3 +/** Lites. */ +#define EXT_SB_OS_ID_CREATOR_LITES 4 +/** @} */ + +/** @name EXT_SB_REV_XXX - Superblock revision + * @{ */ +/** Original format (ext2). */ +#define EXT_SB_REV_ORIG 0 +/** Inodes have dynmic sizes. */ +#define EXT_SB_REV_V2_DYN_INODE_SZ 1 +/** @} */ + +/** @name EXT_SB_FEAT_COMPAT_XXX - Compatible features which can be ignored when set + * and not being supported. + * @{ */ +/** Directories can be preallocated. */ +#define EXT_SB_FEAT_COMPAT_DIR_PREALLOC RT_BIT_32(0) +/** Some sort of "imagic" inodes. */ +#define EXT_SB_FEAT_COMPAT_IMAGIC_INODES RT_BIT_32(1) +/** Filesystem has a journal. */ +#define EXT_SB_FEAT_COMPAT_HAS_JOURNAL RT_BIT_32(2) +/** Filesystem supports extended attributes. */ +#define EXT_SB_FEAT_COMPAT_EXT_ATTR RT_BIT_32(3) +/** Filesystem contains reserved group descriptor blocks for filesystem expansion. */ +#define EXT_SB_FEAT_COMPAT_RESIZE_INODE RT_BIT_32(4) +/** Filesystem contains directory indices. */ +#define EXT_SB_FEAT_COMPAT_DIR_INDEX RT_BIT_32(5) +/** Lazy block group - not used. */ +#define EXT_SB_FEAT_COMPAT_LAZY_BG RT_BIT_32(6) +/** Exclude inode - not used. */ +#define EXT_SB_FEAT_COMPAT_EXCLUDE_INODE RT_BIT_32(7) +/** Exclude bitmap - not used. */ +#define EXT_SB_FEAT_COMPAT_EXCLUDE_BITMAP RT_BIT_32(8) +/** Sparse super blocks, super block contains pointers to block groups + * containing backups of the superblock. */ +#define EXT_SB_FEAT_COMPAT_SPARSE_SUPER2 RT_BIT_32(9) +/** @} */ + +/** @name EXT_SB_FEAT_INCOMPAT_XXX - Incompatible features which cause a mounting + * error when set and not being supported. + * @{ */ +/** Filesystem contains compressed files. */ +#define EXT_SB_FEAT_INCOMPAT_COMPRESSION RT_BIT_32(0) +/** Directory entries contain a file type. */ +#define EXT_SB_FEAT_INCOMPAT_DIR_FILETYPE RT_BIT_32(1) +/** Filesystem needs recovery. */ +#define EXT_SB_FEAT_INCOMPAT_RECOVER RT_BIT_32(2) +/** The journal is recorded on a separate device. */ +#define EXT_SB_FEAT_INCOMPAT_JOURNAL_DEV RT_BIT_32(3) +/** Filesystem uses meta block groups. */ +#define EXT_SB_FEAT_INCOMPAT_META_BG RT_BIT_32(4) +/** Files in the filesystem use extents. */ +#define EXT_SB_FEAT_INCOMPAT_EXTENTS RT_BIT_32(6) +/** Filesystem uses 64bit offsets. */ +#define EXT_SB_FEAT_INCOMPAT_64BIT RT_BIT_32(7) +/** Filesystem requires multiple mount preotection. */ +#define EXT_SB_FEAT_INCOMPAT_MMP RT_BIT_32(8) +/** Filesystem uses flexible block groups. */ +#define EXT_SB_FEAT_INCOMPAT_FLEX_BG RT_BIT_32(9) +/** Inodes can be used to store large extended attribute values. */ +#define EXT_SB_FEAT_INCOMPAT_EXT_ATTR_INODE RT_BIT_32(10) +/** Data is contained in directory entries. */ +#define EXT_SB_FEAT_INCOMPAT_DIRDATA RT_BIT_32(12) +/** Metadata checksum seed is stored in the super block. */ +#define EXT_SB_FEAT_INCOMPAT_CSUM_SEED RT_BIT_32(13) +/** Directories can be larger than 2GiB or contain a 3-level HTree. */ +#define EXT_SB_FEAT_INCOMPAT_LARGE_DIR RT_BIT_32(14) +/** Data is inlined in the inode. */ +#define EXT_SB_FEAT_INCOMPAT_INLINE_DATA RT_BIT_32(15) +/** Encrypted inodes are present on the filesystem. */ +#define EXT_SB_FEAT_INCOMPAT_ENCRYPT RT_BIT_32(16) +/** @} */ + +/** @name EXT_SB_FEAT_COMPAT_RO_XXX - Backward compatible features when mounted readonly + * @{ */ +/** Sparse superblocks. */ +#define EXT_SB_FEAT_COMPAT_RO_SPARSE_SUPER RT_BIT_32(0) +/** There is at least one large file (> 2GiB). */ +#define EXT_SB_FEAT_COMPAT_RO_LARGE_FILE RT_BIT_32(1) +/** Actually not used in the Linux kernel and e2fprogs. */ +#define EXT_SB_FEAT_COMPAT_RO_BTREE_DIR RT_BIT_32(2) +/** Filesystem contains files which sizes are not represented as a multiple of 512 byte sectors + * but logical blocks instead. */ +#define EXT_SB_FEAT_COMPAT_RO_HUGE_FILE RT_BIT_32(3) +/** Group descriptors have checksums embedded */ +#define EXT_SB_FEAT_COMPAT_RO_GDT_CHSKUM RT_BIT_32(4) +/** Subdirectory limit of 32000 doesn't apply. The link count is set to 1 if beyond 64999. */ +#define EXT_SB_FEAT_COMPAT_RO_DIR_NLINK RT_BIT_32(5) +/** Inodes can contain extra data. */ +#define EXT_SB_FEAT_COMPAT_RO_EXTRA_INODE_SZ RT_BIT_32(6) +/** There is at least one snapshot on the filesystem. */ +#define EXT_SB_FEAT_COMPAT_RO_HAS_SNAPSHOTS RT_BIT_32(7) +/** Quotas are enabled for this filesystem. */ +#define EXT_SB_FEAT_COMPAT_RO_QUOTA RT_BIT_32(8) +/** The bigalloc feature is enabled, file extents are tracked in units of clusters + * instead of blocks. */ +#define EXT_SB_FEAT_COMPAT_RO_BIGALLOC RT_BIT_32(9) +/** Metadata contains checksums. */ +#define EXT_SB_FEAT_COMPAT_RO_METADATA_CHKSUM RT_BIT_32(10) +/** Filesystem supports replicas. */ +#define EXT_SB_FEAT_COMPAT_RO_REPLICA RT_BIT_32(11) +/** Filesystem is readonly. */ +#define EXT_SB_FEAT_COMPAT_RO_READONLY RT_BIT_32(12) +/** Filesystem tracks project quotas. */ +#define EXT_SB_FEAT_COMPAT_RO_PROJECT RT_BIT_32(13) +/** @} */ + +/** @name EXT_SB_HASH_VERSION_DEF_XXX - Default hash algorithm used + * @{ */ +/** Legacy. */ +#define EXT_SB_HASH_VERSION_DEF_LEGACY 0 +/** Half MD4. */ +#define EXT_SB_HASH_VERSION_DEF_HALF_MD4 1 +/** Tea. */ +#define EXT_SB_HASH_VERSION_DEF_TEA 2 +/** Unsigned legacy. */ +#define EXT_SB_HASH_VERSION_DEF_LEGACY_UNSIGNED 3 +/** Unsigned half MD4. */ +#define EXT_SB_HASH_VERSION_DEF_HALF_MD4_UNSIGNED 4 +/** Unsigned tea. */ +#define EXT_SB_HASH_VERSION_DEF_TEA_UNSIGNED 5 +/** @} */ + +/** @name EXT_SB_MNT_OPTS_DEF_XXX - Default mount options + * @{ */ +/** Print debugging information on (re)mount. */ +#define EXT_SB_MNT_OPTS_DEF_DEBUG RT_BIT_32(0) +/** Created files take the group ID ofthe containing directory. */ +#define EXT_SB_MNT_OPTS_DEF_BSDGROUPS RT_BIT_32(1) +/** Support userspace extended attributes. */ +#define EXT_SB_MNT_OPTS_DEF_XATTR_USER RT_BIT_32(2) +/** Support POSIX access control lists. */ +#define EXT_SB_MNT_OPTS_DEF_ACL RT_BIT_32(3) +/** Do not support 32bit UIDs. */ +#define EXT_SB_MNT_OPTS_DEF_UID16 RT_BIT_32(4) +/** All data and metadata are committed to the journal. */ +#define EXT_SB_MNT_OPTS_DEF_JMODE_DATA RT_BIT_32(5) +/** All data are flushed to the disk before metadata are committed to the journal. */ +#define EXT_SB_MNT_OPTS_DEF_JMODE_ORDERED RT_BIT_32(6) +/** Data ordering not preserved, data may be written after metadata has been written. */ +#define EXT_SB_MNT_OPTS_DEF_JMODE_WBACK (EXT_SB_MNT_OPTS_DEF_JMODE_DATA | EXT_SB_MNT_OPTS_DEF_JMODE_ORDERED) +/** No write flushes. */ +#define EXT_SB_MNT_OPTS_DEF_NOBARRIER RT_BIT_32(8) +/** Track metadata blocks on the filesystem not being used as data blocks. */ +#define EXT_SB_MNT_OPTS_DEF_BLOCK_VALIDITY RT_BIT_32(9) +/** Enables TRIM/DISCARD support. */ +#define EXT_SB_MNT_OPTS_DEF_DISCARD RT_BIT_32(10) +/** Disable delayed allocation. */ +#define EXT_SB_MNT_OPTS_DEF_NODELALLOC RT_BIT_32(11) +/** @} */ + +/** @name EXT_SB_F_XXX - Superblock flags + * @{ */ +/** Signed directory hash used. */ +#define EXT_SB_F_SIGNED_DIR_HASH RT_BIT_32(0) +/** Unsigned directory hash used. */ +#define EXT_SB_F_UNSIGNED_DIR_HASH RT_BIT_32(1) +/** Only used to test development code. */ +#define EXT_SB_F_DEV_CODE RT_BIT_32(3) +/** @} */ + +/** @name EXT_SB_ENCRYPT_ALGO_XXX - Group descriptor flags + * @{ */ +/** Invalid encryption algorithm. */ +#define EXT_SB_ENCRYPT_ALGO_INVALID 0 +/** 256-bit AES in XTS mode. */ +#define EXT_SB_ENCRYPT_ALGO_256BIT_AES_XTS 1 +/** 256-bit AES in GCM mode. */ +#define EXT_SB_ENCRYPT_ALGO_256BIT_AES_GCM 2 +/** 256-bit AES in CBC mode. */ +#define EXT_SB_ENCRYPT_ALGO_256BIT_AES_CBC 3 +/** @} */ + + +/** + * Block group descriptor (32byte version). + */ +typedef struct EXTBLOCKGROUPDESC32 +{ + /** 0x00: Block address of the block bitmap (low 32bits). */ + uint32_t offBlockBitmapLow; + /** 0x04: Block address of the inode bitmap (low 32bits). */ + uint32_t offInodeBitmapLow; + /** 0x08: Start block address of the inode table (low 32bits). */ + uint32_t offInodeTableLow; + /** 0x0c: Number of unallocated blocks in group (low 16bits). */ + uint16_t cBlocksFreeLow; + /** 0x0e: Number of unallocated inodes in group (low 16bits). */ + uint16_t cInodesFreeLow; + /** 0x10: Number of directories in the group (low 16bits). */ + uint16_t cDirectoriesLow; + /** 0x12: Flags (EXT_GROUP_DESC_F_XXX). */ + uint16_t fFlags; + /** 0x14: Location of snapshot exclusion bitmap (lower 32bits) */ + uint32_t offSnapshotExclBitmapLow; + /** 0x18: Block bitmap checksum (lower 16bits). */ + uint16_t u16ChksumBlockBitmapLow; + /** 0x1a: Inode bitmap checksum (lower 16bits). */ + uint16_t u16ChksumInodeBitmapLow; + /** 0x1c: Unused inode entry count in the groups inode table (lower 16bits).*/ + uint16_t cInodeTblUnusedLow; + /** 0x1e: Group descriptor checksum. */ + uint16_t u16Chksum; +} EXTBLOCKGROUPDESC32; +AssertCompileSize(EXTBLOCKGROUPDESC32, 32); +/** Pointer to an ext block group descriptor. */ +typedef EXTBLOCKGROUPDESC32 *PEXTBLOCKGROUPDESC32; +/** Pointer to a const 32 byte block group descriptor. */ +typedef const EXTBLOCKGROUPDESC32 *PCEXTBLOCKGROUPDESC32; + + +/** + * Block group descriptor (64byte version). + */ +typedef struct EXTBLOCKGROUPDESC64 +{ + /** 0x00: Embedded 32 byte descriptor. */ + EXTBLOCKGROUPDESC32 v32; + /** 0x20: Location of block bitmap (upper 32bits). */ + uint32_t offBlockBitmapHigh; + /** 0x24: Location of inode bitmap (upper 32bits). */ + uint32_t offInodeBitmapHigh; + /** 0x28: Location of inode table (upper 32bits). */ + uint32_t offInodeTableHigh; + /** 0x2c: Number of unallocated blocks (upper 16bits). */ + uint16_t cBlocksFreeHigh; + /** 0x2e: Number of unallocated inodes (upper 16bits). */ + uint16_t cInodesFreeHigh; + /** 0x30: Number of directories in the group (upper 16bits). */ + uint16_t cDirectoriesHigh; + /** 0x32: Unused inode entry count in the groups inode table (upper 16bits).*/ + uint16_t cInodeTblUnusedHigh; + /** 0x34: Location of snapshot exclusion bitmap (upper 32bits) */ + uint32_t offSnapshotExclBitmapHigh; + /** 0x38: Block bitmap checksum (upper 16bits). */ + uint16_t u16ChksumBlockBitmapHigh; + /** 0x3a: Inode bitmap checksum (upper 16bits). */ + uint16_t u16ChksumInodeBitmapHigh; + /** 0x3c: Padding to 64 bytes. */ + uint32_t u64Padding; +} EXTBLOCKGROUPDESC64; +AssertCompileSize(EXTBLOCKGROUPDESC64, 64); +/** Pointer to an ext block group descriptor. */ +typedef EXTBLOCKGROUPDESC64 *PEXTBLOCKGROUPDESC64; +/** Pointer to a const 64 byte block group descriptor. */ +typedef const EXTBLOCKGROUPDESC64 *PCEXTBLOCKGROUPDESC64; + +/** @name EXT_GROUP_DESC_F_XXX - Group descriptor flags + * @{ */ +/** Inode table and bitmaps are not initialized. */ +#define EXT_GROUP_DESC_F_INODE_UNINIT RT_BIT(0) +/** Block bitmap is not initialized. */ +#define EXT_GROUP_DESC_F_BLOCK_UNINIT RT_BIT(1) +/** Inode table is zeroed. */ +#define EXT_GROUP_DESC_F_INODE_ZEROED RT_BIT(2) +/** @} */ + + +/** + * Combiend view of the different block gorup descriptor versions. + */ +typedef union EXTBLOCKGROUPDESC +{ + /** 32 byte version. */ + EXTBLOCKGROUPDESC32 v32; + /** 64 byte version. */ + EXTBLOCKGROUPDESC64 v64; + /** Byte view. */ + uint8_t au8[64]; +} EXTBLOCKGROUPDESC; +/** Poiner to a unified block gorup descriptor view. */ +typedef EXTBLOCKGROUPDESC *PEXTBLOCKGROUPDESC; +/** Poiner to a const unified block gorup descriptor view. */ +typedef const EXTBLOCKGROUPDESC *PCEXTBLOCKGROUPDESC; + + +/** Number of block entries in the inodes block map. */ +#define EXT_INODE_BLOCK_ENTRIES 15 + +/** + * Inode table entry (standard 128 byte version). + */ +typedef struct EXTINODE +{ + /** 0x00: File mode (EXT_INODE_FILE_MODE_XXX). */ + uint16_t fMode; + /** 0x02: Owner UID (lower 16bits). */ + uint16_t uUidLow; + /** 0x04: Size in bytes (lower 32bits). */ + uint32_t cbSizeLow; + /** 0x08: Last access time in seconds since epoch. */ + uint32_t u32TimeLastAccess; + /** 0x0c: Last inode change time in seconds since epoch. */ + uint32_t u32TimeLastChange; + /** 0x10: Last data modification time in seconds since epoch. */ + uint32_t u32TimeLastModification; + /** 0x14: Deletion time in seconds since epoch. */ + uint32_t u32TimeDeletion; + /** 0x18: Group ID (lower 16bits). */ + uint16_t uGidLow; + /** 0x1a: Hard link count. */ + uint16_t cHardLinks; + /** 0x1c: Block count (lower 32bits). */ + uint32_t cBlocksLow; + /** 0x20: Inode flags. */ + uint32_t fFlags; + /** 0x24: Operating system dependent data. */ + union + { + /** Linux: Inode version. */ + uint32_t u32LnxVersion; + } Osd1; + /** 0x28: Block map or extent tree. */ + uint32_t au32Block[EXT_INODE_BLOCK_ENTRIES]; + /** 0x64: File version. */ + uint32_t u32Version; + /** 0x68: Extended attribute control block (lower 32bits). */ + uint32_t offExtAttrLow; + /** 0x6c: File/directory size (upper 32bits). */ + uint32_t cbSizeHigh; + /** 0x70: Fragment address (obsolete). */ + uint32_t u32FragmentAddrObs; + /** 0x74: Operating system dependent data 2. */ + union + { + /** Linux related data. */ + struct + { + /** 0x00: Block count (upper 16bits). */ + uint16_t cBlocksHigh; + /** 0x02: Extended attribute block location (upper 16bits). */ + uint16_t offExtAttrHigh; + /** 0x04: Owner UID (upper 16bits). */ + uint16_t uUidHigh; + /** 0x06: Group ID (upper 16bits). */ + uint16_t uGidHigh; + /** 0x08: Inode checksum (lower 16bits). */ + uint16_t u16ChksumLow; + /** 0x0a: Reserved */ + uint16_t u16Rsvd; + } Lnx; + } Osd2; +} EXTINODE; +AssertCompileSize(EXTINODE, 128); +/** Pointer to an inode. */ +typedef EXTINODE *PEXTINODE; +/** Pointer to a const inode. */ +typedef const EXTINODE *PCEXTINODE; + + +/** + * Extra inode data (coming right behind the fixed inode data). + */ +typedef struct EXTINODEEXTRA +{ + /** 0x80: Size of the extra inode data in bytes. */ + uint16_t cbInodeExtra; + /** 0x82: Inode checksum (upper 16bits.) */ + uint16_t u16ChksumHigh; + /** 0x84: Last inode change time, extra time bits for sub-second precision. */ + uint32_t u32ExtraTimeLastChange; + /** 0x88: Last data modification time, extra time bits for sub-second precision. */ + uint32_t u32ExtraTimeLastModification; + /** 0x8c: Last access time, extra time bits for sub-second precision. */ + uint32_t u32ExtraTimeLastAccess; + /** 0x90: File creation time in seconds since epoch. */ + uint32_t u32TimeCreation; + /** 0x94: File creation time, extra time bits for sub-second precision. */ + uint32_t u32ExtraTimeCreation; + /** 0x98: Version number (upper 32bits). */ + uint32_t u32VersionHigh; + /** 0x9c: Project ID. */ + uint32_t u32ProjectId; +} EXTINODEEXTRA; +/** Pointer to extra inode data. */ +typedef EXTINODEEXTRA *PEXTINODEEXTRA; +/** Pointer to a const extra inode data. */ +typedef const EXTINODEEXTRA *PCEXTINODEEXTRA; + + +/** + * Combined inode data. + */ +typedef struct EXTINODECOMB +{ + /** Core inode structure. */ + EXTINODE Core; + /** Any extra inode data which might be present. */ + EXTINODEEXTRA Extra; +} EXTINODECOMB; +/** Pointer to combined inode data. */ +typedef EXTINODECOMB *PEXTINODECOMB; +/** Pointer to a const combined inode data. */ +typedef const EXTINODECOMB *PCEXTINODECOMB; + + + +/** @name EXT_INODE_MODE_XXX - File mode + * @{ */ +/** Others can execute the file. */ +#define EXT_INODE_MODE_EXEC_OTHER RT_BIT(0) +/** Others can write to the file. */ +#define EXT_INODE_MODE_WRITE_OTHER RT_BIT(1) +/** Others can read the file. */ +#define EXT_INODE_MODE_READ_OTHER RT_BIT(2) +/** Members of the same group can execute the file. */ +#define EXT_INODE_MODE_EXEC_GROUP RT_BIT(3) +/** Members of the same group can write to the file. */ +#define EXT_INODE_MODE_WRITE_GROUP RT_BIT(4) +/** Members of the same group can read the file. */ +#define EXT_INODE_MODE_READ_GROUP RT_BIT(5) +/** Owner can execute the file. */ +#define EXT_INODE_MODE_EXEC_OWNER RT_BIT(6) +/** Owner can write to the file. */ +#define EXT_INODE_MODE_WRITE_OWNER RT_BIT(7) +/** Owner can read the file. */ +#define EXT_INODE_MODE_READ_OWNER RT_BIT(8) +/** Sticky file mode. */ +#define EXT_INODE_MODE_STICKY RT_BIT(9) +/** File is set GID. */ +#define EXT_INODE_MODE_SET_GROUP_ID RT_BIT(10) +/** File is set UID. */ +#define EXT_INODE_MODE_SET_USER_ID RT_BIT(11) +/** @} */ + +/** @name EXT_INODE_MODE_TYPE_XXX - File type + * @{ */ +/** Inode represents a FIFO. */ +#define EXT_INODE_MODE_TYPE_FIFO UINT16_C(0x1000) +/** Inode represents a character device. */ +#define EXT_INODE_MODE_TYPE_CHAR UINT16_C(0x2000) +/** Inode represents a directory. */ +#define EXT_INODE_MODE_TYPE_DIR UINT16_C(0x4000) +/** Inode represents a block device. */ +#define EXT_INODE_MODE_TYPE_BLOCK UINT16_C(0x6000) +/** Inode represents a regular file. */ +#define EXT_INODE_MODE_TYPE_REGULAR UINT16_C(0x8000) +/** Inode represents a symlink. */ +#define EXT_INODE_MODE_TYPE_SYMLINK UINT16_C(0xa000) +/** Inode represents a socket. */ +#define EXT_INODE_MODE_TYPE_SOCKET UINT16_C(0xc000) +/** Returns the inode type from the combined mode field. */ +#define EXT_INODE_MODE_TYPE_GET_TYPE(a_Mode) ((a_Mode) & 0xf000) +/** @} */ + +/** @name EXT_INODE_F_XXX - Inode flags + * @{ */ +/** Inode requires secure erase on deletion. */ +#define EXT_INODE_F_SECURE_ERASE RT_BIT_32(0) +/** Inode should be preserved for undeletion during deletion. */ +#define EXT_INODE_F_UNDELETE RT_BIT_32(1) +/** Inode contains compressed data. */ +#define EXT_INODE_F_COMPRESSED RT_BIT_32(2) +/** All writes to this inode must be synchronous. */ +#define EXT_INODE_F_SYNCHRONOUS RT_BIT_32(3) +/** Inode is immutable. */ +#define EXT_INODE_F_IMMUTABLE RT_BIT_32(4) +/** Inode is append only. */ +#define EXT_INODE_F_APPEND_ONLY RT_BIT_32(5) +/** Inode should not be dumped via dump(1). */ +#define EXT_INODE_F_NO_DUMP RT_BIT_32(6) +/** Access time is not updated. */ +#define EXT_INODE_F_NO_ACCESS_TIME RT_BIT_32(7) +/** Dirty compressed file. */ +#define EXT_INODE_F_DIRTY_COMPRESSED RT_BIT_32(8) +/** Inode has one or more compressed clusters. */ +#define EXT_INODE_F_COMPRESSED_BLOCK RT_BIT_32(9) +/** Inode should not be compressed. */ +#define EXT_INODE_F_NO_COMPRESSION RT_BIT_32(10) +/** Inode is encrypted. */ +#define EXT_INODE_F_ENCRYPTED RT_BIT_32(11) +/** Directory has hashed indexes. */ +#define EXT_INODE_F_DIR_HASHED_INDEX RT_BIT_32(12) +/** AFS magic directory. */ +#define EXT_INODE_F_IMAGIC RT_BIT_32(13) +/** Data must always be written through the journal. */ +#define EXT_INODE_F_JOURNAL_DATA RT_BIT_32(14) +/** File tail should not be merged. */ +#define EXT_INODE_F_NOTAIL RT_BIT_32(15) +/** All directory entry data should be written synchronously. */ +#define EXT_INODE_F_DIR_SYNCHRONOUS RT_BIT_32(16) +/** Top of directory hierarchy. */ +#define EXT_INODE_F_TOP_DIRECTORY RT_BIT_32(17) +/** Inode is a huge file. */ +#define EXT_INODE_F_HUGE_FILE RT_BIT_32(18) +/** Inode uses extents. */ +#define EXT_INODE_F_EXTENTS RT_BIT_32(19) +/** Inode stores a large extended attribute value in its data blocks. */ +#define EXT_INODE_F_EXT_ATTR_INODE RT_BIT_32(20) +/** File has blocks allocated past end of file. */ +#define EXT_INODE_F_ALLOC_BLOCKS_EOF RT_BIT_32(21) +/** Inode is a snapshot. */ +#define EXT_INODE_F_SNAPSHOT RT_BIT_32(22) +/** Snapshot is being deleted. */ +#define EXT_INODE_F_SNAPSHOT_DELETED RT_BIT_32(23) +/** Snapshot shrink has completed. */ +#define EXT_INODE_F_SNAPSHOT_SHRUNK RT_BIT_32(24) +/** Inode contains inline data. */ +#define EXT_INODE_F_INLINE_DATA RT_BIT_32(25) +/** Children are created with the same project ID. */ +#define EXT_INODE_F_PROJECT_ID_INHERIT RT_BIT_32(26) +/** Reserved for ext4 library. */ +#define EXT_INODE_F_RESERVED_LIBRARY RT_BIT_32(27) +/** @} */ + + +/** + * Extent tree header. + */ +typedef struct EXTEXTENTHDR +{ + /** 0x00: Magic number for identification. */ + uint16_t u16Magic; + /** 0x02: Number of valid entries following. */ + uint16_t cEntries; + /** 0x04: Maxmimum number of entries that could follow. */ + uint16_t cMax; + /** 0x06: Depth of this extent node in the tree. */ + uint16_t uDepth; + /** 0x08: Generation of the tree (not used by standard ext4). */ + uint32_t cGeneration; +} EXTEXTENTHDR; +AssertCompileSize(EXTEXTENTHDR, 12); +/** Pointer to a extent tree header. */ +typedef EXTEXTENTHDR *PEXTEXTENTHDR; +/** Pointer to a const extent tree header. */ +typedef const EXTEXTENTHDR *PCEXTEXTENTHDR; + +/** Magic number identifying an extent header. */ +#define EXT_EXTENT_HDR_MAGIC UINT16_C(0xf30a) +/** Maximum depth an extent header can have. */ +#define EXT_EXTENT_HDR_DEPTH_MAX UINT16_C(5) + + +/** + * Extent tree index node. + */ +typedef struct EXTEXTENTIDX +{ + /** 0x00: Start file block this node covers. */ + uint32_t iBlock; + /** 0x04: Block number of child extent node (lower 32bits). */ + uint32_t offChildLow; + /** 0x08: Block number of child extent node (upper 16bits). */ + uint16_t offChildHigh; + /** 0x0a: Reserved. */ + uint16_t u16Rsvd; +} EXTEXTENTIDX; +AssertCompileSize(EXTEXTENTIDX, 12); +/** Pointer to an extent tree index node. */ +typedef EXTEXTENTIDX *PEXTEXTENTIDX; +/** Pointer to a const extent tree index node. */ +typedef const EXTEXTENTIDX *PCEXTEXTENTIDX; + + +/** + * Extent tree leaf node. + */ +typedef struct EXTEXTENT +{ + /** 0x00: First file block number this extent covers. */ + uint32_t iBlock; + /** 0x04: Number of blocks covered by this extent. */ + uint16_t cBlocks; + /** 0x06: Block number this extent points to (upper 32bits). */ + uint16_t offStartHigh; + /** 0x08: Block number this extent points to (lower 32bits). */ + uint32_t offStartLow; +} EXTEXTENT; +AssertCompileSize(EXTEXTENT, 12); +/** Pointer to a leaf node. */ +typedef EXTEXTENT *PEXTEXTENT; +/** Pointer to a const leaf node. */ +typedef const EXTEXTENT *PCEXTEXTENT; + +/** Length field limit for a populated extent, fields greater than that limit indicate a sparse extent. */ +#define EXT_EXTENT_LENGTH_LIMIT UINT16_C(32768) + + +/** + * Directory entry. + */ +typedef struct EXTDIRENTRY +{ + /** 0x00: Inode number being referenced by this entry. */ + uint32_t iInodeRef; + /** 0x04: Record length of this directory entry in bytes (multiple of 4). */ + uint16_t cbRecord; + /** 0x06: Version dependent data. */ + union + { + /** Original. */ + struct + { + /** Name length in bytes (maximum 255). */ + uint16_t cbName; + } v1; + /** Version 2. */ + struct + { + /** Name length in bytes (maximum 255). */ + uint8_t cbName; + /** File type (EXT_DIRENTRY_TYPE_XXX). */ + uint8_t uType; + } v2; + } u; + /** 0x08: File name - variable in size. */ + char achName[1]; +} EXTDIRENTRY; +/** Pointer to a directory entry. */ +typedef EXTDIRENTRY *PEXTDIRENTRY; +/** Poiner to a const directory entry. */ +typedef const EXTDIRENTRY *PCEXTDIRENTRY; + + +/** + * Extended directory entry with the maximum size (263 bytes). + */ +#pragma pack(1) +typedef union EXTDIRENTRYEX +{ + /** The directory entry. */ + EXTDIRENTRY Core; + /** The byte view. */ + uint8_t au8[263]; +} EXTDIRENTRYEX; +#pragma pack() +AssertCompileSize(EXTDIRENTRYEX, 263); +/** Pointer to an extended directory entry. */ +typedef EXTDIRENTRYEX *PEXTDIRENTRYEX; +/** Pointer to a const extended directory entry. */ +typedef const EXTDIRENTRYEX *PCEXTDIRENTRYEX; + + +/** @name EXT_DIRENTRY_TYPE_XXX - file type + * @{ */ +/** Entry is of unknown file type. */ +#define EXT_DIRENTRY_TYPE_UNKNOWN 0 +/** Entry is regular file. */ +#define EXT_DIRENTRY_TYPE_REGULAR 1 +/** Entry is another directory. */ +#define EXT_DIRENTRY_TYPE_DIRECTORY 2 +/** Entry is a character device. */ +#define EXT_DIRENTRY_TYPE_CHAR 3 +/** Entry is a block device. */ +#define EXT_DIRENTRY_TYPE_BLOCK 4 +/** Entry is a FIFO. */ +#define EXT_DIRENTRY_TYPE_FIFO 5 +/** Entry is a socket. */ +#define EXT_DIRENTRY_TYPE_SOCKET 6 +/** Entry is a symlink. */ +#define EXT_DIRENTRY_TYPE_SYMLINK 7 +/** Entry is a checksum and uses EXTDIRENTRYCHKSUM. */ +#define EXT_DIRENTRY_TYPE_CHKSUM 0xde +/** @} */ + + +/** + * Tail directory entry (for checksumming). + */ +typedef struct EXTDIRENTRYCHKSUM +{ + /** 0x00: Reserved, must be 0 (overlays with EXTDIRENTRY::iNodeRef). */ + uint32_t u32Rsvd; + /** 0x04: Record length (must be 12). */ + uint16_t cbRecord; + /** 0x06: Reserved (overlays with EXTDIRENTRY::u::v1::cbName). */ + uint8_t u8Rsvd; + /** 0x07: File type (must be 0xde). */ + uint8_t uType; + /** 0x08: Checksum. */ + uint32_t u32Chksum; +} EXTDIRENTRYCHKSUM; +/** Pointer to a tail directory entry. */ +typedef EXTDIRENTRYCHKSUM *PEXTDIRENTRYCHKSUM; +/** Pointer to const tail directory entry. */ +typedef const EXTDIRENTRYCHKSUM *PCEXTDIRENTRYCHKSUM; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_ext_h */ + diff --git a/include/iprt/formats/fat.h b/include/iprt/formats/fat.h new file mode 100644 index 00000000..d55c0957 --- /dev/null +++ b/include/iprt/formats/fat.h @@ -0,0 +1,759 @@ +/* $Id: fat.h $ */ +/** @file + * IPRT, File Allocation Table (FAT). + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_fat_h +#define IPRT_INCLUDED_formats_fat_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_fat File Allocation Table (FAT) structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + + +/** @name FAT Media byte values + * @remarks This isn't as simple as it's made out to be here! + * @{ */ +#define FATBPB_MEDIA_FLOPPY_8 UINT8_C(0xe5) +#define FATBPB_MEDIA_FLOPPY_5_DOT_25 UINT8_C(0xed) +#define FATBPB_MEDIA_FLOPPY_3_DOT_5 UINT8_C(0xf0) +/* incomplete, figure out as needed... */ + +/** Checks if @a a_bMedia is a valid media byte. */ +#define FATBPB_MEDIA_IS_VALID(a_bMedia) ( (uint8_t)(a_bMedia) >= 0xf8 \ + || (uint8_t)(a_bMedia) == 0xf0 \ + || (uint8_t)(a_bMedia) == 0xf4 /* obscure - msdos 2.11 */ \ + || (uint8_t)(a_bMedia) == 0xf5 /* obscure - msdos 2.11 */ \ + || (uint8_t)(a_bMedia) == 0xed /* obscure - tandy 2000 */ \ + || (uint8_t)(a_bMedia) == 0xe5 /* obscure - tandy 2000 */ ) +/** @} */ + +/** Checks if @a a_bFatId is a valid FAT ID byte. + * @todo uncertain whether 0xf4 and 0xf5 should be allowed here too. */ +#define FAT_ID_IS_VALID(a_bFatId) ( (uint8_t)(a_bFatId) >= 0xf8 \ + || (uint8_t)(a_bFatId) == 0xf0 \ + || (uint8_t)(a_bFatId) == 0xf4 /* obscure - msdos 2.11 */ \ + || (uint8_t)(a_bFatId) == 0xf5 /* obscure - msdos 2.11 */ \ + || (uint8_t)(a_bFatId) == 0xed /* obscure, tandy 2000 */ \ + || (uint8_t)(a_bFatId) == 0xe5 /* obscure, tandy 2000 */ ) + +/** + * The DOS 2.0 BIOS parameter block (BPB). + * + * This was the first DOS version with a BPB. + */ +#pragma pack(1) +typedef struct FATBPB20 +{ + /** 0x0b / 0x00: The sector size in bytes. */ + uint16_t cbSector; + /** 0x0d / 0x02: Number of sectors per cluster. */ + uint8_t cSectorsPerCluster; + /** 0x0e / 0x03: Number of reserved sectors before the first FAT. */ + uint16_t cReservedSectors; + /** 0x10 / 0x05: Number of FATs. */ + uint8_t cFats; + /** 0x11 / 0x06: Max size of the root directory (0 for FAT32). */ + uint16_t cMaxRootDirEntries; + /** 0x13 / 0x08: Total sector count, zero if 32-bit count is used. */ + uint16_t cTotalSectors16; + /** 0x15 / 0x0a: Media ID. */ + uint8_t bMedia; + /** 0x16 / 0x0b: Number of sectors per FAT (0 for FAT32). */ + uint16_t cSectorsPerFat; +} FATBPB20; +#pragma pack() +AssertCompileSize(FATBPB20, 0xd); +/** Pointer to a DOS 2.0 BPB. */ +typedef FATBPB20 *PFATBPB20; +/** Pointer to a const DOS 2.0 BPB. */ +typedef FATBPB20 const *PCFATBPB20; + + +/** + * The DOS 3.0 BPB changes that survived. + */ +#pragma pack(1) +typedef struct FATBPB30CMN +{ + /** DOS v2.0 BPB. */ + FATBPB20 Bpb20; + /** 0x18 / 0x0d: Sectors per track. Zero means reserved and not used. */ + uint16_t cSectorsPerTrack; + /** 0x1a / 0x0f: Number of heads. Zero means reserved and not used. */ + uint16_t cTracksPerCylinder; +} FATBPB30CMN; +#pragma pack() +AssertCompileSize(FATBPB30CMN, 0x11); + +/** + * The DOS 3.0 BPB. + */ +#pragma pack(1) +typedef struct FATBPB30 +{ + /** DOS v3.0 BPB bits that survived. */ + FATBPB30CMN Core30; + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. */ + uint16_t cHiddenSectors; +} FATBPB30; +#pragma pack() +AssertCompileSize(FATBPB30, 0x13); +/** Pointer to a DOS 3.0 BPB. */ +typedef FATBPB30 *PFATBPB30; +/** Pointer to a const DOS 3.0 BPB. */ +typedef FATBPB30 const *PCFATBPB30; + +/** + * The DOS 3.0 BPB, flattened structure. + */ +#pragma pack(1) +typedef struct FATBPB30FLAT +{ + /** @name New in DOS 2.0 + * @{ */ + /** 0x0b / 0x00: The sector size in bytes. */ + uint16_t cbSector; + /** 0x0d / 0x02: Number of sectors per cluster. */ + uint8_t cSectorsPerCluster; + /** 0x0e / 0x03: Number of reserved sectors before the first FAT. */ + uint16_t cReservedSectors; + /** 0x10 / 0x05: Number of FATs. */ + uint8_t cFats; + /** 0x11 / 0x06: Max size of the root directory (0 for FAT32). */ + uint16_t cMaxRootDirEntries; + /** 0x13 / 0x08: Total sector count, zero if 32-bit count is used. */ + uint16_t cTotalSectors16; + /** 0x15 / 0x0a: Media ID. */ + uint8_t bMedia; + /** 0x16 / 0x0b: Number of sectors per FAT (0 for FAT32). */ + uint16_t cSectorsPerFat; + /** @} */ + /** @name New in DOS 3.0 + * @{ */ + /** 0x18 / 0x0d: Sectors per track. Zero means reserved and not used. */ + uint16_t cSectorsPerTrack; + /** 0x1a / 0x0f: Number of heads. Zero means reserved and not used. */ + uint16_t cTracksPerCylinder; + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. */ + uint16_t cHiddenSectors; + /** @} */ +} FATBPB30FLAT; +#pragma pack() +AssertCompileSize(FATBPB30FLAT, 0x13); +/** Pointer to a flattened DOS 3.0 BPB. */ +typedef FATBPB30FLAT *PFATBPB30FLAT; +/** Pointer to a const flattened DOS 3.0 BPB. */ +typedef FATBPB30FLAT const *PCFATBPB30FLAT; + + +/** + * The DOS 3.2 BPB. + */ +#pragma pack(1) +typedef struct FATBPB32 +{ + /** DOS v3.0 BPB. */ + FATBPB30 Bpb30; + /** 0x1e / 0x13: Number of sectors, including the hidden ones. This is ZERO + * in DOS 3.31+. */ + uint16_t cAnotherTotalSectors; +} FATBPB32; +#pragma pack() +AssertCompileSize(FATBPB32, 0x15); +/** Pointer to a DOS 3.2 BPB. */ +typedef FATBPB32 *PFATBPB32; +/** Pointer to const a DOS 3.2 BPB. */ +typedef FATBPB32 const *PCFATBPB32; + +/** + * The DOS 3.2 BPB, flattened structure. + */ +#pragma pack(1) +typedef struct FATBPB32FLAT +{ + /** @name New in DOS 2.0 + * @{ */ + /** 0x0b / 0x00: The sector size in bytes. */ + uint16_t cbSector; + /** 0x0d / 0x02: Number of sectors per cluster. */ + uint8_t cSectorsPerCluster; + /** 0x0e / 0x03: Number of reserved sectors before the first FAT. */ + uint16_t cReservedSectors; + /** 0x10 / 0x05: Number of FATs. */ + uint8_t cFats; + /** 0x11 / 0x06: Max size of the root directory (0 for FAT32). */ + uint16_t cMaxRootDirEntries; + /** 0x13 / 0x08: Total sector count, zero if 32-bit count is used. */ + uint16_t cTotalSectors16; + /** 0x15 / 0x0a: Media ID. */ + uint8_t bMedia; + /** 0x16 / 0x0b: Number of sectors per FAT (0 for FAT32). */ + uint16_t cSectorsPerFat; + /** @} */ + /** @name New in DOS 3.0 + * @{ */ + /** 0x18 / 0x0d: Sectors per track. Zero means reserved and not used. */ + uint16_t cSectorsPerTrack; + /** 0x1a / 0x0f: Number of heads. Zero means reserved and not used. */ + uint16_t cTracksPerCylinder; + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. */ + uint16_t cHiddenSectors; + /** @} */ + /** @name New in DOS 3.2 + * @{ */ + /** 0x1e / 0x13: Number of sectors, including the hidden ones. This is ZERO + * in DOS 3.31+. */ + uint16_t cAnotherTotalSectors; + /** @} */ +} FATBPB32FLAT; +#pragma pack() +AssertCompileSize(FATBPB32FLAT, 0x15); +/** Pointer to a flattened DOS 3.2 BPB. */ +typedef FATBPB32FLAT *PFATBPB32FLAT; +/** Pointer to a const flattened DOS 3.2 BPB. */ +typedef FATBPB32FLAT const *PCFATBPB32FLAT; + + +/** + * The DOS 3.31 BPB. + */ +#pragma pack(1) +typedef struct FATBPB331 +{ + /** DOS v3.0 BPB bits that survived. */ + FATBPB30CMN Core30; + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. Values higher than 65535 are complicated due to + * the field overlapping FATBPB32::cAnotherTotalSectors */ + uint32_t cHiddenSectors; + /** 0x20 / 0x15: Total logical sectors. Used if count >= 64K, otherwise + * FATBPB20::cTotalSectors16 is used. Zero if 64-bit value used with FAT32. */ + uint32_t cTotalSectors32; +} FATBPB331; +#pragma pack() +AssertCompileSize(FATBPB331, 0x19); +/** Pointer to a DOS 3.31 BPB. */ +typedef FATBPB331 *PFATBPB331; +/** Pointer to a const DOS 3.31 BPB. */ +typedef FATBPB331 const *PCFATBPB331; + +/** + * The DOS 3.31 BPB, flattened structure. + */ +#pragma pack(1) +typedef struct FATBPB331FLAT +{ + /** @name New in DOS 2.0 + * @{ */ + /** 0x0b / 0x00: The sector size in bytes. */ + uint16_t cbSector; + /** 0x0d / 0x02: Number of sectors per cluster. */ + uint8_t cSectorsPerCluster; + /** 0x0e / 0x03: Number of reserved sectors before the first FAT (0 for + * NTFS). */ + uint16_t cReservedSectors; + /** 0x10 / 0x05: Number of FATs (0 for NTFS). */ + uint8_t cFats; + /** 0x11 / 0x06: Max size of the root directory (0 for FAT32 & NTFS). */ + uint16_t cMaxRootDirEntries; + /** 0x13 / 0x08: Total sector count, zero if 32-bit count is used (and for + * NTFS). */ + uint16_t cTotalSectors16; + /** 0x15 / 0x0a: Media ID. */ + uint8_t bMedia; + /** 0x16 / 0x0b: Number of sectors per FAT (0 for FAT32 & NTFS). */ + uint16_t cSectorsPerFat; + /** @} */ + /** @name New in DOS 3.0 + * @{ */ + /** 0x18 / 0x0d: Sectors per track. Zero means reserved and not used. */ + uint16_t cSectorsPerTrack; + /** 0x1a / 0x0f: Number of heads. Zero means reserved and not used. */ + uint16_t cTracksPerCylinder; + /** @} */ + /** @name New in DOS 3.31 + * @{ */ + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. Values higher than 65535 are complicated due to + * the field overlapping FATBPB32::cAnotherTotalSectors */ + uint32_t cHiddenSectors; + /** 0x20 / 0x15: Total logical sectors. Used if count >= 64K, otherwise + * FATBPB20::cTotalSectors16 is used. Zero if 64-bit value used with FAT32. + * (Zero for NTFS). */ + uint32_t cTotalSectors32; + /** @} */ +} FATBPB331FLAT; +#pragma pack() +AssertCompileSize(FATBPB331FLAT, 0x19); +/** Pointer to a flattened DOS 3.31 BPB. */ +typedef FATBPB331FLAT *PFATBPB331FLAT; +/** Pointer to a const flattened DOS 3.31 BPB. */ +typedef FATBPB331FLAT const *PCFATBPB331FLAT; + + +/** + * Extended BIOS parameter block (EBPB). + */ +#pragma pack(1) +typedef struct FATEBPB +{ + /** The BPB. */ + FATBPB331FLAT Bpb; + + /** 0x24 / 0x19: BIOS INT13 pysical drive number. */ + uint8_t bInt13Drive; + /** 0x25 / 0x1a: Reserved. NT used bit 0 for indicating dirty FS, and bit 1 + * for surface scan. */ + uint8_t bReserved; + /** 0x26 / 0x1b: Extended boot signature, FATEBPB_SIGNATURE or + * FATEBPB_SIGNATURE_OLD. */ + uint8_t bExtSignature; + /** 0x27 / 0x1c: The volume serial number. */ + uint32_t uSerialNumber; + /** 0x2b / 0x20: The volume label (space padded). + * @remarks Not available with FATEBPB_SIGNATURE_OLD */ + char achLabel[11]; + /** 0x36 / 0x2b: The file system type (space padded). + * @remarks Not available with FATEBPB_SIGNATURE_OLD */ + char achType[8]; +} FATEBPB; +#pragma pack() +AssertCompileSize(FATEBPB, 0x33); +/** Pointer to an extended BIOS parameter block. */ +typedef FATEBPB *PFATEBPB; +/** Pointer to a const extended BIOS parameter block. */ +typedef FATEBPB const *PCFATEBPB; + +/** FATEBPB::bExtSignature value. */ +#define FATEBPB_SIGNATURE UINT8_C(0x29) +/** FATEBPB::bExtSignature value used by OS/2 1.0-1.1 and PC DOS 3.4. These + * does not have the volume and file system type. */ +#define FATEBPB_SIGNATURE_OLD UINT8_C(0x28) + +/**FATEBPB::achType value for FAT12. */ +#define FATEBPB_TYPE_FAT12 "FAT12 " +/**FATEBPB::achType value for FAT16. */ +#define FATEBPB_TYPE_FAT16 "FAT16 " +/**FATEBPB::achType value for FAT12/FAT16. */ +#define FATEBPB_TYPE_FAT "FAT32 " + + +/** + * FAT32 Extended BIOS parameter block (EBPB). + */ +#pragma pack(1) +typedef struct FAT32EBPB +{ + /** The BPB. */ + FATBPB331FLAT Bpb; + + /** 0x24 / 0x19: Number of sectors per FAT. + * @note To avoid confusion with the FATEBPB signature, values which result in + * 0x00280000 or 0x00290000 when masked by 0x00ff0000 must not be used. */ + uint32_t cSectorsPerFat32; + /** 0x28 / 0x1d: Flags pertaining to FAT mirroring and other stuff. */ + uint16_t fFlags; + /** 0x2a / 0x1f: FAT32 version number (FAT32EBPB_VERSION_0_0). */ + uint16_t uVersion; + /** 0x2c / 0x21: Cluster number of the root directory. */ + uint32_t uRootDirCluster; + /** 0x30 / 0x25: Logical sector number of the information sector. */ + uint16_t uInfoSectorNo; + /** 0x32 / 0x27: Logical sector number of boot sector copy. */ + uint16_t uBootSectorCopySectorNo; + /** 0x34 / 0x29: Reserved, zero (or 0xf6) filled, preserve. */ + uint8_t abReserved[12]; + + /** 0x40 / 0x35: BIOS INT13 pysical drive number + * @remarks Same as FATEBPB::bInt13Drive. */ + uint8_t bInt13Drive; + /** 0x41 / 0x36: Reserved. + * @remarks Same as FATEBPB::bReserved. */ + uint8_t bReserved; + /** 0x42 / 0x37: Extended boot signature (FATEBPB_SIGNATURE, or + * FATEBPB_SIGNATURE_OLD in some special cases). + * @remarks Same as FATEBPB::bExtSignature. */ + uint8_t bExtSignature; + /** 0x43 / 0x38: The volume serial number. + * @remarks Same as FATEBPB::uSerialNumber. */ + uint32_t uSerialNumber; + /** 0x47 / 0x3c: The volume label (space padded). + * @remarks Not available with FATEBPB_SIGNATURE_OLD + * @remarks Same as FATEBPB::achLabel. */ + char achLabel[11]; + /** 0x52 / 0x47: The file system type (space padded), or 64-bit logical sector + * count if both other count fields are zero. In the latter case, the type is + * moved to the OEM name field (FATBOOTSECTOR::achOemName). + * + * @remarks Not available with FATEBPB_SIGNATURE_OLD + * @remarks Same as FATEBPB::achType. */ + union + { + /** Type string variant. */ + char achType[8]; + /** Total sector count if 4G or higher. */ + uint64_t cTotalSectors64; + } u; +} FAT32EBPB; +#pragma pack() +AssertCompileSize(FAT32EBPB, 0x4f); +/** Pointer to a FAT32 extended BIOS parameter block. */ +typedef FAT32EBPB *PFAT32EBPB; +/** Pointer to a const FAT32 extended BIOS parameter block. */ +typedef FAT32EBPB const *PCFAT32EBPB; + +/** FAT32 version 0.0 (FAT32EBPB::uVersion). */ +#define FAT32EBPB_VERSION_0_0 UINT16_C(0x0000) + + +/** + * NTFS extended BIOS parameter block (NTFSEBPB). + */ +#pragma pack(1) +typedef struct NTFSEBPB +{ + /** The BPB. */ + FATBPB331FLAT Bpb; + + /** 0x24 / 0x19: BIOS INT13 pysical drive number. + * @note Same location as FATEBPB::bInt13Drive. */ + uint8_t bInt13Drive; + /** 0x25 / 0x1a: Reserved / flags */ + uint8_t bReserved; + /** 0x26 / 0x1b: Extended boot signature (NTFSEBPB_SIGNATURE). + * @note Same location as FATEBPB::bExtSignature. */ + uint8_t bExtSignature; + /** 0x27 / 0x1c: Reserved */ + uint8_t bReserved2; + + /** 0x28 / 0x1d: Number of sectors. */ + uint64_t cSectors; + /** 0x30 / 0x25: Logical cluster number of the master file table (MFT). */ + uint64_t uLcnMft; + /** 0x38 / 0x2d: Logical cluster number of the MFT mirror. */ + uint64_t uLcnMftMirror; + /** 0x40 / 0x35: Logical clusters per file record segment. + * This is a shift count if negative. */ + int8_t cClustersPerMftRecord; + /** 0x41 / 0x36: Reserved. */ + uint8_t abReserved3[3]; + /** 0x44 / 0x39: The default logical clusters count per index node. + * This is a shift count if negative. */ + int8_t cClustersPerIndexNode; + /** 0x45 / 0x3a: Reserved. */ + uint8_t abReserved4[3]; + /** 0x48 / 0x3d: Volume serial number. + * @note This is larger than the the FAT serial numbers. */ + uint64_t uSerialNumber; + /** 0x50 / 0x45: Checksum. */ + uint32_t uChecksum; +} NTFSEBPB; +#pragma pack() +AssertCompileSize(NTFSEBPB, 0x49); +/** Pointer to a NTFS extended BIOS parameter block. */ +typedef NTFSEBPB *PNTFSEBPB; +/** Pointer to a const NTFS extended BIOS parameter block. */ +typedef NTFSEBPB const *PCNTFSEBPB; + +/** NTFS EBPB signature (NTFSEBPB::bExtSignature). */ +#define NTFSEBPB_SIGNATURE UINT8_C(0x80) + + +/** + * FAT boot sector layout. + */ +#pragma pack(1) +typedef struct FATBOOTSECTOR +{ + /** 0x000: DOS 2.0+ jump sequence. */ + uint8_t abJmp[3]; + /** 0x003: OEM name (who formatted this volume). */ + char achOemName[8]; + /** 0x00b: The BIOS parameter block. + * This varies a lot in size. */ + union + { + FATBPB20 Bpb20; + FATBPB30FLAT Bpb30; + FATBPB32FLAT Bpb32; + FATBPB331FLAT Bpb331; + FATEBPB Ebpb; + FAT32EBPB Fat32Ebpb; + NTFSEBPB Ntfs; + } Bpb; + /** 0x05a: Bootloader code/data/stuff. */ + uint8_t abStuff[0x1a3]; + /** 0x1fd: Old drive number location (DOS 3.2-3.31). */ + uint8_t bOldInt13Drive; + /** 0x1fe: DOS signature (FATBOOTSECTOR_SIGNATURE). */ + uint16_t uSignature; +} FATBOOTSECTOR; +#pragma pack() +AssertCompileSize(FATBOOTSECTOR, 0x200); +/** Pointer to a FAT boot sector. */ +typedef FATBOOTSECTOR *PFATBOOTSECTOR; +/** Pointer to a const FAT boot sector. */ +typedef FATBOOTSECTOR const *PCFATBOOTSECTOR; + +/** Boot sector signature (FATBOOTSECTOR::uSignature). */ +#define FATBOOTSECTOR_SIGNATURE UINT16_C(0xaa55) + + + +/** + * FAT32 info sector (follows the boot sector). + */ +typedef struct FAT32INFOSECTOR +{ + /** 0x000: Signature \#1 (FAT32INFOSECTOR_SIGNATURE_1). */ + uint32_t uSignature1; + /** Reserved, should be zero. */ + uint8_t abReserved1[0x1E0]; + /** 0x1e4: Signature \#1 (FAT32INFOSECTOR_SIGNATURE_2). */ + uint32_t uSignature2; + /** 0x1e8: Last known number of free clusters (informational). */ + uint32_t cFreeClusters; + /** 0x1ec: Last allocated cluster number (informational). This could be used as + * an allocation hint when searching for a free cluster. */ + uint32_t cLastAllocatedCluster; + /** 0x1f0: Reserved, should be zero, preserve. */ + uint8_t abReserved2[12]; + /** 0x1fc: Signature \#3 (FAT32INFOSECTOR_SIGNATURE_3). */ + uint32_t uSignature3; +} FAT32INFOSECTOR; +AssertCompileSize(FAT32INFOSECTOR, 0x200); +/** Pointer to a FAT32 info sector. */ +typedef FAT32INFOSECTOR *PFAT32INFOSECTOR; +/** Pointer to a const FAT32 info sector. */ +typedef FAT32INFOSECTOR const *PCFAT32INFOSECTOR; + +#define FAT32INFOSECTOR_SIGNATURE_1 UINT32_C(0x41615252) +#define FAT32INFOSECTOR_SIGNATURE_2 UINT32_C(0x61417272) +#define FAT32INFOSECTOR_SIGNATURE_3 UINT32_C(0xaa550000) + + +/** @name Special FAT cluster numbers and limits. + * @{ */ +#define FAT_FIRST_DATA_CLUSTER 2 /**< The first data cluster. */ + +#define FAT_MAX_FAT12_TOTAL_CLUSTERS UINT32_C(0x00000ff6) /**< Maximum number of clusters in a 12-bit FAT . */ +#define FAT_MAX_FAT16_TOTAL_CLUSTERS UINT32_C(0x0000fff6) /**< Maximum number of clusters in a 16-bit FAT . */ +#define FAT_MAX_FAT32_TOTAL_CLUSTERS UINT32_C(0x0ffffff6) /**< Maximum number of clusters in a 32-bit FAT . */ + +#define FAT_LAST_FAT12_DATA_CLUSTER UINT32_C(0x00000ff5) /**< The last possible data cluster for FAT12. */ +#define FAT_LAST_FAT16_DATA_CLUSTER UINT32_C(0x0000fff5) /**< The last possible data cluster for FAT16. */ +#define FAT_LAST_FAT32_DATA_CLUSTER UINT32_C(0x0ffffff5) /**< The last possible data cluster for FAT32. */ + +#define FAT_MAX_FAT12_DATA_CLUSTERS UINT32_C(0x00000ff4) /**< Maximum number of data clusters for FAT12. */ +#define FAT_MAX_FAT16_DATA_CLUSTERS UINT32_C(0x0000fff4) /**< Maximum number of data clusters for FAT16. */ +#define FAT_MAX_FAT32_DATA_CLUSTERS UINT32_C(0x0ffffff4) /**< Maximum number of data clusters for FAT32. */ + +#define FAT_MIN_FAT12_DATA_CLUSTERS UINT32_C(0x00000001) /**< Maximum number of data clusters for FAT12. */ +#define FAT_MIN_FAT16_DATA_CLUSTERS UINT32_C(0x00000ff5) /**< Maximum number of data clusters for FAT16. */ +#define FAT_MIN_FAT32_DATA_CLUSTERS UINT32_C(0x0000fff5) /**< Maximum number of data clusters for FAT32. */ + +#define FAT_FIRST_FAT12_EOC UINT32_C(0x00000ff8) /**< The first end-of-file-cluster number for FAT12. */ +#define FAT_FIRST_FAT16_EOC UINT32_C(0x0000fff8) /**< The first end-of-file-cluster number for FAT16. */ +#define FAT_FIRST_FAT32_EOC UINT32_C(0x0ffffff8) /**< The first end-of-file-cluster number for FAT32. */ +/** @} */ + + +/** + * FAT directory entry. + */ +typedef struct FATDIRENTRY +{ + /** 0x00: The directory entry name. + * First character serves as a flag to indicate deleted or not. */ + uint8_t achName[8+3]; + /** 0x0b: Attributes (FAT_ATTR_XXX). */ + uint8_t fAttrib; + /** 0x0c: NT case flags (FATDIRENTRY_CASE_F_XXX). */ + uint8_t fCase; + /** 0x0d: Birth milliseconds (DOS 7.0+ w/VFAT). */ + uint8_t uBirthCentiseconds; + /** 0x0e: Birth time (DOS 7.0+ w/VFAT). */ + uint16_t uBirthTime; + /** 0x10: Birth date (DOS 7.0+ w/VFAT). */ + uint16_t uBirthDate; + /** 0x12: Access date (DOS 7.0+ w/ACCDATA in Config.sys). */ + uint16_t uAccessDate; + union + { + /** 0x14: High cluster word for FAT32. */ + uint16_t idxClusterHigh; + /** 0x14: Index of extended attributes (FAT16/FAT12). */ + uint16_t idxEAs; + } u; + /** 0x16: Modify time (PC-DOS 1.1+, MS-DOS 1.20+). */ + uint16_t uModifyTime; + /** 0x18: Modify date. */ + uint16_t uModifyDate; + /** 0x1a: The data cluster index. */ + uint16_t idxCluster; + /** 0x1c: The file size. */ + uint32_t cbFile; +} FATDIRENTRY; +AssertCompileSize(FATDIRENTRY, 0x20); +AssertCompileMemberOffset(FATDIRENTRY, fAttrib, 0x0b); +AssertCompileMemberOffset(FATDIRENTRY, fCase, 0x0c); +AssertCompileMemberOffset(FATDIRENTRY, uBirthCentiseconds, 0x0d); +AssertCompileMemberOffset(FATDIRENTRY, uBirthTime, 0x0e); +AssertCompileMemberOffset(FATDIRENTRY, uBirthDate, 0x10); +AssertCompileMemberOffset(FATDIRENTRY, uAccessDate, 0x12); +AssertCompileMemberOffset(FATDIRENTRY, u, 0x14); +AssertCompileMemberOffset(FATDIRENTRY, uModifyTime, 0x16); +AssertCompileMemberOffset(FATDIRENTRY, uModifyDate, 0x18); +AssertCompileMemberOffset(FATDIRENTRY, idxCluster, 0x1a); +AssertCompileMemberOffset(FATDIRENTRY, cbFile, 0x1c); +/** Pointer to a FAT directory entry. */ +typedef FATDIRENTRY *PFATDIRENTRY; +/** Pointer to a FAT directory entry. */ +typedef FATDIRENTRY const *PCFATDIRENTRY; + + +/** @name FAT_ATTR_XXX - FATDIRENTRY::fAttrib flags. + * @{ */ +#define FAT_ATTR_READONLY UINT8_C(0x01) +#define FAT_ATTR_HIDDEN UINT8_C(0x02) +#define FAT_ATTR_SYSTEM UINT8_C(0x04) +#define FAT_ATTR_VOLUME UINT8_C(0x08) +#define FAT_ATTR_DIRECTORY UINT8_C(0x10) +#define FAT_ATTR_ARCHIVE UINT8_C(0x20) +#define FAT_ATTR_DEVICE UINT8_C(0x40) +#define FAT_ATTR_RESERVED UINT8_C(0x80) +#define FAT_ATTR_NAME_SLOT UINT8_C(0x0f) /**< Special attribute value for FATDIRNAMESLOT. */ +/** @} */ + +/** @name FATDIRENTRY_CASE_F_XXX - FATDIRENTRY::fCase flags. + * @{ */ +/** Lower cased base name (first 8 chars). */ +#define FATDIRENTRY_CASE_F_LOWER_BASE UINT8_C(0x08) +/** Lower cased filename extension (last 3 chars). */ +#define FATDIRENTRY_CASE_F_LOWER_EXT UINT8_C(0x10) +/** @} */ + +/** @name FATDIRENTRY_CH0_XXX - FATDIRENTRY::achName[0] + * @{ */ +/** Deleted entry. */ +#define FATDIRENTRY_CH0_DELETED UINT8_C(0xe5) +/** End of used directory entries (MS-DOS 1.25+, PC-DOS 2.0+). */ +#define FATDIRENTRY_CH0_END_OF_DIR UINT8_C(0x00) +/** The special dot or dot-dot dir aliases (MS-DOS 1.40+, PC-DOS 2.0+). + * @remarks 0x2e is the ascii table entry of the '.' character. */ +#define FATDIRENTRY_CH0_DOT_ALIAS UINT8_C(0x2e) +/** Escaped 0xe5 leadcharacter (DOS 3.0+). */ +#define FATDIRENTRY_CH0_ESC_E5 UINT8_C(0x05) +/** @} */ + + +/** + * FAT directory alias name slot. + * + * Each slot holds 13 UTF-16 (/ UCS-2) characters, so it takes 20 slots to cover + * a 255 character long name. + */ +#pragma pack(1) +typedef struct FATDIRNAMESLOT +{ + /** The slot sequence number. */ + uint8_t idSlot; + /** The first 5 name chars. + * @remarks misaligned */ + RTUTF16 awcName0[5]; + /** Attributes (FAT_ATTR_XXX). */ + uint8_t fAttrib; + /** Always zero. */ + uint8_t fZero; + /** Alias checksum. */ + uint8_t bChecksum; + /** The next 6 name chars. */ + RTUTF16 awcName1[6]; + /** Always zero (usually cluster entry). */ + uint16_t idxZero; + /** The next 2 name chars. */ + RTUTF16 awcName2[2]; +} FATDIRNAMESLOT; +#pragma pack() +AssertCompileSize(FATDIRNAMESLOT, 0x20); +/** Pointer to a FAT directory entry. */ +typedef FATDIRNAMESLOT *PFATDIRNAMESLOT; +/** Pointer to a FAT directory entry. */ +typedef FATDIRNAMESLOT const *PCFATDIRNAMESLOT; + +/** Slot ID flag indicating that it's the first slot. */ +#define FATDIRNAMESLOT_FIRST_SLOT_FLAG UINT8_C(0x40) +/** Highest slot ID recognized. This allows for 260 characters, however many + * implementation limits it to 255 or 250. */ +#define FATDIRNAMESLOT_HIGHEST_SLOT_ID UINT8_C(0x14) +/** Max number of slots recognized. (This is the same as the higest slot ID + * because the 0 isn't a valid ID.) */ +#define FATDIRNAMESLOT_MAX_SLOTS FATDIRNAMESLOT_HIGHEST_SLOT_ID +/** Number of UTF-16 units per slot. */ +#define FATDIRNAMESLOT_CHARS_PER_SLOT (5 + 6 + 2) + + + +/** + * FAT directory entry union. + */ +typedef union FATDIRENTRYUNION +{ + /** Regular entry view. */ + FATDIRENTRY Entry; + /** Name slot view. */ + FATDIRNAMESLOT Slot; +} FATDIRENTRYUNION; +AssertCompileSize(FATDIRENTRYUNION, 0x20); +/** Pointer to a FAT directory entry union. */ +typedef FATDIRENTRYUNION *PFATDIRENTRYUNION; +/** Pointer to a const FAT directory entry union. */ +typedef FATDIRENTRYUNION const *PCFATDIRENTRYUNION; + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_fat_h */ + diff --git a/include/iprt/formats/hfs.h b/include/iprt/formats/hfs.h new file mode 100644 index 00000000..bedcb8f1 --- /dev/null +++ b/include/iprt/formats/hfs.h @@ -0,0 +1,691 @@ +/** @file + * IPRT - Hierarchical File System (HFS). + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_hfs_h +#define IPRT_INCLUDED_formats_hfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#include + + +/** @defgroup grp_rt_fmt_hfs HFS - Hierarchical File System. + * @{ + */ + + +/** @name HFS signature words (HFSPlusVolumeHeader::signature) + * @{ */ +#define kHFSSigWord UINT16_C(0x4244) +#define kHFSPlusSigWord UINT16_C(0x482b) +#define kHFSXSigWord UINT16_C(0x4858) +/** @} */ + +/** @name HFS version numbers (HFSPlusVolumeHeader::version). + * @{ */ +#define kHFSPlusVersion UINT16_C(4) +#define kHFSXVersion UINT16_C(5) +/** @} */ + +/** @name HFS mount version numbers (HFSPlusVolumeHeader::lastMountedVersion). + * @{ */ +#define kHFSPlusMountVersion UINT32_C(0x31302e30) +#define kHFSJMountVersion UINT32_C(0x4846534a) +#define kFSKMountVersion UINT32_C(0x46534b21) +/** @} */ + +/** @name Hard link file creators & types. + * @{ */ +#define kHardLinkFileType UINT32_C(0x686c6e6b) +#define kHFSPlusCreator UINT32_C(0x6866732b) +/** @} */ + +/** @name Symlink file creators & types. + * @{ */ +#define kSymLinkFileType UINT32_C(0x736c6e6b) +#define kSymLinkCreator UINT32_C(0x72686170) +/** @} */ + +/** @name Name limits. + * @{ */ +#define kHFSMaxVolumeNameChars UINT8_C(0x1b) +#define kHFSMaxFileNameChars UINT8_C(0x1f) +#define kHFSPlusMaxFileNameChars UINT8_C(0xff) +#define kHFSMaxAttrNameLen UINT8_C(0x7f) +/** @} */ + +/** @name Extent descriptor record densities + * @{ */ +#define kHFSExtentDensity UINT8_C(3) +#define kHFSPlusExtentDensity UINT8_C(8) +/** @} */ + + +/** @name File IDs (various fileID members). + * @{ */ +#define kHFSRootParentID UINT32_C(0x00000001) +#define kHFSRootFolderID UINT32_C(0x00000002) +#define kHFSExtentsFileID UINT32_C(0x00000003) +#define kHFSCatalogFileID UINT32_C(0x00000004) +#define kHFSBadBlockFileID UINT32_C(0x00000005) +#define kHFSAllocationFileID UINT32_C(0x00000006) +#define kHFSStartupFileID UINT32_C(0x00000007) +#define kHFSAttributesFileID UINT32_C(0x00000008) +#define kHFSAttributeDataFileID UINT32_C(0x0000000c) +#define kHFSRepairCatalogFileID UINT32_C(0x0000000e) +#define kHFSBogusExtentFileID UINT32_C(0x0000000f) +#define kHFSFirstUserCatalogNodeID UINT32_C(0x00000010) +/** @} */ + +/** @name Catalog record types. + * @{ */ +#define kHFSFolderRecord UINT16_C(0x0100) +#define kHFSFileRecord UINT16_C(0x0200) +#define kHFSFolderThreadRecord UINT16_C(0x0300) +#define kHFSFileThreadRecord UINT16_C(0x0400) +#define kHFSPlusFolderRecord UINT16_C(0x0001) +#define kHFSPlusFileRecord UINT16_C(0x0002) +#define kHFSPlusFolderThreadRecord UINT16_C(0x0003) +#define kHFSPlusFileThreadRecord UINT16_C(0x0004) +/** @} */ + +/** @name File record bits and masks. + * @{ */ +#define kHFSFileLockedBit 0 +#define kHFSThreadExistsBit 1 +#define kHFSHasAttributesBit 2 +#define kHFSHasSecurityBit 3 +#define kHFSHasFolderCountBit 4 +#define kHFSHasLinkChainBit 5 +#define kHFSHasChildLinkBit 6 +#define kHFSHasDateAddedBit 7 + +#define kHFSFileLockedMask RT_BIT(kHFSFileLockedBit) +#define kHFSThreadExistsMask RT_BIT(kHFSThreadExistsBit) +#define kHFSHasAttributesMask RT_BIT(kHFSHasAttributesBit) +#define kHFSHasSecurityMask RT_BIT(kHFSHasSecurityBit) +#define kHFSHasFolderCountMask RT_BIT(kHFSHasFolderCountBit) +#define kHFSHasLinkChainMask RT_BIT(kHFSHasLinkChainBit) +#define kHFSHasChildLinkMask RT_BIT(kHFSHasChildLinkBit) +#define kHFSHasDateAddedMask RT_BIT(kHFSHasDateAddedBit) +/** @} */ + +/** @name Key and node lengths. + * @{ */ +#define kHFSPlusAttrKeyMaximumLength ( sizeof(HFSPlusAttrKey) - sizeof(uint16_t) ) +#define kHFSPlusAttrKeyMinimumLength ( kHFSPlusAttrKeyMaximumLength - (kHFSMaxAttrNameLen * sizeof(uint16_t)) ) +#define kHFSPlusExtentKeyMaximumLength ( sizeof(HFSPlusExtentKey) - sizeof(uint16_t), +#define kHFSExtentKeyMaximumLength ( sizeof(HFSExtentKey) - sizeof(uint8_t) ) +#define kHFSPlusCatalogKeyMaximumLength ( sizeof(HFSPlusCatalogKey) - sizeof(uint16_t) ) +#define kHFSPlusCatalogKeyMinimumLength ( kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(uint16_t) ) +#define kHFSCatalogKeyMaximumLength ( sizeof(HFSCatalogKey) - sizeof(uint8_t) ) +#define kHFSCatalogKeyMinimumLength ( kHFSCatalogKeyMaximumLength - kHFSMaxFileNameChars - 1 + sizeof(uint8_t) ) +#define kHFSPlusCatalogMinNodeSize UINT16_C(0x1000) +#define kHFSPlusExtentMinNodeSize UINT16_C(0x0200) +#define kHFSPlusAttrMinNodeSize UINT16_C(0x1000) +/** @} */ + +/** @name Volume Attribute bits and masks. + * @remarks HFS has only 16-bit wide field, HFS+ has 32-bit. + * @{ */ +#define kHFSVolumeHardwareLockBit 7 +#define kHFSVolumeUnmountedBit 8 +#define kHFSVolumeSparedBlocksBit 9 +#define kHFSVolumeNoCacheRequiredBit 10 +#define kHFSBootVolumeInconsistentBit 11 +#define kHFSCatalogNodeIDsReusedBit 12 +#define kHFSVolumeJournaledBit 13 +#define kHFSVolumeInconsistentBit 14 +#define kHFSVolumeSoftwareLockBit 15 +#define kHFSUnusedNodeFixBit 31 +#define kHFSContentProtectionBit 30 + +#define kHFSVolumeHardwareLockMask RT_BIT(kHFSVolumeHardwareLockBit) +#define kHFSVolumeUnmountedMask RT_BIT(kHFSVolumeUnmountedBit) +#define kHFSVolumeSparedBlocksMask RT_BIT(kHFSVolumeSparedBlocksBit) +#define kHFSVolumeNoCacheRequiredMask RT_BIT(kHFSVolumeNoCacheRequiredBit) +#define kHFSBootVolumeInconsistentMask RT_BIT(kHFSBootVolumeInconsistentBit) +#define kHFSCatalogNodeIDsReusedMask RT_BIT(kHFSCatalogNodeIDsReusedBit) +#define kHFSVolumeJournaledMask RT_BIT(kHFSVolumeJournaledBit) +#define kHFSVolumeInconsistentMask RT_BIT(kHFSVolumeInconsistentBit) +#define kHFSVolumeSoftwareLockMask RT_BIT(kHFSVolumeSoftwareLockBit) +#define kHFSUnusedNodeFixMask RT_BIT(kHFSUnusedNodeFixBit) +#define kHFSContentProtectionMask RT_BIT(kHFSContentProtectionBit) + +#define kHFSMDBAttributesMask UINT16_C(0x8380) +/** @} */ + +/** @name Misc + * @{ */ +#define kHFSUnusedNodesFixDate UINT32_C(0xc5ef2480) + +#define HFSPLUSMETADATAFOLDER "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data" +#define HFSPLUS_DIR_METADATA_FOLDER ".HFS+ Private Directory Data\xd" +#define HFS_INODE_PREFIX "iNode" +#define HFS_DELETE_PREFIX "temp" +#define HFS_DIRINODE_PREFIX "dir_" +#define FIRST_LINK_XATTR_NAME "com.apple.system.hfs.firstlink" +#define FIRST_LINK_XATTR_REC_SIZE ( sizeof(HFSPlusAttrData) + 10 ) + +/* {b3e20f39-f292-11d6-97a4-00306543ecac} */ +#define HFS_UUID_NAMESPACE_ID "\xB3\xE2\x0F\x39\xF2\x92\x11\xD6\x97\xA4\x00\x30\x65\x43\xEC\xAC" + +#define SET_HFS_TEXT_ENCODING(a_uHint) (UINT32_C(0x656e6300) | (uint8_t)(a_uHint)) +#define GET_HFS_TEXT_ENCODING(a_uHint) ( ((a_uHint) & UINT32_C(0xffffff00)) == UINT32_C(0x656e6300) \ + ? UINT32_C(0x000000ff)(a_uHint) : UINT32_MAX) +/** @} */ + +/** @name B-tree stuff. + * @{ */ +#define kMaxKeyLength 520 + +#define kBTLeafNode (-1) +#define kBTIndexNode 0 +#define kBTHeaderNode 1 +#define kBTMapNode 2 + +#define kBTBadCloseMask RT_BIT_32(0) +#define kBTBigKeysMask RT_BIT_32(1) +#define kBTVariableIndexKeysMask RT_BIT_32(2) + +/** @} */ + +/** @name B-tree compare types (BTHeaderRec::keyCompareType) + * @{ */ +#define kHFSCaseFolding UINT8_C(0xcf) +#define kHFSBinaryCompare UINT8_C(0xbc) +/** @} */ + +/** @name Journal stuff. + * @{ */ +#define JIB_RESERVED_SIZE ( sizeof(uint32_t) * 32 - 85 ) + +#define kJIJournalInFSMask RT_BIT_32(0) +#define kJIJournalOnOtherDeviceMask RT_BIT_32(1) +#define kJIJournalNeedInitMask RT_BIT_32(2) + +#define EXTJNL_CONTENT_TYPE_UUID "4a6f7572-6e61-11aa-aa11-00306543ecac" +/** @} */ + + + +typedef struct HFSUniStr255 +{ + uint16_t length; + RTUTF16 unicode[255]; +} HFSUniStr255; +AssertCompileSize(HFSUniStr255, 0x200); +typedef const HFSUniStr255 * ConstHFSUniStr255Param; + +#pragma pack(1) +typedef struct HFSExtentKey +{ + uint8_t keyLength; + uint8_t forkType; + uint32_t fileID; /**< Misaligned. */ + uint16_t startBLock; +} HFSExtentKey; +#pragma pack() +AssertCompileSize(HFSExtentKey, 8); + +typedef struct HFSPlusExtentKey +{ + uint16_t keyLength; + uint8_t forkType; + uint8_t pad; + uint32_t fileID; + uint32_t startBlock; +} HFSPlusExtentKey; +AssertCompileSize(HFSPlusExtentKey, 12); + +typedef struct HFSExtentDescriptor +{ + uint16_t startBlock; + uint16_t blockCount; +} HFSExtentDescriptor; +AssertCompileSize(HFSExtentDescriptor, 4); + +typedef struct HFSPlusExtentDescriptor +{ + uint32_t startBlock; + uint32_t blockCount; +} HFSPlusExtentDescriptor; +AssertCompileSize(HFSPlusExtentDescriptor, 8); + +typedef HFSExtentDescriptor HFSExtentRecord[3]; +typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8]; + +typedef struct FndrFileInfo +{ + uint32_t fdType; + uint32_t fdCreator; + uint16_t fdFlags; + struct + { + int16_t v; + int16_t h; + } fdLocation; + uint16_t opaque; +} FndrFileInfo; +AssertCompileSize(FndrFileInfo, 16); + +typedef struct FndrDirInfo +{ + struct + { + int16_t top; + int16_t left; + int16_t bottom; + int16_t right; + } frRect; + uint16_t frFlags; + struct + { + int16_t v; + int16_t h; + } fdLocation; + uint16_t opaque; +} FndrDirInfo; +AssertCompileSize(FndrDirInfo, 16); + +typedef struct FndrOpaqueInfo +{ + int8_t opaque[16]; +} FndrOpaqueInfo; +AssertCompileSize(FndrOpaqueInfo, 16); + +typedef struct FndrExtendedFileInfo +{ + uint32_t reserved1; + uint32_t date_added; + uint16_t extended_flags; + uint16_t reserved2; + uint32_t reserved3; +} FndrExtendedFileInfo; +AssertCompileSize(FndrExtendedFileInfo, 16); + +typedef struct FndrExtendedDirInfo +{ + uint32_t point; + uint32_t date_added; + uint16_t extended_flags; + uint16_t reserved3; + uint32_t reserved4; +} FndrExtendedDirInfo; +AssertCompileSize(FndrExtendedDirInfo, 16); + +typedef struct HFSPlusForkData +{ + uint64_t logicalSize; + uint32_t clumpSize; + uint32_t totalBlocks; + HFSPlusExtentRecord extents; +} HFSPlusForkData; +AssertCompileSize(HFSPlusForkData, 80); + +typedef struct HFSPlusBSDInfo +{ + uint32_t ownerID; + uint32_t groupID; + uint8_t adminFlags; + uint8_t ownerFlags; + uint16_t fileMode; + union + { + uint32_t iNodeNum; + uint32_t linkCount; + uint32_t rawDevice; + } special; +} HFSPlusBSDInfo; +AssertCompileSize(HFSPlusBSDInfo, 16); + +#pragma pack(1) +typedef struct HFSCatalogKey +{ + uint8_t keyLength; + uint8_t reserved; + uint32_t parentID; /**< Misaligned. */ + uint8_t nodeName[kHFSMaxFileNameChars + 1]; +} HFSCatalogKey; +#pragma pack() +AssertCompileSize(HFSCatalogKey, 0x26); + +#pragma pack(1) +typedef struct HFSPlusCatalogKey +{ + uint16_t keyLength; + uint32_t parentID; /**< Misaligned. */ + HFSUniStr255 nodeName; +} HFSPlusCatalogKey; +#pragma pack() +AssertCompileSize(HFSPlusCatalogKey, 0x206); + +#pragma pack(1) +typedef struct HFSCatalogFolder +{ + int16_t recordType; + uint16_t flags; + uint16_t valence; + uint32_t folderID; /**< Misaligned. */ + uint32_t createDate; /**< Misaligned. */ + uint32_t modifyDate; /**< Misaligned. */ + uint32_t backupDate; /**< Misaligned. */ + FndrDirInfo userInfo; + FndrOpaqueInfo finderInfo; + uint32_t reserved[4]; /**< Misaligned. */ +} HFSCatalogFolder; +#pragma pack() +AssertCompileSize(HFSCatalogFolder, 70); + +typedef struct HFSPlusCatalogFolder +{ + int16_t recordType; + uint16_t flags; + uint32_t valence; + uint32_t folderID; + uint32_t createDate; + uint32_t contentModDate; + uint32_t attributeModDate; + uint32_t accessDate; + uint32_t backupDate; + HFSPlusBSDInfo bsdInfo; + FndrDirInfo userInfo; + FndrOpaqueInfo finderInfo; + uint32_t textEncoding; + uint32_t folderCount; +} HFSPlusCatalogFolder; +AssertCompileSize(HFSPlusCatalogFolder, 88); + +#pragma pack(1) +typedef struct HFSCatalogFile +{ + int16_t recordType; + uint8_t flags; + uint8_t fileType; + FndrFileInfo userInfo; + uint32_t fileID; + uint16_t dataStartBlock; + int32_t dataLogicalSize; /**< Misaligned. */ + int32_t dataPhysicalSize; /**< Misaligned. */ + uint16_t rsrcStartBlock; + int32_t rsrcLogicalSize; + int32_t rsrcPhysicalSize; + uint32_t createDate; + uint32_t modifyDate; + uint32_t backupDate; + FndrOpaqueInfo finderInfo; + uint16_t clumpSize; + HFSExtentRecord dataExtents; /**< Misaligned. */ + HFSExtentRecord rsrcExtents; /**< Misaligned. */ + uint32_t reserved; /**< Misaligned. */ +} HFSCatalogFile; +#pragma pack() +AssertCompileSize(HFSCatalogFile, 102); + +#pragma pack(1) +typedef struct HFSPlusCatalogFile +{ + int16_t recordType; + uint16_t flags; + uint32_t reserved1; + uint32_t fileID; + uint32_t createDate; + uint32_t contentModDate; + uint32_t attributeModDate; + uint32_t accessDate; + uint32_t backupDate; + HFSPlusBSDInfo bsdInfo; + FndrFileInfo userInfo; + FndrOpaqueInfo finderInfo; + uint32_t textEncoding; + uint32_t reserved2; + HFSPlusForkData dataFork; + HFSPlusForkData resourceFork; +} HFSPlusCatalogFile; +#pragma pack() +AssertCompileMemberAlignment(HFSPlusCatalogFile, dataFork, 8); +AssertCompileSize(HFSPlusCatalogFile, 248); + +#pragma pack(1) +typedef struct HFSCatalogThread +{ + int16_t recordType; + int32_t reserved[2]; + uint32_t parentID; + uint8_t nodeName[kHFSMaxFileNameChars + 1]; +} HFSCatalogThread; +#pragma pack() +AssertCompileSize(HFSCatalogThread, 46); + +typedef struct HFSPlusCatalogThread +{ + int16_t recordType; + int16_t reserved; + uint32_t parentID; + HFSUniStr255 nodeName; +} HFSPlusCatalogThread; +AssertCompileSize(HFSPlusCatalogThread, 0x208); + +typedef struct HFSPlusAttrForkData +{ + uint32_t recordType; + uint32_t reserved; + HFSPlusForkData theFork; +} HFSPlusAttrForkData; +AssertCompileSize(HFSPlusAttrForkData, 88); + +typedef struct HFSPlusAttrExtents +{ + uint32_t recordType; + uint32_t reserved; + HFSPlusExtentRecord extents; +} HFSPlusAttrExtents; +AssertCompileSize(HFSPlusAttrExtents, 72); + +#pragma pack(1) +typedef struct HFSPlusAttrData +{ + uint32_t recordType; + uint32_t reserved[2]; + uint32_t attrSize; + uint8_t attrData[2]; /**< Causes misaligned struct size. */ +} HFSPlusAttrData; +#pragma pack() +AssertCompileSize(HFSPlusAttrData, 18); + +#pragma pack(1) +typedef struct HFSPlusAttrInlineData +{ + uint32_t recordType; + uint32_t reserved; + uint32_t logicalSize; + uint8_t userData[2]; /**< Causes misaligned struct size. */ +} HFSPlusAttrInlineData; +#pragma pack() +AssertCompileSize(HFSPlusAttrInlineData, 14); + +typedef union HFSPlusAttrRecord +{ + uint32_t recordType; + HFSPlusAttrInlineData inlineData; + HFSPlusAttrData attrData; + HFSPlusAttrForkData forkData; + HFSPlusAttrExtents overflowExtents; +} HFSPlusAttrRecord; +AssertCompileSize(HFSPlusAttrRecord, 88); + +typedef struct HFSPlusAttrKey +{ + uint16_t keyLength; + uint16_t pad; + uint32_t fileID; + uint32_t startBlock; + uint16_t attrNameLen; + RTUTF16 attrName[kHFSMaxAttrNameLen]; +} HFSPlusAttrKey; +AssertCompileSize(HFSPlusAttrKey, 268); + +#pragma pack(1) +typedef struct HFSMasterDirectoryBlock +{ + uint16_t drSigWord; + uint32_t drCrDate; /**< Misaligned. */ + uint32_t drLsMod; /**< Misaligned. */ + uint16_t drAtrb; + uint16_t drNmFls; + uint16_t drVBMSt; + uint16_t drAllocPtr; + uint16_t drNmAlBlks; + uint32_t drAlBlkSiz; + uint32_t drClpSiz; + uint16_t drAlBlSt; + uint32_t drNxCNID; /**< Misaligned. */ + uint16_t drFreeBks; + uint8_t drVN[kHFSMaxVolumeNameChars + 1]; + uint32_t drVolBkUp; + uint16_t drVSeqNum; + uint32_t drWrCnt; /**< Misaligned. */ + uint32_t drXTClpSiz; /**< Misaligned. */ + uint32_t drCTClpSiz; /**< Misaligned. */ + uint16_t drNmRtDirs; + uint32_t drFilCnt; + uint32_t drDirCnt; + uint32_t drFndrInfo[8]; + uint16_t drEmbedSigWord; + HFSExtentDescriptor drEmbedExtent; + uint32_t drXTFlSize; /**< Misaligned. */ + HFSExtentRecord drXTExtRec; + uint32_t drCTFlSize; /**< Misaligned. */ + HFSExtentRecord drCTExtRec; +} HFSMasterDirectoryBlock; +#pragma pack() +AssertCompileSize(HFSMasterDirectoryBlock, 162); + +typedef struct HFSPlusVolumeHeader +{ + uint16_t signature; + uint16_t version; + uint32_t attributes; + uint32_t lastMountedVersion; + uint32_t journalInfoBlock; + uint32_t createDate; + uint32_t modifyDate; + uint32_t backupDate; + uint32_t checkedDate; + uint32_t fileCount; + uint32_t folderCount; + uint32_t blockSize; + uint32_t totalBlocks; + uint32_t freeBlocks; + uint32_t nextAllocation; + uint32_t rsrcClumpSize; + uint32_t dataClumpSize; + uint32_t nextCatalogID; + uint32_t writeCount; + uint64_t encodingsBitmap; + uint8_t finderInfo[32]; + HFSPlusForkData allocationFile; + HFSPlusForkData extentsFile; + HFSPlusForkData catalogFile; + HFSPlusForkData attributesFile; + HFSPlusForkData startupFile; +} HFSPlusVolumeHeader; +AssertCompileMemberAlignment(HFSPlusVolumeHeader, nextCatalogID, 8); +AssertCompileSize(HFSPlusVolumeHeader, 512); + +typedef union BTreeKey +{ + uint8_t length8; + uint16_t length16; + uint8_t rawData[kMaxKeyLength + 2]; +} BTreeKey; +AssertCompileSize(BTreeKey, 522); + +#pragma pack(1) +typedef struct BTNodeDescriptor +{ + uint32_t fLink; + uint32_t bLink; + int8_t kind; + uint8_t height; + uint16_t numRecords; + uint16_t reserved; /**< Causes struct size misalignment. */ +} BTNodeDescriptor; +#pragma pack() +AssertCompileSize(BTNodeDescriptor, 14); + +#pragma pack(1) +typedef struct BTHeaderRec +{ + uint16_t treeDepth; + uint32_t rootNode; /**< Misaligned. */ + uint32_t leafRecords; /**< Misaligned. */ + uint32_t firstLeafNode; /**< Misaligned. */ + uint32_t lastLeafNode; /**< Misaligned. */ + uint16_t nodeSize; + uint16_t maxKeyLength; + uint32_t totalNodes; /**< Misaligned. */ + uint32_t freeNodes; /**< Misaligned. */ + uint16_t reserved1; + uint32_t clumpSize; + uint8_t btreeType; + uint8_t keyCompareType; + uint32_t attributes; /**< Misaligned. */ + uint32_t reserved3[16]; /**< Misaligned. */ +} BTHeaderRec; +#pragma pack() +AssertCompileSize(BTHeaderRec, 106); + +#pragma pack(1) +typedef struct JournalInfoBlock +{ + uint32_t flags; + uint32_t devices_signature[8]; + uint64_t offset; /**< Misaligned (morons). */ + uint64_t size; /**< Misaligned. */ + char ext_jnl_uuid[37]; + char machine_serial_num[48]; + char reserved[JIB_RESERVED_SIZE]; +} JournalInfoBlock; +#pragma pack() +AssertCompileSize(JournalInfoBlock, 180); + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_hfs_h */ + diff --git a/include/iprt/formats/iso9660.h b/include/iprt/formats/iso9660.h new file mode 100644 index 00000000..6b3e7192 --- /dev/null +++ b/include/iprt/formats/iso9660.h @@ -0,0 +1,1516 @@ +/* $Id: iso9660.h $ */ +/** @file + * IPRT, ISO 9660 File System + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_iso9660_h +#define IPRT_INCLUDED_formats_iso9660_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_iso9660 ISO 9660 structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + + +/** The (default) logical sectors size of ISO 9660. */ +#define ISO9660_SECTOR_SIZE 2048 +/** The (default) sector offset mask of ISO 9660. */ +#define ISO9660_SECTOR_OFFSET_MASK 2047 +/** Maximum filename length (level 2 & 3). */ +#define ISO9660_MAX_NAME_LEN 30 + + +/** Accessor for ISO9660U16 and ISO9660U32 that retrievs the member value for + * the host endianess. */ +#ifdef RT_BIG_ENDIAN +# define ISO9660_GET_ENDIAN(a_pInt) ((a_pInt)->be) +#else +# define ISO9660_GET_ENDIAN(a_pInt) ((a_pInt)->le) +#endif + + +/** + * ISO 9660 16-bit unsigned integer type. + */ +typedef struct ISO9660U16 +{ + /** Little endian. */ + uint16_t le; + /** Big endian. */ + uint16_t be; +} ISO9660U16; +/** Pointer to an ISO 9660 16-bit unsigned integer type. */ +typedef ISO9660U16 *PISO9660U16; +/** Pointer to a const ISO 9660 16-bit unsigned integer type. */ +typedef ISO9660U16 const *PCISO9660U16; + +/** ISO 9660 big endian 16-bit unsigned integer. */ +typedef uint16_t ISO9660U16BE; + + +/** + * ISO 9660 32-bit unsigned integer type. + */ +typedef struct ISO9660U32 +{ + /** Little endian. */ + uint32_t le; + /** Big endian. */ + uint32_t be; +} ISO9660U32; +/** Pointer to an ISO 9660 32-bit unsigned integer type. */ +typedef ISO9660U32 *PISO9660U32; +/** Pointer to a const ISO 9660 32-bit unsigned integer type. */ +typedef ISO9660U32 const *PCISO9660U32; + +/** ISO 9660 little endian 32-bit unsigned integer. */ +typedef uint32_t ISO9660U32LE; +/** ISO 9660 big endian 32-bit unsigned integer. */ +typedef uint32_t ISO9660U32BE; + +/** + * ISO 9660 timestamp (date & time). + */ +typedef struct ISO9660TIMESTAMP +{ + /** 0x00: For digit year (0001-9999). */ + char achYear[4]; + /** 0x04: Month of the year (01-12). */ + char achMonth[2]; + /** 0x06: Day of month (01-31). */ + char achDay[2]; + /** 0x08: Hour of day (00-23). */ + char achHour[2]; + /** 0x0a: Minute of hour (00-59). */ + char achMinute[2]; + /** 0x0c: Second of minute (00-59). */ + char achSecond[2]; + /** 0x0e: Hundreth of second (00-99). */ + char achCentisecond[2]; + /** 0x10: The UTC (GMT) offset in 15 min units. */ + int8_t offUtc; +} ISO9660TIMESTAMP; +AssertCompileSize(ISO9660TIMESTAMP, 17); +/** Pointer to an ISO 9660 timestamp. */ +typedef ISO9660TIMESTAMP *PISO9660TIMESTAMP; +/** Pointer to a const ISO 9660 timestamp. */ +typedef ISO9660TIMESTAMP const *PCISO9660TIMESTAMP; + +/** + * ISO 9660 record timestamp (date & time). + */ +typedef struct ISO9660RECTIMESTAMP +{ + /** 0: Years since 1900. */ + uint8_t bYear; + /** 1: Month of year (1-12). */ + uint8_t bMonth; + /** 2: Day of month (1-31). */ + uint8_t bDay; + /** 3: Hour of day (0-23). */ + uint8_t bHour; + /** 4: Minute of hour (0-59). */ + uint8_t bMinute; + /** 5: Second of minute (0-59). */ + uint8_t bSecond; + /** 6: The UTC (GMT) offset in 15 min units. */ + int8_t offUtc; +} ISO9660RECTIMESTAMP; +AssertCompileSize(ISO9660RECTIMESTAMP, 7); +/** Pointer to an ISO 9660 record timestamp. */ +typedef ISO9660RECTIMESTAMP *PISO9660RECTIMESTAMP; +/** Pointer to a const ISO 9660 record timestamp. */ +typedef ISO9660RECTIMESTAMP const *PCISO9660RECTIMESTAMP; + + +/** + * ISO 9660 directory record. + */ +#pragma pack(1) +typedef struct ISO9660DIRREC +{ + /** 0x00: Length of this record in bytes. */ + uint8_t cbDirRec; + /** 0x01: Extended attribute record length in logical blocks. */ + uint8_t cExtAttrBlocks; + /** 0x02: Location of extent (logical block number). + * @note Misaligned. */ + ISO9660U32 offExtent; + /** 0x0a: Size of the data (file section). Does not include EAs. + * @note Misaligned. */ + ISO9660U32 cbData; + /** 0x12: Recording time and date. */ + ISO9660RECTIMESTAMP RecTime; + /** 0x19: File flags (ISO9660_FILE_FLAGS_XXX). */ + uint8_t fFileFlags; + /** 0x1a: File unit size for interlaved mode. */ + uint8_t bFileUnitSize; + /** 0x1b: Interlave gap size. */ + uint8_t bInterleaveGapSize; + /** 0x1c: Volume sequence number where the extent resides. */ + ISO9660U16 VolumeSeqNo; + /** 0x20: Length of file identifier field. */ + uint8_t bFileIdLength; + /** 0x21: File identifier (d-characters or d1-characters). */ + char achFileId[1]; + /* There are more fields following: + * - one byte optional padding so the following field is at an even boundrary. + * - system use field until cbDirRec is reached. + */ +} ISO9660DIRREC; +#pragma pack() +AssertCompileMemberOffset(ISO9660DIRREC, offExtent, 0x02); +AssertCompileMemberOffset(ISO9660DIRREC, cbData, 0x0a); +AssertCompileMemberOffset(ISO9660DIRREC, RecTime, 0x12); +AssertCompileMemberOffset(ISO9660DIRREC, fFileFlags, 0x19); +AssertCompileMemberOffset(ISO9660DIRREC, bFileIdLength, 0x20); +AssertCompileMemberOffset(ISO9660DIRREC, achFileId, 0x21); +/** Pointer to an ISO 9660 directory record. */ +typedef ISO9660DIRREC *PISO9660DIRREC; +/** Pointer to a const ISO 9660 directory record. */ +typedef ISO9660DIRREC const *PCISO9660DIRREC; + +/** @name ISO9660_FILE_FLAGS_XXX + * @{ */ +/** Existence - Hide the file from the user. */ +#define ISO9660_FILE_FLAGS_HIDDEN UINT8_C(0x01) +/** Directory - Indicates a directory as apposed to a regular file (0). */ +#define ISO9660_FILE_FLAGS_DIRECTORY UINT8_C(0x02) +/** Assocated File - Indicates that the file is an associated file. */ +#define ISO9660_FILE_FLAGS_ASSOCIATED_FILE UINT8_C(0x04) +/** Record - Indicates specified file content record format (see EAs). */ +#define ISO9660_FILE_FLAGS_RECORD UINT8_C(0x08) +/** Protection - Indicates owner/group or permission protection in EAs. */ +#define ISO9660_FILE_FLAGS_PROTECTION UINT8_C(0x10) +/** Reserved bit, MBZ. */ +#define ISO9660_FILE_FLAGS_RESERVED_5 UINT8_C(0x20) +/** Reserved bit, MBZ. */ +#define ISO9660_FILE_FLAGS_RESERVED_6 UINT8_C(0x40) +/** Multi-extend - Indicates that this isn't the final record for the file. + * @remarks Use for working around 4 GiB file size limitation. */ +#define ISO9660_FILE_FLAGS_MULTI_EXTENT UINT8_C(0x80) +/** @} */ + + +/** + * ISO 9660 path table record. + */ +#pragma pack(1) +typedef struct ISO9660PATHREC +{ + /** 0x00: Length of the achDirId field in bytes. */ + uint8_t cbDirId; + /** 0x01: Extended attribute record length in bytes? */ + uint8_t cbExtAttr; + /** 0x02: Location of extent (logical block number). + * @note Endianess depends on table. + * @note Misaligned. */ + uint32_t offExtent; + /** 0x06: Parent directory number. + * @note Endianess depends on table. */ + uint16_t idParentRec; + /** 0x08: Directory identifier (d-characters or d1-characters). */ + RT_FLEXIBLE_ARRAY_EXTENSION + char achDirId[RT_FLEXIBLE_ARRAY]; + /* There will be a zero padding byte following if the directory identifier length is odd. */ +} ISO9660PATHREC; +#pragma pack() +AssertCompileMemberOffset(ISO9660PATHREC, cbExtAttr, 0x01); +AssertCompileMemberOffset(ISO9660PATHREC, offExtent, 0x02); +AssertCompileMemberOffset(ISO9660PATHREC, idParentRec, 0x06); +AssertCompileMemberOffset(ISO9660PATHREC, achDirId, 0x08); +/** Pointer to an ISO 9660 path table record. */ +typedef ISO9660PATHREC *PISO9660PATHREC; +/** Pointer to a const ISO 9660 path table record. */ +typedef ISO9660PATHREC const *PCISO9660PATHREC; + + +/** + * ISO 9660 extended attribute record. + */ +typedef struct ISO9660EXATTRREC +{ + /** 0x000: The owner ID. */ + ISO9660U16 idOwner; + /** 0x004: The group ID. */ + ISO9660U16 idGroup; + /** 0x008: File permissions (ISO9660_PERM_XXX). */ + ISO9660U16BE fPermissions; + /** 0x00a: File creation timestamp. */ + ISO9660TIMESTAMP BirthTimestamp; + /** 0x01b: File modification timestamp. */ + ISO9660TIMESTAMP ModifyTimestamp; + /** 0x02c: File expiration timestamp. */ + ISO9660TIMESTAMP ExpireTimestamp; + /** 0x03d: File effective timestamp. */ + ISO9660TIMESTAMP EffectiveTimestamp; + /** 0x04e: Record format. */ + uint8_t bRecordFormat; + /** 0x04f: Record attributes. */ + uint8_t fRecordAttrib; + /** 0x050: Record length. */ + ISO9660U16 RecordLength; + /** 0x054: System identifier (a-characters or a1-characters). */ + char achSystemId[0x20]; + /** 0x074: System specific bytes. */ + uint8_t abSystemUse[64]; + /** 0x0b4: Extended attribute record version (ISO9660EXATTRREC_VERSION). */ + uint8_t bExtRecVersion; + /** 0x0b5: Length of escape sequences. */ + uint8_t cbEscapeSequences; + /** 0x0b6: Reserved for the future, MBZ. */ + uint8_t abReserved183[64]; + /** 0x0f6: Length of the application use field. */ + ISO9660U16 cbAppUse; + /** 0x0fa: Variable sized application use field. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abAppUse[RT_FLEXIBLE_ARRAY]; + /* This is followed by escape sequences with length given by cbEscapeSequnces. */ +} ISO9660EXATTRREC; +AssertCompileMemberOffset(ISO9660EXATTRREC, EffectiveTimestamp, 0x03d); +AssertCompileMemberOffset(ISO9660EXATTRREC, cbAppUse, 0x0f6); + +/** The ISO9660EXATTRREC::bExtRecVersion value. */ +#define ISO9660EXATTRREC_VERSION UINT8_C(0x01) + +/** @name ISO9660_PERM_XXX - ISO9660EXATTRREC::fPermissions + * @{ */ +/** @todo figure out this weird permission stuff... */ +/** @} */ + + +/** + * ISO 9660 volume descriptor header. + */ +typedef struct ISO9660VOLDESCHDR +{ + /** Descriptor type ISO9660VOLDESC_TYPE_XXX. */ + uint8_t bDescType; + /** Standard identifier 'CD001' */ + uint8_t achStdId[5]; + /** The descriptor version. */ + uint8_t bDescVersion; + /* (This is followed by the descriptor specific data). */ +} ISO9660VOLDESCHDR; +AssertCompileSize(ISO9660VOLDESCHDR, 7); +/** Pointer to a volume descriptor header. */ +typedef ISO9660VOLDESCHDR *PISO9660VOLDESCHDR; +/** Pointer to a const volume descriptor header. */ +typedef ISO9660VOLDESCHDR const *PCISO9660VOLDESCHDR; + +/** @name ISO9660VOLDESC_TYPE_XXX - volume descriptor types + * @{ */ +/** See ISO9660BOOTRECORD. */ +#define ISO9660VOLDESC_TYPE_BOOT_RECORD UINT8_C(0x00) +/** See ISO9660PRIMARYVOLDESC. */ +#define ISO9660VOLDESC_TYPE_PRIMARY UINT8_C(0x01) +/** See ISO9660SUPVOLDESC. */ +#define ISO9660VOLDESC_TYPE_SUPPLEMENTARY UINT8_C(0x02) +/** See ISO9660VOLPARTDESC. */ +#define ISO9660VOLDESC_TYPE_PARTITION UINT8_C(0x03) +/** Terminates the volume descriptor set. Has no data (zeros), version is 1. */ +#define ISO9660VOLDESC_TYPE_TERMINATOR UINT8_C(0xff) +/** @} */ + +/** The value of ISO9660VOLDESCHDR::achStdId */ +#define ISO9660VOLDESC_STD_ID "CD001" +#define ISO9660VOLDESC_STD_ID_0 'C' +#define ISO9660VOLDESC_STD_ID_1 'D' +#define ISO9660VOLDESC_STD_ID_2 '0' +#define ISO9660VOLDESC_STD_ID_3 '0' +#define ISO9660VOLDESC_STD_ID_4 '1' + + + +/** + * ISO 9660 boot record (volume descriptor). + */ +typedef struct ISO9660BOOTRECORD +{ + /** The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_BOOT_RECORD and version + * ISO9660BOOTRECORD_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** Boot system identifier string (a-characters). */ + char achBootSystemId[32]; + /** Boot identifier (a-characters). */ + char achBootId[32]; + /** Boot system specific content. */ + uint8_t abBootSystemSpecific[1977]; +} ISO9660BOOTRECORD; +AssertCompileSize(ISO9660BOOTRECORD, ISO9660_SECTOR_SIZE); +/** Pointer to an ISO 9660 boot record. */ +typedef ISO9660BOOTRECORD *PISO9660BOOTRECORD; +/** Pointer to a const ISO 9660 boot record. */ +typedef ISO9660BOOTRECORD const *PCISO9660BOOTRECORD; + +/** The value of ISO9660BOOTRECORD::Hdr.uDescVersion. */ +#define ISO9660BOOTRECORD_VERSION UINT8_C(1) + + +/** + * ISO 9660 boot record (volume descriptor), El Torito variant. + */ +#pragma pack(1) +typedef struct ISO9660BOOTRECORDELTORITO +{ + /** 0x000: The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_BOOT_RECORD and version + * ISO9660BOOTRECORD_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** 0x007: Boot system identifier string, + * zero padded ISO9660BOOTRECORDELTORITO_BOOT_SYSTEM_ID. */ + char achBootSystemId[32]; + /** 0x027: Boot identifier - all zeros. */ + char achBootId[32]; + /** 0x047: Boot catalog location (block offset), always (?) little endian. + * @note Misaligned. */ + uint32_t offBootCatalog; + /** 0x04b: Unused - all zeros. */ + uint8_t abBootSystemSpecific[1973]; +} ISO9660BOOTRECORDELTORITO; +#pragma pack() +AssertCompileSize(ISO9660BOOTRECORDELTORITO, ISO9660_SECTOR_SIZE); +/** Pointer to an ISO 9660 El Torito boot record. */ +typedef ISO9660BOOTRECORDELTORITO *PISO9660BOOTRECORDELTORITO; +/** Pointer to a const ISO 9660 El Torito boot record. */ +typedef ISO9660BOOTRECORDELTORITO const *PCISO9660BOOTRECORDELTORITO; + +/** The value of ISO9660BOOTRECORDELTORITO::achBootSystemId (zero padded). */ +#define ISO9660BOOTRECORDELTORITO_BOOT_SYSTEM_ID "EL TORITO SPECIFICATION" + + +/** + * ISO 9660 primary volume descriptor. + */ +typedef struct ISO9660PRIMARYVOLDESC +{ + /** 0x000: The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_PRIMARY and version + * ISO9660PRIMARYVOLDESC_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** 0x007: Explicit alignment zero padding. */ + uint8_t bPadding8; + /** 0x008: System identifier (a-characters). */ + char achSystemId[32]; + /** 0x028: Volume identifier (d-characters). */ + char achVolumeId[32]; + /** 0x048: Unused field, zero filled. */ + ISO9660U32 Unused73; + /** 0x050: Volume space size in logical blocks (cbLogicalBlock). */ + ISO9660U32 VolumeSpaceSize; + /** 0x058: Unused field(s), zero filled. */ + uint8_t abUnused89[32]; + /** 0x078: The number of volumes in the volume set. */ + ISO9660U16 cVolumesInSet; + /** 0x07c: Volume sequence number. */ + ISO9660U16 VolumeSeqNo; + /** 0x080: Logical block size in bytes. */ + ISO9660U16 cbLogicalBlock; + /** 0x084: Path table size. */ + ISO9660U32 cbPathTable; + /** 0x08c: Type L(ittle endian) path table location (block offset). */ + ISO9660U32LE offTypeLPathTable; + /** 0x090: Optional type L(ittle endian) path table location (block offset). */ + ISO9660U32LE offOptionalTypeLPathTable; + /** 0x094: Type M (big endian) path table location (block offset). */ + ISO9660U32BE offTypeMPathTable; + /** 0x098: Optional type M (big endian) path table location (block offset). */ + ISO9660U32BE offOptionalTypeMPathTable; + /** 0x09c: Directory entry for the root directory (union). */ + union + { + uint8_t ab[34]; + ISO9660DIRREC DirRec; + } RootDir; + /** 0x0be: Volume set identifier (d-characters). */ + char achVolumeSetId[128]; + /** 0x13e: Publisher identifier (a-characters). Alternatively, it may refere to + * a file in the root dir if it starts with 0x5f and restricts itself to 8 + * d-characters. */ + char achPublisherId[128]; + /** 0x1be: Data preparer identifier (a-characters). + * Same file reference alternative as previous field. */ + char achDataPreparerId[128]; + /** 0x23e: Application identifier (a-characters). + * Same file reference alternative as previous field. */ + char achApplicationId[128]; + /** 0x2be: Copyright (root) file identifier (d-characters). + * All spaces if none. */ + char achCopyrightFileId[37]; + /** 0x2e3: Abstract (root) file identifier (d-characters). + * All spaces if none. */ + char achAbstractFileId[37]; + /** 0x308: Bibliographic file identifier (d-characters). + * All spaces if none. */ + char achBibliographicFileId[37]; + /** 0x32d: Volume creation date and time. */ + ISO9660TIMESTAMP BirthTime; + /** 0x33e: Volume modification date and time. */ + ISO9660TIMESTAMP ModifyTime; + /** 0x34f: Volume (data) expiration date and time. + * If not specified, don't regard data as obsolete. */ + ISO9660TIMESTAMP ExpireTime; + /** 0x360: Volume (data) effective date and time. + * If not specified, info can be used immediately. */ + ISO9660TIMESTAMP EffectiveTime; + /** 0x371: File structure version (ISO9660_FILE_STRUCTURE_VERSION). */ + uint8_t bFileStructureVersion; + /** 0x372: Reserve for future, MBZ. */ + uint8_t bReserved883; + /** 0x373: Reserve for future. + * mkisofs & genisoimage & libisofs seems to space pad this most of the time. + * Microsoft image (2.56) zero pads it. isomd5sum uses it to store checksum + * info for the iso and space pads it. */ + uint8_t abAppUse[512]; + /** 0x573: Reserved for future standardization, MBZ. */ + uint8_t abReserved1396[653]; +} ISO9660PRIMARYVOLDESC; +AssertCompileSize(ISO9660PRIMARYVOLDESC, ISO9660_SECTOR_SIZE); +/** Pointer to a ISO 9660 primary volume descriptor. */ +typedef ISO9660PRIMARYVOLDESC *PISO9660PRIMARYVOLDESC; +/** Pointer to a const ISO 9660 primary volume descriptor. */ +typedef ISO9660PRIMARYVOLDESC const *PCISO9660PRIMARYVOLDESC; + +/** The value of ISO9660PRIMARYVOLDESC::Hdr.uDescVersion. */ +#define ISO9660PRIMARYVOLDESC_VERSION UINT8_C(1) +/** The value of ISO9660PRIMARYVOLDESC::bFileStructureVersion and + * ISO9660SUPVOLDESC::bFileStructureVersion. */ +#define ISO9660_FILE_STRUCTURE_VERSION UINT8_C(1) + + + +/** + * ISO 9660 supplementary volume descriptor. + * + * This is in the large parts identicial to the primary descriptor, except it + * have a few more fields where the primary one has reserved spaces. + */ +typedef struct ISO9660SUPVOLDESC +{ + /** 0x000: The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_SUPPLEMENTARY and version + * ISO9660SUPVOLDESC_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** 0x007: Volume flags (ISO9660SUPVOLDESC_VOL_F_XXX). + * @note This is reserved in the primary volume descriptor. */ + uint8_t fVolumeFlags; + /** 0x008: System identifier (a1-characters) of system that can act upon + * sectors 0 thru 15. + * @note Purpose differs from primary description. */ + char achSystemId[32]; + /** 0x028: Volume identifier (d1-characters). + * @note Character set differs from primary description. */ + char achVolumeId[32]; + /** 0x048: Unused field, zero filled. */ + ISO9660U32 Unused73; + /** 0x050: Volume space size in logical blocks (cbLogicalBlock). */ + ISO9660U32 VolumeSpaceSize; + /** 0x058: Escape sequences. + * Complicated stuff, see ISO 2022 and ECMA-35. + * @note This is reserved in the primary volume descriptor. */ + uint8_t abEscapeSequences[32]; + /** 0x078: The number of volumes in the volume set. */ + ISO9660U16 cVolumesInSet; + /** 0x07c: Volume sequence number. */ + ISO9660U16 VolumeSeqNo; + /** 0x080: Logical block size in bytes. */ + ISO9660U16 cbLogicalBlock; + /** 0x084: Path table size. */ + ISO9660U32 cbPathTable; + /** 0x08c: Type L(ittle endian) path table location (block offset). */ + ISO9660U32LE offTypeLPathTable; + /** 0x090: Optional type L(ittle endian) path table location (block offset). */ + ISO9660U32LE offOptionalTypeLPathTable; + /** 0x094: Type M (big endian) path table location (block offset). */ + ISO9660U32BE offTypeMPathTable; + /** 0x098: Optional type M (big endian) path table location (block offset). */ + ISO9660U32BE offOptionalTypeMPathTable; + /** 0x09c: Directory entry for the root directory (union). */ + union + { + uint8_t ab[34]; + ISO9660DIRREC DirRec; + } RootDir; + /** 0x0be: Volume set identifier (d1-characters). + * @note Character set differs from primary description. */ + char achVolumeSetId[128]; + /** 0x13e: Publisher identifier (a1-characters). Alternatively, it may refere + * to a file in the root dir if it starts with 0x5f and restricts itself to 8 + * d1-characters. + * @note Character set differs from primary description. */ + char achPublisherId[128]; + /** 0x1be: Data preparer identifier (a1-characters). + * Same file reference alternative as previous field. + * @note Character set differs from primary description. */ + char achDataPreparerId[128]; + /** 0x23e: Application identifier (a1-characters). + * Same file reference alternative as previous field. + * @note Character set differs from primary description. */ + char achApplicationId[128]; + /** 0x2be: Copyright (root) file identifier (d1-characters). + * All spaces if none. + * @note Character set differs from primary description. */ + char achCopyrightFileId[37]; + /** 0x2e3: Abstract (root) file identifier (d1-characters). + * All spaces if none. + * @note Character set differs from primary description. */ + char achAbstractFileId[37]; + /** 0x308: Bibliographic file identifier (d1-characters). + * All spaces if none. + * @note Character set differs from primary description. */ + char achBibliographicFileId[37]; + /** 0x32d: Volume creation date and time. */ + ISO9660TIMESTAMP BirthTime; + /** 0x33e: Volume modification date and time. */ + ISO9660TIMESTAMP ModifyTime; + /** 0x34f: Volume (data) expiration date and time. + * If not specified, don't regard data as obsolete. */ + ISO9660TIMESTAMP ExpireTime; + /** 0x360: Volume (data) effective date and time. + * If not specified, info can be used immediately. */ + ISO9660TIMESTAMP EffectiveTime; + /** 0x371: File structure version (ISO9660_FILE_STRUCTURE_VERSION). */ + uint8_t bFileStructureVersion; + /** 0x372: Reserve for future, MBZ. */ + uint8_t bReserved883; + /** 0x373: Reserve for future, MBZ. */ + uint8_t abAppUse[512]; + /** 0x573: Reserved for future standardization, MBZ. */ + uint8_t abReserved1396[653]; +} ISO9660SUPVOLDESC; +AssertCompileSize(ISO9660SUPVOLDESC, ISO9660_SECTOR_SIZE); +/** Pointer to a ISO 9660 supplementary volume descriptor. */ +typedef ISO9660SUPVOLDESC *PISO9660SUPVOLDESC; +/** Pointer to a const ISO 9660 supplementary volume descriptor. */ +typedef ISO9660SUPVOLDESC const *PCISO9660SUPVOLDESC; +/** The value of ISO9660SUPVOLDESC::Hdr.uDescVersion. */ +#define ISO9660SUPVOLDESC_VERSION UINT8_C(1) + +/** @name ISO9660SUPVOLDESC_VOL_F_XXX - ISO9660SUPVOLDESC::fVolumeFlags + * @{ */ +#define ISO9660SUPVOLDESC_VOL_F_ESC_ONLY_REG UINT8_C(0x00) +#define ISO9660SUPVOLDESC_VOL_F_ESC_NOT_REG UINT8_C(0x01) +/** @} */ + + + +/** + * ISO 9660 volume partition descriptor. + */ +typedef struct ISO9660VOLPARTDESC +{ + /** 0x000: The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_PARTITION and version + * ISO9660VOLPARTDESC_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** 0x007: Alignment padding. */ + uint8_t bPadding8; + /** 0x008: System identifier (a-characters). */ + char achSystemId[32]; + /** 0x028: Volume partition identifier (d-characters). */ + char achVolumePartitionId[32]; + /** 0x048: The location of the partition (logical block number). */ + ISO9660U32 offVolumePartition; + /** 0x050: The partition size in logical blocks (cbLogicalBlock). */ + ISO9660U32 VolumePartitionSize; + /** 0x058: System specific data. */ + uint8_t achSystemUse[1960]; +} ISO9660VOLPARTDESC; +AssertCompileSize(ISO9660VOLPARTDESC, ISO9660_SECTOR_SIZE); +/** Pointer to an ISO 9660 volume partition description. */ +typedef ISO9660VOLPARTDESC *PISO9660VOLPARTDESC; +/** Pointer to a const ISO 9660 volume partition description. */ +typedef ISO9660VOLPARTDESC const *PCISO9660VOLPARTDESC; +/** The value of ISO9660VOLPARTDESC::Hdr.uDescVersion. */ +#define ISO9660VOLPARTDESC_VERSION UINT8_C(1) + + + +/** @name Joliet escape sequence identifiers. + * + * These bytes appears in the supplementary volume descriptor field + * abEscapeSequences. The ISO9660SUPVOLDESC_VOL_F_ESC_NOT_REG flags will not + * be set. + * + * @{ */ +#define ISO9660_JOLIET_ESC_SEQ_0 UINT8_C(0x25) /**< First escape sequence byte.*/ +#define ISO9660_JOLIET_ESC_SEQ_1 UINT8_C(0x2f) /**< Second escape sequence byte.*/ +#define ISO9660_JOLIET_ESC_SEQ_2_LEVEL_1 UINT8_C(0x40) /**< Third escape sequence byte: level 1 */ +#define ISO9660_JOLIET_ESC_SEQ_2_LEVEL_2 UINT8_C(0x43) /**< Third escape sequence byte: level 2 */ +#define ISO9660_JOLIET_ESC_SEQ_2_LEVEL_3 UINT8_C(0x45) /**< Third escape sequence byte: level 3 */ +/** @} */ + + +/** The size of an El Torito boot catalog entry. */ +#define ISO9660_ELTORITO_ENTRY_SIZE UINT32_C(0x20) + +/** + * El Torito boot catalog: Validation entry. + * + * This is the first entry in the boot catalog. It is followed by a + * ISO9660ELTORITODEFAULTENTRY, which in turn is followed by a + * ISO9660ELTORITOSECTIONHEADER. + */ +typedef struct ISO9660ELTORITOVALIDATIONENTRY +{ + /** 0x00: The header ID (ISO9660_ELTORITO_HEADER_ID_VALIDATION_ENTRY). */ + uint8_t bHeaderId; + /** 0x01: The platform ID (ISO9660_ELTORITO_PLATFORM_ID_XXX). */ + uint8_t bPlatformId; + /** 0x02: Reserved, MBZ. */ + uint16_t u16Reserved; + /** 0x04: String ID of the developer of the CD/DVD-ROM. */ + char achId[24]; + /** 0x1c: The checksum. */ + uint16_t u16Checksum; + /** 0x1e: Key byte 1 (ISO9660_ELTORITO_KEY_BYTE_1). */ + uint8_t bKey1; + /** 0x1f: Key byte 2 (ISO9660_ELTORITO_KEY_BYTE_2). */ + uint8_t bKey2; +} ISO9660ELTORITOVALIDATIONENTRY; +AssertCompileSize(ISO9660ELTORITOVALIDATIONENTRY, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito validation entry. */ +typedef ISO9660ELTORITOVALIDATIONENTRY *PISO9660ELTORITOVALIDATIONENTRY; +/** Pointer to a const El Torito validation entry. */ +typedef ISO9660ELTORITOVALIDATIONENTRY const *PCISO9660ELTORITOVALIDATIONENTRY; + +/** ISO9660ELTORITOVALIDATIONENTRY::bKey1 value. */ +#define ISO9660_ELTORITO_KEY_BYTE_1 UINT8_C(0x55) +/** ISO9660ELTORITOVALIDATIONENTRY::bKey2 value. */ +#define ISO9660_ELTORITO_KEY_BYTE_2 UINT8_C(0xaa) + + +/** @name ISO9660_ELTORITO_HEADER_ID_XXX - header IDs. + * @{ */ +/** Header ID for a ISO9660ELTORITOVALIDATIONENTRY. */ +#define ISO9660_ELTORITO_HEADER_ID_VALIDATION_ENTRY UINT8_C(0x01) +/** Header ID for a ISO9660ELTORITOSECTIONHEADER. */ +#define ISO9660_ELTORITO_HEADER_ID_SECTION_HEADER UINT8_C(0x90) +/** Header ID for the final ISO9660ELTORITOSECTIONHEADER. */ +#define ISO9660_ELTORITO_HEADER_ID_FINAL_SECTION_HEADER UINT8_C(0x91) +/** @} */ + + +/** @name ISO9660_ELTORITO_PLATFORM_ID_XXX - El Torito Platform IDs + * @{ */ +#define ISO9660_ELTORITO_PLATFORM_ID_X86 UINT8_C(0x00) /**< 80x86 */ +#define ISO9660_ELTORITO_PLATFORM_ID_PPC UINT8_C(0x01) /**< PowerPC */ +#define ISO9660_ELTORITO_PLATFORM_ID_MAC UINT8_C(0x02) /**< Mac */ +#define ISO9660_ELTORITO_PLATFORM_ID_EFI UINT8_C(0xef) /**< UEFI */ +/** @} */ + + +/** + * El Torito boot catalog: Section header entry. + * + * A non-final section header entry is followed by + * ISO9660ELTORITOSECTIONHEADER::cEntries ISO9660ELTORITOSECTIONTENTRY instances. + */ +typedef struct ISO9660ELTORITOSECTIONHEADER +{ + /** 0x00: Header ID - ISO9660_ELTORITO_HEADER_ID_SECTION_HEADER or + * ISO9660_ELTORITO_HEADER_ID_FINAL_SECTION_HEADER (if final). */ + uint8_t bHeaderId; + /** 0x01: The platform ID (ISO9660_ELTORITO_PLATFORM_ID_XXX). */ + uint8_t bPlatformId; + /** 0x02: Number of entries in this section (i.e. following this header). */ + uint16_t cEntries; + /** 0x04: String ID for the section. */ + char achSectionId[28]; +} ISO9660ELTORITOSECTIONHEADER; +AssertCompileSize(ISO9660ELTORITOSECTIONHEADER, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito section header entry. */ +typedef ISO9660ELTORITOSECTIONHEADER *PISO9660ELTORITOSECTIONHEADER; +/** Pointer to a const El Torito section header entry. */ +typedef ISO9660ELTORITOSECTIONHEADER const *PCISO9660ELTORITOSECTIONHEADER; + + +/** + * El Torito boot catalog: Default (initial) entry. + * + * Followed by ISO9660ELTORITOSECTIONHEADER. + * + * Differs from ISO9660ELTORITOSECTIONENTRY in that it doesn't have a + * selection criteria and no media flags (only type). + */ +typedef struct ISO9660ELTORITODEFAULTENTRY +{ + /** 0x00: Boot indicator (ISO9660_ELTORITO_BOOT_INDICATOR_XXX). */ + uint8_t bBootIndicator; + /** 0x01: Boot media type. The first four bits are defined by + * ISO9660_ELTORITO_BOOT_MEDIA_TYPE_XXX, whereas the top four bits MBZ. */ + uint8_t bBootMediaType; + /** 0x02: Load segment - load address divided by 0x10. */ + uint16_t uLoadSeg; + /** 0x04: System type from image partition table. */ + uint8_t bSystemType; + /** 0x05: Unused, MBZ. */ + uint8_t bUnused; + /** 0x06: Number of emulated 512 byte sectors to load. */ + uint16_t cEmulatedSectorsToLoad; + /** 0x08: Image location in the ISO (block offset), always (?) little endian. */ + uint32_t offBootImage; + /** 0x0c: Reserved, MBZ */ + uint8_t abReserved[20]; +} ISO9660ELTORITODEFAULTENTRY; +AssertCompileSize(ISO9660ELTORITODEFAULTENTRY, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito default (initial) entry. */ +typedef ISO9660ELTORITODEFAULTENTRY *PISO9660ELTORITODEFAULTENTRY; +/** Pointer to a const El Torito default (initial) entry. */ +typedef ISO9660ELTORITODEFAULTENTRY const *PCISO9660ELTORITODEFAULTENTRY; + + +/** + * El Torito boot catalg: Section entry. + */ +typedef struct ISO9660ELTORITOSECTIONENTRY +{ + /** 0x00: Boot indicator (ISO9660_ELTORITO_BOOT_INDICATOR_XXX). */ + uint8_t bBootIndicator; + /** 0x01: Boot media type and flags. The first four bits are defined by + * ISO9660_ELTORITO_BOOT_MEDIA_TYPE_XXX and the top four bits by + * ISO9660_ELTORITO_BOOT_MEDIA_F_XXX. */ + uint8_t bBootMediaType; + /** 0x02: Load segment - load address divided by 0x10. */ + uint16_t uLoadSeg; + /** 0x04: System type from image partition table. */ + uint8_t bSystemType; + /** 0x05: Unused, MBZ. */ + uint8_t bUnused; + /** 0x06: Number of emulated 512 byte sectors to load. */ + uint16_t cEmulatedSectorsToLoad; + /** 0x08: Image location in the ISO (block offset), always (?) little endian. */ + uint32_t offBootImage; + /** 0x0c: Selection criteria type (ISO9660_ELTORITO_SEL_CRIT_TYPE_XXX). */ + uint8_t bSelectionCriteriaType; + /** 0x0c: Selection criteria specific data. */ + uint8_t abSelectionCriteria[19]; +} ISO9660ELTORITOSECTIONENTRY; +AssertCompileSize(ISO9660ELTORITOSECTIONENTRY, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito default (initial) entry. */ +typedef ISO9660ELTORITOSECTIONENTRY *PISO9660ELTORITOSECTIONENTRY; +/** Pointer to a const El Torito default (initial) entry. */ +typedef ISO9660ELTORITOSECTIONENTRY const *PCISO9660ELTORITOSECTIONENTRY; + + +/** @name ISO9660_ELTORITO_BOOT_INDICATOR_XXX - Boot indicators. + * @{ */ +#define ISO9660_ELTORITO_BOOT_INDICATOR_BOOTABLE UINT8_C(0x88) +#define ISO9660_ELTORITO_BOOT_INDICATOR_NOT_BOOTABLE UINT8_C(0x00) +/** @} */ + +/** @name ISO9660_ELTORITO_BOOT_MEDIA_TYPE_XXX - Boot media types. + * @{ */ +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_NO_EMULATION UINT8_C(0x0) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_FLOPPY_1_2_MB UINT8_C(0x1) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_FLOPPY_1_44_MB UINT8_C(0x2) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_FLOPPY_2_88_MB UINT8_C(0x3) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_HARD_DISK UINT8_C(0x4) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_MASK UINT8_C(0xf) /**< The media type mask. */ +/** @} */ + +/** @name ISO9660_ELTORITO_BOOT_MEDIA_F_XXX - Boot media flags. + * These only applies to the section entry, not to the default (initial) entry. + * @{ */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_RESERVED UINT8_C(0x10) /**< Reserved bit, MBZ. */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_CONTINUATION UINT8_C(0x20) /**< Contiunation entry follows. */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_ATAPI_DRIVER UINT8_C(0x40) /**< Image contains an ATAPI driver. */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_SCSI_DRIVERS UINT8_C(0x80) /**< Image contains SCSI drivers. */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_MASK UINT8_C(0xf0) /**< The media/entry flag mask. */ +/** @} */ + +/** @name ISO9660_ELTORITO_SEL_CRIT_TYPE_XXX - Selection criteria type. + * @{ */ +#define ISO9660_ELTORITO_SEL_CRIT_TYPE_NONE UINT8_C(0x00) /**< No selection criteria */ +#define ISO9660_ELTORITO_SEL_CRIT_TYPE_LANG_AND_VERSION UINT8_C(0x01) /**< Language and version (IBM). */ +/** @} */ + + +/** + * El Torito boot catalog: Section entry extension. + * + * This is used for carrying additional selection criteria data. It follows + * a ISO9660ELTORITOSECTIONENTRY. + */ +typedef struct ISO9660ELTORITOSECTIONENTRYEXT +{ + /** 0x00: Extension indicator (ISO9660_ELTORITO_SECTION_ENTRY_EXT_ID). */ + uint8_t bExtensionId; + /** 0x01: Selection criteria extension flags (ISO9660_ELTORITO_SECTION_ENTRY_EXT_F_XXX). */ + uint8_t fFlags; + /** 0x02: Selection critiera data. */ + uint8_t abSelectionCriteria[30]; +} ISO9660ELTORITOSECTIONENTRYEXT; +AssertCompileSize(ISO9660ELTORITOSECTIONENTRYEXT, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito default (initial) entry. */ +typedef ISO9660ELTORITOSECTIONENTRYEXT *PISO9660ELTORITOSECTIONENTRYEXT; +/** Pointer to a const El Torito default (initial) entry. */ +typedef ISO9660ELTORITOSECTIONENTRYEXT const *PCISO9660ELTORITOSECTIONENTRYEXT; + +/** Value of ISO9660ELTORITOSECTIONENTRYEXT::bExtensionId. */ +#define ISO9660_ELTORITO_SECTION_ENTRY_EXT_ID UINT8_C(0x44) + +/** @name ISO9660_ELTORITO_SECTION_ENTRY_EXT_F_XXX - ISO9660ELTORITOSECTIONENTRYEXT::fFlags + * @{ */ +#define ISO9660_ELTORITO_SECTION_ENTRY_EXT_F_MORE UINT8_C(0x20) /**< Further extension entries follows. */ +#define ISO9660_ELTORITO_SECTION_ENTRY_EXT_F_UNUSED_MASK UINT8_C(0xef) /**< Mask of all unused bits. */ +/** @} */ + + +/** + * Boot information table used by isolinux and GRUB2 El Torito boot files. + */ +typedef struct ISO9660SYSLINUXINFOTABLE +{ + /** 0x00/0x08: Offset of the primary volume descriptor (block offset). */ + uint32_t offPrimaryVolDesc; + /** 0x04/0x0c: Offset of the boot file (block offset). */ + uint32_t offBootFile; + /** 0x08/0x10: Size of the boot file in bytes. */ + uint32_t cbBootFile; + /** 0x0c/0x14: Boot file checksum. + * This is the sum of all the 32-bit words in the image, start at the end of + * this structure (i.e. offset 64). */ + uint32_t uChecksum; + /** 0x10/0x18: Reserved for future fun. */ + uint32_t auReserved[10]; +} ISO9660SYSLINUXINFOTABLE; +AssertCompileSize(ISO9660SYSLINUXINFOTABLE, 56); +/** Pointer to a syslinux boot information table. */ +typedef ISO9660SYSLINUXINFOTABLE *PISO9660SYSLINUXINFOTABLE; +/** Pointer to a const syslinux boot information table. */ +typedef ISO9660SYSLINUXINFOTABLE const *PCISO9660SYSLINUXINFOTABLE; + +/** The file offset of the isolinux boot info table. */ +#define ISO9660SYSLINUXINFOTABLE_OFFSET 8 + + + +/** + * System Use Sharing Protocol Protocol (SUSP) header. + */ +typedef struct ISO9660SUSPHDR +{ + /** Signature byte 1. */ + uint8_t bSig1; + /** Signature byte 2. */ + uint8_t bSig2; + /** Length of the entry (including the header). */ + uint8_t cbEntry; + /** Entry version number. */ + uint8_t bVersion; +} ISO9660SUSPHDR; +AssertCompileSize(ISO9660SUSPHDR, 4); +/** Pointer to a SUSP header. */ +typedef ISO9660SUSPHDR *PISO9660SUSPHDR; +/** Pointer to a const SUSP header. */ +typedef ISO9660SUSPHDR const *PCISO9660SUSPHDR; + + +/** + * SUSP continuation entry (CE). + */ +typedef struct ISO9660SUSPCE +{ + /** Header (ISO9660SUSPCE_SIG1, ISO9660SUSPCE_SIG2, ISO9660SUSPCE_VER). */ + ISO9660SUSPHDR Hdr; + /** The offset of the continutation data block (block offset). */ + ISO9660U32 offBlock; + /** The byte offset in the block of the contiuation data. */ + ISO9660U32 offData; + /** The size of the continuation data. */ + ISO9660U32 cbData; +} ISO9660SUSPCE; +/** Pointer to a SUSP continuation entry. */ +typedef ISO9660SUSPCE *PISO9660SUSPCE; +/** Pointer to a const SUSP continuation entry. */ +typedef ISO9660SUSPCE const *PCISO9660SUSPCE; +#define ISO9660SUSPCE_SIG1 'C' /**< SUSP continutation entry signature byte 1. */ +#define ISO9660SUSPCE_SIG2 'E' /**< SUSP continutation entry signature byte 2. */ +#define ISO9660SUSPCE_LEN 28 /**< SUSP continutation entry length. */ +#define ISO9660SUSPCE_VER 1 /**< SUSP continutation entry version number. */ +AssertCompileSize(ISO9660SUSPCE, ISO9660SUSPCE_LEN); + + +/** + * SUSP padding entry (PD). + */ +typedef struct ISO9660SUSPPD +{ + /** Header (ISO9660SUSPPD_SIG1, ISO9660SUSPPD_SIG2, ISO9660SUSPPD_VER). */ + ISO9660SUSPHDR Hdr; + /* Padding follows. */ +} ISO9660SUSPPD; +AssertCompileSize(ISO9660SUSPPD, 4); +/** Pointer to a SUSP padding entry. */ +typedef ISO9660SUSPPD *PISO9660SUSPPD; +/** Pointer to a const SUSP padding entry. */ +typedef ISO9660SUSPPD const *PCISO9660SUSPPD; +#define ISO9660SUSPPD_SIG1 'P' /**< SUSP padding entry signature byte 1. */ +#define ISO9660SUSPPD_SIG2 'D' /**< SUSP padding entry signature byte 2. */ +#define ISO9660SUSPPD_VER 1 /**< SUSP padding entry version number. */ + + +/** + * SUSP system use protocol entry (SP) + * + * This is only used in the '.' record of the root directory. + */ +typedef struct ISO9660SUSPSP +{ + /** Header (ISO9660SUSPSP_SIG1, ISO9660SUSPSP_SIG2, + * ISO9660SUSPSP_LEN, ISO9660SUSPSP_VER). */ + ISO9660SUSPHDR Hdr; + /** Check byte 1 (ISO9660SUSPSP_CHECK1). */ + uint8_t bCheck1; + /** Check byte 2 (ISO9660SUSPSP_CHECK2). */ + uint8_t bCheck2; + /** Number of bytes to skip within the system use field of each directory + * entry (except the '.' entry of the root, since that's where this is). */ + uint8_t cbSkip; +} ISO9660SUSPSP; +/** Pointer to a SUSP entry. */ +typedef ISO9660SUSPSP *PISO9660SUSPSP; +/** Pointer to a const SUSP entry. */ +typedef ISO9660SUSPSP const *PCISO9660SUSPSP; +#define ISO9660SUSPSP_SIG1 'S' /**< SUSP system use protocol entry signature byte 1. */ +#define ISO9660SUSPSP_SIG2 'P' /**< SUSP system use protocol entry signature byte 2. */ +#define ISO9660SUSPSP_VER 1 /**< SUSP system use protocol entry version number. */ +#define ISO9660SUSPSP_LEN 7 /**< SUSP system use protocol entry length (fixed). */ +#define ISO9660SUSPSP_CHECK1 UINT8_C(0xbe) /**< SUSP system use protocol entry check byte 1. */ +#define ISO9660SUSPSP_CHECK2 UINT8_C(0xef) /**< SUSP system use protocol entry check byte 2. */ +AssertCompileSize(ISO9660SUSPSP, ISO9660SUSPSP_LEN); + + +/** + * SUSP terminator entry (ST) + * + * Used to terminate system use entries. + */ +typedef struct ISO9660SUSPST +{ + /** Header (ISO9660SUSPST_SIG1, ISO9660SUSPST_SIG2, + * ISO9660SUSPST_LEN, ISO9660SUSPST_VER). */ + ISO9660SUSPHDR Hdr; +} ISO9660SUSPST; +/** Pointer to a SUSP padding entry. */ +typedef ISO9660SUSPST *PISO9660SUSPST; +/** Pointer to a const SUSP padding entry. */ +typedef ISO9660SUSPST const *PCISO9660SUSPST; +#define ISO9660SUSPST_SIG1 'S' /**< SUSP system use protocol entry signature byte 1. */ +#define ISO9660SUSPST_SIG2 'T' /**< SUSP system use protocol entry signature byte 2. */ +#define ISO9660SUSPST_VER 1 /**< SUSP system use protocol entry version number. */ +#define ISO9660SUSPST_LEN 4 /**< SUSP system use protocol entry length (fixed). */ +AssertCompileSize(ISO9660SUSPST, ISO9660SUSPST_LEN); + + +/** + * SUSP extension record entry (ER) + * + * This is only used in the '.' record of the root directory. There can be multiple of these. + */ +typedef struct ISO9660SUSPER +{ + /** Header (ISO9660SUSPER_SIG1, ISO9660SUSPER_SIG2, ISO9660SUSPER_VER). */ + ISO9660SUSPHDR Hdr; + /** The length of the identifier component. */ + uint8_t cchIdentifier; + /** The length of the description component. */ + uint8_t cchDescription; + /** The length of the source component. */ + uint8_t cchSource; + /** The extension version number. */ + uint8_t bVersion; + /** The payload: first @a cchIdentifier chars of identifier string, second + * @a cchDescription chars of description string, thrid @a cchSource chars + * of source string. Variable length. */ + char achPayload[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} ISO9660SUSPER; +/** Pointer to a SUSP padding entry. */ +typedef ISO9660SUSPER *PISO9660SUSPER; +/** Pointer to a const SUSP padding entry. */ +typedef ISO9660SUSPER const *PCISO9660SUSPER; +#define ISO9660SUSPER_SIG1 'E' /**< SUSP extension record entry signature byte 1. */ +#define ISO9660SUSPER_SIG2 'R' /**< SUSP extension record entry signature byte 2. */ +#define ISO9660SUSPER_VER 1 /**< SUSP extension record entry version number. */ +#define ISO9660SUSPER_OFF_PAYLOAD 8 /**< SUSP extension record entry payload member offset. */ +AssertCompileMemberOffset(ISO9660SUSPER, achPayload, ISO9660SUSPER_OFF_PAYLOAD); + +/** + * SUSP extension sequence entry (ES) + * + * This is only used in the '.' record of the root directory. + */ +typedef struct ISO9660SUSPES +{ + /** Header (ISO9660SUSPES_SIG1, ISO9660SUSPES_SIG2, ISO9660SUSPES_VER). */ + ISO9660SUSPHDR Hdr; + /** The ER entry sequence number of the extension comming first. */ + uint8_t iFirstExtension; +} ISO9660SUSPES; +/** Pointer to a SUSP padding entry. */ +typedef ISO9660SUSPES *PISO9660SUSPES; +/** Pointer to a const SUSP padding entry. */ +typedef ISO9660SUSPES const *PCISO9660SUSPES; +#define ISO9660SUSPES_SIG1 'E' /**< SUSP extension sequence entry signature byte 1. */ +#define ISO9660SUSPES_SIG2 'S' /**< SUSP extension sequence entry signature byte 2. */ +#define ISO9660SUSPES_VER 1 /**< SUSP extension sequence entry version number. */ +#define ISO9660SUSPES_LEN 5 /**< SUSP extension sequence entry length (fixed). */ +AssertCompileSize(ISO9660SUSPES, ISO9660SUSPES_LEN); + + +/** RRIP ER identifier string from Rock Ridge Interchange Protocol v1.10 specs. */ +#define ISO9660_RRIP_ID "RRIP_1991A" +/** RRIP ER recommended description string (from RRIP v1.10 specs). */ +#define ISO9660_RRIP_DESC "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS" +/** RRIP ER recommended source string (from RRIP v1.10 specs). */ +#define ISO9660_RRIP_SRC "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION." +/** RRIP ER version field value from the Rock Ridge Interchange Protocol v1.10 specs. */ +#define ISO9660_RRIP_VER 1 +/** The length of a RRIP v1.10 ER record. + * The record must be constructed using ISO9660_RRIP_ID, ISO9660_RRIP_DESC + * and ISO9660_RRIP_SRC. */ +#define ISO9660_RRIP_ER_LEN ((uint8_t)( ISO9660SUSPER_OFF_PAYLOAD \ + + sizeof(ISO9660_RRIP_ID) - 1 \ + + sizeof(ISO9660_RRIP_DESC) - 1 \ + + sizeof(ISO9660_RRIP_SRC) - 1 )) + +/** RRIP ER identifier string from RRIP IEEE P1282 v1.12 draft. */ +#define ISO9660_RRIP_1_12_ID "IEEE_P1282" +/** RRIP ER recommended description string (RRIP IEEE P1282 v1.12 draft). */ +#define ISO9660_RRIP_1_12_DESC "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS." +/** RRIP ER recommended source string (RRIP IEEE P1282 v1.12 draft). */ +#define ISO9660_RRIP_1_12_SRC "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION." +/** RRIP ER version field value from the Rock Ridge Interchange Protocol v1.12 specs. */ +#define ISO9660_RRIP_1_12_VER 1 +/** The length of a RRIP v1.12 ER record. + * The record must be constructed using ISO9660_RRIP_1_12_ID, + * ISO9660_RRIP_1_12_DESC and ISO9660_RRIP_1_12_SRC. */ +#define ISO9660_RRIP_1_12_ER_LEN ((uint8_t)( ISO9660SUSPER_OFF_PAYLOAD \ + + sizeof(ISO9660_RRIP_1_12_ID) - 1 \ + + sizeof(ISO9660_RRIP_1_12_DESC) - 1 \ + + sizeof(ISO9660_RRIP_1_12_SRC) - 1 )) + + +/** + * Rock ridge interchange protocol - RR. + */ +typedef struct ISO9660RRIPRR +{ + /** Header (ISO9660RRIPRR_SIG1, ISO9660RRIPRR_SIG2, + * ISO9660RRIPRR_LEN, ISO9660RRIPRR_VER). */ + ISO9660SUSPHDR Hdr; + /** Flags indicating which RRIP entries are present (). */ + uint8_t fFlags; +} ISO9660RRIPRR; +/** Pointer to a RRIP RR entry. */ +typedef ISO9660RRIPRR *PISO9660RRIPRR; +/** Pointer to a const RRIP RR entry. */ +typedef ISO9660RRIPRR const *PCISO9660RRIPRR; +#define ISO9660RRIPRR_SIG1 'R' /**< RRIP RR entry signature byte 1. */ +#define ISO9660RRIPRR_SIG2 'R' /**< RRIP RR entry signature byte 2. */ +#define ISO9660RRIPRR_VER 1 /**< RRIP RR entry version number. */ +#define ISO9660RRIPRR_LEN 5 /**< RRIP RR entry length (fixed). */ +AssertCompileSize(ISO9660RRIPRR, ISO9660RRIPRR_LEN); + +/** @name ISO9660RRIP_RR_F_XXX - Indicates which RRIP entries are present. + * @{ */ +#define ISO9660RRIP_RR_F_PX UINT8_C(0x01) +#define ISO9660RRIP_RR_F_PN UINT8_C(0x02) +#define ISO9660RRIP_RR_F_SL UINT8_C(0x04) +#define ISO9660RRIP_RR_F_NM UINT8_C(0x08) +#define ISO9660RRIP_RR_F_CL UINT8_C(0x10) +#define ISO9660RRIP_RR_F_PL UINT8_C(0x20) +#define ISO9660RRIP_RR_F_RE UINT8_C(0x40) +#define ISO9660RRIP_RR_F_TF UINT8_C(0x80) +/** @} */ + +/** + * Rock ridge interchange protocol - posix attribute entry (PX). + */ +typedef struct ISO9660RRIPPX +{ + /** Header (ISO9660RRIPPX_SIG1, ISO9660RRIPPX_SIG2, + * ISO9660RRIPPX_LEN, ISO9660RRIPPX_VER). */ + ISO9660SUSPHDR Hdr; + /** The file mode (RTFS_UNIX_XXX, RTFS_TYPE_XXX). */ + ISO9660U32 fMode; + /** Number of hardlinks. */ + ISO9660U32 cHardlinks; + /** User ID. */ + ISO9660U32 uid; + /** Group ID. */ + ISO9660U32 gid; + /** Inode number. */ + ISO9660U32 INode; +} ISO9660RRIPPX; +/** Pointer to a RRIP posix attribute entry. */ +typedef ISO9660RRIPPX *PISO9660RRIPPX; +/** Pointer to a const RRIP posix attribute entry. */ +typedef ISO9660RRIPPX const *PCISO9660RRIPPX; +#define ISO9660RRIPPX_SIG1 'P' /**< RRIP posix attribute entry signature byte 1. */ +#define ISO9660RRIPPX_SIG2 'X' /**< RRIP posix attribute entry signature byte 2. */ +#define ISO9660RRIPPX_VER 1 /**< RRIP posix attribute entry version number. */ +#define ISO9660RRIPPX_LEN 44 /**< RRIP posix attribute entry length (fixed). */ +AssertCompileSize(ISO9660RRIPPX, ISO9660RRIPPX_LEN); +#define ISO9660RRIPPX_LEN_NO_INODE 36 /**< RRIP posix attribute entry length without inode (fixed). */ + + +/** + * Rock ridge interchange protocol - timestamp entry (TF). + */ +typedef struct ISO9660RRIPTF +{ + /** Header (ISO9660RRIPTF_SIG1, ISO9660RRIPTF_SIG2, ISO9660RRIPTF_VER). */ + ISO9660SUSPHDR Hdr; + /** Flags, ISO9660RRIPTF_F_XXX. */ + uint8_t fFlags; + /** Timestamp payload bytes (variable size and format). */ + uint8_t abPayload[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} ISO9660RRIPTF; +AssertCompileMemberOffset(ISO9660RRIPTF, abPayload, 5); +/** Pointer to a RRIP timestamp entry. */ +typedef ISO9660RRIPTF *PISO9660RRIPTF; +/** Pointer to a const RRIP timestamp entry. */ +typedef ISO9660RRIPTF const *PCISO9660RRIPTF; +#define ISO9660RRIPTF_SIG1 'T' /**< RRIP child link entry signature byte 1. */ +#define ISO9660RRIPTF_SIG2 'F' /**< RRIP child link entry signature byte 2. */ +#define ISO9660RRIPTF_VER 1 /**< RRIP child link entry version number. */ + +/** @name ISO9660RRIPTF_F_XXX - Timestmap flags. + * @{ */ +#define ISO9660RRIPTF_F_BIRTH UINT8_C(0x01) /**< Birth (creation) timestamp is recorded. */ +#define ISO9660RRIPTF_F_MODIFY UINT8_C(0x02) /**< Modification timestamp is recorded. */ +#define ISO9660RRIPTF_F_ACCESS UINT8_C(0x04) /**< Accessed timestamp is recorded. */ +#define ISO9660RRIPTF_F_CHANGE UINT8_C(0x08) /**< Attribute change timestamp is recorded. */ +#define ISO9660RRIPTF_F_BACKUP UINT8_C(0x10) /**< Backup timestamp is recorded. */ +#define ISO9660RRIPTF_F_EXPIRATION UINT8_C(0x20) /**< Expiration timestamp is recorded. */ +#define ISO9660RRIPTF_F_EFFECTIVE UINT8_C(0x40) /**< Effective timestamp is recorded. */ +#define ISO9660RRIPTF_F_LONG_FORM UINT8_C(0x80) /**< If set ISO9660TIMESTAMP is used, otherwise ISO9660RECTIMESTAMP. */ +/** @} */ + +/** + * Calculates the length of a 'TF' entry given the flags. + * + * @returns Length in bytes. + * @param fFlags The flags (ISO9660RRIPTF_F_XXX). + */ +DECLINLINE(uint8_t) Iso9660RripTfCalcLength(uint8_t fFlags) +{ + unsigned cTimestamps = ((fFlags & ISO9660RRIPTF_F_BIRTH) != 0) + + ((fFlags & ISO9660RRIPTF_F_MODIFY) != 0) + + ((fFlags & ISO9660RRIPTF_F_ACCESS) != 0) + + ((fFlags & ISO9660RRIPTF_F_CHANGE) != 0) + + ((fFlags & ISO9660RRIPTF_F_BACKUP) != 0) + + ((fFlags & ISO9660RRIPTF_F_EXPIRATION) != 0) + + ((fFlags & ISO9660RRIPTF_F_EFFECTIVE) != 0); + return (uint8_t)( cTimestamps * (fFlags & ISO9660RRIPTF_F_LONG_FORM ? sizeof(ISO9660TIMESTAMP) : sizeof(ISO9660RECTIMESTAMP)) + + RT_OFFSETOF(ISO9660RRIPTF, abPayload)); +} + + +/** + * Rock ridge interchange protocol - posix device number entry (PN). + * + * Mandatory for block or character devices. + */ +typedef struct ISO9660RRIPPN +{ + /** Header (ISO9660RRIPPN_SIG1, ISO9660RRIPPN_SIG2, + * ISO9660RRIPPN_LEN, ISO9660RRIPPN_VER). */ + ISO9660SUSPHDR Hdr; + /** The major device number. */ + ISO9660U32 Major; + /** The minor device number. */ + ISO9660U32 Minor; +} ISO9660RRIPPN; +/** Pointer to a RRIP posix attribute entry. */ +typedef ISO9660RRIPPN *PISO9660RRIPPN; +/** Pointer to a const RRIP posix attribute entry. */ +typedef ISO9660RRIPPN const *PCISO9660RRIPPN; +#define ISO9660RRIPPN_SIG1 'P' /**< RRIP posix device number entry signature byte 1. */ +#define ISO9660RRIPPN_SIG2 'N' /**< RRIP posix device number entry signature byte 2. */ +#define ISO9660RRIPPN_VER 1 /**< RRIP posix device number entry version number. */ +#define ISO9660RRIPPN_LEN 20 /**< RRIP posix device number entry length (fixed). */ +AssertCompileSize(ISO9660RRIPPN, ISO9660RRIPPN_LEN); + +/** + * Rock ridge interchange protocol - symlink entry (SL). + * + * Mandatory for symbolic links. + */ +typedef struct ISO9660RRIPSL +{ + /** Header (ISO9660RRIPSL_SIG1, ISO9660RRIPSL_SIG2, ISO9660RRIPSL_VER). */ + ISO9660SUSPHDR Hdr; + /** Flags (0 or ISO9660RRIP_SL_F_CONTINUE). */ + uint8_t fFlags; + /** Variable length of components. First byte in each component is a + * combination of ISO9660RRIP_SL_C_XXX flag values. The second byte the + * length of character data following it. */ + uint8_t abComponents[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} ISO9660RRIPSL; +AssertCompileMemberOffset(ISO9660RRIPSL, abComponents, 5); +/** Pointer to a RRIP symbolic link entry. */ +typedef ISO9660RRIPSL *PISO9660RRIPSL; +/** Pointer to a const RRIP symbolic link entry. */ +typedef ISO9660RRIPSL const *PCISO9660RRIPSL; +#define ISO9660RRIPSL_SIG1 'S' /**< RRIP symbolic link entry signature byte 1. */ +#define ISO9660RRIPSL_SIG2 'L' /**< RRIP symbolic link entry signature byte 2. */ +#define ISO9660RRIPSL_VER 1 /**< RRIP symbolic link entry version number. */ +/** ISO9660RRIPSL.fFlags - When set another symlink entry follows this one. */ +#define ISO9660RRIP_SL_F_CONTINUE UINT8_C(0x01) +/** @name ISO9660RRIP_SL_C_XXX - Symlink component flags. + * @note These matches ISO9660RRIP_NM_F_XXX. + * @{ */ +/** Indicates that the component continues in the next entry. */ +#define ISO9660RRIP_SL_C_CONTINUE UINT8_C(0x01) +/** Refer to '.' (the current dir). */ +#define ISO9660RRIP_SL_C_CURRENT UINT8_C(0x02) +/** Refer to '..' (the parent dir). */ +#define ISO9660RRIP_SL_C_PARENT UINT8_C(0x04) +/** Refer to '/' (the root dir). */ +#define ISO9660RRIP_SL_C_ROOT UINT8_C(0x08) +/** Reserved / historically was mount point reference. */ +#define ISO9660RRIP_SL_C_MOUNT_POINT UINT8_C(0x10) +/** Reserved / historically was uname network node name. */ +#define ISO9660RRIP_SL_C_UNAME UINT8_C(0x20) +/** Reserved mask (considers historically bits reserved). */ +#define ISO9660RRIP_SL_C_RESERVED_MASK UINT8_C(0xf0) +/** @} */ + + +/** + * Rock ridge interchange protocol - name entry (NM). + */ +typedef struct ISO9660RRIPNM +{ + /** Header (ISO9660RRIPNM_SIG1, ISO9660RRIPNM_SIG2, ISO9660RRIPNM_VER). */ + ISO9660SUSPHDR Hdr; + /** Flags (ISO9660RRIP_NM_F_XXX). */ + uint8_t fFlags; + /** The name part (if any). */ + char achName[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} ISO9660RRIPNM; +AssertCompileMemberOffset(ISO9660RRIPNM, achName, 5); +/** Pointer to a RRIP name entry. */ +typedef ISO9660RRIPNM *PISO9660RRIPNM; +/** Pointer to a const RRIP name entry. */ +typedef ISO9660RRIPNM const *PCISO9660RRIPNM; +#define ISO9660RRIPNM_SIG1 'N' /**< RRIP name entry signature byte 1. */ +#define ISO9660RRIPNM_SIG2 'M' /**< RRIP name entry signature byte 2. */ +#define ISO9660RRIPNM_VER 1 /**< RRIP name entry version number. */ +/** @name ISO9660RRIP_NM_F_XXX - Name flags. + * @note These matches ISO9660RRIP_SL_C_XXX. + * @{ */ +/** Indicates there are more 'NM' entries. */ +#define ISO9660RRIP_NM_F_CONTINUE UINT8_C(0x01) +/** Refer to '.' (the current dir). */ +#define ISO9660RRIP_NM_F_CURRENT UINT8_C(0x02) +/** Refer to '..' (the parent dir). */ +#define ISO9660RRIP_NM_F_PARENT UINT8_C(0x04) +/** Reserved / historically was uname network node name. */ +#define ISO9660RRIP_NM_F_UNAME UINT8_C(0x20) +/** Reserved mask (considers historical bits reserved). */ +#define ISO9660RRIP_NM_F_RESERVED_MASK UINT8_C(0xf8) +/** @} */ + +/** Maximum name length in one 'NM' entry. */ +#define ISO9660RRIPNM_MAX_NAME_LEN 250 + + +/** + * Rock ridge interchange protocol - child link entry (CL). + * + * This is used for relocated directories. Relocated directries are employed + * to bypass the ISO 9660 maximum tree depth of 8. + * + * The size of the directory and everything else is found in the '.' entry in + * the specified location. Only the name (NM or dir rec) and this link record + * should be used. + */ +typedef struct ISO9660RRIPCL +{ + /** Header (ISO9660RRIPCL_SIG1, ISO9660RRIPCL_SIG2, + * ISO9660RRIPCL_LEN, ISO9660RRIPCL_VER). */ + ISO9660SUSPHDR Hdr; + /** The offset of the directory data (block offset). */ + ISO9660U32 offExtend; +} ISO9660RRIPCL; +/** Pointer to a RRIP child link entry. */ +typedef ISO9660RRIPCL *PISO9660RRIPCL; +/** Pointer to a const RRIP child link entry. */ +typedef ISO9660RRIPCL const *PCISO9660RRIPCL; +#define ISO9660RRIPCL_SIG1 'C' /**< RRIP child link entry signature byte 1. */ +#define ISO9660RRIPCL_SIG2 'L' /**< RRIP child link entry signature byte 2. */ +#define ISO9660RRIPCL_VER 1 /**< RRIP child link entry version number. */ +#define ISO9660RRIPCL_LEN 12 /**< RRIP child link entry length. */ +AssertCompileSize(ISO9660RRIPCL, ISO9660RRIPCL_LEN); + + +/** + * Rock ridge interchange protocol - parent link entry (PL). + * + * This is used in relocated directories. Relocated directries are employed + * to bypass the ISO 9660 maximum tree depth of 8. + * + * The size of the directory and everything else is found in the '.' entry in + * the specified location. Only the name (NM or dir rec) and this link record + * should be used. + */ +typedef struct ISO9660RRIPPL +{ + /** Header (ISO9660RRIPPL_SIG1, ISO9660RRIPPL_SIG2, + * ISO9660RRIPPL_LEN, ISO9660RRIPPL_VER). */ + ISO9660SUSPHDR Hdr; + /** The offset of the directory data (block offset). */ + ISO9660U32 offExtend; +} ISO9660RRIPPL; +/** Pointer to a RRIP parent link entry. */ +typedef ISO9660RRIPPL *PISO9660RRIPPL; +/** Pointer to a const RRIP parent link entry. */ +typedef ISO9660RRIPPL const *PCISO9660RRIPPL; +#define ISO9660RRIPPL_SIG1 'P' /**< RRIP parent link entry signature byte 1. */ +#define ISO9660RRIPPL_SIG2 'L' /**< RRIP parent link entry signature byte 2. */ +#define ISO9660RRIPPL_VER 1 /**< RRIP parent link entry version number. */ +#define ISO9660RRIPPL_LEN 12 /**< RRIP parent link entry length. */ +AssertCompileSize(ISO9660RRIPPL, ISO9660RRIPPL_LEN); + + +/** + * Rock ridge interchange protocol - relocated entry (RE). + * + * This is used in the directory record for a relocated directory in the + * holding place high up in the directory hierarchy. The system may choose to + * ignore/hide entries with this entry present. + */ +typedef struct ISO9660RRIPRE +{ + /** Header (ISO9660RRIPRE_SIG1, ISO9660RRIPRE_SIG2, + * ISO9660RRIPRE_LEN, ISO9660RRIPRE_VER). */ + ISO9660SUSPHDR Hdr; +} ISO9660RRIPRE; +/** Pointer to a RRIP parent link entry. */ +typedef ISO9660RRIPRE *PISO9660RRIPRE; +/** Pointer to a const RRIP parent link entry. */ +typedef ISO9660RRIPRE const *PCISO9660RRIPRE; +#define ISO9660RRIPRE_SIG1 'R' /**< RRIP relocated entry signature byte 1. */ +#define ISO9660RRIPRE_SIG2 'E' /**< RRIP relocated entry signature byte 2. */ +#define ISO9660RRIPRE_VER 1 /**< RRIP relocated entry version number. */ +#define ISO9660RRIPRE_LEN 4 /**< RRIP relocated entry length. */ +AssertCompileSize(ISO9660RRIPRE, ISO9660RRIPRE_LEN); + + +/** + * Rock ridge interchange protocol - sparse file entry (SF). + */ +#pragma pack(1) +typedef struct ISO9660RRIPSF +{ + /** Header (ISO9660RRIPSF_SIG1, ISO9660RRIPSF_SIG2, + * ISO9660RRIPSF_LEN, ISO9660RRIPSF_VER). */ + ISO9660SUSPHDR Hdr; + /** The high 32-bits of the 64-bit sparse file size. */ + ISO9660U32 cbSparseHi; + /** The low 32-bits of the 64-bit sparse file size. */ + ISO9660U32 cbSparseLo; + /** The table depth. */ + uint8_t cDepth; +} ISO9660RRIPSF; +#pragma pack() +/** Pointer to a RRIP symbolic link entry. */ +typedef ISO9660RRIPSF *PISO9660RRIPSF; +/** Pointer to a const RRIP symbolic link entry. */ +typedef ISO9660RRIPSF const *PCISO9660RRIPSF; +#define ISO9660RRIPSF_SIG1 'S' /**< RRIP spare file entry signature byte 1. */ +#define ISO9660RRIPSF_SIG2 'F' /**< RRIP spare file entry signature byte 2. */ +#define ISO9660RRIPSF_VER 1 /**< RRIP spare file entry version number. */ +#define ISO9660RRIPSF_LEN 21 /**< RRIP spare file entry length. */ +AssertCompileSize(ISO9660RRIPSF, ISO9660RRIPSF_LEN); + +/** @name ISO9660RRIP_SF_TAB_F_XXX - Sparse table format. + * @{ */ +/** The 24-bit logical block number mask. + * This is somewhat complicated, see docs. MBZ for EMPTY. */ +#define ISO9660RRIP_SF_TAB_F_BLOCK_MASK UINT32_C(0x00ffffff) +/** Reserved bits, MBZ. */ +#define ISO9660RRIP_SF_TAB_F_RESERVED RT_BIT_32() +/** References a sub-table with 256 entries (ISO9660U32). */ +#define ISO9660RRIP_SF_TAB_F_TABLE RT_BIT_32(30) +/** Zero data region. */ +#define ISO9660RRIP_SF_TAB_F_EMPTY RT_BIT_32(31) +/** @} */ + + +/** + * SUSP and RRIP union. + */ +typedef union ISO9660SUSPUNION +{ + ISO9660SUSPHDR Hdr; /**< SUSP header . */ + ISO9660SUSPCE CE; /**< SUSP continuation entry. */ + ISO9660SUSPPD PD; /**< SUSP padding entry. */ + ISO9660SUSPSP SP; /**< SUSP system use protocol entry. */ + ISO9660SUSPST ST; /**< SUSP terminator entry. */ + ISO9660SUSPER ER; /**< SUSP extension record entry. */ + ISO9660SUSPES ES; /**< SUSP extension sequence entry. */ + ISO9660RRIPRR RR; /**< RRIP optimization entry. */ + ISO9660RRIPPX PX; /**< RRIP posix attribute entry. */ + ISO9660RRIPTF TF; /**< RRIP timestamp entry. */ + ISO9660RRIPPN PN; /**< RRIP posix device number entry. */ + ISO9660RRIPSF SF; /**< RRIP sparse file entry. */ + ISO9660RRIPSL SL; /**< RRIP symbolic link entry. */ + ISO9660RRIPNM NM; /**< RRIP name entry. */ + ISO9660RRIPCL CL; /**< RRIP child link entry. */ + ISO9660RRIPPL PL; /**< RRIP parent link entry. */ + ISO9660RRIPRE RE; /**< RRIP relocated entry. */ +} ISO9660SUSPUNION; +/** Pointer to a SUSP and RRIP union. */ +typedef ISO9660SUSPUNION *PISO9660SUSPUNION; +/** Pointer to a const SUSP and RRIP union. */ +typedef ISO9660SUSPUNION *PCISO9660SUSPUNION; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_iso9660_h */ + diff --git a/include/iprt/formats/lx.h b/include/iprt/formats/lx.h new file mode 100644 index 00000000..b01a5ab8 --- /dev/null +++ b/include/iprt/formats/lx.h @@ -0,0 +1,510 @@ +/* $Id: lx.h $ */ +/** @file + * LX structures, types and defines. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef IPRT_INCLUDED_formats_lx_h +#define IPRT_INCLUDED_formats_lx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_formats_lx LX executable format (OS/2) + * @ingroup grp_rt_formats + * @{ */ + +#ifndef IMAGE_OS2_SIGNATURE_LX +/** LX signature ("LX") */ +# define IMAGE_LX_SIGNATURE K_LE2H_U16('L' | ('X' << 8)) +#endif + +/** + * Linear eXecutable header. + * This structure is exactly 196 bytes long. + */ +typedef struct e32_exe +{ + uint8_t e32_magic[2]; + uint8_t e32_border; + uint8_t e32_worder; + uint32_t e32_level; + uint16_t e32_cpu; + uint16_t e32_os; + uint32_t e32_ver; + uint32_t e32_mflags; + uint32_t e32_mpages; + uint32_t e32_startobj; + uint32_t e32_eip; + uint32_t e32_stackobj; + uint32_t e32_esp; + uint32_t e32_pagesize; + uint32_t e32_pageshift; + /** The size of the fixup section. + * The fixup section consists of the fixup page table, the fixup record table, + * the import module table, and the import procedure name table. + */ + uint32_t e32_fixupsize; + uint32_t e32_fixupsum; + /** The size of the resident loader section. + * This includes the object table, the object page map table, the resource table, the resident name table, + * the entry table, the module format directives table, and the page checksum table (?). */ + uint32_t e32_ldrsize; + /** The checksum of the loader section. 0 if not calculated. */ + uint32_t e32_ldrsum; + /** The offset of the object table relative to this structure. */ + uint32_t e32_objtab; + /** Count of objects. */ + uint32_t e32_objcnt; + /** The offset of the object page map table relative to this structure. */ + uint32_t e32_objmap; + /** The offset of the object iterated pages (whatever this is used for) relative to the start of the file. */ + uint32_t e32_itermap; + /** The offset of the resource table relative to this structure. */ + uint32_t e32_rsrctab; + /** The number of entries in the resource table. */ + uint32_t e32_rsrccnt; + /** The offset of the resident name table relative to this structure. */ + uint32_t e32_restab; + /** The offset of the entry (export) table relative to this structure. */ + uint32_t e32_enttab; + /** The offset of the module format directives table relative to this structure. */ + uint32_t e32_dirtab; + /** The number of entries in the module format directives table. */ + uint32_t e32_dircnt; + /** The offset of the fixup page table relative to this structure. */ + uint32_t e32_fpagetab; + /** The offset of the fixup record table relative to this structure. */ + uint32_t e32_frectab; + /** The offset of the import module name table relative to this structure. */ + uint32_t e32_impmod; + /** The number of entries in the import module name table. */ + uint32_t e32_impmodcnt; + /** The offset of the import procedure name table relative to this structure. */ + uint32_t e32_impproc; + /** The offset of the page checksum table relative to this structure. */ + uint32_t e32_pagesum; + /** The offset of the data pages relative to the start of the file. */ + uint32_t e32_datapage; + /** The number of preload pages (ignored). */ + uint32_t e32_preload; + /** The offset of the non-resident name table relative to the start of the file. */ + uint32_t e32_nrestab; + /** The size of the non-resident name table. */ + uint32_t e32_cbnrestab; + uint32_t e32_nressum; + uint32_t e32_autodata; + uint32_t e32_debuginfo; + uint32_t e32_debuglen; + uint32_t e32_instpreload; + uint32_t e32_instdemand; + uint32_t e32_heapsize; + uint32_t e32_stacksize; + uint8_t e32_res3[20]; +} e32_exe; +AssertCompileSize(struct e32_exe, 196); + +/** e32_magic[0] */ +#define E32MAGIC1 'L' +/** e32_magic[1] */ +#define E32MAGIC2 'X' +/** MAKEWORD(e32_magic[0], e32_magic[1]) */ +#define E32MAGIC 0x584c +/** e32_border - little endian */ +#define E32LEBO 0 +/** e32_border - big endian */ +#define E32BEBO 1 +/** e32_worder - little endian */ +#define E32LEWO 0 +/** e32_worder - big endian */ +#define E32BEWO 1 +/** e32_level */ +#define E32LEVEL UINT32_C(0) +/** e32_cpu - 80286 */ +#define E32CPU286 1 +/** e32_cpu - 80386 */ +#define E32CPU386 2 +/** e32_cpu - 80486 */ +#define E32CPU486 3 +/** e32_pagesize */ +#define OBJPAGELEN UINT32_C(0x1000) + + +/** @name e32_mflags + * @{ */ +/** App Type: Fullscreen only. */ +#define E32NOPMW UINT32_C(0x00000100) +/** App Type: PM API. */ +#define E32PMAPI UINT32_C(0x00000300) +/** App Type: PM VIO compatible. */ +#define E32PMW UINT32_C(0x00000200) +/** Application type mask. */ +#define E32APPMASK UINT32_C(0x00000300) +/** Executable module. */ +#define E32MODEXE UINT32_C(0x00000000) +/** Dynamic link library (DLL / library) module. */ +#define E32MODDLL UINT32_C(0x00008000) +/** Protected memory DLL. */ +#define E32PROTDLL UINT32_C(0x00010000) +/** Physical Device Driver. */ +#define E32MODPDEV UINT32_C(0x00020000) +/** Virtual Device Driver. */ +#define E32MODVDEV UINT32_C(0x00028000) +/** Device driver */ +#define E32DEVICE E32MODPDEV +/** Dynamic link library (DLL / library) module. */ +#define E32NOTP E32MODDLL +/** Protected memory DLL. */ +#define E32MODPROTDLL (E32MODDLL | E32PROTDLL) +/** Module Type mask. */ +#define E32MODMASK UINT32_C(0x00038000) +/** Not loadable (linker error). */ +#define E32NOLOAD UINT32_C(0x00002000) +/** No internal fixups. */ +#define E32NOINTFIX UINT32_C(0x00000010) +/** No external fixups (i.e. imports). */ +#define E32NOEXTFIX UINT32_C(0x00000020) +/** System DLL, no internal fixups. */ +#define E32SYSDLL UINT32_C(0x00000008) +/** Global (set) or per instance (cleared) library initialization. */ +#define E32LIBINIT UINT32_C(0x00000004) +/** Global (set) or per instance (cleared) library termination. */ +#define E32LIBTERM UINT32_C(0x40000000) +/** Indicates when set in an executable that the process isn't SMP safe. */ +#define E32NOTMPSAFE UINT32_C(0x00080000) +/** @} */ + + +/** @defgroup grp_rt_formats_lx_relocs Relocations (aka Fixups). + * @{ */ +typedef union r32_offset +{ + uint16_t offset16; + uint32_t offset32; +} r32_offset; +AssertCompileSize(r32_offset, 4); + +/** A relocation. + * @remark this structure isn't very usable since LX relocations comes in too many size variations. + */ +#pragma pack(1) +typedef struct r32_rlc +{ + uint8_t nr_stype; + uint8_t nr_flags; + int16_t r32_soff; + uint16_t r32_objmod; + + union targetid + { + r32_offset intref; + union extfixup + { + r32_offset proc; + uint32_t ord; + } extref; + struct addfixup + { + uint16_t entry; + r32_offset addval; + } addfix; + } r32_target; + uint16_t r32_srccount; + uint16_t r32_chain; +} r32_rlc; +#pragma pack() +AssertCompileSize(r32_rlc, 16); +/** @} */ + +/** @name Some attempt at size constanstants. + * @{ + */ +#define RINTSIZE16 8 +#define RINTSIZE32 10 +#define RORDSIZE 8 +#define RNAMSIZE16 8 +#define RNAMSIZE32 10 +#define RADDSIZE16 10 +#define RADDSIZE32 12 +/** @} */ + +/** @name nr_stype (source flags) + * @{ */ +#define NRSBYT 0x00 +#define NRSSEG 0x02 +#define NRSPTR 0x03 +#define NRSOFF 0x05 +#define NRPTR48 0x06 +#define NROFF32 0x07 +#define NRSOFF32 0x08 +#define NRSTYP 0x0f +#define NRSRCMASK 0x0f +#define NRALIAS 0x10 +#define NRCHAIN 0x20 +/** @} */ + +/** @name nr_flags (target flags) + * @{ */ +#define NRRINT 0x00 +#define NRRORD 0x01 +#define NRRNAM 0x02 +#define NRRENT 0x03 +#define NRRTYP 0x03 +#define NRADD 0x04 +#define NRICHAIN 0x08 +#define NR32BITOFF 0x10 +#define NR32BITADD 0x20 +#define NR16OBJMOD 0x40 +#define NR8BITORD 0x80 +/** @} */ + +/** @} */ + + +/** @defgroup grp_rt_formats_lx_object_tab The Object Table (aka segment table) + * @{ */ + +/** The Object Table Entry. */ +typedef struct o32_obj +{ + /** The size of the object. */ + uint32_t o32_size; + /** The base address of the object. */ + uint32_t o32_base; + /** Object flags. */ + uint32_t o32_flags; + /** Page map index. */ + uint32_t o32_pagemap; + /** Page map size. (doesn't need to be o32_size >> page shift). */ + uint32_t o32_mapsize; + /** Reserved */ + uint32_t o32_reserved; +} o32_obj; +AssertCompileSize(o32_obj, 24); + +/** @name o32_flags + * @{ */ +/** Read access. */ +#define OBJREAD UINT32_C(0x00000001) +/** Write access. */ +#define OBJWRITE UINT32_C(0x00000002) +/** Execute access. */ +#define OBJEXEC UINT32_C(0x00000004) +/** Resource object. */ +#define OBJRSRC UINT32_C(0x00000008) +/** The object is discarable (i.e. don't swap, just load in pages from the executable). + * This overlaps a bit with object type. */ +#define OBJDISCARD UINT32_C(0x00000010) +/** The object is shared. */ +#define OBJSHARED UINT32_C(0x00000020) +/** The object has preload pages. */ +#define OBJPRELOAD UINT32_C(0x00000040) +/** The object has invalid pages. */ +#define OBJINVALID UINT32_C(0x00000080) +/** Non-permanent, link386 bug. */ +#define LNKNONPERM UINT32_C(0x00000600) +/** Non-permanent, correct 'value'. */ +#define OBJNONPERM UINT32_C(0x00000000) +/** Obj Type: The object is permanent and swappable. */ +#define OBJPERM UINT32_C(0x00000100) +/** Obj Type: The object is permanent and resident (i.e. not swappable). */ +#define OBJRESIDENT UINT32_C(0x00000200) +/** Obj Type: The object is resident and contigious. */ +#define OBJCONTIG UINT32_C(0x00000300) +/** Obj Type: The object is permanent and long locable. */ +#define OBJDYNAMIC UINT32_C(0x00000400) +/** Object type mask. */ +#define OBJTYPEMASK UINT32_C(0x00000700) +/** x86: The object require an 16:16 alias. */ +#define OBJALIAS16 UINT32_C(0x00001000) +/** x86: Big/Default selector setting, i.e. toggle 32-bit or 16-bit. */ +#define OBJBIGDEF UINT32_C(0x00002000) +/** x86: conforming selector setting (weird stuff). */ +#define OBJCONFORM UINT32_C(0x00004000) +/** x86: IOPL. */ +#define OBJIOPL UINT32_C(0x00008000) +/** @} */ + +/** A Object Page Map Entry. */ +typedef struct o32_map +{ + /** The file offset of the page. */ + uint32_t o32_pagedataoffset; + /** The number of bytes of raw page data. */ + uint16_t o32_pagesize; + /** Per page flags describing how the page is encoded in the file. */ + uint16_t o32_pageflags; +} o32_map; +AssertCompileSize(o32_map, 8); + +/** @name o32 o32_pageflags + * @{ + */ +/** Raw page (uncompressed) in the file. */ +#define VALID UINT16_C(0x0000) +/** RLE encoded page in file. */ +#define ITERDATA UINT16_C(0x0001) +/** Invalid page, nothing in the file. */ +#define INVALID UINT16_C(0x0002) +/** Zero page, nothing in file. */ +#define ZEROED UINT16_C(0x0003) +/** range of pages (what is this?) */ +#define RANGE UINT16_C(0x0004) +/** Compressed page in file. */ +#define ITERDATA2 UINT16_C(0x0005) +/** @} */ + + +/** Iteration Record format (RLE compressed page). */ +#pragma pack(1) +typedef struct LX_Iter +{ + /** Number of iterations. */ + uint16_t LX_nIter; + /** The number of bytes that's being iterated. */ + uint16_t LX_nBytes; + /** The bytes. */ + uint8_t LX_Iterdata; +} LX_Iter; +#pragma pack() +AssertCompileSize(LX_Iter, 5); + +/** @} */ + + +/** A Resource Table Entry */ +#pragma pack(1) +typedef struct rsrc32 +{ + /** Resource Type. */ + uint16_t type; + /** Resource ID. */ + uint16_t name; + /** Resource size in bytes. */ + uint32_t cb; + /** The index of the object containing the resource. */ + uint16_t obj; + /** Offset of the resource that within the object. */ + uint32_t offset; +} rsrc32; +#pragma pack() +AssertCompileSize(rsrc32, 14); + + +/** @defgroup grp_rt_formats_lx_entry_tab The Entry Table (aka Export Table) + * @{ */ + +/** Entry bundle. + * Header descripting up to 255 entries that follows immediatly after this structure. */ +typedef struct b32_bundle +{ + /** The number of entries. */ + uint8_t b32_cnt; + /** The type of bundle. */ + uint8_t b32_type; + /** The index of the object containing these entry points. */ + uint16_t b32_obj; +} b32_bundle; +AssertCompileSize(b32_bundle, 4); + +/** @name b32_type + * @{ */ +/** Empty bundle, filling up unused ranges of ordinals. */ +#define EMPTY 0x00 +/** 16-bit offset entry point. */ +#define ENTRY16 0x01 +/** 16-bit callgate entry point. */ +#define GATE16 0x02 +/** 32-bit offset entry point. */ +#define ENTRY32 0x03 +/** Forwarder entry point. */ +#define ENTRYFWD 0x04 +/** Typing information present indicator. */ +#define TYPEINFO 0x80 +/** @} */ + + +/** Entry point. */ +#pragma pack(1) +typedef struct e32_entry +{ + /** Entry point flags */ + uint8_t e32_flags; /* Entry point flags */ + union entrykind + { + /** ENTRY16 or ENTRY32. */ + r32_offset e32_offset; + /** GATE16 */ + struct scallgate + { + /** Offset into segment. */ + uint16_t offset; + /** The callgate selector */ + uint16_t callgate; + } e32_callgate; + /** ENTRYFWD */ + struct fwd + { + /** Module ordinal number (i.e. into the import module table). */ + uint16_t modord; + /** Procedure name or ordinal number. */ + uint32_t value; + } e32_fwd; + } e32_variant; +} e32_entry; +#pragma pack() + +/** @name e32_flags + * @{ */ +/** Exported entry (set) or private entry (clear). */ +#define E32EXPORT 0x01 +/** Uses shared data. */ +#define E32SHARED 0x02 +/** Parameter word count mask. */ +#define E32PARAMS 0xf8 +/** ENTRYFWD: Imported by ordinal (set) or by name (clear). */ +#define FWD_ORDINAL 0x01 +/** @} */ + +/** @name dunno + * @{ */ +#define FIXENT16 3 +#define FIXENT32 5 +#define GATEENT16 5 +#define FWDENT 7 +/** @} */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_formats_lx_h */ + diff --git a/include/iprt/formats/mach-o.h b/include/iprt/formats/mach-o.h new file mode 100644 index 00000000..75fe0ed2 --- /dev/null +++ b/include/iprt/formats/mach-o.h @@ -0,0 +1,860 @@ +/* $Id: mach-o.h $ */ +/** @file + * IPRT - Mach-O Structures and Constants. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_mach_o_h +#define IPRT_INCLUDED_formats_mach_o_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#ifndef CPU_ARCH_MASK + +/* cputype */ +#define CPU_ARCH_MASK INT32_C(0xff000000) +#define CPU_ARCH_ABI64 INT32_C(0x01000000) +#define CPU_ARCH_ABI64_32 INT32_C(0x02000000) /**< LP32 on 64-bit hardware */ + +#define CPU_TYPE_ANY INT32_C(-1) +#define CPU_TYPE_VAX INT32_C(1) +#define CPU_TYPE_MC680x0 INT32_C(6) +#define CPU_TYPE_X86 INT32_C(7) +#define CPU_TYPE_I386 CPU_TYPE_X86 +#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) +#define CPU_TYPE_MC98000 INT32_C(10) +#define CPU_TYPE_HPPA INT32_C(11) +#define CPU_TYPE_ARM INT32_C(12) +#define CPU_TYPE_ARM32 CPU_TYPE_ARM +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#define CPU_TYPE_ARM64_32 (CPU_TYPE_ARM | CPU_ARCH_ABI64_32) +#define CPU_TYPE_MC88000 INT32_C(13) +#define CPU_TYPE_SPARC INT32_C(14) +#define CPU_TYPE_I860 INT32_C(15) +#define CPU_TYPE_POWERPC INT32_C(18) +#define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) + +/* cpusubtype */ +#define CPU_SUBTYPE_MULTIPLE INT32_C(-1) +#define CPU_SUBTYPE_LITTLE_ENDIAN INT32_C(0) +#define CPU_SUBTYPE_BIG_ENDIAN INT32_C(1) + +#define CPU_SUBTYPE_VAX_ALL INT32_C(0) +#define CPU_SUBTYPE_VAX780 INT32_C(1) +#define CPU_SUBTYPE_VAX785 INT32_C(2) +#define CPU_SUBTYPE_VAX750 INT32_C(3) +#define CPU_SUBTYPE_VAX730 INT32_C(4) +#define CPU_SUBTYPE_UVAXI INT32_C(5) +#define CPU_SUBTYPE_UVAXII INT32_C(6) +#define CPU_SUBTYPE_VAX8200 INT32_C(7) +#define CPU_SUBTYPE_VAX8500 INT32_C(8) +#define CPU_SUBTYPE_VAX8600 INT32_C(9) +#define CPU_SUBTYPE_VAX8650 INT32_C(10) +#define CPU_SUBTYPE_VAX8800 INT32_C(11) +#define CPU_SUBTYPE_UVAXIII INT32_C(12) + +#define CPU_SUBTYPE_MC680x0_ALL INT32_C(1) +#define CPU_SUBTYPE_MC68030 INT32_C(1) +#define CPU_SUBTYPE_MC68040 INT32_C(2) +#define CPU_SUBTYPE_MC68030_ONLY INT32_C(3) + +#define CPU_SUBTYPE_INTEL(fam, model) ( (int32_t )(((model) << 4) | (fam)) ) +#define CPU_SUBTYPE_INTEL_FAMILY(subtype) ( (subtype) & 0xf ) +#define CPU_SUBTYPE_INTEL_MODEL(subtype) ( (subtype) >> 4 ) +#define CPU_SUBTYPE_INTEL_FAMILY_MAX 0xf +#define CPU_SUBTYPE_INTEL_MODEL_ALL 0 + +#define CPU_SUBTYPE_I386_ALL CPU_SUBTYPE_INTEL(3, 0) +#define CPU_SUBTYPE_386 CPU_SUBTYPE_INTEL(3, 0) +#define CPU_SUBTYPE_486 CPU_SUBTYPE_INTEL(4, 0) +#define CPU_SUBTYPE_486SX CPU_SUBTYPE_INTEL(4, 8) +#define CPU_SUBTYPE_586 CPU_SUBTYPE_INTEL(5, 0) +#define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0) +#define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1) +#define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3) +#define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5) +#define CPU_SUBTYPE_CELERON CPU_SUBTYPE_INTEL(7, 6) +#define CPU_SUBTYPE_CELERON_MOBILE CPU_SUBTYPE_INTEL(7, 7) +#define CPU_SUBTYPE_PENTIUM_3 CPU_SUBTYPE_INTEL(8, 0) +#define CPU_SUBTYPE_PENTIUM_3_M CPU_SUBTYPE_INTEL(8, 1) +#define CPU_SUBTYPE_PENTIUM_3_XEON CPU_SUBTYPE_INTEL(8, 2) +#define CPU_SUBTYPE_PENTIUM_M CPU_SUBTYPE_INTEL(9, 0) +#define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0) +#define CPU_SUBTYPE_PENTIUM_4_M CPU_SUBTYPE_INTEL(10, 1) +#define CPU_SUBTYPE_ITANIUM CPU_SUBTYPE_INTEL(11, 0) +#define CPU_SUBTYPE_ITANIUM_2 CPU_SUBTYPE_INTEL(11, 1) +#define CPU_SUBTYPE_XEON CPU_SUBTYPE_INTEL(12, 0) +#define CPU_SUBTYPE_XEON_MP CPU_SUBTYPE_INTEL(12, 1) + +#define CPU_SUBTYPE_X86_ALL INT32_C(3) +#define CPU_SUBTYPE_X86_64_ALL INT32_C(3) +#define CPU_SUBTYPE_X86_ARCH1 INT32_C(4) + +#define CPU_SUBTYPE_MIPS_ALL INT32_C(0) +#define CPU_SUBTYPE_MIPS_R2300 INT32_C(1) +#define CPU_SUBTYPE_MIPS_R2600 INT32_C(2) +#define CPU_SUBTYPE_MIPS_R2800 INT32_C(3) +#define CPU_SUBTYPE_MIPS_R2000a INT32_C(4) +#define CPU_SUBTYPE_MIPS_R2000 INT32_C(5) +#define CPU_SUBTYPE_MIPS_R3000a INT32_C(6) +#define CPU_SUBTYPE_MIPS_R3000 INT32_C(7) + +#define CPU_SUBTYPE_MC98000_ALL INT32_C(0) +#define CPU_SUBTYPE_MC98601 INT32_C(1) + +#define CPU_SUBTYPE_HPPA_ALL INT32_C(0) +#define CPU_SUBTYPE_HPPA_7100 INT32_C(0) +#define CPU_SUBTYPE_HPPA_7100LC INT32_C(1) + +#define CPU_SUBTYPE_ARM_ALL INT32_C(0) +#define CPU_SUBTYPE_ARM_V4T INT32_C(5) +#define CPU_SUBTYPE_ARM_V6 INT32_C(6) +#define CPU_SUBTYPE_ARM_V5TEJ INT32_C(7) +#define CPU_SUBTYPE_ARM_XSCALE INT32_C(8) +#define CPU_SUBTYPE_ARM_V7 INT32_C(9) +#define CPU_SUBTYPE_ARM_V7F INT32_C(10) +#define CPU_SUBTYPE_ARM_V7S INT32_C(11) +#define CPU_SUBTYPE_ARM_V7K INT32_C(12) +#define CPU_SUBTYPE_ARM_V8 INT32_C(13) +#define CPU_SUBTYPE_ARM_V6M INT32_C(14) +#define CPU_SUBTYPE_ARM_V7M INT32_C(15) +#define CPU_SUBTYPE_ARM_V7EM INT32_C(16) +#define CPU_SUBTYPE_ARM_V8M INT32_C(17) + +#define CPU_SUBTYPE_ARM64_ALL INT32_C(0) +#define CPU_SUBTYPE_ARM64_V8 INT32_C(1) +#define CPU_SUBTYPE_ARM64E INT32_C(2) +#define CPU_SUBTYPE_ARM64_PTR_AUTH_MASK UINT32_C(0x0f000000) +#define CPU_SUBTYPE_ARM64_PTR_AUTH_VERSION(a) ( ((a) & CPU_SUBTYPE_ARM64_PTR_AUTH_MASK) >> 24 ) + +#define CPU_SUBTYPE_ARM64_32_ALL INT32_C(0) +#define CPU_SUBTYPE_ARM64_32_V8 INT32_C(1) + +#define CPU_SUBTYPE_MC88000_ALL INT32_C(0) +#define CPU_SUBTYPE_MC88100 INT32_C(1) +#define CPU_SUBTYPE_MC88110 INT32_C(2) + +#define CPU_SUBTYPE_SPARC_ALL INT32_C(0) + +#define CPU_SUBTYPE_I860_ALL INT32_C(0) +#define CPU_SUBTYPE_I860_860 INT32_C(1) + +#define CPU_SUBTYPE_POWERPC_ALL INT32_C(0) +#define CPU_SUBTYPE_POWERPC_601 INT32_C(1) +#define CPU_SUBTYPE_POWERPC_602 INT32_C(2) +#define CPU_SUBTYPE_POWERPC_603 INT32_C(3) +#define CPU_SUBTYPE_POWERPC_603e INT32_C(4) +#define CPU_SUBTYPE_POWERPC_603ev INT32_C(5) +#define CPU_SUBTYPE_POWERPC_604 INT32_C(6) +#define CPU_SUBTYPE_POWERPC_604e INT32_C(7) +#define CPU_SUBTYPE_POWERPC_620 INT32_C(8) +#define CPU_SUBTYPE_POWERPC_750 INT32_C(9) +#define CPU_SUBTYPE_POWERPC_7400 INT32_C(10) +#define CPU_SUBTYPE_POWERPC_7450 INT32_C(11) +#define CPU_SUBTYPE_POWERPC_Max INT32_C(10) +#define CPU_SUBTYPE_POWERPC_SCVger INT32_C(11) +#define CPU_SUBTYPE_POWERPC_970 INT32_C(100) + +#define CPU_SUBTYPE_MASK UINT32_C(0xff000000) +#define CPU_SUBTYPE_LIB64 UINT32_C(0x80000000) + +#endif /* !CPU_ARCH_MASK */ + + +typedef struct fat_header +{ + uint32_t magic; + uint32_t nfat_arch; +} fat_header_t; + +#ifndef IMAGE_FAT_SIGNATURE +# define IMAGE_FAT_SIGNATURE UINT32_C(0xcafebabe) +#endif +#ifndef IMAGE_FAT_SIGNATURE_OE +# define IMAGE_FAT_SIGNATURE_OE UINT32_C(0xbebafeca) +#endif + +typedef struct fat_arch +{ + int32_t cputype; + int32_t cpusubtype; + uint32_t offset; + uint32_t size; + uint32_t align; +} fat_arch_t; + +typedef struct mach_header_32 +{ + uint32_t magic; + int32_t cputype; + int32_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; +} mach_header_32_t; + +/* magic */ +#ifndef IMAGE_MACHO32_SIGNATURE +# define IMAGE_MACHO32_SIGNATURE UINT32_C(0xfeedface) +#endif +#ifndef IMAGE_MACHO32_SIGNATURE_OE +# define IMAGE_MACHO32_SIGNATURE_OE UINT32_C(0xcefaedfe) +#endif +#define MH_MAGIC IMAGE_MACHO32_SIGNATURE +#define MH_CIGAM IMAGE_MACHO32_SIGNATURE_OE + +typedef struct mach_header_64 +{ + uint32_t magic; /**< 0x00 */ + int32_t cputype; /**< 0x04 */ + int32_t cpusubtype; /**< 0x08 */ + uint32_t filetype; /**< 0x0c */ + uint32_t ncmds; /**< 0x10 */ + uint32_t sizeofcmds; /**< 0x14 */ + uint32_t flags; /**< 0x18 */ + uint32_t reserved; /**< 0x1c */ +} mach_header_64_t; +AssertCompileSize(mach_header_64_t, 0x20); + +/* magic */ +#ifndef IMAGE_MACHO64_SIGNATURE +# define IMAGE_MACHO64_SIGNATURE UINT32_C(0xfeedfacf) +#endif +#ifndef IMAGE_MACHO64_SIGNATURE_OE +# define IMAGE_MACHO64_SIGNATURE_OE UINT32_C(0xfefaedfe) +#endif +#define MH_MAGIC_64 IMAGE_MACHO64_SIGNATURE +#define MH_CIGAM_64 IMAGE_MACHO64_SIGNATURE_OE + +/* mach_header_* filetype */ +#define MH_OBJECT UINT32_C(1) +#define MH_EXECUTE UINT32_C(2) +#define MH_FVMLIB UINT32_C(3) +#define MH_CORE UINT32_C(4) +#define MH_PRELOAD UINT32_C(5) +#define MH_DYLIB UINT32_C(6) +#define MH_DYLINKER UINT32_C(7) +#define MH_BUNDLE UINT32_C(8) +#define MH_DYLIB_STUB UINT32_C(9) +#define MH_DSYM UINT32_C(10) +#define MH_KEXT_BUNDLE UINT32_C(11) + +/* mach_header_* flags */ +#define MH_NOUNDEFS UINT32_C(0x00000001) +#define MH_INCRLINK UINT32_C(0x00000002) +#define MH_DYLDLINK UINT32_C(0x00000004) +#define MH_BINDATLOAD UINT32_C(0x00000008) +#define MH_PREBOUND UINT32_C(0x00000010) +#define MH_SPLIT_SEGS UINT32_C(0x00000020) +#define MH_LAZY_INIT UINT32_C(0x00000040) +#define MH_TWOLEVEL UINT32_C(0x00000080) +#define MH_FORCE_FLAT UINT32_C(0x00000100) +#define MH_NOMULTIDEFS UINT32_C(0x00000200) +#define MH_NOFIXPREBINDING UINT32_C(0x00000400) +#define MH_PREBINDABLE UINT32_C(0x00000800) +#define MH_ALLMODSBOUND UINT32_C(0x00001000) +#define MH_SUBSECTIONS_VIA_SYMBOLS UINT32_C(0x00002000) +#define MH_CANONICAL UINT32_C(0x00004000) +#define MH_WEAK_DEFINES UINT32_C(0x00008000) +#define MH_BINDS_TO_WEAK UINT32_C(0x00010000) +#define MH_ALLOW_STACK_EXECUTION UINT32_C(0x00020000) +#define MH_ROOT_SAFE UINT32_C(0x00040000) +#define MH_SETUID_SAFE UINT32_C(0x00080000) +#define MH_NO_REEXPORTED_DYLIBS UINT32_C(0x00100000) +#define MH_PIE UINT32_C(0x00200000) +#define MH_DEAD_STRIPPABLE_DYLIB UINT32_C(0x00400000) +#define MH_HAS_TLV_DESCRIPTORS UINT32_C(0x00800000) +#define MH_NO_HEAP_EXECUTION UINT32_C(0x01000000) +#define MH_UNKNOWN UINT32_C(0x80000000) +#define MH_VALID_FLAGS UINT32_C(0x81ffffff) + + +typedef struct load_command +{ + uint32_t cmd; + uint32_t cmdsize; +} load_command_t; + +/* load cmd */ +#define LC_REQ_DYLD UINT32_C(0x80000000) +#define LC_SEGMENT_32 UINT32_C(0x01) +#define LC_SYMTAB UINT32_C(0x02) +#define LC_SYMSEG UINT32_C(0x03) +#define LC_THREAD UINT32_C(0x04) +#define LC_UNIXTHREAD UINT32_C(0x05) +#define LC_LOADFVMLIB UINT32_C(0x06) +#define LC_IDFVMLIB UINT32_C(0x07) +#define LC_IDENT UINT32_C(0x08) +#define LC_FVMFILE UINT32_C(0x09) +#define LC_PREPAGE UINT32_C(0x0a) +#define LC_DYSYMTAB UINT32_C(0x0b) +#define LC_LOAD_DYLIB UINT32_C(0x0c) +#define LC_ID_DYLIB UINT32_C(0x0d) +#define LC_LOAD_DYLINKER UINT32_C(0x0e) +#define LC_ID_DYLINKER UINT32_C(0x0f) +#define LC_PREBOUND_DYLIB UINT32_C(0x10) +#define LC_ROUTINES UINT32_C(0x11) +#define LC_SUB_FRAMEWORK UINT32_C(0x12) +#define LC_SUB_UMBRELLA UINT32_C(0x13) +#define LC_SUB_CLIENT UINT32_C(0x14) +#define LC_SUB_LIBRARY UINT32_C(0x15) +#define LC_TWOLEVEL_HINTS UINT32_C(0x16) +#define LC_PREBIND_CKSUM UINT32_C(0x17) +#define LC_LOAD_WEAK_DYLIB (UINT32_C(0x18) | LC_REQ_DYLD) +#define LC_SEGMENT_64 UINT32_C(0x19) +#define LC_ROUTINES_64 UINT32_C(0x1a) +#define LC_UUID UINT32_C(0x1b) +#define LC_RPATH (UINT32_C(0x1c) | LC_REQ_DYLD) +#define LC_CODE_SIGNATURE UINT32_C(0x1d) +#define LC_SEGMENT_SPLIT_INFO UINT32_C(0x1e) +#define LC_REEXPORT_DYLIB (UINT32_C(0x1f) | LC_REQ_DYLD) +#define LC_LAZY_LOAD_DYLIB UINT32_C(0x20) +#define LC_ENCRYPTION_INFO UINT32_C(0x21) +#define LC_DYLD_INFO UINT32_C(0x22) +#define LC_DYLD_INFO_ONLY (UINT32_C(0x22) | LC_REQ_DYLD) +#define LC_LOAD_UPWARD_DYLIB (UINT32_C(0x23) | LC_REQ_DYLD) +#define LC_VERSION_MIN_MACOSX UINT32_C(0x24) +#define LC_VERSION_MIN_IPHONEOS UINT32_C(0x25) +#define LC_FUNCTION_STARTS UINT32_C(0x26) +#define LC_DYLD_ENVIRONMENT UINT32_C(0x27) +#define LC_MAIN (UINT32_C(0x28) | LC_REQ_DYLD) +#define LC_DATA_IN_CODE UINT32_C(0x29) +#define LC_SOURCE_VERSION UINT32_C(0x2a) /**< source_version_command */ +#define LC_DYLIB_CODE_SIGN_DRS UINT32_C(0x2b) +#define LC_ENCRYPTION_INFO_64 UINT32_C(0x2c) +#define LC_LINKER_OPTION UINT32_C(0x2d) +#define LC_LINKER_OPTIMIZATION_HINT UINT32_C(0x2e) +#define LC_VERSION_MIN_TVOS UINT32_C(0x2f) +#define LC_VERSION_MIN_WATCHOS UINT32_C(0x30) +#define LC_NOTE UINT32_C(0x31) +#define LC_BUILD_VERSION UINT32_C(0x32) + + +typedef struct lc_str +{ + uint32_t offset; +} lc_str_t; + +typedef struct segment_command_32 +{ + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint32_t vmaddr; + uint32_t vmsize; + uint32_t fileoff; + uint32_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +} segment_command_32_t; + +typedef struct segment_command_64 +{ + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +} segment_command_64_t; + +/* segment flags */ +#define SG_HIGHVM UINT32_C(0x00000001) +#define SG_FVMLIB UINT32_C(0x00000002) +#define SG_NORELOC UINT32_C(0x00000004) +#define SG_PROTECTED_VERSION_1 UINT32_C(0x00000008) +#define SG_READ_ONLY UINT32_C(0x00000010) /**< Make it read-only after applying fixups. @since 10.14 */ + +/* maxprot/initprot */ +#ifndef VM_PROT_NONE +# define VM_PROT_NONE UINT32_C(0x00000000) +# define VM_PROT_READ UINT32_C(0x00000001) +# define VM_PROT_WRITE UINT32_C(0x00000002) +# define VM_PROT_EXECUTE UINT32_C(0x00000004) +# define VM_PROT_ALL UINT32_C(0x00000007) +#endif + +typedef struct section_32 +{ + char sectname[16]; + char segname[16]; + uint32_t addr; + uint32_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + /** For S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS and S_SYMBOL_STUBS + * this is the index into the indirect symbol table. */ + uint32_t reserved1; + /** For S_SYMBOL_STUBS this is the entry size. */ + uint32_t reserved2; +} section_32_t; + +typedef struct section_64 +{ + char sectname[16]; + char segname[16]; + uint64_t addr; + uint64_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + /** For S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS and S_SYMBOL_STUBS + * this is the index into the indirect symbol table. */ + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; +} section_64_t; + +/* section flags */ +#define SECTION_TYPE UINT32_C(0xff) +#define S_REGULAR UINT32_C(0x00) +#define S_ZEROFILL UINT32_C(0x01) +#define S_CSTRING_LITERALS UINT32_C(0x02) +#define S_4BYTE_LITERALS UINT32_C(0x03) +#define S_8BYTE_LITERALS UINT32_C(0x04) +#define S_LITERAL_POINTERS UINT32_C(0x05) +#define S_NON_LAZY_SYMBOL_POINTERS UINT32_C(0x06) +#define S_LAZY_SYMBOL_POINTERS UINT32_C(0x07) +#define S_SYMBOL_STUBS UINT32_C(0x08) +#define S_MOD_INIT_FUNC_POINTERS UINT32_C(0x09) +#define S_MOD_TERM_FUNC_POINTERS UINT32_C(0x0a) +#define S_COALESCED UINT32_C(0x0b) +#define S_GB_ZEROFILL UINT32_C(0x0c) +#define S_INTERPOSING UINT32_C(0x0d) +#define S_16BYTE_LITERALS UINT32_C(0x0e) +#define S_DTRACE_DOF UINT32_C(0x0f) +#define S_LAZY_DYLIB_SYMBOL_POINTERS UINT32_C(0x10) +#define S_THREAD_LOCAL_REGULAR UINT32_C(0x11) +#define S_THREAD_LOCAL_ZEROFILL UINT32_C(0x12) +#define S_THREAD_LOCAL_VARIABLES UINT32_C(0x13) +#define S_THREAD_LOCAL_VARIABLE_POINTERS UINT32_C(0x14) +#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS UINT32_C(0x15) + + + + +#define SECTION_ATTRIBUTES UINT32_C(0xffffff00) +#define SECTION_ATTRIBUTES_USR UINT32_C(0xff000000) +#define S_ATTR_PURE_INSTRUCTIONS UINT32_C(0x80000000) +#define S_ATTR_NO_TOC UINT32_C(0x40000000) +#define S_ATTR_STRIP_STATIC_SYMS UINT32_C(0x20000000) +#define S_ATTR_NO_DEAD_STRIP UINT32_C(0x10000000) +#define S_ATTR_LIVE_SUPPORT UINT32_C(0x08000000) +#define S_ATTR_SELF_MODIFYING_CODE UINT32_C(0x04000000) +#define S_ATTR_DEBUG UINT32_C(0x02000000) +#define SECTION_ATTRIBUTES_SYS UINT32_C(0x00ffff00) +#define S_ATTR_SOME_INSTRUCTIONS UINT32_C(0x00000400) +#define S_ATTR_EXT_RELOC UINT32_C(0x00000200) +#define S_ATTR_LOC_RELOC UINT32_C(0x00000100) + +/* standard section names */ +#define SEG_PAGEZERO "__PAGEZERO" +#define SEG_TEXT "__TEXT" +#define SECT_TEXT "__text" +#define SECT_FVMLIB_INIT0 "__fvmlib_init0" +#define SECT_FVMLIB_INIT1 "__fvmlib_init1" +#define SEG_DATA "__DATA" +#define SECT_DATA "__data" +#define SECT_BSS "__bss" +#define SECT_COMMON "__common" +#define SEG_OBJC "__OBJC" +#define SECT_OBJC_SYMBOLS "__symbol_table" +#define SECT_OBJC_MODULES "__module_info" +#define SECT_OBJC_STRINGS "__selector_strs" +#define SECT_OBJC_REFS "__selector_refs" +#define SEG_ICON "__ICON" +#define SECT_ICON_HEADER "__header" +#define SECT_ICON_TIFF "__tiff" +#define SEG_LINKEDIT "__LINKEDIT" +#define SEG_UNIXSTACK "__UNIXSTACK" +#define SEG_IMPORT "__IMPORT" + +typedef struct thread_command +{ + uint32_t cmd; + uint32_t cmdsize; +} thread_command_t; + +typedef struct symtab_command +{ + uint32_t cmd; + uint32_t cmdsize; + uint32_t symoff; + uint32_t nsyms; + uint32_t stroff; + uint32_t strsize; +} symtab_command_t; + +typedef struct dysymtab_command +{ + uint32_t cmd; + uint32_t cmdsize; + /** @name Symbol groupings. + * @{ */ + uint32_t ilocalsym; /**< Index into the symbol table of the first local symbol. */ + uint32_t nlocalsym; /**< Number of local symbols. */ + uint32_t iextdefsym; /**< Index into the symbol table of the first externally defined symbol. */ + uint32_t nextdefsym; /**< Number of externally defined symbols. */ + uint32_t iundefsym; /**< Index into the symbol table of the first undefined symbol. */ + uint32_t nundefsym; /**< Number of undefined symbols. */ + /** @} */ + uint32_t tocoff; /**< Table of content file offset. (usually empty) */ + uint32_t ntoc; /**< Number of entries in TOC. */ + uint32_t modtaboff; /** The module table file offset. (usually empty) */ + uint32_t nmodtab; /**< Number of entries in the module table. */ + /** @name Dynamic symbol tables. + * @{ */ + uint32_t extrefsymoff; /**< Externally referenceable symbol table file offset. @sa dylib_reference_t */ + uint32_t nextrefsym; /**< Number externally referenceable symbols. */ + uint32_t indirectsymboff; /**< Indirect symbol table (32-bit symtab indexes) for thunks and offset tables. */ + uint32_t nindirectsymb; /**< Number of indirect symbol table entries. */ + /** @} */ + /** @name Relocations. + * @{ */ + uint32_t extreloff; /**< External relocations (r_address is relative to first segment (i.e. RVA)). */ + uint32_t nextrel; /**< Number of external relocations. */ + uint32_t locreloff; /**< Local relocations (r_address is relative to first segment (i.e. RVA)). */ + uint32_t nlocrel; /**< Number of local relocations. */ + /** @} */ +} dysymtab_command_t; +AssertCompileSize(dysymtab_command_t, 80); + +/** Special indirect symbol table entry value, stripped local symbol. */ +#define INDIRECT_SYMBOL_LOCAL UINT32_C(0x80000000) +/** Special indirect symbol table entry value, stripped absolute symbol. */ +#define INDIRECT_SYMBOL_ABS UINT32_C(0x40000000) + +typedef struct dylib_reference +{ + uint32_t isym : 24; /**< Symbol table index. */ + uint32_t flags : 8; /**< REFERENCE_FLAG_XXX? */ +} dylib_reference_t; +AssertCompileSize(dylib_reference_t, 4); + + +typedef struct dylib_table_of_contents +{ + uint32_t symbol_index; /**< External symbol table entry. */ + uint32_t module_index; /**< The module table index of the module defining it. */ +} dylib_table_of_contents_t; +AssertCompileSize(dylib_table_of_contents_t, 8); + + +/** 32-bit module table entry. */ +typedef struct dylib_module +{ + uint32_t module_name; + uint32_t iextdefsym; + uint32_t nextdefsym; + uint32_t irefsym; + uint32_t nrefsym; + uint32_t ilocalsym; + uint32_t nlocalsym; + uint32_t iextrel; + uint32_t nextrel; + uint32_t iinit_iterm; + uint32_t ninit_nterm; + uint32_t objc_module_info_addr; + uint32_t objc_module_info_size; +} dylib_module_32_t; +AssertCompileSize(dylib_module_32_t, 13*4); + +/* a 64-bit module table entry */ +typedef struct dylib_module_64 +{ + uint32_t module_name; + uint32_t iextdefsym; + uint32_t nextdefsym; + uint32_t irefsym; + uint32_t nrefsym; + uint32_t ilocalsym; + uint32_t nlocalsym; + uint32_t iextrel; + uint32_t nextrel; + uint32_t iinit_iterm; + uint32_t ninit_nterm; + uint32_t objc_module_info_size; + uint64_t objc_module_info_addr; +} dylib_module_64_t; +AssertCompileSize(dylib_module_64_t, 12*4+8); + +typedef struct uuid_command +{ + uint32_t cmd; + uint32_t cmdsize; + uint8_t uuid[16]; +} uuid_command_t; +AssertCompileSize(uuid_command_t, 24); + +typedef struct linkedit_data_command +{ + uint32_t cmd; /**< LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS */ + uint32_t cmdsize; /**< Size of this structure (16). */ + uint32_t dataoff; /**< Offset into the file of the data. */ + uint32_t datasize; /**< The size of the data. */ +} linkedit_data_command_t; +AssertCompileSize(linkedit_data_command_t, 16); + +typedef struct version_min_command +{ + uint32_t cmd; /**< LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS */ + uint32_t cmdsize; /**< Size of this structure (16). */ + uint32_t version; /**< 31..16=major, 15..8=minor, 7..0=patch. */ + uint32_t reserved; /**< MBZ. */ +} version_min_command_t; +AssertCompileSize(version_min_command_t, 16); + +typedef struct build_tool_version +{ + uint32_t tool; /**< TOOL_XXX */ + uint32_t version; /**< 31..16=major, 15..8=minor, 7..0=patch. */ +} build_tool_version_t; +AssertCompileSize(build_tool_version_t, 8); + +/** @name TOOL_XXX - Values for build_tool_version::tool + * @{ */ +#define TOOL_CLANG 1 +#define TOOL_SWIFT 2 +#define TOOL_LD 3 +/** @} */ + +typedef struct build_version_command +{ + uint32_t cmd; /**< LC_BUILD_VERSION */ + uint32_t cmdsize; /**< Size of this structure (at least 24). */ + uint32_t platform; /**< PLATFORM_XXX */ + uint32_t minos; /**< Minimum OS version: 31..16=major, 15..8=minor, 7..0=patch */ + uint32_t sdk; /**< SDK version: 31..16=major, 15..8=minor, 7..0=patch */ + uint32_t ntools; /**< Number of build_tool_version entries following in aTools. */ + RT_FLEXIBLE_ARRAY_EXTENSION + build_tool_version_t aTools[RT_FLEXIBLE_ARRAY]; +} build_version_command_t; +AssertCompileMemberOffset(build_version_command_t, aTools, 24); + +/** @name PLATFORM_XXX - Values for build_version_command::platform + * @{ */ +#define PLATFORM_MACOS 1 +#define PLATFORM_IOS 2 +#define PLATFORM_TVOS 3 +#define PLATFORM_WATCHOS 4 +/** @} */ + +typedef struct source_version_command +{ + uint32_t cmd; /**< LC_SOURCE_VERSION */ + uint32_t cmdsize; /**< Size of this structure (16). */ + uint64_t version; /**< A.B.C.D.E, where A is 24 bits wide and the rest 10 bits each. */ +} source_version_command_t; +AssertCompileSize(source_version_command_t, 16); + + +typedef struct macho_nlist_32 +{ + union + { + int32_t n_strx; + } n_un; + uint8_t n_type; + uint8_t n_sect; + int16_t n_desc; + uint32_t n_value; +} macho_nlist_32_t; + + +typedef struct macho_nlist_64 +{ + union + { + uint32_t n_strx; + } n_un; + uint8_t n_type; + uint8_t n_sect; + int16_t n_desc; + uint64_t n_value; +} macho_nlist_64_t; + +#define MACHO_N_EXT UINT8_C(0x01) +#define MACHO_N_PEXT UINT8_C(0x10) + +#define MACHO_N_TYPE UINT8_C(0x0e) +#define MACHO_N_UNDF UINT8_C(0x00) +#define MACHO_N_ABS UINT8_C(0x02) +#define MACHO_N_INDR UINT8_C(0x0a) +#define MACHO_N_PBUD UINT8_C(0x0c) +#define MACHO_N_SECT UINT8_C(0x0e) + +#define MACHO_N_STAB UINT8_C(0xe0) +#define MACHO_N_GSYM UINT8_C(0x20) +#define MACHO_N_FNAME UINT8_C(0x22) +#define MACHO_N_FUN UINT8_C(0x24) +#define MACHO_N_STSYM UINT8_C(0x26) +#define MACHO_N_LCSYM UINT8_C(0x28) +#define MACHO_N_BNSYM UINT8_C(0x2e) +#define MACHO_N_PC UINT8_C(0x30) +#define MACHO_N_OPT UINT8_C(0x3c) +#define MACHO_N_RSYM UINT8_C(0x40) +#define MACHO_N_SLINE UINT8_C(0x44) +#define MACHO_N_ENSYM UINT8_C(0x4e) +#define MACHO_N_SSYM UINT8_C(0x60) +#define MACHO_N_SO UINT8_C(0x64) +#define MACHO_N_OSO UINT8_C(0x66) +#define MACHO_N_LSYM UINT8_C(0x80) +#define MACHO_N_BINCL UINT8_C(0x82) +#define MACHO_N_SOL UINT8_C(0x84) +#define MACHO_N_PARAMS UINT8_C(0x86) +#define MACHO_N_VERSION UINT8_C(0x88) +#define MACHO_N_OLEVEL UINT8_C(0x8A) +#define MACHO_N_PSYM UINT8_C(0xa0) +#define MACHO_N_EINCL UINT8_C(0xa2) +#define MACHO_N_ENTRY UINT8_C(0xa4) +#define MACHO_N_LBRAC UINT8_C(0xc0) +#define MACHO_N_EXCL UINT8_C(0xc2) +#define MACHO_N_RBRAC UINT8_C(0xe0) +#define MACHO_N_BCOMM UINT8_C(0xe2) +#define MACHO_N_ECOMM UINT8_C(0xe4) +#define MACHO_N_ECOML UINT8_C(0xe8) +#define MACHO_N_LENG UINT8_C(0xfe) + +#define MACHO_NO_SECT UINT8_C(0x00) +#define MACHO_MAX_SECT UINT8_C(0xff) + +#define REFERENCE_TYPE UINT16_C(0x000f) +#define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0 +#define REFERENCE_FLAG_UNDEFINED_LAZY 1 +#define REFERENCE_FLAG_DEFINED 2 +#define REFERENCE_FLAG_PRIVATE_DEFINED 3 +#define REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY 4 +#define REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY 5 +#define REFERENCED_DYNAMICALLY UINT16_C(0x0010) + +#define GET_LIBRARY_ORDINAL(a_n_desc) \ + RT_BYTE2(a_n_desc) +#define SET_LIBRARY_ORDINAL(a_n_desc, a_ordinal) \ + do { (a_n_desc) = RT_MAKE_U16(RT_BYTE1(a_n_desc), a_ordinal); } while (0) + +#define SELF_LIBRARY_ORDINAL 0x00 +#define MAX_LIBRARY_ORDINAL 0xfd +#define DYNAMIC_LOOKUP_ORDINAL 0xfe +#define EXECUTABLE_ORDINAL 0xff + +#define N_NO_DEAD_STRIP UINT16_C(0x0020) +#define N_DESC_DISCARDED UINT16_C(0x0020) +#define N_WEAK_REF UINT16_C(0x0040) +#define N_WEAK_DEF UINT16_C(0x0080) +#define N_REF_TO_WEAK UINT16_C(0x0080) +#define N_SYMBOL_RESOLVER UINT16_C(0x0100) +#define N_ALT_ENTRY UINT16_C(0x0200) + +typedef struct macho_relocation_info +{ + int32_t r_address; + uint32_t r_symbolnum : 24; + uint32_t r_pcrel : 1; + uint32_t r_length : 2; + uint32_t r_extern : 1; + uint32_t r_type : 4; +} macho_relocation_info_t; +AssertCompileSize(macho_relocation_info_t, 8); + +#define R_ABS 0 +#define R_SCATTERED UINT32_C(0x80000000) + +typedef struct scattered_relocation_info +{ +#ifdef RT_LITTLE_ENDIAN + uint32_t r_address : 24; + uint32_t r_type : 4; + uint32_t r_length : 2; + uint32_t r_pcrel : 1; + uint32_t r_scattered : 1; +#elif defined(RT_BIG_ENDIAN) + uint32_t r_scattered : 1; + uint32_t r_pcrel : 1; + uint32_t r_length : 2; + uint32_t r_type : 4; + uint32_t r_address : 24; +#else +# error "Neither K_ENDIAN isn't LITTLE or BIG!" +#endif + int32_t r_value; +} scattered_relocation_info_t; +AssertCompileSize(scattered_relocation_info_t, 8); + +typedef union +{ + macho_relocation_info_t r; + scattered_relocation_info_t s; +} macho_relocation_union_t; +AssertCompileSize(macho_relocation_union_t, 8); + +typedef enum reloc_type_generic +{ + GENERIC_RELOC_VANILLA = 0, + GENERIC_RELOC_PAIR, + GENERIC_RELOC_SECTDIFF, + GENERIC_RELOC_PB_LA_PTR, + GENERIC_RELOC_LOCAL_SECTDIFF +} reloc_type_generic_t; + +typedef enum reloc_type_x86_64 +{ + X86_64_RELOC_UNSIGNED = 0, + X86_64_RELOC_SIGNED, + X86_64_RELOC_BRANCH, + X86_64_RELOC_GOT_LOAD, + X86_64_RELOC_GOT, + X86_64_RELOC_SUBTRACTOR, + X86_64_RELOC_SIGNED_1, + X86_64_RELOC_SIGNED_2, + X86_64_RELOC_SIGNED_4 +} reloc_type_x86_64_t; + +#endif /* !IPRT_INCLUDED_formats_mach_o_h */ + diff --git a/include/iprt/formats/mz.h b/include/iprt/formats/mz.h new file mode 100644 index 00000000..4759ad40 --- /dev/null +++ b/include/iprt/formats/mz.h @@ -0,0 +1,77 @@ +/* $Id: mz.h $ */ +/** @file + * IPRT, MZ Executable Header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_mz_h +#define IPRT_INCLUDED_formats_mz_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +typedef struct _IMAGE_DOS_HEADER +{ + uint16_t e_magic; + uint16_t e_cblp; + uint16_t e_cp; + uint16_t e_crlc; + uint16_t e_cparhdr; + uint16_t e_minalloc; + uint16_t e_maxalloc; + uint16_t e_ss; + uint16_t e_sp; + uint16_t e_csum; + uint16_t e_ip; + uint16_t e_cs; + uint16_t e_lfarlc; + uint16_t e_ovno; + uint16_t e_res[4]; + uint16_t e_oemid; + uint16_t e_oeminfo; + uint16_t e_res2[10]; + uint32_t e_lfanew; +} IMAGE_DOS_HEADER; +AssertCompileSize(IMAGE_DOS_HEADER, 0x40); +typedef IMAGE_DOS_HEADER *PIMAGE_DOS_HEADER; + +#ifndef IMAGE_DOS_SIGNATURE +# define IMAGE_DOS_SIGNATURE ('M' | ('Z' << 8)) /* fix endianness */ +#endif + + +#endif /* !IPRT_INCLUDED_formats_mz_h */ + diff --git a/include/iprt/formats/mz.mac b/include/iprt/formats/mz.mac new file mode 100644 index 00000000..97e30cc6 --- /dev/null +++ b/include/iprt/formats/mz.mac @@ -0,0 +1,66 @@ +;; @file +; IPRT - MZ (DOS Executable Header) definitions for YASM/NASM. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_formats_mz_mac +%define ___iprt_formats_mz_mac + +struc IMAGE_DOS_HEADER + .e_magic resw 1 + .e_cblp resw 1 + .e_cp resw 1 + .e_crlc resw 1 + .e_cparhdr resw 1 + .e_minalloc resw 1 + .e_maxalloc resw 1 + .e_ss resw 1 + .e_sp resw 1 + .e_csum resw 1 + .e_ip resw 1 + .e_cs resw 1 + .e_lfarlc resw 1 + .e_ovno resw 1 + .e_res resw 4 + .e_oemid resw 1 + .e_oeminfo resw 1 + .e_res2 resw 10 + .e_lfanew resd 1 +endstruc + +%ifndef IMAGE_DOS_SIGNATURE + %define IMAGE_DOS_SIGNATURE 0x5a4d +%endif + +%endif + diff --git a/include/iprt/formats/ntfs.h b/include/iprt/formats/ntfs.h new file mode 100644 index 00000000..36c0b112 --- /dev/null +++ b/include/iprt/formats/ntfs.h @@ -0,0 +1,782 @@ +/* $Id: ntfs.h $ */ +/** @file + * IPRT, NT File System (NTFS). + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_ntfs_h +#define IPRT_INCLUDED_formats_ntfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_rt_formats_ntfs NT File System (NTFS) structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/** Value of the FATBOOTSECTOR::achOemName for an NTFS file system. */ +#define NTFS_OEM_ID_MAGIC "NTFS " + + +/** @name NTFS_MFT_IDX_XXX - Predefined MFT indexes. + * @{ */ +#define NTFS_MFT_IDX_MFT 0 /**< The MFT itself. */ +#define NTFS_MFT_IDX_MFT_MIRROR 1 /**< Mirror MFT (partial?). */ +#define NTFS_MFT_IDX_LOG_FILE 2 /**< Journalling log. */ +#define NTFS_MFT_IDX_VOLUME 3 /**< Volume attributes. */ +#define NTFS_MFT_IDX_ATTRIB_DEF 4 /**< Attribute definitions. */ +#define NTFS_MFT_IDX_ROOT 5 /**< The root directory. */ +#define NTFS_MFT_IDX_BITMAP 6 /**< Allocation bitmap. */ +#define NTFS_MFT_IDX_BOOT 7 /**< The boot sector. */ +#define NTFS_MFT_IDX_BAD_CLUSTER 8 /**< Bad cluster table. */ +#define NTFS_MFT_IDX_SECURITY 9 /**< Shared security descriptors (w2k and later). */ +#define NTFS_MFT_IDX_UP_CASE 10 /**< Unicode upper case table. */ +#define NTFS_MFT_IDX_EXTEND 11 /**< Directory containing further system files. */ +#define NTFS_MFT_IDX_FIRST_USER 16 /**< The first user file. */ +/** @} */ + +/** + * NTFS MFT record reference. + */ +typedef union NTFSMFTREF +{ + /** unsigned 64-bit view. */ + uint64_t u64; + /** unsigned 32-bit view. */ + uint32_t au32[2]; + /** unsigned 16-bit view. */ + uint16_t au16[4]; + + /** Structured view. */ + struct + { + /** Index of the master file table record. */ + RT_GCC_EXTENSION uint64_t idxMft : 48; + /** MFT record reuse sequence number (for catching dangling references). */ + RT_GCC_EXTENSION uint64_t uRecReuseSeqNo : 16; + } s; +} NTFSMFTREF; +AssertCompileSize(NTFSMFTREF, 8); +/** Pointer to a NTFS MFT record reference. */ +typedef NTFSMFTREF *PNTFSMFTREF; +/** Pointer to a const NTFS MFT record reference. */ +typedef NTFSMFTREF const *PCNTFSMFTREF; + +/** @name NTFSMFTREF_GET_IDX + * Gets the MFT index number (host endian) from a MFT reference. */ +/** @name NTFSMFTREF_GET_SEQ + * Gets the MFT reuse sequence number (host endian) from a MFT reference. */ +/** @name NTFSMFTREF_SET_IDX + * Sets the MFT index number of a MFT reference. */ +/** @name NTFSMFTREF_SET_SEQ + * Sets the MFT reuse sequence number of a MFT reference. */ +/** @name NTFSMFTREF_SET + * Sets the values of a MFT reference. */ +#ifdef RT_LITTLE_ENDIAN +# define NTFSMFTREF_GET_IDX(a_pMftRef) ((a_pMftRef)->s.idxMft) +# define NTFSMFTREF_GET_SEQ(a_pMftRef) ((a_pMftRef)->s.uRecReuseSeqNo) +# define NTFSMFTREF_SET_SEQ(a_pMftRef, a_uValue) do { (a_pMftRef)->s.uRecReuseSeqNo = (a_uValue); } while (0) +# define NTFSMFTREF_SET_IDX(a_pMftRef, a_uValue) do { (a_pMftRef)->s.idxMft = (a_uValue); } while (0) +# define NTFSMFTREF_SET(a_pMftRef, a_idx, a_uSeq) \ + do { \ + (a_pMftRef)->s.idxMft = (a_idx); \ + (a_pMftRef)->s.uRecReuseSeqNo = (a_uSeq); \ + } while (0) +#else +# define NTFSMFTREF_GET_IDX(a_pMftRef) (RT_LE2H_U64((a_pMftRef)->u64) & UINT64_C(0x0000ffffffffffff)) +# define NTFSMFTREF_GET_SEQ(a_pMftRef) RT_LE2H_U16((uint16_t)(a_pMftRef)->u64) +# define NTFSMFTREF_SET_SEQ(a_pMftRef, a_uValue) do { (a_pMftRef)->au16[3] = RT_H2LE_U16(a_uValue); } while (0) +# define NTFSMFTREF_SET_IDX(a_pMftRef, a_uValue) \ + do { \ + (a_pMftRef)->au32[0] = RT_H2LE_U32((uint32_t)(a_uValue)); \ + (a_pMftRef)->au16[2] = RT_H2LE_U16((uint16_t)((a_uValue) >> 32)); \ + } while (0) +# define NTFSMFTREF_SET(a_pMftRef, a_idx, a_uSeq) \ + do { \ + (a_pMftRef)->au32[0] = RT_H2LE_U32((uint32_t)(a_idx)); \ + (a_pMftRef)->au16[2] = RT_H2LE_U16((uint16_t)((a_idx) >> 32)); \ + (a_pMftRef)->au16[3] = RT_H2LE_U16((uint16_t)(a_uSeq)); \ + } while (0) +#endif +/** Check that the reference is zero. */ +#define NTFSMFTREF_IS_ZERO(a_pMftRef) ((a_pMftRef)->u64 == 0) + + +/** + * NTFS record header. + */ +typedef struct NTFSRECHDR +{ + /** Magic number (usually ASCII). */ + uint32_t uMagic; + /** Offset of the update sequence array from the start of the record. */ + uint16_t offUpdateSeqArray; + /** Number of entries in the update sequence array. (uint16_t sized entries) */ + uint16_t cUpdateSeqEntries; +} NTFSRECHDR; +AssertCompileSize(NTFSRECHDR, 8); +/** Pointer to a NTFS record header. */ +typedef NTFSRECHDR *PNTFSRECHDR; +/** Pointer to a const NTFS record header. */ +typedef NTFSRECHDR const *PCNTFSRECHDR; + +/** The multi-sector update sequence stride. + * @see https://msdn.microsoft.com/en-us/library/bb470212%28v=vs.85%29.aspx + * @see NTFSRECHDR::offUpdateSeqArray, NTFSRECHDR::cUpdateSeqEntries + */ +#define NTFS_MULTI_SECTOR_STRIDE 512 + + +/** + * NTFS file record (in the MFT). + */ +typedef struct NTFSRECFILE +{ + /** 0x00: Header with NTFSREC_MAGIC_FILE. */ + NTFSRECHDR Hdr; + /** 0x08: Log file sequence number. */ + uint64_t uLsn; + /** 0x10: MFT record reuse sequence number (for dangling MFT references). */ + uint16_t uRecReuseSeqNo; + /** 0x12: Number of hard links. */ + uint16_t cLinks; + /** 0x14: Offset of the first attribute (relative to start of record). */ + uint16_t offFirstAttrib; + /** 0x16: Record flags (NTFSRECFILE_F_XXX). */ + uint16_t fFlags; + /** 0x18: Number of byte in use in this MFT record. */ + uint32_t cbRecUsed; + /** 0x1c: The MFT record size. */ + uint32_t cbRecSize; + /** 0x20: Reference to the base MFT record. */ + NTFSMFTREF BaseMftRec; + /** 0x28: Next attribute instance number. */ + uint16_t idNextAttrib; + /** 0x2a: Padding if NTFS 3.1+, update sequence array if older. */ + uint16_t uPaddingOrUsa; + /** 0x2c: MFT index of this record. */ + uint32_t idxMftSelf; +} NTFSRECFILE; +AssertCompileSize(NTFSRECFILE, 0x30); +/** Pointer to a NTFS file record. */ +typedef NTFSRECFILE *PNTFSRECFILE; +/** Pointer to a const NTFS file record. */ +typedef NTFSRECFILE const *PCNTFSRECFILE; + + +/** NTFS 'FILE' record magic value. */ +#define NTFSREC_MAGIC_FILE RT_H2LE_U32_C(UINT32_C(0x454c4946)) + +/** @name NTFSRECFILE_F_XXX - NTFSRECFILE::fFlags. + * @{ */ +/** MFT record is in use. */ +#define NTFSRECFILE_F_IN_USE RT_H2LE_U16_C(UINT16_C(0x0001)) +/** Directory record. */ +#define NTFSRECFILE_F_DIRECTORY RT_H2LE_U16_C(UINT16_C(0x0002)) +/** @} */ + + +/** @name NTFS_AT_XXX - Attribute types + * @{ */ +#define NTFS_AT_UNUSED RT_H2LE_U32_C(UINT32_C(0x00000000)) +/** NTFSATSTDINFO */ +#define NTFS_AT_STANDARD_INFORMATION RT_H2LE_U32_C(UINT32_C(0x00000010)) +/** NTFSATLISTENTRY */ +#define NTFS_AT_ATTRIBUTE_LIST RT_H2LE_U32_C(UINT32_C(0x00000020)) +/** NTFSATFILENAME */ +#define NTFS_AT_FILENAME RT_H2LE_U32_C(UINT32_C(0x00000030)) +#define NTFS_AT_OBJECT_ID RT_H2LE_U32_C(UINT32_C(0x00000040)) +#define NTFS_AT_SECURITY_DESCRIPTOR RT_H2LE_U32_C(UINT32_C(0x00000050)) +#define NTFS_AT_VOLUME_NAME RT_H2LE_U32_C(UINT32_C(0x00000060)) +/** NTFSATVOLUMEINFO */ +#define NTFS_AT_VOLUME_INFORMATION RT_H2LE_U32_C(UINT32_C(0x00000070)) +#define NTFS_AT_DATA RT_H2LE_U32_C(UINT32_C(0x00000080)) +/** NTFSATINDEXROOT */ +#define NTFS_AT_INDEX_ROOT RT_H2LE_U32_C(UINT32_C(0x00000090)) +#define NTFS_AT_INDEX_ALLOCATION RT_H2LE_U32_C(UINT32_C(0x000000a0)) +#define NTFS_AT_BITMAP RT_H2LE_U32_C(UINT32_C(0x000000b0)) +#define NTFS_AT_REPARSE_POINT RT_H2LE_U32_C(UINT32_C(0x000000c0)) +#define NTFS_AT_EA_INFORMATION RT_H2LE_U32_C(UINT32_C(0x000000d0)) +#define NTFS_AT_EA RT_H2LE_U32_C(UINT32_C(0x000000e0)) +#define NTFS_AT_PROPERTY_SET RT_H2LE_U32_C(UINT32_C(0x000000f0)) +#define NTFS_AT_LOGGED_UTILITY_STREAM RT_H2LE_U32_C(UINT32_C(0x00000100)) +#define NTFS_AT_FIRST_USER_DEFINED RT_H2LE_U32_C(UINT32_C(0x00001000)) +#define NTFS_AT_END RT_H2LE_U32_C(UINT32_C(0xffffffff)) +/** @} */ + +/** @name NTFS_AF_XXX - Attribute flags. + * @{ */ +#define NTFS_AF_COMPR_FMT_NONE RT_H2LE_U16_C(UINT16_C(0x0000)) +/** See RtlCompressBuffer / COMPRESSION_FORMAT_LZNT1. */ +#define NTFS_AF_COMPR_FMT_LZNT1 RT_H2LE_U16_C(UINT16_C(0x0001)) +/** See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */ +#define NTFS_AF_COMPR_FMT_XPRESS RT_H2LE_U16_C(UINT16_C(0x0002)) +/** See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */ +#define NTFS_AF_COMPR_FMT_XPRESS_HUFF RT_H2LE_U16_C(UINT16_C(0x0003)) +#define NTFS_AF_COMPR_FMT_MASK RT_H2LE_U16_C(UINT16_C(0x00ff)) +#define NTFS_AF_ENCRYPTED RT_H2LE_U16_C(UINT16_C(0x4000)) +#define NTFS_AF_SPARSE RT_H2LE_U16_C(UINT16_C(0x8000)) +/** @} */ + +/** + * NTFS attribute header. + * + * This has three forms: + * - Resident + * - Non-resident, no compression + * - Non-resident, compressed. + * + * Each form translates to a different header size. + */ +typedef struct NTFSATTRIBHDR +{ + /** 0x00: Attribute type (NTFS_AT_XXX). */ + uint32_t uAttrType; + /** 0x04: Length of this attribute (resident part). */ + uint32_t cbAttrib; + /** 0x08: Set (1) if non-resident attribute, 0 if resident. */ + uint8_t fNonResident; + /** 0x09: Attribute name length (can be zero). */ + uint8_t cwcName; + /** 0x0a: Offset of the name string (relative to the start of this header). */ + uint16_t offName; + /** 0x0c: NTFS_AF_XXX. */ + uint16_t fFlags; + /** 0x0e: Attribute instance number. Unique within the MFT record. */ + uint16_t idAttrib; + /** 0x10: Data depending on the fNonResident member value. */ + union + { + /** Resident attributes. */ + struct + { + /** 0x10: Attribute value length. */ + uint32_t cbValue; + /** 0x14: Offset of the value (relative to the start of this header). */ + uint16_t offValue; + /** 0x16: NTFS_RES_AF_XXX. */ + uint8_t fFlags; + /** 0x17: Reserved. */ + uint8_t bReserved; + } Res; + + /** Non-resident attributes. */ + struct + { + /** 0x10: The first virtual cluster containing data. + * + * This is mainly for internal checking when the run list doesn't fit in one + * MFT record. It can also be used to avoid recording a sparse run at the + * beginning of the data covered by this attribute record. */ + int64_t iVcnFirst; + /** 0x18: The last virtual cluster containing data (inclusive). */ + int64_t iVcnLast; + /** 0x20: Offset of the mapping pair program. This program gives us a mapping + * between VNC and LCN for the attribute value. */ + uint16_t offMappingPairs; + /** 0x22: Power of two compression unit size in clusters (cbCluster << uCompessionUnit). + * Zero means uncompressed. */ + uint8_t uCompressionUnit; + /** 0x23: Reserved */ + uint8_t abReserved[5]; + /** 0x28: Allocated size (rouneded to cluster). + * @note Only set in the first attribute record (iVcnFirst == 0). */ + int64_t cbAllocated; + /** 0x30: The exact length of the data. + * @note Only set in the first attribute record (iVcnFirst == 0). */ + int64_t cbData; + /** 0x38: The length of the initialized data. (Not necessarily + * rounded up to cluster size.) + * @note Only set in the first attribute record (iVcnFirst == 0). */ + int64_t cbInitialized; + /** 0x40: Compressed size if compressed, otherwise absent. */ + int64_t cbCompressed; + } NonRes; + } u; +} NTFSATTRIBHDR; +AssertCompileSize(NTFSATTRIBHDR, 0x48); +AssertCompileMemberOffset(NTFSATTRIBHDR, u.Res, 0x10); +AssertCompileMemberOffset(NTFSATTRIBHDR, u.Res.bReserved, 0x17); +AssertCompileMemberOffset(NTFSATTRIBHDR, u.NonRes, 0x10); +AssertCompileMemberOffset(NTFSATTRIBHDR, u.NonRes.cbCompressed, 0x40); +/** Pointer to a NTFS attribute header. */ +typedef NTFSATTRIBHDR *PNTFSATTRIBHDR; +/** Pointer to a const NTFS attribute header. */ +typedef NTFSATTRIBHDR const *PCNTFSATTRIBHDR; + +/** @name NTFSATTRIBHDR_SIZE_XXX - Attribute header sizes. + * @{ */ +/** Attribute header size for resident values. */ +#define NTFSATTRIBHDR_SIZE_RESIDENT (0x18) +/** Attribute header size for uncompressed non-resident values. */ +#define NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED (0x40) +/** Attribute header size for compressed non-resident values. */ +#define NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED (0x48) +/** @} */ + +/** Get the pointer to the embedded name from an attribute. + * @note ASSUMES the caller check that there is a name. */ +#define NTFSATTRIBHDR_GET_NAME(a_pAttrHdr) ( (PRTUTF16)((uintptr_t)(a_pAttrHdr) + (a_pAttrHdr)->offName) ) + +/** Get the pointer to resident value. + * @note ASSUMES the caller checks that it's resident and valid. */ +#define NTFSATTRIBHDR_GET_RES_VALUE_PTR(a_pAttrHdr) ( (uint8_t *)(a_pAttrHdr) + (a_pAttrHdr)->u.Res.offValue ) + + +/** @name NTFS_RES_AF_XXX + * @{ */ +/** Attribute is referenced in an index. */ +#define NTFS_RES_AF_INDEXED UINT8_C(0x01) +/** @} */ + +/** + * Attribute list entry (NTFS_AT_ATTRIBUTE_LIST). + * + * This is used to deal with a file having attributes in more than one MFT + * record. A prominent example is an fragment file (unnamed data attribute) + * which mapping pairs doesn't fit in a single MFT record. + * + * This attribute can be non-resident, however it's mapping pair program must + * fit in the base MFT record. + */ +typedef struct NTFSATLISTENTRY +{ + /** 0x00: Attribute type (NTFS_AT_XXX). */ + uint32_t uAttrType; + /** 0x04: Length of this entry. */ + uint16_t cbEntry; + /** 0x06: Attribute name length (zero if none). */ + uint8_t cwcName; + /** 0x07: Name offset. */ + uint8_t offName; + /** 0x08: The first VNC for this part of the attribute value. */ + int64_t iVcnFirst; + /** 0x10: The MFT record holding the actual attribute. */ + NTFSMFTREF InMftRec; + /** 0x18: Attribute instance number. Unique within the MFT record. */ + uint16_t idAttrib; + /** 0x1a: Maybe where the attribute name starts. */ + RT_FLEXIBLE_ARRAY_EXTENSION + RTUTF16 wszName[RT_FLEXIBLE_ARRAY]; +} NTFSATLISTENTRY; +AssertCompileMemberOffset(NTFSATLISTENTRY, idAttrib, 0x18); +/** Pointer to a NTFS attribute list entry. */ +typedef NTFSATLISTENTRY *PNTFSATLISTENTRY; +/** Pointer to a const NTFS attribute list entry. */ +typedef NTFSATLISTENTRY const *PCNTFSATLISTENTRY; + +/** Unaligned minimum entry size (no name). */ +#define NTFSATLISTENTRY_SIZE_MINIMAL 0x1a + + + +/** + * NTFS standard file info attribute (NTFS_AT_STANDARD_INFORMATION). + */ +typedef struct NTFSATSTDINFO +{ + /** 0x00: Creation timestamp. */ + int64_t iCreationTime; + /** 0x08: Last data modification timestamp. */ + int64_t iLastDataModTime; + /** 0x10: Last MFT record modification timestamp. */ + int64_t iLastMftModTime; + /** 0x18: Last access timestamp. */ + int64_t iLastAccessTime; + /** 0x20: File attributes. */ + uint32_t fFileAttribs; + /** 0x24: Maximum number of file versions allowed. + * @note NTFS 3.x, padding in 1.2 */ + uint32_t cMaxFileVersions; + /** 0x28: Current file version number. + * @note NTFS 3.x, padding in 1.2 */ + uint32_t uFileVersion; + /** 0x2c: Class ID (whatever that is). + * @note NTFS 3.x, padding in 1.2 */ + uint32_t idClass; + /** 0x30: Owner ID. + * Translated via $Q index in NTFS_MFT_IDX_EXTENDED/$Quota. + * @note NTFS 3.x, not present in 1.2 */ + uint32_t idOwner; + /** 0x34: Security ID. Translated via $SII index and $SDS data stream in + * NTFS_MFT_IDX_SECURITY. + * @note NTFS 3.x, not present in 1.2 */ + uint32_t idSecurity; + /** 0x38: Total quota charged for this file. + * @note NTFS 3.x, not present in 1.2 */ + uint64_t cbQuotaChared; + /** 0x40: Last update sequence number, index into $UsnJrnl. + * @note NTFS 3.x, not present in 1.2 */ + uint64_t idxUpdateSequence; +} NTFSATSTDINFO; +AssertCompileSize(NTFSATSTDINFO, 0x48); +/** Pointer to NTFS standard file info. */ +typedef NTFSATSTDINFO *PNTFSATSTDINFO; +/** Pointer to const NTFS standard file info. */ +typedef NTFSATSTDINFO const *PCNTFSATSTDINFO; + +/** The size of NTFSATSTDINFO in NTFS v1.2 and earlier. */ +#define NTFSATSTDINFO_SIZE_NTFS_V12 (0x30) + +/** @name NTFS_FA_XXX - NTFS file attributes (host endian). + * @{ */ +#define NTFS_FA_READONLY UINT32_C(0x00000001) +#define NTFS_FA_HIDDEN UINT32_C(0x00000002) +#define NTFS_FA_SYSTEM UINT32_C(0x00000004) +#define NTFS_FA_DIRECTORY UINT32_C(0x00000010) +#define NTFS_FA_ARCHIVE UINT32_C(0x00000020) +#define NTFS_FA_DEVICE UINT32_C(0x00000040) +#define NTFS_FA_NORMAL UINT32_C(0x00000080) +#define NTFS_FA_TEMPORARY UINT32_C(0x00000100) +#define NTFS_FA_SPARSE_FILE UINT32_C(0x00000200) +#define NTFS_FA_REPARSE_POINT UINT32_C(0x00000400) +#define NTFS_FA_COMPRESSED UINT32_C(0x00000800) +#define NTFS_FA_OFFLINE UINT32_C(0x00001000) +#define NTFS_FA_NOT_CONTENT_INDEXED UINT32_C(0x00002000) +#define NTFS_FA_ENCRYPTED UINT32_C(0x00004000) +#define NTFS_FA_VALID_FLAGS UINT32_C(0x00007fb7) +#define NTFS_FA_VALID_SET_FLAGS UINT32_C(0x000031a7) +#define NTFS_FA_DUP_FILE_NAME_INDEX_PRESENT UINT32_C(0x10000000) /**< This means directory apparently. */ +#define NTFS_FA_DUP_VIEW_INDEX_PRESENT UINT32_C(0x20000000) /**< ?? */ +/** @} */ + + + +/** + * NTFS filename attribute (NTFS_AT_FILENAME). + */ +typedef struct NTFSATFILENAME +{ + /** 0x00: The parent directory MFT record. */ + NTFSMFTREF ParentDirMftRec; + /** 0x08: Creation timestamp. */ + int64_t iCreationTime; + /** 0x10: Last data modification timestamp. */ + int64_t iLastDataModTime; + /** 0x18: Last MFT record modification timestamp. */ + int64_t iLastMftModTime; + /** 0x20: Last access timestamp. */ + int64_t iLastAccessTime; + /** 0x28: Allocated disk space for the unnamed data attribute. */ + int64_t cbAllocated; + /** 0x30: Actual size of unnamed data attribute. */ + int64_t cbData; + /** 0x38: File attributes (NTFS_FA_XXX). */ + uint32_t fFileAttribs; + union + { + /** 0x3c: Packed EA length. */ + uint16_t cbPackedEas; + /** 0x3c: Reparse tag, if no EAs. */ + uint32_t uReparseTag; + } u; + /** 0x40: Filename length in unicode chars. */ + uint8_t cwcFilename; + /** 0x41: Filename type (NTFS_FILENAME_T_XXX). */ + uint8_t fFilenameType; + /** 0x42: The filename. */ + RT_FLEXIBLE_ARRAY_EXTENSION + RTUTF16 wszFilename[RT_FLEXIBLE_ARRAY]; +} NTFSATFILENAME; +AssertCompileMemberOffset(NTFSATFILENAME, cbData, 0x30); +AssertCompileMemberOffset(NTFSATFILENAME, u.cbPackedEas, 0x3c); +AssertCompileMemberOffset(NTFSATFILENAME, u.uReparseTag, 0x3c); +AssertCompileMemberOffset(NTFSATFILENAME, wszFilename, 0x42); +/** Pointer to a NTFS filename attribute. */ +typedef NTFSATFILENAME *PNTFSATFILENAME; +/** Pointer to a const NTFS filename attribute. */ +typedef NTFSATFILENAME const *PCNTFSATFILENAME; + +/** @name NTFS_FILENAME_T_XXX - filename types + * @{ */ +#define NTFS_FILENAME_T_POSIX 0 +#define NTFS_FILENAME_T_WINDOWS 1 +#define NTFS_FILENAME_T_DOS 2 +#define NTFS_FILENAME_T_WINDOWS_AND_DSO 3 +/** @} */ + + +/** + * NTFS volume information (NTFS_AT_VOLUME_INFORMATION). + * + * This is found in the special NTFS_MFT_IDX_VOLUME file. + */ +typedef struct NTFSATVOLUMEINFO +{ + /** 0x00: Reserved bytes. */ + uint8_t abReserved[8]; + /** 0x08: Major NTFS version number. */ + uint8_t uMajorVersion; + /** 0x09: Minor NTFS version number. */ + uint8_t uMinorVersion; + /** 0x0a: Volume flags (NTFS_VOLUME_F_XXX) */ + uint16_t fFlags; +} NTFSATVOLUMEINFO; +AssertCompileSize(NTFSATVOLUMEINFO, 12); +/** Pointer to NTFS volume information. */ +typedef NTFSATVOLUMEINFO *PNTFSATVOLUMEINFO; +/** Pointer to const NTFS volume information. */ +typedef NTFSATVOLUMEINFO const *PCNTFSATVOLUMEINFO; + +/** @name NTFS_VOLUME_F_XXX + * @{ */ +#define NTFS_VOLUME_F_DIRTY RT_H2LE_U16_C(0x0001) /**< Volume is dirty. */ +#define NTFS_VOLUME_F_RESIZE_LOG_FILE RT_H2LE_U16_C(0x0002) /**< */ +#define NTFS_VOLUME_F_UPGRADE_ON_MOUNT RT_H2LE_U16_C(0x0004) /**< */ +#define NTFS_VOLUME_F_MOUNTED_ON_NT4 RT_H2LE_U16_C(0x0008) /**< */ +#define NTFS_VOLUME_F_DELETE_USN_UNDERWAY RT_H2LE_U16_C(0x0010) /**< */ +#define NTFS_VOLUME_F_REPAIR_OBJECT_ID RT_H2LE_U16_C(0x0020) /**< */ +#define NTFS_VOLUME_F_CHKDSK_UNDERWAY RT_H2LE_U16_C(0x4000) /**< */ +#define NTFS_VOLUME_F_MODIFIED_BY_CHKDSK RT_H2LE_U16_C(0x8000) /**< */ + +#define NTFS_VOLUME_F_KNOWN_MASK RT_H2LE_U16_C(0xc03f) +#define NTFS_VOLUME_F_MOUNT_READONLY_MASK RT_H2LE_U16_C(0xc027) +/** @} */ + + +/** The attribute name used by the index attributes on NTFS directories, + * ASCII stirng variant. */ +#define NTFS_DIR_ATTRIBUTE_NAME "$I30" + +/** + * NTFS index header. + * + * This is used by NTFSATINDEXROOT and NTFSATINDEXALLOC as a prelude to the + * sequence of entries in a node. + */ +typedef struct NTFSINDEXHDR +{ + /** 0x00: Offset of the first entry relative to this header. */ + uint32_t offFirstEntry; + /** 0x04: Current index size in bytes, including this header. */ + uint32_t cbUsed; + /** 0x08: Number of bytes allocated for the index (including this header). */ + uint32_t cbAllocated; + /** 0x0c: Flags (NTFSINDEXHDR_F_XXX). */ + uint8_t fFlags; + /** 0x0d: Reserved bytes. */ + uint8_t abReserved[3]; + /* NTFSIDXENTRYHDR sequence typically follows here */ +} NTFSINDEXHDR; +AssertCompileSize(NTFSINDEXHDR, 16); +/** Pointer to a NTFS index header. */ +typedef NTFSINDEXHDR *PNTFSINDEXHDR; +/** Pointer to a const NTFS index header. */ +typedef NTFSINDEXHDR const *PCNTFSINDEXHDR; + +/** @name NTFSINDEXHDR_F_XXX + * @{ */ +/** An internal node (as opposed to a leaf node if clear). + * This means that the entries will have trailing node references (VCN). */ +#define NTFSINDEXHDR_F_INTERNAL UINT8_C(0x01) +/** @} */ + +/** Gets the pointer to the first entry header for an index. */ +#define NTFSINDEXHDR_GET_FIRST_ENTRY(a_pIndexHdr) \ + ( (PNTFSIDXENTRYHDR)((uint8_t *)(a_pIndexHdr) + RT_LE2H_U32((a_pIndexHdr)->offFirstEntry)) ) + + +/** + * NTFS index root node (NTFS_AT_INDEX_ROOT). + * + * This is a generic index structure, but is most prominently used for + * implementating directories. The index is structured like B-tree, meaning + * each node contains multiple entries, and each entry contains data regardless + * of whether it's a leaf node or not. + * + * The index is sorted in ascending order according to the collation rules + * defined by the root node (NTFSATINDEXROOT::uCollationRules, see also (see + * NTFS_COLLATION_XXX). + * + * @note The root directory contains a '.' entry, others don't. + */ +typedef struct NTFSATINDEXROOT +{ + /** 0x00: The index type (NTFSATINDEXROOT_TYPE_XXX). */ + uint32_t uType; + /** 0x04: The sorting rules to use (NTFS_COLLATION_XXX). */ + uint32_t uCollationRules; + /** 0x08: Number of bytes in + * Index node size (in bytes). */ + uint32_t cbIndexNode; + /** 0x0c: Number of node addresses per node. + * This sounds weird right? A subnode is generally addressed as a virtual + * cluster when cbIndexNode >= cbCluster, but when clusters are large NTFS uses + * 512 bytes chunks. + * + * (You would've thought it would be simpler to just use cbIndexNode as the + * addressing unit, maybe storing the log2 here to avoid a ffs call.) */ + uint8_t cAddressesPerIndexNode; + /** 0x0d: Reserved padding or something. */ + uint8_t abReserved[3]; + /** 0x10: Index header detailing the entries that follows. */ + NTFSINDEXHDR Hdr; + /* 0x20: NTFSIDXENTRYHDR sequence typically follows here */ +} NTFSATINDEXROOT; +AssertCompileSize(NTFSATINDEXROOT, 32); +/** Pointer to a NTFS index root. */ +typedef NTFSATINDEXROOT *PNTFSATINDEXROOT; +/** Pointer to a const NTFS index root. */ +typedef NTFSATINDEXROOT const *PCNTFSATINDEXROOT; + +/** @name NTFSATINDEXROOT_TYPE_XXX + * @{ */ +/** View index. */ +#define NTFSATINDEXROOT_TYPE_VIEW RT_H2LE_U32_C(UINT32_C(0x00000000)) +/** Directory index, NTFSATFILENAME follows NTFSINDEXENTRY. */ +#define NTFSATINDEXROOT_TYPE_DIR RT_H2LE_U32_C(UINT32_C(0x00000030)) +/** @} */ + +/** @name NTFS_COLLATION_XXX - index sorting rules + * @{ */ +/** Little endian binary compare (or plain byte compare if you like). */ +#define NTFS_COLLATION_BINARY RT_H2LE_U32_C(UINT32_C(0x00000000)) +/** Same as NTFS_COLLATION_UNICODE_STRING. */ +#define NTFS_COLLATION_FILENAME RT_H2LE_U32_C(UINT32_C(0x00000001)) +/** Compare the uppercased unicode characters. */ +#define NTFS_COLLATION_UNICODE_STRING RT_H2LE_U32_C(UINT32_C(0x00000002)) + +/** Single little endian 32-bit unsigned integer value as sort key. */ +#define NTFS_COLLATION_UINT32 RT_H2LE_U32_C(UINT32_C(0x00000010)) +/** Little endian SID value as sort key. */ +#define NTFS_COLLATION_SID RT_H2LE_U32_C(UINT32_C(0x00000011)) +/** Two little endian 32-bit unsigned integer values used as sorting key. */ +#define NTFS_COLLATION_UINT32_PAIR RT_H2LE_U32_C(UINT32_C(0x00000012)) +/** Sequence of little endian 32-bit unsigned integer values used as sorting key. */ +#define NTFS_COLLATION_UINT32_SEQ RT_H2LE_U32_C(UINT32_C(0x00000013)) +/** @} */ + + +/** + * NTFS index non-root node. + */ +typedef struct NTFSATINDEXALLOC +{ + /** 0x00: Header with NTFSREC_MAGIC_INDEX_ALLOC. */ + NTFSRECHDR RecHdr; + /** 0x08: Log file sequence number. */ + uint64_t uLsn; + /** 0x10: The node address of this node (for consistency checking and + * perhaps data reconstruction). + * @see NTFSATINDEXROOT::cAddressesPerIndexNode for node addressing. */ + int64_t iSelfAddress; + /** 0x18: Index header detailing the entries that follows. */ + NTFSINDEXHDR Hdr; + /* 0x28: NTFSIDXENTRYHDR sequence typically follows here */ +} NTFSATINDEXALLOC; +AssertCompileSize(NTFSATINDEXALLOC, 40); +/** Pointer to a NTFS index non-root node. */ +typedef NTFSATINDEXALLOC *PNTFSATINDEXALLOC; +/** Pointer to a const NTFS index non-root node. */ +typedef NTFSATINDEXALLOC const *PCNTFSATINDEXALLOC; + +/** NTFS 'INDX' attribute magic value (NTFSATINDEXALLOC). + * @todo sort out the record / attribute name clash here. */ +#define NTFSREC_MAGIC_INDEX_ALLOC RT_H2LE_U32_C(UINT32_C(0x58444e49)) + + +/** + * NTFS index entry header. + * + * Each entry in a node starts with this header. It is immediately followed by + * the key data (NTFSIDXENTRYHDR::cbKey). When + * + */ +typedef struct NTFSIDXENTRYHDR +{ + union + { + /** 0x00: NTFSATINDEXROOT_TYPE_DIR: Reference to the MFT record being indexed here. + * @note This is invalid if NTFSIDXENTRYHDR_F_END is set (no key data). */ + NTFSMFTREF FileMftRec; + /** 0x00: NTFSATINDEXROOT_TYPE_VIEW: Go figure later if necessary. */ + struct + { + /** 0x00: Offset to the data relative to this header. + * @note This is invalid if NTFSIDXENTRYHDR_F_END is set (no key data). */ + uint16_t offData; + /** 0x02: Size of data at offData. + * @note This is invalid if NTFSIDXENTRYHDR_F_END is set (no key data). */ + uint16_t cbData; + /** 0x04: Reserved. */ + uint32_t uReserved; + } View; + } u; + + /** 0x08: Size of this entry, 8-byte aligned. */ + uint16_t cbEntry; + /** 0x0a: Key length (unaligned). */ + uint16_t cbKey; + /** 0x0c: Entry flags, NTFSIDXENTRYHDR_F_XXX. */ + uint16_t fFlags; + /** 0x0e: Reserved. */ + uint16_t uReserved; +} NTFSIDXENTRYHDR; +AssertCompileSize(NTFSIDXENTRYHDR, 16); +/** Pointer to a NTFS index entry header. */ +typedef NTFSIDXENTRYHDR *PNTFSIDXENTRYHDR; +/** Pointer to a const NTFS index entry header. */ +typedef NTFSIDXENTRYHDR const *PCNTFSIDXENTRYHDR; + +/** @name NTFSIDXENTRYHDR_F_XXX - NTFSIDXENTRYHDR::fFlags + * @{ */ +/** Indicates an internal node (as opposed to a leaf node). + * This indicates that there is a 64-bit integer value at the very end of the + * entry (NTFSIDXENTRYHDR::cbEntry - 8) giving the virtual cluster number of the + * subnode. The subnode and all its decendants contain keys that are lower than + * the key in this entry. + */ +#define NTFSIDXENTRYHDR_F_INTERNAL RT_H2LE_U16_C(UINT16_C(0x0001)) +/** Set if special end entry in a node. + * This does not have any key data, but can point to a subnode with + * higher keys. */ +#define NTFSIDXENTRYHDR_F_END RT_H2LE_U16_C(UINT16_C(0x0002)) +/** @} */ + +/** Gets the pointer to the next index entry header. */ +#define NTFSIDXENTRYHDR_GET_NEXT(a_pEntryHdr) \ + ( (PNTFSIDXENTRYHDR)((uintptr_t)(a_pEntryHdr) + RT_LE2H_U16((a_pEntryHdr)->cbEntry)) ) +/** Gets the subnode address from an index entry. + * @see NTFSATINDEXROOT::cAddressesPerIndexNode for node addressing. + * @note Only invoke when NTFSIDXENTRYHDR_F_INTERNAL is set! */ +#define NTFSIDXENTRYHDR_GET_SUBNODE(a_pEntryHdr) \ + ( *(int64_t *)((uintptr_t)(a_pEntryHdr) + RT_LE2H_U16((a_pEntryHdr)->cbEntry) - sizeof(int64_t)) ) + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_ntfs_h */ + diff --git a/include/iprt/formats/omf.h b/include/iprt/formats/omf.h new file mode 100644 index 00000000..b5ffb01d --- /dev/null +++ b/include/iprt/formats/omf.h @@ -0,0 +1,260 @@ +/* $Id: omf.h $ */ +/** @file + * IPRT - Relocatable Object Module Format (OMF). + * + * @remarks For a more details description, see specification from Tools + * Interface Standards (TIS), version 1.1 dated May 2015. + * Typically named found as OMF_v1.1.pdf. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_omf_h +#define IPRT_INCLUDED_formats_omf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_omf Relocatable Object Module Format (OMF) structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/** + * OMF record header. + */ +#pragma pack(1) +typedef struct OMFRECHDR +{ + /** The record type. */ + uint8_t bType; + /** The record length, excluding the this header. */ + uint16_t cbLen; +} OMFRECHDR; +#pragma pack() +AssertCompileSize(OMFRECHDR, 3); +/** Pointer to an OMF header. */ +typedef OMFRECHDR *POMFRECHDR; +/** Pointer to a const OMF header. */ +typedef OMFRECHDR *PCOMFRECHDR; + +/** The max OMF record length, including the header. */ +#define OMF_MAX_RECORD_LENGTH UINT16_C(1024) + +/** The max OMF record payload, including CRC byte. */ +#define OMF_MAX_RECORD_PAYLOAD UINT16_C(1021) + + +/** @name OMF Record Types (OMFRECHDR::bType). + * @{ */ +/** Record type flag indicating 32-bit record. */ +#define OMF_REC32 UINT8_C(0x01) +/** Object file header record. + * Is followed by a length prefixed string */ +#define OMF_THEADR UINT8_C(0x80) +/** Comment record. + * Is followed by a comment type byte and a commen class byte, thereafter comes + * type specific byte sequence. */ +#define OMF_COMENT UINT8_C(0x88) +/** Local name table referenced by segment and group defintions. + * Array of length prefixed strings. Multi record. */ +#define OMF_LNAMES UINT8_C(0x96) +/** 16-bit segment definition. + * Complicated, see TIS docs. */ +#define OMF_SEGDEF16 UINT8_C(0x98) +/** 32-bit segment definition. + * Complicated, see TIS docs. */ +#define OMF_SEGDEF32 UINT8_C(0x99) +/** Segment group definition. + * Starts with an LNAMES index (one or two bytes) of the group name. Followed + * by an array which entries consists of a 0xff byte and a segment + * defintion index (one or two bytes). */ +#define OMF_GRPDEF UINT8_C(0x9a) +/** External symbol defintions. + * Array where each entry is a length prefixed symbol name string followed by a + * one or two byte type number. */ +#define OMF_EXTDEF UINT8_C(0x8c) +/** 16-but public symbol definitions. + * Starts with a group index (one or two bytes) and a segment index (ditto) + * which indicates which group/segment the symbols belong to. + * Is followed by an array with entries consiting of a length prefixed symbol + * name string, a two byte segment offset, and a one or two byte type index. */ +#define OMF_PUBDEF16 UINT8_C(0x90) +/** 32-but public symbol definitions. + * Identical to #OMF_PUBDEF16 except that the symbol offset field is four + * byte. */ +#define OMF_PUBDEF32 UINT8_C(0x91) +/** 16-bit local symbol definitions. + * Same format as #OMF_PUBDEF16. */ +#define OMF_LPUBDEF16 UINT8_C(0xb6) +/** 16-bit local symbol definitions. + * Same format as #OMF_PUBDEF32. */ +#define OMF_LPUBDEF32 UINT8_C(0xb7) +/** Logical enumerated data record (a chunk of raw segment bits). + * Starts with the index of the segment it contributes to (one or two bytes) and + * is followed by the offset into the segment of the bytes (two bytes). + * After that comes the raw data bytes. */ +#define OMF_LEDATA16 UINT8_C(0xa0) +/** Logical enumerated data record (a chunk of raw segment bits). + * Identical to #OMF_LEDATA16 except that is has a the segment offset field is + * four bytes. */ +#define OMF_LEDATA32 UINT8_C(0xa1) +/** 16-bit fixup record. + * Complicated, see TIS docs. */ +#define OMF_FIXUPP16 UINT8_C(0x9c) +/** 32-bit fixup record. + * Complicated, see TIS docs. */ +#define OMF_FIXUPP32 UINT8_C(0x9d) +/** 16-bit line numbers record. */ +#define OMF_LINNUM16 UINT8_C(0x94) +/** 32-bit line numbers record. */ +#define OMF_LINNUM32 UINT8_C(0x95) +/** 16-bit object file end record. + * Duh! wrong bitfield order. + * + * Starts with a byte bitfield indicating module type: bit 0 is set if this is a + * main program module; bit 1 is set if this is a start address is available; + * bits 2 thru 6 are reserved and must be zero; bit 7 is set to indicate + * a non-absolute start address. + * + * When bit 1 is set what follow is: A FIXUPP byte, one or two byte frame datum, + * one or two byte target datum, and a 2 byte target displacement. */ +#define OMF_MODEND16 UINT8_C(0x8a) +/** 32-bit object file end record. + * Identical to #OMF_MODEND16 except that is has a 4 byte target + * displacement field. */ +#define OMF_MODEND32 UINT8_C(0x8b) +/** @} */ + +/** @name OMF COMENT Type Flags + * @{ */ +/** Comment type: Don't remove comment when object is manipulated. */ +#define OMF_CTYP_NO_PURGE UINT8_C(0x80) +/** Comment type: Don't include in object listing. */ +#define OMF_CTYP_NO_LIST UINT8_C(0x40) +/** @} */ + +/** @name OMF COMENT Classes + * @{ */ +/** Comment class: Dependency file. + * Is followed by a dword timestamp (1980 based?) and a length prefix + * filename string. */ +#define OMF_CCLS_DEP_FILE UINT8_C(0x88) +/** Comment class: Link pass separator. + * Contains a byte with the value 01 to indicate the linker can stop pass 1 + * processing now. */ +#define OMF_CCLS_LINK_PASS_SEP UINT8_C(0xa2) +/** Comment class: Borland type information. */ +#define OMF_CCLS_BORLAND_TYPES UINT8_C(0xe3) +/** Comment class: Borland symbol information. */ +#define OMF_CCLS_BORLAND_SYMBOLS UINT8_C(0xe6) +/** Comment class: Borland source file (applies to subsequent LINNUMs). */ +#define OMF_CCLS_BORLAND_SRC_FILE UINT8_C(0xe8) +/** Comment class: Borland dependency files. */ +#define OMF_CCLS_BORLAND_DEP_FILES UINT8_C(0xe9) +/** @} */ + +/** @name OMF SEGDEF Attrib. + * @{ */ +#define OMF_SEG_ATTR_ALIGN_ABS (UINT8_C(0) << 5) /**< SEGDEF attrib A: absolute - frame and offset fields present. */ +#define OMF_SEG_ATTR_ALIGN_BYTE (UINT8_C(1) << 5) /**< SEGDEF attrib A: 1-byte alignment. */ +#define OMF_SEG_ATTR_ALIGN_WORD (UINT8_C(2) << 5) /**< SEGDEF attrib A: 2-byte alignment. */ +#define OMF_SEG_ATTR_ALIGN_PARA (UINT8_C(3) << 5) /**< SEGDEF attrib A: 16-byte alignment. */ +#define OMF_SEG_ATTR_ALIGN_PAGE (UINT8_C(4) << 5) /**< SEGDEF attrib A: 4096-byte alignment (or 256-byte). */ +#define OMF_SEG_ATTR_ALIGN_DWORD (UINT8_C(5) << 5) /**< SEGDEF attrib A: 4-byte alignment. */ +#define OMF_SEG_ATTR_ALIGN_6 (UINT8_C(6) << 5) /**< SEGDEF attrib A: not supported (load-time locatable, paragraph aligned). */ +#define OMF_SEG_ATTR_ALIGN_7 (UINT8_C(7) << 5) /**< SEGDEF attrib A: undefined. */ +#define OMF_SEG_ATTR_ALIGN_MASK (UINT8_C(7) << 5) /**< SEGDEF attrib A: Mask for the alignment field. */ +#define OMF_SEG_ATTR_ALIGN_SHIFT 5 /**< SEGDEF attrib A: Shift count for the alignment field. */ + +#define OMF_SEG_ATTR_COMB_PRIVATE (UINT8_C(0) << 2) /**< SEGDEF attrib C: Private - do not combine with anyone. */ +#define OMF_SEG_ATTR_COMB_1 (UINT8_C(1) << 2) /**< SEGDEF attrib C: Reserved */ +#define OMF_SEG_ATTR_COMB_PUBLIC (UINT8_C(2) << 2) /**< SEGDEF attrib C: Public - append at offset meeting alignment. */ +#define OMF_SEG_ATTR_COMB_3 (UINT8_C(3) << 2) /**< SEGDEF attrib C: Reserved */ +#define OMF_SEG_ATTR_COMB_PUBLIC_4 (UINT8_C(4) << 2) /**< SEGDEF attrib C: Public - append at offset meeting alignment. */ +#define OMF_SEG_ATTR_COMB_STACK (UINT8_C(5) << 2) /**< SEGDEF attrib C: Stack - same as public, but forced byte alignment. */ +#define OMF_SEG_ATTR_COMB_COMMON (UINT8_C(6) << 2) /**< SEGDEF attrib C: Common - overlay using maximum size. */ +#define OMF_SEG_ATTR_COMB_PUBLIC_7 (UINT8_C(5) << 2) /**< SEGDEF attrib C: Public - append at offset meeting alignment. */ +#define OMF_SEG_ATTR_COMB_MASK (UINT8_C(7) << 2) /**< SEGDEF attrib C: Mask for the combination field. */ +#define OMF_SEG_ATTR_COMB_SHIFT 2 /**< SEGDEF attrib C: Shift count for the combination field. */ +#define OMF_SEG_ATTR_BIG UINT8_C(2) /**< SEGDEF attrib B: Big segment 64K / 4GB. */ +#define OMF_SEG_ATTR_USE32 UINT8_C(1) /**< SEGDEF attrib P: Indicates 32-bit data or code. */ +#define OMF_SEG_ATTR_USE16 UINT8_C(0) /**< SEGDEF attrib ~P: Just for spelling out !USE32. */ +/** @} */ + + +/** @name OMF FIXUPP Locations. + * @{ */ +#define OMF_FIX_LOC_8BIT_LOW_BYTE UINT8_C(0) /**< FIXUP location: low byte (offset or displacement). */ +#define OMF_FIX_LOC_16BIT_OFFSET UINT8_C(1) /**< FIXUP location: 16-bit offset. */ +#define OMF_FIX_LOC_16BIT_SEGMENT UINT8_C(2) /**< FIXUP location: 16-bit segment. */ +#define OMF_FIX_LOC_1616FAR UINT8_C(3) /**< FIXUP location: 16:16 far pointer. */ +#define OMF_FIX_LOC_8BIT_HIGH_BYTE UINT8_C(4) /**< FIXUP location: high byte (offset). Not supported by MS/IBM. */ +#define OMF_FIX_LOC_16BIT_OFFSET_LDR UINT8_C(5) /**< FIXUP location: 16-bit loader resolved offset, same a 1 for linker. PharLab conflict. */ +#define OMF_FIX_LOC_RESERVED_FAR1632 UINT8_C(6) /**< FIXUP location: PharLab 16:32 far pointers, not defined by MS/IBM. */ +#define OMF_FIX_LOC_RESERVED_7 UINT8_C(7) /**< FIXUP location: Not defined. */ +#define OMF_FIX_LOC_RESERVED_8 UINT8_C(8) /**< FIXUP location: Not defined. */ +#define OMF_FIX_LOC_32BIT_OFFSET UINT8_C(9) /**< FIXUP location: 32-bit offset. */ +#define OMF_FIX_LOC_RESERVED_10 UINT8_C(10) /**< FIXUP location: Not defined. */ +#define OMF_FIX_LOC_1632FAR UINT8_C(11) /**< FIXUP location: 16:32 far pointer. */ +#define OMF_FIX_LOC_RESERVED_12 UINT8_C(12) /**< FIXUP location: Not defined. */ +#define OMF_FIX_LOC_32BIT_OFFSET_LDR UINT8_C(13) /**< FIXUP location: 32-bit loader resolved offset, same as 9 for linker. */ +/** @} */ +/** @name OMF FIXUPP Targets + * @{ */ +#define OMF_FIX_T_SEGDEF UINT8_C(0) /**< FIXUP target: SEGDEF index. */ +#define OMF_FIX_T_GRPDEF UINT8_C(1) /**< FIXUP target: GRPDEF index. */ +#define OMF_FIX_T_EXTDEF UINT8_C(2) /**< FIXUP target: EXTDEF index. */ +#define OMF_FIX_T_FRAME_NO UINT8_C(3) /**< FIXUP target: Explicit frame number, not supported by MS/IBM. */ +#define OMF_FIX_T_SEGDEF_NO_DISP UINT8_C(4) /**< FIXUP target: SEGDEF index only, displacement take as 0. */ +#define OMF_FIX_T_GRPDEF_NO_DISP UINT8_C(5) /**< FIXUP target: GRPDEF index only, displacement take as 0. */ +#define OMF_FIX_T_EXTDEF_NO_DISP UINT8_C(6) /**< FIXUP target: EXTDEF index only, displacement take as 0. */ +/** @} */ +/** @name OMF FIXUPP Frames + * @{ */ +#define OMF_FIX_F_SEGDEF UINT8_C(0) /**< FIXUP frame: SEGDEF index. */ +#define OMF_FIX_F_GRPDEF UINT8_C(1) /**< FIXUP frame: GRPDEF index. */ +#define OMF_FIX_F_EXTDEF UINT8_C(2) /**< FIXUP frame: EXTDEF index. */ +#define OMF_FIX_F_FRAME_NO UINT8_C(3) /**< FIXUP frame: Explicit frame number, not supported by any linkers. */ +#define OMF_FIX_F_LXDATA_SEG UINT8_C(4) /**< FIXUP frame: Determined from the data being fixed up. (No index field.) */ +#define OMF_FIX_F_TARGET_SEG UINT8_C(5) /**< FIXUP frame: Determined from the target. (No index field.) */ +#define OMF_FIX_F_RESERVED_6 UINT8_C(6) /**< FIXUP frame: Reserved. */ +/** @} */ + + +/** @} */ +#endif /* !IPRT_INCLUDED_formats_omf_h */ + diff --git a/include/iprt/formats/pe.mac b/include/iprt/formats/pe.mac new file mode 100644 index 00000000..62bf83b1 --- /dev/null +++ b/include/iprt/formats/pe.mac @@ -0,0 +1,732 @@ +;; @file +; IPRT - Windows PE definitions for YASM/NASM. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_format_pe_mac +%define ___iprt_format_pe_mac + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +%define IMAGE_NT_SIGNATURE 0x00004550 + +; file header +%define IMAGE_FILE_MACHINE_I386 0x014c +%define IMAGE_FILE_MACHINE_AMD64 0x8664 + +%define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +%define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +%define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +%define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +%define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 +%define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +%define IMAGE_FILE_16BIT_MACHINE 0x0040 +%define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +%define IMAGE_FILE_32BIT_MACHINE 0x0100 +%define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +%define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +%define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +%define IMAGE_FILE_SYSTEM 0x1000 +%define IMAGE_FILE_DLL 0x2000 +%define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +%define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + + +; optional header +%define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10B +%define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20B + +%define IMAGE_SUBSYSTEM_UNKNOWN 0x0 +%define IMAGE_SUBSYSTEM_NATIVE 0x1 +%define IMAGE_SUBSYSTEM_WINDOWS_GUI 0x2 +%define IMAGE_SUBSYSTEM_WINDOWS_CUI 0x3 +%define IMAGE_SUBSYSTEM_OS2_GUI 0x4 +%define IMAGE_SUBSYSTEM_OS2_CUI 0x5 +%define IMAGE_SUBSYSTEM_POSIX_CUI 0x7 + +%define IMAGE_LIBRARY_PROCESS_INIT 0x0001 +%define IMAGE_LIBRARY_PROCESS_TERM 0x0002 +%define IMAGE_LIBRARY_THREAD_INIT 0x0004 +%define IMAGE_LIBRARY_THREAD_TERM 0x0008 +%define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 +%define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 +%define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 +%define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 +%define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + +%define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 0x10 + +%define IMAGE_DIRECTORY_ENTRY_EXPORT 0x0 +%define IMAGE_DIRECTORY_ENTRY_IMPORT 0x1 +%define IMAGE_DIRECTORY_ENTRY_RESOURCE 0x2 +%define IMAGE_DIRECTORY_ENTRY_EXCEPTION 0x3 +%define IMAGE_DIRECTORY_ENTRY_SECURITY 0x4 +%define IMAGE_DIRECTORY_ENTRY_BASERELOC 0x5 +%define IMAGE_DIRECTORY_ENTRY_DEBUG 0x6 +%define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 0x7 +%define IMAGE_DIRECTORY_ENTRY_COPYRIGHT IMAGE_DIRECTORY_ENTRY_ARCHITECTURE +%define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 0x8 +%define IMAGE_DIRECTORY_ENTRY_TLS 0x9 +%define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 0xa +%define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 0xb +%define IMAGE_DIRECTORY_ENTRY_IAT 0xc +%define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 0xd +%define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 0xe + + +; section header +%define IMAGE_SIZEOF_SHORT_NAME 0x8 + +%define IMAGE_SCN_TYPE_REG 0x00000000 +%define IMAGE_SCN_TYPE_DSECT 0x00000001 +%define IMAGE_SCN_TYPE_NOLOAD 0x00000002 +%define IMAGE_SCN_TYPE_GROUP 0x00000004 +%define IMAGE_SCN_TYPE_NO_PAD 0x00000008 +%define IMAGE_SCN_TYPE_COPY 0x00000010 + +%define IMAGE_SCN_CNT_CODE 0x00000020 +%define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +%define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 + +%define IMAGE_SCN_LNK_OTHER 0x00000100 +%define IMAGE_SCN_LNK_INFO 0x00000200 +%define IMAGE_SCN_TYPE_OVER 0x00000400 +%define IMAGE_SCN_LNK_REMOVE 0x00000800 +%define IMAGE_SCN_LNK_COMDAT 0x00001000 +%define IMAGE_SCN_MEM_PROTECTED 0x00004000 +%define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 +%define IMAGE_SCN_GPREL 0x00008000 +%define IMAGE_SCN_MEM_FARDATA 0x00008000 +%define IMAGE_SCN_MEM_SYSHEAP 0x00010000 +%define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +%define IMAGE_SCN_MEM_16BIT 0x00020000 +%define IMAGE_SCN_MEM_LOCKED 0x00040000 +%define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +%define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +%define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +%define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +%define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +%define IMAGE_SCN_ALIGN_16BYTES 0x00500000 +%define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +%define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +%define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +%define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +%define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +%define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +%define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +%define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +%define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 +%define IMAGE_SCN_ALIGN_MASK 0x00F00000 +%define IMAGE_SCN_ALIGN_SHIFT 20 + +%define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 +%define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +%define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +%define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +%define IMAGE_SCN_MEM_SHARED 0x10000000 +%define IMAGE_SCN_MEM_EXECUTE 0x20000000 +%define IMAGE_SCN_MEM_READ 0x40000000 +%define IMAGE_SCN_MEM_WRITE 0x80000000 + + +; relocations +%define IMAGE_REL_BASED_ABSOLUTE 0x0 +%define IMAGE_REL_BASED_HIGH 0x1 +%define IMAGE_REL_BASED_LOW 0x2 +%define IMAGE_REL_BASED_HIGHLOW 0x3 +%define IMAGE_REL_BASED_HIGHADJ 0x4 +%define IMAGE_REL_BASED_MIPS_JMPADDR 0x5 +%define IMAGE_REL_BASED_MIPS_JMPADDR16 0x9 +%define IMAGE_REL_BASED_IA64_IMM64 0x9 +%define IMAGE_REL_BASED_DIR64 0xa +%define IMAGE_REL_BASED_HIGH3ADJ 0xb + + +; imports +%define IMAGE_ORDINAL_FLAG32 0x80000000 +%define IMAGE_ORDINAL_FLAG64 UINT64_MAX(0x8000000000000000) + + +; debug dir +%define IMAGE_DEBUG_TYPE_UNKNOWN UINT32_C(0x0) +%define IMAGE_DEBUG_TYPE_COFF UINT32_C(0x1) +%define IMAGE_DEBUG_TYPE_CODEVIEW UINT32_C(0x2) +%define IMAGE_DEBUG_TYPE_FPO UINT32_C(0x3) +%define IMAGE_DEBUG_TYPE_MISC UINT32_C(0x4) +%define IMAGE_DEBUG_TYPE_EXCEPTION UINT32_C(0x5) +%define IMAGE_DEBUG_TYPE_FIXUP UINT32_C(0x6) +%define IMAGE_DEBUG_TYPE_OMAP_TO_SRC UINT32_C(0x7) +%define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC UINT32_C(0x8) +%define IMAGE_DEBUG_TYPE_BORLAND UINT32_C(0x9) +%define IMAGE_DEBUG_TYPE_RESERVED10 UINT32_C(0x10) + +%define IMAGE_DEBUG_MISC_EXENAME UINT32_C(1) + +; security directory +%define WIN_CERT_REVISION_1_0 UINT16_C(0x0100) +%define WIN_CERT_REVISION_2_0 UINT16_C(0x0200) + +%define WIN_CERT_TYPE_X509 UINT16_C(1) +%define WIN_CERT_TYPE_PKCS_SIGNED_DATA UINT16_C(2) +%define WIN_CERT_TYPE_RESERVED_1 UINT16_C(3) +%define WIN_CERT_TYPE_TS_STACK_SIGNED UINT16_C(4) +%define WIN_CERT_TYPE_EFI_PKCS115 UINT16_C(0x0ef0) +%define WIN_CERT_TYPE_EFI_GUID UINT16_C(0x0ef1) + + +; For .DBG files. +%define IMAGE_SEPARATE_DEBUG_SIGNATURE UINT16_C(0x4944) + +%define IMAGE_SIZE_OF_SYMBOL 18 +%define IMAGE_SIZE_OF_SYMBOL_EX 20 + +%define IMAGE_SYM_UNDEFINED INT16_C(0) +%define IMAGE_SYM_ABSOLUTE INT16_C(-1) +%define IMAGE_SYM_DEBUG INT16_C(-2) + +%define IMAGE_SYM_CLASS_END_OF_FUNCTION UINT8_C(0xff) ; -1 +%define IMAGE_SYM_CLASS_NULL UINT8_C(0) +%define IMAGE_SYM_CLASS_AUTOMATIC UINT8_C(1) +%define IMAGE_SYM_CLASS_EXTERNAL UINT8_C(2) +%define IMAGE_SYM_CLASS_STATIC UINT8_C(3) +%define IMAGE_SYM_CLASS_REGISTER UINT8_C(4) +%define IMAGE_SYM_CLASS_EXTERNAL_DEF UINT8_C(5) +%define IMAGE_SYM_CLASS_LABEL UINT8_C(6) +%define IMAGE_SYM_CLASS_UNDEFINED_LABEL UINT8_C(7) +%define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT UINT8_C(8) +%define IMAGE_SYM_CLASS_ARGUMENT UINT8_C(9) +%define IMAGE_SYM_CLASS_STRUCT_TAG UINT8_C(10) +%define IMAGE_SYM_CLASS_MEMBER_OF_UNION UINT8_C(11) +%define IMAGE_SYM_CLASS_UNION_TAG UINT8_C(12) +%define IMAGE_SYM_CLASS_TYPE_DEFINITION UINT8_C(13) +%define IMAGE_SYM_CLASS_UNDEFINED_STATIC UINT8_C(14) +%define IMAGE_SYM_CLASS_ENUM_TAG UINT8_C(15) +%define IMAGE_SYM_CLASS_MEMBER_OF_ENUM UINT8_C(16) +%define IMAGE_SYM_CLASS_REGISTER_PARAM UINT8_C(17) +%define IMAGE_SYM_CLASS_BIT_FIELD UINT8_C(18) +%define IMAGE_SYM_CLASS_FAR_EXTERNAL UINT8_C(68) +%define IMAGE_SYM_CLASS_BLOCK UINT8_C(100) +%define IMAGE_SYM_CLASS_FUNCTION UINT8_C(101) +%define IMAGE_SYM_CLASS_END_OF_STRUCT UINT8_C(102) +%define IMAGE_SYM_CLASS_FILE UINT8_C(103) +%define IMAGE_SYM_CLASS_SECTION UINT8_C(104) +%define IMAGE_SYM_CLASS_WEAK_EXTERNAL UINT8_C(105) +%define IMAGE_SYM_CLASS_CLR_TOKEN UINT8_C(107) + + +%define IMAGE_SYM_TYPE_NULL UINT16_C(0x0000) +%define IMAGE_SYM_TYPE_VOID UINT16_C(0x0001) +%define IMAGE_SYM_TYPE_CHAR UINT16_C(0x0002) +%define IMAGE_SYM_TYPE_SHORT UINT16_C(0x0003) +%define IMAGE_SYM_TYPE_INT UINT16_C(0x0004) +%define IMAGE_SYM_TYPE_LONG UINT16_C(0x0005) +%define IMAGE_SYM_TYPE_FLOAT UINT16_C(0x0006) +%define IMAGE_SYM_TYPE_DOUBLE UINT16_C(0x0007) +%define IMAGE_SYM_TYPE_STRUCT UINT16_C(0x0008) +%define IMAGE_SYM_TYPE_UNION UINT16_C(0x0009) +%define IMAGE_SYM_TYPE_ENUM UINT16_C(0x000a) +%define IMAGE_SYM_TYPE_MOE UINT16_C(0x000b) +%define IMAGE_SYM_TYPE_BYTE UINT16_C(0x000c) +%define IMAGE_SYM_TYPE_WORD UINT16_C(0x000d) +%define IMAGE_SYM_TYPE_UINT UINT16_C(0x000e) +%define IMAGE_SYM_TYPE_DWORD UINT16_C(0x000f) +%define IMAGE_SYM_TYPE_PCODE UINT16_C(0x8000) + +%define IMAGE_SYM_DTYPE_NULL UINT16_C(0x0) +%define IMAGE_SYM_DTYPE_POINTER UINT16_C(0x1) +%define IMAGE_SYM_DTYPE_FUNCTION UINT16_C(0x2) +%define IMAGE_SYM_DTYPE_ARRAY UINT16_C(0x3) + + +%define N_BTMASK UINT16_C(0x000f) +%define N_TMASK UINT16_C(0x0030) +%define N_TMASK1 UINT16_C(0x00c0) +%define N_TMASK2 UINT16_C(0x00f0) +%define N_BTSHFT 4 +%define N_TSHIFT 2 + + +;******************************************************************************* +;* Structures and Typedefs * +;******************************************************************************* + +struc IMAGE_FILE_HEADER + .Machine resw 1 ;;< 0x00 + .NumberOfSections resw 1 ;;< 0x02 + .TimeDateStamp resd 1 ;;< 0x04 + .PointerToSymbolTable resd 1 ;;< 0x08 + .NumberOfSymbols resd 1 ;;< 0x0c + .SizeOfOptionalHeader resw 1 ;;< 0x10 + .Characteristics resw 1 ;;< 0x12 +endstruc +AssertCompileSize(IMAGE_FILE_HEADER, 0x14) + +struc IMAGE_DATA_DIRECTORY + .VirtualAddress resd 1 + .Size resd 1 +endstruc + + +struc IMAGE_OPTIONAL_HEADER32 + .Magic resw 1 ;;< 0x00 + .MajorLinkerVersion resb 1 ;;< 0x02 + .MinorLinkerVersion resb 1 ;;< 0x03 + .SizeOfCode resd 1 ;;< 0x04 + .SizeOfInitializedData resd 1 ;;< 0x08 + .SizeOfUninitializedData resd 1 ;;< 0x0c + .AddressOfEntryPoint resd 1 ;;< 0x10 + .BaseOfCode resd 1 ;;< 0x14 + .BaseOfData resd 1 ;;< 0x18 + .ImageBase resd 1 ;;< 0x1c + .SectionAlignment resd 1 ;;< 0x20 + .FileAlignment resd 1 ;;< 0x24 + .MajorOperatingSystemVersion resw 1 ;;< 0x28 + .MinorOperatingSystemVersion resw 1 ;;< 0x2a + .MajorImageVersion resw 1 ;;< 0x2c + .MinorImageVersion resw 1 ;;< 0x2e + .MajorSubsystemVersion resw 1 ;;< 0x30 + .MinorSubsystemVersion resw 1 ;;< 0x32 + .Win32VersionValue resd 1 ;;< 0x34 + .SizeOfImage resd 1 ;;< 0x38 + .SizeOfHeaders resd 1 ;;< 0x3c + .CheckSum resd 1 ;;< 0x40 + .Subsystem resw 1 ;;< 0x44 + .DllCharacteristics resw 1 ;;< 0x46 + .SizeOfStackReserve resd 1 ;;< 0x48 + .SizeOfStackCommit resd 1 ;;< 0x4c + .SizeOfHeapReserve resd 1 ;;< 0x50 + .SizeOfHeapCommit resd 1 ;;< 0x54 + .LoaderFlags resd 1 ;;< 0x58 + .NumberOfRvaAndSizes resd 1 ;;< 0x5c + .DataDirectory resb IMAGE_DATA_DIRECTORY_size * IMAGE_NUMBEROF_DIRECTORY_ENTRIES ;;< 0x60; 0x10*8 = 0x80 +endstruc +AssertCompileSize(IMAGE_OPTIONAL_HEADER32, 0xe0); + +struc IMAGE_OPTIONAL_HEADER64 + .Magic resw 1 ;;< 0x00 + .MajorLinkerVersion resb 1 ;;< 0x02 + .MinorLinkerVersion resb 1 ;;< 0x03 + .SizeOfCode resd 1 ;;< 0x04 + .SizeOfInitializedData resd 1 ;;< 0x08 + .SizeOfUninitializedData resd 1 ;;< 0x0c + .AddressOfEntryPoint resd 1 ;;< 0x10 + .BaseOfCode resd 1 ;;< 0x14 + .ImageBase resq 1 ;;< 0x18 + .SectionAlignment resd 1 ;;< 0x20 + .FileAlignment resd 1 ;;< 0x24 + .MajorOperatingSystemVersion resw 1 ;;< 0x28 + .MinorOperatingSystemVersion resw 1 ;;< 0x2a + .MajorImageVersion resw 1 ;;< 0x2c + .MinorImageVersion resw 1 ;;< 0x2e + .MajorSubsystemVersion resw 1 ;;< 0x30 + .MinorSubsystemVersion resw 1 ;;< 0x32 + .Win32VersionValue resd 1 ;;< 0x34 + .SizeOfImage resd 1 ;;< 0x38 + .SizeOfHeaders resd 1 ;;< 0x3c + .CheckSum resd 1 ;;< 0x40 + .Subsystem resw 1 ;;< 0x44 + .DllCharacteristics resw 1 ;;< 0x46 + .SizeOfStackReserve resq 1 ;;< 0x48 + .SizeOfStackCommit resq 1 ;;< 0x50 + .SizeOfHeapReserve resq 1 ;;< 0x58 + .SizeOfHeapCommit resq 1 ;;< 0x60 + .LoaderFlags resd 1 ;;< 0x68 + .NumberOfRvaAndSizes resd 1 ;;< 0x6c + .DataDirectory resb IMAGE_DATA_DIRECTORY_size * IMAGE_NUMBEROF_DIRECTORY_ENTRIES ;;< 0x70; 0x10*8 = 0x80 +endstruc ; size: 0xf0 +AssertCompileSize(IMAGE_OPTIONAL_HEADER64, 0xf0); + + +struc IMAGE_NT_HEADERS32 + .Signature resd 1 ;;< 0x00 + .FileHeader resb IMAGE_FILE_HEADER_size ; ;;< 0x04 + .OptionalHeader resb IMAGE_OPTIONAL_HEADER32_size ;;< 0x18 +endstruc ; size: 0xf8 +AssertCompileSize(IMAGE_NT_HEADERS32, 0xf8); +AssertCompileMemberOffset(IMAGE_NT_HEADERS32, FileHeader, 4); +AssertCompileMemberOffset(IMAGE_NT_HEADERS32, OptionalHeader, 24); + +struc IMAGE_NT_HEADERS64 + .Signature resd 1 ;;< 0x00 + .FileHeader resb IMAGE_FILE_HEADER_size ;;< 0x04 + .OptionalHeader resb IMAGE_OPTIONAL_HEADER64_size ;;< 0x18 +endstruc ; size: 0x108 +AssertCompileSize(IMAGE_NT_HEADERS64, 0x108); +AssertCompileMemberOffset(IMAGE_NT_HEADERS64, FileHeader, 4); +AssertCompileMemberOffset(IMAGE_NT_HEADERS64, OptionalHeader, 24); + + +struc IMAGE_SECTION_HEADER + .Name resb IMAGE_SIZEOF_SHORT_NAME + .Misc.VirtualSize resd 1 + .VirtualAddress resd 1 + .SizeOfRawData resd 1 + .PointerToRawData resd 1 + .PointerToRelocations resd 1 + .PointerToLinenumbers resd 1 + .NumberOfRelocations resw 1 + .NumberOfLinenumbers resw 1 + .Characteristics resd 1 +endstruc +%define IMAGE_SECTION_HEADER.Misc.PhysicalAddress IMAGE_SECTION_HEADER.Misc.VirtualSize + + +struc IMAGE_BASE_RELOCATION + .VirtualAddress resd 1 + .SizeOfBlock resd 1 +endstruc + + +struc IMAGE_EXPORT_DIRECTORY + .Characteristics resd 1 + .TimeDateStamp resd 1 + .MajorVersion resw 1 + .MinorVersion resw 1 + .Name resd 1 + .Base resd 1 + .NumberOfFunctions resd 1 + .NumberOfNames resd 1 + .AddressOfFunctions resd 1 + .AddressOfNames resd 1 + .AddressOfNameOrdinals resd 1 +endstruc + + +struc IMAGE_IMPORT_DESCRIPTOR + .u.Characteristics resd 1 + .TimeDateStamp resd 1 + .ForwarderChain resd 1 + .Name resd 1 + .FirstThunk resd 1 +endstruc +%define IMAGE_IMPORT_DESCRIPTOR.u.OriginalFirstThunk IMAGE_IMPORT_DESCRIPTOR.u.Characteristics + +struc IMAGE_IMPORT_BY_NAME + .Hint resw 1 + .Name resb 1 +endstruc + + +struc IMAGE_THUNK_DATA64 + .u1.ForwarderString resq 1 +endstruc +%define IMAGE_THUNK_DATA64.u1.Function IMAGE_THUNK_DATA64.u1.ForwarderString +%define IMAGE_THUNK_DATA64.u1.Ordinal IMAGE_THUNK_DATA64.u1.ForwarderString +%define IMAGE_THUNK_DATA64.u1.AddressOfData IMAGE_THUNK_DATA64.u1.ForwarderString + +struc IMAGE_THUNK_DATA32 + .u1.ForwarderString resd 1 +endstruc +%define IMAGE_THUNK_DATA32.u1.Function IMAGE_THUNK_DATA32.u1.ForwarderString +%define IMAGE_THUNK_DATA32.u1.Ordinal IMAGE_THUNK_DATA32.u1.ForwarderString +%define IMAGE_THUNK_DATA32.u1.AddressOfData IMAGE_THUNK_DATA32.u1.ForwarderString + + +struc IMAGE_LOAD_CONFIG_DIRECTORY32 + .Size resd 1 + .TimeDateStamp resd 1 + .MajorVersion resw 1 + .MinorVersion resw 1 + .GlobalFlagsClear resd 1 + .GlobalFlagsSet resd 1 + .CriticalSectionDefaultTimeout resd 1 + .DeCommitFreeBlockThreshold resd 1 + .DeCommitTotalFreeThreshold resd 1 + .LockPrefixTable resd 1 + .MaximumAllocationSize resd 1 + .VirtualMemoryThreshold resd 1 + .ProcessHeapFlags resd 1 + .ProcessAffinityMask resd 1 + .CSDVersion resw 1 + .Reserved1 resw 1 + .EditList resd 1 + .SecurityCookie resd 1 + .SEHandlerTable resd 1 + .SEHandlerCount resd 1 +endstruc + +struc IMAGE_LOAD_CONFIG_DIRECTORY64 + .Size resd 1 + .TimeDateStamp resd 1 + .MajorVersion resw 1 + .MinorVersion resw 1 + .GlobalFlagsClear resd 1 + .GlobalFlagsSet resd 1 + .CriticalSectionDefaultTimeout resd 1 + .DeCommitFreeBlockThreshold resq 1 + .DeCommitTotalFreeThreshold resq 1 + .LockPrefixTable resq 1 + .MaximumAllocationSize resq 1 + .VirtualMemoryThreshold resq 1 + .ProcessAffinityMask resq 1 + .ProcessHeapFlags resd 1 + .CSDVersion resw 1 + .Reserved1 resw 1 + .EditList resq 1 + .SecurityCookie resq 1 + .SEHandlerTable resq 1 + .SEHandlerCount resq 1 +endstruc + + +struc IMAGE_DEBUG_DIRECTORY + .Characteristics resd 1 + .TimeDateStamp resd 1 + .MajorVersion resw 1 + .MinorVersion resw 1 + .Type resd 1 + .SizeOfData resd 1 + .AddressOfRawData resd 1 + .PointerToRawData resd 1 +endstruc + +struc IMAGE_DEBUG_MISC + .DataType resd 1 + .Length resd 1 + .Unicode resb 1 + .Reserved resb 3 + .Data resb 1 +endstruc + + +struc WIN_CERTIFICATE + .dwLength resd 1 + .wRevision resw 1 + .wCertificateType resw 1 + .bCertificate resb 8 +endstruc + +;; The header of a .DBG file (NT4). +struc IMAGE_SEPARATE_DEBUG_HEADER + .Signature resw 1 ;;< 0x00 + .Flags resw 1 ;;< 0x02 + .Machine resw 1 ;;< 0x04 + .Characteristics resw 1 ;;< 0x06 + .TimeDateStamp resd 1 ;;< 0x08 + .CheckSum resd 1 ;;< 0x0c + .ImageBase resd 1 ;;< 0x10 + .SizeOfImage resd 1 ;;< 0x14 + .NumberOfSections resd 1 ;;< 0x18 + .ExportedNamesSize resd 1 ;;< 0x1c + .DebugDirectorySize resd 1 ;;< 0x20 + .SectionAlignment resd 1 ;;< 0x24 + .Reserved resd 2 ;;< 0x28 +endstruc ; size: 0x30 +AssertCompileSize(IMAGE_SEPARATE_DEBUG_HEADER, 0x30); + + +struc IMAGE_COFF_SYMBOLS_HEADER + .NumberOfSymbols resd 1 + .LvaToFirstSymbol resd 1 + .NumberOfLinenumbers resd 1 + .LvaToFirstLinenumber resd 1 + .RvaToFirstByteOfCode resd 1 + .RvaToLastByteOfCode resd 1 + .RvaToFirstByteOfData resd 1 + .RvaToLastByteOfData resd 1 +endstruc +AssertCompileSize(IMAGE_COFF_SYMBOLS_HEADER, 0x20); + + +struc IMAGE_LINENUMBER + .Type.VirtualAddress resd 1 + .Linenumber resw 1 +endstruc +AssertCompileSize(IMAGE_LINENUMBER, 6); +%define IMAGE_LINENUMBER.Type.SymbolTableIndex IMAGE_LINENUMBER.Type.VirtualAddress + + +;;#pragma pack(2) +;;struc IMAGE_SYMBOL +;;{ +;; union +;; { +;; uint8_t ShortName[8]; +;; struct +;; { +;; .Short resd 1 +;; .Long resd 1 +;; } Name; +;; uint32_t LongName[2]; +;; } N; +;; +;; .Value resd 1 +;; int16_t SectionNumber; +;; .Type resw 1 +;; .StorageClass resb 1 +;; .NumberOfAuxSymbols resb 1 +;;} IMAGE_SYMBOL; +;;#pragma pack() +;;AssertCompileSize(IMAGE_SYMBOL, IMAGE_SIZE_OF_SYMBOL); +;; +;; +;;#pragma pack(2) +;;typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF +;;{ +;; .bAuxType resb 1 +;; .bReserved resb 1 +;; .SymbolTableIndex resd 1 +;; uint8_t rgbReserved[12]; +;;} IMAGE_AUX_SYMBOL_TOKEN_DEF; +;;#pragma pack() +;;AssertCompileSize(IMAGE_AUX_SYMBOL_TOKEN_DEF, IMAGE_SIZE_OF_SYMBOL); +;; +;; +;;#pragma pack(1) +;;typedef union _IMAGE_AUX_SYMBOL +;;{ +;; struct +;; { +;; .TagIndex resd 1 +;; union +;; { +;; struct +;; { +;; .Linenumber resw 1 +;; .Size resw 1 +;; } LnSz; +;; } Misc; +;; union +;; { +;; struct +;; { +;; .PointerToLinenumber resd 1 +;; .PointerToNextFunction resd 1 +;; } Function; +;; struct +;; { +;; uint16_t Dimension[4]; +;; } Array; +;; } FcnAry; +;; .TvIndex resw 1 +;; } Sym; +;; +;; struct +;; { +;; uint8_t Name[IMAGE_SIZE_OF_SYMBOL]; +;; } File; +;; +;; struct +;; { +;; .Length resd 1 +;; .NumberOfRelocations resw 1 +;; .NumberOfLinenumbers resw 1 +;; .CheckSum resd 1 +;; .Number resw 1 +;; .Selection resb 1 +;; .bReserved resb 1 +;; .HighNumber resw 1 +;; } Section; +;; +;; IMAGE_AUX_SYMBOL_TOKEN_DEF TokenDef; +;; struct +;; { +;; .crc resd 1 +;; uint8_t rgbReserved[14]; +;; } CRC; +;;} IMAGE_AUX_SYMBOL; +;;#pragma pack() +;;AssertCompileSize(IMAGE_AUX_SYMBOL, IMAGE_SIZE_OF_SYMBOL); +;; +;; +;; +;;struc IMAGE_SYMBOL_EX +;;{ +;; union +;; { +;; uint8_t ShortName[8]; +;; struct +;; { +;; .Short resd 1 +;; .Long resd 1 +;; } Name; +;; uint32_t LongName[2]; +;; } N; +;; +;; .Value resd 1 +;; int32_t SectionNumber; /* The difference from IMAGE_SYMBOL +;; .Type resw 1 +;; .StorageClass resb 1 +;; .NumberOfAuxSymbols resb 1 +;;} IMAGE_SYMBOL_EX; +;;AssertCompileSize(IMAGE_SYMBOL_EX, IMAGE_SIZE_OF_SYMBOL_EX); +;; +;; +;;typedef union _IMAGE_AUX_SYMBOL_EX +;;{ +;; struct +;; { +;; .WeakDefaultSymIndex resd 1 +;; .WeakSearchType resd 1 +;; uint8_t rgbReserved[12]; +;; } Sym; +;; +;; struct +;; { +;; uint8_t Name[IMAGE_SIZE_OF_SYMBOL_EX]; +;; } File; +;; +;; struct +;; { +;; .Length resd 1 +;; .NumberOfRelocations resw 1 +;; .NumberOfLinenumbers resw 1 +;; .CheckSum resd 1 +;; .Number resw 1 +;; .Selection resb 1 +;; .bReserved resb 1 +;; .HighNumber resw 1 +;; uint8_t rgbReserved[2]; +;; } Section; +;; +;; IMAGE_AUX_SYMBOL_TOKEN_DEF TokenDef; +;; +;; struct +;; { +;; .crc resd 1 +;; uint8_t rgbReserved[16]; +;; } CRC; +;;} IMAGE_AUX_SYMBOL_EX; +;;AssertCompileSize(IMAGE_AUX_SYMBOL_EX, IMAGE_SIZE_OF_SYMBOL_EX); + +%endif + diff --git a/include/iprt/formats/pecoff.h b/include/iprt/formats/pecoff.h new file mode 100644 index 00000000..a705d20a --- /dev/null +++ b/include/iprt/formats/pecoff.h @@ -0,0 +1,2610 @@ +/* $Id: pecoff.h $ */ +/** @file + * IPRT - Windows NT PE & COFF Structures and Constants. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_pecoff_h +#define IPRT_INCLUDED_formats_pecoff_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_pecoff PE & Microsoft COFF structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + + +/** + * PE & COFF file header. + * + * This starts COFF files, while in PE files it's preceeded by the PE signature + * (see IMAGE_NT_HEADERS32, IMAGE_NT_HEADERS64). + */ +typedef struct _IMAGE_FILE_HEADER +{ + uint16_t Machine; /**< 0x00 */ + uint16_t NumberOfSections; /**< 0x02 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint32_t PointerToSymbolTable; /**< 0x08 */ + uint32_t NumberOfSymbols; /**< 0x0c */ + uint16_t SizeOfOptionalHeader; /**< 0x10 */ + uint16_t Characteristics; /**< 0x12 */ +} IMAGE_FILE_HEADER; /* size: 0x14 */ +AssertCompileSize(IMAGE_FILE_HEADER, 0x14); +typedef IMAGE_FILE_HEADER *PIMAGE_FILE_HEADER; +typedef IMAGE_FILE_HEADER const *PCIMAGE_FILE_HEADER; + + +/** @name PE & COFF machine types. + * Used by IMAGE_FILE_HEADER::Machine and IMAGE_SEPARATE_DEBUG_HEADER::Machine. + * @{ */ +/** X86 compatible CPU, 32-bit instructions. */ +#define IMAGE_FILE_MACHINE_I386 UINT16_C(0x014c) +/** AMD64 compatible CPU, 64-bit instructions. */ +#define IMAGE_FILE_MACHINE_AMD64 UINT16_C(0x8664) + +/** Unknown target CPU. */ +#define IMAGE_FILE_MACHINE_UNKNOWN UINT16_C(0x0000) +/** Basic-16 (whatever that is). */ +#define IMAGE_FILE_MACHINE_BASIC_16 UINT16_C(0x0142) +/** Basic-16 (whatever that is) w/ transfer vector(s?) (TV). */ +#define IMAGE_FILE_MACHINE_BASIC_16_TV UINT16_C(0x0143) +/** Intel iAPX 16 (8086?). */ +#define IMAGE_FILE_MACHINE_IAPX16 UINT16_C(0x0144) +/** Intel iAPX 16 (8086?) w/ transfer vector(s?) (TV). */ +#define IMAGE_FILE_MACHINE_IAPX16_TV UINT16_C(0x0145) +/** Intel iAPX 20 (80286?). */ +#define IMAGE_FILE_MACHINE_IAPX20 UINT16_C(0x0144) +/** Intel iAPX 20 (80286?) w/ transfer vector(s?) (TV). */ +#define IMAGE_FILE_MACHINE_IAPX20_TV UINT16_C(0x0145) +/** X86 compatible CPU, 8086. */ +#define IMAGE_FILE_MACHINE_I8086 UINT16_C(0x0148) +/** X86 compatible CPU, 8086 w/ transfer vector(s?) (TV). */ +#define IMAGE_FILE_MACHINE_I8086_TV UINT16_C(0x0149) +/** X86 compatible CPU, 80286 small model program. */ +#define IMAGE_FILE_MACHINE_I286_SMALL UINT16_C(0x014a) +/** Motorola 68000. */ +#define IMAGE_FILE_MACHINE_MC68 UINT16_C(0x0150) +/** Motorola 68000 w/ writable text sections. */ +#define IMAGE_FILE_MACHINE_MC68_WR UINT16_C(0x0150) +/** Motorola 68000 w/ transfer vector(s?). */ +#define IMAGE_FILE_MACHINE_MC68_TV UINT16_C(0x0151) +/** Motorola 68000 w/ demand paged text. + * @note shared with 80286 large model program. */ +#define IMAGE_FILE_MACHINE_MC68_PG UINT16_C(0x0152) +/** X86 compatible CPU, 80286 large model program. + * @note shared with MC68000 w/ demand paged text */ +#define IMAGE_FILE_MACHINE_I286_LARGE UINT16_C(0x0152) +/** IBM 370 (writable text). */ +#define IMAGE_FILE_MACHINE_U370_WR UINT16_C(0x0158) +/** Amdahl 470/580 (writable text). */ +#define IMAGE_FILE_MACHINE_AMDAHL_470_WR UINT16_C(0x0159) +/** Amdahl 470/580 (read only text). */ +#define IMAGE_FILE_MACHINE_AMDAHL_470_RO UINT16_C(0x015c) +/** IBM 370 (read only text). */ +#define IMAGE_FILE_MACHINE_U370_RO UINT16_C(0x015d) +/** MIPS R4000 CPU, little endian. */ +#define IMAGE_FILE_MACHINE_R4000 UINT16_C(0x0166) +/** MIPS CPU, little endian, Windows CE (?) v2 designation. */ +#define IMAGE_FILE_MACHINE_WCEMIPSV2 UINT16_C(0x0169) +/** VAX-11/750 and VAX-11/780 (writable text). */ +#define IMAGE_FILE_MACHINE_VAX_WR UINT16_C(0x0178) +/** VAX-11/750 and VAX-11/780 (read-only text). */ +#define IMAGE_FILE_MACHINE_VAX_RO UINT16_C(0x017d) +/** Hitachi SH3 CPU. */ +#define IMAGE_FILE_MACHINE_SH3 UINT16_C(0x01a2) +/** Hitachi SH3 DSP. */ +#define IMAGE_FILE_MACHINE_SH3DSP UINT16_C(0x01a3) +/** Hitachi SH4 CPU. */ +#define IMAGE_FILE_MACHINE_SH4 UINT16_C(0x01a6) +/** Hitachi SH5 CPU. */ +#define IMAGE_FILE_MACHINE_SH5 UINT16_C(0x01a8) +/** Little endian ARM CPU. */ +#define IMAGE_FILE_MACHINE_ARM UINT16_C(0x01c0) +/** ARM or Thumb stuff. */ +#define IMAGE_FILE_MACHINE_THUMB UINT16_C(0x01c2) +/** ARMv7 or higher CPU, Thumb mode. */ +#define IMAGE_FILE_MACHINE_ARMNT UINT16_C(0x01c4) +/** Matshushita AM33 CPU. */ +#define IMAGE_FILE_MACHINE_AM33 UINT16_C(0x01d3) +/** Power PC CPU, little endian. */ +#define IMAGE_FILE_MACHINE_POWERPC UINT16_C(0x01f0) +/** Power PC CPU with FPU, also little endian? */ +#define IMAGE_FILE_MACHINE_POWERPCFP UINT16_C(0x01f1) +/** "Itanic" CPU. */ +#define IMAGE_FILE_MACHINE_IA64 UINT16_C(0x0200) +/** MIPS CPU, compact 16-bit instructions only? */ +#define IMAGE_FILE_MACHINE_MIPS16 UINT16_C(0x0266) +/** MIPS CPU with FPU, full 32-bit instructions only? */ +#define IMAGE_FILE_MACHINE_MIPSFPU UINT16_C(0x0366) +/** MIPS CPU with FPU, compact 16-bit instructions? */ +#define IMAGE_FILE_MACHINE_MIPSFPU16 UINT16_C(0x0466) +/** EFI byte code. */ +#define IMAGE_FILE_MACHINE_EBC UINT16_C(0x0ebc) +/** Mitsubishi M32R CPU, little endian. */ +#define IMAGE_FILE_MACHINE_M32R UINT16_C(0x9041) +/** ARMv8 CPU, 64-bit mode. */ +#define IMAGE_FILE_MACHINE_ARM64 UINT16_C(0xaa64) +/** @} */ + +/** @name File header characteristics (IMAGE_FILE_HEADER::Characteristics) + * @{ */ +#define IMAGE_FILE_RELOCS_STRIPPED UINT16_C(0x0001) +#define IMAGE_FILE_EXECUTABLE_IMAGE UINT16_C(0x0002) +#define IMAGE_FILE_LINE_NUMS_STRIPPED UINT16_C(0x0004) +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED UINT16_C(0x0008) +#define IMAGE_FILE_AGGRESIVE_WS_TRIM UINT16_C(0x0010) +#define IMAGE_FILE_LARGE_ADDRESS_AWARE UINT16_C(0x0020) +#define IMAGE_FILE_16BIT_MACHINE UINT16_C(0x0040) +#define IMAGE_FILE_BYTES_REVERSED_LO UINT16_C(0x0080) +#define IMAGE_FILE_32BIT_MACHINE UINT16_C(0x0100) +#define IMAGE_FILE_DEBUG_STRIPPED UINT16_C(0x0200) +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP UINT16_C(0x0400) +#define IMAGE_FILE_NET_RUN_FROM_SWAP UINT16_C(0x0800) +#define IMAGE_FILE_SYSTEM UINT16_C(0x1000) /**< (COFF/IAPX*: Used to indicate 80186 instructions) */ +#define IMAGE_FILE_DLL UINT16_C(0x2000) /**< (COFF/IAPX*: Used to indicate 80286 instructions) */ +#define IMAGE_FILE_UP_SYSTEM_ONLY UINT16_C(0x4000) +#define IMAGE_FILE_BYTES_REVERSED_HI UINT16_C(0x8000) +/** @} */ + + +/** + * PE data directory. + * + * This is used to locate data in the loaded image so the dynamic linker or + * others can make use of it. However, in the case of + * IMAGE_DIRECTORY_ENTRY_SECURITY it is referring to raw file offsets. + */ +typedef struct _IMAGE_DATA_DIRECTORY +{ + uint32_t VirtualAddress; + uint32_t Size; +} IMAGE_DATA_DIRECTORY; +AssertCompileSize(IMAGE_DATA_DIRECTORY, 0x8); +typedef IMAGE_DATA_DIRECTORY *PIMAGE_DATA_DIRECTORY; +typedef IMAGE_DATA_DIRECTORY const *PCIMAGE_DATA_DIRECTORY; + +/** The standard number of data directories in the optional header. + * I.e. the dimensions of IMAGE_OPTIONAL_HEADER32::DataDirectory and + * IMAGE_OPTIONAL_HEADER64::DataDirectory. + */ +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 0x10 + + +/** + * PE optional header, 32-bit version. + */ +typedef struct _IMAGE_OPTIONAL_HEADER32 +{ + uint16_t Magic; /**< 0x00 */ + uint8_t MajorLinkerVersion; /**< 0x02 */ + uint8_t MinorLinkerVersion; /**< 0x03 */ + uint32_t SizeOfCode; /**< 0x04 */ + uint32_t SizeOfInitializedData; /**< 0x08 */ + uint32_t SizeOfUninitializedData; /**< 0x0c */ + uint32_t AddressOfEntryPoint; /**< 0x10 */ + uint32_t BaseOfCode; /**< 0x14 */ + uint32_t BaseOfData; /**< 0x18 */ + uint32_t ImageBase; /**< 0x1c */ + uint32_t SectionAlignment; /**< 0x20 */ + uint32_t FileAlignment; /**< 0x24 */ + uint16_t MajorOperatingSystemVersion; /**< 0x28 */ + uint16_t MinorOperatingSystemVersion; /**< 0x2a */ + uint16_t MajorImageVersion; /**< 0x2c */ + uint16_t MinorImageVersion; /**< 0x2e */ + uint16_t MajorSubsystemVersion; /**< 0x30 */ + uint16_t MinorSubsystemVersion; /**< 0x32 */ + uint32_t Win32VersionValue; /**< 0x34 */ + uint32_t SizeOfImage; /**< 0x38 */ + uint32_t SizeOfHeaders; /**< 0x3c */ + uint32_t CheckSum; /**< 0x40 */ + uint16_t Subsystem; /**< 0x44 */ + uint16_t DllCharacteristics; /**< 0x46 */ + uint32_t SizeOfStackReserve; /**< 0x48 */ + uint32_t SizeOfStackCommit; /**< 0x4c */ + uint32_t SizeOfHeapReserve; /**< 0x50 */ + uint32_t SizeOfHeapCommit; /**< 0x54 */ + uint32_t LoaderFlags; /**< 0x58 */ + uint32_t NumberOfRvaAndSizes; /**< 0x5c */ + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /**< 0x60; 0x10*8 = 0x80 */ +} IMAGE_OPTIONAL_HEADER32; /* size: 0xe0 */ +AssertCompileSize(IMAGE_OPTIONAL_HEADER32, 0xe0); +typedef IMAGE_OPTIONAL_HEADER32 *PIMAGE_OPTIONAL_HEADER32; +typedef IMAGE_OPTIONAL_HEADER32 const *PCIMAGE_OPTIONAL_HEADER32; + +/** + * PE optional header, 64-bit version. + */ +typedef struct _IMAGE_OPTIONAL_HEADER64 +{ + uint16_t Magic; /**< 0x00 */ + uint8_t MajorLinkerVersion; /**< 0x02 */ + uint8_t MinorLinkerVersion; /**< 0x03 */ + uint32_t SizeOfCode; /**< 0x04 */ + uint32_t SizeOfInitializedData; /**< 0x08 */ + uint32_t SizeOfUninitializedData; /**< 0x0c */ + uint32_t AddressOfEntryPoint; /**< 0x10 */ + uint32_t BaseOfCode; /**< 0x14 */ + uint64_t ImageBase; /**< 0x18 */ + uint32_t SectionAlignment; /**< 0x20 */ + uint32_t FileAlignment; /**< 0x24 */ + uint16_t MajorOperatingSystemVersion; /**< 0x28 */ + uint16_t MinorOperatingSystemVersion; /**< 0x2a */ + uint16_t MajorImageVersion; /**< 0x2c */ + uint16_t MinorImageVersion; /**< 0x2e */ + uint16_t MajorSubsystemVersion; /**< 0x30 */ + uint16_t MinorSubsystemVersion; /**< 0x32 */ + uint32_t Win32VersionValue; /**< 0x34 */ + uint32_t SizeOfImage; /**< 0x38 */ + uint32_t SizeOfHeaders; /**< 0x3c */ + uint32_t CheckSum; /**< 0x40 */ + uint16_t Subsystem; /**< 0x44 */ + uint16_t DllCharacteristics; /**< 0x46 */ + uint64_t SizeOfStackReserve; /**< 0x48 */ + uint64_t SizeOfStackCommit; /**< 0x50 */ + uint64_t SizeOfHeapReserve; /**< 0x58 */ + uint64_t SizeOfHeapCommit; /**< 0x60 */ + uint32_t LoaderFlags; /**< 0x68 */ + uint32_t NumberOfRvaAndSizes; /**< 0x6c */ + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /**< 0x70; 0x10*8 = 0x80 */ +} IMAGE_OPTIONAL_HEADER64; /* size: 0xf0 */ +AssertCompileSize(IMAGE_OPTIONAL_HEADER64, 0xf0); +typedef IMAGE_OPTIONAL_HEADER64 *PIMAGE_OPTIONAL_HEADER64; +typedef IMAGE_OPTIONAL_HEADER64 const *PCIMAGE_OPTIONAL_HEADER64; + +/** @name Optional header magic values. + * @{ */ +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC UINT16_C(0x010b) +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC UINT16_C(0x020b) +/** @} */ + +/** @name IMAGE_SUBSYSTEM_XXX - Optional header subsystems. + * IMAGE_OPTIONAL_HEADER32::Subsystem, IMAGE_OPTIONAL_HEADER64::Subsystem + * @{ */ +#define IMAGE_SUBSYSTEM_UNKNOWN UINT16_C(0x0000) +#define IMAGE_SUBSYSTEM_NATIVE UINT16_C(0x0001) +#define IMAGE_SUBSYSTEM_WINDOWS_GUI UINT16_C(0x0002) +#define IMAGE_SUBSYSTEM_WINDOWS_CUI UINT16_C(0x0003) +#define IMAGE_SUBSYSTEM_OS2_GUI UINT16_C(0x0004) +#define IMAGE_SUBSYSTEM_OS2_CUI UINT16_C(0x0005) +#define IMAGE_SUBSYSTEM_POSIX_CUI UINT16_C(0x0007) +/** @} */ + +/** @name Optional header characteristics. + * @{ */ +#define IMAGE_LIBRARY_PROCESS_INIT UINT16_C(0x0001) +#define IMAGE_LIBRARY_PROCESS_TERM UINT16_C(0x0002) +#define IMAGE_LIBRARY_THREAD_INIT UINT16_C(0x0004) +#define IMAGE_LIBRARY_THREAD_TERM UINT16_C(0x0008) +#define IMAGE_DLLCHARACTERISTICS_RESERVED UINT16_C(0x0010) +#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA UINT16_C(0x0020) +#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE UINT16_C(0x0040) +#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY UINT16_C(0x0080) +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT UINT16_C(0x0100) +#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION UINT16_C(0x0200) +#define IMAGE_DLLCHARACTERISTICS_NO_SEH UINT16_C(0x0400) +#define IMAGE_DLLCHARACTERISTICS_NO_BIND UINT16_C(0x0800) +#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER UINT16_C(0x1000) +#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER UINT16_C(0x2000) +#define IMAGE_DLLCHARACTERISTICS_GUARD_CF UINT16_C(0x4000) +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE UINT16_C(0x8000) +/** @} */ + + +/** @name IMAGE_DIRECTORY_ENTRY_XXX - Data directory indexes. + * Used to index IMAGE_OPTIONAL_HEADER32::DataDirectory and + * IMAGE_OPTIONAL_HEADER64::DataDirectory + * @{ */ +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0x0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 0x1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 0x2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 0x3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 0x4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 0x5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 0x6 +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 0x7 +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT IMAGE_DIRECTORY_ENTRY_ARCHITECTURE +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 0x8 +#define IMAGE_DIRECTORY_ENTRY_TLS 0x9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 0xa +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 0xb +#define IMAGE_DIRECTORY_ENTRY_IAT 0xc +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 0xd +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 0xe +/** @} */ + + +/** + * PE (NT) headers, 32-bit version. + */ +typedef struct _IMAGE_NT_HEADERS32 +{ + uint32_t Signature; /**< 0x00 */ + IMAGE_FILE_HEADER FileHeader; /**< 0x04 */ + IMAGE_OPTIONAL_HEADER32 OptionalHeader; /**< 0x18 */ +} IMAGE_NT_HEADERS32; /* size: 0xf8 */ +AssertCompileSize(IMAGE_NT_HEADERS32, 0xf8); +AssertCompileMemberOffset(IMAGE_NT_HEADERS32, FileHeader, 4); +AssertCompileMemberOffset(IMAGE_NT_HEADERS32, OptionalHeader, 24); +typedef IMAGE_NT_HEADERS32 *PIMAGE_NT_HEADERS32; +typedef IMAGE_NT_HEADERS32 const *PCIMAGE_NT_HEADERS32; + +/** + * PE (NT) headers, 64-bit version. + */ +typedef struct _IMAGE_NT_HEADERS64 +{ + uint32_t Signature; /**< 0x00 */ + IMAGE_FILE_HEADER FileHeader; /**< 0x04 */ + IMAGE_OPTIONAL_HEADER64 OptionalHeader; /**< 0x18 */ +} IMAGE_NT_HEADERS64; /**< 0x108 */ +AssertCompileSize(IMAGE_NT_HEADERS64, 0x108); +AssertCompileMemberOffset(IMAGE_NT_HEADERS64, FileHeader, 4); +AssertCompileMemberOffset(IMAGE_NT_HEADERS64, OptionalHeader, 24); +typedef IMAGE_NT_HEADERS64 *PIMAGE_NT_HEADERS64; +typedef IMAGE_NT_HEADERS64 const *PCIMAGE_NT_HEADERS64; + +/** The PE signature. + * Used by IMAGE_NT_HEADERS32::Signature, IMAGE_NT_HEADERS64::Signature. */ +#define IMAGE_NT_SIGNATURE UINT32_C(0x00004550) + + +/** Section header short name length (IMAGE_SECTION_HEADER::Name). */ +#define IMAGE_SIZEOF_SHORT_NAME 0x8 + +/** + * PE & COFF section header. + */ +typedef struct _IMAGE_SECTION_HEADER +{ + uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; + union + { + uint32_t PhysicalAddress; + uint32_t VirtualSize; + } Misc; + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLinenumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; +} IMAGE_SECTION_HEADER; +AssertCompileSize(IMAGE_SECTION_HEADER, 40); +typedef IMAGE_SECTION_HEADER *PIMAGE_SECTION_HEADER; +typedef IMAGE_SECTION_HEADER const *PCIMAGE_SECTION_HEADER; + +/** @name IMAGE_SCN_XXX - Section header characteristics. + * Used by IMAGE_SECTION_HEADER::Characteristics. + * @{ */ +#define IMAGE_SCN_TYPE_REG UINT32_C(0x00000000) +#define IMAGE_SCN_TYPE_DSECT UINT32_C(0x00000001) +#define IMAGE_SCN_TYPE_NOLOAD UINT32_C(0x00000002) +#define IMAGE_SCN_TYPE_GROUP UINT32_C(0x00000004) +#define IMAGE_SCN_TYPE_NO_PAD UINT32_C(0x00000008) +#define IMAGE_SCN_TYPE_COPY UINT32_C(0x00000010) + +#define IMAGE_SCN_CNT_CODE UINT32_C(0x00000020) +#define IMAGE_SCN_CNT_INITIALIZED_DATA UINT32_C(0x00000040) +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA UINT32_C(0x00000080) + +#define IMAGE_SCN_LNK_OTHER UINT32_C(0x00000100) +#define IMAGE_SCN_LNK_INFO UINT32_C(0x00000200) +#define IMAGE_SCN_TYPE_OVER UINT32_C(0x00000400) +#define IMAGE_SCN_LNK_REMOVE UINT32_C(0x00000800) +#define IMAGE_SCN_LNK_COMDAT UINT32_C(0x00001000) +#define IMAGE_SCN_MEM_PROTECTED UINT32_C(0x00004000) +#define IMAGE_SCN_NO_DEFER_SPEC_EXC UINT32_C(0x00004000) +#define IMAGE_SCN_GPREL UINT32_C(0x00008000) +#define IMAGE_SCN_MEM_FARDATA UINT32_C(0x00008000) +#define IMAGE_SCN_MEM_SYSHEAP UINT32_C(0x00010000) +#define IMAGE_SCN_MEM_PURGEABLE UINT32_C(0x00020000) +#define IMAGE_SCN_MEM_16BIT UINT32_C(0x00020000) +#define IMAGE_SCN_MEM_LOCKED UINT32_C(0x00040000) +#define IMAGE_SCN_MEM_PRELOAD UINT32_C(0x00080000) + +#define IMAGE_SCN_ALIGN_1BYTES UINT32_C(0x00100000) +#define IMAGE_SCN_ALIGN_2BYTES UINT32_C(0x00200000) +#define IMAGE_SCN_ALIGN_4BYTES UINT32_C(0x00300000) +#define IMAGE_SCN_ALIGN_8BYTES UINT32_C(0x00400000) +#define IMAGE_SCN_ALIGN_16BYTES UINT32_C(0x00500000) +#define IMAGE_SCN_ALIGN_32BYTES UINT32_C(0x00600000) +#define IMAGE_SCN_ALIGN_64BYTES UINT32_C(0x00700000) +#define IMAGE_SCN_ALIGN_128BYTES UINT32_C(0x00800000) +#define IMAGE_SCN_ALIGN_256BYTES UINT32_C(0x00900000) +#define IMAGE_SCN_ALIGN_512BYTES UINT32_C(0x00A00000) +#define IMAGE_SCN_ALIGN_1024BYTES UINT32_C(0x00B00000) +#define IMAGE_SCN_ALIGN_2048BYTES UINT32_C(0x00C00000) +#define IMAGE_SCN_ALIGN_4096BYTES UINT32_C(0x00D00000) +#define IMAGE_SCN_ALIGN_8192BYTES UINT32_C(0x00E00000) +#define IMAGE_SCN_ALIGN_MASK UINT32_C(0x00F00000) +#define IMAGE_SCN_ALIGN_SHIFT 20 + +#define IMAGE_SCN_LNK_NRELOC_OVFL UINT32_C(0x01000000) +#define IMAGE_SCN_MEM_DISCARDABLE UINT32_C(0x02000000) +#define IMAGE_SCN_MEM_NOT_CACHED UINT32_C(0x04000000) +#define IMAGE_SCN_MEM_NOT_PAGED UINT32_C(0x08000000) +#define IMAGE_SCN_MEM_SHARED UINT32_C(0x10000000) +#define IMAGE_SCN_MEM_EXECUTE UINT32_C(0x20000000) +#define IMAGE_SCN_MEM_READ UINT32_C(0x40000000) +#define IMAGE_SCN_MEM_WRITE UINT32_C(0x80000000) +/** @} */ + + +/** + * PE image base relocations block header. + * + * This found in IMAGE_DIRECTORY_ENTRY_BASERELOC. Each entry is follow + * immediately by an array of 16-bit words, where the lower 12-bits are used + * for the page offset and the upper 4-bits for the base relocation type + * (IMAGE_REL_BASE_XXX). The block should be padded with + * IMAGE_REL_BASED_ABSOLUTE entries to ensure 32-bit alignment of this header. + */ +typedef struct _IMAGE_BASE_RELOCATION +{ + /** The RVA of the page/block the following ase relocations applies to. */ + uint32_t VirtualAddress; + /** The size of this relocation block, including this header. */ + uint32_t SizeOfBlock; +} IMAGE_BASE_RELOCATION; +AssertCompileSize(IMAGE_BASE_RELOCATION, 8); +typedef IMAGE_BASE_RELOCATION *PIMAGE_BASE_RELOCATION; +typedef IMAGE_BASE_RELOCATION const *PCIMAGE_BASE_RELOCATION; + +/** @name IMAGE_REL_BASED_XXX - PE base relocations. + * Found in the IMAGE_DIRECTORY_ENTRY_BASERELOC data directory. + * @{ */ +#define IMAGE_REL_BASED_ABSOLUTE UINT16_C(0x0) +#define IMAGE_REL_BASED_HIGH UINT16_C(0x1) +#define IMAGE_REL_BASED_LOW UINT16_C(0x2) +#define IMAGE_REL_BASED_HIGHLOW UINT16_C(0x3) +#define IMAGE_REL_BASED_HIGHADJ UINT16_C(0x4) +#define IMAGE_REL_BASED_MIPS_JMPADDR UINT16_C(0x5) +#define IMAGE_REL_BASED_MIPS_JMPADDR16 UINT16_C(0x9) +#define IMAGE_REL_BASED_IA64_IMM64 UINT16_C(0x9) +#define IMAGE_REL_BASED_DIR64 UINT16_C(0xa) +#define IMAGE_REL_BASED_HIGH3ADJ UINT16_C(0xb) +/** @} */ + +/** + * PE export directory entry. + */ +typedef struct _IMAGE_EXPORT_DIRECTORY +{ + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t Name; + uint32_t Base; + uint32_t NumberOfFunctions; + uint32_t NumberOfNames; + uint32_t AddressOfFunctions; + uint32_t AddressOfNames; + uint32_t AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY; +AssertCompileSize(IMAGE_EXPORT_DIRECTORY, 40); +typedef IMAGE_EXPORT_DIRECTORY *PIMAGE_EXPORT_DIRECTORY; +typedef IMAGE_EXPORT_DIRECTORY const *PCIMAGE_EXPORT_DIRECTORY; + + +/** + * PE import directory entry. + */ +typedef struct _IMAGE_IMPORT_DESCRIPTOR +{ + union + { + uint32_t Characteristics; + uint32_t OriginalFirstThunk; + } u; + uint32_t TimeDateStamp; + uint32_t ForwarderChain; + uint32_t Name; + uint32_t FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR; +AssertCompileSize(IMAGE_IMPORT_DESCRIPTOR, 20); +typedef IMAGE_IMPORT_DESCRIPTOR *PIMAGE_IMPORT_DESCRIPTOR; +typedef IMAGE_IMPORT_DESCRIPTOR const *PCIMAGE_IMPORT_DESCRIPTOR; + +/** + * Something we currently don't make use of... + */ +typedef struct _IMAGE_IMPORT_BY_NAME +{ + uint16_t Hint; + uint8_t Name[1]; +} IMAGE_IMPORT_BY_NAME; +AssertCompileSize(IMAGE_IMPORT_BY_NAME, 4); +typedef IMAGE_IMPORT_BY_NAME *PIMAGE_IMPORT_BY_NAME; +typedef IMAGE_IMPORT_BY_NAME const *PCIMAGE_IMPORT_BY_NAME; + + +#if 0 +/* The image_thunk_data32/64 structures are not very helpful except for getting RSI. + keep them around till all the code has been converted. */ +typedef struct _IMAGE_THUNK_DATA64 +{ + union + { + uint64_t ForwarderString; + uint64_t Function; + uint64_t Ordinal; + uint64_t AddressOfData; + } u1; +} IMAGE_THUNK_DATA64; +typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; +typedef IMAGE_THUNK_DATA64 const *PCIMAGE_THUNK_DATA64; + +typedef struct _IMAGE_THUNK_DATA32 +{ + union + { + uint32_t ForwarderString; + uint32_t Function; + uint32_t Ordinal; + uint32_t AddressOfData; + } u1; +} IMAGE_THUNK_DATA32; +typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; +typedef IMAGE_THUNK_DATA32 const *PCIMAGE_THUNK_DATA32; +#endif + +/** @name PE import directory macros. + * @{ */ +#define IMAGE_ORDINAL_FLAG32 UINT32_C(0x80000000) +#define IMAGE_ORDINAL32(ord) ((ord) & UINT32_C(0xffff)) +#define IMAGE_SNAP_BY_ORDINAL32(ord) (!!((ord) & IMAGE_ORDINAL_FLAG32)) + +#define IMAGE_ORDINAL_FLAG64 UINT64_C(0x8000000000000000) +#define IMAGE_ORDINAL64(ord) ((ord) & UINT32_C(0xffff)) +#define IMAGE_SNAP_BY_ORDINAL64(ord) (!!((ord) & IMAGE_ORDINAL_FLAG64)) +/** @} */ + +/** @name PE Resource directory + * @{ */ +typedef struct _IMAGE_RESOURCE_DIRECTORY +{ + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint16_t NumberOfNamedEntries; + uint16_t NumberOfIdEntries; +} IMAGE_RESOURCE_DIRECTORY; +typedef IMAGE_RESOURCE_DIRECTORY *PIMAGE_RESOURCE_DIRECTORY; +typedef IMAGE_RESOURCE_DIRECTORY const *PCIMAGE_RESOURCE_DIRECTORY; + +typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY +{ + union + { + struct + { + uint32_t NameOffset : 31; + uint32_t NameIsString : 1; /**< IMAGE_RESOURCE_NAME_IS_STRING */ + } s; + uint32_t Name; + uint16_t Id; + } u; + union + { + struct + { + uint32_t OffsetToDirectory : 31; + uint32_t DataIsDirectory : 1; /**< IMAGE_RESOURCE_DATA_IS_DIRECTORY*/ + } s2; + uint32_t OffsetToData; + } u2; +} IMAGE_RESOURCE_DIRECTORY_ENTRY; +typedef IMAGE_RESOURCE_DIRECTORY_ENTRY *PIMAGE_RESOURCE_DIRECTORY_ENTRY; +typedef IMAGE_RESOURCE_DIRECTORY_ENTRY const *PCIMAGE_RESOURCE_DIRECTORY_ENTRY; + +#define IMAGE_RESOURCE_NAME_IS_STRING UINT32_C(0x80000000) +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY UINT32_C(0x80000000) + +typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING +{ + uint16_t Length; + char NameString[1]; +} IMAGE_RESOURCE_DIRECTORY_STRING; +typedef IMAGE_RESOURCE_DIRECTORY_STRING *PIMAGE_RESOURCE_DIRECTORY_STRING; +typedef IMAGE_RESOURCE_DIRECTORY_STRING const *PCIMAGE_RESOURCE_DIRECTORY_STRING; + + +typedef struct _IMAGE_RESOURCE_DIR_STRING_U +{ + uint16_t Length; + RTUTF16 NameString[1]; +} IMAGE_RESOURCE_DIR_STRING_U; +typedef IMAGE_RESOURCE_DIR_STRING_U *PIMAGE_RESOURCE_DIR_STRING_U; +typedef IMAGE_RESOURCE_DIR_STRING_U const *PCIMAGE_RESOURCE_DIR_STRING_U; + + +typedef struct _IMAGE_RESOURCE_DATA_ENTRY +{ + uint32_t OffsetToData; + uint32_t Size; + uint32_t CodePage; + uint32_t Reserved; +} IMAGE_RESOURCE_DATA_ENTRY; +typedef IMAGE_RESOURCE_DATA_ENTRY *PIMAGE_RESOURCE_DATA_ENTRY; +typedef IMAGE_RESOURCE_DATA_ENTRY const *PCIMAGE_RESOURCE_DATA_ENTRY; + +/** @} */ + +/** @name Image exception information + * @{ */ + +/** This structure is used by AMD64 and "Itanic". + * MIPS uses a different one. ARM, SH3, SH4 and PPC on WinCE also uses a different one. */ +typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY +{ + uint32_t BeginAddress; + uint32_t EndAddress; + uint32_t UnwindInfoAddress; +} IMAGE_RUNTIME_FUNCTION_ENTRY; +AssertCompileSize(IMAGE_RUNTIME_FUNCTION_ENTRY, 12); +typedef IMAGE_RUNTIME_FUNCTION_ENTRY *PIMAGE_RUNTIME_FUNCTION_ENTRY; +typedef IMAGE_RUNTIME_FUNCTION_ENTRY const *PCIMAGE_RUNTIME_FUNCTION_ENTRY; + +/** + * An unwind code for AMD64 and ARM64. + * + * @note Also known as UNWIND_CODE or _UNWIND_CODE. + */ +typedef union IMAGE_UNWIND_CODE +{ + struct + { + /** The prolog offset where the change takes effect. + * This means the instruction following the one being described. */ + uint8_t CodeOffset; + /** Unwind opcode. + * For AMD64 see IMAGE_AMD64_UNWIND_OP_CODES. */ + RT_GCC_EXTENSION uint8_t UnwindOp : 4; + /** Opcode specific. */ + RT_GCC_EXTENSION uint8_t OpInfo : 4; + } u; + uint16_t FrameOffset; +} IMAGE_UNWIND_CODE; +AssertCompileSize(IMAGE_UNWIND_CODE, 2); + +/** + * Unwind information for AMD64 and ARM64. + * + * Pointed to by IMAGE_RUNTIME_FUNCTION_ENTRY::UnwindInfoAddress, + * + * @note Also known as UNWIND_INFO or _UNWIND_INFO. + */ +typedef struct IMAGE_UNWIND_INFO +{ + /** Version, currently 1 or 2. The latter if IMAGE_AMD64_UWOP_EPILOG is used. */ + RT_GCC_EXTENSION uint8_t Version : 3; + /** IMAGE_UNW_FLAG_XXX */ + RT_GCC_EXTENSION uint8_t Flags : 5; + /** Size of function prolog. */ + uint8_t SizeOfProlog; + /** Number of opcodes in aOpcodes. */ + uint8_t CountOfCodes; + /** Initial frame register. */ + RT_GCC_EXTENSION uint8_t FrameRegister : 4; + /** Scaled frame register offset. */ + RT_GCC_EXTENSION uint8_t FrameOffset : 4; + /** Unwind opcodes. */ + RT_FLEXIBLE_ARRAY_EXTENSION + IMAGE_UNWIND_CODE aOpcodes[RT_FLEXIBLE_ARRAY]; +} IMAGE_UNWIND_INFO; +AssertCompileMemberOffset(IMAGE_UNWIND_INFO, aOpcodes, 4); +typedef IMAGE_UNWIND_INFO *PIMAGE_UNWIND_INFO; +typedef IMAGE_UNWIND_INFO const *PCIMAGE_UNWIND_INFO; + +/** IMAGE_UNW_FLAGS_XXX - IMAGE_UNWIND_INFO::Flags. + * @{ */ +/** No handler. + * @note Also know as UNW_FLAG_NHANDLER. */ +#define IMAGE_UNW_FLAGS_NHANDLER 0 +/** Have exception handler (RVA after codes, dword aligned.) + * @note Also know as UNW_FLAG_NHANDLER. */ +#define IMAGE_UNW_FLAGS_EHANDLER 1 +/** Have unwind handler (RVA after codes, dword aligned.) + * @note Also know as UNW_FLAG_NHANDLER. */ +#define IMAGE_UNW_FLAGS_UHANDLER 2 +/** Set if not primary unwind info for a function. An + * IMAGE_RUNTIME_FUNCTION_ENTRY giving the chained unwind info follows the + * aOpcodes array at a dword aligned offset. */ +#define IMAGE_UNW_FLAGS_CHAININFO 4 +/** @} */ + +/** + * AMD64 unwind opcodes. + */ +typedef enum IMAGE_AMD64_UNWIND_OP_CODES +{ + /** Push non-volatile register (OpInfo). + * YASM: [pushreg reg] + * MASM: .PUSHREG reg */ + IMAGE_AMD64_UWOP_PUSH_NONVOL = 0, + /** Stack allocation: Size stored in scaled in the next slot if OpInfo == 0, + * otherwise stored unscaled in the next two slots. + * YASM: [allocstack size] + * MASM: .ALLOCSTACK size */ + IMAGE_AMD64_UWOP_ALLOC_LARGE, + /** Stack allocation: OpInfo = size / 8 - 1. + * YASM: [allocstack size] + * MASM: .ALLOCSTACK size */ + IMAGE_AMD64_UWOP_ALLOC_SMALL, + /** Set frame pointer register: RSP + FrameOffset * 16. + * YASM: [setframe reg, offset] + * MASM: .SETFRAME reg, offset + * @code + * LEA RBP, [RSP + 20h] + * [setframe RBP, 20h] + * @endcode */ + IMAGE_AMD64_UWOP_SET_FPREG, + /** Save non-volatile register (OpInfo) on stack (RSP/FP + next slot). + * YASM: [savereg reg, offset] + * MASM: .SAVEREG reg, offset */ + IMAGE_AMD64_UWOP_SAVE_NONVOL, + /** Save non-volatile register (OpInfo) on stack (RSP/FP + next two slots). + * YASM: [savereg reg, offset] + * MASM: .SAVEREG reg, offset */ + IMAGE_AMD64_UWOP_SAVE_NONVOL_FAR, + /** Epilog info, version 2+. + * + * The first time this opcode is used, the CodeOffset gives the size of the + * epilog and bit 0 of the OpInfo field indicates that there is only one + * epilog at the very end of the function. + * + * Subsequent uses of this opcode specifies epilog start offsets relative to + * the end of the function, using CodeOffset for the 8 lower bits and OpInfo + * for bits 8 thru 11. + * + * The compiler seems to stack allocations and register saving opcodes and + * indicates the location mirroring the first IMAGE_AMD64_UWOP_PUSH_NONVOL. */ + IMAGE_AMD64_UWOP_EPILOG, + /** Undefined. */ + IMAGE_AMD64_UWOP_RESERVED_7, + /** Save 128-bit XMM register (OpInfo) on stack (RSP/FP + next slot). + * YASM: [savexmm128 reg, offset] + * MASM: .SAVEXMM128 reg, offset */ + IMAGE_AMD64_UWOP_SAVE_XMM128, + /** Save 128-bit XMM register (OpInfo) on stack (RSP/FP + next two slots). + * YASM: [savexmm128 reg, offset] + * MASM: .SAVEXMM128 reg, offset */ + IMAGE_AMD64_UWOP_SAVE_XMM128_FAR, + /** IRET frame, OpInfo serves as error code indicator. + * YASM: [pushframe with-code] + * MASM: .pushframe with-code */ + IMAGE_AMD64_UWOP_PUSH_MACHFRAME +} IMAGE_AMD64_UNWIND_OP_CODES; +/** @} */ + + + +/** @name Image load config directories + * @{ */ + +/** @since Windows 10 (preview 9879) */ +typedef struct _IMAGE_LOAD_CONFIG_CODE_INTEGRITY +{ + uint16_t Flags; + uint16_t Catalog; + uint32_t CatalogOffset; + uint32_t Reserved; +} IMAGE_LOAD_CONFIG_CODE_INTEGRITY; +AssertCompileSize(IMAGE_LOAD_CONFIG_CODE_INTEGRITY, 12); +typedef IMAGE_LOAD_CONFIG_CODE_INTEGRITY *PIMAGE_LOAD_CONFIG_CODE_INTEGRITY; +typedef IMAGE_LOAD_CONFIG_CODE_INTEGRITY const *PCIMAGE_LOAD_CONFIG_CODE_INTEGRITY; + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V1 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V1; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V1, 0x40); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V1 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V1; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V1 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V1; + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V2 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; + uint32_t SEHandlerTable; + uint32_t SEHandlerCount; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V2; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V2, 0x48); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V2 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V2; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V2 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V2; + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V3 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; + uint32_t SEHandlerTable; + uint32_t SEHandlerCount; + uint32_t GuardCFCCheckFunctionPointer; + uint32_t GuardCFDispatchFunctionPointer; + uint32_t GuardCFFunctionTable; + uint32_t GuardCFFunctionCount; + uint32_t GuardFlags; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V3; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V3, 0x5c); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V3 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V3; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V3 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V3; + +/** @since Windows 10 (preview 9879) */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V4 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; + uint32_t SEHandlerTable; + uint32_t SEHandlerCount; + uint32_t GuardCFCCheckFunctionPointer; + uint32_t GuardCFDispatchFunctionPointer; + uint32_t GuardCFFunctionTable; + uint32_t GuardCFFunctionCount; + uint32_t GuardFlags; + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V4; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V4, 0x68); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V4 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V4; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V4 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V4; + +/** @since Windows 10 build 14286 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V5 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; + uint32_t SEHandlerTable; + uint32_t SEHandlerCount; + uint32_t GuardCFCCheckFunctionPointer; + uint32_t GuardCFDispatchFunctionPointer; + uint32_t GuardCFFunctionTable; + uint32_t GuardCFFunctionCount; + uint32_t GuardFlags; + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; + uint32_t GuardAddressTakenIatEntryTable; + uint32_t GuardAddressTakenIatEntryCount; + uint32_t GuardLongJumpTargetTable; + uint32_t GuardLongJumpTargetCount; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V5; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V5, 0x78); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V5 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V5; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V5 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V5; + +/** @since Windows 10 build 14383 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V6 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t HybridMetadataPointer; /**< 0x7c */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V6; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V6, 0x80); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V6 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V6; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V6 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V6; + +/** @since Windows 10 build 14901 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V7 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V7; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V7, 0x90); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V7 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V7; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V7 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V7; + +/** @since Windows 10 build 15002 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V8 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V8; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V8, 0x98); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V8 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V8; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V8 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V8; + +/** @since Windows 10 build 16237 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V9 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V9; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V9, 0xa0); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V9 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V9; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V9 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V9; + +/** @since Windows 10 build 18362 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V10 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c */ + uint32_t VolatileMetadataPointer; /**< 0xa0 */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V10; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V10, 0xa4); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V10 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V10; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V10 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V10; + +/** @since Windows 10 build 19564 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V11 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c - virtual address */ + uint32_t VolatileMetadataPointer; /**< 0xa0 */ + uint32_t GuardEHContinuationTable; /**< 0xa4 - virtual address */ + uint32_t GuardEHContinuationCount; /**< 0xa8 */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V11; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V11, 0xac); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V11 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V11; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V11 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V11; + +/** @since Visual C++ 2019 / RS5_IMAGE_LOAD_CONFIG_DIRECTORY32. */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V12 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c - virtual address */ + uint32_t VolatileMetadataPointer; /**< 0xa0 */ + uint32_t GuardEHContinuationTable; /**< 0xa4 - virtual address */ + uint32_t GuardEHContinuationCount; /**< 0xa8 */ + uint32_t GuardXFGCheckFunctionPointer; /**< 0xac */ + uint32_t GuardXFGDispatchFunctionPointer; /**< 0xb0 */ + uint32_t GuardXFGTableDispatchFunctionPointer; /**< 0xb4 */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V12; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V12, 0xb8); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V12 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V12; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V12 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V12; + +/** @since Visual C++ 2019 16.x (found in 16.11.9) / RS5_IMAGE_LOAD_CONFIG_DIRECTORY32. */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V13 +{ + uint32_t Size; /**< 0x00 - virtual address */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 - virtual address */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c - virtual address */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 - virtual address of pointer variable */ + uint32_t ProcessHeapFlags; /**< 0x2c - virtual address of pointer variable */ + uint32_t ProcessAffinityMask; /**< 0x30 - virtual address */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c - virtual address */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 - virtual address */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c - virtual address */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 - virtual address */ + uint32_t GuardFlags; /**< 0x58 - virtual address of pointer variable */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 - virtual address */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 - virtual address */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 - virtual address */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 - virtual address */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 - virtual address of pointer variable */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 - virtual address of pointer variable */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c - virtual address of pointer variable */ + uint32_t VolatileMetadataPointer; /**< 0xa0 - virtual address of pointer variable */ + uint32_t GuardEHContinuationTable; /**< 0xa4 - virtual address */ + uint32_t GuardEHContinuationCount; /**< 0xa8 */ + uint32_t GuardXFGCheckFunctionPointer; /**< 0xac - virtual address of pointer variable */ + uint32_t GuardXFGDispatchFunctionPointer; /**< 0xb0 - virtual address of pointer variable */ + uint32_t GuardXFGTableDispatchFunctionPointer; /**< 0xb4 - virtual address of pointer variable */ + uint32_t CastGuardOsDeterminedFailureMode; /**< 0xb8 - virtual address */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V13; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V13, 0xbc); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V13 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V13; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V13 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V13; + +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V13 IMAGE_LOAD_CONFIG_DIRECTORY32; +typedef PIMAGE_LOAD_CONFIG_DIRECTORY32_V13 PIMAGE_LOAD_CONFIG_DIRECTORY32; +typedef PCIMAGE_LOAD_CONFIG_DIRECTORY32_V13 PCIMAGE_LOAD_CONFIG_DIRECTORY32; + + +/* No _IMAGE_LOAD_CONFIG_DIRECTORY64_V1 exists. */ + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V2 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint64_t DeCommitFreeBlockThreshold; + uint64_t DeCommitTotalFreeThreshold; + uint64_t LockPrefixTable; + uint64_t MaximumAllocationSize; + uint64_t VirtualMemoryThreshold; + uint64_t ProcessAffinityMask; + uint32_t ProcessHeapFlags; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint64_t EditList; + uint64_t SecurityCookie; + uint64_t SEHandlerTable; + uint64_t SEHandlerCount; +} IMAGE_LOAD_CONFIG_DIRECTORY64_V2; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V2, 0x70); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V2 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V2; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V2 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V2; + +#pragma pack(4) /* Why not 8 byte alignment, baka microsofties?!? */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V3 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint64_t DeCommitFreeBlockThreshold; + uint64_t DeCommitTotalFreeThreshold; + uint64_t LockPrefixTable; + uint64_t MaximumAllocationSize; + uint64_t VirtualMemoryThreshold; + uint64_t ProcessAffinityMask; + uint32_t ProcessHeapFlags; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint64_t EditList; + uint64_t SecurityCookie; + uint64_t SEHandlerTable; + uint64_t SEHandlerCount; + uint64_t GuardCFCCheckFunctionPointer; + uint64_t GuardCFDispatchFunctionPointer; + uint64_t GuardCFFunctionTable; + uint64_t GuardCFFunctionCount; + uint32_t GuardFlags; +} IMAGE_LOAD_CONFIG_DIRECTORY64_V3; +#pragma pack() +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V3, 0x94); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V3 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V3; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V3 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V3; + +/** @since Windows 10 (Preview (9879). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V4 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V4; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V4, 0xa0); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V4 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V4; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V4 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V4; + +/** @since Windows 10 build 14286 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V5 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V5; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V5, 0xc0); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V5 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V5; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V5 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V5; + +/** @since Windows 10 build 14393 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V6 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t HybridMetadataPointer; /**< 0xc8 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V6; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V6, 0xd0); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V6 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V6; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V6 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V6; + +/** @since Windows 10 build 14901 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V7 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 Not sure when this was renamed from HybridMetadataPointer. */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V7; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V7, 0xe8); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V7 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V7; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V7 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V7; + +/** @since Windows 10 build 15002 (or maybe earlier). */ +#pragma pack(4) /* Stupid, stupid microsofties! */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V8 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V8; +#pragma pack() +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V8, 0xf4); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V8 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V8; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V8 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V8; + +/** @since Windows 10 build 15002 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V9 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V9; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V9, 0x100); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V9 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V9; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V9 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V9; + +/** @since Windows 10 build 18362 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V10 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ + uint64_t VolatileMetadataPointer; /**< 0x100 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V10; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V10, 0x108); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V10 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V10; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V10 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V10; + +/** @since Windows 10 build 19534 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V11 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ + uint64_t VolatileMetadataPointer; /**< 0x100 */ + uint64_t GuardEHContinuationTable; /**< 0x108 - virtual address */ + uint64_t GuardEHContinuationCount; /**< 0x110 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V11; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V11, 0x118); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V11 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V11; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V11 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V11; + +/** @since Visual C++ 2019 / RS5_IMAGE_LOAD_CONFIG_DIRECTORY64. */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V12 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ + uint64_t VolatileMetadataPointer; /**< 0x100 */ + uint64_t GuardEHContinuationTable; /**< 0x108 - virtual address */ + uint64_t GuardEHContinuationCount; /**< 0x110 */ + uint64_t GuardXFGCheckFunctionPointer; /**< 0x118 */ + uint64_t GuardXFGDispatchFunctionPointer; /**< 0x120 */ + uint64_t GuardXFGTableDispatchFunctionPointer; /**< 0x128 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V12; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V12, 0x130); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V12 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V12; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V12 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V12; + +/** @since Visual C++ 2019 16.x (found in 16.11.9) / RS5_IMAGE_LOAD_CONFIG_DIRECTORY32. */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V13 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 - virtual address */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 - virtual address */ + uint64_t SecurityCookie; /**< 0x58 - virtual address */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 - virtual address of pointer variable */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 - virtual address of pointer variable */ + uint64_t GuardCFFunctionTable; /**< 0x80 - virtual address */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 - virtual address */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 - virtual address */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 - virtual address */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 - virtual address */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 - virtual address of pointer variable */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 - virtual address of pointer variable */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ + uint64_t VolatileMetadataPointer; /**< 0x100 - virtual address of pointer variable */ + uint64_t GuardEHContinuationTable; /**< 0x108 - virtual address */ + uint64_t GuardEHContinuationCount; /**< 0x110 */ + uint64_t GuardXFGCheckFunctionPointer; /**< 0x118 - virtual address of pointer variable */ + uint64_t GuardXFGDispatchFunctionPointer; /**< 0x120 - virtual address of pointer variable */ + uint64_t GuardXFGTableDispatchFunctionPointer; /**< 0x128 - virtual address of pointer variable */ + uint64_t CastGuardOsDeterminedFailureMode; /**< 0x130 - virtual address */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V13; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V13, 0x138); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V13 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V13; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V13 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V13; + +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V13 IMAGE_LOAD_CONFIG_DIRECTORY64; +typedef PIMAGE_LOAD_CONFIG_DIRECTORY64_V13 PIMAGE_LOAD_CONFIG_DIRECTORY64; +typedef PCIMAGE_LOAD_CONFIG_DIRECTORY64_V13 PCIMAGE_LOAD_CONFIG_DIRECTORY64; + +/** @} */ + + +/** + * PE certificate directory. + * + * Found in IMAGE_DIRECTORY_ENTRY_SECURITY. + */ +typedef struct WIN_CERTIFICATE +{ + uint32_t dwLength; + uint16_t wRevision; + uint16_t wCertificateType; + uint8_t bCertificate[8]; +} WIN_CERTIFICATE; +AssertCompileSize(WIN_CERTIFICATE, 16); +typedef WIN_CERTIFICATE *PWIN_CERTIFICATE; +typedef WIN_CERTIFICATE const *PCWIN_CERTIFICATE; + +/** @name WIN_CERT_REVISION_XXX - Certificate data directory revision. + * Used WIN_CERTIFICATE::wRevision found in the IMAGE_DIRECTORY_ENTRY_SECURITY + * data directory. + * @{ */ +#define WIN_CERT_REVISION_1_0 UINT16_C(0x0100) +#define WIN_CERT_REVISION_2_0 UINT16_C(0x0200) +/** @} */ + +/** @name WIN_CERT_TYPE_XXX - Signature type. + * Used by WIN_CERTIFICATE::wCertificateType. + * @{ */ +#define WIN_CERT_TYPE_X509 UINT16_C(1) +#define WIN_CERT_TYPE_PKCS_SIGNED_DATA UINT16_C(2) +#define WIN_CERT_TYPE_RESERVED_1 UINT16_C(3) +#define WIN_CERT_TYPE_TS_STACK_SIGNED UINT16_C(4) +#define WIN_CERT_TYPE_EFI_PKCS115 UINT16_C(0x0ef0) +#define WIN_CERT_TYPE_EFI_GUID UINT16_C(0x0ef1) +/** @} */ + +/** The alignment of the certificate table. + * @remarks Found thru signtool experiments. + * @note There is a copy of this in RTSignTool.cpp. */ +#define WIN_CERTIFICATE_ALIGNMENT UINT32_C(8) + + +/** + * Debug directory. + * + * Found in IMAGE_DIRECTORY_ENTRY_DEBUG. + */ +typedef struct _IMAGE_DEBUG_DIRECTORY +{ + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t Type; + uint32_t SizeOfData; + uint32_t AddressOfRawData; + uint32_t PointerToRawData; +} IMAGE_DEBUG_DIRECTORY; +AssertCompileSize(IMAGE_DEBUG_DIRECTORY, 28); +typedef IMAGE_DEBUG_DIRECTORY *PIMAGE_DEBUG_DIRECTORY; +typedef IMAGE_DEBUG_DIRECTORY const *PCIMAGE_DEBUG_DIRECTORY; + +/** @name IMAGE_DEBUG_TYPE_XXX - Debug format types. + * Used by IMAGE_DEBUG_DIRECTORY::Type. + * @{ */ +#define IMAGE_DEBUG_TYPE_UNKNOWN UINT32_C(0x00) +#define IMAGE_DEBUG_TYPE_COFF UINT32_C(0x01) +#define IMAGE_DEBUG_TYPE_CODEVIEW UINT32_C(0x02) +#define IMAGE_DEBUG_TYPE_FPO UINT32_C(0x03) +#define IMAGE_DEBUG_TYPE_MISC UINT32_C(0x04) +#define IMAGE_DEBUG_TYPE_EXCEPTION UINT32_C(0x05) +#define IMAGE_DEBUG_TYPE_FIXUP UINT32_C(0x06) +#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC UINT32_C(0x07) +#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC UINT32_C(0x08) +#define IMAGE_DEBUG_TYPE_BORLAND UINT32_C(0x09) +#define IMAGE_DEBUG_TYPE_RESERVED10 UINT32_C(0x0a) +#define IMAGE_DEBUG_TYPE_CLSID UINT32_C(0x0b) +#define IMAGE_DEBUG_TYPE_VC_FEATURE UINT32_C(0x0c) +#define IMAGE_DEBUG_TYPE_POGO UINT32_C(0x0d) +#define IMAGE_DEBUG_TYPE_ILTCG UINT32_C(0x0e) +#define IMAGE_DEBUG_TYPE_MPX UINT32_C(0x0f) +#define IMAGE_DEBUG_TYPE_REPRO UINT32_C(0x10) +/** @} */ + +/** @name IMAGE_DEBUG_MISC_XXX - Misc debug data type. + * Used by IMAGE_DEBUG_MISC::DataType. + * @{ */ +#define IMAGE_DEBUG_MISC_EXENAME UINT32_C(1) +/** @} */ + + +/** + * The format of IMAGE_DEBUG_TYPE_MISC debug info. + */ +typedef struct _IMAGE_DEBUG_MISC +{ + uint32_t DataType; + uint32_t Length; + uint8_t Unicode; + uint8_t Reserved[3]; + uint8_t Data[1]; +} IMAGE_DEBUG_MISC; +AssertCompileSize(IMAGE_DEBUG_MISC, 16); +typedef IMAGE_DEBUG_MISC *PIMAGE_DEBUG_MISC; +typedef IMAGE_DEBUG_MISC const *PCIMAGE_DEBUG_MISC; + + + +/** + * The header of a .DBG file (NT4). + */ +typedef struct _IMAGE_SEPARATE_DEBUG_HEADER +{ + uint16_t Signature; /**< 0x00 */ + uint16_t Flags; /**< 0x02 */ + uint16_t Machine; /**< 0x04 */ + uint16_t Characteristics; /**< 0x06 */ + uint32_t TimeDateStamp; /**< 0x08 */ + uint32_t CheckSum; /**< 0x0c */ + uint32_t ImageBase; /**< 0x10 */ + uint32_t SizeOfImage; /**< 0x14 */ + uint32_t NumberOfSections; /**< 0x18 */ + uint32_t ExportedNamesSize; /**< 0x1c */ + uint32_t DebugDirectorySize; /**< 0x20 */ + uint32_t SectionAlignment; /**< 0x24 */ + uint32_t Reserved[2]; /**< 0x28 */ +} IMAGE_SEPARATE_DEBUG_HEADER; /* size: 0x30 */ +AssertCompileSize(IMAGE_SEPARATE_DEBUG_HEADER, 0x30); +typedef IMAGE_SEPARATE_DEBUG_HEADER *PIMAGE_SEPARATE_DEBUG_HEADER; +typedef IMAGE_SEPARATE_DEBUG_HEADER const *PCIMAGE_SEPARATE_DEBUG_HEADER; + +/** The signature of a IMAGE_SEPARATE_DEBUG_HEADER. */ +#define IMAGE_SEPARATE_DEBUG_SIGNATURE UINT16_C(0x4944) + + +/** + * The format of IMAGE_DEBUG_TYPE_COFF debug info. + */ +typedef struct _IMAGE_COFF_SYMBOLS_HEADER +{ + uint32_t NumberOfSymbols; + uint32_t LvaToFirstSymbol; + uint32_t NumberOfLinenumbers; + uint32_t LvaToFirstLinenumber; + uint32_t RvaToFirstByteOfCode; + uint32_t RvaToLastByteOfCode; + uint32_t RvaToFirstByteOfData; + uint32_t RvaToLastByteOfData; +} IMAGE_COFF_SYMBOLS_HEADER; +AssertCompileSize(IMAGE_COFF_SYMBOLS_HEADER, 0x20); +typedef IMAGE_COFF_SYMBOLS_HEADER *PIMAGE_COFF_SYMBOLS_HEADER; +typedef IMAGE_COFF_SYMBOLS_HEADER const *PCIMAGE_COFF_SYMBOLS_HEADER; + + +/** + * Line number format of IMAGE_DEBUG_TYPE_COFF debug info. + * + * @remarks This has misaligned members. + */ +#pragma pack(2) +typedef struct _IMAGE_LINENUMBER +{ + union + { + uint32_t VirtualAddress; + uint32_t SymbolTableIndex; + } Type; + uint16_t Linenumber; +} IMAGE_LINENUMBER; +#pragma pack() +AssertCompileSize(IMAGE_LINENUMBER, 6); +typedef IMAGE_LINENUMBER *PIMAGE_LINENUMBER; +typedef IMAGE_LINENUMBER const *PCIMAGE_LINENUMBER; + + +/** The size of a IMAGE_SYMBOL & IMAGE_AUX_SYMBOL structure. */ +#define IMAGE_SIZE_OF_SYMBOL 18 +/** The size of a IMAGE_SYMBOL_EX & IMAGE_AUX_SYMBOL_EX structure. */ +#define IMAGE_SIZE_OF_SYMBOL_EX 20 + +/** + * COFF symbol. + */ +#pragma pack(2) +typedef struct _IMAGE_SYMBOL +{ + union + { + uint8_t ShortName[8]; + struct + { + uint32_t Short; + uint32_t Long; + } Name; + uint32_t LongName[2]; + } N; + + uint32_t Value; + int16_t SectionNumber; + uint16_t Type; + uint8_t StorageClass; + uint8_t NumberOfAuxSymbols; +} IMAGE_SYMBOL; +#pragma pack() +AssertCompileSize(IMAGE_SYMBOL, IMAGE_SIZE_OF_SYMBOL); +typedef IMAGE_SYMBOL *PIMAGE_SYMBOL; +typedef IMAGE_SYMBOL const *PCIMAGE_SYMBOL; + +/** + * COFF auxiliary symbol token defintion (whatever that is). + */ +#pragma pack(2) +typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF +{ + uint8_t bAuxType; + uint8_t bReserved; + uint32_t SymbolTableIndex; + uint8_t rgbReserved[12]; +} IMAGE_AUX_SYMBOL_TOKEN_DEF; +#pragma pack() +AssertCompileSize(IMAGE_AUX_SYMBOL_TOKEN_DEF, IMAGE_SIZE_OF_SYMBOL); +typedef IMAGE_AUX_SYMBOL_TOKEN_DEF *PIMAGE_AUX_SYMBOL_TOKEN_DEF; +typedef IMAGE_AUX_SYMBOL_TOKEN_DEF const *PCIMAGE_AUX_SYMBOL_TOKEN_DEF; + +/** + * COFF auxiliary symbol. + */ +#pragma pack(1) +typedef union _IMAGE_AUX_SYMBOL +{ + struct + { + uint32_t TagIndex; + union + { + struct + { + uint16_t Linenumber; + uint16_t Size; + } LnSz; + } Misc; + union + { + struct + { + uint32_t PointerToLinenumber; + uint32_t PointerToNextFunction; + } Function; + struct + { + uint16_t Dimension[4]; + } Array; + } FcnAry; + uint16_t TvIndex; + } Sym; + + struct + { + uint8_t Name[IMAGE_SIZE_OF_SYMBOL]; + } File; + + struct + { + uint32_t Length; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t CheckSum; + uint16_t Number; + uint8_t Selection; + uint8_t bReserved; + uint16_t HighNumber; + } Section; + + IMAGE_AUX_SYMBOL_TOKEN_DEF TokenDef; + struct + { + uint32_t crc; + uint8_t rgbReserved[14]; + } CRC; +} IMAGE_AUX_SYMBOL; +#pragma pack() +AssertCompileSize(IMAGE_AUX_SYMBOL, IMAGE_SIZE_OF_SYMBOL); +typedef IMAGE_AUX_SYMBOL *PIMAGE_AUX_SYMBOL; +typedef IMAGE_AUX_SYMBOL const *PCIMAGE_AUX_SYMBOL; + + +/** + * Extended COFF symbol. + */ +typedef struct _IMAGE_SYMBOL_EX +{ + union + { + uint8_t ShortName[8]; + struct + { + uint32_t Short; + uint32_t Long; + } Name; + uint32_t LongName[2]; + } N; + + uint32_t Value; + int32_t SectionNumber; /* The difference from IMAGE_SYMBOL */ + uint16_t Type; + uint8_t StorageClass; + uint8_t NumberOfAuxSymbols; +} IMAGE_SYMBOL_EX; +AssertCompileSize(IMAGE_SYMBOL_EX, IMAGE_SIZE_OF_SYMBOL_EX); +typedef IMAGE_SYMBOL_EX *PIMAGE_SYMBOL_EX; +typedef IMAGE_SYMBOL_EX const *PCIMAGE_SYMBOL_EX; + +/** + * Extended COFF auxiliary symbol. + */ +typedef union _IMAGE_AUX_SYMBOL_EX +{ + struct + { + uint32_t WeakDefaultSymIndex; + uint32_t WeakSearchType; + uint8_t rgbReserved[12]; + } Sym; + + struct + { + uint8_t Name[IMAGE_SIZE_OF_SYMBOL_EX]; + } File; + + struct + { + uint32_t Length; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t CheckSum; + uint16_t Number; + uint8_t Selection; + uint8_t bReserved; + uint16_t HighNumber; + uint8_t rgbReserved[2]; + } Section; + + IMAGE_AUX_SYMBOL_TOKEN_DEF TokenDef; + + struct + { + uint32_t crc; + uint8_t rgbReserved[16]; + } CRC; +} IMAGE_AUX_SYMBOL_EX; +AssertCompileSize(IMAGE_AUX_SYMBOL_EX, IMAGE_SIZE_OF_SYMBOL_EX); +typedef IMAGE_AUX_SYMBOL_EX *PIMAGE_AUX_SYMBOL_EX; +typedef IMAGE_AUX_SYMBOL_EX const *PCIMAGE_AUX_SYMBOL_EX; + +/** @name Special COFF section numbers. + * Used by IMAGE_SYMBOL::SectionNumber and IMAGE_SYMBOL_EX::SectionNumber + * @{ */ +#define IMAGE_SYM_UNDEFINED INT16_C(0) +#define IMAGE_SYM_ABSOLUTE INT16_C(-1) +#define IMAGE_SYM_DEBUG INT16_C(-2) +/** @} */ + +/** @name IMAGE_SYM_CLASS_XXX - COFF symbol storage classes. + * @{ */ +#define IMAGE_SYM_CLASS_END_OF_FUNCTION UINT8_C(0xff) /* -1 */ +#define IMAGE_SYM_CLASS_NULL UINT8_C(0) +#define IMAGE_SYM_CLASS_AUTOMATIC UINT8_C(1) +#define IMAGE_SYM_CLASS_EXTERNAL UINT8_C(2) +#define IMAGE_SYM_CLASS_STATIC UINT8_C(3) +#define IMAGE_SYM_CLASS_REGISTER UINT8_C(4) +#define IMAGE_SYM_CLASS_EXTERNAL_DEF UINT8_C(5) +#define IMAGE_SYM_CLASS_LABEL UINT8_C(6) +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL UINT8_C(7) +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT UINT8_C(8) +#define IMAGE_SYM_CLASS_ARGUMENT UINT8_C(9) +#define IMAGE_SYM_CLASS_STRUCT_TAG UINT8_C(10) +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION UINT8_C(11) +#define IMAGE_SYM_CLASS_UNION_TAG UINT8_C(12) +#define IMAGE_SYM_CLASS_TYPE_DEFINITION UINT8_C(13) +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC UINT8_C(14) +#define IMAGE_SYM_CLASS_ENUM_TAG UINT8_C(15) +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM UINT8_C(16) +#define IMAGE_SYM_CLASS_REGISTER_PARAM UINT8_C(17) +#define IMAGE_SYM_CLASS_BIT_FIELD UINT8_C(18) +#define IMAGE_SYM_CLASS_FAR_EXTERNAL UINT8_C(68) +#define IMAGE_SYM_CLASS_BLOCK UINT8_C(100) +#define IMAGE_SYM_CLASS_FUNCTION UINT8_C(101) +#define IMAGE_SYM_CLASS_END_OF_STRUCT UINT8_C(102) +#define IMAGE_SYM_CLASS_FILE UINT8_C(103) +#define IMAGE_SYM_CLASS_SECTION UINT8_C(104) +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL UINT8_C(105) +#define IMAGE_SYM_CLASS_CLR_TOKEN UINT8_C(107) +/** @} */ + +/** @name IMAGE_SYM_TYPE_XXX - COFF symbol base types + * @{ */ +#define IMAGE_SYM_TYPE_NULL UINT16_C(0x0000) +#define IMAGE_SYM_TYPE_VOID UINT16_C(0x0001) +#define IMAGE_SYM_TYPE_CHAR UINT16_C(0x0002) +#define IMAGE_SYM_TYPE_SHORT UINT16_C(0x0003) +#define IMAGE_SYM_TYPE_INT UINT16_C(0x0004) +#define IMAGE_SYM_TYPE_LONG UINT16_C(0x0005) +#define IMAGE_SYM_TYPE_FLOAT UINT16_C(0x0006) +#define IMAGE_SYM_TYPE_DOUBLE UINT16_C(0x0007) +#define IMAGE_SYM_TYPE_STRUCT UINT16_C(0x0008) +#define IMAGE_SYM_TYPE_UNION UINT16_C(0x0009) +#define IMAGE_SYM_TYPE_ENUM UINT16_C(0x000a) +#define IMAGE_SYM_TYPE_MOE UINT16_C(0x000b) +#define IMAGE_SYM_TYPE_BYTE UINT16_C(0x000c) +#define IMAGE_SYM_TYPE_WORD UINT16_C(0x000d) +#define IMAGE_SYM_TYPE_UINT UINT16_C(0x000e) +#define IMAGE_SYM_TYPE_DWORD UINT16_C(0x000f) +#define IMAGE_SYM_TYPE_PCODE UINT16_C(0x8000) +/** @} */ + +/** @name IMAGE_SYM_DTYPE_XXX - COFF symbol complex types + * @{ */ +#define IMAGE_SYM_DTYPE_NULL UINT16_C(0x0) +#define IMAGE_SYM_DTYPE_POINTER UINT16_C(0x1) +#define IMAGE_SYM_DTYPE_FUNCTION UINT16_C(0x2) +#define IMAGE_SYM_DTYPE_ARRAY UINT16_C(0x3) +/** @} */ + +/** @name COFF Symbol type masks and shift counts. + * @{ */ +#define N_BTMASK UINT16_C(0x000f) +#define N_TMASK UINT16_C(0x0030) +#define N_TMASK1 UINT16_C(0x00c0) +#define N_TMASK2 UINT16_C(0x00f0) +#define N_BTSHFT 4 +#define N_TSHIFT 2 +/** @} */ + +/** @name COFF Symbol type macros. + * @{ */ +#define BTYPE(a_Type) ( (a_Type) & N_BTMASK ) +#define ISPTR(a_Type) ( ((a_Type) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT) ) +#define ISFCN(a_Type) ( ((a_Type) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT) ) +#define ISARY(a_Type) ( ((a_Type) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT) ) +#define ISTAG(a_StorageClass) ( (a_StorageClass) == IMAGE_SYM_CLASS_STRUCT_TAG \ + || (a_StorageClass) == IMAGE_SYM_CLASS_UNION_TAG \ + || (a_StorageClass) == IMAGE_SYM_CLASS_ENUM_TAG ) +/** @} */ + + +/** + * COFF relocation table entry. + * + * @note The size of the structure is not a multiple of the largest member + * (uint32_t), so odd relocation table entry members will have + * misaligned uint32_t members. + */ +#pragma pack(1) +typedef struct _IMAGE_RELOCATION +{ + union + { + uint32_t VirtualAddress; + uint32_t RelocCount; + } u; + uint32_t SymbolTableIndex; + uint16_t Type; +} IMAGE_RELOCATION; +#pragma pack() +/** The size of a COFF relocation entry. */ +#define IMAGE_SIZEOF_RELOCATION 10 +AssertCompileSize(IMAGE_RELOCATION, IMAGE_SIZEOF_RELOCATION); +typedef IMAGE_RELOCATION *PIMAGE_RELOCATION; +typedef IMAGE_RELOCATION const *PCIMAGE_RELOCATION; + + +/** @name IMAGE_REL_AMD64_XXX - COFF relocations for AMD64 CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_AMD64_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_AMD64_ADDR64 UINT16_C(0x0001) +#define IMAGE_REL_AMD64_ADDR32 UINT16_C(0x0002) +#define IMAGE_REL_AMD64_ADDR32NB UINT16_C(0x0003) +#define IMAGE_REL_AMD64_REL32 UINT16_C(0x0004) +#define IMAGE_REL_AMD64_REL32_1 UINT16_C(0x0005) +#define IMAGE_REL_AMD64_REL32_2 UINT16_C(0x0006) +#define IMAGE_REL_AMD64_REL32_3 UINT16_C(0x0007) +#define IMAGE_REL_AMD64_REL32_4 UINT16_C(0x0008) +#define IMAGE_REL_AMD64_REL32_5 UINT16_C(0x0009) +#define IMAGE_REL_AMD64_SECTION UINT16_C(0x000a) +#define IMAGE_REL_AMD64_SECREL UINT16_C(0x000b) +#define IMAGE_REL_AMD64_SECREL7 UINT16_C(0x000c) +#define IMAGE_REL_AMD64_TOKEN UINT16_C(0x000d) +#define IMAGE_REL_AMD64_SREL32 UINT16_C(0x000e) +#define IMAGE_REL_AMD64_PAIR UINT16_C(0x000f) +#define IMAGE_REL_AMD64_SSPAN32 UINT16_C(0x0010) +/** @} */ + +/** @name ARM IMAGE_REL_ARM_XXX - COFF relocations for ARM CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_ARM_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_ARM_ADDR32 UINT16_C(0x0001) +#define IMAGE_REL_ARM_ADDR32NB UINT16_C(0x0002) +#define IMAGE_REL_ARM_BRANCH24 UINT16_C(0x0003) +#define IMAGE_REL_ARM_BRANCH11 UINT16_C(0x0004) +#define IMAGE_REL_ARM_TOKEN UINT16_C(0x0005) +#define IMAGE_REL_ARM_BLX24 UINT16_C(0x0008) +#define IMAGE_REL_ARM_BLX11 UINT16_C(0x0009) +#define IMAGE_REL_ARM_SECTION UINT16_C(0x000e) +#define IMAGE_REL_ARM_SECREL UINT16_C(0x000f) +#define IMAGE_REL_ARM_MOV32A UINT16_C(0x0010) +#define IMAGE_REL_ARM_MOV32T UINT16_C(0x0011) +#define IMAGE_REL_ARM_BRANCH20T UINT16_C(0x0012) +#define IMAGE_REL_ARM_BRANCH24T UINT16_C(0x0014) +#define IMAGE_REL_ARM_BLX23T UINT16_C(0x0015) +/** @} */ + +/** @name IMAGE_REL_ARM64_XXX - COFF relocations for ARMv8 CPUs (64-bit). + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_ARM64_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_ARM64_ADDR32 UINT16_C(0x0001) +#define IMAGE_REL_ARM64_ADDR32NB UINT16_C(0x0002) +#define IMAGE_REL_ARM64_BRANCH26 UINT16_C(0x0003) +#define IMAGE_REL_ARM64_PAGEBASE_REL21 UINT16_C(0x0004) +#define IMAGE_REL_ARM64_REL21 UINT16_C(0x0005) +#define IMAGE_REL_ARM64_PAGEOFFSET_12A UINT16_C(0x0006) +#define IMAGE_REL_ARM64_PAGEOFFSET_12L UINT16_C(0x0007) +#define IMAGE_REL_ARM64_SECREL UINT16_C(0x0008) +#define IMAGE_REL_ARM64_SECREL_LOW12A UINT16_C(0x0009) +#define IMAGE_REL_ARM64_SECREL_HIGH12A UINT16_C(0x000a) +#define IMAGE_REL_ARM64_SECREL_LOW12L UINT16_C(0x000b) +#define IMAGE_REL_ARM64_TOKEN UINT16_C(0x000c) +#define IMAGE_REL_ARM64_SECTION UINT16_C(0x000d) +#define IMAGE_REL_ARM64_ADDR64 UINT16_C(0x000e) +/** @} */ + +/** @name IMAGE_REL_SH3_XXX - COFF relocation for Hitachi SuperH CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_SH3_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_SH3_DIRECT16 UINT16_C(0x0001) +#define IMAGE_REL_SH3_DIRECT32 UINT16_C(0x0002) +#define IMAGE_REL_SH3_DIRECT8 UINT16_C(0x0003) +#define IMAGE_REL_SH3_DIRECT8_WORD UINT16_C(0x0004) +#define IMAGE_REL_SH3_DIRECT8_LONG UINT16_C(0x0005) +#define IMAGE_REL_SH3_DIRECT4 UINT16_C(0x0006) +#define IMAGE_REL_SH3_DIRECT4_WORD UINT16_C(0x0007) +#define IMAGE_REL_SH3_DIRECT4_LONG UINT16_C(0x0008) +#define IMAGE_REL_SH3_PCREL8_WORD UINT16_C(0x0009) +#define IMAGE_REL_SH3_PCREL8_LONG UINT16_C(0x000a) +#define IMAGE_REL_SH3_PCREL12_WORD UINT16_C(0x000b) +#define IMAGE_REL_SH3_STARTOF_SECTION UINT16_C(0x000c) +#define IMAGE_REL_SH3_SIZEOF_SECTION UINT16_C(0x000d) +#define IMAGE_REL_SH3_SECTION UINT16_C(0x000e) +#define IMAGE_REL_SH3_SECREL UINT16_C(0x000f) +#define IMAGE_REL_SH3_DIRECT32_NB UINT16_C(0x0010) +#define IMAGE_REL_SH3_GPREL4_LONG UINT16_C(0x0011) +#define IMAGE_REL_SH3_TOKEN UINT16_C(0x0012) +#define IMAGE_REL_SHM_PCRELPT UINT16_C(0x0013) +#define IMAGE_REL_SHM_REFLO UINT16_C(0x0014) +#define IMAGE_REL_SHM_REFHALF UINT16_C(0x0015) +#define IMAGE_REL_SHM_RELLO UINT16_C(0x0016) +#define IMAGE_REL_SHM_RELHALF UINT16_C(0x0017) +#define IMAGE_REL_SHM_PAIR UINT16_C(0x0018) +#define IMAGE_REL_SHM_NOMODE UINT16_C(0x8000) +/** @} */ + +/** @name IMAGE_REL_PPC_XXX - COFF relocations for IBM PowerPC CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_PPC_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_PPC_ADDR64 UINT16_C(0x0001) +#define IMAGE_REL_PPC_ADDR32 UINT16_C(0x0002) +#define IMAGE_REL_PPC_ADDR24 UINT16_C(0x0003) +#define IMAGE_REL_PPC_ADDR16 UINT16_C(0x0004) +#define IMAGE_REL_PPC_ADDR14 UINT16_C(0x0005) +#define IMAGE_REL_PPC_REL24 UINT16_C(0x0006) +#define IMAGE_REL_PPC_REL14 UINT16_C(0x0007) +#define IMAGE_REL_PPC_ADDR32NB UINT16_C(0x000a) +#define IMAGE_REL_PPC_SECREL UINT16_C(0x000b) +#define IMAGE_REL_PPC_SECTION UINT16_C(0x000c) +#define IMAGE_REL_PPC_SECREL16 UINT16_C(0x000f) +#define IMAGE_REL_PPC_REFHI UINT16_C(0x0010) +#define IMAGE_REL_PPC_REFLO UINT16_C(0x0011) +#define IMAGE_REL_PPC_PAIR UINT16_C(0x0012) +#define IMAGE_REL_PPC_SECRELLO UINT16_C(0x0013) +#define IMAGE_REL_PPC_GPREL UINT16_C(0x0015) +#define IMAGE_REL_PPC_TOKEN UINT16_C(0x0016) +/** @} */ + +/** @name IMAGE_REL_I386_XXX - COFF relocations for x86 CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_I386_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_I386_DIR16 UINT16_C(0x0001) +#define IMAGE_REL_I386_REL16 UINT16_C(0x0002) +#define IMAGE_REL_I386_DIR32 UINT16_C(0x0006) +#define IMAGE_REL_I386_DIR32NB UINT16_C(0x0007) +#define IMAGE_REL_I386_SEG12 UINT16_C(0x0009) +#define IMAGE_REL_I386_SECTION UINT16_C(0x000A) +#define IMAGE_REL_I386_SECREL UINT16_C(0x000B) +#define IMAGE_REL_I386_TOKEN UINT16_C(0x000C) +#define IMAGE_REL_I386_SECREL7 UINT16_C(0x000D) +#define IMAGE_REL_I386_REL32 UINT16_C(0x0014) +/** @} */ + +/** @name IMAGE_REL_IA64_XXX - COFF relocations for "Itanic" CPUs. + * @{ */ +#define IMAGE_REL_IA64_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_IA64_IMM14 UINT16_C(0x0001) +#define IMAGE_REL_IA64_IMM22 UINT16_C(0x0002) +#define IMAGE_REL_IA64_IMM64 UINT16_C(0x0003) +#define IMAGE_REL_IA64_DIR32 UINT16_C(0x0004) +#define IMAGE_REL_IA64_DIR64 UINT16_C(0x0005) +#define IMAGE_REL_IA64_PCREL21B UINT16_C(0x0006) +#define IMAGE_REL_IA64_PCREL21M UINT16_C(0x0007) +#define IMAGE_REL_IA64_PCREL21F UINT16_C(0x0008) +#define IMAGE_REL_IA64_GPREL22 UINT16_C(0x0009) +#define IMAGE_REL_IA64_LTOFF22 UINT16_C(0x000a) +#define IMAGE_REL_IA64_SECTION UINT16_C(0x000b) +#define IMAGE_REL_IA64_SECREL22 UINT16_C(0x000c) +#define IMAGE_REL_IA64_SECREL64I UINT16_C(0x000d) +#define IMAGE_REL_IA64_SECREL32 UINT16_C(0x000e) +#define IMAGE_REL_IA64_DIR32NB UINT16_C(0x0010) +#define IMAGE_REL_IA64_SREL14 UINT16_C(0x0011) +#define IMAGE_REL_IA64_SREL22 UINT16_C(0x0012) +#define IMAGE_REL_IA64_SREL32 UINT16_C(0x0013) +#define IMAGE_REL_IA64_UREL32 UINT16_C(0x0014) +#define IMAGE_REL_IA64_PCREL60X UINT16_C(0x0015) +#define IMAGE_REL_IA64_PCREL60B UINT16_C(0x0016) +#define IMAGE_REL_IA64_PCREL60F UINT16_C(0x0017) +#define IMAGE_REL_IA64_PCREL60I UINT16_C(0x0018) +#define IMAGE_REL_IA64_PCREL60M UINT16_C(0x0019) +#define IMAGE_REL_IA64_IMMGPREL64 UINT16_C(0x001a) +#define IMAGE_REL_IA64_TOKEN UINT16_C(0x001b) +#define IMAGE_REL_IA64_GPREL32 UINT16_C(0x001c) +#define IMAGE_REL_IA64_ADDEND UINT16_C(0x001f) +/** @} */ + +/** @name IMAGE_REL_MIPS_XXX - COFF relocations for MIPS CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_MIPS_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_MIPS_REFHALF UINT16_C(0x0001) +#define IMAGE_REL_MIPS_REFWORD UINT16_C(0x0002) +#define IMAGE_REL_MIPS_JMPADDR UINT16_C(0x0003) +#define IMAGE_REL_MIPS_REFHI UINT16_C(0x0004) +#define IMAGE_REL_MIPS_REFLO UINT16_C(0x0005) +#define IMAGE_REL_MIPS_GPREL UINT16_C(0x0006) +#define IMAGE_REL_MIPS_LITERAL UINT16_C(0x0007) +#define IMAGE_REL_MIPS_SECTION UINT16_C(0x000a) +#define IMAGE_REL_MIPS_SECREL UINT16_C(0x000b) +#define IMAGE_REL_MIPS_SECRELLO UINT16_C(0x000c) +#define IMAGE_REL_MIPS_SECRELHI UINT16_C(0x000d) +#define IMAGE_REL_MIPS_JMPADDR16 UINT16_C(0x0010) +#define IMAGE_REL_MIPS_REFWORDNB UINT16_C(0x0022) +#define IMAGE_REL_MIPS_PAIR UINT16_C(0x0025) +/** @} */ + +/** @name IMAGE_REL_M32R_XXX - COFF relocations for Mitsubishi M32R CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_M32R_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_M32R_ADDR32 UINT16_C(0x0001) +#define IMAGE_REL_M32R_ADDR32NB UINT16_C(0x0002) +#define IMAGE_REL_M32R_ADDR24 UINT16_C(0x0003) +#define IMAGE_REL_M32R_GPREL16 UINT16_C(0x0004) +#define IMAGE_REL_M32R_PCREL24 UINT16_C(0x0005) +#define IMAGE_REL_M32R_PCREL16 UINT16_C(0x0006) +#define IMAGE_REL_M32R_PCREL8 UINT16_C(0x0007) +#define IMAGE_REL_M32R_REFHALF UINT16_C(0x0008) +#define IMAGE_REL_M32R_REFHI UINT16_C(0x0009) +#define IMAGE_REL_M32R_REFLO UINT16_C(0x000a) +#define IMAGE_REL_M32R_PAIR UINT16_C(0x000b) +#define IMAGE_REL_M32R_SECTION UINT16_C(0x000c) +#define IMAGE_REL_M32R_SECREL UINT16_C(0x000d) +#define IMAGE_REL_M32R_TOKEN UINT16_C(0x000e) +/** @} */ + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_pecoff_h */ + diff --git a/include/iprt/formats/riff.h b/include/iprt/formats/riff.h new file mode 100644 index 00000000..91de3bec --- /dev/null +++ b/include/iprt/formats/riff.h @@ -0,0 +1,247 @@ +/* $Id: riff.h $ */ +/** @file + * IPRT - Resource Interchange File Format (RIFF), WAVE, ++. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_riff_h +#define IPRT_INCLUDED_formats_riff_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_riff RIFF & WAVE structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/** + * Resource interchange file format (RIFF) file header. + */ +typedef struct RTRIFFHDR +{ + /** The 'RIFF' magic (RTRIFFHDR_MAGIC). */ + uint32_t uMagic; + /** The file size. */ + uint32_t cbFile; + /** The file type. */ + uint32_t uFileType; +} RTRIFFHDR; +AssertCompileSize(RTRIFFHDR, 12); +/** Pointer to a RIFF file header. */ +typedef RTRIFFHDR *PRTRIFFHDR; + +/** Magic value for RTRIFFHDR::uMagic ('RIFF'). */ +#define RTRIFFHDR_MAGIC RT_BE2H_U32_C(0x52494646) + +/** @name RIFF file types (RTRIFFHDR::uFileType) + * @{ */ +/** RIFF file type: WAVE (audio) */ +#define RTRIFF_FILE_TYPE_WAVE RT_BE2H_U32_C(0x57415645) +/** RIFF file type: AVI (video) */ +#define RTRIFF_FILE_TYPE_AVI RT_BE2H_U32_C(0x41564920) +/** @} */ + +/** + * A RIFF chunk. + */ +typedef struct RTRIFFCHUNK +{ + /** The chunk magic (four character code). */ + uint32_t uMagic; + /** The size of the chunk minus this header. */ + uint32_t cbChunk; +} RTRIFFCHUNK; +AssertCompileSize(RTRIFFCHUNK, 8); +/** Pointer to a RIFF chunk. */ +typedef RTRIFFCHUNK *PRTRIFFCHUNK; + +/** + * A RIFF list. + */ +typedef struct RTRIFFLIST +{ + /** The list indicator (RTRIFFLIST_MAGIC). */ + uint32_t uMagic; + /** The size of the chunk minus this header. */ + uint32_t cbChunk; + /** The list type (four character code). */ + uint32_t uListType; +} RTRIFFLIST; +AssertCompileSize(RTRIFFLIST, 12); +/** Pointer to a RIFF list. */ +typedef RTRIFFLIST *PRTRIFFLIST; +/** Magic value for RTRIFFLIST::uMagic ('LIST'). */ +#define RTRIFFLIST_MAGIC RT_BE2H_U32_C(0x4c495354) + +/** Generic 'INFO' list type. */ +#define RTRIFFLIST_TYPE_INFO RT_BE2H_U32_C(0x494e464f) + + +/** + * Wave file format (WAVEFORMATEX w/o cbSize). + * @see RTRIFFWAVEFMTCHUNK. + */ +typedef struct RTRIFFWAVEFMT +{ + /** Audio format tag. */ + uint16_t uFormatTag; + /** Number of channels. */ + uint16_t cChannels; + /** Sample rate. */ + uint32_t uHz; + /** Byte rate (= uHz * cChannels * cBitsPerSample / 8) */ + uint32_t cbRate; + /** Frame size (aka block alignment). */ + uint16_t cbFrame; + /** Number of bits per sample. */ + uint16_t cBitsPerSample; +} RTRIFFWAVEFMT; +AssertCompileSize(RTRIFFWAVEFMT, 16); +/** Pointer to a wave file format structure. */ +typedef RTRIFFWAVEFMT *PRTRIFFWAVEFMT; + +/** + * Extensible wave file format (WAVEFORMATEXTENSIBLE). + * @see RTRIFFWAVEFMTEXTCHUNK. + */ +#pragma pack(4) /* Override the uint64_t effect from RTUUID, so we can safely put it after RTRIFFHDR in a structure. */ +typedef struct RTRIFFWAVEFMTEXT +{ + /** The coreformat structure. */ + RTRIFFWAVEFMT Core; + /** Number of bytes of extra information after the core. */ + uint16_t cbExtra; + /** Number of valid bits per sample. */ + uint16_t cValidBitsPerSample; + /** The channel mask. */ + uint32_t fChannelMask; + /** The GUID of the sub-format. */ + RTUUID SubFormat; +} RTRIFFWAVEFMTEXT; +#pragma pack() +AssertCompileSize(RTRIFFWAVEFMTEXT, 16+2+22); +/** Pointer to an extensible wave file format structure. */ +typedef RTRIFFWAVEFMTEXT *PRTRIFFWAVEFMTEXT; + +/** RTRIFFWAVEFMT::uFormatTag value for PCM (WDK: WAVE_FORMAT_PCM). */ +#define RTRIFFWAVEFMT_TAG_PCM UINT16_C(0x0001) +/** RTRIFFWAVEFMT::uFormatTag value for extensible wave files (WDK: WAVE_FORMAT_EXTENSIBLE). */ +#define RTRIFFWAVEFMT_TAG_EXTENSIBLE UINT16_C(0xfffe) + +/** Typical RTRIFFWAVEFMTEXT::cbExtra value (min). */ +#define RTRIFFWAVEFMTEXT_EXTRA_SIZE UINT16_C(22) + +/** @name Channel IDs for RTRIFFWAVEFMTEXT::fChannelMask. + * @{ */ +#define RTRIFFWAVEFMTEXT_CH_ID_FL RT_BIT_32(0) /**< Front left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_FR RT_BIT_32(1) /**< Front right. */ +#define RTRIFFWAVEFMTEXT_CH_ID_FC RT_BIT_32(2) /**< Front center */ +#define RTRIFFWAVEFMTEXT_CH_ID_LFE RT_BIT_32(3) /**< Low frequency */ +#define RTRIFFWAVEFMTEXT_CH_ID_BL RT_BIT_32(4) /**< Back left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_BR RT_BIT_32(5) /**< Back right. */ +#define RTRIFFWAVEFMTEXT_CH_ID_FLC RT_BIT_32(6) /**< Front left of center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_FLR RT_BIT_32(7) /**< Front right of center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_BC RT_BIT_32(8) /**< Back center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_SL RT_BIT_32(9) /**< Side left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_SR RT_BIT_32(10) /**< Side right. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TC RT_BIT_32(11) /**< Top center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TFL RT_BIT_32(12) /**< Top front left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TFC RT_BIT_32(13) /**< Top front center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TFR RT_BIT_32(14) /**< Top front right. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TBL RT_BIT_32(15) /**< Top back left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TBC RT_BIT_32(16) /**< Top back center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TBR RT_BIT_32(17) /**< Top back right. */ +/** @} */ + +/** RTRIFFWAVEFMTEXT::SubFormat UUID string for PCM. */ +#define RTRIFFWAVEFMTEXT_SUBTYPE_PCM "00000001-0000-0010-8000-00aa00389b71" + + +/** + * Wave file format chunk. + */ +typedef struct RTRIFFWAVEFMTCHUNK +{ + /** Chunk header with RTRIFFWAVEFMT_MAGIC as magic. */ + RTRIFFCHUNK Chunk; + /** The wave file format. */ + RTRIFFWAVEFMT Data; +} RTRIFFWAVEFMTCHUNK; +AssertCompileSize(RTRIFFWAVEFMTCHUNK, 8+16); +/** Pointer to a wave file format chunk. */ +typedef RTRIFFWAVEFMTCHUNK *PRTRIFFWAVEFMTCHUNK; +/** Magic value for RTRIFFWAVEFMTCHUNK and RTRIFFWAVEFMTEXTCHUNK ('fmt '). */ +#define RTRIFFWAVEFMT_MAGIC RT_BE2H_U32_C(0x666d7420) + +/** + * Extensible wave file format chunk. + */ +typedef struct RTRIFFWAVEFMTEXTCHUNK +{ + /** Chunk header with RTRIFFWAVEFMT_MAGIC as magic. */ + RTRIFFCHUNK Chunk; + /** The wave file format. */ + RTRIFFWAVEFMTEXT Data; +} RTRIFFWAVEFMTEXTCHUNK; +AssertCompileSize(RTRIFFWAVEFMTEXTCHUNK, 8+16+2+22); +/** Pointer to a wave file format chunk. */ +typedef RTRIFFWAVEFMTEXTCHUNK *PRTRIFFWAVEFMTEXTCHUNK; + + +/** + * Wave file data chunk. + */ +typedef struct RTRIFFWAVEDATACHUNK +{ + /** Chunk header with RTRIFFWAVEFMT_MAGIC as magic. */ + RTRIFFCHUNK Chunk; + /** Variable sized sample data. */ + uint8_t abData[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} RTRIFFWAVEDATACHUNK; + +/** Magic value for RTRIFFWAVEFMT::uMagic ('data'). */ +#define RTRIFFWAVEDATACHUNK_MAGIC RT_BE2H_U32_C(0x64617461) + + +/** Magic value padding chunks ('PAD '). */ +#define RTRIFFPADCHUNK_MAGIC RT_BE2H_U32_C(0x50414420) + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_riff_h */ + diff --git a/include/iprt/formats/tpm.h b/include/iprt/formats/tpm.h new file mode 100644 index 00000000..454a2d4f --- /dev/null +++ b/include/iprt/formats/tpm.h @@ -0,0 +1,313 @@ +/* $Id: tpm.h $ */ +/** @file + * IPRT, TPM common definitions (this is actually a protocol and not a format). + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_tpm_h +#define IPRT_INCLUDED_formats_tpm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + + +/** + * TPM request header (everything big endian). + */ +#pragma pack(1) +typedef struct TPMREQHDR +{ + /** The tag for this request. */ + uint16_t u16Tag; + /** Size of the request in bytes. */ + uint32_t cbReq; + /** The request ordinal to execute. */ + uint32_t u32Ordinal; +} TPMREQHDR; +#pragma pack() +AssertCompileSize(TPMREQHDR, 2 + 4 + 4); +/** Pointer to a TPM request header. */ +typedef TPMREQHDR *PTPMREQHDR; +/** Pointer to a const TPM request header. */ +typedef const TPMREQHDR *PCTPMREQHDR; + + +/** @name TPM 1.2 request tags + * @{ */ +/** Command with no authentication. */ +#define TPM_TAG_RQU_COMMAND UINT16_C(0x00c1) +/** An authenticated command with one authentication handle. */ +#define TPM_TAG_RQU_AUTH1_COMMAND UINT16_C(0x00c2) +/** An authenticated command with two authentication handles. */ +#define TPM_TAG_RQU_AUTH2_COMMAND UINT16_C(0x00c3) +/** @} */ + + +/** @name TPM 2.0 request/response tags + * @{ */ +/** Command with no associated session. */ +#define TPM2_ST_NO_SESSIONS UINT16_C(0x8001) +/** Command with an associated session. */ +#define TPM2_ST_SESSIONS UINT16_C(0x8002) +/** @} */ + + +/** @name TPM 1.2 request ordinals. + * @{ */ +/** Perform a full self test. */ +#define TPM_ORD_SELFTESTFULL UINT32_C(80) +/** Continue the selftest. */ +#define TPM_ORD_CONTINUESELFTEST UINT32_C(83) +/** Return the test result. */ +#define TPM_ORD_GETTESTRESULT UINT32_C(84) +/** Get a capability. */ +#define TPM_ORD_GETCAPABILITY UINT32_C(101) +/** @} */ + + +/** @name TPM 2.0 command codes. + * @{ */ +/** Get a capability. */ +#define TPM2_CC_GET_CAPABILITY UINT32_C(378) +/** @} */ + + +/** @name Defines related to TPM_ORD_GETCAPABILITY. + * @{ */ +/** Return a TPM related property. */ +#define TPM_CAP_PROPERTY UINT32_C(5) + +/** Returns the size of the input buffer. */ +#define TPM_CAP_PROP_INPUT_BUFFER UINT32_C(0x124) + +/** + * TPM_ORD_GETCAPABILITY request. + */ +#pragma pack(1) +typedef struct TPMREQGETCAPABILITY +{ + /** Request header. */ + TPMREQHDR Hdr; + /** The capability group to query. */ + uint32_t u32Cap; + /** Length of the capability. */ + uint32_t u32Length; + /** The sub capability to query. */ + uint32_t u32SubCap; +} TPMREQGETCAPABILITY; +#pragma pack() +/** Pointer to a TPM_ORD_GETCAPABILITY request. */ +typedef TPMREQGETCAPABILITY *PTPMREQGETCAPABILITY; +/** Pointer to a const TPM_ORD_GETCAPABILITY request. */ +typedef const TPMREQGETCAPABILITY *PCTPMREQGETCAPABILITY; +/** @} */ + + +/** @name Defines related to TPM2_CC_GET_CAPABILITY. + * @{ */ +/** Return a TPM related property. */ +#define TPM2_CAP_TPM_PROPERTIES UINT32_C(6) + +/** Returns the size of the input buffer. */ +#define TPM2_PT_INPUT_BUFFER UINT32_C(0x10d) + +/** + * TPM2_CC_GET_CAPABILITY request. + */ +#pragma pack(1) +typedef struct TPM2REQGETCAPABILITY +{ + /** Request header. */ + TPMREQHDR Hdr; + /** The capability group to query. */ + uint32_t u32Cap; + /** Property to query. */ + uint32_t u32Property; + /** Number of values to return. */ + uint32_t u32Count; +} TPM2REQGETCAPABILITY; +#pragma pack() +/** Pointer to a TPM2_CC_GET_CAPABILITY request. */ +typedef TPM2REQGETCAPABILITY *PTPM2REQGETCAPABILITY; +/** Pointer to a const TPM2_CC_GET_CAPABILITY request. */ +typedef const TPM2REQGETCAPABILITY *PCTPM2REQGETCAPABILITY; +/** @} */ + + +/** + * TPM response header (everything big endian). + */ +#pragma pack(1) +typedef struct TPMRESPHDR +{ + /** The tag for this request. */ + uint16_t u16Tag; + /** Size of the response in bytes. */ + uint32_t cbResp; + /** The error code for the response. */ + uint32_t u32ErrCode; +} TPMRESPHDR; +#pragma pack() +AssertCompileSize(TPMRESPHDR, 2 + 4 + 4); +/** Pointer to a TPM response header. */ +typedef TPMRESPHDR *PTPMRESPHDR; +/** Pointer to a const TPM response header. */ +typedef const TPMRESPHDR *PCTPMRESPHDR; + + +/** @name TPM 1.2 response tags + * @{ */ +/** A response from a command with no authentication. */ +#define TPM_TAG_RSP_COMMAND UINT16_C(0x00c4) +/** An authenticated response with one authentication handle. */ +#define TPM_TAG_RSP_AUTH1_COMMAND UINT16_C(0x00c5) +/** An authenticated response with two authentication handles. */ +#define TPM_TAG_RSP_AUTH2_COMMAND UINT16_C(0x00c6) +/** @} */ + + +/** @name TPM status codes. + * @{ */ +#ifndef TPM_SUCCESS +/** Request executed successfully. */ +# define TPM_SUCCESS UINT32_C(0) +#endif +#ifndef TPM_AUTHFAIL +/** Authentication failed. */ +# define TPM_AUTHFAIL UINT32_C(1) +#endif +#ifndef TPM_BADINDEX +/** An index is malformed. */ +# define TPM_BADINDEX UINT32_C(2) +#endif +#ifndef TPM_BAD_PARAMETER +/** A request parameter is invalid. */ +# define TPM_BAD_PARAMETER UINT32_C(3) +#endif +#ifndef TPM_FAIL +/** The TPM failed to execute the request. */ +# define TPM_FAIL UINT32_C(9) +#endif +/** @todo Extend as need arises. */ +/** @} */ + + +/* Some inline helpers to account for the unaligned members of the request and response headers. */ + +/** + * Returns the request tag of the given TPM request header. + * + * @returns TPM request tag in bytes. + * @param pTpmReqHdr Pointer to the TPM request header. + */ +DECLINLINE(uint16_t) RTTpmReqGetTag(PCTPMREQHDR pTpmReqHdr) +{ + return RT_BE2H_U16(pTpmReqHdr->u16Tag); +} + + +/** + * Returns the request size of the given TPM request header. + * + * @returns TPM request size in bytes. + * @param pTpmReqHdr Pointer to the TPM request header. + */ +DECLINLINE(size_t) RTTpmReqGetSz(PCTPMREQHDR pTpmReqHdr) +{ + uint32_t cbReq; + memcpy(&cbReq, &pTpmReqHdr->cbReq, sizeof(pTpmReqHdr->cbReq)); + return RT_BE2H_U32(cbReq); +} + + +/** + * Returns the request ordinal of the given TPM request header. + * + * @returns TPM request ordinal in bytes. + * @param pTpmReqHdr Pointer to the TPM request header. + */ +DECLINLINE(uint32_t) RTTpmReqGetOrdinal(PCTPMREQHDR pTpmReqHdr) +{ + uint32_t u32Ordinal; + memcpy(&u32Ordinal, &pTpmReqHdr->u32Ordinal, sizeof(pTpmReqHdr->u32Ordinal)); + return RT_BE2H_U32(u32Ordinal); +} + + +/** + * Returns the response tag of the given TPM response header. + * + * @returns TPM request tag in bytes. + * @param pTpmRespHdr Pointer to the TPM response header. + */ +DECLINLINE(uint16_t) RTTpmRespGetTag(PCTPMRESPHDR pTpmRespHdr) +{ + return RT_BE2H_U16(pTpmRespHdr->u16Tag); +} + + +/** + * Returns the response size included in the given TPM response header. + * + * @returns TPM response size in bytes. + * @param pTpmRespHdr Pointer to the TPM response header. + */ +DECLINLINE(size_t) RTTpmRespGetSz(PCTPMRESPHDR pTpmRespHdr) +{ + uint32_t cbResp; + memcpy(&cbResp, &pTpmRespHdr->cbResp, sizeof(pTpmRespHdr->cbResp)); + return RT_BE2H_U32(cbResp); +} + + +/** + * Returns the error code of the given TPM response header. + * + * @returns TPM response error code. + * @param pTpmRespHdr Pointer to the TPM response header. + */ +DECLINLINE(uint32_t) RTTpmRespGetErrCode(PCTPMRESPHDR pTpmRespHdr) +{ + uint32_t u32ErrCode; + memcpy(&u32ErrCode, &pTpmRespHdr->u32ErrCode, sizeof(pTpmRespHdr->u32ErrCode)); + return RT_BE2H_U32(u32ErrCode); +} + +#endif /* !IPRT_INCLUDED_formats_tpm_h */ + diff --git a/include/iprt/formats/tracelog.h b/include/iprt/formats/tracelog.h new file mode 100644 index 00000000..8b20e925 --- /dev/null +++ b/include/iprt/formats/tracelog.h @@ -0,0 +1,239 @@ +/* $Id: tracelog.h $ */ +/** @file + * IPRT, Binary trace log format. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_tracelog_h +#define IPRT_INCLUDED_formats_tracelog_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @defgroup grp_rt_formats_tracelog Binary trace log structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/** Size of the record magic in bytes. */ +#define TRACELOG_MAGIC_SZ 8 + +/** + * Trace log identification and options header. + */ +typedef struct TRACELOGHDR +{ + /** Identifiaction magic. */ + uint8_t szMagic[8]; + /** Endianess indicator. */ + uint32_t u32Endianess; + /** File version indicator. */ + uint32_t u32Version; + /** File flags (MBZ for now). */ + uint32_t fFlags; + /** Size of the trace log description in bytes following this header. */ + uint32_t cbStrDesc; + /** Size of a pointer item in bytes. */ + uint8_t cbTypePtr; + /** size of the size_t item in bytes. */ + uint8_t cbTypeSize; + /** Padding to an 4 byte boundary. */ + uint16_t u16Reserved0; + /** Padding to an 8 byte boundary. */ + uint32_t u32Reserved0; + /** Starting timestamp when the log was initialised. */ + uint64_t u64TsStart; + /** Padding to 64byte boundary, reserved for future use. */ + uint64_t au64Reserved[3]; +} TRACELOGHDR; +AssertCompileSize(TRACELOGHDR, 64); +/** Pointer to a trace log header. */ +typedef TRACELOGHDR *PTRACELOGHDR; +/** Pointer to a const trace log header. */ +typedef const TRACELOGHDR *PCTRACELOGHDR; + +/** Magic value for a trace log file (TRACELOG backwards). */ +#define TRACELOG_HDR_MAGIC "GOLECART" +/** Endianess indicator. */ +#define TRACELOG_HDR_ENDIANESS 0xdeadc0de +/** The default version (Higher 16bits major, low 16bits minor version). */ +#define TRACELOG_VERSION RT_MAKE_U32(1, 0) + + +/** + * Trace log event structure descriptor. + */ +typedef struct TRACELOGEVTDESC +{ + /** Event descriptor magic. */ + uint8_t szMagic[8]; + /** Event structure descriptor ID for identification in events later. */ + uint32_t u32Id; + /** Severity class of the event .*/ + uint32_t u32Severity; + /** Size of the identifier string in bytes without terminator. */ + uint32_t cbStrId; + /** Size of the description string in bytes without terminator. */ + uint32_t cbStrDesc; + /** Number of event items following. */ + uint32_t cEvtItems; + /** Padding to end the descriptor on a 32 byte boundary. */ + uint32_t au32Padding0; +} TRACELOGEVTDESC; +AssertCompileSize(TRACELOGEVTDESC, 32); +/** Pointer to a trace log event structure descriptor. */ +typedef TRACELOGEVTDESC *PTRACELOGEVTDESC; +/** Pointer to a const trace log event structure descriptor. */ +typedef const TRACELOGEVTDESC *PCTRACELOGEVTDESC; + +/** Event descriptor magic. */ +#define TRACELOG_EVTDESC_MAGIC "\0CSEDTVE" + +/** Severity: Informational event*/ +#define TRACELOG_EVTDESC_SEVERITY_INFO UINT32_C(0) +/** Severity: Warning event*/ +#define TRACELOG_EVTDESC_SEVERITY_WARNING UINT32_C(1) +/** Severity: Error event*/ +#define TRACELOG_EVTDESC_SEVERITY_ERROR UINT32_C(2) +/** Severity: Fatal event*/ +#define TRACELOG_EVTDESC_SEVERITY_FATAL UINT32_C(3) +/** Severity: Debug event*/ +#define TRACELOG_EVTDESC_SEVERITY_DEBUG UINT32_C(4) + + +/** + * Trace log event item descriptor. + */ +typedef struct TRACELOGEVTITEMDESC +{ + /** Event item descriptor magic. */ + uint8_t szMagic[8]; + /** Size of the item name string in bytes without terminator. */ + uint32_t cbStrName; + /** Size of the optional description string in bytes without terminator. */ + uint32_t cbStrDesc; + /** Item type */ + uint32_t u32Type; + /** Size of the raw data type if static throughout. */ + uint32_t cbRawData; + /** Padding to end the descriptor on a 32 byte boundary. */ + uint32_t au32Padding0[2]; +} TRACELOGEVTITEMDESC; +AssertCompileSize(TRACELOGEVTITEMDESC, 32); +/** Pointer to a trace log event item descriptor. */ +typedef TRACELOGEVTITEMDESC *PTRACELOGEVTITEMDESC; +/** Pointer to a const trace log event item descriptor. */ +typedef const TRACELOGEVTITEMDESC *PCTRACELOGEVTITEMDESC; + +/** Event item descriptor magic. */ +#define TRACELOG_EVTITEMDESC_MAGIC "CSEDMETI" +/** Boolean type. */ +#define TRACELOG_EVTITEMDESC_TYPE_BOOL UINT32_C(1) +/** Unsigned 8bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_UINT8 UINT32_C(2) +/** Signed 8bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_INT8 UINT32_C(3) +/** Unsigned 16bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_UINT16 UINT32_C(4) +/** Signed 16bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_INT16 UINT32_C(5) +/** Unsigned 32bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_UINT32 UINT32_C(6) +/** Signed 32bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_INT32 UINT32_C(7) +/** Unsigned 64bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_UINT64 UINT32_C(8) +/** Signed 64bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_INT64 UINT32_C(9) +/** 32bit floating point type. */ +#define TRACELOG_EVTITEMDESC_TYPE_FLOAT32 UINT32_C(10) +/** 64bit floating point type. */ +#define TRACELOG_EVTITEMDESC_TYPE_FLOAT64 UINT32_C(11) +/** Raw binary data type. */ +#define TRACELOG_EVTITEMDESC_TYPE_RAWDATA UINT32_C(12) +/** Pointer data type. */ +#define TRACELOG_EVTITEMDESC_TYPE_POINTER UINT32_C(13) +/** size_t data type. */ +#define TRACELOG_EVTITEMDESC_TYPE_SIZE UINT32_C(14) + +/** + * Trace log event marker. + */ +typedef struct TRACELOGEVT +{ + /** Event marker magic. */ + uint8_t szMagic[8]; + /** Trace log sequence number to identify the event uniquely. */ + uint64_t u64SeqNo; + /** Timestamp for the marker (resolution is infered from the header). */ + uint64_t u64Ts; + /** Event group ID for grouping different events together - for no grouped event. */ + uint64_t u64EvtGrpId; + /** Parent group ID this event originated from. */ + uint64_t u64EvtParentGrpId; + /** Overall number of bytes for the event data following including static and possibly variable data. */ + uint32_t cbEvtData; + /** Number of size_t sized raw data size indicators before the raw event data follows. */ + uint32_t cRawEvtDataSz; + /** Event flags. */ + uint32_t fFlags; + /** Event structure descriptor ID to use for structuring the event data. */ + uint32_t u32EvtDescId; + /** Reserved for future use. */ + uint64_t u64Reserved0; +} TRACELOGEVT; +AssertCompileSize(TRACELOGEVT, 64); +/** Pointer to a trace log event marker. */ +typedef TRACELOGEVT *PTRACELOGEVT; +/** Pointer to a const trace log event marker. */ +typedef const TRACELOGEVT *PCTRACELOGEVT; + +/** Event marker descriptor magic. */ +#define TRACELOG_EVT_MAGIC "\0RKRMTVE" +/** Flag indicating this is the start of an event group and all subsequent events + * with the same group ID belong to the same group. */ +#define TRACELOG_EVT_F_GRP_START RT_BIT_32(0) +/** Flag indicating this is the end of an event group which was started earlier. */ +#define TRACELOG_EVT_F_GRP_END RT_BIT_32(1) +/** Combination of valid flags. */ +#define TRACELOG_EVT_F_VALID (TRACELOG_EVT_F_GRP_START | TRACELOG_EVT_F_GRP_END) + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_tracelog_h */ + diff --git a/include/iprt/formats/udf.h b/include/iprt/formats/udf.h new file mode 100644 index 00000000..5081c11e --- /dev/null +++ b/include/iprt/formats/udf.h @@ -0,0 +1,2232 @@ +/* $Id: udf.h $ */ +/** @file + * IPRT, Universal Disk Format (UDF). + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_udf_h +#define IPRT_INCLUDED_formats_udf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @defgroup grp_rt_formats_udf Universal Disk Format (UDF) structures and definitions + * @ingroup grp_rt_formats + * + * References: + * - https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-167.pdf + * - http://www.osta.org/specs/pdf/udf260.pdf + * - http://wiki.osdev.org/UDF + * - https://sites.google.com/site/udfintro/ + * + * @{ + */ + +/** + * UDF d-character string (@ecma167{1,7.2.12,25}). + * + * This is mainly to mark what's d-strings and what's not. + */ +typedef char UDFDSTRING; +/** Pointer to an UDF dstring. */ +typedef UDFDSTRING *PUDFDSTRING; +/** Pointer to a const UDF dstring. */ +typedef UDFDSTRING const *PCUDFDSTRING; + +/** + * UDF extent allocation descriptor (AD) (@ecma167{3,7.1,42}). + */ +typedef struct UDFEXTENTAD +{ + /** Extent length in bytes. */ + uint32_t cb; + /** Extent offset (logical sector number). + * If @a cb is zero, this is also zero. */ + uint32_t off; +} UDFEXTENTAD; +AssertCompileSize(UDFEXTENTAD, 8); +/** Pointer to an UDF extent descriptor. */ +typedef UDFEXTENTAD *PUDFEXTENTAD; +/** Pointer to a const UDF extent descriptor. */ +typedef UDFEXTENTAD const *PCUDFEXTENTAD; + + +/** + * UDF logical block address (@ecma167{4,7.1,73}). + */ +#pragma pack(2) +typedef struct UDFLBADDR +{ + /** Logical block number, relative to the start of the given partition. */ + uint32_t off; + /** Partition reference number. */ + uint16_t uPartitionNo; +} UDFLBADDR; +#pragma pack() +AssertCompileSize(UDFLBADDR, 6); +/** Pointer to an UDF logical block address. */ +typedef UDFLBADDR *PUDFLBADDR; +/** Pointer to a const UDF logical block address. */ +typedef UDFLBADDR const *PCUDFLBADDR; + + +/** @name UDF_AD_TYPE_XXX - Allocation descriptor types. + * + * Used by UDFSHORTAD::uType, UDFLONGAD::uType and UDFEXTAD::uType. + * + * See @ecma167{4,14.14.1.1,116}. + * + * @{ */ +/** Recorded and allocated. + * Also used for zero length descriptors. */ +#define UDF_AD_TYPE_RECORDED_AND_ALLOCATED 0 +/** Allocated but not recorded. */ +#define UDF_AD_TYPE_ONLY_ALLOCATED 1 +/** Not recorded nor allocated. */ +#define UDF_AD_TYPE_FREE 2 +/** Go figure. */ +#define UDF_AD_TYPE_NEXT 3 +/** @} */ + +/** + * UDF short allocation descriptor (@ecma167{4,14.14.1,116}). + */ +typedef struct UDFSHORTAD +{ +#ifdef RT_BIG_ENDIAN + /** Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; + /** Extent length in bytes, top 2 bits . */ + uint32_t cb : 30; +#else + /** Extent length in bytes. */ + uint32_t cb : 30; + /** Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; +#endif + /** Extent offset (logical sector number). */ + uint32_t off; +} UDFSHORTAD; +AssertCompileSize(UDFSHORTAD, 8); +/** Pointer to an UDF short allocation descriptor. */ +typedef UDFSHORTAD *PUDFSHORTAD; +/** Pointer to a const UDF short allocation descriptor. */ +typedef UDFSHORTAD const *PCUDFSHORTAD; + +/** + * UDF long allocation descriptor (@ecma167{4,14.14.2,116}). + */ +#pragma pack(2) +typedef struct UDFLONGAD +{ +#ifdef RT_BIG_ENDIAN + /** Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; + /** Extent length in bytes, top 2 bits . */ + uint32_t cb : 30; +#else + /** Extent length in bytes. */ + uint32_t cb : 30; + /** Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; +#endif + /** Extent location. */ + UDFLBADDR Location; + /** Implementation use area. */ + union + { + /** Generic view. */ + uint8_t ab[6]; + /** Used in FIDs. + * See @udf260{2.3.10.1,66}, @udf260{2.3.4.3,58}. + */ + struct + { + /** Flags (UDF_AD_IMP_USE_FLAGS_XXX). */ + uint16_t fFlags; + /** Unique ID. */ + uint32_t idUnique; + } Fid; + } ImplementationUse; +} UDFLONGAD; +#pragma pack() +AssertCompileSize(UDFLONGAD, 16); +/** Pointer to an UDF long allocation descriptor. */ +typedef UDFLONGAD *PUDFLONGAD; +/** Pointer to a const UDF long allocation descriptor. */ +typedef UDFLONGAD const *PCUDFLONGAD; + +/** @name UDF_AD_IMP_USE_FLAGS_XXX - UDFLONGAD::ImplementationUse::Fid::fFlags values + * See @udf260{2.3.10.1,66}. + * @{ */ +/** Set if erased and the extend is of the type UDF_AD_TYPE_ONLY_ALLOCATED. */ +#define UDF_AD_IMP_USE_FLAGS_ERASED UINT16_C(0x0001) +/** Valid mask. */ +#define UDF_AD_IMP_USE_FLAGS_VALID_MASK UINT16_C(0x0001) +/** @} */ + +/** + * UDF extended allocation descriptor (@ecma167{4,14.14.3,117}). + */ +typedef struct UDFEXTAD +{ +#ifdef RT_BIG_ENDIAN + /** 0x00: Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; + /** 0x00: Extent length in bytes, top 2 bits . */ + uint32_t cb : 30; + /** 0x04: Reserved, MBZ. */ + uint32_t uReserved : 2; + /** 0x04: Number of bytes recorded. */ + uint32_t cbRecorded : 30; +#else + /** 0x00: Extent length in bytes. */ + uint32_t cb : 30; + /** 0x00: Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; + /** 0x04: Number of bytes recorded. */ + uint32_t cbRecorded : 30; + /** 0x04: Reserved, MBZ. */ + uint32_t uReserved : 2; +#endif + /** 0x08: Number of bytes of information (from first byte). */ + uint32_t cbInformation; + /** 0x0c: Extent location. */ + UDFLBADDR Location; + /** 0x12: Implementation use area. */ + uint8_t abImplementationUse[2]; +} UDFEXTAD; +AssertCompileSize(UDFEXTAD, 20); +/** Pointer to an UDF extended allocation descriptor. */ +typedef UDFEXTAD *PUDFEXTAD; +/** Pointer to a const UDF extended allocation descriptor. */ +typedef UDFEXTAD const *PCUDFEXTAD; + + +/** + * UDF timestamp (@ecma167{1,7.3,25}, @udf260{2.1.4,19}). + */ +typedef struct UDFTIMESTAMP +{ +#ifdef RT_BIG_ENDIAN + /** 0x00: Type (UDFTIMESTAMP_T_XXX). */ + RT_GCC_EXTENSION uint16_t fType : 4; + /** 0x00: Time zone offset in minutes. + * For EST this will be -300, whereas for CET it will be 60. */ + RT_GCC_EXTENSION int16_t offUtcInMin : 12; +#else + /** 0x00: Time zone offset in minutes. + * For EST this will be -300, whereas for CET it will be 60. */ + RT_GCC_EXTENSION int16_t offUtcInMin : 12; + /** 0x00: Type (UDFTIMESTAMP_T_XXX). */ + RT_GCC_EXTENSION uint16_t fType : 4; +#endif + /** 0x02: The year. */ + int16_t iYear; + /** 0x04: Month of year (1-12). */ + uint8_t uMonth; + /** 0x05: Day of month (1-31). */ + uint8_t uDay; + /** 0x06: Hour of day (0-23). */ + uint8_t uHour; + /** 0x07: Minute of hour (0-59). */ + uint8_t uMinute; + /** 0x08: Second of minute (0-60 if type 2, otherwise 0-59). */ + uint8_t uSecond; + /** 0x09: Number of Centiseconds (0-99). */ + uint8_t cCentiseconds; + /** 0x0a: Number of hundreds of microseconds (0-99). Unit is 100us. */ + uint8_t cHundredsOfMicroseconds; + /** 0x0b: Number of microseconds (0-99). */ + uint8_t cMicroseconds; +} UDFTIMESTAMP; +AssertCompileSize(UDFTIMESTAMP, 12); +/** Pointer to an UDF timestamp. */ +typedef UDFTIMESTAMP *PUDFTIMESTAMP; +/** Pointer to a const UDF timestamp. */ +typedef UDFTIMESTAMP const *PCUDFTIMESTAMP; + +/** @name UDFTIMESTAMP_T_XXX + * @{ */ +/** Local time. */ +#define UDFTIMESTAMP_T_LOCAL 1 +/** @} */ + +/** No time zone specified. */ +#define UDFTIMESTAMP_NO_TIME_ZONE (-2047) + + +/** + * UDF character set specficiation (@ecma167{1,7.2.1,21}, @udf260{2.1.2,18}). + */ +typedef struct UDFCHARSPEC +{ + /** The character set type (UDF_CHAR_SET_TYPE_XXX) */ + uint8_t uType; + /** Character set information. */ + uint8_t abInfo[63]; +} UDFCHARSPEC; +AssertCompileSize(UDFCHARSPEC, 64); +/** Pointer to UDF character set specification. */ +typedef UDFCHARSPEC *PUDFCHARSPEC; +/** Pointer to const UDF character set specification. */ +typedef UDFCHARSPEC const *PCUDFCHARSPEC; + +/** @name UDF_CHAR_SET_TYPE_XXX - Character set types. + * @{ */ +/** CS0: By agreement between the medium producer and consumer. + * See UDF_CHAR_SET_OSTA_COMPRESSED_UNICODE. */ +#define UDF_CHAR_SET_TYPE_BY_AGREEMENT UINT8_C(0x00) +/** CS1: ASCII (ECMA-6) with all or part of the specified graphic characters. */ +#define UDF_CHAR_SET_TYPE_ASCII UINT8_C(0x01) +/** CS5: Latin-1 (ECMA-94) with all graphical characters. */ +#define UDF_CHAR_SET_TYPE_LATIN_1 UINT8_C(0x05) +/* there are more defined here, but they are mostly useless, since UDF only uses CS0. */ + +/** The CS0 definition used by the UDF specification. */ +#define UDF_CHAR_SET_OSTA_COMPRESSED_UNICODE UDF_CHAR_SET_TYPE_BY_AGREEMENT +/** String to put in the UDFCHARSEPC::abInfo field for UDF CS0. */ +#define UDF_CHAR_SET_OSTA_COMPRESSED_UNICODE_INFO "OSTA Compressed Unicode" +/** @} */ + + +/** + * UDF entity identifier (@ecma167{1,7.4,26}, @udf260{2.1.5,20}). + */ +typedef struct UDFENTITYID +{ + /** 0x00: Flags (UDFENTITYID_FLAGS_XXX). */ + uint8_t fFlags; + /** 0x01: Identifier string (see UDF_ENTITY_ID_XXX). */ + char achIdentifier[23]; + /** 0x18: Identifier suffix. */ + union + { + /** Domain ID suffix. */ + struct + { + uint16_t uUdfRevision; + uint8_t fDomain; + uint8_t abReserved[5]; + } Domain; + + /** UDF ID suffix. */ + struct + { + uint16_t uUdfRevision; + uint8_t bOsClass; + uint8_t idOS; + uint8_t abReserved[4]; + } Udf; + + + /** Implementation ID suffix. */ + struct + { + uint8_t bOsClass; + uint8_t idOS; + uint8_t achImplUse[6]; + } Implementation; + + /** Application ID suffix / generic. */ + uint8_t abApplication[8]; + } Suffix; +} UDFENTITYID; +AssertCompileSize(UDFENTITYID, 32); +/** Pointer to UDF entity identifier. */ +typedef UDFENTITYID *PUDFENTITYID; +/** Pointer to const UDF entity identifier. */ +typedef UDFENTITYID const *PCUDFENTITYID; + +/** @name UDF_ENTITY_ID_XXX - UDF identifier strings + * + * See @udf260{2.1.5.2,21}. + * + * @{ */ +/** Implementation use volume descriptor, implementation ID field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_IUVD_IMPLEMENTATION "*UDF LV Info" + +/** Partition descriptor, partition contents field, set to indicate UDF + * (ECMA-167 3rd edition). Application ID suffix. */ +#define UDF_ENTITY_ID_PD_PARTITION_CONTENTS_UDF "+NSR03" +/** Partition descriptor, partition contents field, set to indicate ISO-9660 + * (ECMA-119). Application ID suffix. */ +#define UDF_ENTITY_ID_PD_PARTITION_CONTENTS_ISO9660 "+CD001" +/** Partition descriptor, partition contents field, set to indicate ECMA-168. + * Application ID suffix. */ +#define UDF_ENTITY_ID_PD_PARTITION_CONTENTS_CDW "+CDW02" +/** Partition descriptor, partition contents field, set to indicate FAT + * (ECMA-107). Application ID suffix. */ +#define UDF_ENTITY_ID_PD_PARTITION_CONTENTS_FAT "+FDC01" + +/** Logical volume descriptor, domain ID field. + * Domain ID suffix. */ +#define UDF_ENTITY_ID_LVD_DOMAIN "*OSTA UDF Compliant" + +/** File set descriptor, domain ID field. + * Domain ID suffix. */ +#define UDF_ENTITY_FSD_LVD_DOMAIN "*OSTA UDF Compliant" + +/** UDF implementation use extended attribute, implementation ID field, set + * to free EA space. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_FREE_EA_SPACE "*UDF FreeEASpace" +/** UDF implementation use extended attribute, implementation ID field, set + * to DVD copyright management information. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_DVD_CGMS_INFO "*UDF DVD CGMS Info" +/** UDF implementation use extended attribute, implementation ID field, set + * to OS/2 extended attribute length. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_OS2_EA_LENGTH "*UDF OS/2 EALength" +/** UDF implementation use extended attribute, implementation ID field, set + * to Machintosh OS volume information. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_MAC_VOLUME_INFO "*UDF Mac VolumeInfo" +/** UDF implementation use extended attribute, implementation ID field, set + * to Machintosh Finder Info. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO "*UDF Mac FinderInfo" +/** UDF implementation use extended attribute, implementation ID field, set + * to OS/400 extended directory information. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_OS400_DIR_INFO "*UDF OS/400 DirInfo" + +/** UDF application use extended attribute, application ID field, set + * to free application use EA space. UDF ID suffix. */ +#define UDF_ENTITY_ID_AUEA_FREE_EA_SPACE "*UDF FreeAppEASpace" + +/** Virtual partition map, partition type field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_VPM_PARTITION_TYPE "*UDF Virtual Partition" + +/** Sparable partition map, partition type field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_SPM_PARTITION_TYPE "*UDF Sparable Partition" + +/** Metadata partition map, partition type field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_MPM_PARTITION_TYPE "*UDF Metadata Partition" + +/** Sparing table, sparing identifier field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_ST_SPARING "*UDF Sparting Table" + +/** @} */ + + +/** + * UDF descriptor tag (@ecma167{3,7.2,42}, @udf260{2.2.1,26}). + */ +typedef struct UDFTAG +{ + /** Tag identifier (UDF_TAG_ID_XXX). */ + uint16_t idTag; + /** Descriptor version. */ + uint16_t uVersion; + /** Tag checksum. + * Sum of each byte in the structure with this field as zero. */ + uint8_t uChecksum; + /** Reserved, MBZ. */ + uint8_t bReserved; + /** Tag serial number. */ + uint16_t uTagSerialNo; + /** Descriptor CRC. */ + uint16_t uDescriptorCrc; + /** Descriptor CRC length. */ + uint16_t cbDescriptorCrc; + /** The tag location (logical sector number). */ + uint32_t offTag; +} UDFTAG; +AssertCompileSize(UDFTAG, 16); +/** Pointer to an UDF descriptor tag. */ +typedef UDFTAG *PUDFTAG; +/** Pointer to a const UDF descriptor tag. */ +typedef UDFTAG const *PCUDFTAG; + +/** @name UDF_TAG_ID_XXX - UDF descriptor tag IDs. + * @{ */ +#define UDF_TAG_ID_PRIMARY_VOL_DESC UINT16_C(0x0001) /**< See UDFPRIMARYVOLUMEDESC */ +#define UDF_TAG_ID_ANCHOR_VOLUME_DESC_PTR UINT16_C(0x0002) /**< See UDFANCHORVOLUMEDESCPTR */ +#define UDF_TAG_ID_VOLUME_DESC_PTR UINT16_C(0x0003) /**< See UDFVOLUMEDESCPTR */ +#define UDF_TAG_ID_IMPLEMENTATION_USE_VOLUME_DESC UINT16_C(0x0004) /**< See UDFIMPLEMENTATIONUSEVOLUMEDESC */ +#define UDF_TAG_ID_PARTITION_DESC UINT16_C(0x0005) /**< See UDFPARTITIONDESC */ +#define UDF_TAG_ID_LOGICAL_VOLUME_DESC UINT16_C(0x0006) /**< See UDFLOGICALVOLUMEDESC */ +#define UDF_TAG_ID_UNALLOCATED_SPACE_DESC UINT16_C(0x0007) /**< See UDFUNALLOCATEDSPACEDESC */ +#define UDF_TAG_ID_TERMINATING_DESC UINT16_C(0x0008) /**< See UDFTERMINATINGDESC */ +#define UDF_TAG_ID_LOGICAL_VOLUME_INTEGRITY_DESC UINT16_C(0x0009) /**< See UDFLOGICALVOLINTEGRITYDESC */ +#define UDF_TAG_ID_FILE_SET_DESC UINT16_C(0x0100) /**< See UDFFILESETDESC */ +#define UDF_TAG_ID_FILE_ID_DESC UINT16_C(0x0101) /**< See UDFFILEIDDESC */ +#define UDF_TAG_ID_ALLOCATION_EXTENT_DESC UINT16_C(0x0102) /**< See UDFALLOCATIONEXTENTDESC */ +#define UDF_TAG_ID_INDIRECT_ENTRY UINT16_C(0x0103) /**< See UDFINDIRECTENTRY */ +#define UDF_TAG_ID_TERMINAL_ENTRY UINT16_C(0x0104) /**< See UDFTERMINALENTRY */ +#define UDF_TAG_ID_FILE_ENTRY UINT16_C(0x0105) /**< See UDFFILEENTRY */ +#define UDF_TAG_ID_EXTENDED_ATTRIB_HDR_DESC UINT16_C(0x0106) /**< See UDFEXTATTRIBHDRDESC */ +#define UDF_TAG_ID_UNALLOCATED_SPACE_ENTRY UINT16_C(0x0107) /**< See UDFUNALLOCATEDSPACEENTRY */ +#define UDF_TAG_ID_SPACE_BITMAP_DESC UINT16_C(0x0108) /**< See UDFSPACEBITMAPDESC */ +#define UDF_TAG_ID_PARTITION_INTEGERITY_DESC UINT16_C(0x0109) /**< See UDFPARTITIONINTEGRITYDESC */ +#define UDF_TAG_ID_EXTENDED_FILE_ENTRY UINT16_C(0x010a) /**< See UDFEXFILEENTRY */ +/** @} */ + + +/** + * UDF primary volume descriptor (PVD) (@ecma167{3,10.1,50}, + * @udf260{2.2.2,27}). + */ +typedef struct UDFPRIMARYVOLUMEDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_PRIMARY_VOL_DESC). */ + UDFTAG Tag; + /** 0x010: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x014: Primary volume descriptor number. */ + uint32_t uPrimaryVolumeDescNo; + /** 0x018: Volume identifier (dstring). */ + UDFDSTRING achVolumeID[32]; + /** 0x038: Volume sequence number. */ + uint16_t uVolumeSeqNo; + /** 0x03a: Maximum volume sequence number. */ + uint16_t uMaxVolumeSeqNo; + /** 0x03c: Interchange level. */ + uint16_t uInterchangeLevel; + /** 0x03e: Maximum interchange level. */ + uint16_t uMaxInterchangeLevel; + /** 0x040: Character set bitmask (aka list). Each bit correspond to a + * character set number. */ + uint32_t fCharacterSets; + /** 0x044: Maximum character set bitmask (aka list). */ + uint32_t fMaxCharacterSets; + /** 0x048: Volume set identifier (dstring). This starts with 16 unique + * characters, the first 8 being the hex representation of a time value. */ + UDFDSTRING achVolumeSetID[128]; + /** 0x0c8: Descriptor character set. + * For achVolumeSetID and achVolumeID. */ + UDFCHARSPEC DescCharSet; + /** 0x108: Explanatory character set. + * For VolumeAbstract and VolumeCopyrightNotice data. */ + UDFCHARSPEC ExplanatoryCharSet; + /** 0x148: Volume abstract. */ + UDFEXTENTAD VolumeAbstract; + /** 0x150: Volume copyright notice. */ + UDFEXTENTAD VolumeCopyrightNotice; + /** 0x158: Application identifier ("*Application ID"). */ + UDFENTITYID idApplication; + /** 0x178: Recording date and time. */ + UDFTIMESTAMP RecordingTimestamp; + /** 0x184: Implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0x1a4: Implementation use. */ + uint8_t abImplementationUse[64]; + /** 0x1e4: Predecessor volume descriptor sequence location. */ + uint32_t offPredecessorVolDescSeq; + /** 0x1e8: Flags (UDF_PVD_FLAGS_XXX). */ + uint16_t fFlags; + /** 0x1ea: Reserved. */ + uint8_t abReserved[22]; +} UDFPRIMARYVOLUMEDESC; +AssertCompileSize(UDFPRIMARYVOLUMEDESC, 512); +/** Pointer to a UDF primary volume descriptor. */ +typedef UDFPRIMARYVOLUMEDESC *PUDFPRIMARYVOLUMEDESC; +/** Pointer to a const UDF primary volume descriptor. */ +typedef UDFPRIMARYVOLUMEDESC const *PCUDFPRIMARYVOLUMEDESC; + +/** @name UDF_PVD_FLAGS_XXX - Flags for UDFPRIMARYVOLUMEDESC::fFlags. + * @{ */ +/** Indicates that the volume set ID is common to all members of the set. */ +#define UDF_PVD_FLAGS_COMMON_VOLUME_SET_ID UINT16_C(0x0001) +/** @} */ + + +/** + * UDF anchor volume descriptor pointer (AVDP) (@ecma167{3,10.2,53}, + * @udf260{2.2.3,29}). + * + * This is stored at least two of these locations: + * - logical sector 256 + * - logical sector N - 256. + * - logical sector N. + */ +typedef struct UDFANCHORVOLUMEDESCPTR +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_ANCHOR_VOLUME_DESC_PTR). */ + UDFTAG Tag; + /** 0x10: The extent descripting the main volume descriptor sequence. */ + UDFEXTENTAD MainVolumeDescSeq; + /** 0x18: Location of the backup descriptor sequence. */ + UDFEXTENTAD ReserveVolumeDescSeq; + /** 0x20: Reserved, probably must be zeros. */ + uint8_t abReserved[0x1e0]; +} UDFANCHORVOLUMEDESCPTR; +AssertCompileSize(UDFANCHORVOLUMEDESCPTR, 512); +/** Pointer to UDF anchor volume descriptor pointer. */ +typedef UDFANCHORVOLUMEDESCPTR *PUDFANCHORVOLUMEDESCPTR; +/** Pointer to const UDF anchor volume descriptor pointer. */ +typedef UDFANCHORVOLUMEDESCPTR const *PCUDFANCHORVOLUMEDESCPTR; + + +/** + * UDF volume descriptor pointer (VDP) (@ecma167{3,10.3,53}). + */ +typedef struct UDFVOLUMEDESCPTR +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_VOLUME_DESC_PTR). */ + UDFTAG Tag; + /** 0x10: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x14: Location of the next volume descriptor sequence. */ + UDFEXTENTAD NextVolumeDescSeq; + /** 0x1c: Reserved, probably must be zeros. */ + uint8_t abReserved[484]; +} UDFVOLUMEDESCPTR; +AssertCompileSize(UDFVOLUMEDESCPTR, 512); +/** Pointer to UDF volume descriptor pointer. */ +typedef UDFVOLUMEDESCPTR *PUDFVOLUMEDESCPTR; +/** Pointer to const UDF volume descriptor pointer. */ +typedef UDFVOLUMEDESCPTR const *PCUDFVOLUMEDESCPTR; + + +/** + * UDF implementation use volume descriptor (IUVD) (@ecma167{3,10.4,55}, + * @udf260{2.2.7,35}). + */ +typedef struct UDFIMPLEMENTATIONUSEVOLUMEDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_IMPLEMENTATION_USE_VOLUME_DESC). */ + UDFTAG Tag; + /** 0x10: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x14: The implementation identifier (UDF_ENTITY_ID_IUVD_IMPLEMENTATION). */ + UDFENTITYID idImplementation; + /** 0x34: The implementation use area. */ + union + { + /** Generic view. */ + uint8_t ab[460]; + /** Logical volume information (@udf260{2.2.7.2,35}). */ + struct + { + /** 0x034: The character set used in this sub-structure. */ + UDFCHARSPEC Charset; + /** 0x074: Logical volume identifier. */ + UDFDSTRING achVolumeID[128]; + /** 0x0f4: Info string \#1. */ + UDFDSTRING achInfo1[36]; + /** 0x118: Info string \#2. */ + UDFDSTRING achInfo2[36]; + /** 0x13c: Info string \#3. */ + UDFDSTRING achInfo3[36]; + /** 0x160: The implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0x180: Additional use bytes. */ + uint8_t abUse[128]; + } Lvi; + } ImplementationUse; +} UDFIMPLEMENTATIONUSEVOLUMEDESC; +AssertCompileSize(UDFIMPLEMENTATIONUSEVOLUMEDESC, 512); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.Charset, 0x034); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.achVolumeID, 0x074); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.achInfo1, 0x0f4); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.achInfo2, 0x118); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.achInfo3, 0x13c); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.idImplementation, 0x160); +/** Pointer to an UDF implementation use volume descriptor. */ +typedef UDFIMPLEMENTATIONUSEVOLUMEDESC *PUDFIMPLEMENTATIONUSEVOLUMEDESC; +/** Pointer to a const UDF implementation use volume descriptor. */ +typedef UDFIMPLEMENTATIONUSEVOLUMEDESC const *PCUDFIMPLEMENTATIONUSEVOLUMEDESC; + + +/** + * UDF partition header descriptor (@ecma167{4,14.3,90}, @udf260{2.3.3,56}). + * + * This is found in UDFPARTITIONDESC::ContentsUse. + */ +typedef struct UDFPARTITIONHDRDESC +{ + /** 0x00: Unallocated space table location. Zero length means no table. */ + UDFSHORTAD UnallocatedSpaceTable; + /** 0x08: Unallocated space bitmap location. Zero length means no bitmap. */ + UDFSHORTAD UnallocatedSpaceBitmap; + /** 0x10: Partition integrity table location. Zero length means no table. */ + UDFSHORTAD PartitionIntegrityTable; + /** 0x18: Freed space table location. Zero length means no table. */ + UDFSHORTAD FreedSpaceTable; + /** 0x20: Freed space bitmap location. Zero length means no bitmap. */ + UDFSHORTAD FreedSpaceBitmap; + /** 0x28: Reserved, MBZ. */ + uint8_t abReserved[88]; +} UDFPARTITIONHDRDESC; +AssertCompileSize(UDFPARTITIONHDRDESC, 128); +AssertCompileMemberOffset(UDFPARTITIONHDRDESC, PartitionIntegrityTable, 0x10); +AssertCompileMemberOffset(UDFPARTITIONHDRDESC, abReserved, 0x28); +/** Pointer to an UDF partition header descriptor. */ +typedef UDFPARTITIONHDRDESC *PUDFPARTITIONHDRDESC; +/** Pointer to a const UDF partition header descriptor. */ +typedef UDFPARTITIONHDRDESC const *PCUDFPARTITIONHDRDESC; + + +/** + * UDF partition descriptor (PD) (@ecma167{3,10.5,55}, @udf260{2.2.14,51}). + */ +typedef struct UDFPARTITIONDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_PARTITION_DESC). */ + UDFTAG Tag; + /** 0x010: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x014: The partition flags (UDF_PARTITION_FLAGS_XXX). */ + uint16_t fFlags; + /** 0x016: The partition number. */ + uint16_t uPartitionNo; + /** 0x018: Partition contents (UDF_ENTITY_ID_PD_PARTITION_CONTENTS_XXX). */ + UDFENTITYID PartitionContents; + /** 0x038: partition contents use (depends on the PartitionContents field). */ + union + { + /** Generic view. */ + uint8_t ab[128]; + /** UDF partition header descriptor (UDF_ENTITY_ID_PD_PARTITION_CONTENTS_UDF). */ + UDFPARTITIONHDRDESC Hdr; + } ContentsUse; + /** 0x0b8: Access type (UDF_PART_ACCESS_TYPE_XXX). */ + uint32_t uAccessType; + /** 0x0bc: Partition starting location (logical sector number). */ + uint32_t offLocation; + /** 0x0c0: Partition length in sectors. */ + uint32_t cSectors; + /** 0x0c4: Implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0x0e4: Implementation use bytes. */ + union + { + /** Generic view. */ + uint8_t ab[128]; + } ImplementationUse; + /** 0x164: Reserved. */ + uint8_t abReserved[156]; +} UDFPARTITIONDESC; +AssertCompileSize(UDFPARTITIONDESC, 512); +/** Pointer to an UDF partitions descriptor. */ +typedef UDFPARTITIONDESC *PUDFPARTITIONDESC; +/** Pointer to a const UDF partitions descriptor. */ +typedef const UDFPARTITIONDESC *PCUDFPARTITIONDESC; + +/** @name UDF_PART_ACCESS_TYPE_XXX - UDF partition access types + * + * See @ecma167{3,10.5.7,57}, @udf260{2.2.14.2,51}. + * + * @{ */ +/** Access not specified by this field. */ +#define UDF_PART_ACCESS_TYPE_NOT_SPECIFIED UINT32_C(0x00000000) +/** Read only: No writes. */ +#define UDF_PART_ACCESS_TYPE_READ_ONLY UINT32_C(0x00000001) +/** Write once: Sectors can only be written once. */ +#define UDF_PART_ACCESS_TYPE_WRITE_ONCE UINT32_C(0x00000002) +/** Rewritable: Logical sectors may require preprocessing before writing. */ +#define UDF_PART_ACCESS_TYPE_REWRITABLE UINT32_C(0x00000003) +/** Overwritable: No restrictions on writing. */ +#define UDF_PART_ACCESS_TYPE_OVERWRITABLE UINT32_C(0x00000004) +/** @} */ + + +/** + * Logical volume descriptor (LVD) (@ecma167{3,10.6,58}, @udf260{2.2.4,30}). + * + * @note Variable length. + */ +typedef struct UDFLOGICALVOLUMEDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_LOGICAL_VOLUME_DESC). */ + UDFTAG Tag; + /** 0x010: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x014: Character set used in the achLogicalVolumeID field. */ + UDFCHARSPEC DescCharSet; + /** 0x054: The logical volume ID (label). */ + UDFDSTRING achLogicalVolumeID[128]; + /** 0x0d4: Logical block size (in bytes). */ + uint32_t cbLogicalBlock; + /** 0x0d8: Domain identifier (UDF_ENTITY_ID_LVD_DOMAIN). */ + UDFENTITYID idDomain; + /** 0x0f8: Logical volume contents use. */ + union + { + /** Byte view. */ + uint8_t ab[16]; + /** The extent containing the file set descriptor. */ + UDFLONGAD FileSetDescriptor; + } ContentsUse; + /** 0x108: Map table length (in bytes). */ + uint32_t cbMapTable; + /** 0x10c: Number of partition maps. */ + uint32_t cPartitionMaps; + /** 0x110: Implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0x130: Implementation use. */ + union + { + /** Byte view. */ + uint8_t ab[128]; + } ImplementationUse; + /** 0x1b0: Integrity sequence extent. Can be zero if cPartitionMaps is zero. */ + UDFEXTENTAD IntegritySeqExtent; + /** 0x1b8: Partition maps (length given by @a cbMapTable), data format is + * defined by UDFPARTMAPHDR, UDFPARTMAPTYPE1 and UDFPARTMAPTYPE2. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abPartitionMaps[RT_FLEXIBLE_ARRAY]; +} UDFLOGICALVOLUMEDESC; +AssertCompileMemberOffset(UDFLOGICALVOLUMEDESC, abPartitionMaps, 0x1b8); +/** Pointer to an UDF logical volume descriptor. */ +typedef UDFLOGICALVOLUMEDESC *PUDFLOGICALVOLUMEDESC; +/** Pointer to a const UDF logical volume descriptor. */ +typedef UDFLOGICALVOLUMEDESC const *PCUDFLOGICALVOLUMEDESC; + +/** + * Partition map header (UDFLOGICALVOLUMEDESC::abPartitionMaps). + */ +typedef struct UDFPARTMAPHDR +{ + /** 0x00: The partition map type. */ + uint8_t bType; + /** 0x01: The partition map length (header included). */ + uint8_t cb; +} UDFPARTMAPHDR; +AssertCompileSize(UDFPARTMAPHDR, 2); +/** Pointer to a partition map header. */ +typedef UDFPARTMAPHDR *PUDFPARTMAPHDR; +/** Pointer to a const partition map header. */ +typedef UDFPARTMAPHDR const *PCUDFPARTMAPHDR; + +/** + * Partition map type 1 (UDFLOGICALVOLUMEDESC::abPartitionMaps). + */ +typedef struct UDFPARTMAPTYPE1 +{ + /** 0x00: Header (uType=1, cb=6). */ + UDFPARTMAPHDR Hdr; + /** 0x02: Volume sequence number. */ + uint16_t uVolumeSeqNo; + /** 0x04: Partition number. */ + uint16_t uPartitionNo; +} UDFPARTMAPTYPE1; +AssertCompileSize(UDFPARTMAPTYPE1, 6); +/** Pointer to a type 1 partition map. */ +typedef UDFPARTMAPTYPE1 *PUDFPARTMAPTYPE1; +/** Pointer to a const type 1 partition map. */ +typedef UDFPARTMAPTYPE1 const *PCUDFPARTMAPTYPE1; + +/** + * Partition map type 2 (UDFLOGICALVOLUMEDESC::abPartitionMaps). + */ +typedef struct UDFPARTMAPTYPE2 +{ + /** 0x00: Header (uType=2, cb=64). */ + UDFPARTMAPHDR Hdr; + /** 0x02: Reserved \#1. */ + uint16_t uReserved1; + /** 0x04: Partition ID type (UDF_ENTITY_ID_VPM_PARTITION_TYPE, + * UDF_ENTITY_ID_SPM_PARTITION_TYPE, or UDF_ENTITY_ID_MPM_PARTITION_TYPE). */ + UDFENTITYID idPartitionType; + /** 0x24: Volume sequence number. */ + uint16_t uVolumeSeqNo; + /** 0x26: Partition number. */ + uint16_t uPartitionNo; + /** 0x28: Data specific to the partition ID type. */ + union + { + /** 0x28: Generic view. */ + uint8_t ab[24]; + + /** UDF_ENTITY_ID_VPM_PARTITION_TYPE. */ + struct + { + /** 0x28: Reserved. */ + uint8_t abReserved2[24]; + } Vpm; + + /** UDF_ENTITY_ID_SPM_PARTITION_TYPE. */ + struct + { + /** 0x28: Packet length in blocks. */ + uint16_t cBlocksPerPacket; + /** 0x2a: Number of sparing tables. */ + uint8_t cSparingTables; + /** 0x2b: Reserved padding byte. */ + uint8_t bReserved2; + /** 0x2c: The size of each sparing table. */ + uint32_t cbSparingTable; + /** 0x30: The sparing table locations (logical block). */ + uint32_t aoffSparingTables[4]; + } Spm; + + /** UDF_ENTITY_ID_MPM_PARTITION_TYPE. */ + struct + { + /** 0x28: Metadata file entry location (logical block). */ + uint32_t offMetadataFile; + /** 0x2c: Metadata mirror file entry location (logical block). */ + uint32_t offMetadataMirrorFile; + /** 0x30: Metadata bitmap file entry location (logical block). */ + uint32_t offMetadataBitmapFile; + /** 0x34: The metadata allocation unit (logical blocks) */ + uint32_t cBlocksAllocationUnit; + /** 0x38: The metadata allocation unit alignment (logical blocks). */ + uint16_t cBlocksAlignmentUnit; + /** 0x3a: Flags, UDFPARTMAPMETADATA_F_XXX. */ + uint8_t fFlags; + /** 0x3b: Reserved. */ + uint8_t abReserved2[5]; + } Mpm; + } u; +} UDFPARTMAPTYPE2; +AssertCompileSize(UDFPARTMAPTYPE2, 64); +/** Pointer to a type 2 partition map. */ +typedef UDFPARTMAPTYPE2 *PUDFPARTMAPTYPE2; +/** Pointer to a const type 2 partition map. */ +typedef UDFPARTMAPTYPE2 const *PCUDFPARTMAPTYPE2; + +/** @name UDFPARTMAPMETADATA_F_XXX + * @{ */ +/** Indicates that the metadata is mirrored too, not just the file entry. */ +#define UDFPARTMAPMETADATA_F_DATA_MIRRORED UINT8_C(1) +/** @} */ + + +/** + * UDF unallocated space descriptor (USD) (@ecma167{3,10.8,61}, @udf260{2.2.5,32}). + * + * @note Variable length. + */ +typedef struct UDFUNALLOCATEDSPACEDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_UNALLOCATED_SPACE_DESC). */ + UDFTAG Tag; + /** 0x10: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x14: Number of allocation descriptors in the array below. */ + uint32_t cAllocationDescriptors; + /** 0x18: Allocation descriptors (variable length). */ + RT_FLEXIBLE_ARRAY_EXTENSION + UDFEXTENTAD aAllocationDescriptors[RT_FLEXIBLE_ARRAY]; +} UDFUNALLOCATEDSPACEDESC; +AssertCompileMemberOffset(UDFUNALLOCATEDSPACEDESC, aAllocationDescriptors, 0x18); +/** Pointer to an UDF unallocated space descriptor. */ +typedef UDFUNALLOCATEDSPACEDESC *PUDFUNALLOCATEDSPACEDESC; +/** Pointer to a const UDF unallocated space descriptor. */ +typedef UDFUNALLOCATEDSPACEDESC const *PCUDFUNALLOCATEDSPACEDESC; + + +/** + * UDF terminating descriptor (@ecma167{3,10.9,62}, @ecma167{4,14.2,62}). + */ +typedef struct UDFTERMINATINGDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_TERMINATING_DESC). */ + UDFTAG Tag; + /** 0x10: Reserved, MBZ. */ + uint8_t abReserved[496]; +} UDFTERMINATINGDESC; +/** Pointer to an UDF terminating descriptor. */ +typedef UDFTERMINATINGDESC *PUDFTERMINATINGDESC; +/** Pointer to a const UDF terminating descriptor. */ +typedef UDFTERMINATINGDESC const *PCUDFTERMINATINGDESC; + + +/** + * UDF logical volume integrity descriptor (LVID) (@ecma167{3,10.10,62}, + * @udf260{2.2.6,32}). + */ +typedef struct UDFLOGICALVOLINTEGRITYDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_TERMINATING_DESC). */ + UDFTAG Tag; + /** 0x10: Recording timestamp. */ + UDFTIMESTAMP RecordingTimestamp; + /** 0x1c: Integrity type (UDF_LVID_TYPE_XXX). */ + uint32_t uIntegrityType; + /** 0x20: The next integrity extent. */ + UDFEXTENTAD NextIntegrityExtent; + /** 0x28: Number of partitions. */ + uint32_t cPartitions; + /** 0x2c: Length of implementation use. */ + uint32_t cbImplementationUse; + /** + * There are two tables each @a cPartitions in size. The first is the free + * space table. The second the size table. + * + * Following these tables there are @a cbImplementationUse bytes of space for + * the implementation to use. + */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint32_t aTables[RT_FLEXIBLE_ARRAY]; +} UDFLOGICALVOLINTEGRITYDESC; +AssertCompileMemberOffset(UDFLOGICALVOLINTEGRITYDESC, cbImplementationUse, 0x2c); +AssertCompileMemberOffset(UDFLOGICALVOLINTEGRITYDESC, aTables, 0x30); +/** Pointer to an UDF logical volume integrity descriptor. */ +typedef UDFLOGICALVOLINTEGRITYDESC *PUDFLOGICALVOLINTEGRITYDESC; +/** Pointer to a const UDF logical volume integrity descriptor. */ +typedef UDFLOGICALVOLINTEGRITYDESC const *PCUDFLOGICALVOLINTEGRITYDESC; + +/** @name UDF_LVID_TYPE_XXX - Integirty types. + * @{ */ +#define UDF_LVID_TYPE_OPEN UINT32_C(0x00000000) +#define UDF_LVID_TYPE_CLOSE UINT32_C(0x00000001) +/** @} */ + +/** + * UDF file set descriptor (FSD) (@ecma167{4,14.1,86}, @udf260{2.3.2,54}). + */ +typedef struct UDFFILESETDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_FILE_SET_DESC). */ + UDFTAG Tag; + /** 0x010: Recording timestamp. */ + UDFTIMESTAMP RecordingTimestamp; + /** 0x01c: Interchange level. */ + uint16_t uInterchangeLevel; + /** 0x01e: Maximum interchange level. */ + uint16_t uMaxInterchangeLevel; + /** 0x020: Character set bitmask (aka list). Each bit correspond to a + * character set number. */ + uint32_t fCharacterSets; + /** 0x024: Maximum character set bitmask (aka list). */ + uint32_t fMaxCharacterSets; + /** 0x028: File set number. */ + uint32_t uFileSetNo; + /** 0x02c: File set descriptor number. */ + uint32_t uFileSetDescNo; + /** 0x030: Logical volume identifier character set. */ + UDFCHARSPEC LogicalVolumeIDCharSet; + /** 0x070: Logical volume identifier string. */ + UDFDSTRING achLogicalVolumeID[128]; + /** 0x0e0: File set character set. */ + UDFCHARSPEC FileSetCharSet; + /** 0x130: Identifier string for this file set. */ + UDFDSTRING achFileSetID[32]; + /** 0x150: Names a root file containing copyright info. Optional. */ + UDFDSTRING achCopyrightFile[32]; + /** 0x170: Names a root file containing an abstract for the file set. Optional. */ + UDFDSTRING achAbstractFile[32]; + /** 0x190: Root directory information control block location (ICB). + * An ICB is a sequence made up of UDF_TAG_ID_FILE_ENTRY, + * UDF_TAG_ID_INDIRECT_ENTRY, and UDF_TAG_ID_TERMINAL_ENTRY descriptors. */ + UDFLONGAD RootDirIcb; + /** 0x1a0: Domain identifier (UDF_ENTITY_FSD_LVD_DOMAIN). Optional. */ + UDFENTITYID idDomain; + /** 0x1c0: Next location with file set descriptors location, 0 if none. */ + UDFLONGAD NextExtent; + /** 0x1d0: Location of the system stream directory associated with the + * file set. Optional. */ + UDFLONGAD SystemStreamDirIcb; + /** 0x1e0: Reserved, MBZ. */ + uint8_t abReserved[32]; +} UDFFILESETDESC; +AssertCompileSize(UDFFILESETDESC, 512); +/** Pointer to an UDF file set descriptor. */ +typedef UDFFILESETDESC *PUDFFILESETDESC; +/** Pointer to a const UDF file set descriptor. */ +typedef UDFFILESETDESC const *PCUDFFILESETDESC; + + +/** + * UDF file identifier descriptor (FID) (@ecma167{4,14.4,91}, @udf260{2.3.4,57}). + */ +typedef struct UDFFILEIDDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_FILE_ID_DESC). */ + UDFTAG Tag; + /** 0x10: File version number (1..32767). Always set to 1. */ + uint16_t uVersion; + /** 0x12: File characteristics (UDF_FILE_FLAGS_XXX). */ + uint8_t fFlags; + /** 0x13: File identifier (name) length. */ + uint8_t cbName; + /** 0x14: Location of an information control block describing the file. + * Can be null if marked deleted. The implementation defined part of + * this contains additional flags and a unique ID. */ + UDFLONGAD Icb; + /** 0x24: Length of implementation use field (in bytes). This can be zero. + * + * It can be used to prevent the following FID from spanning a block + * boundrary, in which case it will be 32 bytes or more, and the it will + * start with an UDFENTITYID identifying who last wrote it. + * + * The latter padding fun is a requirement from write-once media. */ + uint16_t cbImplementationUse; + /** 0x26: Two variable sized fields followed by padding to make the + * actual structure size 4 byte aligned. The first field in an + * implementation use field with length given by @a cbImplementationUse. + * After that is a d-string field with the name of the file, length + * specified by @a cbName. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abImplementationUse[RT_FLEXIBLE_ARRAY]; +} UDFFILEIDDESC; +AssertCompileMemberOffset(UDFFILEIDDESC, fFlags, 0x12); +AssertCompileMemberOffset(UDFFILEIDDESC, cbName, 0x13); +AssertCompileMemberOffset(UDFFILEIDDESC, Icb, 0x14); +AssertCompileMemberOffset(UDFFILEIDDESC, abImplementationUse, 0x26); +/** Pointer to an UDF file set descriptor */ +typedef UDFFILEIDDESC *PUDFFILEIDDESC; +/** Pointer to a const UDF file set descriptor */ +typedef UDFFILEIDDESC const *PCUDFFILEIDDESC; + +/** Get the pointer to the name field. */ +#define UDFFILEIDDESC_2_NAME(a_pFid) ((uint8_t const *)(&(a_pFid)->abImplementationUse[(a_pFid)->cbImplementationUse])) +/** Calculates the total size the size of a record. */ +#define UDFFILEIDDESC_CALC_SIZE_EX(cbImplementationUse, cbName) \ + RT_ALIGN_32((uint32_t)RT_UOFFSETOF(UDFFILEIDDESC, abImplementationUse) + cbImplementationUse + cbName, 4) +/** Gets the actual size of a record. */ +#define UDFFILEIDDESC_GET_SIZE(a_pFid) UDFFILEIDDESC_CALC_SIZE_EX((a_pFid)->cbImplementationUse, (a_pFid)->cbName) + +/** @name UDF_FILE_FLAGS_XXX + * @{ */ +/** Existence - Hide the file from the user. */ +#define UDF_FILE_FLAGS_HIDDEN UINT8_C(0x01) +/** Directory - Indicates a directory as apposed to some kind of file or symlink or something (0). */ +#define UDF_FILE_FLAGS_DIRECTORY UINT8_C(0x02) +/** Deleted - Indicate that the file has been deleted. Assoicated descriptors may still be valid, though. */ +#define UDF_FILE_FLAGS_DELETED UINT8_C(0x04) +/** Parent - Indicate the ICB field refers to the parent directory (or maybe + * a file in case of streaming directory). */ +#define UDF_FILE_FLAGS_PARENT UINT8_C(0x08) +/** Metadata - Zero means user data, one means implementation specific metadata. + * Only allowed used in stream directory. */ +#define UDF_FILE_FLAGS_METADATA UINT8_C(0x10) +/** Reserved bits that should be zer. */ +#define UDF_FILE_FLAGS_RESERVED_MASK UINT8_C(0xe0) +/** @} */ + + +/** + * UDF allocation extent descriptor (@ecma167{4,14.5,93}, @udf260{2.3.11,67}). + */ +typedef struct UDFALLOCATIONEXTENTDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_ALLOCATION_EXTENT_DESC). */ + UDFTAG Tag; + /** 0x10: Previous allocation extent location (logical block in current + * partition). */ + uint32_t offPrevExtent; + /** 0x14: Size of the following allocation descriptors (in bytes). */ + uint32_t cbAllocDescs; + /** 0x18: Allocation descriptors. */ + union + { + UDFSHORTAD aShortADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFLONGAD aLongADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFEXTAD aExtADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + } u; +} UDFALLOCATIONEXTENTDESC; +AssertCompileMemberOffset(UDFALLOCATIONEXTENTDESC, u, 0x18); +/** Pointer to an UDF allocation extent descriptor. */ +typedef UDFALLOCATIONEXTENTDESC *PUDFALLOCATIONEXTENTDESC; +/** Pointer to a const UDF allocation extent descriptor. */ +typedef UDFALLOCATIONEXTENTDESC const *PCUDFALLOCATIONEXTENTDESC; + +/** + * UDF information control block tag (@ecma167{4,14.6,93}, @udf260{2.3.5,60}). + */ +typedef struct UDFICBTAG +{ + /** 0x00: Number of direct entries in this ICB prior to this one. */ + uint32_t cEntiresBeforeThis; + /** 0x04: ICB hierarchy building strategy type (UDF_ICB_STRATEGY_TYPE_XXX). */ + uint16_t uStrategyType; + /** 0x06: Type specific parameters. */ + uint8_t abStrategyParams[2]; + /** 0x08: Max number of direct and indirect entries that MAY be recorded in this ICB. */ + uint16_t cMaxEntries; + /** 0x0a: Reserved, MBZ. */ + uint8_t bReserved; + /** 0x0b: File type (UDF_FILE_TYPE_XXX). */ + uint8_t bFileType; + /** 0x0c: Parent ICB location. */ + UDFLBADDR ParentIcb; + /** 0x12: Parent ICB location (UDF_ICB_FLAGS_XXX). */ + uint16_t fFlags; +} UDFICBTAG; +AssertCompileSize(UDFICBTAG, 20); +typedef UDFICBTAG *PUDFICBTAG; +typedef UDFICBTAG const *PCUDFICBTAG; + +/** @name UDF_ICB_STRATEGY_TYPE_XXX - ICB hierarchy building strategies + * + * See @ecma167{4,14.6.2,94}, @udf260{6.6,121} + * + * @{ */ +/** Strategy not specified. */ +#define UDF_ICB_STRATEGY_TYPE_NOT_SPECIFIED UINT16_C(0x0000) +/** See @ecma167{4,A.2,129}. */ +#define UDF_ICB_STRATEGY_TYPE_1 UINT16_C(0x0001) +/** See @ecma167{4,A.3,131}. */ +#define UDF_ICB_STRATEGY_TYPE_2 UINT16_C(0x0002) +/** See @ecma167{4,A.4,131}. */ +#define UDF_ICB_STRATEGY_TYPE_3 UINT16_C(0x0003) +/** See @ecma167{4,A.5,131}. */ +#define UDF_ICB_STRATEGY_TYPE_4 UINT16_C(0x0004) +/** Defined by the UDF spec, see @udf260{6.6,121}. */ +#define UDF_ICB_STRATEGY_TYPE_4096 UINT16_C(0x1000) +/** @} */ + +/** @name UDF_ICB_FLAGS_XXX - ICB flags + * + * See @ecma167{4,14.6.8,95}, @udf260{2.3.5.4,61} + * + * @{ */ +/** Using UDFSHORTAD. */ +#define UDF_ICB_FLAGS_AD_TYPE_SHORT UINT16_C(0x0000) +/** Using UDFLONGAD. */ +#define UDF_ICB_FLAGS_AD_TYPE_LONG UINT16_C(0x0001) +/** Using UDFEXTAD. */ +#define UDF_ICB_FLAGS_AD_TYPE_EXTENDED UINT16_C(0x0002) +/** File content is embedded in the allocation descriptor area. */ +#define UDF_ICB_FLAGS_AD_TYPE_EMBEDDED UINT16_C(0x0003) +/** Allocation type mask. */ +#define UDF_ICB_FLAGS_AD_TYPE_MASK UINT16_C(0x0007) +/** Set on directories that are sorted (according to @ecma167{4,8.6.1,78}). + * @note Directories are never sorted in UDF. */ +#define UDF_ICB_FLAGS_SORTED_DIRECTORY UINT16_C(0x0008) +/** Not relocatable. */ +#define UDF_ICB_FLAGS_NON_RELOCATABLE UINT16_C(0x0010) +/** Indicate that the file needs backing up (DOS attribute). */ +#define UDF_ICB_FLAGS_ARCHIVE UINT16_C(0x0020) +/** Set UID bit (UNIX). */ +#define UDF_ICB_FLAGS_SET_UID UINT16_C(0x0040) +/** Set GID bit (UNIX). */ +#define UDF_ICB_FLAGS_SET_GID UINT16_C(0x0080) +/** Set sticky bit (UNIX). */ +#define UDF_ICB_FLAGS_STICKY UINT16_C(0x0100) +/** Extents are contiguous. */ +#define UDF_ICB_FLAGS_CONTIGUOUS UINT16_C(0x0200) +/** System bit, reserved for implementation use. */ +#define UDF_ICB_FLAGS_SYSTEM UINT16_C(0x0400) +/** Data has been transformed in some way. + * @note UDF shall not set this bit. */ +#define UDF_ICB_FLAGS_TRANSFORMED UINT16_C(0x0800) +/** Directory may contain multi-versioned files. + * @note UDF shall not set this bit. */ +#define UDF_ICB_FLAGS_MULTI_VERSIONS UINT16_C(0x1000) +/** Is a stream in a stream directory. */ +#define UDF_ICB_FLAGS_STREAM UINT16_C(0x2000) +/** Reserved mask. */ +#define UDF_ICB_FLAGS_RESERVED_MASK UINT16_C(0xc000) +/** @} */ + +/** @name UDF_FILE_TYPE_XXX - File types + * + * See @ecma167{4,14.6.6,94}, @udf260{2.3.5.2,60} + * + * @{ */ +#define UDF_FILE_TYPE_NOT_SPECIFIED UINT8_C(0x00) /**< Not specified by this field. */ +#define UDF_FILE_TYPE_UNALLOCATED_SPACE_ENTRY UINT8_C(0x01) +#define UDF_FILE_TYPE_PARTITION_INTEGRITY_ENTRY UINT8_C(0x02) +#define UDF_FILE_TYPE_INDIRECT_ENTRY UINT8_C(0x03) +#define UDF_FILE_TYPE_DIRECTORY UINT8_C(0x04) +#define UDF_FILE_TYPE_REGULAR_FILE UINT8_C(0x05) +#define UDF_FILE_TYPE_BLOCK_DEVICE UINT8_C(0x06) +#define UDF_FILE_TYPE_CHARACTER_DEVICE UINT8_C(0x07) +#define UDF_FILE_TYPE_EXTENDED_ATTRIBUTES UINT8_C(0x08) +#define UDF_FILE_TYPE_FIFO UINT8_C(0x09) +#define UDF_FILE_TYPE_SOCKET UINT8_C(0x0a) +#define UDF_FILE_TYPE_TERMINAL_ENTRY UINT8_C(0x0b) +#define UDF_FILE_TYPE_SYMBOLIC_LINK UINT8_C(0x0c) +#define UDF_FILE_TYPE_STREAM_DIRECTORY UINT8_C(0x0d) +#define UDF_FILE_TYPE_VAT UINT8_C(0xf8) +#define UDF_FILE_TYPE_REAL_TIME_FILE UINT8_C(0xf9) +#define UDF_FILE_TYPE_METADATA_FILE UINT8_C(0xfa) +#define UDF_FILE_TYPE_METADATA_MIRROR_FILE UINT8_C(0xfb) +#define UDF_FILE_TYPE_METADATA_BITMAP_FILE UINT8_C(0xfc) +/** @} */ + + +/** + * UDF ICB header (derived structure). + */ +typedef struct UDFICBHDR +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_INDIRECT_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; +} UDFICBHDR; +AssertCompileSize(UDFICBHDR, 36); +/** Pointer to an UDF ICB header. */ +typedef UDFICBHDR *PUDFICBHDR; +/** Pointer to a const UDF ICB header. */ +typedef UDFICBHDR const *PCUDFICBHDR; + + +/** + * UDF indirect entry (@ecma167{4,14.7,96}). + */ +typedef struct UDFINDIRECTENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_INDIRECT_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x24: Indirect ICB location. */ + UDFLONGAD IndirectIcb; +} UDFINDIRECTENTRY; +AssertCompileSize(UDFINDIRECTENTRY, 52); +/** Pointer to an UDF indirect entry. */ +typedef UDFINDIRECTENTRY *PUDFINDIRECTENTRY; +/** Pointer to a const UDF indirect entry. */ +typedef UDFINDIRECTENTRY const *PCUDFINDIRECTENTRY; + + +/** + * UDF terminal entry (@ecma167{4,14.8,97}). + */ +typedef struct UDFTERMINALENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_TERMINAL_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag (UDF_FILE_TYPE_TERMINAL_ENTRY). */ + UDFICBTAG IcbTag; +} UDFTERMINALENTRY; +AssertCompileSize(UDFTERMINALENTRY, 36); +/** Pointer to an UDF terminal entry. */ +typedef UDFTERMINALENTRY *PUDFTERMINALENTRY; +/** Pointer to a const UDF terminal entry. */ +typedef UDFTERMINALENTRY const *PCUDFTERMINALENTRY; + + +/** + * UDF file entry (FE) (@ecma167{4,14.8,97}, @udf260{2.3.6,62}). + * + * @note Total length shall not exceed one logical block. + */ +typedef struct UDFFILEENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_FILE_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x24: User ID (UNIX). */ + uint32_t uid; + /** 0x28: Group ID (UNIX). */ + uint32_t gid; + /** 0x2c: Permission (UDF_PERM_XXX). */ + uint32_t fPermissions; + /** 0x30: Number hard links. */ + uint16_t cHardlinks; + /** 0x32: Record format (UDF_REC_FMT_XXX). */ + uint8_t uRecordFormat; + /** 0x33: Record format (UDF_REC_ATTR_XXX). */ + uint8_t fRecordDisplayAttribs; + /** 0x34: Record length (in bytes). + * @note Must be zero according to the UDF specification. */ + uint32_t cbRecord; + /** 0x38: Information length in bytes (file size). */ + uint64_t cbData; + /** 0x40: Number of logical blocks allocated (for file data). */ + uint64_t cLogicalBlocks; + /** 0x48: Time of last access (prior to recording the file entry). */ + UDFTIMESTAMP AccessTime; + /** 0x54: Time of last data modification. */ + UDFTIMESTAMP ModificationTime; + /** 0x60: Time of last attribute/status modification. */ + UDFTIMESTAMP ChangeTime; + /** 0x6c: Checkpoint number (defaults to 1). */ + uint32_t uCheckpoint; + /** 0x70: Extended attribute information control block location. */ + UDFLONGAD ExtAttribIcb; + /** 0x80: Implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0xa0: Unique ID. */ + uint64_t INodeId; + /** 0xa8: Length of extended attributes in bytes, multiple of four. */ + uint32_t cbExtAttribs; + /** 0xac: Length of allocation descriptors in bytes, multiple of four. */ + uint32_t cbAllocDescs; + /** 0xb0: Two variable sized fields. First @a cbExtAttribs bytes of extended + * attributes, then @a cbAllocDescs bytes of allocation descriptors. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abExtAttribs[RT_FLEXIBLE_ARRAY]; +} UDFFILEENTRY; +AssertCompileMemberOffset(UDFFILEENTRY, abExtAttribs, 0xb0); +/** Pointer to an UDF file entry. */ +typedef UDFFILEENTRY *PUDFFILEENTRY; +/** Pointer to a const UDF file entry. */ +typedef UDFFILEENTRY const *PCUDFFILEENTRY; + +/** @name UDF_PERM_XXX - UDFFILEENTRY::fPermissions + * See @ecma167{4,14.9.5,99}. + * @{ */ +#define UDF_PERM_OTH_EXEC UINT32_C(0x00000001) +#define UDF_PERM_OTH_WRITE UINT32_C(0x00000002) +#define UDF_PERM_OTH_READ UINT32_C(0x00000004) +#define UDF_PERM_OTH_ATTRIB UINT32_C(0x00000008) +#define UDF_PERM_OTH_DELETE UINT32_C(0x00000010) +#define UDF_PERM_OTH_MASK UINT32_C(0x0000001f) + +#define UDF_PERM_GRP_EXEC UINT32_C(0x00000020) +#define UDF_PERM_GRP_WRITE UINT32_C(0x00000040) +#define UDF_PERM_GRP_READ UINT32_C(0x00000080) +#define UDF_PERM_GRP_ATTRIB UINT32_C(0x00000100) +#define UDF_PERM_GRP_DELETE UINT32_C(0x00000200) +#define UDF_PERM_GRP_MASK UINT32_C(0x000003e0) + +#define UDF_PERM_USR_EXEC UINT32_C(0x00000400) +#define UDF_PERM_USR_WRITE UINT32_C(0x00000800) +#define UDF_PERM_USR_READ UINT32_C(0x00001000) +#define UDF_PERM_USR_ATTRIB UINT32_C(0x00002000) +#define UDF_PERM_USR_DELETE UINT32_C(0x00004000) +#define UDF_PERM_USR_MASK UINT32_C(0x00007c00) + +#define UDF_PERM_USR_RESERVED_MASK UINT32_C(0xffff8000) +/** @} */ + +/** @name UDF_REC_FMT_XXX - Record format. + * See @ecma167{4,14.9.7,100}. + * @{ */ +/** Not record format specified. + * @note The only allowed value according to the UDF specification. */ +#define UDF_REC_FMT_NOT_SPECIFIED UINT8_C(0x00) +/** @} */ + +/** @name UDF_REC_ATTR_XXX - Record display attributes. + * See @ecma167{4,14.9.8,100}. + * @{ */ +/** Manner of record display not specified. + * @note The only allowed value according to the UDF specification. */ +#define UDF_REC_ATTR_NOT_SPECIFIED UINT8_C(0x00) +/** @} */ + + +/** + * UDF extended attribute header descriptor (@ecma167{4,14.10.1,102}, + * @udf260{3.3.4,79}). + */ +typedef struct UDFEXTATTRIBHDRDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_EXTENDED_ATTRIB_HDR_DESC). */ + UDFTAG Tag; + /** 0x10: Implementation attributes location (byte offset) into the EA space. + * This typically set to UINT32_MAX if not present, though any value larger + * than the EA space will do. */ + uint32_t offImplementationAttribs; + /** 0x14: Application attributes location (byte offset) into the EA space. + * This typically set to UINT32_MAX if not present, though any value larger + * than the EA space will do. */ + uint32_t offApplicationAttribs; +} UDFEXTATTRIBHDRDESC; +AssertCompileSize(UDFEXTATTRIBHDRDESC, 24); +/** Pointer to an UDF extended attribute header descriptor. */ +typedef UDFEXTATTRIBHDRDESC *PUDFEXTATTRIBHDRDESC; +/** Pointer to a const UDF extended attribute header descriptor. */ +typedef UDFEXTATTRIBHDRDESC const *PCUDFEXTATTRIBHDRDESC; + +/** + * UDF character set info EA data (@ecma167{4,14.10.3,104}). + * + * Not needed by UDF. + */ +typedef struct UDFEADATACHARSETINFO +{ + /** 0x00/0x0c: The length of the escape sequences (in bytes). */ + uint32_t cbEscSeqs; + /** 0x04/0x10: The character set type (UDF_CHAR_SET_TYPE_XXX). */ + uint8_t bType; + /** 0x05/0x11: Escape sequences. */ + uint8_t abEscSeqs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFEADATACHARSETINFO; +/** Pointer to UDF character set info EA data. */ +typedef UDFEADATACHARSETINFO *PUDFEADATACHARSETINFO; +/** Pointer to const UDF character set info EA data. */ +typedef UDFEADATACHARSETINFO const *PCUDFEADATACHARSETINFO; +/** UDFGEA::uAttribType value for UDFEADATACHARSETINFO.*/ +#define UDFEADATACHARSETINFO_ATTRIB_TYPE UINT32_C(0x00000001) +/** UDFGEA::uAttribSubtype value for UDFEADATACHARSETINFO. */ +#define UDFEADATACHARSETINFO_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF alternate permissions EA data (@ecma167{4,14.10.4,105}, @udf260{3.3.4.2,80}). + * @note Not recorded according to the UDF specification. + */ +typedef struct UDFEADATAALTPERM +{ + /** 0x00/0x0c: Alternative owner ID. */ + uint16_t idOwner; + /** 0x02/0x0e: Alternative group ID. */ + uint16_t idGroup; + /** 0x04/0x10: Alternative permissions. */ + uint16_t fPermission; +} UDFEADATAALTPERM; +/** Pointer to UDF alternative permissions EA data. */ +typedef UDFEADATAALTPERM *PUDFEADATAALTPERM; +/** Pointer to const UDF alternative permissions EA data. */ +typedef UDFEADATAALTPERM const *PCUDFEADATAALTPERM; +/** UDFGEA::uAttribType value for UDFEADATAALTPERM. */ +#define UDFEADATAALTPERM_ATTRIB_TYPE UINT32_C(0x00000003) +/** UDFGEA::uAttribSubtype value for UDFEADATAALTPERM. */ +#define UDFEADATAALTPERM_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF file times EA data (@ecma167{4,14.10.5,108}, @udf260{3.3.4.3,80}). + * (This is a bit reminiscent of ISO9660RRIPTF.) + */ +typedef struct UDFEADATAFILETIMES +{ + /** 0x00/0x0c: Timestamp length. */ + uint32_t cbTimestamps; + /** 0x04/0x10: Indicates which timestamps are present + * (UDF_FILE_TIMES_EA_F_XXX). */ + uint32_t fFlags; + /** 0x08/0x14: Timestamps. */ + UDFTIMESTAMP aTimestamps[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFEADATAFILETIMES; +/** Pointer to UDF file times EA data. */ +typedef UDFEADATAFILETIMES *PUDFEADATAFILETIMES; +/** Pointer to const UDF file times EA data. */ +typedef UDFEADATAFILETIMES const *PCUDFEADATAFILETIMES; +/** UDFGEA::uAttribType value for UDFEADATAFILETIMES. */ +#define UDFEADATAFILETIMES_ATTRIB_TYPE UINT32_C(0x00000005) +/** UDFGEA::uAttribSubtype value for UDFEADATAFILETIMES. */ +#define UDFEADATAFILETIMES_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** @name UDF_FILE_TIMES_EA_F_XXX - File times existence flags. + * See @ecma167{4,14.10.5.6,109} + * @{ */ +#define UDF_FILE_TIMES_EA_F_BIRTH UINT8_C(0x01) /**< Birth (creation) timestamp is recorded. */ +#define UDF_FILE_TIMES_EA_F_DELETE UINT8_C(0x04) /**< Deletion timestamp is recorded. */ +#define UDF_FILE_TIMES_EA_F_EFFECTIVE UINT8_C(0x08) /**< Effective timestamp is recorded. */ +#define UDF_FILE_TIMES_EA_F_BACKUP UINT8_C(0x20) /**< Backup timestamp is recorded. */ +#define UDF_FILE_TIMES_EA_F_RESERVED_MASK UINT8_C(0xd2) +/** @} */ + +/** + * UDF information times EA data (@ecma167{4,14.10.6,109}). + */ +typedef struct UDFEADATAINFOTIMES +{ + /** 0x00/0x0c: Timestamp length. */ + uint32_t cbTimestamps; + /** 0x04/0x10: Indicates which timestamps are present + * (UDF_INFO_TIMES_EA_F_XXX). */ + uint32_t fFlags; + /** 0x08/0x14: Timestamps. */ + UDFTIMESTAMP aTimestamps[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFEADATAINFOTIMES; +/** Pointer to UDF information times EA data. */ +typedef UDFEADATAINFOTIMES *PUDFEADATAINFOTIMES; +/** Pointer to const UDF information times EA data. */ +typedef UDFEADATAINFOTIMES const *PCUDFEADATAINFOTIMES; +/** UDFGEA::uAttribType value for UDFEADATAINFOTIMES. */ +#define UDFEADATAINFOTIMES_ATTRIB_TYPE UINT32_C(0x00000006) +/** UDFGEA::uAttribSubtype value for UDFEADATAINFOTIMES. */ +#define UDFEADATAINFOTIMES_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** @name UDF_INFO_TIMES_EA_F_XXX - Information times existence flags. + * See @ecma167{4,14.10.6.6,110} + * @{ */ +#define UDF_INFO_TIMES_EA_F_BIRTH UINT8_C(0x01) /**< Birth (creation) timestamp is recorded. */ +#define UDF_INFO_TIMES_EA_F_MODIFIED UINT8_C(0x02) /**< Last (data) modified timestamp is recorded. */ +#define UDF_INFO_TIMES_EA_F_EXPIRE UINT8_C(0x04) /**< Expiration (deletion) timestamp is recorded. */ +#define UDF_INFO_TIMES_EA_F_EFFECTIVE UINT8_C(0x08) /**< Effective timestamp is recorded. */ +#define UDF_INFO_TIMES_EA_F_RESERVED_MASK UINT8_C(0xf0) +/** @} */ + +/** + * UDF device specification EA data (@ecma167{4,14.10.7,110}, @udf260{3.3.4.4,81}). + */ +typedef struct UDFEADATADEVICESPEC +{ + /** 0x00/0x0c: Length of implementation use field. */ + uint32_t cbImplementationUse; + /** 0x04/0x10: Major device number. */ + uint32_t uMajorDeviceNo; + /** 0x08/0x14: Minor device number. */ + uint32_t uMinorDeviceNo; + /** 0x0c/0x18: Implementation use field (variable length). + * UDF specficiation expects UDFENTITYID with a "*Developer ID" as first part + * here. */ + uint8_t abImplementationUse[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFEADATADEVICESPEC; +/** Pointer to UDF device specification EA data. */ +typedef UDFEADATADEVICESPEC *PUDFEADATADEVICESPEC; +/** Pointer to const UDF device specification EA data. */ +typedef UDFEADATADEVICESPEC const *PCUDFEADATADEVICESPEC; +/** UDFGEA::uAttribType value for UDFEADATADEVICESPEC. */ +#define UDFEADATADEVICESPEC_ATTRIB_TYPE UINT32_C(0x0000000c) +/** UDFGEA::uAttribSubtype value for UDFEADATADEVICESPEC. */ +#define UDFEADATADEVICESPEC_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF free EA space payload for implementation and application use EAs + * (@udf260{3.3.4.5.1.1,82}, @udf260{3.3.4.6.1.1,88}). + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_FREE_EA_SPACE. + * UDFEADATAAPPUSE::idImplementation is UDF_ENTITY_ID_AUEA_FREE_EA_SPACE. + */ +typedef struct UDFFREEEASPACE +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Free space. */ + uint8_t abFree[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFFREEEASPACE; +/** Pointer to UDF free EA space impl/app use payload. */ +typedef UDFFREEEASPACE *PUDFFREEEASPACE; +/** Pointer to const UDF free EA space impl/app use payload. */ +typedef UDFFREEEASPACE const *PCUDFFREEEASPACE; + +/** + * UDF DVD copyright management information implementation use EA payload + * (@udf260{3.3.4.5.1.2,83}). + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_DVD_CGMS_INFO. + */ +typedef struct UDFIUEADVDCGMSINFO +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: The CGMS information (whatever that is). */ + uint8_t bInfo; + /** 0x03/0x33: Data structure type (whatever that is). */ + uint8_t bType; + /** 0x04/0x34: Production system information, probably dependend on the + * values of previous fields. */ + uint8_t abProtSysInfo[4]; +} UDFIUEADVDCGMSINFO; +/** Pointer to UDF DVD copyright management information implementation use EA payload. */ +typedef UDFIUEADVDCGMSINFO *PUDFIUEADVDCGMSINFO; +/** Pointer to const UDF DVD copyright management information implementation use EA payload. */ +typedef UDFIUEADVDCGMSINFO const *PCUDFIUEADVDCGMSINFO; + +/** + * UDF OS/2 EA length implementation use EA payload (@udf260{3.3.4.5.3.1,84}). + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_OS2_EA_LENGTH. + */ +#pragma pack(2) +typedef struct UDFIUEAOS2EALENGTH +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: The CGMS information (whatever that is). */ + uint32_t cbEAs; +} UDFIUEAOS2EALENGTH; +#pragma pack() +AssertCompileMemberOffset(UDFIUEAOS2EALENGTH, cbEAs, 2); +/** Pointer to UDF OS/2 EA length implementation use EA payload. */ +typedef UDFIUEAOS2EALENGTH *PUDFIUEAOS2EALENGTH; +/** Pointer to const UDF OS/2 EA length implementation use EA payload. */ +typedef UDFIUEAOS2EALENGTH const *PCUDFIUEAOS2EALENGTH; + +/** + * UDF Mac volume info implementation use EA payload (@udf260{3.3.4.5.4.1,84}). + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_MAC_VOLUME_INFO. + */ +#pragma pack(2) +typedef struct UDFIUEAMACVOLINFO +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Last modification time. */ + UDFTIMESTAMP LastModificationTime; + /** 0x0e/0x3e: Last backup time. */ + UDFTIMESTAMP LastBackupTime; + /** 0x1a/0x4e: Volume finder information. */ + uint32_t au32FinderInfo[8]; +} UDFIUEAMACVOLINFO; +#pragma pack() +AssertCompileMemberOffset(UDFIUEAMACVOLINFO, au32FinderInfo, 0x1a); +/** Pointer to UDF Mac volume info implementation use EA payload. */ +typedef UDFIUEAMACVOLINFO *PUDFIUEAMACVOLINFO; +/** Pointer to const UDF Mac volume info implementation use EA payload. */ +typedef UDFIUEAMACVOLINFO const *PCUDFIUEAMACVOLINFO; + +/** + * UDF point for use in Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACPOINT +{ + /** X coordinate. */ + int16_t x; + /** Y coordinate. */ + int16_t y; +} UDFMACPOINT; + +/** + * UDF rectangle for using Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACRECT +{ + /** top Y coordinate. */ + int16_t yTop; + /** left X coordinate. */ + int16_t xLeft; + /** bottom Y coordinate. (exclusive?) */ + int16_t yBottom; + /** right X coordinate. (exclusive?) */ + int16_t xRight; +} UDFMACRECT; + +/** + * UDF finder directory info for Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACFDINFO +{ + UDFMACRECT FrRect; + int16_t FrFlags; + UDFMACPOINT FrLocation; + int16_t FrView; +} UDFMACFDINFO; +AssertCompileSize(UDFMACFDINFO, 16); + +/** + * UDF finder directory extended info for Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACFDXINFO +{ + UDFMACPOINT FrScroll; + int32_t FrOpenChain; + uint8_t FrScript; + uint8_t FrXFlags; + uint16_t FrComment; + uint32_t FrPutAway; +} UDFMACFDXINFO; +AssertCompileSize(UDFMACFDXINFO, 16); + +/** + * UDF Mac finder info implementation use EA payload (@udf260{3.3.4.5.4.1,84}), + * directory edition. + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO. + */ +typedef struct UDFIUEAMACFINDERINFODIR +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Explicit alignment padding, MBZ. */ + uint16_t uPadding; + /** 0x04/0x34: Parent directory ID. */ + uint32_t idParentDir; + /** 0x08/0x38: Dir information. */ + UDFMACFDINFO DirInfo; + /** 0x18/0x48: Dir extended information. */ + UDFMACFDXINFO DirExInfo; +} UDFIUEAMACFINDERINFODIR; +AssertCompileMemberOffset(UDFIUEAMACFINDERINFODIR, DirInfo, 0x08); +AssertCompileMemberOffset(UDFIUEAMACFINDERINFODIR, DirExInfo, 0x18); +AssertCompileSize(UDFIUEAMACFINDERINFODIR, 0x28); +/** Pointer to UDF Mac finder info for dir implementation use EA payload. */ +typedef UDFIUEAMACFINDERINFODIR *PUDFIUEAMACFINDERINFODIR; +/** Pointer to const UDF Mac finder info for dir implementation use EA payload. */ +typedef UDFIUEAMACFINDERINFODIR const *PCUDFIUEAMACFINDERINFODIR; + +/** + * UDF finder file info for Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACFFINFO +{ + uint32_t FrType; + uint32_t FrCreator; + uint16_t FrFlags; + UDFMACPOINT FrLocation; + int16_t FrFldr; +} UDFMACFFINFO; +AssertCompileSize(UDFMACFFINFO, 16); + +/** + * UDF finder file extended info for Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACFFXINFO +{ + int16_t FrIconID; + uint8_t FdUnused[6]; + uint8_t FrScript; + uint8_t FrXFlags; + uint16_t FrComment; + uint32_t FrPutAway; +} UDFMACFFXINFO; +AssertCompileSize(UDFMACFFXINFO, 16); + +/** + * UDF Mac finder info implementation use EA payload (@udf260{3.3.4.5.4.1,84}), + * file edition. + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO. + */ +typedef struct UDFIUEAMACFINDERINFOFILE +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Explicit alignment padding, MBZ. */ + uint16_t uPadding; + /** 0x04/0x34: Parent directory ID. */ + uint32_t idParentDir; + /** 0x08/0x38: File information. */ + UDFMACFFINFO FileInfo; + /** 0x18/0x48: File extended information. */ + UDFMACFFXINFO FileExInfo; + /** 0x28/0x58: The size of the fork data (in bytes). */ + uint32_t cbForkData; + /** 0x2c/0x5c: The size of the fork allocation (in bytes). */ + uint32_t cbForkAlloc; +} UDFIUEAMACFINDERINFOFILE; +AssertCompileMemberOffset(UDFIUEAMACFINDERINFOFILE, FileInfo, 0x08); +AssertCompileMemberOffset(UDFIUEAMACFINDERINFOFILE, FileExInfo, 0x18); +AssertCompileMemberOffset(UDFIUEAMACFINDERINFOFILE, cbForkData, 0x28); +AssertCompileSize(UDFIUEAMACFINDERINFOFILE, 0x30); +/** Pointer to UDF Mac finder info for file implementation use EA payload. */ +typedef UDFIUEAMACFINDERINFOFILE *PUDFIUEAMACFINDERINFOFILE; +/** Pointer to const UDF Mac finder info for file implementation use EA payload. */ +typedef UDFIUEAMACFINDERINFOFILE const *PCUDFIUEAMACFINDERINFOFILE; + +/** + * UDF OS/400 directory info implementation use EA payload (@udf260{3.3.4.5.6.1,87}) + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_OS400_DIR_INFO. + */ +typedef struct UDFIUEAOS400DIRINFO +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Explicit alignment padding, MBZ. */ + uint16_t uPadding; + /** 0x04/0x34: The directory info, format documented elsewhere. */ + uint8_t abDirInfo[44]; +} UDFIUEAOS400DIRINFO; +AssertCompileSize(UDFIUEAOS400DIRINFO, 0x30); +/** Pointer to UDF Mac finder info for file implementation use EA payload. */ +typedef UDFIUEAOS400DIRINFO *PUDFIUEAOS400DIRINFO; +/** Pointer to const UDF Mac finder info for file implementation use EA payload. */ +typedef UDFIUEAOS400DIRINFO const *PCUDFIUEAOS400DIRINFO; + + +/** + * UDF implementation use EA data (@ecma167{4,14.10.8,111}, @udf260{3.3.4.5,82}). + */ +typedef struct UDFEADATAIMPLUSE +{ + /** 0x00/0x0c: Length uData in bytes. */ + uint32_t cbData; + /** 0x04/0x10: Implementation identifier (UDF_ENTITY_ID_IUEA_XXX). */ + UDFENTITYID idImplementation; + /** 0x24/0x30: Implementation use field (variable length). */ + union + { + /** Generic byte view. */ + uint8_t abData[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + /** Free EA space (UDF_ENTITY_ID_IUEA_FREE_EA_SPACE). */ + UDFFREEEASPACE FreeEaSpace; + /** DVD copyright management information (UDF_ENTITY_ID_IUEA_DVD_CGMS_INFO). */ + UDFIUEADVDCGMSINFO DvdCgmsInfo; + /** OS/2 EA length (UDF_ENTITY_ID_IUEA_OS2_EA_LENGTH). */ + UDFIUEAOS2EALENGTH Os2EaLength; + /** Mac volume info (UDF_ENTITY_ID_IUEA_MAC_VOLUME_INFO). */ + UDFIUEAMACVOLINFO MacVolInfo; + /** Mac finder info, directory edition (UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO). */ + UDFIUEAMACFINDERINFODIR MacFinderInfoDir; + /** Mac finder info, file edition (UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO). */ + UDFIUEAMACFINDERINFOFILE MacFinderInfoFile; + /** OS/400 directory info (UDF_ENTITY_ID_IUEA_OS400_DIR_INFO). */ + UDFIUEAOS400DIRINFO Os400DirInfo; + } u; +} UDFEADATAIMPLUSE; +/** Pointer to UDF implementation use EA data. */ +typedef UDFEADATAIMPLUSE *PUDFEADATAIMPLUSE; +/** Pointer to const UDF implementation use EA data. */ +typedef UDFEADATAIMPLUSE const *PCUDFEADATAIMPLUSE; +/** UDFGEA::uAttribType value for UDFEADATAIMPLUSE. */ +#define UDFEADATAIMPLUSE_ATTRIB_TYPE UINT32_C(0x00000800) +/** UDFGEA::uAttribSubtype value for UDFEADATAIMPLUSE. */ +#define UDFEADATAIMPLUSE_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF application use EA data (@ecma167{4,14.10.9,112}, @udf260{3.3.4.6,88}). + */ +typedef struct UDFEADATAAPPUSE +{ + /** 0x0c: Length uData in bytes. */ + uint32_t cbData; + /** 0x10: Application identifier (UDF_ENTITY_ID_AUEA_FREE_EA_SPACE). */ + UDFENTITYID idApplication; + /** 0x30: Application use field (variable length). */ + union + { + /** Generic byte view. */ + uint8_t ab[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + /** Free EA space (UDF_ENTITY_ID_AUEA_FREE_EA_SPACE). */ + UDFFREEEASPACE FreeEaSpace; + } uData; +} UDFEADATAAPPUSE; +/** Pointer to UDF application use EA data. */ +typedef UDFEADATAAPPUSE *PUDFEADATAAPPUSE; +/** Pointer to const UDF application use EA data. */ +typedef UDFEADATAAPPUSE const *PCUDFEADATAAPPUSE; +/** UDFGEA::uAttribType value for UDFEADATAAPPUSE. */ +#define UDFEADATAAPPUSE_ATTRIB_TYPE UINT32_C(0x00010000) +/** UDFGEA::uAttribSubtype value for UDFEADATAAPPUSE. */ +#define UDFEADATAAPPUSE_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF generic extended attribute (@ecma167{4,14.10.2,103}). + */ +typedef struct UDFGEA +{ + /** 0x00: Attribute type (UDFXXX_ATTRIB_TYPE). */ + uint32_t uAttribType; + /** 0x04: Attribute subtype (UDFXXX_ATTRIB_SUBTYPE). */ + uint8_t uAttribSubtype; + /** 0x05: Reserved padding bytes, MBZ. */ + uint8_t abReserved[3]; + /** 0x08: Size of the whole extended attribute. + * Multiple of four is recommended. */ + uint32_t cbAttrib; + /** 0x0c: Attribute data union. */ + union + { + /** Generic byte view (variable size). */ + uint8_t abData[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + /** Character set information (@ecma167{4,14.10.3,104}). */ + UDFEADATACHARSETINFO CharSetInfo; + /** Alternate permissions (@ecma167{4,14.10.4,105}, @udf260{3.3.4.2,80}). + * @note Not recorded according to the UDF specification. */ + UDFEADATAALTPERM AltPerm; + /** File times (@ecma167{4,14.10.5,108}, @udf260{3.3.4.3,80}). + * (This is a bit reminiscent of ISO9660RRIPTF.) */ + UDFEADATAFILETIMES FileTimes; + /** Information times (@ecma167{4,14.10.6,109}). */ + UDFEADATAINFOTIMES InfoTimes; + /** Device specification (@ecma167{4,14.10.7,110}, @udf260{3.3.4.4,81}). */ + UDFEADATADEVICESPEC DeviceSpec; + /** Implementation use (@ecma167{4,14.10.8,111}, @udf260{3.3.4.5,82}). */ + UDFEADATAIMPLUSE ImplUse; + /** Application use (@ecma167{4,14.10.9,112}, @udf260{3.3.4.6,88}). */ + UDFEADATAAPPUSE AppUse; + } u; +} UDFGEA; +AssertCompileMemberOffset(UDFGEA, u, 0x0c); +/** Pointer to a UDF extended attribute. */ +typedef UDFGEA *PUDFGEA; +/** Pointer to a const UDF extended attribute. */ +typedef UDFGEA const *PCUDFGEA; + + +/** + * UDF unallocated space entry (@ecma167{4,14.11,113}, @udf260{2.3.7,64}). + * + * @note Total length shall not exceed one logical block. + */ +typedef struct UDFUNALLOCATEDSPACEENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_UNALLOCATED_SPACE_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x24: Size of the allocation desciptors in bytes. */ + uint32_t cbAllocDescs; + /** 0x28: Allocation desciptors, type given by IcbTag::fFlags. */ + union + { + UDFSHORTAD aShortADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFLONGAD aLongADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFEXTAD aExtADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFEXTENTAD SingleAD; + } u; +} UDFUNALLOCATEDSPACEENTRY; +AssertCompileMemberOffset(UDFUNALLOCATEDSPACEENTRY, u, 0x28); +/** Pointer to an UDF unallocated space entry. */ +typedef UDFUNALLOCATEDSPACEENTRY *PUDFUNALLOCATEDSPACEENTRY; +/** Pointer to a const UDF unallocated space entry. */ +typedef UDFUNALLOCATEDSPACEENTRY const *PCUDFUNALLOCATEDSPACEENTRY; + + +/** + * UDF space bitmap descriptor (SBD) (@ecma167{4,14.12,114}, @udf260{2.3.8,65}). + */ +typedef struct UDFSPACEBITMAPDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_SPACE_BITMAP_DESC). */ + UDFTAG Tag; + /** 0x10: Number of bits in the bitmap. */ + uint32_t cBits; + /** 0x14: The bitmap size in bytes. */ + uint32_t cbBitmap; + /** 0x18: The bitmap. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abBitmap[RT_FLEXIBLE_ARRAY]; +} UDFSPACEBITMAPDESC; +AssertCompileMemberOffset(UDFSPACEBITMAPDESC, abBitmap, 0x18); +/** Pointer to an UDF space bitmap descriptor. */ +typedef UDFSPACEBITMAPDESC *PUDFSPACEBITMAPDESC; +/** Pointer to a const UDF space bitmap descriptor. */ +typedef UDFSPACEBITMAPDESC const *PCUDFSPACEBITMAPDESC; + + +/** + * UDF partition integrity descriptor (@ecma167{4,14.3,115}, @udf260{2.3.9,65}). + * + * @note Not needed by UDF. + */ +typedef struct UDFPARTITIONINTEGRITYDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_PARTITION_INTEGERITY_DESC). */ + UDFTAG Tag; + /** 0x010: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x024: Recording timestamp. */ + UDFTIMESTAMP RecordingTimestamp; + /** 0x030: Interity type (UDF_PARTITION_INTEGRITY_TYPE_XXX). */ + uint8_t bType; + /** 0x031: Reserved. */ + uint8_t abReserved[175]; + /** 0x0e0: Implementation identifier. */ + UDFENTITYID idImplementation; + /** 0x100: Implementation use data. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abImplementationUse[RT_FLEXIBLE_ARRAY]; +} UDFPARTITIONINTEGRITYDESC; +AssertCompileMemberOffset(UDFPARTITIONINTEGRITYDESC, abImplementationUse, 0x100); +/** Pointer to an UDF partition integrity descriptor. */ +typedef UDFPARTITIONINTEGRITYDESC *PUDFPARTITIONINTEGRITYDESC; +/** Pointer to a const UDF partition integrity descriptor. */ +typedef UDFPARTITIONINTEGRITYDESC const *PCUDFPARTITIONINTEGRITYDESC; + + +/** + * UDF extended file entry (EFE) (@ecma167{4,14.17,120}, @udf260{3.3.5,83}). + * + * @note Total length shall not exceed one logical block. + */ +typedef struct UDFEXFILEENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_EXTENDED_FILE_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x24: User ID (UNIX). */ + uint32_t uid; + /** 0x28: Group ID (UNIX). */ + uint32_t gid; + /** 0x2c: Permission (UDF_PERM_XXX). */ + uint32_t fPermissions; + /** 0x30: Number hard links. */ + uint16_t cHardlinks; + /** 0x32: Record format (UDF_REC_FMT_XXX). */ + uint8_t uRecordFormat; + /** 0x33: Record format (UDF_REC_FMT_XXX). */ + uint8_t fRecordDisplayAttribs; + /** 0x34: Record length (in bytes). + * @note Must be zero according to the UDF specification. */ + uint32_t cbRecord; + /** 0x38: Information length in bytes (file size). */ + uint64_t cbData; + /** 0x40: The size of all streams. Same as cbData if no additional streams. */ + uint64_t cbObject; + /** 0x48: Number of logical blocks allocated (for file data). */ + uint64_t cLogicalBlocks; + /** 0x50: Time of last access (prior to recording the file entry). */ + UDFTIMESTAMP AccessTime; + /** 0x5c: Time of last data modification. */ + UDFTIMESTAMP ModificationTime; + /** 0x68: Birth (creation) time. */ + UDFTIMESTAMP BirthTime; + /** 0x74: Time of last attribute/status modification. */ + UDFTIMESTAMP ChangeTime; + /** 0x80: Checkpoint number (defaults to 1). */ + uint32_t uCheckpoint; + /** 0x84: Reserved, MBZ. */ + uint32_t uReserved; + /** 0x88: Extended attribute information control block location. */ + UDFLONGAD ExtAttribIcb; + /** 0x98: Stream directory information control block location. */ + UDFLONGAD StreamDirIcb; + /** 0xa8: Implementation identifier (UDF_ENTITY_ID_FE_IMPLEMENTATION). */ + UDFENTITYID idImplementation; + /** 0xc8: Unique ID. */ + uint64_t INodeId; + /** 0xd0: Length of extended attributes in bytes, multiple of four. */ + uint32_t cbExtAttribs; + /** 0xd4: Length of allocation descriptors in bytes, multiple of four. */ + uint32_t cbAllocDescs; + /** 0xd8: Two variable sized fields. First @a cbExtAttribs bytes of extended + * attributes, then @a cbAllocDescs bytes of allocation descriptors. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abExtAttribs[RT_FLEXIBLE_ARRAY]; +} UDFEXFILEENTRY; +AssertCompileMemberOffset(UDFEXFILEENTRY, abExtAttribs, 0xd8); +/** Pointer to an UDF extended file entry. */ +typedef UDFEXFILEENTRY *PUDFEXFILEENTRY; +/** Pointer to a const UDF extended file entry. */ +typedef UDFEXFILEENTRY const *PCUDFEXFILEENTRY; + + + +/** @name UDF Volume Recognition Sequence (VRS) + * + * The recognition sequence usually follows the CD001 descriptor sequence at + * sector 16 and is there to indicate that the medium (also) contains a UDF file + * system and which standards are involved. + * + * See @ecma167{2,8,31}, @ecma167{2,9,32}, @udf260{2.1.7,25}. + * + * @{ */ + +/** The type value used for all the extended UDF volume descriptors + * (ISO9660VOLDESCHDR::bDescType). */ +#define UDF_EXT_VOL_DESC_TYPE 0 +/** The version value used for all the extended UDF volume descriptors + * (ISO9660VOLDESCHDR::bDescVersion). */ +#define UDF_EXT_VOL_DESC_VERSION 1 + +/** Standard ID for UDFEXTVOLDESCBEGIN. */ +#define UDF_EXT_VOL_DESC_STD_ID_BEGIN "BEA01" +/** Standard ID for UDFEXTVOLDESCTERM. */ +#define UDF_EXT_VOL_DESC_STD_ID_TERM "TEA01" +/** Standard ID for UDFEXTVOLDESCNSR following ECMA-167 2nd edition. */ +#define UDF_EXT_VOL_DESC_STD_ID_NSR_02 "NSR02" +/** Standard ID for UDFEXTVOLDESCNSR following ECMA-167 3rd edition. */ +#define UDF_EXT_VOL_DESC_STD_ID_NSR_03 "NSR03" +/** Standard ID for UDFEXTVOLDESCBOOT. */ +#define UDF_EXT_VOL_DESC_STD_ID_BOOT "BOOT2" + + +/** + * Begin UDF extended volume descriptor area (@ecma167{2,9.2,33}). + */ +typedef struct UDFEXTVOLDESCBEGIN +{ + /** The volume descriptor header. + * The standard identifier is UDF_EXT_VOL_DESC_STD_ID_BEGIN. */ + ISO9660VOLDESCHDR Hdr; + /** Zero payload. */ + uint8_t abZero[2041]; +} UDFEXTVOLDESCBEGIN; +AssertCompileSize(UDFEXTVOLDESCBEGIN, 2048); +/** Pointer to an UDF extended volume descriptor indicating the start of the + * extended descriptor area. */ +typedef UDFEXTVOLDESCBEGIN *PUDFEXTVOLDESCBEGIN; +/** Pointer to a const UDF extended volume descriptor indicating the start of + * the extended descriptor area. */ +typedef UDFEXTVOLDESCBEGIN const *PCUDFEXTVOLDESCBEGIN; + + +/** + * Terminate UDF extended volume descriptor area (@ecma167{2,9.3,33}). + */ +typedef struct UDFEXTVOLDESCTERM +{ + /** The volume descriptor header. + * The standard identifier is UDF_EXT_VOL_DESC_STD_ID_TERM. */ + ISO9660VOLDESCHDR Hdr; + /** Zero payload. */ + uint8_t abZero[2041]; +} UDFEXTVOLDESCTERM; +AssertCompileSize(UDFEXTVOLDESCTERM, 2048); +/** Pointer to an UDF extended volume descriptor indicating the end of the + * extended descriptor area. */ +typedef UDFEXTVOLDESCTERM *PUDFEXTVOLDESCTERM; +/** Pointer to a const UDF extended volume descriptor indicating the end of + * the extended descriptor area. */ +typedef UDFEXTVOLDESCTERM const *PCUDFEXTVOLDESCTERM; + + +/** + * UDF NSR extended volume descriptor (@ecma167{3,9.1,50}). + * + * This gives the ECMA standard version. + */ +typedef struct UDFEXTVOLDESCNSR +{ + /** The volume descriptor header. + * The standard identifier is UDF_EXT_VOL_DESC_STD_ID_NSR_02, or + * UDF_EXT_VOL_DESC_STD_ID_NSR_03. */ + ISO9660VOLDESCHDR Hdr; + /** Zero payload. */ + uint8_t abZero[2041]; +} UDFEXTVOLDESCNSR; +AssertCompileSize(UDFEXTVOLDESCNSR, 2048); +/** Pointer to an extended volume descriptor giving the UDF standard version. */ +typedef UDFEXTVOLDESCNSR *PUDFEXTVOLDESCNSR; +/** Pointer to a const extended volume descriptor giving the UDF standard version. */ +typedef UDFEXTVOLDESCNSR const *PCUDFEXTVOLDESCNSR; + + +/** + * UDF boot extended volume descriptor (@ecma167{2,9.4,34}). + * + * @note Probably entirely unused. + */ +typedef struct UDFEXTVOLDESCBOOT +{ + /** 0x00: The volume descriptor header. + * The standard identifier is UDF_EXT_VOL_DESC_STD_ID_BOOT. */ + ISO9660VOLDESCHDR Hdr; + /** 0x07: Reserved/alignment, MBZ. */ + uint8_t bReserved1; + /** 0x08: The architecture type. */ + UDFENTITYID ArchType; + /** 0x28: The boot identifier. */ + UDFENTITYID idBoot; + /** 0x48: Logical sector number of load the boot loader from. */ + uint32_t offBootExtent; + /** 0x4c: Number of bytes to load. */ + uint32_t cbBootExtent; + /** 0x50: The load address (in memory). */ + uint64_t uLoadAddress; + /** 0x58: The start address (in memory). */ + uint64_t uStartAddress; + /** 0x60: The descriptor creation timestamp. */ + UDFTIMESTAMP CreationTimestamp; + /** 0x6c: Flags. */ + uint16_t fFlags; + /** 0x6e: Reserved, MBZ. */ + uint8_t abReserved2[32]; + /** 0x8e: Implementation use. */ + uint8_t abBootUse[1906]; +} UDFEXTVOLDESCBOOT; +AssertCompileSize(UDFEXTVOLDESCBOOT, 2048); +/** Pointer to a boot extended volume descriptor. */ +typedef UDFEXTVOLDESCBOOT *PUDFEXTVOLDESCBOOT; +/** Pointer to a const boot extended volume descriptor. */ +typedef UDFEXTVOLDESCBOOT const *PCUDFEXTVOLDESCBOOT; + +/** @} */ + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_udf_h */ + diff --git a/include/iprt/formats/wim.h b/include/iprt/formats/wim.h new file mode 100644 index 00000000..b0fb7036 --- /dev/null +++ b/include/iprt/formats/wim.h @@ -0,0 +1,160 @@ +/** @file + * IPRT - Windows Imaging (WIM) format. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_wim_h +#define IPRT_INCLUDED_formats_wim_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @defgroup grp_rt_formats_win Windows Imaging (WIM) format + * @ingroup grp_rt_formats + * + * Specification: + * http://download.microsoft.com/download/f/e/f/fefdc36e-392d-4678-9e4e-771ffa2692ab/Windows%20Imaging%20File%20Format.rtf + * + * @{ */ + + +/** + * A short WIM resource entry. + * + * This is a simplified version of the specs. + */ +typedef struct RESHDRDISKSHORT +{ + /** 0x00 - The compressed size. */ + RT_GCC_EXTENSION + uint64_t cb : 56; + /** 0x07 - Flags, RESHDR_FLAGS_XXX. */ + RT_GCC_EXTENSION + uint64_t bFlags : 8; + /** 0x08 - Offset. + * @note This is signed in the specficiation... */ + uint64_t off; + /** 0x10 - The uncompressed original size. + * @note This is signed in the specficiation... */ + uint64_t cbOriginal; +} RESHDRDISKSHORT; +AssertCompileSize(RESHDRDISKSHORT, 0x18); +/** Pointer to a short WIM resource entry. */ +typedef RESHDRDISKSHORT *PRESHDRDISKSHORT; +/** Pointer to a const short WIM resource entry. */ +typedef RESHDRDISKSHORT *PCRESHDRDISKSHORT; + +/** @name RESHDR_FLAGS_XXX + * @{ */ +#define RESHDR_FLAGS_FREE UINT8_C(0x01) +#define RESHDR_FLAGS_METADATA UINT8_C(0x02) +#define RESHDR_FLAGS_COMPRESSED UINT8_C(0x04) +#define RESHDR_FLAGS_SPANNED UINT8_C(0x08) +/** @} */ + +/** + * WIM file header, version 1. + * + * The field names have been normalized to our coding style. + */ +#pragma pack(4) +typedef struct WIMHEADERV1 +{ + /** 0x00 - Magic value WIMHEADER_MAGIC. */ + char szMagic[8]; + /** 0x08 - The size of this header structure. */ + uint32_t cbHeader; + /** 0x0c - The header version structure. */ + uint32_t uVersion; + /** 0x10 - Flags. */ + uint32_t fFlags; + /** 0x14 - ??. */ + uint32_t cbCompression; + /** 0x18 - Unique identifier. */ + RTUUID WIMGuid; + /** 0x28 - Part number in spanned (split) wim set. Unsplit use part number 1. */ + uint16_t idxPartNumber; + /** 0x2a - Total number of parts in spanned set. */ + uint16_t cTotalParts; + /** 0x2c - Number of images in the archive. */ + uint32_t cImages; + /** 0x30 - Resource lookup table offset & size. */ + RESHDRDISKSHORT OffsetTable; + /** 0x48 - XML data offset & size. */ + RESHDRDISKSHORT XmlData; + /** 0x60 - Boot metadata offset & size. */ + RESHDRDISKSHORT BootMetadata; + /** 0x78 - Bootable image index, zero if no bootable image. */ + uint32_t idxBoot; + /** 0x7c - Integrity data offset & size. + * @note Misaligned! */ + RESHDRDISKSHORT Integrity; + /** 0x94 - Reserved */ + uint8_t abUnused[60]; +} WIMHEADERV1; +#pragma pack() +AssertCompileSize(WIMHEADERV1, 0xd0); +/** Pointer to a XAR header. */ +typedef WIMHEADERV1 *PWIMHEADERV1; +/** Pointer to a const XAR header. */ +typedef WIMHEADERV1 const *PCWIMHEADERV1; + +/** The WIMHEADERV1::szMagic value. */ +#define WIMHEADER_MAGIC "MSWIM\0\0" +AssertCompile(sizeof(WIMHEADER_MAGIC) == 8); + +/** @name WIMHEADER_FLAGS_XXX - WINHEADERV1::fFlags. + * @note Specfication names these FLAG_HEADER_XXX. + * @{ */ +#define WIMHEADER_FLAGS_RESERVED RT_BIT_32(0) +#define WIMHEADER_FLAGS_COMPRESSION RT_BIT_32(1) +#define WIMHEADER_FLAGS_READONLY RT_BIT_32(2) +#define WIMHEADER_FLAGS_SPANNED RT_BIT_32(3) +#define WIMHEADER_FLAGS_RESOURCE_ONLY RT_BIT_32(4) +#define WIMHEADER_FLAGS_METADATA_ONLY RT_BIT_32(5) +#define WIMHEADER_FLAGS_WRITE_IN_PROGRESS RT_BIT_32(5) +#define WIMHEADER_FLAGS_RP_FIX RT_BIT_32(6) +#define WIMHEADER_FLAGS_COMPRESS_RESERVED RT_BIT_32(16) +#define WIMHEADER_FLAGS_COMPRESS_XPRESS RT_BIT_32(17) +#define WIMHEADER_FLAGS_COMPRESS_LZX RT_BIT_32(18) +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_wim_h */ + diff --git a/include/iprt/formats/xar.h b/include/iprt/formats/xar.h new file mode 100644 index 00000000..9b3b85c4 --- /dev/null +++ b/include/iprt/formats/xar.h @@ -0,0 +1,90 @@ +/** @file + * IPRT - Extensible Archiver (XAR) format. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_xar_h +#define IPRT_INCLUDED_formats_xar_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_xar Extensible Archive (XAR) format + * @ingroup grp_rt_formats + * + * @{ */ + +#pragma pack(4) /* Misdesigned header, not 8-byte aligned size. */ +typedef struct XARHEADER +{ + /** The magic number 'xar!' (XAR_HEADER_MAGIC). */ + uint32_t u32Magic; + /** The size of this header structure. */ + uint16_t cbHeader; + /** The header version structure. */ + uint16_t uVersion; + /** The size of the compressed table of content (TOC). */ + uint64_t cbTocCompressed; + /** The size of the table of context (TOC) when not compressed. */ + uint64_t cbTocUncompressed; + /** Which cryptographic hash function is used (XAR_HASH_XXX). */ + uint32_t uHashFunction; +} XARHEADER; +#pragma pack() +AssertCompileSize(XARHEADER, 28); +/** Pointer to a XAR header. */ +typedef XARHEADER *PXARHEADER; +/** Pointer to a const XAR header. */ +typedef XARHEADER const *PCXARHEADER; + +/** XAR magic value (on disk endian). */ +#define XAR_HEADER_MAGIC RT_H2LE_U32(RT_MAKE_U32_FROM_U8('x', 'a', 'r', '!')) +/** The current header version value (host endian). */ +#define XAR_HEADER_VERSION 1 + +/** @name XAR hashing functions. + * @{ */ +#define XAR_HASH_NONE 0 +#define XAR_HASH_SHA1 1 +#define XAR_HASH_MD5 2 +#define XAR_HASH_MAX 2 +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_xar_h */ + diff --git a/include/iprt/formats/xfs.h b/include/iprt/formats/xfs.h new file mode 100644 index 00000000..a50d6b9f --- /dev/null +++ b/include/iprt/formats/xfs.h @@ -0,0 +1,721 @@ +/* $Id: xfs.h $ */ +/** @file + * IPRT, XFS format. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_xfs_h +#define IPRT_INCLUDED_formats_xfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_rt_formats_xfs XFS filesystem structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/* + * The filesystem structures were retrieved from: + * http://xfs.org/docs/xfsdocs-xml-dev/XFS_Filesystem_Structure//tmp/en-US/html/index.html and + * https://elixir.bootlin.com/linux/v4.9/source/fs/xfs/libxfs/xfs_format.h and + * https://righteousit.wordpress.com/ + */ + +/** XFS superblock offset from the beginning of the volume, this is constant. */ +#define XFS_SB_OFFSET UINT64_C(0) + +/** @name Common XFS types as defined in the spec. + * @{ */ +/** Unsigned 64 bit absolute inode number. */ +typedef uint64_t XFSINO; +/** Signed 64 bit file offset. */ +typedef int64_t XFSFOFF; +/** Signed 64 bit disk address. */ +typedef int64_t XFSDADDR; +/** Unsinged 32 bit allocation group (AG) number. */ +typedef uint32_t XFSAGNUMBER; +/** Unsigned 32 bit AG relative block number. */ +typedef uint32_t XFSAGBLOCK; +/** Unsigned 32 bit extent length in blocks. */ +typedef uint32_t XFSEXTLEN; +/** Signed 32 bit number of extents in a file. */ +typedef int32_t XFSEXTNUM; +/** Unsigned 32 bit block number for directories and extended attributes. */ +typedef uint32_t XFSDABLK; +/** Unsigned 32 bit hash of a directory file name or extended attribute name. */ +typedef uint32_t XFSDAHASH; +/** Unsigned 64 bit filesystem block number combining AG number and block offset into the AG. */ +typedef uint64_t XFSDFSBNO; +/** Unsigned 64 bit raw filesystem block number. */ +typedef uint64_t XFSDRFSBNO; +/** Unsigned 64 bit extent number in the real-time device. */ +typedef uint64_t XFSDRTBNO; +/** Unsigned 64 bit block offset int oa file. */ +typedef uint64_t XFSDFILOFF; +/** Unsigned 64 bit block count for a file. */ +typedef uint64_t XFSDFILBLKS; +/** @} */ + +/** + * XFS superblock. + */ +#pragma pack(1) +typedef struct XFSSUPERBLOCK +{ + /** 0x00: Magic number to identify the superblock. */ + uint32_t u32Magic; + /** 0x04: Size of smallest allocation unit in bytes. */ + uint32_t cbBlock; + /** 0x04: Number of blocks available for data and metadata. */ + XFSDRFSBNO cBlocks; + /** 0x0c: Number of block in the real-time device. */ + XFSDRFSBNO cBlocksRtDev; + /** 0x14: Number of extents on real-time device. */ + XFSDRTBNO cExtentsRtDev; + /** 0x1c: UUID of the filesystem. */ + uint8_t abUuid[16]; + /** 0x2c: First block of the filesystem journal. */ + XFSDFSBNO uBlockJournal; + /** 0x34: Inode number of the root directory. */ + XFSINO uInodeRoot; + /** Inode for the real-time extent bitmap. */ + XFSINO uInodeBitmapRtExt; + /** Inode for the real-time bitmap summary. */ + XFSINO uInodeBitmapSummary; + /** Extent size on the real-time device in blocks. */ + XFSAGBLOCK cRtExtent; + /** Size of an AG in blocks. */ + XFSAGBLOCK cAgBlocks; + /** Number of AGs in hte filesystem. */ + XFSAGNUMBER cAg; + /** Number of real-time bitmap blocks. */ + XFSEXTLEN cRtBitmapBlocks; + /** Number of blocks for the journal. */ + XFSEXTLEN cJournalBlocks; + /** Version number (actually flag bitmaps of features). */ + uint16_t fVersion; + /** Sector size of the underlying medium. */ + uint16_t cbSector; + /** Size of an inode in bytes. */ + uint16_t cbInode; + /** Number of inodes stored in one block. */ + uint16_t cInodesPerBlock; + /** Name of the filesystem. */ + char achFsName[12]; + /** Block size as log2 (number of bits to shift left). */ + uint8_t cBlockSzLog; + /** Sector size as log2 (number of bits to shift left). */ + uint8_t cSectorSzLog; + /** Inode size as log2 (number of bits to shift left). */ + uint8_t cInodeSzLog; + /** Number of inodes per block as log2. */ + uint8_t cInodesPerBlockLog; + /** Number of AG blocks as log2 (number of bits to shift left). */ + uint8_t cAgBlocksLog; + /** Number of extent blocks as log2. */ + uint8_t cExtentsRtDevLog; + /** Flag when the filesystem is in the process of being created. */ + uint8_t fInProgress; + /** Maximum percentage of the filesystem usable for inodes. */ + uint8_t cInodeMaxPct; + /** Global number of inodes allocated (only mainted on the first superblock). */ + uint64_t cInodesGlobal; + /** Global number of free inodes (only mainted on the first superblock). */ + uint64_t cInodesGlobalFree; + /** Global count of free data blocks on the filesystem (only mainted on the first superblock). */ + uint64_t cBlocksFree; + /** Global count of free extents on the real-time device (only mainted on the first superblock). */ + uint64_t cExtentsRtFree; + /** Inode containing the user quotas. */ + XFSINO uInodeQuotaUsr; + /** Inode containing the group/project quotas. */ + XFSINO uInodeQuotaGrp; + /** Quota flags. */ + uint16_t fQuotaFlags; + /** Misc flags. */ + uint8_t fFlagsMisc; + /** Reserved MBZ. */ + uint8_t uSharedVn; + /** Number of filesystem blocks for the inode chunk alignment. */ + XFSEXTLEN cBlocksInodeAlignment; + /** Raid stripe size in blocks. */ + uint32_t cBlocksRaidStripe; + /** Raid width in number of blocks. */ + uint32_t cBlocksRaidWidth; + /** Multiplier for determining the allocation size for directory blocks as log2. */ + uint8_t cDirBlockAllocLog; + /** Sub volume sector size as log2 if an external journal device is used. */ + uint8_t cLogDevSubVolSectorSzLog; + /** Sector size of the device an external journal is stored as log2. */ + uint16_t cLogDevSectorSzLog; + /** Log devices stripe size. */ + uint32_t cLogDevRaidStripe; + /** Additional features which may be active. */ + uint32_t fFeatures2; + /** Padding. */ + uint32_t u32Padding0; + /** From here follow data only available from version 5 and later. */ + /** Read/Write feature flags. */ + uint32_t fFeaturesRw; + /** Read-only feature flags. */ + uint32_t fFeaturesRo; + /** Read/Write incompatible feature flags. */ + uint32_t fFeaturesIncompatRw; + /** Read/Write incompatible feature flags for the journal. */ + uint32_t fFeaturesJrnlIncompatRw; + /** CRC32 checksum for the superblock. */ + uint32_t u32Chksum; + /** Sparse inode alignment. */ + uint32_t u32SparseInodeAlignment; + /** Project quota inode. */ + XFSINO uInodeProjectQuota; + /** Log sequence number of last superblock update. */ + uint64_t uJrnlSeqSbUpdate; + /** UUID used when INCOMPAT_META_UUID is used. */ + uint8_t abUuidMeta[16]; + /** Inode if INCOMPATMETA_RMAPBT is used. */ + XFSINO uInodeRm; +} XFSSUPERBLOCK; +#pragma pack() +AssertCompileSize(XFSSUPERBLOCK, 272); +/** Pointer to an XFS superblock. */ +typedef XFSSUPERBLOCK *PXFSSUPERBLOCK; +/** Pointer to a const XFS superblock. */ +typedef const XFSSUPERBLOCK *PCXFSSUPERBLOCK; + +/** XFS superblock magic. */ +#define XFS_SB_MAGIC RT_MAKE_U32_FROM_U8('B', 'S', 'F', 'X') + +/** @name XFS_SB_VERSION_F_XXX - Version/Feature flags. + * @{ */ +/** Retrieves the version part of the field. */ +#define XFS_SB_VERSION_GET(a_fVersion) ((a_fVersion) & 0xf) +/** Version number for filesystem 5.3, 6.0.1 and 6.1. */ +#define XFS_SB_VERSION_1 1 +/** Version number for filesystem 6.2 - attributes. */ +#define XFS_SB_VERSION_2 2 +/** Version number for filesystem 6.2 - new inode version. */ +#define XFS_SB_VERSION_3 3 +/** Version number for filesystem 6.2+ - new bitmask version. */ +#define XFS_SB_VERSION_4 4 +/** Introduced checksums in the metadata. */ +#define XFS_SB_VERSION_5 5 +/** Extended attributes are used for at least one inode. */ +#define XFS_SB_VERSION_F_ATTR RT_BIT_32(4) +/** At least one inode use 32-bit nlink values. */ +#define XFS_SB_VERSION_F_NLINK RT_BIT_32(5) +/** Quotas are enabled on the filesystem. */ +#define XFS_SB_VERSION_F_QUOTA RT_BIT_32(6) +/** Set if XFSSUPERBLOCK::cBlocksInodeAlignment is used. */ +#define XFS_SB_VERSION_F_ALIGN RT_BIT_32(7) +/** Set if XFSSUPERBLOCK::cBlocksRaidStripe and XFSSUPERBLOCK::cBlocksRaidWidth are used. */ +#define XFS_SB_VERSION_F_DALIGN RT_BIT_32(8) +/** Set if XFSSUPERBLOCK::uSharedVn is used. */ +#define XFS_SB_VERSION_F_SHARED RT_BIT_32(9) +/** Version 2 journaling is used. */ +#define XFS_SB_VERSION_F_LOGV2 RT_BIT_32(10) +/** Set if sector size is not 512 bytes. */ +#define XFS_SB_VERSION_F_SECTOR RT_BIT_32(11) +/** Set if unwritten extents are used (always set). */ +#define XFS_SB_VERSION_F_EXTFLG RT_BIT_32(12) +/** Version 2 directories are used (always set). */ +#define XFS_SB_VERSION_F_DIRV2 RT_BIT_32(13) +/** Set if XFSSUPERBLOCK::fFeatures2 is used. */ +#define XFS_SB_VERSION_F_FEAT2 RT_BIT_32(14) +/** @} */ + +/** @name XFS_SB_QUOTA_F_XXX - Quota flags + * @{ */ +/** User quota accounting enabled. */ +#define XFS_SB_QUOTA_F_USR_ACCT RT_BIT(0) +/** User quotas are enforced. */ +#define XFS_SB_QUOTA_F_USR_ENFD RT_BIT(1) +/** User quotas have been checked and updated on disk. */ +#define XFS_SB_QUOTA_F_USR_CHKD RT_BIT(2) +/** Project quota accounting is enabled. */ +#define XFS_SB_QUOTA_F_PROJ_ACCT RT_BIT(3) +/** Other quotas are enforced. */ +#define XFS_SB_QUOTA_F_OTH_ENFD RT_BIT(4) +/** Other quotas have been checked and updated on disk. */ +#define XFS_SB_QUOTA_F_OTH_CHKD RT_BIT(5) +/** Group quota accounting enabled. */ +#define XFS_SB_QUOTA_F_GRP_ACCT RT_BIT(6) +/** @} */ + +/** @name XFS_SB_FEATURES2_F_XXX - Additional features + * @{ */ +/** Global counters are lazy and are only updated when the filesystem is cleanly unmounted. */ +#define XFS_SB_FEATURES2_F_LAZYSBCOUNT RT_BIT_32(1) +/** Extended attributes version 2. */ +#define XFS_SB_FEATURES2_F_ATTR2 RT_BIT_32(3) +/** Parent pointers, inodes must have an extended attribute pointing to the parent inode. */ +#define XFS_SB_FEATURES2_F_PARENT RT_BIT_32(4) +/** @} */ + + +/** + * XFS AG free space block. + */ +typedef struct XFSAGF +{ + /** Magic number. */ + uint32_t u32Magic; + /** Header version number. */ + uint32_t uVersion; + /** AG number for the sector. */ + uint32_t uSeqNo; + /** Length of the AG in filesystem blocks. */ + uint32_t cLengthBlocks; + /** Block numbers for the roots of the free space B+trees. */ + uint32_t auRoots[3]; + /** Depths of the free space B+trees. */ + uint32_t acLvls[3]; + /** Index of the first free list block. */ + uint32_t idxFreeListFirst; + /** Index of the last free list block. */ + uint32_t idxFreeListLast; + /** Number of blocks in the free list. */ + uint32_t cFreeListBlocks; + /** Current number of free blocks in the AG. */ + uint32_t cFreeBlocks; + /** Longest number of contiguous free blocks in the AG. */ + uint32_t cFreeBlocksLongest; + /** Number of blocks used for the free space B+-trees. */ + uint32_t cBlocksBTrees; + /** UUID of filesystem the AG belongs to. */ + uint8_t abUuid[16]; + /** Number of blocks used for the reverse map. */ + uint32_t cBlocksRevMap; + /** Number of blocks used for the refcount B+-tree. */ + uint32_t cBlocksRefcountBTree; + /** Block number for the refcount tree root. */ + uint32_t uRootRefcount; + /** Depth of the refcount B+-tree. */ + uint32_t cLvlRefcount; + /** Reserved contiguous space for future extensions. */ + uint64_t au64Rsvd[14]; + /** Last write sequence number. */ + uint64_t uSeqNoLastWrite; + /** CRC of the AGF. */ + uint32_t uChkSum; + /** Padding to 64 bit alignment. */ + uint32_t uAlignment0; +} XFSAGF; +/** Pointer to a AG free space block. */ +typedef XFSAGF *PXFSAGF; +/** Poiner to a const AG free space block. */ +typedef const XFSAGF *PCXFSAGF; + +/** AGF magic. */ +#define XFS_AGF_MAGIC RT_MAKE_U32_FROM_U8('F', 'G', 'A', 'X') +/** The current valid AGF version. */ +#define XFS_AGF_VERSION 1 + + +/** + * XFS AG inode information. + */ +typedef struct XFSAGI +{ + /** Magic number. */ + uint32_t u32Magic; + /** Header version number. */ + uint32_t uVersion; + /** AG number for the sector. */ + uint32_t uSeqNo; + /** Length of the AG in filesystem blocks. */ + uint32_t cLengthBlocks; + /** Count of allocated inodes. */ + uint32_t cInodesAlloc; + /** Block number of the inode tree root. */ + uint32_t uRootInode; + /** Depth of the inode B+-tree. */ + uint32_t cLvlsInode; + /** Newest allocated inode. */ + uint32_t uInodeNew; + /** Last directory inode chunk. */ + uint32_t uInodeDir; + /** Hash table of unlinked but still referenced inodes. */ + uint32_t au32HashUnlinked[64]; + /** UUID of filesystem. */ + uint8_t abUuid[16]; + /** CRC of the AGI. */ + uint32_t uChkSum; + /** Padding. */ + uint32_t uAlignment0; + /** Last write sequence number. */ + uint64_t uSeqNoLastWrite; + /** Block number of the free inode tree. */ + uint32_t uRootFreeInode; + /** Depth of the free inode B+-tree. */ + uint32_t cLvlsFreeInode; +} XFSAGI; +/** Pointer to a AG inode information. */ +typedef XFSAGI *PXFSAGI; +/** Pointer to a const AG inode information. */ +typedef const XFSAGI *PCXFSAGI; + +/** AGI magic. */ +#define XFS_AGI_MAGIC RT_MAKE_U32_FROM_U8('I', 'G', 'A', 'X') +/** The current valid AGI version. */ +#define XFS_AGI_VERSION 1 + + +/** + * XFS timestamp structure. + */ +typedef struct XFSTIMESTAMP +{ + /** 0x00: The second part of the timestamp since the epoch. */ + int32_t cSecEpoch; + /** 0x04: Nanosecond part of the timestamp. */ + int32_t cNanoSec; +} XFSTIMESTAMP; +/** Pointer to a XFS timestamp. */ +typedef XFSTIMESTAMP *PXFSTIMESTAMP; +/** Poiner to a const CFS timestamp. */ +typedef const XFSTIMESTAMP *PCXFSTIMESTAMP; + + +/** + * The inode core structure. + */ +typedef struct XFSINODECORE +{ + /** 0x00: Magic value. */ + uint16_t u16Magic; + /** 0x02: File mode and access bits (XFS_INODE_MODE_XXX). */ + uint16_t fMode; + /** 0x04: Inode version. */ + int8_t iVersion; + /** 0x05: The format of the data fork. */ + int8_t enmFormat; + /** 0x06: Number of links to this inode from directories for v1 inodes. */ + uint16_t cOnLinks; + /** 0x08: Owners UID. */ + uint32_t uUid; + /** 0x0c: Owners GID. */ + uint32_t uGid; + /** 0x10: The number of links to this inode for v2 inodes. */ + uint32_t cLinks; + /** 0x14: Project ID for v2 inodes (not used for v1, low 16bits). */ + uint16_t uProjIdLow; + /** 0x16: Project ID for v2 inodes (not used for v1, high 16bits). */ + uint16_t uProjIdHigh; + /** 0x18: Padding. */ + uint8_t abPad0[6]; + /** 0x1e: Flush counter. */ + uint16_t cFlush; + /** 0x20: Last accessed timestamp. */ + XFSTIMESTAMP TsLastAccessed; + /** 0x28: Last modified timestamp. */ + XFSTIMESTAMP TsLastModified; + /** 0x30: Inode created/modified timestamp. */ + XFSTIMESTAMP TsCreatedModified; + /** 0x38: Number of bytes in the file. */ + uint64_t cbInode; + /** 0x40: Number of direct and B-Tree blocks used for the forks. */ + uint64_t cBlocks; + /** 0x48: Minimum extent size for the inode. */ + uint32_t cExtentBlocksMin; + /** 0x4c: Number of extents in the data fork. */ + uint32_t cExtentsData; + /** 0x50: Number of extents in the attribute fork. */ + uint16_t cExtentsAttr; + /** 0x52: Offset of the attribute fork from the start of the inode. */ + uint8_t offAttrFork; + /** 0x53: Attribute fork format. */ + int8_t enmFormatAttr; + /** 0x54: DMIG event mask. */ + uint32_t fEvtMaskDmig; + /** 0x58: DMIG state info. */ + uint16_t uStateDmig; + /** 0x5a: Inode flags. */ + uint16_t fFlags; + /** 0x5c: Generation number. */ + uint32_t cGeneration; + /** 0x60: AGI unlinked list pointer. */ + uint32_t offBlockUnlinkedNext; + /** The following fields are for v3 inodes only. */ + /** 0x64: The CRC of the inode. */ + uint32_t uChkSum; + /** 0x68: Number of attribute changes. */ + uint64_t cAttrChanges; + /** 0x70: Last flush sequence number. */ + uint64_t uFlushSeqNo; + /** 0x78: Additional flags. */ + uint64_t fFlags2; + /** 0x80: Basic COW extent size. */ + uint32_t cExtentCowMin; + /** 0x84: Padding for future expansion. */ + uint8_t abPad1[12]; + /** 0x90: Inode creation timestamp. */ + XFSTIMESTAMP TsCreation; + /** 0x98: The inode number. */ + uint64_t uInode; + /** 0x100: Filesystem UUID the inode belongs to. */ + uint8_t abUuid[16]; +} XFSINODECORE; +AssertCompileSizeAlignment(XFSINODECORE, 8); +/** Pointer to a inode core. */ +typedef XFSINODECORE *PXFSINODECORE; +/** Pointer to a const inode core. */ +typedef const XFSINODECORE *PCXFSINODECORE; + +/** Inode magic. */ +#define XFS_INODE_MAGIC RT_MAKE_U16_FROM_U8('N', 'I') + +/** @name XFS_INODE_MODE_XXX - File mode + * @{ */ +/** Others can execute the file. */ +#define XFS_INODE_MODE_EXEC_OTHER RT_BIT(0) +/** Others can write to the file. */ +#define XFS_INODE_MODE_WRITE_OTHER RT_BIT(1) +/** Others can read the file. */ +#define XFS_INODE_MODE_READ_OTHER RT_BIT(2) +/** Members of the same group can execute the file. */ +#define XFS_INODE_MODE_EXEC_GROUP RT_BIT(3) +/** Members of the same group can write to the file. */ +#define XFS_INODE_MODE_WRITE_GROUP RT_BIT(4) +/** Members of the same group can read the file. */ +#define XFS_INODE_MODE_READ_GROUP RT_BIT(5) +/** Owner can execute the file. */ +#define XFS_INODE_MODE_EXEC_OWNER RT_BIT(6) +/** Owner can write to the file. */ +#define XFS_INODE_MODE_WRITE_OWNER RT_BIT(7) +/** Owner can read the file. */ +#define XFS_INODE_MODE_READ_OWNER RT_BIT(8) +/** Sticky file mode. */ +#define XFS_INODE_MODE_STICKY RT_BIT(9) +/** File is set GID. */ +#define XFS_INODE_MODE_SET_GROUP_ID RT_BIT(10) +/** File is set UID. */ +#define XFS_INODE_MODE_SET_USER_ID RT_BIT(11) +/** @} */ + +/** @name XFS_INODE_MODE_TYPE_XXX - File type + * @{ */ +/** Inode represents a FIFO. */ +#define XFS_INODE_MODE_TYPE_FIFO UINT16_C(0x1000) +/** Inode represents a character device. */ +#define XFS_INODE_MODE_TYPE_CHAR UINT16_C(0x2000) +/** Inode represents a directory. */ +#define XFS_INODE_MODE_TYPE_DIR UINT16_C(0x4000) +/** Inode represents a block device. */ +#define XFS_INODE_MODE_TYPE_BLOCK UINT16_C(0x6000) +/** Inode represents a regular file. */ +#define XFS_INODE_MODE_TYPE_REGULAR UINT16_C(0x8000) +/** Inode represents a symlink. */ +#define XFS_INODE_MODE_TYPE_SYMLINK UINT16_C(0xa000) +/** Inode represents a socket. */ +#define XFS_INODE_MODE_TYPE_SOCKET UINT16_C(0xc000) +/** Returns the inode type from the combined mode field. */ +#define XFS_INODE_MODE_TYPE_GET_TYPE(a_Mode) ((a_Mode) & 0xf000) +/** @} */ + +/** @name XFS_INODE_FORMAT_XXX - Inode data fork format. + * @{ */ +/** Device node data. */ +#define XFS_INODE_FORMAT_DEV 0 +/** Inline data. */ +#define XFS_INODE_FORMAT_LOCAL 1 +/** Array of extent descriptors. */ +#define XFS_INODE_FORMAT_EXTENTS 2 +/** Data fork contains root of B-Tree. */ +#define XFS_INODE_FORMAT_BTREE 3 +/** Data fork contains UUID. */ +#define XFS_INODE_FORMAT_UUID 4 +/** @} */ + +/** @name XFS_INODE_F_XXX - Inode flags. + * @{ */ +/** File data blocks are stored in the real-time device area. */ +#define XFS_INODE_F_RTDEV RT_BIT(0) +/** File space has been pre-allocated. */ +#define XFS_INODE_F_PREALLOC RT_BIT(1) +/** Use new real-time bitmap format. */ +#define XFS_INODE_F_NEWRTBITMAP RT_BIT(2) +/** Inode is immutable. */ +#define XFS_INODE_F_IMMUTABLE RT_BIT(3) +/** Inode is append only. */ +#define XFS_INODE_F_APPEND RT_BIT(4) +/** Inode is written synchronously. */ +#define XFS_INODE_F_SYNC RT_BIT(5) +/** The last accessed timestamp is not updated. */ +#define XFS_INODE_F_NOATIME RT_BIT(6) +/** The inode is not dumpable via dump(1). */ +#define XFS_INODE_F_NODUMP RT_BIT(7) +/** Create with real-time bit set. */ +#define XFS_INODE_F_RTINHERIT RT_BIT(8) +/** Create with parents project ID. */ +#define XFS_INODE_F_PROJIDINHERIT RT_BIT(9) +/** Deny symlink creation. */ +#define XFS_INODE_F_NOSYMLINKS RT_BIT(10) +/** Inode extent size allocator hint. */ +#define XFS_INODE_F_EXTSIZEHINT RT_BIT(11) +/** Inode extent size is inherited. */ +#define XFS_INODE_F_EXTSIZEINHERIT RT_BIT(12) +/** Do not defrag/reorganize the inode. */ +#define XFS_INODE_F_NODEFRAG RT_BIT(13) +/** Use filestream allocator. */ +#define XFS_INODE_F_FILESTREAM RT_BIT(14) +/** @} */ + +/** @name XFS_INODE_F2_XXX - Inode flags number 2 (XFSINODECORE::fFlags2). + * @{ */ +/** Use DAX for the inode. */ +#define XFS_INODE_F2_DAX RT_BIT_64(0) +/** Blocks use reference counting for sharing. */ +#define XFS_INODE_F2_REFLINK RT_BIT_64(1) +/** Inode COW extent size hint is valid. */ +#define XFS_INODE_F2_COWEXTSIZEHINT RT_BIT_64(2) +/** @} */ + + +/** + * Inode B-Tree record. + */ +typedef struct XFSINODEBTREEREC +{ + /** 0x00: Starting inode number. */ + uint32_t uInodeStart; + /** 0x04: Version dependent data. */ + union + { + /** Full (old) version. */ + struct + { + /** 0x04: Number of free inodes. */ + uint32_t cInodesFree; + } Full; + /** Sparse (new) version. */ + struct + { + /** 0x04: Hole mask for sparse chunks. */ + uint16_t bmHoles; + /** 0x06: Total number of inodes. */ + uint8_t cInodes; + /** 0x07: Number of free inodes. */ + uint8_t cInodesFree; + } Sparse; + } u; + /** 0x08: Free inode mask. */ + uint64_t bmInodesFree; +} XFSINODEBTREEREC; +/** Pointer to an inode B-Tree record. */ +typedef XFSINODEBTREEREC *PXFSINODEBTREEREC; +/** Pointer to a const inode B-Tree record. */ +typedef const XFSINODEBTREEREC *PCXFSINODEBTREEREC; + + +/** + * XFS B+Tree root header. + */ +typedef struct XFSBTREEROOTHDR +{ + /** 0x00: Tree level. */ + uint16_t iLvl; + /** 0x02: Number of records. */ + uint16_t cRecs; +} XFSBTREEROOTHDR; +/** Pointer to a B+Tree root header */ +typedef XFSBTREEROOTHDR *PXFSBTREEROOTHDR; +/** Pointer to a const B+Tree root header. */ +typedef const XFSBTREEROOTHDR *PCXFSBTREEROOTHDR; + + +/** + * XFS B+Tree intermediate/leave node header. + */ +typedef struct XFSBTREENODEHDR +{ + /** 0x00: Magic identifying the node. */ + uint32_t u32Magic; + /** 0x04: Tree level. */ + uint16_t iLvl; + /** 0x06: Number of records. */ + uint16_t cRecs; + /** 0x08: Block number of the left sibling. */ + uint64_t uSibLeft; + /** 0x10: Block number of the right sibling. */ + uint64_t uSibRight; +} XFSBTREENODEHDR; +/** Pointer to a B+Tree intermediate/leave node header. */ +typedef XFSBTREENODEHDR *PXFSBTREENODEHDR; +/** Pointer to a const B+Tree intermediate/leave node header. */ +typedef const XFSBTREENODEHDR *PCXFSBTREENODEHDR; + +/** @name XFS_BTREENODEHDR_XXX - B+Tree node related defines. + * @{ */ +/** Magic for the tree node header. */ +#define XFS_BTREENODEHDR_MAGIC RT_MAKE_U32_FROM_U8('P', 'A', 'M', 'B') +/** @} */ + + +/** + * XFS Extent. + */ +typedef struct XFSEXTENT +{ + /** 0x00: Low 64 bits. */ + uint64_t u64Low; + /** 0x08: High 64 bits. */ + uint64_t u64High; +} XFSEXTENT; +/** Pointer to an XFS extent. */ +typedef XFSEXTENT *PXFSEXTENT; +/** Pointer to a const XFS extent. */ +typedef const XFSEXTENT *PCXFSEXTENT; + +/** @name XFS_EXTENT_XXX - Extent related getters. + * @{ */ +/** Returns whether the extent is allocated but unwritten (true) or a normal extent (false). */ +#define XFS_EXTENT_IS_UNWRITTEN(a_pExtent) (RT_BOOL((a_pExtent)->u64High & RT_BIT_64(63))) +/** Returns the number of blocks the extent covers. */ +#define XFS_EXTENT_GET_BLOCK_COUNT(a_pExtent) ((a_pExtent)->u64Low & UINT64_C(0x1fffff)) +/** Returns the absolute block number where the data is stored on the disk. */ +#define XFS_EXTENT_GET_DISK_BLOCK(a_pExtent) ( (((a_pExtent)->u64High & UINT64_C(0x1ff)) << 42) \ + | (((a_pExtent)->u64Low & UINT64_C(0xffffffffffe00000)) >> 21)) +/** Returns the logical inode block offset. */ +#define XFS_EXTENT_GET_LOGICAL_BLOCK(a_pExtent) (((a_pExtent)->u64High & UINT64_C(0x7ffffffffffffe00)) >> 9) +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_xfs_h */ + diff --git a/include/iprt/fs.h b/include/iprt/fs.h new file mode 100644 index 00000000..03c4f370 --- /dev/null +++ b/include/iprt/fs.h @@ -0,0 +1,668 @@ +/** @file + * IPRT - Filesystem. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_fs_h +#define IPRT_INCLUDED_fs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fs RTFs - Filesystem and Volume + * @ingroup grp_rt + * @{ + */ + + +/** @name Filesystem Object Mode Flags. + * + * There are two sets of flags: the unix mode flags and the dos attributes. + * + * APIs returning mode flags will provide both sets. + * + * When specifying mode flags to any API at least one of them must be given. If + * one set is missing the API will synthesize it from the one given if it + * requires it. + * + * Both sets match their x86 ABIs, the DOS/NT one is simply shifted up 16 bits. + * The DOS/NT range is bits 16 to 31 inclusively. The Unix range is bits 0 to 15 + * (inclusively). + * + * @remarks These constants have been comitted to a binary format and must not + * be changed in any incompatible ways. + * + * @{ + */ + +/** Set user id on execution (S_ISUID). */ +#define RTFS_UNIX_ISUID 0004000U +/** Set group id on execution (S_ISGID). */ +#define RTFS_UNIX_ISGID 0002000U +/** Sticky bit (S_ISVTX / S_ISTXT). */ +#define RTFS_UNIX_ISTXT 0001000U + +/** Owner RWX mask (S_IRWXU). */ +#define RTFS_UNIX_IRWXU 0000700U +/** Owner readable (S_IRUSR). */ +#define RTFS_UNIX_IRUSR 0000400U +/** Owner writable (S_IWUSR). */ +#define RTFS_UNIX_IWUSR 0000200U +/** Owner executable (S_IXUSR). */ +#define RTFS_UNIX_IXUSR 0000100U + +/** Group RWX mask (S_IRWXG). */ +#define RTFS_UNIX_IRWXG 0000070U +/** Group readable (S_IRGRP). */ +#define RTFS_UNIX_IRGRP 0000040U +/** Group writable (S_IWGRP). */ +#define RTFS_UNIX_IWGRP 0000020U +/** Group executable (S_IXGRP). */ +#define RTFS_UNIX_IXGRP 0000010U + +/** Other RWX mask (S_IRWXO). */ +#define RTFS_UNIX_IRWXO 0000007U +/** Other readable (S_IROTH). */ +#define RTFS_UNIX_IROTH 0000004U +/** Other writable (S_IWOTH). */ +#define RTFS_UNIX_IWOTH 0000002U +/** Other executable (S_IXOTH). */ +#define RTFS_UNIX_IXOTH 0000001U + +/** All UNIX access permission bits (0777). */ +#define RTFS_UNIX_ALL_ACCESS_PERMS 0000777U +/** All UNIX permission bits, including set id and sticky bits. */ +#define RTFS_UNIX_ALL_PERMS 0007777U + +/** Named pipe (fifo) (S_IFIFO). */ +#define RTFS_TYPE_FIFO 0010000U +/** Character device (S_IFCHR). */ +#define RTFS_TYPE_DEV_CHAR 0020000U +/** Directory (S_IFDIR). */ +#define RTFS_TYPE_DIRECTORY 0040000U +/** Block device (S_IFBLK). */ +#define RTFS_TYPE_DEV_BLOCK 0060000U +/** Regular file (S_IFREG). */ +#define RTFS_TYPE_FILE 0100000U +/** Symbolic link (S_IFLNK). */ +#define RTFS_TYPE_SYMLINK 0120000U +/** Socket (S_IFSOCK). */ +#define RTFS_TYPE_SOCKET 0140000U +/** Whiteout (S_IFWHT). */ +#define RTFS_TYPE_WHITEOUT 0160000U +/** Type mask (S_IFMT). */ +#define RTFS_TYPE_MASK 0170000U +/** The shift count to convert between RTFS_TYPE_MASK and DIRENTRYTYPE. */ +#define RTFS_TYPE_DIRENTRYTYPE_SHIFT 12 + +/** Unix attribute mask. */ +#define RTFS_UNIX_MASK 0xffffU +/** The mask of all the NT, OS/2 and DOS attributes. */ +#define RTFS_DOS_MASK (0x7fffU << RTFS_DOS_SHIFT) + +/** The shift value. */ +#define RTFS_DOS_SHIFT 16 +/** The mask of the OS/2 and DOS attributes. */ +#define RTFS_DOS_MASK_OS2 (0x003fU << RTFS_DOS_SHIFT) +/** The mask of the NT attributes. */ +#define RTFS_DOS_MASK_NT (0x7fffU << RTFS_DOS_SHIFT) + +/** Readonly object. */ +#define RTFS_DOS_READONLY (0x0001U << RTFS_DOS_SHIFT) +/** Hidden object. */ +#define RTFS_DOS_HIDDEN (0x0002U << RTFS_DOS_SHIFT) +/** System object. */ +#define RTFS_DOS_SYSTEM (0x0004U << RTFS_DOS_SHIFT) +/** Directory. */ +#define RTFS_DOS_DIRECTORY (0x0010U << RTFS_DOS_SHIFT) +/** Archived object. + * This bit is set by the filesystem after each modification of a file. */ +#define RTFS_DOS_ARCHIVED (0x0020U << RTFS_DOS_SHIFT) +/** Undocumented / Reserved, used to be the FAT volume label. */ +#define RTFS_DOS_NT_DEVICE (0x0040U << RTFS_DOS_SHIFT) +/** Normal object, no other attribute set (NT). */ +#define RTFS_DOS_NT_NORMAL (0x0080U << RTFS_DOS_SHIFT) +/** Temporary object (NT). */ +#define RTFS_DOS_NT_TEMPORARY (0x0100U << RTFS_DOS_SHIFT) +/** Sparse file (NT). */ +#define RTFS_DOS_NT_SPARSE_FILE (0x0200U << RTFS_DOS_SHIFT) +/** Reparse point (NT). */ +#define RTFS_DOS_NT_REPARSE_POINT (0x0400U << RTFS_DOS_SHIFT) +/** Compressed object (NT). + * For a directory, compression is the default for new files. */ +#define RTFS_DOS_NT_COMPRESSED (0x0800U << RTFS_DOS_SHIFT) +/** Physically offline data (NT). + * MSDN say, don't mess with this one. */ +#define RTFS_DOS_NT_OFFLINE (0x1000U << RTFS_DOS_SHIFT) +/** Not content indexed by the content indexing service (NT). */ +#define RTFS_DOS_NT_NOT_CONTENT_INDEXED (0x2000U << RTFS_DOS_SHIFT) +/** Encryped object (NT). + * For a directory, encrypted is the default for new files. */ +#define RTFS_DOS_NT_ENCRYPTED (0x4000U << RTFS_DOS_SHIFT) + +/** @} */ + + +/** @name Filesystem Object Type Predicates. + * @{ */ +/** Checks the mode flags indicate a named pipe (fifo) (S_ISFIFO). */ +#define RTFS_IS_FIFO(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_FIFO ) +/** Checks the mode flags indicate a character device (S_ISCHR). */ +#define RTFS_IS_DEV_CHAR(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_DEV_CHAR ) +/** Checks the mode flags indicate a directory (S_ISDIR). */ +#define RTFS_IS_DIRECTORY(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_DIRECTORY ) +/** Checks the mode flags indicate a block device (S_ISBLK). */ +#define RTFS_IS_DEV_BLOCK(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_DEV_BLOCK ) +/** Checks the mode flags indicate a regular file (S_ISREG). */ +#define RTFS_IS_FILE(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_FILE ) +/** Checks the mode flags indicate a symbolic link (S_ISLNK). */ +#define RTFS_IS_SYMLINK(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_SYMLINK ) +/** Checks the mode flags indicate a socket (S_ISSOCK). */ +#define RTFS_IS_SOCKET(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_SOCKET ) +/** Checks the mode flags indicate a whiteout (S_ISWHT). */ +#define RTFS_IS_WHITEOUT(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_WHITEOUT ) +/** @} */ + + +/** + * Filesystem type IDs returned by RTFsQueryType. + * + * This enum is subject to changes and must not be used as part of any ABI or + * binary format (file, network, etc). + * + * @remarks When adding new entries, please update RTFsTypeName(). Also, try + * add them to the most natural group. + */ +typedef enum RTFSTYPE +{ + /** Unknown file system. */ + RTFSTYPE_UNKNOWN = 0, + + /** Universal Disk Format. */ + RTFSTYPE_UDF, + /** ISO 9660, aka Compact Disc File System (CDFS). */ + RTFSTYPE_ISO9660, + /** Filesystem in Userspace. */ + RTFSTYPE_FUSE, + /** VirtualBox shared folders. */ + RTFSTYPE_VBOXSHF, + + /* Linux: */ + RTFSTYPE_EXT, + RTFSTYPE_EXT2, + RTFSTYPE_EXT3, + RTFSTYPE_EXT4, + RTFSTYPE_XFS, + RTFSTYPE_CIFS, + RTFSTYPE_SMBFS, + RTFSTYPE_TMPFS, + RTFSTYPE_SYSFS, + RTFSTYPE_PROC, + RTFSTYPE_OCFS2, + RTFSTYPE_BTRFS, + + /* Windows: */ + /** New Technology File System. */ + RTFSTYPE_NTFS, + /** FAT12, FAT16 and FAT32 lumped into one basket. + * The partition size limit of FAT12 and FAT16 will be the factor + * limiting the file size (except, perhaps for the 64KB cluster case on + * non-Windows hosts). */ + RTFSTYPE_FAT, + /** Extended File Allocation Table, main target are flash drives. */ + RTFSTYPE_EXFAT, + /** Resilient File System. */ + RTFSTYPE_REFS, + + /* Solaris: */ + /** Zettabyte File System. */ + RTFSTYPE_ZFS, + /** Unix File System. */ + RTFSTYPE_UFS, + /** Network File System. */ + RTFSTYPE_NFS, + + /* Mac OS X: */ + /** Hierarchical File System. */ + RTFSTYPE_HFS, + /** @todo RTFSTYPE_HFS_PLUS? */ + RTFSTYPE_APFS, + RTFSTYPE_AUTOFS, + RTFSTYPE_DEVFS, + + /* *BSD: */ + + /* OS/2: */ + /** High Performance File System. */ + RTFSTYPE_HPFS, + /** Journaled File System (v2). */ + RTFSTYPE_JFS, + + /** The end of valid Filesystem types IDs. */ + RTFSTYPE_END, + /** The usual 32-bit type blow up. */ + RTFSTYPE_32BIT_HACK = 0x7fffffff +} RTFSTYPE; +/** Pointer to a Filesystem type ID. */ +typedef RTFSTYPE *PRTFSTYPE; + + +/** + * The available additional information in a RTFSOBJATTR object. + */ +typedef enum RTFSOBJATTRADD +{ + /** No additional information is available / requested. */ + RTFSOBJATTRADD_NOTHING = 1, + /** The additional unix attributes (RTFSOBJATTR::u::Unix) are available / + * requested. */ + RTFSOBJATTRADD_UNIX, + /** The additional unix attributes (RTFSOBJATTR::u::UnixOwner) are + * available / requested. */ + RTFSOBJATTRADD_UNIX_OWNER, + /** The additional unix attributes (RTFSOBJATTR::u::UnixGroup) are + * available / requested. */ + RTFSOBJATTRADD_UNIX_GROUP, + /** The additional extended attribute size (RTFSOBJATTR::u::EASize) is available / requested. */ + RTFSOBJATTRADD_EASIZE, + /** The last valid item (inclusive). + * The valid range is RTFSOBJATTRADD_NOTHING thru RTFSOBJATTRADD_LAST. */ + RTFSOBJATTRADD_LAST = RTFSOBJATTRADD_EASIZE, + + /** The usual 32-bit hack. */ + RTFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff +} RTFSOBJATTRADD; + +/** The number of bytes reserved for the additional attribute union. */ +#define RTFSOBJATTRUNION_MAX_SIZE 128 + +/** + * Additional Unix Attributes (RTFSOBJATTRADD_UNIX). + */ +typedef struct RTFSOBJATTRUNIX +{ + /** The user owning the filesystem object (st_uid). + * This field is NIL_RTUID if not supported. */ + RTUID uid; + + /** The group the filesystem object is assigned (st_gid). + * This field is NIL_RTGID if not supported. */ + RTGID gid; + + /** Number of hard links to this filesystem object (st_nlink). + * This field is 1 if the filesystem doesn't support hardlinking or + * the information isn't available. + */ + uint32_t cHardlinks; + + /** The device number of the device which this filesystem object resides on (st_dev). + * This field is 0 if this information is not available. */ + RTDEV INodeIdDevice; + + /** The unique identifier (within the filesystem) of this filesystem object (st_ino). + * Together with INodeIdDevice, this field can be used as a OS wide unique id + * when both their values are not 0. + * This field is 0 if the information is not available. + * + * @remarks The special '..' dir always shows up with 0 on NTFS/Windows. */ + RTINODE INodeId; + + /** User flags (st_flags). + * This field is 0 if this information is not available. */ + uint32_t fFlags; + + /** The current generation number (st_gen). + * This field is 0 if this information is not available. */ + uint32_t GenerationId; + + /** The device number of a character or block device type object (st_rdev). + * This field is 0 if the file isn't of a character or block device type and + * when the OS doesn't subscribe to the major+minor device idenfication scheme. */ + RTDEV Device; +} RTFSOBJATTRUNIX; + + +/** + * Additional Unix Attributes (RTFSOBJATTRADD_UNIX_OWNER). + * + * @remarks This interface is mainly for TAR. + */ +typedef struct RTFSOBJATTRUNIXOWNER +{ + /** The user owning the filesystem object (st_uid). + * This field is NIL_UID if not supported. */ + RTUID uid; + /** The user name. + * Empty if not available or not supported, truncated if too long. */ + char szName[RTFSOBJATTRUNION_MAX_SIZE - sizeof(RTUID)]; +} RTFSOBJATTRUNIXOWNER; + + +/** + * Additional Unix Attributes (RTFSOBJATTRADD_UNIX_GROUP). + * + * @remarks This interface is mainly for TAR. + */ +typedef struct RTFSOBJATTRUNIXGROUP +{ + /** The user owning the filesystem object (st_uid). + * This field is NIL_GID if not supported. */ + RTGID gid; + /** The group name. + * Empty if not available or not supported, truncated if too long. */ + char szName[RTFSOBJATTRUNION_MAX_SIZE - sizeof(RTGID)]; +} RTFSOBJATTRUNIXGROUP; + + +/** + * Filesystem object attributes. + */ +typedef struct RTFSOBJATTR +{ + /** Mode flags (st_mode). RTFS_UNIX_*, RTFS_TYPE_*, and RTFS_DOS_*. */ + RTFMODE fMode; + + /** The additional attributes available. */ + RTFSOBJATTRADD enmAdditional; + + /** + * Additional attributes. + * + * Unless explicitly specified to an API, the API can provide additional + * data as it is provided by the underlying OS. + */ + union RTFSOBJATTRUNION + { + /** Additional Unix Attributes - RTFSOBJATTRADD_UNIX. */ + RTFSOBJATTRUNIX Unix; + /** Additional Unix Owner Attributes - RTFSOBJATTRADD_UNIX_OWNER. */ + RTFSOBJATTRUNIXOWNER UnixOwner; + /** Additional Unix Group Attributes - RTFSOBJATTRADD_UNIX_GROUP. */ + RTFSOBJATTRUNIXGROUP UnixGroup; + + /** + * Extended attribute size is available when RTFS_DOS_HAVE_EA_SIZE is set. + */ + struct RTFSOBJATTREASIZE + { + /** Size of EAs. */ + RTFOFF cb; + } EASize; + /** Reserved space. */ + uint8_t abReserveSpace[128]; + } u; +} RTFSOBJATTR; +/** Pointer to a filesystem object attributes structure. */ +typedef RTFSOBJATTR *PRTFSOBJATTR; +/** Pointer to a const filesystem object attributes structure. */ +typedef const RTFSOBJATTR *PCRTFSOBJATTR; + + +/** + * Filesystem object information structure. + * + * This is returned by the RTPathQueryInfo(), RTFileQueryInfo() and RTDirRead() APIs. + */ +typedef struct RTFSOBJINFO +{ + /** Logical size (st_size). + * For normal files this is the size of the file. + * For symbolic links, this is the length of the path name contained + * in the symbolic link. + * For other objects this fields needs to be specified. + */ + RTFOFF cbObject; + + /** Disk allocation size (st_blocks * DEV_BSIZE). */ + RTFOFF cbAllocated; + + /** Time of last access (st_atime). */ + RTTIMESPEC AccessTime; + + /** Time of last data modification (st_mtime). */ + RTTIMESPEC ModificationTime; + + /** Time of last status change (st_ctime). + * If not available this is set to ModificationTime. + */ + RTTIMESPEC ChangeTime; + + /** Time of file birth (st_birthtime). + * If not available this is set to ChangeTime. + */ + RTTIMESPEC BirthTime; + + /** Attributes. */ + RTFSOBJATTR Attr; + +} RTFSOBJINFO; +/** Pointer to a filesystem object information structure. */ +typedef RTFSOBJINFO *PRTFSOBJINFO; +/** Pointer to a const filesystem object information structure. */ +typedef const RTFSOBJINFO *PCRTFSOBJINFO; + + +#ifdef IN_RING3 + +/** + * Query the sizes of a filesystem. + * + * @returns iprt status code. + * @param pszFsPath Path within the mounted filesystem. + * @param pcbTotal Where to store the total filesystem space. (Optional) + * @param pcbFree Where to store the remaining free space in the filesystem. (Optional) + * @param pcbBlock Where to store the block size. (Optional) + * @param pcbSector Where to store the sector size. (Optional) + * + * @sa RTFileQueryFsSizes + */ +RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, PRTFOFF pcbTotal, RTFOFF *pcbFree, + uint32_t *pcbBlock, uint32_t *pcbSector); + +/** + * Query the mountpoint of a filesystem. + * + * @returns iprt status code. + * @returns VERR_BUFFER_OVERFLOW if cbMountpoint isn't enough. + * @param pszFsPath Path within the mounted filesystem. + * @param pszMountpoint Where to store the mountpoint path. + * @param cbMountpoint Size of the buffer pointed to by pszMountpoint. + */ +RTR3DECL(int) RTFsQueryMountpoint(const char *pszFsPath, char *pszMountpoint, size_t cbMountpoint); + +/** + * Query the label of a filesystem. + * + * @returns iprt status code. + * @returns VERR_BUFFER_OVERFLOW if cbLabel isn't enough. + * @param pszFsPath Path within the mounted filesystem. + * @param pszLabel Where to store the label. + * @param cbLabel Size of the buffer pointed to by pszLabel. + */ +RTR3DECL(int) RTFsQueryLabel(const char *pszFsPath, char *pszLabel, size_t cbLabel); + +/** + * Query the serial number of a filesystem. + * + * @returns iprt status code. + * @param pszFsPath Path within the mounted filesystem. + * @param pu32Serial Where to store the serial number. + */ +RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial); + +/** + * Query the name of the filesystem driver. + * + * @returns iprt status code. + * @returns VERR_BUFFER_OVERFLOW if cbFsDriver isn't enough. + * @param pszFsPath Path within the mounted filesystem. + * @param pszFsDriver Where to store the filesystem driver name. + * @param cbFsDriver Size of the buffer pointed to by pszFsDriver. + */ +RTR3DECL(int) RTFsQueryDriver(const char *pszFsPath, char *pszFsDriver, size_t cbFsDriver); + +/** + * Query the name of the filesystem the file is located on. + * + * @returns iprt status code. + * @param pszFsPath Path within the mounted filesystem. It must exist. + * In case this is a symlink, the file it refers to is + * evaluated. + * @param penmType Where to store the filesystem type, this is always + * set. See RTFSTYPE for the values. + */ +RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType); + +#endif /* IN_RING3 */ + +/** + * Gets the name of a filesystem type. + * + * @returns Pointer to a read-only string containing the name. + * @param enmType A valid filesystem ID. If outside the valid range, + * the returned string will be pointing to a static + * memory buffer which will be changed on subsequent + * calls to this function by any thread. + */ +RTDECL(const char *) RTFsTypeName(RTFSTYPE enmType); + +/** + * Filesystem properties. + */ +typedef struct RTFSPROPERTIES +{ + /** The maximum size of a filesystem object name. + * This does not include the '\\0'. */ + uint32_t cbMaxComponent; + + /** True if the filesystem is remote. + * False if the filesystem is local. */ + bool fRemote; + + /** True if the filesystem is case sensitive. + * False if the filesystem is case insensitive. */ + bool fCaseSensitive; + + /** True if the filesystem is mounted read only. + * False if the filesystem is mounted read write. */ + bool fReadOnly; + + /** True if the filesystem can encode unicode object names. + * False if it can't. */ + bool fSupportsUnicode; + + /** True if the filesystem is compressed. + * False if it isn't or we don't know. */ + bool fCompressed; + + /** True if the filesystem compresses of individual files. + * False if it doesn't or we don't know. */ + bool fFileCompression; + + /** @todo more? */ +} RTFSPROPERTIES; +/** Pointer to a filesystem properties structure. */ +typedef RTFSPROPERTIES *PRTFSPROPERTIES; +/** Pointer to a const filesystem properties structure. */ +typedef RTFSPROPERTIES const *PCRTFSPROPERTIES; + +#ifdef IN_RING3 + +/** + * Query the properties of a mounted filesystem. + * + * @returns iprt status code. + * @param pszFsPath Path within the mounted filesystem. + * @param pProperties Where to store the properties. + */ +RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties); + +/** + * Checks if the given volume is case sensitive or not. + * + * This may be misleading in some cases as we lack the necessary APIs to query + * the information on some system (or choose not to use them) and are instead + * returning the general position on case sensitive file name of the system. + * + * @returns @c true if case sensitive, @c false if not. + * @param pszFsPath Path within the mounted file system. + */ +RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath); + +/** + * Mountpoint enumerator callback. + * + * @returns iprt status code. Failure terminates the enumeration. + * @param pszMountpoint The mountpoint name. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTFSMOUNTPOINTENUM,(const char *pszMountpoint, void *pvUser)); +/** Pointer to a FNRTFSMOUNTPOINTENUM(). */ +typedef FNRTFSMOUNTPOINTENUM *PFNRTFSMOUNTPOINTENUM; + +/** + * Enumerate mount points. + * + * @returns iprt status code. + * @param pfnCallback The callback function. + * @param pvUser The user argument to the callback. + */ +RTR3DECL(int) RTFsMountpointsEnum(PFNRTFSMOUNTPOINTENUM pfnCallback, void *pvUser); + + +/** + * A /bin/ls clone. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTR3DECL(RTEXITCODE) RTFsCmdLs(unsigned cArgs, char **papszArgs); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_fs_h */ + diff --git a/include/iprt/fsisomaker.h b/include/iprt/fsisomaker.h new file mode 100644 index 00000000..5eb782ba --- /dev/null +++ b/include/iprt/fsisomaker.h @@ -0,0 +1,826 @@ +/** @file + * IPRT - ISO Image Maker. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_fsisomaker_h +#define IPRT_INCLUDED_fsisomaker_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fsisomaker RTFsIsoMaker - ISO Image Maker + * @ingroup grp_rt_fs + * @{ + */ + + +/** @name RTFSISOMAKER_NAMESPACE_XXX - Namespace selector. + * @{ + */ +#define RTFSISOMAKER_NAMESPACE_ISO_9660 RT_BIT_32(0) /**< The primary ISO-9660 namespace. */ +#define RTFSISOMAKER_NAMESPACE_JOLIET RT_BIT_32(1) /**< The joliet namespace. */ +#define RTFSISOMAKER_NAMESPACE_UDF RT_BIT_32(2) /**< The UDF namespace. */ +#define RTFSISOMAKER_NAMESPACE_HFS RT_BIT_32(3) /**< The HFS namespace */ +#define RTFSISOMAKER_NAMESPACE_ALL UINT32_C(0x0000000f) /**< All namespaces. */ +#define RTFSISOMAKER_NAMESPACE_VALID_MASK UINT32_C(0x0000000f) /**< Valid namespace bits. */ +/** @} */ + +/** Root directory configuration index. */ +#define RTFSISOMAKER_CFG_IDX_ROOT UINT32_C(0) + + +/** + * Creates an ISO maker instance. + * + * @returns IPRT status code. + * @param phIsoMaker Where to return the handle to the new ISO maker. + */ +RTDECL(int) RTFsIsoMakerCreate(PRTFSISOMAKER phIsoMaker); + +/** + * Retains a references to an ISO maker instance. + * + * @returns New reference count on success, UINT32_MAX if invalid handle. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint32_t) RTFsIsoMakerRetain(RTFSISOMAKER hIsoMaker); + +/** + * Releases a references to an ISO maker instance. + * + * @returns New reference count on success, UINT32_MAX if invalid handle. + * @param hIsoMaker The ISO maker handle. NIL is ignored. + */ +RTDECL(uint32_t) RTFsIsoMakerRelease(RTFSISOMAKER hIsoMaker); + +/** + * Sets the ISO-9660 level. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param uIsoLevel The level, 1-3. + */ +RTDECL(int) RTFsIsoMakerSetIso9660Level(RTFSISOMAKER hIsoMaker, uint8_t uIsoLevel); + +/** + * Gets the ISO-9660 level. + * + * @returns The level, UINT8_MAX if invalid handle. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint8_t) RTFsIsoMakerGetIso9660Level(RTFSISOMAKER hIsoMaker); + +/** + * Sets the joliet level. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param uJolietLevel The joliet UCS-2 level 1-3, or 0 to disable + * joliet. + */ +RTDECL(int) RTFsIsoMakerSetJolietUcs2Level(RTFSISOMAKER hIsoMaker, uint8_t uJolietLevel); + +/** + * Sets the rock ridge support level (on the primary ISO-9660 namespace). + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param uLevel 0 if disabled, 1 to just enable, 2 to enable and + * write the ER tag. + */ +RTDECL(int) RTFsIsoMakerSetRockRidgeLevel(RTFSISOMAKER hIsoMaker, uint8_t uLevel); + +/** + * Sets the rock ridge support level on the joliet namespace (experimental). + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param uLevel 0 if disabled, 1 to just enable, 2 to enable and + * write the ER tag. + */ +RTDECL(int) RTFsIsoMakerSetJolietRockRidgeLevel(RTFSISOMAKER hIsoMaker, uint8_t uLevel); + +/** + * Gets the rock ridge support level (on the primary ISO-9660 namespace). + * + * @returns 0 if disabled, 1 just enabled, 2 if enabled with ER tag, and + * UINT8_MAX if the handle is invalid. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint8_t) RTFsIsoMakerGetRockRidgeLevel(RTFSISOMAKER hIsoMaker); + +/** + * Gets the rock ridge support level on the joliet namespace (experimental). + * + * @returns 0 if disabled, 1 just enabled, 2 if enabled with ER tag, and + * UINT8_MAX if the handle is invalid. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint8_t) RTFsIsoMakerGetJolietRockRidgeLevel(RTFSISOMAKER hIsoMaker); + +/** + * Changes the file attribute (mode, owner, group) inherit style (from source). + * + * The strict style will use the exact attributes from the source, where as the + * non-strict (aka rational and default) style will use 0 for the owner and + * group IDs and normalize the mode bits along the lines of 'chmod a=rX', + * stripping set-uid/gid bitson files but preserving sticky ones on directories. + * + * When disabling strict style, the default dir and file modes will be restored + * to default values. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fStrict Indicates strict (true) or non-strict (false) + * style. + */ +RTDECL(int) RTFsIsoMakerSetAttribInheritStyle(RTFSISOMAKER hIsoMaker, bool fStrict); + +/** + * Sets the default file mode settings. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fMode The default file mode. + */ +RTDECL(int) RTFsIsoMakerSetDefaultFileMode(RTFSISOMAKER hIsoMaker, RTFMODE fMode); + +/** + * Sets the default dir mode settings. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fMode The default dir mode. + */ +RTDECL(int) RTFsIsoMakerSetDefaultDirMode(RTFSISOMAKER hIsoMaker, RTFMODE fMode); + +/** + * Sets the forced file mode, if @a fForce is true also the default mode is set. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fMode The file mode. + * @param fForce Indicate whether forced mode is active or not. + */ +RTDECL(int) RTFsIsoMakerSetForcedFileMode(RTFSISOMAKER hIsoMaker, RTFMODE fMode, bool fForce); + +/** + * Sets the forced dir mode, if @a fForce is true also the default mode is set. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fMode The dir mode. + * @param fForce Indicate whether forced mode is active or not. + */ +RTDECL(int) RTFsIsoMakerSetForcedDirMode(RTFSISOMAKER hIsoMaker, RTFMODE fMode, bool fForce); + +/** + * Sets the content of the system area, i.e. the first 32KB of the image. + * + * This can be used to put generic boot related stuff. + * + * @note Other settings may overwrite parts of the content (yet to be + * determined which). + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pvContent The content to put in the system area. + * @param cbContent The size of the content. + * @param off The offset into the system area. + */ +RTDECL(int) RTFsIsoMakerSetSysAreaContent(RTFSISOMAKER hIsoMaker, void const *pvContent, size_t cbContent, uint32_t off); + +/** + * String properties settable thru RTFsIsoMakerSetStringProp. + */ +typedef enum RTFSISOMAKERSTRINGPROP +{ + /** The customary invalid zero value. */ + RTFSISOMAKERSTRINGPROP_INVALID = 0, + /** The system identifier. */ + RTFSISOMAKERSTRINGPROP_SYSTEM_ID, + /** The volume identifier(label). */ + RTFSISOMAKERSTRINGPROP_VOLUME_ID, + /** The volume set identifier. */ + RTFSISOMAKERSTRINGPROP_VOLUME_SET_ID, + /** The publisher ID (root file reference if it starts with '_'). */ + RTFSISOMAKERSTRINGPROP_PUBLISHER_ID, + /** The data preparer ID (root file reference if it starts with '_'). */ + RTFSISOMAKERSTRINGPROP_DATA_PREPARER_ID, + /** The application ID (root file reference if it starts with '_'). */ + RTFSISOMAKERSTRINGPROP_APPLICATION_ID, + /** The copyright file ID. */ + RTFSISOMAKERSTRINGPROP_COPYRIGHT_FILE_ID, + /** The abstract file ID. */ + RTFSISOMAKERSTRINGPROP_ABSTRACT_FILE_ID, + /** The bibliographic file ID. */ + RTFSISOMAKERSTRINGPROP_BIBLIOGRAPHIC_FILE_ID, + /** End of valid string property values. */ + RTFSISOMAKERSTRINGPROP_END, + /** Make sure it's a 32-bit type. */ + RTFSISOMAKERSTRINGPROP_32BIT_HACK = 0x7fffffff +} RTFSISOMAKERSTRINGPROP; + +/** + * Sets a string property in one or more namespaces. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param enmStringProp The string property to set. + * @param fNamespaces The namespaces to set it in. + * @param pszValue The value to set it to. NULL is treated like an + * empty string. The value will be silently truncated + * to fit the available space. + */ +RTDECL(int) RTFsIsoMakerSetStringProp(RTFSISOMAKER hIsoMaker, RTFSISOMAKERSTRINGPROP enmStringProp, + uint32_t fNamespaces, const char *pszValue); + +/** + * Specifies image padding. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param cSectors Number of sectors to pad the image with. + */ +RTDECL(int) RTFsIsoMakerSetImagePadding(RTFSISOMAKER hIsoMaker, uint32_t cSectors); + +/** + * Gets currently populated namespaces. + * + * @returns Set of namespaces (RTFSISOMAKER_NAMESPACE_XXX), UINT32_MAX on error. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint32_t) RTFsIsoMakerGetPopulatedNamespaces(RTFSISOMAKER hIsoMaker); + +/** + * Resolves a path into a object ID. + * + * This will be doing the looking up using the specified object names rather + * than the version adjusted and mangled according to the namespace setup. + * + * @returns The object ID corresponding to @a pszPath, or UINT32_MAX if not + * found or invalid parameters. + * @param hIsoMaker The ISO maker instance. + * @param fNamespaces The namespace to resolve @a pszPath in. It's + * possible to specify multiple namespaces here, of + * course, but that's inefficient. + * @param pszPath The path to the object. + */ +RTDECL(uint32_t) RTFsIsoMakerGetObjIdxForPath(RTFSISOMAKER hIsoMaker, uint32_t fNamespaces, const char *pszPath); + +/** + * Queries the configuration index of the boot catalog file object. + * + * The boot catalog file is created as necessary, thus this have to be a query + * rather than a getter since object creation may fail. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param pidxObj Where to return the configuration index. + */ +RTDECL(int) RTFsIsoMakerQueryObjIdxForBootCatalog(RTFSISOMAKER hIsoMaker, uint32_t *pidxObj); + +/** + * Removes the specified object from the image. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker instance. + * @param idxObj The index of the object to remove. + */ +RTDECL(int) RTFsIsoMakerObjRemove(RTFSISOMAKER hIsoMaker, uint32_t idxObj); + +/** + * Sets the path (name) of an object in the selected namespaces. + * + * The name will be transformed as necessary. + * + * The initial implementation does not allow this function to be called more + * than once on an object. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index of to name. + * @param fNamespaces The namespaces to apply the path to + * (RTFSISOMAKER_NAMESPACE_XXX). + * @param pszPath The path. + */ +RTDECL(int) RTFsIsoMakerObjSetPath(RTFSISOMAKER hIsoMaker, uint32_t idxObj, uint32_t fNamespaces, const char *pszPath); + +/** + * Sets the name of an object in the selected namespaces, placing it under the + * given directory. + * + * The name will be transformed as necessary. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index of to name. + * @param idxParentObj The parent directory object. + * @param fNamespaces The namespaces to apply the path to + * (RTFSISOMAKER_NAMESPACE_XXX). + * @param pszName The name. + * @param fNoNormalize Don't normalize the name (imported or such). + */ +RTDECL(int) RTFsIsoMakerObjSetNameAndParent(RTFSISOMAKER hIsoMaker, uint32_t idxObj, uint32_t idxParentObj, + uint32_t fNamespaces, const char *pszName, bool fNoNormalize); + +/** + * Changes the rock ridge name for the object in the selected namespaces. + * + * The object must already be enetered into the namespaces by + * RTFsIsoMakerObjSetNameAndParent, RTFsIsoMakerObjSetPath or similar. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index of to name. + * @param fNamespaces The namespaces to apply the path to + * (RTFSISOMAKER_NAMESPACE_XXX). + * @param pszRockName The rock ridge name. Passing NULL or an empty + * string will restore the specified name. + */ +RTDECL(int) RTFsIsoMakerObjSetRockName(RTFSISOMAKER hIsoMaker, uint32_t idxObj, uint32_t fNamespaces, const char *pszRockName); + +/** + * Enables or disable syslinux boot info table patching of a file. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index. + * @param fEnable Whether to enable or disable patching. + */ +RTDECL(int) RTFsIsoMakerObjEnableBootInfoTablePatching(RTFSISOMAKER hIsoMaker, uint32_t idxObj, bool fEnable); + +/** + * Gets the data size of an object. + * + * Currently only supported on file objects. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index. + * @param pcbData Where to return the size. + */ +RTDECL(int) RTFsIsoMakerObjQueryDataSize(RTFSISOMAKER hIsoMaker, uint32_t idxObj, uint64_t *pcbData); + +/** + * Adds an unnamed directory to the image. + * + * The directory must explictly be entered into the desired namespaces. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pObjInfo Pointer to object attributes, must be set to + * UNIX. The size and hardlink counts are ignored. + * Optional. + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddDir, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedDir(RTFSISOMAKER hIsoMaker, PCRTFSOBJINFO pObjInfo, uint32_t *pidxObj); + +/** + * Adds a directory to the image in all namespaces and default attributes. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszDir The path (UTF-8) to the directory in the ISO. + * + * @param pidxObj Where to return the configuration index of the + * directory. Optional. + * @sa RTFsIsoMakerAddUnnamedDir, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddDir(RTFSISOMAKER hIsoMaker, const char *pszDir, uint32_t *pidxObj); + +/** + * Adds an unnamed file to the image that's backed by a host file. + * + * The file must explictly be entered into the desired namespaces. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszSrcFile The source file path. VFS chain spec allowed. + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddFile, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedFileWithSrcPath(RTFSISOMAKER hIsoMaker, const char *pszSrcFile, uint32_t *pidxObj); + +/** + * Adds an unnamed file to the image that's backed by a VFS file. + * + * The file must explictly be entered into the desired namespaces. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param hVfsFileSrc The source file handle. + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddUnnamedFileWithSrcPath, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedFileWithVfsFile(RTFSISOMAKER hIsoMaker, RTVFSFILE hVfsFileSrc, uint32_t *pidxObj); + +/** + * Adds an unnamed file to the image that's backed by a portion of a common + * source file. + * + * The file must explictly be entered into the desired namespaces. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param idxCommonSrc The common source file index. + * @param offData The offset of the data in the source file. + * @param cbData The file size. + * @param pObjInfo Pointer to file info. Optional. + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddUnnamedFileWithSrcPath, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedFileWithCommonSrc(RTFSISOMAKER hIsoMaker, uint32_t idxCommonSrc, + uint64_t offData, uint64_t cbData, PCRTFSOBJINFO pObjInfo, uint32_t *pidxObj); + +/** + * Adds a common source file. + * + * Using RTFsIsoMakerAddUnnamedFileWithCommonSrc a sections common source file + * can be referenced to make up other files. The typical use case is when + * importing data from an existing ISO. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param hVfsFile VFS handle of the common source. (A reference + * is added, none consumed.) + * @param pidxCommonSrc Where to return the assigned common source + * index. This is used to reference the file. + * @sa RTFsIsoMakerAddUnnamedFileWithCommonSrc + */ +RTDECL(int) RTFsIsoMakerAddCommonSourceFile(RTFSISOMAKER hIsoMaker, RTVFSFILE hVfsFile, uint32_t *pidxCommonSrc); + +/** + * Adds a file that's backed by a host file to the image in all namespaces and + * with attributes taken from the source file. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszFile The path to the file in the image. + * @param pszSrcFile The source file path. VFS chain spec allowed. + * @param pidxObj Where to return the configuration index of the file. + * Optional + * @sa RTFsIsoMakerAddFileWithVfsFile, + * RTFsIsoMakerAddUnnamedFileWithSrcPath + */ +RTDECL(int) RTFsIsoMakerAddFileWithSrcPath(RTFSISOMAKER hIsoMaker, const char *pszFile, const char *pszSrcFile, uint32_t *pidxObj); + +/** + * Adds a file that's backed by a VFS file to the image in all namespaces and + * with attributes taken from the source file. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszFile The path to the file in the image. + * @param hVfsFileSrc The source file handle. + * @param pidxObj Where to return the configuration index of the file. + * Optional. + * @sa RTFsIsoMakerAddUnnamedFileWithVfsFile, + * RTFsIsoMakerAddFileWithSrcPath + */ +RTDECL(int) RTFsIsoMakerAddFileWithVfsFile(RTFSISOMAKER hIsoMaker, const char *pszFile, RTVFSFILE hVfsFileSrc, uint32_t *pidxObj); + +/** + * Adds an unnamed symbolic link to the image. + * + * The symlink must explictly be entered into the desired namespaces. Please + * note that it is not possible to enter a symbolic link into an ISO 9660 + * namespace where rock ridge extensions are disabled, since symbolic links + * depend on rock ridge. For HFS and UDF there is no such requirement. + * + * Will fail if no namespace is configured that supports symlinks. + * + * @returns IPRT status code + * @retval VERR_ISOMK_SYMLINK_SUPPORT_DISABLED if not supported. + * @param hIsoMaker The ISO maker handle. + * @param pObjInfo Pointer to object attributes, must be set to + * UNIX. The size and hardlink counts are ignored. + * Optional. + * @param pszTarget The symbolic link target (UTF-8). + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddSymlink, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedSymlink(RTFSISOMAKER hIsoMaker, PCRTFSOBJINFO pObjInfo, const char *pszTarget, uint32_t *pidxObj); + +/** + * Adds a directory to the image in all namespaces and default attributes. + * + * Will fail if no namespace is configured that supports symlinks. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszSymlink The path (UTF-8) to the symlink in the ISO. + * @param pszTarget The symlink target (UTF-8). + * @param pidxObj Where to return the configuration index of the + * directory. Optional. + * @sa RTFsIsoMakerAddUnnamedSymlink, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddSymlink(RTFSISOMAKER hIsoMaker, const char *pszSymlink, const char *pszTarget, uint32_t *pidxObj); + +/** + * Modifies the mode mask for a given path in one or more namespaces. + * + * The mode mask is used by rock ridge, UDF and HFS. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if the path wasn't found in any of the specified + * namespaces. + * + * @param hIsoMaker The ISO maker handler. + * @param pszPath The path which mode mask should be modified. + * @param fNamespaces The namespaces to set it in. + * @param fSet The mode bits to set. + * @param fUnset The mode bits to clear (applied first). + * @param fFlags Reserved, MBZ. + * @param pcHits Where to return number of paths found. Optional. + */ +RTDECL(int) RTFsIsoMakerSetPathMode(RTFSISOMAKER hIsoMaker, const char *pszPath, uint32_t fNamespaces, + RTFMODE fSet, RTFMODE fUnset, uint32_t fFlags, uint32_t *pcHits); + +/** + * Modifies the owner ID for a given path in one or more namespaces. + * + * The owner ID is used by rock ridge, UDF and HFS. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if the path wasn't found in any of the specified + * namespaces. + * + * @param hIsoMaker The ISO maker handler. + * @param pszPath The path which mode mask should be modified. + * @param fNamespaces The namespaces to set it in. + * @param idOwner The new owner ID to set. + * @param pcHits Where to return number of paths found. Optional. + */ +RTDECL(int) RTFsIsoMakerSetPathOwnerId(RTFSISOMAKER hIsoMaker, const char *pszPath, uint32_t fNamespaces, + RTUID idOwner, uint32_t *pcHits); + +/** + * Modifies the group ID for a given path in one or more namespaces. + * + * The group ID is used by rock ridge, UDF and HFS. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if the path wasn't found in any of the specified + * namespaces. + * + * @param hIsoMaker The ISO maker handler. + * @param pszPath The path which mode mask should be modified. + * @param fNamespaces The namespaces to set it in. + * @param idGroup The new group ID to set. + * @param pcHits Where to return number of paths found. Optional. + */ +RTDECL(int) RTFsIsoMakerSetPathGroupId(RTFSISOMAKER hIsoMaker, const char *pszPath, uint32_t fNamespaces, + RTGID idGroup, uint32_t *pcHits); + +/** + * Set the validation entry of the boot catalog (this is the first entry). + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idPlatform The platform ID + * (ISO9660_ELTORITO_PLATFORM_ID_XXX). + * @param pszString CD/DVD-ROM identifier. Optional. + */ +RTDECL(int) RTFsIsoMakerBootCatSetValidationEntry(RTFSISOMAKER hIsoMaker, uint8_t idPlatform, const char *pszString); + +/** + * Set the validation entry of the boot catalog (this is the first entry). + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxBootCat The boot catalog entry. Zero and two are + * invalid. Must be less than 63. + * @param idxImageObj The configuration index of the boot image. + * @param bBootMediaType The media type and flag (not for entry 1) + * (ISO9660_ELTORITO_BOOT_MEDIA_TYPE_XXX, + * ISO9660_ELTORITO_BOOT_MEDIA_F_XXX). + * @param bSystemType The partitiona table system ID. + * @param fBootable Whether it's a bootable entry or if we just want + * the BIOS to setup the emulation without booting + * it. + * @param uLoadSeg The load address divided by 0x10 (i.e. the real + * mode segment number). + * @param cSectorsToLoad Number of emulated sectors to load. + * @param bSelCritType The selection criteria type, if none pass + * ISO9660_ELTORITO_SEL_CRIT_TYPE_NONE. + * @param pvSelCritData Pointer to the selection criteria data. + * @param cbSelCritData Size of the selection criteria data. + */ +RTDECL(int) RTFsIsoMakerBootCatSetSectionEntry(RTFSISOMAKER hIsoMaker, uint32_t idxBootCat, uint32_t idxImageObj, + uint8_t bBootMediaType, uint8_t bSystemType, bool fBootable, + uint16_t uLoadSeg, uint16_t cSectorsToLoad, + uint8_t bSelCritType, void const *pvSelCritData, size_t cbSelCritData); + +/** + * Set the validation entry of the boot catalog (this is the first entry). + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxBootCat The boot catalog entry. + * @param cEntries Number of entries in the section. + * @param idPlatform The platform ID + * (ISO9660_ELTORITO_PLATFORM_ID_XXX). + * @param pszString Section identifier or something. Optional. + */ +RTDECL(int) RTFsIsoMakerBootCatSetSectionHeaderEntry(RTFSISOMAKER hIsoMaker, uint32_t idxBootCat, uint32_t cEntries, + uint8_t idPlatform, const char *pszString); + +/** + * Sets the boot catalog backing file. + * + * The content of the given file will be discarded and replaced with the boot + * catalog, the naming and file attributes (other than size) will be retained. + * + * This API exists mainly to assist when importing ISOs. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index of the file. + */ +RTDECL(int) RTFsIsoMakerBootCatSetFile(RTFSISOMAKER hIsoMaker, uint32_t idxObj); + + +/** + * ISO maker import results (RTFsIsoMakerImport). + */ +typedef struct RTFSISOMAKERIMPORTRESULTS +{ + /** Number of names added. */ + uint32_t cAddedNames; + /** Number of directories added. */ + uint32_t cAddedDirs; + /** Amount of added data blocks, files only. */ + uint64_t cbAddedDataBlocks; + /** Number of unique files added (unique in terms of data location). */ + uint32_t cAddedFiles; + /** Number of symbolic links added. */ + uint32_t cAddedSymlinks; + /** Number of imported boot catalog entries. */ + uint32_t cBootCatEntries; + /** Number of system area bytes imported (from offset zero). */ + uint32_t cbSysArea; + + /** Number of import errors. */ + uint32_t cErrors; +} RTFSISOMAKERIMPORTRESULTS; +/** Pointer to ISO maker import results. */ +typedef RTFSISOMAKERIMPORTRESULTS *PRTFSISOMAKERIMPORTRESULTS; + +/** + * Imports an existing ISO. + * + * Just like other source files, the existing image must remain present and + * unmodified till the ISO maker is done with it. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param hIsoFile VFS file handle to the existing image to import / clone. + * @param fFlags Reserved for the future, MBZ. + * @param pResults Where to return import results. + * @param pErrInfo Where to return additional error information. + * Optional. + */ +RTDECL(int) RTFsIsoMakerImport(RTFSISOMAKER hIsoMaker, RTVFSFILE hIsoFile, uint32_t fFlags, + PRTFSISOMAKERIMPORTRESULTS pResults, PRTERRINFO pErrInfo); + +/** @name RTFSISOMK_IMPORT_F_XXX - Flags for RTFsIsoMakerImport. + * @{ */ +#define RTFSISOMK_IMPORT_F_NO_PRIMARY_ISO RT_BIT_32(0) /**< Skip the primary ISO-9660 namespace (rock ridge included). */ +#define RTFSISOMK_IMPORT_F_NO_JOLIET RT_BIT_32(1) /**< Skip the joliet namespace. */ +#define RTFSISOMK_IMPORT_F_NO_ROCK_RIDGE RT_BIT_32(2) /**< Skip rock ridge (both primary and joliet). */ +#define RTFSISOMK_IMPORT_F_NO_UDF RT_BIT_32(3) /**< Skip the UDF namespace. */ +#define RTFSISOMK_IMPORT_F_NO_HFS RT_BIT_32(4) /**< Skip the HFS namespace. */ +#define RTFSISOMK_IMPORT_F_NO_BOOT RT_BIT_32(5) /**< Skip importing El Torito boot stuff. */ +#define RTFSISOMK_IMPORT_F_NO_SYS_AREA RT_BIT_32(6) /**< Skip importing the system area (first 32KB). */ + +#define RTFSISOMK_IMPORT_F_NO_SYSTEM_ID RT_BIT_32(7) /**< Don't import the system ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_VOLUME_ID RT_BIT_32(8) /**< Don't import the volume ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_VOLUME_SET_ID RT_BIT_32(9) /**< Don't import the volume set ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_PUBLISHER_ID RT_BIT_32(10) /**< Don't import the publisher ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_DATA_PREPARER_ID RT_BIT_32(11) /**< Do import the data preparer ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_APPLICATION_ID RT_BIT_32(12) /**< Do import the application ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_COPYRIGHT_FID RT_BIT_32(13) /**< Don't import the copyright file ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_ABSTRACT_FID RT_BIT_32(14) /**< Don't import the abstract file ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_BIBLIO_FID RT_BIT_32(15) /**< Don't import the bibliographic file ID primary descriptor field. */ + +#define RTFSISOMK_IMPORT_F_NO_J_SYSTEM_ID RT_BIT_32(16) /**< Don't import the system ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_VOLUME_ID RT_BIT_32(17) /**< Don't import the volume ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_VOLUME_SET_ID RT_BIT_32(18) /**< Don't import the volume set ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_PUBLISHER_ID RT_BIT_32(19) /**< Don't import the publisher ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_J_DATA_PREPARER_ID RT_BIT_32(20) /**< Do import the data preparer ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_J_APPLICATION_ID RT_BIT_32(21) /**< Do import the application ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_COPYRIGHT_FID RT_BIT_32(22) /**< Don't import the copyright file ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_ABSTRACT_FID RT_BIT_32(23) /**< Don't import the abstract file ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_BIBLIO_FID RT_BIT_32(24) /**< Don't import the bibliographic file ID joliet descriptor field. */ + +#define RTFSISOMK_IMPORT_F_VALID_MASK UINT32_C(0x01ffffff) +/** @} */ + + +/** + * Finalizes the image. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(int) RTFsIsoMakerFinalize(RTFSISOMAKER hIsoMaker); + +/** + * Creates a VFS file for a finalized ISO maker instanced. + * + * The file can be used to access the image. Both sequential and random access + * are supported, so that this could in theory be hooked up to a CD/DVD-ROM + * drive emulation and used as a virtual ISO image. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param phVfsFile Where to return the handle. + */ +RTDECL(int) RTFsIsoMakerCreateVfsOutputFile(RTFSISOMAKER hIsoMaker, PRTVFSFILE phVfsFile); + + + +/** + * ISO maker command (creates image file on disk). + * + * @returns IPRT status code + * @param cArgs Number of arguments. + * @param papszArgs Pointer to argument array. + */ +RTDECL(RTEXITCODE) RTFsIsoMakerCmd(unsigned cArgs, char **papszArgs); + +/** + * Extended ISO maker command. + * + * This can be used as a ISO maker command that produces a image file, or + * alternatively for setting up a virtual ISO in memory. + * + * @returns IPRT status code + * @param cArgs Number of arguments. + * @param papszArgs Pointer to argument array. + * @param hVfsCwd The current working directory to assume when processing + * relative file/dir references. Pass NIL_RTVFSDIR to use + * the current CWD of the process. + * @param pszCwd Path to @a hVfsCwdDir. Use for error reporting and + * optimizing the open file count if possible. + * @param phVfsFile Where to return the virtual ISO. Pass NULL to for + * normal operation (creates file on disk). + * @param pErrInfo Where to return extended error information in the + * virtual ISO mode. + */ +RTDECL(int) RTFsIsoMakerCmdEx(unsigned cArgs, char **papszArgs, RTVFSDIR hVfsCwd, const char *pszCwd, + PRTVFSFILE phVfsFile, PRTERRINFO pErrInfo); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_fsisomaker_h */ + diff --git a/include/iprt/fsvfs.h b/include/iprt/fsvfs.h new file mode 100644 index 00000000..0b9d8d03 --- /dev/null +++ b/include/iprt/fsvfs.h @@ -0,0 +1,204 @@ +/** @file + * IPRT - Filesystem, VFS implementations. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_fsvfs_h +#define IPRT_INCLUDED_fsvfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fs_vfs VFS File System Implementations + * @ingroup grp_rt_fs + * @{ + */ + +/** + * Opens a FAT file system volume. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the volume. + * @param fReadOnly Whether to mount it read-only. + * @param offBootSector The offset of the boot sector relative to the start + * of @a hVfsFileIn. Pass 0 for floppies. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTFsFatVolOpen(RTVFSFILE hVfsFileIn, bool fReadOnly, uint64_t offBootSector, PRTVFS phVfs, PRTERRINFO pErrInfo); + + +/** + * FAT type (format). + */ +typedef enum RTFSFATTYPE +{ + RTFSFATTYPE_INVALID = 0, + RTFSFATTYPE_FAT12, + RTFSFATTYPE_FAT16, + RTFSFATTYPE_FAT32, + RTFSFATTYPE_END +} RTFSFATTYPE; + + +/** @name RTFSFATVOL_FMT_F_XXX - RTFsFatVolFormat flags + * @{ */ +/** Perform a full format, filling unused sectors with 0xf6. */ +#define RTFSFATVOL_FMT_F_FULL UINT32_C(0) +/** Perform a quick format. + * I.e. just write the boot sector, FATs and root directory. */ +#define RTFSFATVOL_FMT_F_QUICK RT_BIT_32(0) +/** Mask containing all valid flags. */ +#define RTFSFATVOL_FMT_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Formats a FAT volume. + * + * @returns IRPT status code. + * @param hVfsFile The volume file. + * @param offVol The offset into @a hVfsFile of the file. + * Typically 0. + * @param cbVol The size of the volume. Pass 0 if the rest of + * hVfsFile should be used. + * @param fFlags See RTFSFATVOL_FMT_F_XXX. + * @param cbSector The logical sector size. Must be power of two. + * Optional, pass zero to use 512. + * @param cSectorsPerCluster Number of sectors per cluster. Power of two. + * Optional, pass zero to auto detect. + * @param enmFatType The FAT type (12, 16, 32) to use. + * Optional, pass RTFSFATTYPE_INVALID for default. + * @param cHeads The number of heads to report in the BPB. + * Optional, pass zero to auto detect. + * @param cSectorsPerTrack The number of sectors per track to put in the + * BPB. Optional, pass zero to auto detect. + * @param bMedia The media byte value and FAT ID to use. + * Optional, pass zero to auto detect. + * @param cRootDirEntries Number of root directory entries. + * Optional, pass zero to auto detect. + * @param cHiddenSectors Number of hidden sectors. Pass 0 for + * unpartitioned media. + * @param pErrInfo Additional error information, maybe. Optional. + */ +RTDECL(int) RTFsFatVolFormat(RTVFSFILE hVfsFile, uint64_t offVol, uint64_t cbVol, uint32_t fFlags, uint16_t cbSector, + uint16_t cSectorsPerCluster, RTFSFATTYPE enmFatType, uint32_t cHeads, uint32_t cSectorsPerTrack, + uint8_t bMedia, uint16_t cRootDirEntries, uint32_t cHiddenSectors, PRTERRINFO pErrInfo); + +/** + * Formats a 1.44MB floppy image. + * + * @returns IPRT status code. + * @param hVfsFile The image. Will be grown to 1.44MB if + * necessary. + * @param fQuick Whether to quick format the floppy or not. + */ +RTDECL(int) RTFsFatVolFormat144(RTVFSFILE hVfsFile, bool fQuick); + +/** + * Formats a 2.88MB floppy image. + * + * @returns IPRT status code. + * @param hVfsFile The image. Will be grown to 1.44MB if + * necessary. + * @param fQuick Whether to quick format the floppy or not. + */ +RTDECL(int) RTFsFatVolFormat288(RTVFSFILE hVfsFile, bool fQuick); + + +/** + * Opens an EXT2/3/4 file system volume. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the volume. + * @param fMntFlags RTVFSMNT_F_XXX. + * @param fExtFlags Reserved, MBZ. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTFsExtVolOpen(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fExtFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + + + +/** @name RTFSISO9660_F_XXX - ISO 9660 mount flags. + * @{ */ +/** Do not use the UDF part if present. */ +#define RTFSISO9660_F_NO_UDF RT_BIT_32(0) +/** Do not use the joliet part. */ +#define RTFSISO9660_F_NO_JOLIET RT_BIT_32(1) +/** Do not use the rock ridge extensions if present. */ +#define RTFSISO9660_F_NO_ROCK RT_BIT_32(2) +/** Valid ISO 9660 mount option mask. */ +#define RTFSISO9660_F_VALID_MASK UINT32_C(0x00000007) +/** Checks if @a a_fNoType is the only acceptable volume type. */ +#define RTFSISO9660_F_IS_ONLY_TYPE(a_fFlags, a_fNoType) \ + ( ((a_fFlags) & (RTFSISO9660_F_NO_UDF | RTFSISO9660_F_NO_JOLIET | RTFSISO9660_F_NO_ROCK)) \ + == (~(a_fNoType) & (RTFSISO9660_F_NO_UDF | RTFSISO9660_F_NO_JOLIET | RTFSISO9660_F_NO_ROCK)) ) +/** @} */ + +/** + * Opens an ISO 9660 file system volume. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the volume. + * @param fFlags RTFSISO9660_F_XXX. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTFsIso9660VolOpen(RTVFSFILE hVfsFileIn, uint32_t fFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + + +/** + * Opens an NTFS file system volume. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the volume. + * @param fMntFlags RTVFSMNT_F_XXX. + * @param fNtfsFlags Reserved, MBZ. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTFsNtfsVolOpen(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fNtfsFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_fsvfs_h */ + diff --git a/include/iprt/ftp.h b/include/iprt/ftp.h new file mode 100644 index 00000000..8771d1d2 --- /dev/null +++ b/include/iprt/ftp.h @@ -0,0 +1,390 @@ +/* $Id: ftp.h $ */ +/** @file + * Header file for FTP client / server implementations. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ftp_h +#define IPRT_INCLUDED_ftp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_ftp RTFtp - FTP server and client. + * @ingroup grp_rt + * @{ + */ + +/** @defgroup grp_rt_ftpserver RTFtpServer - FTP server implementation. + * @{ + */ + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** FTP server handle. */ +typedef R3PTRTYPE(struct RTFTPSERVERINTERNAL *) RTFTPSERVER; +/** Pointer to a FTP server handle. */ +typedef RTFTPSERVER *PRTFTPSERVER; +/** Nil FTP client handle. */ +#define NIL_RTFTPSERVER ((RTFTPSERVER)0) + +/** Maximum length (in characters) a command can have (without parameters). */ +#define RTFTPSERVER_MAX_CMD_LEN 8 + +/** + * Enumeration for defining the current server connection mode. + */ +typedef enum RTFTPSERVER_CONNECTION_MODE +{ + /** Normal mode, nothing to transfer. */ + RTFTPSERVER_CONNECTION_MODE_NORMAL = 0, + /** Server is in passive mode (is listening). */ + RTFTPSERVER_CONNECTION_MODE_PASSIVE, + /** Server connects via port to the client. */ + RTFTPSERVER_CONNECTION_MODE_MODE_PORT, + /** The usual 32-bit hack. */ + RTFTPSERVER_CONNECTION_MODE_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_CONNECTION_MODE; + +/** + * Enumeration for defining the data transfer mode. + */ +typedef enum RTFTPSERVER_TRANSFER_MODE +{ + /** Default if nothing else is set. */ + RTFTPSERVER_TRANSFER_MODE_STREAM = 0, + RTFTPSERVER_TRANSFER_MODE_BLOCK, + RTFTPSERVER_TRANSFER_MODE_COMPRESSED, + /** The usual 32-bit hack. */ + RTFTPSERVER_DATA_MODE_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_DATA_MODE; + +/** + * Enumeration for defining the data type. + */ +typedef enum RTFTPSERVER_DATA_TYPE +{ + /** Default if nothing else is set. */ + RTFTPSERVER_DATA_TYPE_ASCII = 0, + RTFTPSERVER_DATA_TYPE_EBCDIC, + RTFTPSERVER_DATA_TYPE_IMAGE, + RTFTPSERVER_DATA_TYPE_LOCAL, + /** The usual 32-bit hack. */ + RTFTPSERVER_DATA_TYPE_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_DATA_TYPE; + +/** + * Enumeration for defining the struct type. + */ +typedef enum RTFTPSERVER_STRUCT_TYPE +{ + /** Default if nothing else is set. */ + RTFTPSERVER_STRUCT_TYPE_FILE = 0, + RTFTPSERVER_STRUCT_TYPE_RECORD, + RTFTPSERVER_STRUCT_TYPE_PAGE, + /** The usual 32-bit hack. */ + RTFTPSERVER_STRUCT_TYPE_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_STRUCT_TYPE; + +/** + * Enumeration for FTP server reply codes. + * + ** @todo Might needs more codes, not complete yet. + */ +typedef enum RTFTPSERVER_REPLY +{ + /** Invalid reply type, do not use. */ + RTFTPSERVER_REPLY_INVALID = 0, + /** Data connection already open. */ + RTFTPSERVER_REPLY_DATACONN_ALREADY_OPEN = 125, + /** Command okay. */ + RTFTPSERVER_REPLY_FILE_STS_OK_OPENING_DATA_CONN = 150, + /** Command okay. */ + RTFTPSERVER_REPLY_OKAY = 200, + /** Command not implemented, superfluous at this site. */ + RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL_SUPERFLUOUS = 202, + /** System status report. */ + RTFTPSERVER_REPLY_SYSTEM_STATUS = 211, + /** Service ready for new user. */ + RTFTPSERVER_REPLY_READY_FOR_NEW_USER = 220, + /** Service is closing control connection. */ + RTFTPSERVER_REPLY_CLOSING_CTRL_CONN = 221, + /** Closing data connection. */ + RTFTPSERVER_REPLY_CLOSING_DATA_CONN = 226, + /** Requested file action okay, completed. */ + RTFTPSERVER_REPLY_FILE_ACTION_OKAY_COMPLETED = 250, + /** "PATHNAME" ok (created / exists). */ + RTFTPSERVER_REPLY_PATHNAME_OK = 257, + /** User logged in, proceed. */ + RTFTPSERVER_REPLY_LOGGED_IN_PROCEED = 230, + /** User name okay, need password. */ + RTFTPSERVER_REPLY_USERNAME_OKAY_NEED_PASSWORD = 331, + /** Service not available, closing control connection. */ + RTFTPSERVER_REPLY_SVC_NOT_AVAIL_CLOSING_CTRL_CONN = 421, + /** Can't open data connection. */ + RTFTPSERVER_REPLY_CANT_OPEN_DATA_CONN = 425, + /** Connection closed; transfer aborted. */ + RTFTPSERVER_REPLY_CONN_CLOSED_TRANSFER_ABORTED = 426, + /** Requested file action not taken. */ + RTFTPSERVER_REPLY_CONN_REQ_FILE_ACTION_NOT_TAKEN = 450, + /** Requested action aborted; local error in processing. */ + RTFTPSERVER_REPLY_ACTION_ABORTED_LOCAL_ERROR = 451, + /** Syntax error, command unrecognized. */ + RTFTPSERVER_REPLY_ERROR_CMD_NOT_RECOGNIZED = 500, + /** Syntax error in parameters or arguments. */ + RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS = 501, + /** Command not implemented. */ + RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL = 502, + /** Bad sequence of commands. */ + RTFTPSERVER_REPLY_ERROR_BAD_SEQUENCE = 503, + /** Command not implemented for that parameter. */ + RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL_PARAM = 504, + /** Not logged in. */ + RTFTPSERVER_REPLY_NOT_LOGGED_IN = 530, + /** Requested action not taken. */ + RTFTPSERVER_REPLY_REQ_ACTION_NOT_TAKEN = 550, + /** The usual 32-bit hack. */ + RTFTPSERVER_REPLY_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_REPLY; + +/** + * Structure for maintaining a FTP server client state. + */ +typedef struct RTFTPSERVERCLIENTSTATE +{ + /** Authenticated user (name). If NULL, no user has been logged in (yet). */ + char *pszUser; + /** Current working directory. + * *Always* relative to the server's root directory (which is only is known to the actual implemenation). */ + char *pszCWD; + /** Number of failed login attempts. */ + uint8_t cFailedLoginAttempts; + /** Timestamp (in ms) of last command issued by the client. */ + uint64_t tsLastCmdMs; + /** Current set data type. */ + RTFTPSERVER_DATA_TYPE enmDataType; + /** Current set struct type. */ + RTFTPSERVER_STRUCT_TYPE enmStructType; +} RTFTPSERVERCLIENTSTATE; +/** Pointer to a FTP server client state. */ +typedef RTFTPSERVERCLIENTSTATE *PRTFTPSERVERCLIENTSTATE; + +/** + * Structure for storing FTP server callback data. + */ +typedef struct RTFTPCALLBACKDATA +{ + /** Pointer to the client state. */ + PRTFTPSERVERCLIENTSTATE pClient; + /** Saved user pointer. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} RTFTPCALLBACKDATA; +/** Pointer to FTP server callback data. */ +typedef RTFTPCALLBACKDATA *PRTFTPCALLBACKDATA; + +/** + * Function callback table for the FTP server implementation. + * + * All callbacks are optional and therefore can be NULL. + */ +typedef struct RTFTPSERVERCALLBACKS +{ + /** + * Callback which gets invoked when a user connected. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszUser User name. + */ + DECLCALLBACKMEMBER(int, pfnOnUserConnect,(PRTFTPCALLBACKDATA pData, const char *pcszUser)); + /** + * Callback which gets invoked when a user tries to authenticate with a password. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszUser User name to authenticate. + * @param pcszPassword Password to authenticate with. + */ + DECLCALLBACKMEMBER(int, pfnOnUserAuthenticate,(PRTFTPCALLBACKDATA pData, const char *pcszUser, const char *pcszPassword)); + /** + * Callback which gets invoked when a user disconnected. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszUser User name which disconnected. + */ + DECLCALLBACKMEMBER(int, pfnOnUserDisconnect,(PRTFTPCALLBACKDATA pData, const char *pcszUser)); + /** + * Callback which gets invoked when the client wants to start reading or writing a file. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcsszPath Relative path (to root directory) of file to open. + * @param fMode File mode to use (IPRT stlye). + * @param ppvHandle Opaque file handle only known to the callback implementation. + */ + DECLCALLBACKMEMBER(int, pfnOnFileOpen,(PRTFTPCALLBACKDATA pData, const char *pcszPath, uint32_t fMode, void **ppvHandle)); + /** + * Callback which gets invoked when the client wants to read from a file. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pvHandle Opaque file handle only known to the callback implementation. + * @param pvBuf Where to store the read file data. + * @param cbToRead How much (in bytes) to read. Must at least supply the size of pvBuf. + * @param pcbRead How much (in bytes) was read. Optional. + */ + DECLCALLBACKMEMBER(int, pfnOnFileRead,(PRTFTPCALLBACKDATA pData, void *pvHandle, void *pvBuf, size_t cbToRead, size_t *pcbRead)); + /** + * Callback which gets invoked when the client is done reading from or writing to a file. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param ppvHandle Opaque file handle only known to the callback implementation. + */ + DECLCALLBACKMEMBER(int, pfnOnFileClose,(PRTFTPCALLBACKDATA pData, void *pvHandle)); + /** + * Callback which gets invoked when the client wants to retrieve the size of a specific file. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszPath Relative path (to root directory) of file to retrieve size for. + * @param puSize Where to store the file size on success. + */ + DECLCALLBACKMEMBER(int, pfnOnFileGetSize,(PRTFTPCALLBACKDATA pData, const char *pcszPath, uint64_t *puSize)); + /** + * Callback which gets invoked when the client wants to retrieve information about a file. + * + * @param pData Pointer to generic callback data. + * @param pcszPath Relative path (to root directory) of file / directory to "stat". Optional. + * If NULL, the current directory will be used. + * @param pFsObjInfo Where to return the RTFSOBJINFO data on success. Optional. + * @returns VBox status code. + */ + DECLCALLBACKMEMBER(int, pfnOnFileStat,(PRTFTPCALLBACKDATA pData, const char *pcszPath, PRTFSOBJINFO pFsObjInfo)); + /** + * Callback which gets invoked when setting the current working directory. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszCWD Current working directory to set. + */ + DECLCALLBACKMEMBER(int, pfnOnPathSetCurrent,(PRTFTPCALLBACKDATA pData, const char *pcszCWD)); + /** + * Callback which gets invoked when a client wants to retrieve the current working directory. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pszPWD Where to store the current working directory. + * @param cbPWD Size of buffer in bytes. + */ + DECLCALLBACKMEMBER(int, pfnOnPathGetCurrent,(PRTFTPCALLBACKDATA pData, char *pszPWD, size_t cbPWD)); + /** + * Callback which gets invoked when the client wants to move up a directory (relative to the current working directory). + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + */ + DECLCALLBACKMEMBER(int, pfnOnPathUp,(PRTFTPCALLBACKDATA pData)); + /** + * Callback which gets invoked when the server wants to open a directory for reading. + * + * @returns VBox status code. VERR_NO_MORE_FILES if listing is complete. + * @param pData Pointer to generic callback data. + * @param pcszPath Relative path (to root directory) of file / directory to list. Optional. + * If NULL, the current directory will be listed. + * @param ppvHandle Where to return the opaque directory handle. + */ + DECLCALLBACKMEMBER(int, pfnOnDirOpen,(PRTFTPCALLBACKDATA pData, const char *pcszPath, void **ppvHandle)); + /** + * Callback which gets invoked when the server wants to close a directory handle. + * + * @returns VBox status code. VERR_NO_MORE_FILES if listing is complete. + * @param pData Pointer to generic callback data. + * @param pvHandle Directory handle to close. + */ + DECLCALLBACKMEMBER(int, pfnOnDirClose,(PRTFTPCALLBACKDATA pData, void *pvHandle)); + /** + * Callback which gets invoked when the server wants to read the next directory entry. + * + * @returns VBox status code. VERR_NO_MORE_FILES if listing is complete. + * @param pData Pointer to generic callback data. + * @param pvHandle Directory handle to use for reading. + * @param pInfo Where to store the FS object information. + * @param ppszEntry Where to return the allocated string of the entry name. + * @param ppszOwner Where to return the allocated string of the owner. + * @param ppszGroup Where to return the allocated string of the group. + * @param ppszTarget Where to return the allocated string of the target (if a link). Currently unused. + */ + DECLCALLBACKMEMBER(int, pfnOnDirRead,(PRTFTPCALLBACKDATA pData, void *pvHandle, char **ppszEntry, + PRTFSOBJINFO pInfo, char **ppszOwner, char **ppszGroup, char **ppszTarget)); +} RTFTPSERVERCALLBACKS; +/** Pointer to a FTP server callback data table. */ +typedef RTFTPSERVERCALLBACKS *PRTFTPSERVERCALLBACKS; + +/** + * Creates a FTP server instance. + * + * @returns IPRT status code. + * @param phFTPServer Where to store the FTP server handle. + * @param pcszAddress The address for creating a listening socket. + * If NULL or empty string the server is bound to all interfaces. + * @param uPort The port for creating a listening socket. + * @param pCallbacks Callback table to use. + * @param pvUser Pointer to user-specific data. Optional. + * @param cbUser Size of user-specific data. Optional. + */ +RTR3DECL(int) RTFtpServerCreate(PRTFTPSERVER phFTPServer, const char *pcszAddress, uint16_t uPort, + PRTFTPSERVERCALLBACKS pCallbacks, void *pvUser, size_t cbUser); + +/** + * Destroys a FTP server instance. + * + * @returns IPRT status code. + * @param hFTPServer Handle to the FTP server handle. + */ +RTR3DECL(int) RTFtpServerDestroy(RTFTPSERVER hFTPServer); + +/** @} */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_ftp_h */ + diff --git a/include/iprt/fuzz.h b/include/iprt/fuzz.h new file mode 100644 index 00000000..5ad6f397 --- /dev/null +++ b/include/iprt/fuzz.h @@ -0,0 +1,971 @@ +/** @file + * IPRT - Fuzzing framework + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_fuzz_h +#define IPRT_INCLUDED_fuzz_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fuzz RTFuzz - Data fuzzing framework + * @ingroup grp_rt + * @sa grp_rt_test + * @{ + */ + +/** A fuzzer context handle. */ +typedef struct RTFUZZCTXINT *RTFUZZCTX; +/** Pointer to a fuzzer context handle. */ +typedef RTFUZZCTX *PRTFUZZCTX; +/** NIL fuzzer context handle. */ +#define NIL_RTFUZZCTX ((RTFUZZCTX)~(uintptr_t)0) +/** A fuzzer input handle. */ +typedef struct RTFUZZINPUTINT *RTFUZZINPUT; +/** Pointer to a fuzzer input handle. */ +typedef RTFUZZINPUT *PRTFUZZINPUT; +/** NIL fuzzer input handle. */ +#define NIL_RTFUZZINPUT ((RTFUZZINPUT)~(uintptr_t)0) + + +/** A fuzzer config handle. */ +typedef struct RTFUZZCFGINT *RTFUZZCFG; +/** Pointer to a fuzzer config handle. */ +typedef RTFUZZCFG *PRTFUZZCFG; +/** NIL fuzzer config handle. */ +#define NIL_RTFUZZCFG ((RTFUZZCFG)~(uintptr_t)0) + + +/** A fuzzer target recorder handler. */ +typedef struct RTFUZZTGTRECINT *RTFUZZTGTREC; +/** Pointer to a fuzzer target recorder handle. */ +typedef RTFUZZTGTREC *PRTFUZZTGTREC; +/** NIL fuzzer target recorder handle. */ +#define NIL_RTFUZZTGTREC ((RTFUZZTGTREC)~(uintptr_t)0) +/** A fuzzed target state handle. */ +typedef struct RTFUZZTGTSTATEINT *RTFUZZTGTSTATE; +/** Pointer to a fuzzed target state handle. */ +typedef RTFUZZTGTSTATE *PRTFUZZTGTSTATE; +/** NIL fuzzed target state handle. */ +#define NIL_RTFUZZTGTSTATE ((RTFUZZTGTSTATE)~(uintptr_t)0) + + +/** Fuzzing observer handle. */ +typedef struct RTFUZZOBSINT *RTFUZZOBS; +/** Pointer to a fuzzing observer handle. */ +typedef RTFUZZOBS *PRTFUZZOBS; +/** NIL fuzzing observer handle. */ +#define NIL_RTFUZZOBS ((RTFUZZOBS)~(uintptr_t)0) + + +/** + * Fuzzing context type. + */ +typedef enum RTFUZZCTXTYPE +{ + /** Invalid type. */ + RTFUZZCTXTYPE_INVALID = 0, + /** Original input data is a single binary large object (BLOB), from a file or similar. */ + RTFUZZCTXTYPE_BLOB, + /** Original input data is from a data stream like a network connection. */ + RTFUZZCTXTYPE_STREAM, + /** 32bit hack. */ + RTFUZZCTXTYPE_32BIT_HACK = 0x7fffffff +} RTFUZZCTXTYPE; + + +/** + * Fuzzing context statistics. + */ +typedef struct RTFUZZCTXSTATS +{ + /** Amount of memory currently allocated. */ + size_t cbMemory; + /** Number of mutations accumulated in the corpus. */ + uint64_t cMutations; +} RTFUZZCTXSTATS; +/** Pointer to fuzzing context statistics. */ +typedef RTFUZZCTXSTATS *PRTFUZZCTXSTATS; + + +/** @name RTFUZZCTX_F_XXX - Flags for RTFuzzCtxCfgSetBehavioralFlags + * @{ */ +/** Adds all generated inputs automatically to the input corpus for the owning context. */ +#define RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS RT_BIT_32(0) +/** All valid behavioral modification flags. */ +#define RTFUZZCTX_F_BEHAVIORAL_VALID (RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS) +/** @} */ + + +/** @name RTFUZZOBS_SANITIZER_F_XXX - Flags for RTFuzzObsSetTestBinarySanitizers(). + * @{ */ +/** ASAN is compiled and enabled (observer needs to configure to abort on error to catch memory errors). */ +#define RTFUZZOBS_SANITIZER_F_ASAN UINT32_C(0x00000001) +/** A converage sanitizer is compiled in which can be used to produce coverage reports aiding in the + * fuzzing process. */ +#define RTFUZZOBS_SANITIZER_F_SANCOV UINT32_C(0x00000002) +/** @} */ + + +/** @name RTFUZZTGT_REC_STATE_F_XXX - Flags for RTFuzzTgtRecorderCreate(). + * @{ */ +/** The output from stdout is used to compare states. */ +#define RTFUZZTGT_REC_STATE_F_STDOUT RT_BIT_32(0) +/** The output from stderr is used to compare states. */ +#define RTFUZZTGT_REC_STATE_F_STDERR RT_BIT_32(1) +/** The process status is used to compare states. */ +#define RTFUZZTGT_REC_STATE_F_PROCSTATUS RT_BIT_32(2) +/** The coverage report is used to compare states. */ +#define RTFUZZTGT_REC_STATE_F_SANCOV RT_BIT_32(3) +/** Mask of all valid flags. */ +#define RTFUZZTGT_REC_STATE_F_VALID UINT32_C(0x0000000f) +/** @} */ + + +/** @name RTFUZZCFG_IMPORT_F_XXX - Flags for RTFuzzCfgImport(). + * @{ */ +/** Default flags. */ +#define RTFUZZCFG_IMPORT_F_DEFAULT 0 +/** Adds only the inputs and doesn't set any glboal configuration flags of the fuzzing context. */ +#define RTFUZZCFG_IMPORT_F_ONLY_INPUT RT_BIT_32(0) +/** Mask of all valid flags. */ +#define RTFUZZCFG_IMPORT_F_VALID UINT32_C(0x00000001) +/** @} */ + + +/** + * Fuzzing context state export callback. + * + * @returns IPRT status code. + * @param hFuzzCtx Handle of the fuzzing context. + * @param pvBuf The data to write. + * @param cbWrite Number of bytes to write. + * @param pvUser Opaque user data passed in RTFuzzCtxStateExport(). + */ +typedef DECLCALLBACKTYPE(int, FNRTFUZZCTXEXPORT,(RTFUZZCTX hFuzzCtx, const void *pvBuf, size_t cbWrite, void *pvUser)); +/** Pointer to a fuzzing context state export callback. */ +typedef FNRTFUZZCTXEXPORT *PFNRTFUZZCTXEXPORT; + +/** + * Fuzzing context state import callback. + * + * @returns IPRT status code. + * @param hFuzzCtx Handle of the fuzzing context. + * @param pvBuf Where to store the read data. + * @param cbRead Number of bytes to read. + * @param pcbRead Where to store the amount of data written, optional. + * @param pvUser Opaque user data passed in RTFuzzCtxCreateFromState(). + */ +typedef DECLCALLBACKTYPE(int, FNRTFUZZCTXIMPORT,(RTFUZZCTX hFuzzCtx, void *pvBuf, size_t cbRead, size_t *pcbRead, void *pvUser)); +/** Pointer to a fuzzing context state export callback. */ +typedef FNRTFUZZCTXIMPORT *PFNRTFUZZCTXIMPORT; + + +/** + * Creates a new fuzzing context. + * + * @returns IPRT status code. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * @param enmType Fuzzing context data type. + */ +RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx, RTFUZZCTXTYPE enmType); + +/** + * Creates a new fuzzing context from the given state. + * + * @returns IPRT status code. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * @param pfnImport State import callback. + * @param pvUser Opaque user data to pass to the callback. + */ +RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, PFNRTFUZZCTXIMPORT pfnImport, void *pvUser); + +/** + * Creates a new fuzzing context loading the state from the given memory buffer. + * + * @returns IPRT status code. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * @param pvState Pointer to the memory containing the state. + * @param cbState Size of the state buffer. + */ +RTDECL(int) RTFuzzCtxCreateFromStateMem(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState); + +/** + * Creates a new fuzzing context loading the state from the given file. + * + * @returns IPRT status code. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * @param pszFilename File to load the fuzzing context from. + */ +RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename); + +/** + * Retains a reference to the given fuzzing context. + * + * @returns New reference count on success. + * @param hFuzzCtx Handle of the fuzzing context. + */ +RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx); + +/** + * Releases a reference from the given fuzzing context, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzing context got destroyed. + * @param hFuzzCtx Handle of the fuzzing context. + */ +RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx); + +/** + * Queries statistics about the given fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx Handle of the fuzzing context. + * @param pStats Where to store the stats on success. + */ +RTDECL(int) RTFuzzCtxQueryStats(RTFUZZCTX hFuzzCtx, PRTFUZZCTXSTATS pStats); + +/** + * Exports the given fuzzing context state. + * + * @returns IPRT statuse code + * @param hFuzzCtx The fuzzing context to export. + * @param pfnExport Export callback. + * @param pvUser Opaque user data to pass to the callback. + */ +RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, PFNRTFUZZCTXEXPORT pfnExport, void *pvUser); + +/** + * Exports the given fuzzing context state to memory allocating the buffer. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context to export. + * @param ppvState Where to store the pointer to the memory containing state on success. + * Free with RTMemFree(). + * @param pcbState Where to store the size of the state in bytes. + */ +RTDECL(int) RTFuzzCtxStateExportToMem(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState); + +/** + * Exports the given fuzzing context state to the given file. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context to export. + * @param pszFilename The file to save the state to. + */ +RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename); + +/** + * Adds a new seed to the input corpus of the given fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pvInput The pointer to the input buffer. + * @param cbInput Size of the input buffer. + */ +RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput); + +/** + * Adds a new seed to the input corpus of the given fuzzing context - extended version. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pvInput The pointer to the input buffer. + * @param cbInput Size of the input buffer. + * @param offMutStart Start offset at which a mutation can happen. + * @param cbMutRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddEx(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput, + uint64_t offMutStart, uint64_t cbMutRange); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given file. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pszFilename The filename to load the seed from. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given file - extended version. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pszFilename The filename to load the seed from. + * @param offMutStart Start offset at which a mutation can happen. + * @param cbMutRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromFileEx(RTFUZZCTX hFuzzCtx, const char *pszFilename, + uint64_t offMutStart, uint64_t cbMutRange); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given VFS file. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param hVfsFile The VFS file handle to load the seed from. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given VFS file - extended version. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param hVfsFile The VFS file handle to load the seed from. + * @param offMutStart Start offset at which a mutation can happen. + * @param cbMutRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFileEx(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile, + uint64_t offMutStart, uint64_t cbMutRange); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given VFS I/O stream. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param hVfsIos The VFS I/O stream handle to load the seed from. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsIoStrm(RTFUZZCTX hFuzzCtx, RTVFSIOSTREAM hVfsIos); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given VFS I/O stream - extended version. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param hVfsIos The VFS I/O stream handle to load the seed from. + * @param offMutStart Start offset at which a mutation can happen. + * @param cbMutRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsIoStrmEx(RTFUZZCTX hFuzzCtx, RTVFSIOSTREAM hVfsIos, + uint64_t offMutStart, uint64_t cbMutRange); + +/** + * Adds new seeds to the input corpus of the given fuzzing context from the given directory. + * + * Will only process regular files, i.e. ignores directories, symbolic links, devices, fifos + * and such. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pszDirPath The directory to load seeds from. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath); + +/** + * Restricts the maximum input size to generate by the fuzzing context. + * + * @returns IPRT status code + * @param hFuzzCtx The fuzzing context handle. + * @param cbMax Maximum input size in bytes. + */ +RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax); + +/** + * Returns the maximum input size of the given fuzzing context. + * + * @returns Maximum input size generated in bytes. + * @param hFuzzCtx The fuzzing context handle. + */ +RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx); + +/** + * Sets flags controlling the behavior of the fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param fFlags Flags controlling the fuzzing context, RTFUZZCTX_F_XXX. + */ +RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags); + +/** + * Returns the current set behavioral flags for the given fuzzing context. + * + * @returns Behavioral flags of the given fuzzing context. + * @param hFuzzCtx The fuzzing context handle. + */ +RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx); + +/** + * Sets the temporary directory used by the fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pszPathTmp The directory for the temporary state. + */ +RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp); + +/** + * Returns the current temporary directory. + * + * @returns Current temporary directory. + * @param hFuzzCtx The fuzzing context handle. + */ +RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx); + +/** + * Sets the range in which a particular input can get mutated. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param offStart Start offset at which a mutation can happen. + * @param cbRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCfgSetMutationRange(RTFUZZCTX hFuzzCtx, uint64_t offStart, uint64_t cbRange); + +/** + * Reseeds the PRNG of the given fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param uSeed The new seed. + */ +RTDECL(int) RTFuzzCtxReseed(RTFUZZCTX hFuzzCtx, uint64_t uSeed); + +/** + * Generates a new input from the given fuzzing context and returns it. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param phFuzzInput Where to store the handle to the fuzzed input on success. + */ +RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput); + + +/** + * Retains a reference to the given fuzzing input handle. + * + * @returns New reference count on success. + * @param hFuzzInput The fuzzing input handle. + */ +RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput); + +/** + * Releases a reference from the given fuzzing input handle, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzing input got destroyed. + * @param hFuzzInput The fuzzing input handle. + */ +RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput); + +/** + * Queries the data pointer and size of the given fuzzed input blob. + * + * @returns IPRT status code + * @param hFuzzInput The fuzzing input handle. + * @param ppv Where to store the pointer to the input data on success. + * @param pcb Where to store the size of the input data on success. + */ +RTDECL(int) RTFuzzInputQueryBlobData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb); + +/** + * Processes the given data stream for a streamed fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzInput The fuzzing input handle. + * @param pvBuf The data buffer. + * @param cbBuf Size of the buffer. + */ +RTDECL(int) RTFuzzInputMutateStreamData(RTFUZZINPUT hFuzzInput, void *pvBuf, size_t cbBuf); + +/** + * Queries the string of the MD5 digest for the given fuzzed input. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the size of the string buffer is not sufficient. + * @param hFuzzInput The fuzzing input handle. + * @param pszDigest Where to store the digest string and a closing terminator. + * @param cchDigest Size of the string buffer in characters (including the zero terminator). + */ +RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest); + +/** + * Writes the given fuzzing input to the given file. + * + * @returns IPRT status code. + * @param hFuzzInput The fuzzing input handle. + * @param pszFilename The filename to store the input to. + */ +RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename); + +/** + * Adds the given fuzzed input to the input corpus of the owning context. + * + * @returns IPRT status code. + * @retval VERR_ALREADY_EXISTS if the input exists already. + * @param hFuzzInput The fuzzing input handle. + */ +RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput); + +/** + * Removes the given fuzzed input from the input corpus of the owning context. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the input is not part of the corpus. + * @param hFuzzInput The fuzzing input handle. + */ +RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput); + + +/** + * Creates a fuzzing config from the given VFS file handle. + * + * @returns IPRT status code. + * @param phFuzzCfg Where to store the handle to the fuzzing config on success. + * @param hVfsFile The VFS file to use (retained). + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTFuzzCfgCreateFromVfsFile(PRTFUZZCFG phFuzzCfg, RTVFSFILE hVfsFile, PRTERRINFO pErrInfo); + +/** + * Creates a fuzzing config from the given file path. + * + * @returns IPRT status code. + * @param phFuzzCfg Where to store the handle to the fuzzing config on success. + * @param pszFilename Filename to load the config from. + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTFuzzCfgCreateFromFile(PRTFUZZCFG phFuzzCfg, const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Retains a reference to the given fuzzing config. + * + * @returns New reference count on success. + * @param hFuzzCfg Handle of the fuzzing config. + */ +RTDECL(uint32_t) RTFuzzCfgRetain(RTFUZZCFG hFuzzCfg); + +/** + * Releases a reference from the given fuzzing config, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzing config got destroyed. + * @param hFuzzCfg Handle of the fuzzing config. + */ +RTDECL(uint32_t) RTFuzzCfgRelease(RTFUZZCFG hFuzzCfg); + +/** + * Imports the given fuzzing config into a previously created fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCfg Handle of the fuzzing config. + * @param hFuzzCtx Handle of the fuzzing context. + * @param fFlags Flags controlling what to import exactly, combination of RTFUZZCFG_IMPORT_F_XXX. + */ +RTDECL(int) RTFuzzCfgImport(RTFUZZCFG hFuzzCfg, RTFUZZCTX hFuzzCtx, uint32_t fFlags); + +/** + * Queries the custom config for the controller of the fuzzing process. + * + * @returns IPRT status code. + * @param hFuzzCfg Handle of the fuzzing config. + * @param phVfsFile Where to store the handle of the VFS file containing the custom config. + */ +RTDECL(int) RTFuzzCfgQueryCustomCfg(RTFUZZCFG hFuzzCfg, PRTVFSFILE phVfsFile); + + +/** + * Creates a new fuzzed target recorder. + * + * @returns IPRT status code. + * @param phFuzzTgtRec Where to store the handle to the fuzzed target recorder on success. + * @param fRecFlags What to take into account when checking for equal states. + * Combination of RTFUZZTGT_REC_STATE_F_* + */ +RTDECL(int) RTFuzzTgtRecorderCreate(PRTFUZZTGTREC phFuzzTgtRec, uint32_t fRecFlags); + +/** + * Retains a reference to the given fuzzed target recorder handle. + * + * @returns New reference count on success. + * @param hFuzzTgtRec The fuzzed target recorder handle. + */ +RTDECL(uint32_t) RTFuzzTgtRecorderRetain(RTFUZZTGTREC hFuzzTgtRec); + +/** + * Releases a reference from the given fuzzed target recorder handle, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzed target recorder got destroyed. + * @param hFuzzTgtRec The fuzzed target recorder handle. + */ +RTDECL(uint32_t) RTFuzzTgtRecorderRelease(RTFUZZTGTREC hFuzzTgtRec); + +/** + * Creates a new empty fuzzed target state. + * + * @returns IPRT status code. + * @param hFuzzTgtRec The fuzzed target recorder handle. + * @param phFuzzTgtState Where to store the handle to the fuzzed target state on success. + */ +RTDECL(int) RTFuzzTgtRecorderCreateNewState(RTFUZZTGTREC hFuzzTgtRec, PRTFUZZTGTSTATE phFuzzTgtState); + +/** + * Retains a reference to the given fuzzed target state handle. + * + * @returns New reference count on success. + * @param hFuzzTgtState The fuzzed target state handle. + */ +RTDECL(uint32_t) RTFuzzTgtStateRetain(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Releases a reference from the given fuzzed target state handle, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzed target recorder got destroyed. + * @param hFuzzTgtState The fuzzed target state handle. + */ +RTDECL(uint32_t) RTFuzzTgtStateRelease(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Resets the given fuzzed target state to an empty state (keeping allocated memory). + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * + * @note Useful when the state is not added to the recorded set to avoid allocating memory. + */ +RTDECL(int) RTFuzzTgtStateReset(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Finalizes the given fuzzed target state, making it readonly. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + */ +RTDECL(int) RTFuzzTgtStateFinalize(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Adds the given state to the set for the owning target recorder. + * + * @returns IPRT status code. + * @retval VERR_ALREADY_EXISTS if the state is already existing in the recorder set. + * @param hFuzzTgtState The fuzzed target state handle. + * + * @note This also finalizes the target state if not already done. + */ +RTDECL(int) RTFuzzTgtStateAddToRecorder(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Appends the given stdout output to the given target state. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pvStdOut Pointer to the stdout data buffer. + * @param cbStdOut Size of the stdout data buffer in bytes. + */ +RTDECL(int) RTFuzzTgtStateAppendStdoutFromBuf(RTFUZZTGTSTATE hFuzzTgtState, const void *pvStdOut, size_t cbStdOut); + +/** + * Appends the given stderr output to the given target state. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pvStdErr Pointer to the stderr data buffer. + * @param cbStdErr Size of the stderr data buffer in bytes. + */ +RTDECL(int) RTFuzzTgtStateAppendStderrFromBuf(RTFUZZTGTSTATE hFuzzTgtState, const void *pvStdErr, size_t cbStdErr); + +/** + * Appends the given stdout output to the given target state, reading from the given pipe. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param hPipe The stdout pipe to read the data from. + */ +RTDECL(int) RTFuzzTgtStateAppendStdoutFromPipe(RTFUZZTGTSTATE hFuzzTgtState, RTPIPE hPipe); + +/** + * Appends the given stderr output to the given target state, reading from the given pipe. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param hPipe The stdout pipe to read the data from. + */ +RTDECL(int) RTFuzzTgtStateAppendStderrFromPipe(RTFUZZTGTSTATE hFuzzTgtState, RTPIPE hPipe); + +/** + * Adds the SanCov coverage information from the given file to the given target state. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pszFilename Filename of the coverage report. + */ +RTDECL(int) RTFuzzTgtStateAddSanCovReportFromFile(RTFUZZTGTSTATE hFuzzTgtState, const char *pszFilename); + +/** + * Adds the given process status to the target state. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pProcSts The process status to add. + */ +RTDECL(int) RTFuzzTgtStateAddProcSts(RTFUZZTGTSTATE hFuzzTgtState, PCRTPROCSTATUS pProcSts); + +/** + * Dumps the given target state to the given directory. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pszDirPath The directory to dump to. + */ +RTDECL(int) RTFuzzTgtStateDumpToDir(RTFUZZTGTSTATE hFuzzTgtState, const char *pszDirPath); + + +/** + * Fuzzed binary input channel. + */ +typedef enum RTFUZZOBSINPUTCHAN +{ + /** Invalid. */ + RTFUZZOBSINPUTCHAN_INVALID = 0, + /** File input. */ + RTFUZZOBSINPUTCHAN_FILE, + /** Input over stdin. */ + RTFUZZOBSINPUTCHAN_STDIN, + /** The binary is a fuzzing aware client using the + * specified protocol over stdin/stdout. */ + RTFUZZOBSINPUTCHAN_FUZZING_AWARE_CLIENT, + /** TCP server. */ + RTFUZZOBSINPUTCHAN_TCP_SERVER, + /** TCP client. */ + RTFUZZOBSINPUTCHAN_TCP_CLIENT, + /** UDP server. */ + RTFUZZOBSINPUTCHAN_UDP_SERVER, + /** UDP client. */ + RTFUZZOBSINPUTCHAN_UDP_CLIENT, + /** 32bit hack. */ + RTFUZZOBSINPUTCHAN_32BIT_HACK = 0x7fffffff +} RTFUZZOBSINPUTCHAN; + +/** + * Fuzzing observer statistics. + */ +typedef struct RTFUZZOBSSTATS +{ + /** Number of fuzzed inputs per second. */ + uint32_t cFuzzedInputsPerSec; + /** Number of overall fuzzed inputs. */ + uint32_t cFuzzedInputs; + /** Number of observed hangs. */ + uint32_t cFuzzedInputsHang; + /** Number of observed crashes. */ + uint32_t cFuzzedInputsCrash; +} RTFUZZOBSSTATS; +/** Pointer to a fuzzing observer statistics record. */ +typedef RTFUZZOBSSTATS *PRTFUZZOBSSTATS; + +/** + * Creates a new fuzzing observer. + * + * @returns IPRT status code. + * @param phFuzzObs Where to store the fuzzing observer handle on success. + * @param enmType Fuzzing context data type. + * @param fTgtRecFlags Flags to pass to the target state recorder, see RTFuzzTgtRecorderCreate(). + */ +RTDECL(int) RTFuzzObsCreate(PRTFUZZOBS phFuzzObs, RTFUZZCTXTYPE enmType, uint32_t fTgtRecFlags); + +/** + * Destroys a previously created fuzzing observer. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + */ +RTDECL(int) RTFuzzObsDestroy(RTFUZZOBS hFuzzObs); + +/** + * Queries the internal fuzzing context of the given observer. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * + * @note The fuzzing context handle should be released with RTFuzzCtxRelease() when not used anymore. + */ +RTDECL(int) RTFuzzObsQueryCtx(RTFUZZOBS hFuzzObs, PRTFUZZCTX phFuzzCtx); + +/** + * Queries the current statistics for the given fuzzing observer. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param pStats Where to store the statistics to. + */ +RTDECL(int) RTFuzzObsQueryStats(RTFUZZOBS hFuzzObs, PRTFUZZOBSSTATS pStats); + +/** + * Sets the temp directory for the given fuzzing observer. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param pszTmp The temp directory path. + */ +RTDECL(int) RTFuzzObsSetTmpDirectory(RTFUZZOBS hFuzzObs, const char *pszTmp); + +/** + * Sets the directory to store results to. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param pszResults The path to store the results. + */ +RTDECL(int) RTFuzzObsSetResultDirectory(RTFUZZOBS hFuzzObs, const char *pszResults); + +/** + * Sets the binary to run for each fuzzed input. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param pszBinary The binary path. + * @param enmInputChan The input channel to use. + */ +RTDECL(int) RTFuzzObsSetTestBinary(RTFUZZOBS hFuzzObs, const char *pszBinary, RTFUZZOBSINPUTCHAN enmInputChan); + +/** + * Sets additional arguments to run the binary with. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param papszArgs Pointer to the array of arguments. + * @param cArgs Number of arguments. + */ +RTDECL(int) RTFuzzObsSetTestBinaryArgs(RTFUZZOBS hFuzzObs, const char * const *papszArgs, unsigned cArgs); + +/** + * Sets an environment block to run the binary in. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param hEnv The environment block to set for the test binary. + * Use RTENV_DEFAULT for the default process environment or + * NULL for an empty environment. + * + * @note Upon successful return of this function the observer has taken ownership over the + * environment block and can alter it in unexpected ways. It also destroys the environment + * block when the observer gets destroyed. So don't touch the environment block after + * calling this function. + */ +RTDECL(int) RTFuzzObsSetTestBinaryEnv(RTFUZZOBS hFuzzObs, RTENV hEnv); + +/** + * Makes the observer aware of any configured sanitizers for the test binary. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param fSanitizers Bitmask of compiled and enabled sanitiziers in the + * target binary. + */ +RTDECL(int) RTFuzzObsSetTestBinarySanitizers(RTFUZZOBS hFuzzObs, uint32_t fSanitizers); + +/** + * Sets maximum timeout until a process is considered hung and killed. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param msTimeoutMax The maximum number of milliseconds to wait until the process + * is considered hung. + */ +RTDECL(int) RTFuzzObsSetTestBinaryTimeout(RTFUZZOBS hFuzzObs, RTMSINTERVAL msTimeoutMax); + +/** + * Starts fuzzing the set binary. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param cProcs Number of processes to run simulteanously, + * 0 will create as many processes as there are CPUs available. + */ +RTDECL(int) RTFuzzObsExecStart(RTFUZZOBS hFuzzObs, uint32_t cProcs); + +/** + * Stops the fuzzing process. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + */ +RTDECL(int) RTFuzzObsExecStop(RTFUZZOBS hFuzzObs); + + +/** + * A fuzzing master program. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTR3DECL(RTEXITCODE) RTFuzzCmdMaster(unsigned cArgs, char **papszArgs); + + +/** + * Client input consumption callback. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS the fuzzed code accepted the input. + * @retval VERR_* the client rejected the input while parsing it. + * @param pvBuf The buffer containing the input data. + * @param cbBuf Size of the buffer in bytes. + * @param pvUser Opaque user data. + */ +typedef DECLCALLBACKTYPE(int, FNFUZZCLIENTCONSUME,(const void *pvBuf, size_t cbBuf, void *pvUser)); +/** Pointer to a client consumption callback. */ +typedef FNFUZZCLIENTCONSUME *PFNFUZZCLIENTCONSUME; + +/** + * A fuzzing client program for more efficient fuzzing. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + * @param pfnConsume Input data consumption callback. + * @param pvUser Opaque user data to pass to the callback. + */ +RTR3DECL(RTEXITCODE) RTFuzzCmdFuzzingClient(unsigned cArgs, char **papszArgs, PFNFUZZCLIENTCONSUME pfnConsume, void *pvUser); +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_fuzz_h */ + diff --git a/include/iprt/getopt.h b/include/iprt/getopt.h new file mode 100644 index 00000000..57a2bbcf --- /dev/null +++ b/include/iprt/getopt.h @@ -0,0 +1,564 @@ +/** @file + * IPRT - Command Line Parsing. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_getopt_h +#define IPRT_INCLUDED_getopt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#include +#include /* for VINF_GETOPT_NOT_OPTION */ + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_getopt RTGetOpt - Command Line Parsing + * @ingroup grp_rt + * @{ + */ + +/** @name Values for RTGETOPTDEF::fFlags and the fFlags parameter of + * RTGetOptFetchValue. + * + * @remarks When neither of the RTGETOPT_FLAG_HEX, RTGETOPT_FLAG_OCT and RTGETOPT_FLAG_DEC + * flags are specified with a integer value format, RTGetOpt will default to + * decimal but recognize the 0x prefix when present. RTGetOpt will not look for + * for the octal prefix (0). + * @{ */ +/** Requires no extra argument. + * (Can be assumed to be 0 for ever.) */ +#define RTGETOPT_REQ_NOTHING 0 +/** A value is required or error will be returned. */ +#define RTGETOPT_REQ_STRING 1 +/** The value must be a valid signed 8-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_INT8 2 +/** The value must be a valid unsigned 8-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_UINT8 3 +/** The value must be a valid signed 16-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_INT16 4 +/** The value must be a valid unsigned 16-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_UINT16 5 +/** The value must be a valid signed 32-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_INT32 6 +/** The value must be a valid unsigned 32-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_UINT32 7 +/** The value must be a valid signed 64-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_INT64 8 +/** The value must be a valid unsigned 64-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_UINT64 9 +/** The value must be a valid IPv4 address. + * (Not a name, but 4 values in the 0..255 range with dots separating them). */ +#define RTGETOPT_REQ_IPV4ADDR 10 +/** The value must be a valid IPv4 CIDR. + * As with RTGETOPT_REQ_IPV4ADDR, no name. + */ +#define RTGETOPT_REQ_IPV4CIDR 11 +#if 0 +/* take placers */ +/** The value must be a valid IPv6 addr + * @todo: Add types and parsing routines in (iprt/net.h) + */ +#define RTGETOPT_REQ_IPV6ADDR 12 +/** The value must be a valid IPv6 CIDR + * @todo: Add types and parsing routines in (iprt/net.h) + */ +#define RTGETOPT_REQ_IPV6CIDR 13 +#endif +/** The value must be a valid ethernet MAC address. */ +#define RTGETOPT_REQ_MACADDR 14 +/** The value must be a valid UUID. */ +#define RTGETOPT_REQ_UUID 15 +/** The value must be a string with value as "on" or "off". */ +#define RTGETOPT_REQ_BOOL_ONOFF 16 +/** Boolean option accepting a wide range of typical ways of + * expression true and false. */ +#define RTGETOPT_REQ_BOOL 17 +/** The value must two unsigned 32-bit integer values separated by a colon, + * slash, pipe or space(s). */ +#define RTGETOPT_REQ_UINT32_PAIR 18 +/** The value must two unsigned 64-bit integer values separated by a colon, + * slash, pipe or space(s). */ +#define RTGETOPT_REQ_UINT64_PAIR 19 +/** The value must at least unsigned 32-bit integer value, optionally + * followed by a second separated by a colon, slash, pipe or space(s). */ +#define RTGETOPT_REQ_UINT32_OPTIONAL_PAIR 20 +/** The value must at least unsigned 64-bit integer value, optionally + * followed by a second separated by a colon, slash, pipe or space(s). */ +#define RTGETOPT_REQ_UINT64_OPTIONAL_PAIR 21 +/** The mask of the valid required types. */ +#define RTGETOPT_REQ_MASK 31 +/** Treat the value as hexadecimal - only applicable with the RTGETOPT_REQ_*INT*. */ +#define RTGETOPT_FLAG_HEX RT_BIT(16) +/** Treat the value as octal - only applicable with the RTGETOPT_REQ_*INT*. */ +#define RTGETOPT_FLAG_OCT RT_BIT(17) +/** Treat the value as decimal - only applicable with the RTGETOPT_REQ_*INT*. */ +#define RTGETOPT_FLAG_DEC RT_BIT(18) +/** The index value is attached to the argument - only valid for long arguments. */ +#define RTGETOPT_FLAG_INDEX RT_BIT(19) +/** Used with RTGETOPT_FLAG_INDEX, setting index to zero if none given. + * (The default is to fail with VERR_GETOPT_INDEX_MISSING.) */ +#define RTGETOPT_FLAG_INDEX_DEF_0 RT_BIT(20) +/** Used with RTGETOPT_FLAG_INDEX, setting index to one if none given. + * (The default is to fail with VERR_GETOPT_INDEX_MISSING.) */ +#define RTGETOPT_FLAG_INDEX_DEF_1 RT_BIT(21) +/** For simplicity. */ +#define RTGETOPT_FLAG_INDEX_DEF_MASK (RT_BIT(20) | RT_BIT(21)) +/** For simple conversion. */ +#define RTGETOPT_FLAG_INDEX_DEF_SHIFT 20 +/** For use with RTGETOPT_FLAG_INDEX_DEF_0 or RTGETOPT_FLAG_INDEX_DEF_1 to + * imply a dash before the index when a digit is specified. + * This is for transitioning from options without index to optionally allow + * index options, i.e. "--long" defaults to either index 1 or 1 using the above + * flags, while "--long-1" explicitly gives the index ("--long-" is not valid). + * This flag matches an "-" separating the "--long" string + * (RTGETOPTDEFS::pszLong) from the index value. */ +#define RTGETOPT_FLAG_INDEX_DEF_DASH RT_BIT(22) +/** Treat the long option as case insensitive. */ +#define RTGETOPT_FLAG_ICASE RT_BIT(23) +/** Mask of valid bits - for validation. */ +#define RTGETOPT_VALID_MASK ( RTGETOPT_REQ_MASK \ + | RTGETOPT_FLAG_HEX \ + | RTGETOPT_FLAG_OCT \ + | RTGETOPT_FLAG_DEC \ + | RTGETOPT_FLAG_INDEX \ + | RTGETOPT_FLAG_INDEX_DEF_0 \ + | RTGETOPT_FLAG_INDEX_DEF_1 \ + | RTGETOPT_FLAG_INDEX_DEF_DASH \ + | RTGETOPT_FLAG_ICASE ) +/** @} */ + +/** + * An option definition. + */ +typedef struct RTGETOPTDEF +{ + /** The long option. + * This is optional */ + const char *pszLong; + /** The short option character. + * This doesn't have to be a character, it may also be a \#define or enum value if + * there isn't any short version of this option. Must be greater than 0. */ + int iShort; + /** The flags (RTGETOPT_*). */ + unsigned fFlags; +} RTGETOPTDEF; +/** Pointer to an option definition. */ +typedef RTGETOPTDEF *PRTGETOPTDEF; +/** Pointer to an const option definition. */ +typedef const RTGETOPTDEF *PCRTGETOPTDEF; + +/** + * Option argument union. + * + * What ends up here depends on argument format in the option definition. + */ +typedef union RTGETOPTUNION +{ + /** Pointer to the definition on failure or when the option doesn't take an argument. + * This can be NULL for some errors. */ + PCRTGETOPTDEF pDef; + /** A RTGETOPT_REQ_STRING option argument. */ + const char *psz; + + /** A RTGETOPT_REQ_INT8 option argument. */ + int8_t i8; + /** A RTGETOPT_REQ_UINT8 option argument . */ + uint8_t u8; + /** A RTGETOPT_REQ_INT16 option argument. */ + int16_t i16; + /** A RTGETOPT_REQ_UINT16 option argument . */ + uint16_t u16; + /** A RTGETOPT_REQ_INT16 option argument. */ + int32_t i32; + /** A RTGETOPT_REQ_UINT32 option argument . */ + uint32_t u32; + /** A RTGETOPT_REQ_INT64 option argument. */ + int64_t i64; + /** A RTGETOPT_REQ_UINT64 option argument. */ + uint64_t u64; +#ifdef IPRT_INCLUDED_net_h + /** A RTGETOPT_REQ_IPV4ADDR option argument. */ + RTNETADDRIPV4 IPv4Addr; + /** A RTGETOPT_REQ_IPV4CIDR option argument. */ + struct + { + RTNETADDRIPV4 IPv4Network; + RTNETADDRIPV4 IPv4Netmask; + } CidrIPv4; +#endif + /** A RTGETOPT_REQ_MACADDR option argument. */ + RTMAC MacAddr; + /** A RTGETOPT_REQ_UUID option argument. */ + RTUUID Uuid; + /** A boolean flag. */ + bool f; + /** A RTGETOPT_REQ_UINT32_PAIR or RTGETOPT_REQ_UINT32_OPTIONAL_PAIR option + * argument. */ + struct + { + uint32_t uFirst; + uint32_t uSecond; /**< Set to UINT32_MAX if optional and not present. */ + } PairU32; + /** A RTGETOPT_REQ_UINT64_COLON_PAIR option argument. */ + struct + { + uint64_t uFirst; + uint64_t uSecond; /**< Set to UINT64_MAX if optional and not present. */ + } PairU64; +} RTGETOPTUNION; +/** Pointer to an option argument union. */ +typedef RTGETOPTUNION *PRTGETOPTUNION; +/** Pointer to a const option argument union. */ +typedef RTGETOPTUNION const *PCRTGETOPTUNION; + + +/** + * RTGetOpt state. + */ +typedef struct RTGETOPTSTATE +{ + /** The next argument. */ + int iNext; + /** Argument array. */ + char **argv; + /** Number of items in argv. */ + int argc; + /** Option definition array. */ + PCRTGETOPTDEF paOptions; + /** Number of items in paOptions. */ + size_t cOptions; + /** The next short option. + * (For parsing ls -latrT4 kind of option lists.) */ + const char *pszNextShort; + /** The option definition which matched. NULL otherwise. */ + PCRTGETOPTDEF pDef; + /** The index of an index option, otherwise UINT32_MAX. */ + uint32_t uIndex; + /** The flags passed to RTGetOptInit. */ + uint32_t fFlags; + /** Number of non-options that we're skipping during a sorted get. The value + * INT32_MAX is used to indicate that there are no more options. This is used + * to implement '--'. */ + int32_t cNonOptions; + + /* More members may be added later for dealing with new features. */ +} RTGETOPTSTATE; +/** Pointer to RTGetOpt state. */ +typedef RTGETOPTSTATE *PRTGETOPTSTATE; + + +/** + * Initialize the RTGetOpt state. + * + * The passed in argument vector may be sorted if fFlags indicates that this is + * desired (to be implemented). + * + * @returns VINF_SUCCESS, VERR_INVALID_PARAMETER or VERR_INVALID_POINTER. + * @param pState The state. + * + * @param argc Argument count, to be copied from what comes in with + * main(). + * @param argv Argument array, to be copied from what comes in with + * main(). This may end up being modified by the + * option/argument sorting. + * @param paOptions Array of RTGETOPTDEF structures, which must specify what + * options are understood by the program. + * @param cOptions Number of array items passed in with paOptions. + * @param iFirst The argument to start with (in argv). + * @param fFlags The flags, see RTGETOPTINIT_FLAGS_XXX. + */ +RTDECL(int) RTGetOptInit(PRTGETOPTSTATE pState, int argc, char **argv, + PCRTGETOPTDEF paOptions, size_t cOptions, + int iFirst, uint32_t fFlags); + +/** @name RTGetOptInit flags. + * @{ */ +/** Sort the arguments so that options comes first, then non-options. */ +#define RTGETOPTINIT_FLAGS_OPTS_FIRST RT_BIT_32(0) +/** Prevent add the standard version and help options: + * - "--help", "-h" and "-?" returns 'h'. + * - "--version" and "-V" return 'V'. + */ +#define RTGETOPTINIT_FLAGS_NO_STD_OPTS RT_BIT_32(1) +/** @} */ + +/** + * Command line argument parser, handling both long and short options and checking + * argument formats, if desired. + * + * This is to be called in a loop until it returns 0 (meaning that all options + * were parsed) or a negative value (meaning that an error occurred). How non-option + * arguments are dealt with depends on the flags passed to RTGetOptInit. The default + * (fFlags = 0) is to return VINF_GETOPT_NOT_OPTION with pValueUnion->psz pointing to + * the argument string. + * + * For example, for a program which takes the following options: + * + * --optwithstring (or -s) and a string argument; + * --optwithint (or -i) and a 32-bit signed integer argument; + * --verbose (or -v) with no arguments, + * + * code would look something like this: + * + * @code +int main(int argc, char **argv) +{ + int rc = RTR3Init(); + if (RT_FAILURE(rc)) + return RTMsgInitFailure(rc); + + static const RTGETOPTDEF s_aOptions[] = + { + { "--optwithstring", 's', RTGETOPT_REQ_STRING }, + { "--optwithint", 'i', RTGETOPT_REQ_INT32 }, + { "--verbose", 'v', 0 }, + }; + + int ch; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); + while ((ch = RTGetOpt(&GetState, &ValueUnion))) + { + // for options that require an argument, ValueUnion has received the value + switch (ch) + { + case 's': // --optwithstring or -s + // string argument, copy ValueUnion.psz + break; + + case 'i': // --optwithint or -i + // integer argument, copy ValueUnion.i32 + break; + + case 'v': // --verbose or -v + g_fOptVerbose = true; + break; + + case VINF_GETOPT_NOT_OPTION: + // handle non-option argument in ValueUnion.psz. + break; + + default: + return RTGetOptPrintError(ch, &ValueUnion); + } + } + + return RTEXITCODE_SUCCESS; +} + @endcode + * + * @returns 0 when done parsing. + * @returns the iShort value of the option. pState->pDef points to the option + * definition which matched. + * @returns IPRT error status on parse error. + * @returns VINF_GETOPT_NOT_OPTION when encountering a non-option argument and + * RTGETOPTINIT_FLAGS_OPTS_FIRST was not specified. pValueUnion->psz + * points to the argument string. + * @returns VERR_GETOPT_UNKNOWN_OPTION when encountering an unknown option. + * pValueUnion->psz points to the option string. + * @returns VERR_GETOPT_REQUIRED_ARGUMENT_MISSING and pValueUnion->pDef if + * a required argument (aka value) was missing for an option. + * @returns VERR_GETOPT_INVALID_ARGUMENT_FORMAT and pValueUnion->pDef if + * argument (aka value) conversion failed. + * + * @param pState The state previously initialized with RTGetOptInit. + * @param pValueUnion Union with value; in the event of an error, psz member + * points to erroneous parameter; otherwise, for options + * that require an argument, this contains the value of + * that argument, depending on the type that is required. + */ +RTDECL(int) RTGetOpt(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion); + +/** + * Fetch a value. + * + * Used to retrive a value argument in a manner similar to what RTGetOpt does + * (@a fFlags -> @a pValueUnion). This can be used when handling + * VINF_GETOPT_NOT_OPTION, but is equally useful for decoding options that + * takes more than one value. + * + * @returns VINF_SUCCESS on success. + * @returns IPRT error status on parse error. + * @returns VERR_INVALID_PARAMETER if the flags are wrong. + * @returns VERR_GETOPT_UNKNOWN_OPTION when pState->pDef is null. + * @returns VERR_GETOPT_REQUIRED_ARGUMENT_MISSING if there are no more + * available arguments. pValueUnion->pDef is NULL. + * @returns VERR_GETOPT_INVALID_ARGUMENT_FORMAT and pValueUnion->pDef is + * unchanged if value conversion failed. + * + * @param pState The state previously initialized with RTGetOptInit. + * @param pValueUnion Union with value; in the event of an error, psz member + * points to erroneous parameter; otherwise, for options + * that require an argument, this contains the value of + * that argument, depending on the type that is required. + * @param fFlags What to get, that is RTGETOPT_REQ_XXX. + */ +RTDECL(int) RTGetOptFetchValue(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion, uint32_t fFlags); + +/** + * Gets the pointer to the argv entry of the current non-option argument. + * + * This function ASSUMES the previous RTGetOpt() call returned + * VINF_GETOPT_NOT_OPTION and require RTGETOPTINIT_FLAGS_OPTS_FIRST to be + * specified to RTGetOptInit(). + * + * @returns Pointer to the argv entry of the current non-option. NULL if + * (detectable) precondition isn't fullfilled (asserted) + * @param pState The state previously initialized with RTGetOptInit. + */ +RTDECL(char **) RTGetOptNonOptionArrayPtr(PRTGETOPTSTATE pState); + +/** + * Print error messages for a RTGetOpt default case. + * + * Uses RTMsgError. + * + * @returns Suitable exit code. + * + * @param ch The RTGetOpt return value. + * @param pValueUnion The value union returned by RTGetOpt. + */ +RTDECL(RTEXITCODE) RTGetOptPrintError(int ch, PCRTGETOPTUNION pValueUnion); + +/** + * Formats error messages for a RTGetOpt default case. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). (RTStrPrintf2 style.) + * + * @param pszBuf The buffer to format into. + * @param cbBuf The size of the buffer @a pszBuf points to. + * @param ch The RTGetOpt return value. + * @param pValueUnion The value union returned by RTGetOpt. + */ +RTDECL(ssize_t) RTGetOptFormatError(char *pszBuf, size_t cbBuf, int ch, PCRTGETOPTUNION pValueUnion); + +/** + * Parses the @a pszCmdLine string into an argv array. + * + * This is useful for converting a response file or similar to an argument + * vector that can be used with RTGetOptInit(). + * + * This function aims at following the bourne shell string quoting rules. + * + * @returns IPRT status code. + * + * @param ppapszArgv Where to return the argument vector. This must be + * freed by calling RTGetOptArgvFreeEx or + * RTGetOptArgvFree. + * @param pcArgs Where to return the argument count. + * @param pszCmdLine The string to parse. + * @param fFlags A combination of the RTGETOPTARGV_CNV_XXX flags, + * except RTGETOPTARGV_CNV_UNQUOTED is not supported. + * @param pszSeparators String containing the argument separators. If NULL, + * then space, tab, line feed (\\n) and return (\\r) + * are used. + */ +RTDECL(int) RTGetOptArgvFromString(char ***ppapszArgv, int *pcArgs, const char *pszCmdLine, uint32_t fFlags, + const char *pszSeparators); + +/** + * Frees and argument vector returned by RTGetOptStringToArgv. + * + * @param papszArgv Argument vector. NULL is fine. + */ +RTDECL(void) RTGetOptArgvFree(char **papszArgv); + +/** + * Frees and argument vector returned by RTGetOptStringToArgv, taking + * RTGETOPTARGV_CNV_MODIFY_INPUT into account. + * + * @param papszArgv Argument vector. NULL is fine. + * @param fFlags The flags passed to RTGetOptStringToArgv. + */ +RTDECL(void) RTGetOptArgvFreeEx(char **papszArgv, uint32_t fFlags); + +/** + * Turns an argv array into a command line string. + * + * This is useful for calling CreateProcess on Windows, but can also be used for + * displaying an argv array. + * + * This function aims at following the bourn shell string quoting rules. + * + * @returns IPRT status code. + * + * @param ppszCmdLine Where to return the command line string. This must + * be freed by calling RTStrFree. + * @param papszArgv The argument vector to convert. + * @param fFlags A combination of the RTGETOPTARGV_CNV_XXX flags. + */ +RTDECL(int) RTGetOptArgvToString(char **ppszCmdLine, const char * const *papszArgv, uint32_t fFlags); + +/** @name RTGetOptArgvToString, RTGetOptArgvToUtf16String and + * RTGetOptArgvFromString flags + * @{ */ +/** Quote strings according to the Microsoft CRT rules. */ +#define RTGETOPTARGV_CNV_QUOTE_MS_CRT UINT32_C(0x00000000) +/** Quote strings according to the Unix Bourne Shell. */ +#define RTGETOPTARGV_CNV_QUOTE_BOURNE_SH UINT32_C(0x00000001) +/** Don't quote any strings at all. */ +#define RTGETOPTARGV_CNV_UNQUOTED UINT32_C(0x00000002) +/** Mask for the quoting style. */ +#define RTGETOPTARGV_CNV_QUOTE_MASK UINT32_C(0x00000003) +/** Allow RTGetOptArgvFromString to modifying the command line input string. + * @note Must use RTGetOptArgvFreeEx to free. */ +#define RTGETOPTARGV_CNV_MODIFY_INPUT UINT32_C(0x00000004) +/** Valid bits. */ +#define RTGETOPTARGV_CNV_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Convenience wrapper around RTGetOpArgvToString and RTStrToUtf16. + * + * @returns IPRT status code. + * + * @param ppwszCmdLine Where to return the command line string. This must + * be freed by calling RTUtf16Free. + * @param papszArgv The argument vector to convert. + * @param fFlags A combination of the RTGETOPTARGV_CNV_XXX flags. + */ +RTDECL(int) RTGetOptArgvToUtf16String(PRTUTF16 *ppwszCmdLine, const char * const *papszArgv, uint32_t fFlags); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_getopt_h */ + diff --git a/include/iprt/handle.h b/include/iprt/handle.h new file mode 100644 index 00000000..9f4ad5bd --- /dev/null +++ b/include/iprt/handle.h @@ -0,0 +1,81 @@ +/** @file + * IPRT - Generic Handle Operations. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_handle_h +#define IPRT_INCLUDED_handle_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_handle RTHandle - Generic Handle Operations + * @ingroup grp_rt + * @{ + */ + +/** + * Closes or destroy a generic handle. + * + * @returns IPRT status code. + * @param ph Pointer to the generic handle. The structure handle + * will be set to NIL. A NULL pointer or a NIL handle + * will be quietly ignore (VINF_SUCCESS). + */ +RTDECL(int) RTHandleClose(PRTHANDLE ph); + +/** + * Gets one of the standard handles. + * + * @returns IPRT status code. + * @param enmStdHandle The standard handle. + * @param fLeaveOpen Whether closing the returned handle should leave the + * native standard handle open or not. + * Note! This currently only works with pipes and + * sockets! + * @param ph Pointer to the generic handle. This will contain + * the most appropriate IPRT handle on success. + */ +RTDECL(int) RTHandleGetStandard(RTHANDLESTD enmStdHandle, bool fLeaveOpen, PRTHANDLE ph); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_handle_h */ + diff --git a/include/iprt/handletable.h b/include/iprt/handletable.h new file mode 100644 index 00000000..98d243af --- /dev/null +++ b/include/iprt/handletable.h @@ -0,0 +1,259 @@ +/** @file + * IPRT - Handle Tables. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_handletable_h +#define IPRT_INCLUDED_handletable_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_handletable RTHandleTable - Handle Tables + * @ingroup grp_rt + * @{ + */ + +/** + * Callback for retaining an object during the lookup and free calls. + * + * This callback is executed when a handle is being looked up in one + * way or another from behind the handle table lock. This allows you + * to increase the reference (or some equivalent thing) during the + * handle lookup and thereby eliminate any race with anyone trying + * to free the handle. + * + * Note that there is no counterpart to this callback, so if you make + * use of this you'll have to release the object manually of course. + * + * Another use of this callback is to do some extra access checking. + * Use the return code to indicate whether the lookup should fail + * or not (no object is returned on faliure, naturally). + * + * @returns IPRT status code for the lookup (the caller won't see this). + * + * @param hHandleTable The handle table handle. + * @param pvObj The object which has been looked up. + * @param pvCtx The context argument if the handle table was created with the + * RTHANDLETABLE_FLAGS_CONTEXT set. Otherwise NULL. + * @param pvUser The user context argument specified when creating the table. + */ +typedef DECLCALLBACKTYPE(int, FNRTHANDLETABLERETAIN,(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)); +/** Pointer to a FNHANDLETABLERETAIN. */ +typedef FNRTHANDLETABLERETAIN *PFNRTHANDLETABLERETAIN; + +/** + * Callback for deleting a left over object during RTHandleTableDestroy. + * + * @param hHandleTable The handle table handle. + * @param h The handle. + * @param pvObj The object. + * @param pvCtx The context argument if the handle table was created with the + * RTHANDLETABLE_FLAGS_CONTEXT set. Otherwise NULL. + * @param pvUser The user context argument specified when creating the table. + * + */ +typedef DECLCALLBACKTYPE(void, FNRTHANDLETABLEDELETE,(RTHANDLETABLE hHandleTable, uint32_t h, void *pvObj, void *pvCtx, void *pvUser)); +/** Pointer to a FNRTHANDLETABLEDELETE. */ +typedef FNRTHANDLETABLEDELETE *PFNRTHANDLETABLEDELETE; + + +/** @name RTHandleTableCreateEx flags + * @{ */ +/** Whether the handle table entries takes a context or not. + * + * This can be useful for associating a handle with for instance a process or + * similar in order to prevent anyone but the owner from using the handle. + * + * Setting this means you will have to use the WithCtx functions to do the + * handle management. */ +#define RTHANDLETABLE_FLAGS_CONTEXT RT_BIT_32(0) +/** Whether the handle table should take care of the serialization (IRQ unsafe). + * If not specified the caller will have to take care of that. */ +#define RTHANDLETABLE_FLAGS_LOCKED RT_BIT_32(1) +/** Like RTHANDLETABLE_FLAGS_LOCKED, except it's IRQ safe. + * A side-effect is that callbacks may be called with IRQs disabled. */ +#define RTHANDLETABLE_FLAGS_LOCKED_IRQ_SAFE RT_BIT_32(2) +/** The mask of valid flags. */ +#define RTHANDLETABLE_FLAGS_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * Creates a handle table. + * + * The handle table translates a 32-bit handle into an object pointer, + * optionally calling you back so you can retain the object without + * racing RTHandleTableFree. + * + * @returns IPRT status code and on success a handle table handle will be stored at the + * location phHandleTable points at. + * + * @param phHandleTable Where to store the handle table handle on success. + * @param fFlags Flags, see RTHANDLETABLE_FLAGS_*. + * @param uBase The handle base value. This is the value of the + * first handle to be returned. + * @param cMax The max number of handles. When exceeded the RTHandleTableAlloc + * or RTHandleTableAllocWithCtx calls will fail. Note that this + * number will be rounded up to a multiple of the sub-table size, + * or if it's too close to UINT32_MAX it will be rounded down. + * @param pfnRetain Optional retain callback that will be called from behind the + * lock (if any) during lookup. + * @param pvUser The user argument to the retain callback. + */ +RTDECL(int) RTHandleTableCreateEx(PRTHANDLETABLE phHandleTable, uint32_t fFlags, uint32_t uBase, uint32_t cMax, + PFNRTHANDLETABLERETAIN pfnRetain, void *pvUser); + +/** + * A simplified version of the RTHandleTableCreateEx API. + * + * It assumes a max of about 64K handles with 1 being the base. The table + * access will serialized (RTHANDLETABLE_FLAGS_LOCKED). + * + * @returns IPRT status code and *phHandleTable. + * + * @param phHandleTable Where to store the handle table handle on success. + */ +RTDECL(int) RTHandleTableCreate(PRTHANDLETABLE phHandleTable); + +/** + * Destroys a handle table. + * + * If any entries are still in used the pfnDelete callback will be invoked + * on each of them (if specfied) to allow to you clean things up. + * + * @returns IPRT status code + * + * @param hHandleTable The handle to the handle table. + * @param pfnDelete Function to be called back on each handle still in use. Optional. + * @param pvUser The user argument to pfnDelete. + */ +RTDECL(int) RTHandleTableDestroy(RTHANDLETABLE hHandleTable, PFNRTHANDLETABLEDELETE pfnDelete, void *pvUser); + +/** + * Allocates a handle from the handle table. + * + * @returns IPRT status code, almost any. + * @retval VINF_SUCCESS on success. + * @retval VERR_NO_MEMORY if we failed to extend the handle table. + * @retval VERR_NO_MORE_HANDLES if we're out of handles. + * + * @param hHandleTable The handle to the handle table. + * @param pvObj The object to associate with the new handle. + * This must be aligned on a 4 byte boundary. + * @param ph Where to return the handle on success. + * + * @remarks Do not call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(int) RTHandleTableAlloc(RTHANDLETABLE hHandleTable, void *pvObj, uint32_t *ph); + +/** + * Looks up a handle. + * + * @returns The object pointer on success. NULL on failure. + * + * @param hHandleTable The handle to the handle table. + * @param h The handle to lookup. + * + * @remarks Do not call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(void *) RTHandleTableLookup(RTHANDLETABLE hHandleTable, uint32_t h); + +/** + * Looks up and frees a handle. + * + * @returns The object pointer on success. NULL on failure. + * + * @param hHandleTable The handle to the handle table. + * @param h The handle to lookup. + * + * @remarks Do not call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(void *) RTHandleTableFree(RTHANDLETABLE hHandleTable, uint32_t h); + +/** + * Allocates a handle from the handle table. + * + * @returns IPRT status code, almost any. + * @retval VINF_SUCCESS on success. + * @retval VERR_NO_MEMORY if we failed to extend the handle table. + * @retval VERR_NO_MORE_HANDLES if we're out of handles. + * + * @param hHandleTable The handle to the handle table. + * @param pvObj The object to associate with the new handle. + * This must be aligned on a 4 byte boundary. + * @param pvCtx The context to associate with the new handle. + * @param ph Where to return the handle on success. + * + * @remarks Call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(int) RTHandleTableAllocWithCtx(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, uint32_t *ph); + +/** + * Looks up a handle. + * + * @returns The object pointer on success. NULL on failure. + * + * @param hHandleTable The handle to the handle table. + * @param h The handle to lookup. + * @param pvCtx The handle context, this must match what was given on allocation. + * + * @remarks Call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(void *) RTHandleTableLookupWithCtx(RTHANDLETABLE hHandleTable, uint32_t h, void *pvCtx); + +/** + * Looks up and frees a handle. + * + * @returns The object pointer on success. NULL on failure. + * + * @param hHandleTable The handle to the handle table. + * @param h The handle to lookup. + * @param pvCtx The handle context, this must match what was given on allocation. + * + * @remarks Call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(void *) RTHandleTableFreeWithCtx(RTHANDLETABLE hHandleTable, uint32_t h, void *pvCtx); + +/** @} */ + +RT_C_DECLS_END + + +#endif /* !IPRT_INCLUDED_handletable_h */ + diff --git a/include/iprt/heap.h b/include/iprt/heap.h new file mode 100644 index 00000000..bf2b3853 --- /dev/null +++ b/include/iprt/heap.h @@ -0,0 +1,369 @@ +/** @file + * IPRT - Heap Implementations + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_heap_h +#define IPRT_INCLUDED_heap_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_heap RTHeap - Heap Implementations + * @ingroup grp_rt + * @{ + */ + + +/** @defgroup grp_rt_heap_simple RTHeapSimple - Simple Heap + * @{ + */ + +/** + * Initializes the heap. + * + * @returns IPRT status code. + * @param pHeap Where to store the heap anchor block on success. + * @param pvMemory Pointer to the heap memory. + * @param cbMemory The size of the heap memory. + */ +RTDECL(int) RTHeapSimpleInit(PRTHEAPSIMPLE pHeap, void *pvMemory, size_t cbMemory); + +/** + * Merge two simple heaps into one. + * + * The requirement is of course that they next two each other memory wise. + * + * @returns IPRT status code. + * @param pHeap Where to store the handle to the merged heap on success. + * @param Heap1 Handle to the first heap. + * @param Heap2 Handle to the second heap. + * @remark This API isn't implemented yet. + */ +RTDECL(int) RTHeapSimpleMerge(PRTHEAPSIMPLE pHeap, RTHEAPSIMPLE Heap1, RTHEAPSIMPLE Heap2); + +/** + * Relocater the heap internal structures after copying it to a new location. + * + * This can be used when loading a saved heap. + * + * @returns IPRT status code. + * @param hHeap Heap handle that has already been adjusted by to the new + * location. That is to say, when calling + * RTHeapSimpleInit, the caller must note the offset of the + * returned heap handle into the heap memory. This offset + * must be used when calcuating the handle value for the + * new location. The offset may in some cases not be zero! + * @param offDelta The delta between the new and old location, i.e. what + * should be added to the internal pointers. + */ +RTDECL(int) RTHeapSimpleRelocate(RTHEAPSIMPLE hHeap, uintptr_t offDelta); + +/** + * Allocates memory from the specified simple heap. + * + * @returns Pointer to the allocated memory block on success. + * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.) + * + * @param Heap The heap to allocate the memory on. + * @param cb The requested heap block size. + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + */ +RTDECL(void *) RTHeapSimpleAlloc(RTHEAPSIMPLE Heap, size_t cb, size_t cbAlignment); + +/** + * Allocates zeroed memory from the specified simple heap. + * + * @returns Pointer to the allocated memory block on success. + * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.) + * + * @param Heap The heap to allocate the memory on. + * @param cb The requested heap block size. + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + */ +RTDECL(void *) RTHeapSimpleAllocZ(RTHEAPSIMPLE Heap, size_t cb, size_t cbAlignment); + +/** + * Reallocates / Allocates / Frees a heap block. + * + * @param Heap The heap. This is optional and will only be used for strict assertions. + * @param pv The heap block returned by RTHeapSimple. If NULL it behaves like RTHeapSimpleAlloc(). + * @param cbNew The new size of the heap block. If NULL it behaves like RTHeapSimpleFree(). + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + * @remark This API isn't implemented yet. + */ +RTDECL(void *) RTHeapSimpleRealloc(RTHEAPSIMPLE Heap, void *pv, size_t cbNew, size_t cbAlignment); + +/** + * Reallocates / Allocates / Frees a heap block, zeroing any new bits. + * + * @param Heap The heap. This is optional and will only be used for strict assertions. + * @param pv The heap block returned by RTHeapSimple. If NULL it behaves like RTHeapSimpleAllocZ(). + * @param cbNew The new size of the heap block. If NULL it behaves like RTHeapSimpleFree(). + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + * @remark This API isn't implemented yet. + */ +RTDECL(void *) RTHeapSimpleReallocZ(RTHEAPSIMPLE Heap, void *pv, size_t cbNew, size_t cbAlignment); + +/** + * Frees memory allocated from a simple heap. + * + * @param Heap The heap. This is optional and will only be used for strict assertions. + * @param pv The heap block returned by RTHeapSimple + */ +RTDECL(void) RTHeapSimpleFree(RTHEAPSIMPLE Heap, void *pv); + +/** + * Gets the size of the specified heap block. + * + * @returns The actual size of the heap block. + * @returns 0 if \a pv is NULL or it doesn't point to a valid heap block. An invalid \a pv + * can also cause traps or trigger assertions. + * @param Heap The heap. This is optional and will only be used for strict assertions. + * @param pv The heap block returned by RTHeapSimple + */ +RTDECL(size_t) RTHeapSimpleSize(RTHEAPSIMPLE Heap, void *pv); + +/** + * Gets the size of the heap. + * + * This size includes all the internal heap structures. So, even if the heap is + * empty the RTHeapSimpleGetFreeSize() will never reach the heap size returned + * by this function. + * + * @returns The heap size. + * @returns 0 if heap was safely detected as being bad. + * @param Heap The heap. + */ +RTDECL(size_t) RTHeapSimpleGetHeapSize(RTHEAPSIMPLE Heap); + +/** + * Returns the sum of all free heap blocks. + * + * This is the amount of memory you can theoretically allocate + * if you do allocations exactly matching the free blocks. + * + * @returns The size of the free blocks. + * @returns 0 if heap was safely detected as being bad. + * @param Heap The heap. + */ +RTDECL(size_t) RTHeapSimpleGetFreeSize(RTHEAPSIMPLE Heap); + +/** + * Printf like callbaclk function for RTHeapSimpleDump. + * @param pszFormat IPRT format string. + * @param ... Format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNRTHEAPSIMPLEPRINTF,(const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(1, 2); +/** Pointer to a FNRTHEAPSIMPLEPRINTF function. */ +typedef FNRTHEAPSIMPLEPRINTF *PFNRTHEAPSIMPLEPRINTF; + +/** + * Dumps the hypervisor heap. + * + * @param Heap The heap handle. + * @param pfnPrintf Printf like function that groks IPRT formatting. + */ +RTDECL(void) RTHeapSimpleDump(RTHEAPSIMPLE Heap, PFNRTHEAPSIMPLEPRINTF pfnPrintf); + +/** @} */ + + + +/** @defgroup grp_rt_heap_offset RTHeapOffset - Offset Based Heap + * + * This is a variation on the simple heap that doesn't use pointers internally + * and therefore can be saved and restored without any extra effort. + * + * @{ + */ + +/** + * Initializes the heap. + * + * @returns IPRT status code. + * @param phHeap Where to store the heap anchor block on success. + * @param pvMemory Pointer to the heap memory. + * @param cbMemory The size of the heap memory. + */ +RTDECL(int) RTHeapOffsetInit(PRTHEAPOFFSET phHeap, void *pvMemory, size_t cbMemory); + +/** + * Merge two simple heaps into one. + * + * The requirement is of course that they next two each other memory wise. + * + * @returns IPRT status code. + * @param phHeap Where to store the handle to the merged heap on success. + * @param hHeap1 Handle to the first heap. + * @param hHeap2 Handle to the second heap. + * @remark This API isn't implemented yet. + */ +RTDECL(int) RTHeapOffsetMerge(PRTHEAPOFFSET phHeap, RTHEAPOFFSET hHeap1, RTHEAPOFFSET hHeap2); + +/** + * Allocates memory from the specified simple heap. + * + * @returns Pointer to the allocated memory block on success. + * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.) + * + * @param hHeap The heap to allocate the memory on. + * @param cb The requested heap block size. + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + */ +RTDECL(void *) RTHeapOffsetAlloc(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment); + +/** + * Allocates zeroed memory from the specified simple heap. + * + * @returns Pointer to the allocated memory block on success. + * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.) + * + * @param hHeap The heap to allocate the memory on. + * @param cb The requested heap block size. + * @param cbAlignment The requested heap block alignment. Pass 0 for default + * alignment. Must be a power of 2. + */ +RTDECL(void *) RTHeapOffsetAllocZ(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment); + +/** + * Reallocates / Allocates / Frees a heap block. + * + * @param hHeap The heap handle. This is optional and will only be used + * for strict assertions. + * @param pv The heap block returned by RTHeapOffset. If NULL it + * behaves like RTHeapOffsetAlloc(). + * @param cbNew The new size of the heap block. If NULL it behaves like + * RTHeapOffsetFree(). + * @param cbAlignment The requested heap block alignment. Pass 0 for default + * alignment. Must be a power of 2. + * @remark This API isn't implemented yet. + */ +RTDECL(void *) RTHeapOffsetRealloc(RTHEAPOFFSET hHeap, void *pv, size_t cbNew, size_t cbAlignment); + +/** + * Reallocates / Allocates / Frees a heap block, zeroing any new bits. + * + * @param hHeap The heap handle. This is optional and will only be used + * for strict assertions. + * @param pv The heap block returned by RTHeapOffset. If NULL it + * behaves like RTHeapOffsetAllocZ(). + * @param cbNew The new size of the heap block. If NULL it behaves like + * RTHeapOffsetFree(). + * @param cbAlignment The requested heap block alignment. Pass 0 for default + * alignment. Must be a power of 2. + * @remark This API isn't implemented yet. + */ +RTDECL(void *) RTHeapOffsetReallocZ(RTHEAPOFFSET hHeap, void *pv, size_t cbNew, size_t cbAlignment); + +/** + * Frees memory allocated from a simple heap. + * + * @param hHeap The heap handle. This is optional and will only be used + * for strict assertions. + * @param pv The heap block returned by RTHeapOffset + */ +RTDECL(void) RTHeapOffsetFree(RTHEAPOFFSET hHeap, void *pv); + +/** + * Gets the size of the specified heap block. + * + * @returns The actual size of the heap block. + * @returns 0 if \a pv is NULL or it doesn't point to a valid heap block. An + * invalid \a pv can also cause traps or trigger assertions. + * + * @param hHeap The heap handle. This is optional and will only be used + * for strict assertions. + * @param pv The heap block returned by RTHeapOffset + */ +RTDECL(size_t) RTHeapOffsetSize(RTHEAPOFFSET hHeap, void *pv); + +/** + * Gets the size of the heap. + * + * This size includes all the internal heap structures. So, even if the heap is + * empty the RTHeapOffsetGetFreeSize() will never reach the heap size returned + * by this function. + * + * @returns The heap size. + * @returns 0 if heap was safely detected as being bad. + * @param hHeap The heap handle. + */ +RTDECL(size_t) RTHeapOffsetGetHeapSize(RTHEAPOFFSET hHeap); + +/** + * Returns the sum of all free heap blocks. + * + * This is the amount of memory you can theoretically allocate + * if you do allocations exactly matching the free blocks. + * + * @returns The size of the free blocks. + * @returns 0 if heap was safely detected as being bad. + * @param hHeap The heap handle. + */ +RTDECL(size_t) RTHeapOffsetGetFreeSize(RTHEAPOFFSET hHeap); + +/** + * Printf like callbaclk function for RTHeapOffsetDump. + * @param pszFormat IPRT format string. + * @param ... Format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNRTHEAPOFFSETPRINTF,(const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(1, 2); +/** Pointer to a FNRTHEAPOFFSETPRINTF function. */ +typedef FNRTHEAPOFFSETPRINTF *PFNRTHEAPOFFSETPRINTF; + +/** + * Dumps the hypervisor heap. + * + * @param hHeap The heap handle. + * @param pfnPrintf Printf like function that groks IPRT formatting. + */ +RTDECL(void) RTHeapOffsetDump(RTHEAPOFFSET hHeap, PFNRTHEAPOFFSETPRINTF pfnPrintf); + +/** @} */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_heap_h */ + diff --git a/include/iprt/http-common.h b/include/iprt/http-common.h new file mode 100644 index 00000000..d9cc746f --- /dev/null +++ b/include/iprt/http-common.h @@ -0,0 +1,286 @@ +/* $Id: http-common.h $ */ +/** @file + * IPRT - Common (client / server) HTTP API. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_http_common_h +#define IPRT_INCLUDED_http_common_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** HTTP methods. */ +typedef enum RTHTTPMETHOD +{ + RTHTTPMETHOD_INVALID = 0, + RTHTTPMETHOD_GET, + RTHTTPMETHOD_PUT, + RTHTTPMETHOD_POST, + RTHTTPMETHOD_PATCH, + RTHTTPMETHOD_DELETE, + RTHTTPMETHOD_HEAD, + RTHTTPMETHOD_OPTIONS, + RTHTTPMETHOD_TRACE, +#ifdef IPRT_HTTP_WITH_WEBDAV + RTHTTPMETHOD_PROPFIND, +#endif + RTHTTPMETHOD_END, + RTHTTPMETHOD_32BIT_HACK = 0x7fffffff +} RTHTTPMETHOD; + +/** HTTP status codes. */ +typedef enum RTHTTPSTATUS +{ + RTHTTPSTATUS_INTERNAL_NOT_SET = 0, + /** + * 2xx - Success / information codes. + */ + RTHTTPSTATUS_OK = 200, + RTHTTPSTATUS_CREATED = 201, + RTHTTPSTATUS_ACCEPTED = 202, + RTHTTPSTATUS_NONAUTHORITATIVEINFORMATION = 203, + RTHTTPSTATUS_NOCONTENT = 204, + RTHTTPSTATUS_RESETCONTENT = 205, + RTHTTPSTATUS_PARTIALCONTENT = 206, + RTHTTPSTATUS_MULTISTATUS = 207, + RTHTTPSTATUS_ALREADYREPORTED = 208, + RTHTTPSTATUS_IMUSED = 226, + /** + * 4xx - Client error codes. + */ + RTHTTPSTATUS_BADREQUEST = 400, + RTHTTPSTATUS_UNAUTHORIZED = 401, + RTHTTPSTATUS_PAYMENTREQUIRED = 402, + RTHTTPSTATUS_FORBIDDEN = 403, + RTHTTPSTATUS_NOTFOUND = 404, + RTHTTPSTATUS_METHODNOTALLOWED = 405, + RTHTTPSTATUS_NOTACCEPTABLE = 406, + RTHTTPSTATUS_PROXYAUTHENTICATIONREQUIRED = 407, + RTHTTPSTATUS_REQUESTTIMEOUT = 408, + RTHTTPSTATUS_CONFLICT = 409, + RTHTTPSTATUS_GONE = 410, + RTHTTPSTATUS_LENGTHREQUIRED = 411, + RTHTTPSTATUS_PRECONDITIONFAILED = 412, + RTHTTPSTATUS_PAYLOADTOOLARGE = 413, + RTHTTPSTATUS_URITOOLONG = 414, + RTHTTPSTATUS_UNSUPPORTEDMEDIATYPE = 415, + RTHTTPSTATUS_RANGENOTSATISFIABLE = 416, + RTHTTPSTATUS_EXPECTATIONFAILED = 417, + RTHTTPSTATUS_IMATEAPOT = 418, + RTHTTPSTATUS_UNPROCESSABLEENTITY = 422, + RTHTTPSTATUS_LOCKED = 423, + RTHTTPSTATUS_FAILEDDEPENDENCY = 424, + RTHTTPSTATUS_UPGRADEREQUIRED = 426, + RTHTTPSTATUS_PRECONDITIONREQUIRED = 428, + RTHTTPSTATUS_TOOMANYREQUESTS = 429, + RTHTTPSTATUS_REQUESTHEADERFIELDSTOOLARGE = 431, + RTHTTPSTATUS_UNAVAILABLEFORLEGALREASONS = 451, + /** + * 5xx - Server error codes. + */ + RTHTTPSTATUS_INTERNALSERVERERROR = 500, + RTHTTPSTATUS_NOTIMPLEMENTED = 501, + RTHTTPSTATUS_BADGATEWAY = 502, + RTHTTPSTATUS_SERVICEUNAVAILABLE = 503, + RTHTTPSTATUS_GATEWAYTIMEOUT = 504, + RTHTTPSTATUS_HTTPVERSIONNOTSUPPORTED = 505, + RTHTTPSTATUS_VARIANTALSONEGOTIATES = 506, + RTHTTPSTATUS_INSUFFICIENTSTORAGE = 507, + RTHTTPSTATUS_LOOPDETECTED = 508, + RTHTTPSTATUS_NOTEXTENDED = 510, + RTHTTPSTATUS_NETWORKAUTHENTICATIONREQUIRED = 511, + + RTHTTPSTATUS_32BIT_HACK = 0x7fffffff +} RTHTTPSTATUS; + +/** Checks whether a HTTP status is of type "informational" or not. */ +#define RTHTTPSTATUS_IS_INFO(a_Code) (a_Code >= 100 && a_Code < 200) +/** Checks whether a HTTP status indicates success or not. */ +#define RTHTTPSTATUS_IS_OK(a_Code) (a_Code >= 200 && a_Code < 300) +/** Checks whether a HTTP status indicates a redirection or not. */ +#define RTHTTPSTATUS_IS_REDIRECT(a_Code) (a_Code >= 300 && a_Code < 400) +/** Checks whether a HTTP status indicates a client error or not. */ +#define RTHTTPSTATUS_IS_CLIENTERROR(a_Code) (a_Code >= 400 && a_Code < 500) +/** Checks whether a HTTP status indicates a server error or not. */ +#define RTHTTPSTATUS_IS_SERVERERROR(a_Code) (a_Code >= 500 && a_Code < 600) +/** Checks whether a HTTP status indicates an error or not. */ +#define RTHTTPSTATUS_IS_ERROR(a_Code) (a_Code >= 400) + +/** Specifies a HTTP MIME type. */ +typedef uint32_t RTHTTPMIMETYPE; + +#define RTHTTPMIMETYPE_TEXT_PLAIN "text/plain" +#define RTHTTPMIMETYPE_APPLICATION_OCTET_STREAM "application/octet-stream" + +/** Specifies HTTP version 1.1 as a string. */ +#define RTHTTPVER_1_1_STR "HTTP/1.1" + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** HTTP header list handle. */ +typedef R3PTRTYPE(struct RTHTTPHEADERLISTINTERNAL *) RTHTTPHEADERLIST; +/** Pointer to a HTTP header list handle. */ +typedef RTHTTPHEADERLIST *PRTHTTPHEADERLIST; +/** Nil HTTP HTTP header list handle. */ +#define NIL_RTHTTPHEADERLIST ((RTHTTPHEADERLIST)0) + +/** + * HTTP header list entry. + */ +typedef struct RTHTTPHEADERENTRY +{ + /** The list node. */ + RTLISTNODE Node; + /** The field name length. */ + uint32_t cchName; + /** The value offset. */ + uint32_t offValue; + /** The full header field. */ + RT_FLEXIBLE_ARRAY_EXTENSION + RT_GCC_EXTENSION char szData[RT_FLEXIBLE_ARRAY]; +} RTHTTPHEADERENTRY; +/** Pointer to a HTTP header. */ +typedef RTHTTPHEADERENTRY *PRTHTTPHEADERENTRY; + +/** + * Structure for maintaining a HTTP body. + */ +typedef struct RTHTTPBODY +{ + /** Body to send, if any. Can be NULL. */ + void *pvBody; + /** Body allocation size (in bytes). */ + size_t cbBodyAlloc; + /** How much body data is being used (in bytes). */ + size_t cbBodyUsed; + /** Current body data read/write offset (in bytes). */ + size_t offBody; +} RTHTTPBODY; +/** Pointer to a HTTP body. */ +typedef RTHTTPBODY *PRTHTTPBODY; + +/** + * Returns the name of the HTTP method. + * @returns Read only string. + * @param enmMethod The HTTP method to name. + */ +RTR3DECL(const char *) RTHttpMethodToStr(RTHTTPMETHOD enmMethod); + +RTR3DECL(const char *) RTHttpStatusToStr(RTHTTPSTATUS enmSts); + +RTR3DECL(int) RTHttpHeaderListInit(PRTHTTPHEADERLIST hHdrList); + +RTR3DECL(void) RTHttpHeaderListDestroy(RTHTTPHEADERLIST hHdrList); + +/** + * Set custom raw headers. + * + * @returns IPRT status code. + * @param hHdrLst The HTTP header list handle. + * @param cHeaders Number of custom headers. + * @param papszHeaders Array of headers in form "foo: bar". + */ +RTR3DECL(int) RTHttpHeaderListSet(RTHTTPHEADERLIST hHdrLst, size_t cHeaders, const char * const *papszHeaders); + +/** @name RTHTTPHEADERLISTADD_F_XXX - Flags for RTHttpHeaderListAddRaw and RTHttpHeaderListAdd + * @{ */ +#define RTHTTPHEADERLISTADD_F_BACK UINT32_C(0) /**< Append the header. */ +#define RTHTTPHEADERLISTADD_F_FRONT UINT32_C(1) /**< Prepend the header. */ +/** @} */ + +/** + * Adds a raw header. + * + * @returns IPRT status code. + * @param hHdrLst The HTTP header list handle. + * @param pszHeader Header string on the form "foo: bar". + * @param fFlags RTHTTPADDHDR_F_FRONT or RTHTTPADDHDR_F_BACK. + */ +RTR3DECL(int) RTHttpHeaderListAddRaw(RTHTTPHEADERLIST hHdrLst, const char *pszHeader, uint32_t fFlags); + +/** + * Adds a header field and value. + * + * @returns IPRT status code. + * @param hHdrLst The HTTP header list handle. + * @param pszField The header field name. + * @param pszValue The header field value. + * @param cchValue The value length or RTSTR_MAX. + * @param fFlags Only RTHTTPADDHDR_F_FRONT or RTHTTPADDHDR_F_BACK, + * may be extended with encoding controlling flags if + * needed later. + */ +RTR3DECL(int) RTHttpHeaderListAdd(RTHTTPHEADERLIST hHdrLst, const char *pszField, const char *pszValue, size_t cchValue, uint32_t fFlags); + +/** + * Gets a header previously added using RTHttpSetHeaders, RTHttpAppendRawHeader + * or RTHttpAppendHeader. + * + * @returns Pointer to the header value on if found, otherwise NULL. + * @param hHdrLst The HTTP header list handle. + * @param pszField The field name (no colon). + * @param cchField The length of the field name or RTSTR_MAX. + */ +RTR3DECL(const char *) RTHttpHeaderListGet(RTHTTPHEADERLIST hHdrLst, const char *pszField, size_t cchField); + +/** + * Gets the number of headers specified by RTHttpAddHeader, RTHttpAddRawHeader or RTHttpSetHeaders. + * + * @returns Number of headers. + * @param hHdrLst The HTTP header list handle. + * @note This can be slow and is only really intended for test cases and debugging! + */ +RTR3DECL(size_t) RTHttpHeaderListGetCount(RTHTTPHEADERLIST hHdrLst); + +/** + * Gets a header by ordinal. + * + * Can be used together with RTHttpGetHeaderCount by test case and debug code to + * iterate headers specified by RTHttpAddHeader, RTHttpAddRawHeader or RTHttpSetHeaders. + * + * @returns The header string ("field: value"). + * @param hHdrLst The HTTP header list handle. + * @param iOrdinal The number of the header to get. + * @note This can be slow and is only really intended for test cases and debugging! + */ +RTR3DECL(const char *) RTHttpHeaderListGetByOrdinal(RTHTTPHEADERLIST hHdrLst, size_t iOrdinal); + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_http_common_h */ + diff --git a/include/iprt/http-server.h b/include/iprt/http-server.h new file mode 100644 index 00000000..eab06a37 --- /dev/null +++ b/include/iprt/http-server.h @@ -0,0 +1,244 @@ +/* $Id: http-server.h $ */ +/** @file + * Header file for HTTP server implementation. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_http_server_h +#define IPRT_INCLUDED_http_server_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_httpserver RTHttpServer - HTTP server implementation. + * @ingroup grp_rt + * @{ + */ + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** HTTP server handle. */ +typedef R3PTRTYPE(struct RTHTTPSERVERINTERNAL *) RTHTTPSERVER; +/** Pointer to a HTTP server handle. */ +typedef RTHTTPSERVER *PRTHTTPSERVER; +/** Nil HTTP client handle. */ +#define NIL_RTHTTPSERVER ((RTHTTPSERVER)0) + +/** + * Structure for maintaining a HTTP client request. + */ +typedef struct RTHTTPSERVERREQ +{ + /** Request URL. */ + char *pszUrl; + /** Request method. */ + RTHTTPMETHOD enmMethod; + /** Request header list. */ + RTHTTPHEADERLIST hHdrLst; + /** Request body data. */ + RTHTTPBODY Body; +} RTHTTPSERVERREQ; +/** Pointer to a HTTP client request. */ +typedef RTHTTPSERVERREQ *PRTHTTPSERVERREQ; + +/** + * Structure for maintaining a HTTP server response. + */ +typedef struct RTHTTPSERVERRESP +{ + /** HTTP status to send. */ + RTHTTPSTATUS enmSts; + /** List of headers to send. */ + RTHTTPHEADERLIST hHdrLst; + /** Body data to send. */ + RTHTTPBODY Body; +} RTHTTPSERVERRESP; +/** Pointer to a HTTP server response. */ +typedef RTHTTPSERVERRESP *PRTHTTPSERVERRESP; + +RTR3DECL(int) RTHttpServerResponseInitEx(PRTHTTPSERVERRESP pResp, size_t cbBody); +RTR3DECL(int) RTHttpServerResponseInit(PRTHTTPSERVERRESP pResp); +RTR3DECL(void) RTHttpServerResponseDestroy(PRTHTTPSERVERRESP pResp); + +/** + * Structure for maintaining a HTTP server client state. + * + * Note: The HTTP protocol itself is stateless, but we want to have to possibility to store + * some state stuff here nevertheless. + */ +typedef struct RTHTTPSERVERCLIENTSTATE +{ + /** If non-zero, the time (in ms) to keep a client connection alive. + * Requested via client header, but set and controlled by the server in the end. */ + RTMSINTERVAL msKeepAlive; +} RTHTTPSERVERCLIENTSTATE; +/** Pointer to a FTP server client state. */ +typedef RTHTTPSERVERCLIENTSTATE *PRTHTTPSERVERCLIENTSTATE; + +/** + * Structure for storing HTTP server callback data. + */ +typedef struct RTHTTPCALLBACKDATA +{ + /** Pointer to the client state. */ + PRTHTTPSERVERCLIENTSTATE pClient; + /** Saved user pointer. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} RTHTTPCALLBACKDATA; +/** Pointer to HTTP server callback data. */ +typedef RTHTTPCALLBACKDATA *PRTHTTPCALLBACKDATA; + +/** + * Function callback table for the HTTP server implementation. + * + * All callbacks are optional and therefore can be NULL. + */ +typedef struct RTHTTPSERVERCALLBACKS +{ + /** + * Called before a given URL will be retrieved by the GET method. + * + * Note: High level function, not being called when pfnOnGetRequest is implemented. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pReq Pointer to request to handle. + * @param ppvHandle Where to return the pointer to the opaque handle used for object identification. + */ + DECLCALLBACKMEMBER(int, pfnOpen,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq, void **ppvHandle)); + /** + * Called when a given URL will be retrieved by the GET method. + * + * Note: High level function, not being called when pfnOnGetRequest is implemented. + * Note2: Can be called multiple times, based on the body size to send. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pvHandle Opaque handle for object identification. + * @param pvBuf Pointer to buffer where to store the read data. + * @param cbBuf Size (in bytes) of the buffer where to store the read data. + * @param pcbRead Where to return the amount (in bytes) of read data. Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnRead,(PRTHTTPCALLBACKDATA pData, void *pvHandle, void *pvBuf, size_t cbBuf, size_t *pcbRead)); + /** + * Called when a given URL is done retrieving by the GET method. + * + * Note: High level function, not being called when pfnOnGetRequest is implemented. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pszUrl URL to handle. + * @param pvHandle Opaque handle for object identification. + */ + DECLCALLBACKMEMBER(int, pfnClose,(PRTHTTPCALLBACKDATA pData, void *pvHandle)); + /** + * Queries information about a given URL. + * + * Will be called with GET or HEAD request. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pReq Pointer to request to handle. + * @param pObjInfo Where to store the queried file information on success. + * @param ppszMIMEHint Where to return an allocated MIME type hint on success. + * Must be free'd by the caller using RTStrFree(). + */ + DECLCALLBACKMEMBER(int, pfnQueryInfo,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint)); + /** + * Low-level handler for a GET method request. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pReq Pointer to request to handle. + */ + DECLCALLBACKMEMBER(int, pfnOnGetRequest,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq)); + /** + * Low-level handler for a HEAD method request. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pReq Pointer to request to handle. + */ + DECLCALLBACKMEMBER(int, pfnOnHeadRequest,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq)); + /** + * Called before the HTTP server will be destroyed. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + */ + DECLCALLBACKMEMBER(int, pfnDestroy,(PRTHTTPCALLBACKDATA pData)); +} RTHTTPSERVERCALLBACKS; +/** Pointer to a HTTP server callback data table. */ +typedef RTHTTPSERVERCALLBACKS *PRTHTTPSERVERCALLBACKS; + +/** Maximum length (in bytes) a single client request can have. */ +#define RTHTTPSERVER_MAX_REQ_LEN _8K +/** EOL string according to the HTTP 1.1 specs. + * See https://tools.ietf.org/html/rfc2616#section-2.2 */ +#define RTHTTPSERVER_HTTP11_EOL_STR "\r\n" + +/** + * Creates a HTTP server instance. + * + * @returns IPRT status code. + * @param phHttpServer Where to store the HTTP server handle. + * @param pcszAddress The address for creating a listening socket. + * If NULL or empty string the server is bound to all interfaces. + * @param uPort The port for creating a listening socket. + * @param pCallbacks Callback table to use. + * @param pvUser Pointer to user-specific data. Optional. + * @param cbUser Size of user-specific data. Optional. + */ +RTR3DECL(int) RTHttpServerCreate(PRTHTTPSERVER phHttpServer, const char *pcszAddress, uint16_t uPort, + PRTHTTPSERVERCALLBACKS pCallbacks, void *pvUser, size_t cbUser); + +/** + * Destroys a HTTP server instance. + * + * @returns IPRT status code. + * @param hHttpServer Handle to the HTTP server handle. + */ +RTR3DECL(int) RTHttpServerDestroy(RTHTTPSERVER hHttpServer); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_http_server_h */ + diff --git a/include/iprt/http.h b/include/iprt/http.h new file mode 100644 index 00000000..5ab966fd --- /dev/null +++ b/include/iprt/http.h @@ -0,0 +1,746 @@ +/* $Id: http.h $ */ +/** @file + * IPRT - Simple HTTP/HTTPS Client API. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_http_h +#define IPRT_INCLUDED_http_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_http RTHttp - Simple HTTP/HTTPS Client API + * @ingroup grp_rt + * @{ + */ + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** HTTP/HTTPS client handle. */ +typedef R3PTRTYPE(struct RTHTTPINTERNAL *) RTHTTP; +/** Pointer to a HTTP/HTTPS client handle. */ +typedef RTHTTP *PRTHTTP; +/** Nil HTTP/HTTPS client handle. */ +#define NIL_RTHTTP ((RTHTTP)0) + + +/** + * Creates a HTTP client instance. + * + * @returns IPRT status code. + * @param phHttp Where to store the HTTP handle. + */ +RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp); + +/** + * Resets a HTTP client instance. + * + * @returns IPRT status code. + * @param hHttp Handle to the HTTP interface. + * @param fFlags Flags, RTHTTP_RESET_F_XXX. + */ +RTR3DECL(int) RTHttpReset(RTHTTP hHttp, uint32_t fFlags); + +/** @name RTHTTP_RESET_F_XXX - Flags for RTHttpReset. + * @{ */ +/** Keep the headers. */ +#define RTHTTP_RESET_F_KEEP_HEADERS RT_BIT_32(0) +/** Mask containing the valid flags. */ +#define RTHTTP_RESET_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + + +/** + * Destroys a HTTP client instance. + * + * @returns IPRT status code. + * @param hHttp Handle to the HTTP interface. + */ +RTR3DECL(int) RTHttpDestroy(RTHTTP hHttp); + + +/** + * Retrieve the redir location for 301 responses. + * + * @param hHttp Handle to the HTTP interface. + * @param ppszRedirLocation Where to store the string. To be freed with + * RTStrFree(). + */ +RTR3DECL(int) RTHttpGetRedirLocation(RTHTTP hHttp, char **ppszRedirLocation); + +/** + * Perform a simple blocking HTTP GET request. + * + * This is a just a convenient wrapper around RTHttpGetBinary that returns a + * different type and sheds a parameter. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl URL. + * @param ppszNotUtf8 Where to return the pointer to the HTTP response. + * The string is of course zero terminated. Use + * RTHttpFreeReponseText to free. + * + * @remarks BIG FAT WARNING! + * + * This function does not guarantee the that returned string is valid UTF-8 or + * any other kind of text encoding! + * + * The caller must determine and validate the string encoding _before_ + * passing it along to functions that expect UTF-8! + * + * Also, this function does not guarantee that the returned string + * doesn't have embedded zeros and provides the caller no way of + * finding out! If you are worried about the response from the HTTPD + * containing embedded zero's, use RTHttpGetBinary instead. + */ +RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8); + +/** + * Perform a simple blocking HTTP HEAD request. + * + * This is a just a convenient wrapper around RTHttpGetBinary that returns a + * different type and sheds a parameter. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl URL. + * @param ppszNotUtf8 Where to return the pointer to the HTTP response. + * The string is of course zero terminated. Use + * RTHttpFreeReponseText to free. + * + * @remarks BIG FAT WARNING! + * + * This function does not guarantee the that returned string is valid UTF-8 or + * any other kind of text encoding! + * + * The caller must determine and validate the string encoding _before_ + * passing it along to functions that expect UTF-8! + * + * Also, this function does not guarantee that the returned string + * doesn't have embedded zeros and provides the caller no way of + * finding out! If you are worried about the response from the HTTPD + * containing embedded zero's, use RTHttpGetHeaderBinary instead. + */ +RTR3DECL(int) RTHttpGetHeaderText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8); + +/** + * Frees memory returned by RTHttpGetText. + * + * @param pszNotUtf8 What RTHttpGetText returned. + */ +RTR3DECL(void) RTHttpFreeResponseText(char *pszNotUtf8); + +/** + * Perform a simple blocking HTTP GET request. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl The URL. + * @param ppvResponse Where to store the HTTP response data. Use + * RTHttpFreeResponse to free. + * @param pcb Size of the returned buffer. + * + * @note There is a limit on how much this function allows to be downloaded, + * given that the return requires a single heap allocation and all + * that. Currently 32 MB on 32-bit hosts and 64 MB on 64-bit hosts. + * Use RTHttpGetFile or RTHttpSetDownloadCallback for larger transfers. + */ +RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb); + +/** + * Perform a simple blocking HTTP HEAD request. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl The URL. + * @param ppvResponse Where to store the HTTP response data. Use + * RTHttpFreeResponse to free. + * @param pcb Size of the returned buffer. + */ +RTR3DECL(int) RTHttpGetHeaderBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb); + +/** + * Frees memory returned by RTHttpGetBinary. + * + * @param pvResponse What RTHttpGetBinary returned. + */ +RTR3DECL(void) RTHttpFreeResponse(void *pvResponse); + +/** + * Perform a simple blocking HTTP request, writing the output to a file. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl The URL. + * @param pszDstFile The destination file name. + */ +RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile); + +/** + * Performs generic blocking HTTP request, optionally returning the body and headers. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pszUrl The URL. + * @param enmMethod The HTTP method for the request. + * @param pvReqBody Pointer to the request body. NULL if none. + * @param cbReqBody Size of the request body. Zero if none. + * @param puHttpStatus Where to return the HTTP status code. Optional. + * @param ppvHeaders Where to return the headers. Optional. + * @param pcbHeaders Where to return the header size. + * @param ppvBody Where to return the body. Optional. + * @param pcbBody Where to return the body size. + */ +RTR3DECL(int) RTHttpPerform(RTHTTP hHttp, const char *pszUrl, RTHTTPMETHOD enmMethod, void const *pvReqBody, size_t cbReqBody, + uint32_t *puHttpStatus, void **ppvHeaders, size_t *pcbHeaders, void **ppvBody, size_t *pcbBody); + + +/** + * Abort a pending HTTP request. A blocking RTHttpGet() call will return with + * VERR_HTTP_ABORTED. It may take some time (current cURL implementation needs + * up to 1 second) before the request is aborted. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + */ +RTR3DECL(int) RTHttpAbort(RTHTTP hHttp); + +/** + * Tells the HTTP interface to use the system proxy configuration. + * + * @returns iprt status code. + * @param hHttp The HTTP client handle. + */ +RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp); + +/** + * Sets up the proxy according to the specified URL. + * + * @returns IPRT status code. + * @retval VWRN_WRONG_TYPE if the type isn't known/supported and we defaulted to 'http'. + * + * @param hHttp The HTTP client handle. + * @param pszUrl The proxy URL (libproxy style): + * + * [{type}"://"][{userid}[\@{password}]:]{server}[":"{port}] + * + * Valid proxy types are: http (default), https, socks4, socks4a, + * socks5, socks5h and direct. Support for the socks and https + * ones depends on the HTTP library we use. + * + * The port number defaults to 80 for http, 443 for https and 1080 + * for the socks ones. + * + * If this starts with "direct://", then no proxy will be used. + * An empty or NULL string is equivalent to calling + * RTHttpUseSystemProxySettings(). + */ +RTR3DECL(int) RTHttpSetProxyByUrl(RTHTTP hHttp, const char *pszUrl); + +/** + * Specify proxy settings. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszProxyUrl URL of the proxy server. + * @param uPort port number of the proxy, use 0 for not specifying a port. + * @param pszProxyUser Username, pass NULL for no authentication. + * @param pszProxyPwd Password, pass NULL for no authentication. + * + * @todo This API does not allow specifying the type of proxy server... We're + * currently assuming it's a HTTP proxy. + * + * @deprecated Use RTHttpSetProxyByUrl. + */ +RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pszProxyUrl, uint32_t uPort, + const char *pszProxyUser, const char *pszProxyPwd); + +/** + * Set follow redirects (3xx) + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param cMaxRedirects Max number of redirects to follow. Zero if no + * redirects should be followed but instead returned + * to caller. + */ +RTR3DECL(int) RTHttpSetFollowRedirects(RTHTTP hHttp, uint32_t cMaxRedirects); + +/** + * Gets the follow redirect setting. + * + * @returns cMaxRedirects value, 0 means not to follow. + * @param hHttp The HTTP client handle. + */ +RTR3DECL(uint32_t) RTHttpGetFollowRedirects(RTHTTP hHttp); + +/** + * Set custom raw headers. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param cHeaders Number of custom headers. + * @param papszHeaders Array of headers in form "foo: bar". + */ +RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders); + +/** @name RTHTTPADDHDR_F_XXX - Flags for RTHttpAddRawHeader and RTHttpAddHeader + * @{ */ +#define RTHTTPADDHDR_F_BACK UINT32_C(0) /**< Append the header. */ +#define RTHTTPADDHDR_F_FRONT UINT32_C(1) /**< Prepend the header. */ +/** @} */ + +/** + * Adds a raw header. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pszHeader Header string on the form "foo: bar". + * @param fFlags RTHTTPADDHDR_F_FRONT or RTHTTPADDHDR_F_BACK. + */ +RTR3DECL(int) RTHttpAddRawHeader(RTHTTP hHttp, const char *pszHeader, uint32_t fFlags); + +/** + * Adds a header field and value. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pszField The header field name. + * @param pszValue The header field value. + * @param cchValue The value length or RTSTR_MAX. + * @param fFlags Only RTHTTPADDHDR_F_FRONT or RTHTTPADDHDR_F_BACK, + * may be extended with encoding controlling flags if + * needed later. + */ +RTR3DECL(int) RTHttpAddHeader(RTHTTP hHttp, const char *pszField, const char *pszValue, size_t cchValue, uint32_t fFlags); + +/** + * Gets a header previously added using RTHttpSetHeaders, RTHttpAppendRawHeader + * or RTHttpAppendHeader. + * + * @returns Pointer to the header value on if found, otherwise NULL. + * @param hHttp The HTTP client handle. + * @param pszField The field name (no colon). + * @param cchField The length of the field name or RTSTR_MAX. + */ +RTR3DECL(const char *) RTHttpGetHeader(RTHTTP hHttp, const char *pszField, size_t cchField); + +/** + * Gets the number of headers specified by RTHttpAddHeader, RTHttpAddRawHeader or RTHttpSetHeaders. + * + * @returns Number of headers. + * @param hHttp The HTTP client handle. + * @note This can be slow and is only really intended for test cases and debugging! + */ +RTR3DECL(size_t) RTHttpGetHeaderCount(RTHTTP hHttp); + +/** + * Gets a header by ordinal. + * + * Can be used together with RTHttpGetHeaderCount by test case and debug code to + * iterate headers specified by RTHttpAddHeader, RTHttpAddRawHeader or RTHttpSetHeaders. + * + * @returns The header string ("field: value"). + * @param hHttp The HTTP client handle. + * @param iOrdinal The number of the header to get. + * @note This can be slow and is only really intended for test cases and debugging! + */ +RTR3DECL(const char *) RTHttpGetByOrdinal(RTHTTP hHttp, size_t iOrdinal); + +/** + * Sign all headers present according to pending "Signing HTTP Messages" RFC. + * + * Currently hardcoded RSA-SHA-256 algorithm choice. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param enmMethod The HTTP method that will be used for the request. + * @param pszUrl The target URL for the request. + * @param hKey The RSA key to use when signing. + * @param pszKeyId The key ID string corresponding to @a hKey. + * @param fFlags Reserved for future, MBZ. + * + * @note Caller is responsible for making all desired fields are present before + * making the call. + * + * @remarks Latest RFC draft at the time of writing: + * https://tools.ietf.org/html/draft-cavage-http-signatures-10 + */ +RTR3DECL(int) RTHttpSignHeaders(RTHTTP hHttp, RTHTTPMETHOD enmMethod, const char *pszUrl, + RTCRKEY hKey, const char *pszKeyId, uint32_t fFlags); + +/** + * Tells the HTTP client instance to gather system CA certificates into a + * temporary file and use it for HTTPS connections. + * + * This will be called automatically if a 'https' URL is presented and + * RTHttpSetCaFile hasn't been called yet. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pErrInfo Where to store additional error/warning information. + * Optional. + */ +RTR3DECL(int) RTHttpUseTemporaryCaFile(RTHTTP hHttp, PRTERRINFO pErrInfo); + +/** + * Set a custom certification authority file, containing root certificates. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszCAFile File name containing root certificates. + * + * @remarks For portable HTTPS support, use RTHttpGatherCaCertsInFile and pass + */ +RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pszCAFile); + +/** + * Gathers certificates into a cryptographic (certificate) store + * + * This is a just a combination of RTHttpGatherCaCertsInStore and + * RTCrStoreCertExportAsPem. + * + * @returns IPRT status code. + * @param hStore The certificate store to gather the certificates + * in. + * @param fFlags RTHTTPGATHERCACERT_F_XXX. + * @param pErrInfo Where to store additional error/warning information. + * Optional. + */ +RTR3DECL(int) RTHttpGatherCaCertsInStore(RTCRSTORE hStore, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Gathers certificates into a file that can be used with RTHttpSetCAFile. + * + * This is a just a combination of RTHttpGatherCaCertsInStore and + * RTCrStoreCertExportAsPem. + * + * @returns IPRT status code. + * @param pszCaFile The output file. + * @param fFlags RTHTTPGATHERCACERT_F_XXX. + * @param pErrInfo Where to store additional error/warning information. + * Optional. + */ +RTR3DECL(int) RTHttpGatherCaCertsInFile(const char *pszCaFile, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Set whether to verify the peer's SSL certificate. + * + * The default is to verify it. It can however sometimes be useful or even + * necessary to skip this. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param fVerify Verify the certificate if @a true. + */ +RTR3DECL(int) RTHttpSetVerifyPeer(RTHTTP hHttp, bool fVerify); + +/** + * Get the state of the peer's SSL certificate setting. + * + * @returns true if we verify the SSL certificate, false if not. + * @param hHttp The HTTP client handle. + */ +RTR3DECL(bool) RTHttpGetVerifyPeer(RTHTTP hHttp); + +/** + * Callback function to be called during RTHttpGet*(). + * + * Register it using RTHttpSetDownloadProgressCallback(). + * + * @param hHttp The HTTP client handle. + * @param pvUser The user parameter specified when registering the callback. + * @param cbDownloadTotal The content-length value, if available. + * Warning! Not entirely clear what it will be if + * unavailable, probably 0. + * @param cbDownloaded How much was downloaded thus far. + */ +typedef DECLCALLBACKTYPE(void, FNRTHTTPDOWNLDPROGRCALLBACK,(RTHTTP hHttp, void *pvUser, uint64_t cbDownloadTotal, + uint64_t cbDownloaded)); +/** Pointer to a download progress callback. */ +typedef FNRTHTTPDOWNLDPROGRCALLBACK *PFNRTHTTPDOWNLDPROGRCALLBACK; + +/** + * Set the callback function which is called during (GET) + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pfnCallback Progress function to be called. Set it to + * NULL to disable the callback. + * @param pvUser Convenience pointer for the callback function. + */ +RTR3DECL(int) RTHttpSetDownloadProgressCallback(RTHTTP hHttp, PFNRTHTTPDOWNLDPROGRCALLBACK pfnCallback, void *pvUser); + +/** + * Callback function for receiving body data. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pvBuf Pointer to buffer with body bytes. + * @param cbBuf Number of bytes in the buffer. + * @param uHttpStatus The HTTP status code. + * @param offContent The byte offset corresponding to the start of @a pvBuf. + * @param cbContent The content length field value, UINT64_MAX if not available. + * @param pvUser The user parameter. + * + * @note The @a offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The + * value is the sum of the previous @a cbBuf values. + */ +typedef DECLCALLBACKTYPE(int, FNRTHTTPDOWNLOADCALLBACK,(RTHTTP hHttp, void const *pvBuf, size_t cbBuf, uint32_t uHttpStatus, + uint64_t offContent, uint64_t cbContent, void *pvUser)); +/** Pointer to a download data receiver callback. */ +typedef FNRTHTTPDOWNLOADCALLBACK *PFNRTHTTPDOWNLOADCALLBACK; + +/** + * Set the callback function for downloading data (HTTP GET). + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param fFlags RTHTTPDOWNLOAD_F_XXX. + * @param pfnCallback The callback function. Pass NULL to reset the callback. + * @param pvUser Convenience pointer for the callback function. + * + * @remarks There can only be one download callback, so it is not possible to + * call this method for different status codes. Only the last one + * with be honored. + * + * @note This only works reliably with RTHttpPerform at the moment. + */ +RTR3DECL(int) RTHttpSetDownloadCallback(RTHTTP hHttp, uint32_t fFlags, PFNRTHTTPDOWNLOADCALLBACK pfnCallback, void *pvUser); + +/** @name RTHTTPDOWNLOAD_F_XXX + * @{ */ +/** The lower 10 bits gives the HTTP status required by the callback. + * For all other status codes, any body data will be returned via the + * RTHttpPerform ppvBody/pcbBody return parameters. */ +#define RTHTTPDOWNLOAD_F_ONLY_STATUS_MASK UINT32_C(0x000003ff) +/** Callback requires no special HTTP status. */ +#define RTHTTPDOWNLOAD_F_ANY_STATUS UINT32_C(0x000003ff) +/** @} */ + + +/** + * Callback function for producing body data for uploading. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pvBuf Where to put the data to upload + * @param cbBuf Max number of bytes to provide. + * @param offContent The byte offset corresponding to the start of @a pvBuf. + * @param pcbActual Actual number of bytes provided. + * @param pvUser The user parameter. + * + * @note The @a offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The + * value is the sum of the previously returned @a *pcbActual values. + */ +typedef DECLCALLBACKTYPE(int, FNRTHTTPUPLOADCALLBACK,(RTHTTP hHttp, void *pvBuf, size_t cbBuf, uint64_t offContent, + size_t *pcbActual, void *pvUser)); +/** Pointer to an upload data producer callback. */ +typedef FNRTHTTPUPLOADCALLBACK *PFNRTHTTPUPLOADCALLBACK; + +/** + * Set the callback function for providing upload data (HTTP PUT / POST). + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param cbContent The content length, UINT64_MAX if not know or specified separately. + * @param pfnCallback The callback function. Pass NULL to reset the callback. + * @param pvUser Convenience pointer for the callback function. + * + * @note This only works reliably with RTHttpPerform at the moment. + */ +RTR3DECL(int) RTHttpSetUploadCallback(RTHTTP hHttp, uint64_t cbContent, PFNRTHTTPUPLOADCALLBACK pfnCallback, void *pvUser); + + +/** + * Callback for consuming header fields. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param uMatchWord Match word constructed by RTHTTP_MAKE_HDR_MATCH_WORD + * @param pchField The field name (not zero terminated). + * Not necessarily valid UTF-8! + * @param cchField The length of the field. + * @param pchValue The field value (not zero terminated). + * Not necessarily valid UTF-8! + * @param cchValue The length of the value. + * @param pvUser The user parameter. + * + * @remarks This is called with two fictitious header fields too: + * - ':http-status-line' -- the HTTP/{version} {status-code} stuff. + * - ':end-of-headers' -- marks the end of header callbacks. + */ +typedef DECLCALLBACKTYPE(int, FNRTHTTPHEADERCALLBACK,(RTHTTP hHttp, uint32_t uMatchWord, const char *pchField, size_t cchField, + const char *pchValue, size_t cchValue, void *pvUser)); +/** Pointer to a header field consumer callback. */ +typedef FNRTHTTPHEADERCALLBACK *PFNRTHTTPHEADERCALLBACK; + +/** + * Forms a fast header match word. + * + * @returns Fast header match word. + * @param a_cchField The length of the header field name. + * @param a_chLower1 The first character in the name, lowercased. + * @param a_chLower2 The second character in the name, lowercased. + * @param a_chLower3 The third character in the name, lowercased. + */ +#define RTHTTP_MAKE_HDR_MATCH_WORD(a_cchField, a_chLower1, a_chLower2, a_chLower3) \ + RT_MAKE_U32_FROM_U8(a_cchField, a_chLower1, a_chLower2, a_chLower3) + +/** + * Set the callback function for processing header fields in the response. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pfnCallback The callback function. Pass NULL to reset the callback. + * @param pvUser Convenience pointer for the callback function. + * + * @note This only works reliably with RTHttpPerform at the moment. + */ +RTR3DECL(int) RTHttpSetHeaderCallback(RTHTTP hHttp, PFNRTHTTPHEADERCALLBACK pfnCallback, void *pvUser); + + +/** + * Supported proxy types. + */ +typedef enum RTHTTPPROXYTYPE +{ + RTHTTPPROXYTYPE_INVALID = 0, + RTHTTPPROXYTYPE_NOPROXY, + RTHTTPPROXYTYPE_HTTP, + RTHTTPPROXYTYPE_HTTPS, + RTHTTPPROXYTYPE_SOCKS4, + RTHTTPPROXYTYPE_SOCKS5, + RTHTTPPROXYTYPE_UNKNOWN, + RTHTTPPROXYTYPE_END, + RTHTTPPROXYTYPE_32BIT_HACK = 0x7fffffff +} RTHTTPPROXYTYPE; + +/** + * Proxy information returned by RTHttpQueryProxyInfoForUrl. + */ +typedef struct RTHTTPPROXYINFO +{ + /** Proxy host name. */ + char *pszProxyHost; + /** Proxy port number (UINT32_MAX if not specified). */ + uint32_t uProxyPort; + /** The proxy type (RTHTTPPROXYTYPE_HTTP, RTHTTPPROXYTYPE_SOCKS5, ++). */ + RTHTTPPROXYTYPE enmProxyType; + /** Proxy username. */ + char *pszProxyUsername; + /** Proxy password. */ + char *pszProxyPassword; +} RTHTTPPROXYINFO; +/** A pointer to proxy information structure. */ +typedef RTHTTPPROXYINFO *PRTHTTPPROXYINFO; + +/** + * Retrieve system proxy information for the specified URL. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pszUrl The URL that needs to be accessed via proxy. + * @param pProxyInfo Where to return the proxy information. This must be + * freed up by calling RTHttpFreeProxyInfo() when done. + */ +RTR3DECL(int) RTHttpQueryProxyInfoForUrl(RTHTTP hHttp, const char *pszUrl, PRTHTTPPROXYINFO pProxyInfo); + +/** + * Counter part to RTHttpQueryProxyInfoForUrl that releases any memory returned + * in the proxy info structure. + * + * @returns IPRT status code. + * @param pProxyInfo Pointer to proxy info returned by a successful + * RTHttpQueryProxyInfoForUrl() call. + */ +RTR3DECL(int) RTHttpFreeProxyInfo(PRTHTTPPROXYINFO pProxyInfo); + +/** @name thin wrappers for setting one or a few related curl options + * @remarks Temporary. Will not be included in the 7.0 release! + * @{ */ +typedef DECLCALLBACKTYPE_EX(size_t, RT_NOTHING, FNRTHTTPREADCALLBACKRAW,(void *pbDst, size_t cbItem, size_t cItems, void *pvUser)); +typedef FNRTHTTPREADCALLBACKRAW *PFNRTHTTPREADCALLBACKRAW; +#define RT_HTTP_READCALLBACK_ABORT 0x10000000 /* CURL_READFUNC_ABORT */ +RTR3DECL(int) RTHttpRawSetReadCallback(RTHTTP hHttp, PFNRTHTTPREADCALLBACKRAW pfnRead, void *pvUser); + +typedef DECLCALLBACKTYPE_EX(size_t, RT_NOTHING, FNRTHTTPWRITECALLBACKRAW,(char *pbSrc, size_t cbItem, size_t cItems, void *pvUser)); +typedef FNRTHTTPWRITECALLBACKRAW *PFNRTHTTPWRITECALLBACKRAW; +RTR3DECL(int) RTHttpRawSetWriteCallback(RTHTTP hHttp, PFNRTHTTPWRITECALLBACKRAW pfnWrite, void *pvUser); +RTR3DECL(int) RTHttpRawSetWriteHeaderCallback(RTHTTP hHttp, PFNRTHTTPWRITECALLBACKRAW pfnWrite, void *pvUser); + +RTR3DECL(int) RTHttpRawSetUrl(RTHTTP hHttp, const char *pszUrl); + +RTR3DECL(int) RTHttpRawSetGet(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetHead(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetPost(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetPut(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetDelete(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetCustomRequest(RTHTTP hHttp, const char *pszVerb); + +RTR3DECL(int) RTHttpRawSetPostFields(RTHTTP hHttp, const void *pv, size_t cb); +RTR3DECL(int) RTHttpRawSetInfileSize(RTHTTP hHttp, RTFOFF cb); + +RTR3DECL(int) RTHttpRawSetVerbose(RTHTTP hHttp, bool fValue); +RTR3DECL(int) RTHttpRawSetTimeout(RTHTTP hHttp, long sec); + +RTR3DECL(int) RTHttpRawPerform(RTHTTP hHttp); + +RTR3DECL(int) RTHttpRawGetResponseCode(RTHTTP hHttp, long *plCode); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_http_h */ + diff --git a/include/iprt/inifile.h b/include/iprt/inifile.h new file mode 100644 index 00000000..bc784bc5 --- /dev/null +++ b/include/iprt/inifile.h @@ -0,0 +1,150 @@ +/* $Id: inifile.h $ */ +/** @file + * IPRT - INI-file parser. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_inifile_h +#define IPRT_INCLUDED_inifile_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_inifile RTIniFile - INI-file parser + * @ingroup grp_rt + * @{ + */ + +/** @name RTINIFILE_F_XXX - INI-file open flags. + * @{ */ +/** Readonly. */ +#define RTINIFILE_F_READONLY RT_BIT(0) +/** Valid mask. */ +#define RTINIFILE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + + + +/** + * Creates a INI-file instance from a VFS file handle. + * + * @returns IPRT status code + * @param phIniFile Where to return the INI-file handle. + * @param hVfsFile The VFS file handle (not consumed, additional + * reference is retained). + * @param fFlags Flags, RTINIFILE_F_XXX. + */ +RTDECL(int) RTIniFileCreateFromVfsFile(PRTINIFILE phIniFile, RTVFSFILE hVfsFile, uint32_t fFlags); + +/** + * Retains a reference to an INI-file instance. + * + * @returns New reference count, UINT32_MAX on failure. + * @param hIniFile The INI-file handle. + */ +RTDECL(uint32_t) RTIniFileRetain(RTINIFILE hIniFile); + +/** + * Releases a reference to an INI-file instance, destroying it if the count + * reaches zero. + * + * @returns New reference count, UINT32_MAX on failure. + * @param hIniFile The INI-file handle. NIL is ignored. + */ +RTDECL(uint32_t) RTIniFileRelease(RTINIFILE hIniFile); + +/** + * Queries a named value in a section. + * + * The first matching value is returned. The matching is by default case + * insensitive. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if section or key not found. + * + * @param hIniFile The INI-file handle. + * @param pszSection The section name. Pass NULL to refer to the + * unsectioned key space at the top of the file. + * @param pszKey The key name. + * @param pszValue Where to return the value. + * @param cbValue Size of the buffer @a pszValue points to. + * @param pcbActual Where to return the actual value size excluding + * terminator on success. On VERR_BUFFER_OVERFLOW this + * will be set to the buffer size needed to hold the + * value, terminator included. Optional. + */ +RTDECL(int) RTIniFileQueryValue(RTINIFILE hIniFile, const char *pszSection, const char *pszKey, + char *pszValue, size_t cbValue, size_t *pcbActual); + +/** + * Queries a key-value pair in a section by ordinal. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the section wasn't found or if it contains no pair + * with the given ordinal value. + * + * @param hIniFile The INI-file handle. + * @param pszSection The section name. Pass NULL to refer to the + * unsectioned key space at the top of the file. + * @param idxPair The pair to fetch (counting from 0). + * + * @param pszKey Where to return the key name. + * @param cbKey Size of the buffer @a pszKey points to. + * @param pcbKeyActual Where to return the actual key size excluding + * terminator on success. On VERR_BUFFER_OVERFLOW this + * will be set to the buffer size needed to hold the + * value, terminator included. Optional. + * + * @param pszValue Where to return the value. + * @param cbValue Size of the buffer @a pszValue points to. + * @param pcbValueActual Where to return the actual value size excluding + * terminator on success. On VERR_BUFFER_OVERFLOW this + * will be set to the buffer size needed to hold the + * value, terminator included. Optional. + */ +RTDECL(int) RTIniFileQueryPair(RTINIFILE hIniFile, const char *pszSection, uint32_t idxPair, + char *pszKey, size_t cbKey, size_t *pcbKeyActual, + char *pszValue, size_t cbValue, size_t *pcbValueActual); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_inifile_h */ + diff --git a/include/iprt/initterm.h b/include/iprt/initterm.h new file mode 100644 index 00000000..8083d559 --- /dev/null +++ b/include/iprt/initterm.h @@ -0,0 +1,291 @@ +/** @file + * IPRT - Runtime Init/Term. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_initterm_h +#define IPRT_INCLUDED_initterm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt IPRT C/C++ APIs + * @{ + */ + +/** @defgroup grp_rt_initterm RTInit/RTTerm - Initialization and Termination + * + * APIs for initializing and terminating the IPRT, optionally it can also + * convert input arguments to UTF-8 (in ring-3). + * + * @sa RTOnce, RTOnceEx. + * + * @{ + */ + +#ifdef IN_RING3 + +/** @name RTR3INIT_FLAGS_XXX - RTR3Init* flags. + * @see RTR3InitExeNoArguments, RTR3InitExe, RTR3InitDll, RTR3InitEx + * @{ */ +/** Initializing IPRT from a DLL. */ +# define RTR3INIT_FLAGS_DLL RT_BIT(0) +/** The caller ensures that the argument vector is UTF-8. */ +# define RTR3INIT_FLAGS_UTF8_ARGV RT_BIT(1) +/** Indicates that this is a standalone application without any additional + * shared libraries in the application directory. Mainly windows loader mess. */ +# define RTR3INIT_FLAGS_STANDALONE_APP RT_BIT(2) +/** We are sharing a process space, so we need to behave. */ +# define RTR3INIT_FLAGS_UNOBTRUSIVE RT_BIT(3) + +/** Initialize SUPLib (must not fail). */ +# define RTR3INIT_FLAGS_SUPLIB RT_BIT(16) +/** Try initialize SUPLib and ignore failures. */ +# define RTR3INIT_FLAGS_TRY_SUPLIB RT_BIT(17) +/** Shift count for passing thru SUPR3INIT_F_XXX flags. */ +# define RTR3INIT_FLAGS_SUPLIB_SHIFT 18 +/** The mask covering the passthru SUPR3INIT_F_XXX flags. */ +# define RTR3INIT_FLAGS_SUPLIB_MASK UINT32_C(0xfffc0000) + +/** Valid flag mask. */ +# define RTR3INIT_FLAGS_VALID_MASK UINT32_C(0xffff000f) +/** @} */ + +/** @name RTR3InitEx version + * @{ */ +/** Version 1. */ +# define RTR3INIT_VER_1 UINT32_C(1) +/** Version 2 - new flags, rearranged a bit. */ +# define RTR3INIT_VER_2 UINT32_C(2) +/** The current version. */ +# define RTR3INIT_VER_CUR RTR3INIT_VER_2 +/** @} */ + +/** + * Initializes the runtime library. + * + * @returns iprt status code. + * @param fFlags Flags, see RTR3INIT_FLAGS_XXX. + */ +RTR3DECL(int) RTR3InitExeNoArguments(uint32_t fFlags); + +/** + * Initializes the runtime library. + * + * @returns iprt status code. + * @param cArgs Pointer to the argument count. + * @param ppapszArgs Pointer to the argument vector pointer. + * @param fFlags Flags, see RTR3INIT_FLAGS_XXX. + */ +RTR3DECL(int) RTR3InitExe(int cArgs, char ***ppapszArgs, uint32_t fFlags); + +/** + * Initializes the runtime library. + * + * @returns iprt status code. + * @param fFlags Flags, see RTR3INIT_FLAGS_XXX. + */ +RTR3DECL(int) RTR3InitDll(uint32_t fFlags); + +/** + * Initializes the runtime library and possibly also SUPLib too. + * + * Avoid this interface, it's not considered stable. + * + * @returns IPRT status code. + * @param iVersion The interface version. Must be 0 atm. + * @param fFlags Flags, see RTR3INIT_FLAGS_XXX. + * @param cArgs Pointer to the argument count. + * @param ppapszArgs Pointer to the argument vector pointer. NULL + * allowed if @a cArgs is 0. + * @param pszProgramPath The program path. Pass NULL if we're to figure it + * out ourselves. + */ +RTR3DECL(int) RTR3InitEx(uint32_t iVersion, uint32_t fFlags, int cArgs, char ***ppapszArgs, const char *pszProgramPath); + +/** + * Terminates the runtime library. + */ +RTR3DECL(void) RTR3Term(void); + +/** + * Is IPRT succesfully initialized? + * + * @returns true/false. + */ +RTR3DECL(bool) RTR3InitIsInitialized(void); + +/** + * Are we running in unobtrusive mode? + * @returns true/false. + */ +RTR3DECL(bool) RTR3InitIsUnobtrusive(void); + +#endif /* IN_RING3 */ + + +#ifdef IN_RING0 +/** + * Initializes the ring-0 driver runtime library. + * + * @returns iprt status code. + * @param fReserved Flags reserved for the future. + */ +RTR0DECL(int) RTR0Init(unsigned fReserved); + +/** + * Terminates the ring-0 driver runtime library. + */ +RTR0DECL(void) RTR0Term(void); + +/** + * Forcibily terminates the ring-0 driver runtime library. + * + * This should be used when statically linking the IPRT. Module using dynamic + * linking shall use RTR0Term. If you're not sure, use RTR0Term! + */ +RTR0DECL(void) RTR0TermForced(void); +#endif + +#ifdef IN_RC +/** + * Initializes the raw-mode context runtime library. + * + * @returns iprt status code. + * + * @param u64ProgramStartNanoTS The startup timestamp. + */ +RTRCDECL(int) RTRCInit(uint64_t u64ProgramStartNanoTS); + +/** + * Terminates the raw-mode context runtime library. + */ +RTRCDECL(void) RTRCTerm(void); +#endif + + +/** + * Termination reason. + */ +typedef enum RTTERMREASON +{ + /** Normal exit. iStatus contains the exit code. */ + RTTERMREASON_EXIT = 1, + /** Any abnormal exit. iStatus is 0 and has no meaning. */ + RTTERMREASON_ABEND, + /** Killed by a signal. The iStatus contains the signal number. */ + RTTERMREASON_SIGNAL, + /** The IPRT module is being unloaded. iStatus is 0 and has no meaning. */ + RTTERMREASON_UNLOAD +} RTTERMREASON; + +/** Whether lazy clean up is Okay or not. + * When the process is exiting, it is a waste of time to for instance free heap + * memory or close open files. OTOH, when the runtime is unloaded from the + * process, it is important to release absolutely all resources to prevent + * resource leaks. */ +#define RTTERMREASON_IS_LAZY_CLEANUP_OK(enmReason) ((enmReason) != RTTERMREASON_UNLOAD) + + +/** + * IPRT termination callback function. + * + * @param enmReason The cause of the termination. + * @param iStatus The meaning of this depends on enmReason. + * @param pvUser User argument passed to RTTermRegisterCallback. + */ +typedef DECLCALLBACKTYPE(void, FNRTTERMCALLBACK,(RTTERMREASON enmReason, int32_t iStatus, void *pvUser)); +/** Pointer to an IPRT termination callback function. */ +typedef FNRTTERMCALLBACK *PFNRTTERMCALLBACK; + + +/** + * Registers a termination callback. + * + * This is intended for performing clean up during IPRT termination. Frequently + * paired with lazy initialization thru RTOnce. + * + * The callbacks are called in LIFO order. + * + * @returns IPRT status code. + * + * @param pfnCallback The callback function. + * @param pvUser The user argument for the callback. + * + * @remarks May need to acquire a fast mutex or critical section, so use with + * some care in ring-0 context. + * + * @remarks Be very careful using this from code that may be unloaded before + * IPRT terminates. Unlike some atexit and on_exit implementations, + * IPRT will not automatically unregister callbacks when a module gets + * unloaded. + */ +RTDECL(int) RTTermRegisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser); + +/** + * Deregister a termination callback. + * + * @returns VINF_SUCCESS if found, VERR_NOT_FOUND if the callback/pvUser pair + * wasn't found. + * + * @param pfnCallback The callback function. + * @param pvUser The user argument for the callback. + */ +RTDECL(int) RTTermDeregisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser); + +/** + * Runs the termination callback queue. + * + * Normally called by an internal IPRT termination function, but may also be + * called by external code immediately prior to terminating IPRT if it is in a + * better position to state the termination reason and/or status. + * + * @param enmReason The reason why it's called. + * @param iStatus The associated exit status or signal number. + */ +RTDECL(void) RTTermRunCallbacks(RTTERMREASON enmReason, int32_t iStatus); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + + +#endif /* !IPRT_INCLUDED_initterm_h */ + diff --git a/include/iprt/ioqueue.h b/include/iprt/ioqueue.h new file mode 100644 index 00000000..92f1e2f1 --- /dev/null +++ b/include/iprt/ioqueue.h @@ -0,0 +1,405 @@ +/** @file + * IPRT Generic I/O queue API. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ioqueue_h +#define IPRT_INCLUDED_ioqueue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_ioqueue IPRT generic I/O queue API + * @ingroup grp_rt + * + * This API models a generic I/O queue which can be attached to different providers + * for different types of handles. + * + * @{ + */ + + +/** + * I/O queue request operations. + */ +typedef enum RTIOQUEUEOP +{ + /** The usual invalid option. */ + RTIOQUEUEOP_INVALID = 0, + /** Read request. */ + RTIOQUEUEOP_READ, + /** Write request. */ + RTIOQUEUEOP_WRITE, + /** Synchronize (i.e. flush) request. */ + RTIOQUEUEOP_SYNC, + /** Usual 32bit hack. */ + RTIOQUEUEOP_32BIT_HACK = 0x7fffffff +} RTIOQUEUEOP; +/** Pointer to a I/O queue operation code. */ +typedef RTIOQUEUEOP *PRTIOQUEUEOP; + +/** I/O queue provider (processes requests put into the I/O queue) handle. */ +typedef struct RTIOQUEUEPROVINT *RTIOQUEUEPROV; +/** I/O queue handle. */ +typedef struct RTIOQUEUEINT *RTIOQUEUE; +/** Pointer to an I/O queue handle. */ +typedef RTIOQUEUE *PRTIOQUEUE; +/** NIL I/O queue handle value. */ +#define NIL_RTIOQUEUE ((RTIOQUEUE)0) + + +/** + * I/O queue completion event. + */ +typedef struct RTIOQUEUECEVT +{ + /** The user data passed when preparing the request. */ + void *pvUser; + /** The IPRT status code for this request. */ + int rcReq; + /** Transferred data size if applicaple by the request. */ + size_t cbXfered; +} RTIOQUEUECEVT; +/** Pointer to a I/O queue completion event. */ +typedef RTIOQUEUECEVT *PRTIOQUEUECEVT; +/** Pointer to a const I/O queue completion event. */ +typedef const RTIOQUEUECEVT *PCRTIOQUEUECEVT; + + +/** + * I/O queue provider virtual method table. + */ +typedef struct RTIOQUEUEPROVVTABLE +{ + /** The structure version (RTIOQUEUEPROVVTABLE_VERSION). */ + uint32_t uVersion; + /** Provider ID. */ + const char *pszId; + /** Size of provider specific data for an I/O queue instance. */ + size_t cbIoQueueProv; + /** The handle type the provider is able to process. */ + RTHANDLETYPE enmHnd; + /** Additional flags for exposing supported features or quirks to the user. */ + uint32_t fFlags; + + /** + * Returns whether the provider is supported on the calling host system. + * + * @returns Flag whether the provider is supported. + */ + DECLCALLBACKMEMBER(bool, pfnIsSupported,(void)); + + /** + * Initializes the provider specific parts of the given I/O queue. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance to initialize. + * @param fFlags Flags for the queue. + * @param cSqEntries Number of entries for the submission queue. + * @param cCqEntries Number of entries for the completion queue. + */ + DECLCALLBACKMEMBER(int, pfnQueueInit,(RTIOQUEUEPROV hIoQueueProv, uint32_t fFlags, uint32_t cSqEntries, uint32_t cCqEntries)); + + /** + * Destroys the provider specific parts of the I/O queue and frees all + * associated resources. + * + * @returns nothing. + * @param hIoQueueProv The I/O queue provider instance to destroy. + */ + DECLCALLBACKMEMBER(void, pfnQueueDestroy,(RTIOQUEUEPROV hIoQueueProv)); + + /** + * Registers the given handle for use with the I/O queue instance. + * The generic code already checked for the correct handle type and that the + * handle wasn't registered already by tracking all registered handles. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pHandle The handle to register. + */ + DECLCALLBACKMEMBER(int, pfnHandleRegister,(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle)); + + /** + * Deregisters the given handle for use with the I/O queue instance. + * The generic code already checked for the correct handle type and that the + * handle was registered previously. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pHandle The handle to deregister. + */ + DECLCALLBACKMEMBER(int, pfnHandleDeregister,(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle)); + + /** + * Prepares a request for the given I/O queue. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pHandle The handle the request is for. + * @param enmOp The operation to perform. + * @param off Start offset (if applicable, not all handles support/require it and will ignore it). + * @param pvBuf Buffer to use for read/write operations (sync ignores this). + * @param cbBuf Size of the buffer in bytes. + * @param fReqFlags Additional flags for the request. + * @param pvUser Opaque user data which is passed back in the completion event. + */ + DECLCALLBACKMEMBER(int, pfnReqPrepare,(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, void *pvBuf, size_t cbBuf, uint32_t fReqFlags, void *pvUser)); + + /** + * Prepares a request for the given I/O queue. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pHandle The handle the request is for. + * @param enmOp The operation to perform. + * @param off Start offset (if applicable, not all handles support/require it and will ignore it). + * @param pSgBuf The S/G buufer to use for read/write operations (sync ignores this). + * @param cbSg Number of bytes to transfer from the S/G buffer. + * @param fReqFlags Additional flags for the request. + * @param pvUser Opaque user data which is passed back in the completion event. + */ + DECLCALLBACKMEMBER(int, pfnReqPrepareSg,(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, PCRTSGBUF pSgBuf, size_t cbSg, uint32_t fReqFlags, void *pvUser)); + + /** + * Commits all prepared requests to the consumer for processing. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pcReqsCommitted Where to store the number of requests actually committed. + */ + DECLCALLBACKMEMBER(int, pfnCommit,(RTIOQUEUEPROV hIoQueueProv, uint32_t *pcReqsCommitted)); + + /** + * Waits for completion events from the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_EMPTY if there is nothing to wait for. + * @param hIoQueueProv The I/O queue provider instance. + * @param paCEvt Pointer to the array of completion event entries to fill. + * @param cCEvt Size of the completion event entry array. + * @param cMinWait Minimum number of completion events to wait for before returning. + * @param pcCEvt Where to store the number of completion events on success. + * @param fFlags Additional flags controlling the wait behavior. + */ + DECLCALLBACKMEMBER(int, pfnEvtWait,(RTIOQUEUEPROV hIoQueueProv, PRTIOQUEUECEVT paCEvt, uint32_t cCEvt, + uint32_t cMinWait, uint32_t *pcCEvt, uint32_t fFlags)); + + /** + * Wakes up the thread waiting in RTIOQUEUEPROVVTABLE::pfnEvtWait(). + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + */ + DECLCALLBACKMEMBER(int, pfnEvtWaitWakeup,(RTIOQUEUEPROV hIoQueueProv)); + + /** Marks the end of the structure (RTIOQUEUEPROVVTABLE_VERSION). */ + uintptr_t uEndMarker; +} RTIOQUEUEPROVVTABLE; +/** Pointer to an I/O queue provider vtable. */ +typedef RTIOQUEUEPROVVTABLE *PRTIOQUEUEPROVVTABLE; +/** Pointer to a const I/O queue provider vtable. */ +typedef RTIOQUEUEPROVVTABLE const *PCRTIOQUEUEPROVVTABLE; + +/** The RTIOQUEUEPROVVTABLE structure version. */ +#define RTIOQUEUEPROVVTABLE_VERSION RT_MAKE_U32_FROM_U8(0xff,0xf,1,0) + +/** @name RTIOQUEUEPROVVTABLE::fFlags + * @{ */ +/** Provider supports S/G lists. */ +#define RTIOQUEUEPROVVTABLE_F_SG RT_BIT_32(0) +/** Mask of the valid I/O stream feature flags. */ +#define RTIOQUEUEPROVVTABLE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + + +/** + * Tries to return the best I/O queue provider for the given handle type on the called + * host system. + * + * @returns Pointer to the I/O queue provider handle table or NULL if no suitable + * provider was found for the given handle type. + * @param enmHnd The handle type to look for a provider. + */ +RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetBestForHndType(RTHANDLETYPE enmHnd); + + +/** + * Returns the I/O queue provider with the given ID. + * + * @returns Pointer to the I/O queue provider handle table or NULL if no provider with + * the given ID was found. + * @param pszId The ID to look for. + */ +RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetById(const char *pszId); + + +/** + * Creates a new I/O queue with the given consumer. + * + * @returns IPRT status code. + * @param phIoQueue Where to store the handle to the I/O queue on success. + * @param pProvVTable The I/O queue provider vtable which will process the requests. + * @param fFlags Flags for the queue (MBZ for now). + * @param cSqEntries Number of entries for the submission queue. + * @param cCqEntries Number of entries for the completion queue. + * + * @note The number of submission and completion queue entries serve only as a hint to the + * provider implementation. It may decide to align the number to a smaller or greater + * size. + */ +RTDECL(int) RTIoQueueCreate(PRTIOQUEUE phIoQueue, PCRTIOQUEUEPROVVTABLE pProvVTable, + uint32_t fFlags, uint32_t cSqEntries, uint32_t cCqEntries); + + +/** + * Destroys the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_BUSY if the I/O queue is still processing requests. + * @param hIoQueue The I/O queue handle to destroy. + */ +RTDECL(int) RTIoQueueDestroy(RTIOQUEUE hIoQueue); + + +/** + * Registers the given handle for use with the I/O queue. + * + * @returns IPRT status code. + * @retval VERR_ALREADY_EXISTS if the handle was already registered. + * @retval VERR_NOT_SUPPORTED if the handle type is not supported by the consumer + * for the given I/O queue. + * @param hIoQueue The I/O queue handle. + * @param pHandle The handle to register. + */ +RTDECL(int) RTIoQueueHandleRegister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle); + + +/** + * Deregisters the given handle from the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_HANDLE_NOT_REGISTERED if the handle wasn't registered by a call to RTIoQueueHandleRegister(). + * @param hIoQueue The I/O queue handle. + * @param pHandle The handle to deregister. + */ +RTDECL(int) RTIoQueueHandleDeregister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle); + + +/** + * Prepares a request for the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_FULL if the I/O queue can't accept the new request because the submission queue is full. + * @retval VERR_IOQUEUE_HANDLE_NOT_REGISTERED if the handle wasn't registered for use with RTIoQueueHandleRegister() yet. + * @param hIoQueue The I/O queue handle. + * @param pHandle The handle the request is for. + * @param enmOp The operation to perform. + * @param off Start offset (if applicable, not all handles support/require it and will ignore it). + * @param pvBuf Buffer to use for read/write operations (sync ignores this). + * @param cbBuf Size of the buffer in bytes. + * @param fReqFlags Additional flags for the request. + * @param pvUser Opaque user data which is passed back in the completion event. + */ +RTDECL(int) RTIoQueueRequestPrepare(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, void *pvBuf, size_t cbBuf, uint32_t fReqFlags, + void *pvUser); + + +/** + * Prepares a request for the given I/O queue - S/G buffer variant. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_FULL if the I/O queue can't accept the new request because the submission queue is full. + * @retval VERR_IOQUEUE_HANDLE_NOT_REGISTERED if the handle wasn't registered for use with RTIoQueueHandleRegister() yet. + * @param hIoQueue The I/O queue handle. + * @param pHandle The handle the request is for. + * @param enmOp The operation to perform. + * @param off Start offset (if applicable, not all handles support/require it and will ignore it). + * @param pSgBuf The S/G buufer to use for read/write operations (sync ignores this). + * @param cbSg Number of bytes to transfer from the S/G buffer. + * @param fReqFlags Additional flags for the request. + * @param pvUser Opaque user data which is passed back in the completion event. + */ +RTDECL(int) RTIoQueueRequestPrepareSg(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, PCRTSGBUF pSgBuf, size_t cbSg, uint32_t fReqFlags, + void *pvUser); + + +/** + * Commits all prepared requests to the consumer for processing. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_EMPTY if there is nothing to commit. + * @param hIoQueue The I/O queue handle. + */ +RTDECL(int) RTIoQueueCommit(RTIOQUEUE hIoQueue); + + +/** + * Waits for completion events from the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_EMPTY if there is nothing to wait for. + * @param hIoQueue The I/O queue handle. + * @param paCEvt Pointer to the array of completion event entries to fill. + * @param cCEvt Size of the completion event entry array. + * @param cMinWait Minimum number of completion events to wait for before returning. + * @param pcCEvt Where to store the number of completion events on success. + * @param fFlags Additional flags controlling the wait behavior. + */ +RTDECL(int) RTIoQueueEvtWait(RTIOQUEUE hIoQueue, PRTIOQUEUECEVT paCEvt, uint32_t cCEvt, uint32_t cMinWait, + uint32_t *pcCEvt, uint32_t fFlags); + + +/** + * Wakes up the thread waiting in RTIoQueueEvtWait(). + * + * @returns IPRT status code. + * @param hIoQueue The I/O queue handle to wake up. + */ +RTDECL(int) RTIoQueueEvtWaitWakeup(RTIOQUEUE hIoQueue); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_ioqueue_h */ + diff --git a/include/iprt/json.h b/include/iprt/json.h new file mode 100644 index 00000000..df588736 --- /dev/null +++ b/include/iprt/json.h @@ -0,0 +1,384 @@ +/** @file + * IPRT - JavaScript Object Notation (JSON) Parser. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_json_h +#define IPRT_INCLUDED_json_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_json RTJson - JavaScript Object Notation (JSON) Parser + * @ingroup grp_rt + * @{ + */ + +/** + * JSON value types. + */ +typedef enum RTJSONVALTYPE +{ + /** Invalid first value. */ + RTJSONVALTYPE_INVALID = 0, + /** Value containing an object. */ + RTJSONVALTYPE_OBJECT, + /** Value containing an array. */ + RTJSONVALTYPE_ARRAY, + /** Value containing a string. */ + RTJSONVALTYPE_STRING, + /** Value containg an integer number. */ + RTJSONVALTYPE_INTEGER, + /** Value containg an floating point number. */ + RTJSONVALTYPE_NUMBER, + /** Value containg the special null value. */ + RTJSONVALTYPE_NULL, + /** Value containing true. */ + RTJSONVALTYPE_TRUE, + /** Value containing false. */ + RTJSONVALTYPE_FALSE, + /** 32-bit hack. */ + RTJSONVALTYPE_32BIT_HACK = 0x7fffffff +} RTJSONVALTYPE; +/** Pointer to a JSON value type. */ +typedef RTJSONVALTYPE *PRTJSONVALTYPE; + +/** JSON value handle. */ +typedef struct RTJSONVALINT *RTJSONVAL; +/** Pointer to a JSON value handle. */ +typedef RTJSONVAL *PRTJSONVAL; +/** NIL JSON value handle. */ +#define NIL_RTJSONVAL ((RTJSONVAL)~(uintptr_t)0) + +/** JSON iterator handle. */ +typedef struct RTJSONITINT *RTJSONIT; +/** Pointer to a JSON iterator handle. */ +typedef RTJSONIT *PRTJSONIT; +/** NIL JSON iterator handle. */ +#define NIL_RTJSONIT ((RTJSONIT)~(uintptr_t)0) + +/** + * Parses a JSON document in the provided buffer returning the root JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_MALFORMED if the document does not conform to the spec. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param pbBuf The byte buffer containing the JSON document. + * @param cbBuf Size of the buffer. + * @param pErrInfo Where to store extended error info. Optional. + * + * @todo r=bird: The use of uint8_t makes no sense here since the parser + * expects ASCII / UTF-8. What's more, if this is a real buffer the + * type should be 'const void *' rather than 'const uint8_t *'. + * This function should be modified to reflect that it's really for + * handling unterminated strings. + */ +RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf, PRTERRINFO pErrInfo); + +/** + * Parses a JSON document from the provided string returning the root JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_MALFORMED if the document does not conform to the spec. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param pszStr The string containing the JSON document. + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo); + +/** + * Parses a JSON document from the file pointed to by the given filename + * returning the root JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_MALFORMED if the document does not conform to the spec. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param pszFilename The name of the file containing the JSON document. + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Parses a JSON document from the given VFS file + * returning the root JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_MALFORMED if the document does not conform to the spec. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param hVfsFile The VFS file to parse. + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTJsonParseFromVfsFile(PRTJSONVAL phJsonVal, RTVFSFILE hVfsFile, PRTERRINFO pErrInfo); + +/** + * Retain a given JSON value. + * + * @returns New reference count. + * @param hJsonVal The JSON value handle. + */ +RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal); + +/** + * Release a given JSON value. + * + * @returns New reference count, if this drops to 0 the value is freed. + * @param hJsonVal The JSON value handle. + */ +RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal); + +/** + * Return the type of a given JSON value. + * + * @returns Type of the given JSON value. + * @param hJsonVal The JSON value handle. + */ +RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal); + +/** + * Translates value type to a name. + * + * @returns Readonly name string + * @param enmType The JSON value type to name. + */ +RTDECL(const char *) RTJsonValueTypeName(RTJSONVALTYPE enmType); + +/** + * Returns the string from a given JSON string value. + * + * @returns Pointer to the string of the JSON value, NULL if the value type + * doesn't indicate a string. + * @param hJsonVal The JSON value handle. + */ +RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal); + +/** + * Returns the string from a given JSON string value, extended. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not a string. + * @param hJsonVal The JSON value handle. + * @param ppszStr Where to store the pointer to the string on success. + */ +RTDECL(int) RTJsonValueQueryString(RTJSONVAL hJsonVal, const char **ppszStr); + +/** + * Returns the integer from a given JSON integer value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not a number. + * @param hJsonVal The JSON value handle. + * @param pi64Num WHere to store the number on success. + * @sa RTJsonValueQueryNumber + */ +RTDECL(int) RTJsonValueQueryInteger(RTJSONVAL hJsonVal, int64_t *pi64Num); + +/** + * Returns the floating point value from a given JSON number value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not a number. + * @param hJsonVal The JSON value handle. + * @param prdNum WHere to store the floating point number on success. + * @sa RTJsonValueQueryInteger + */ +RTDECL(int) RTJsonValueQueryNumber(RTJSONVAL hJsonVal, double *prdNum); + +/** + * Returns the value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param phJsonVal Where to store the handle to the JSON value on success. + */ +RTDECL(int) RTJsonValueQueryByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal); + +/** + * Returns the number of a number value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object or + * the name does not point to an integer value. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param pi64Num Where to store the number on success. + */ +RTDECL(int) RTJsonValueQueryIntegerByName(RTJSONVAL hJsonVal, const char *pszName, int64_t *pi64Num); + +/** + * Returns the number of a number value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object or + * the name does not point to a number value. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param prdNum WHere to store the floating point number on success. + */ +RTDECL(int) RTJsonValueQueryNumberByName(RTJSONVAL hJsonVal, const char *pszName, double *prdNum); + +/** + * Returns the string of a string value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object or + * the name does not point to a string value. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param ppszStr Where to store the pointer to the string on success. + * Must be freed with RTStrFree(). + */ +RTDECL(int) RTJsonValueQueryStringByName(RTJSONVAL hJsonVal, const char *pszName, char **ppszStr); + +/** + * Returns the boolean of a true/false value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object or + * the name does not point to a true/false value. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param pfBoolean Where to store the boolean value on success. + */ +RTDECL(int) RTJsonValueQueryBooleanByName(RTJSONVAL hJsonVal, const char *pszName, bool *pfBoolean); + +/** + * Returns the size of a given JSON array value. + * + * @returns Size of the JSON array value. + * @retval 0 if the array is empty or the JSON value is not an array. + * @param hJsonVal The JSON value handle. + */ +RTDECL(unsigned) RTJsonValueGetArraySize(RTJSONVAL hJsonVal); + +/** + * Returns the size of a given JSON array value - extended version. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an array. + * @param hJsonVal The JSON value handle. + * @param pcItems Where to store the size of the JSON array value on success. + */ +RTDECL(int) RTJsonValueQueryArraySize(RTJSONVAL hJsonVal, unsigned *pcItems); + +/** + * Returns the value for the given index of a given JSON array value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an array. + * @retval VERR_OUT_OF_RANGE if @a idx is out of bounds. + * + * @param hJsonVal The JSON value handle. + * @param idx The index to get the value from. + * @param phJsonVal Where to store the handle to the JSON value on success. + */ +RTDECL(int) RTJsonValueQueryByIndex(RTJSONVAL hJsonVal, unsigned idx, PRTJSONVAL phJsonVal); + +/** + * Creates an iterator for a given JSON array or object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an array or + * object. + * @param hJsonVal The JSON value handle. + * @param phJsonIt Where to store the JSON iterator handle on success. + * @todo Make return VERR_JSON_IS_EMPTY (or remove it). + */ +RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt); + +/** + * Creates an iterator for a given JSON array value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an array. + * @retval VERR_JSON_IS_EMPTY if no members. + * @param hJsonVal The JSON value handle. + * @param phJsonIt Where to store the JSON iterator handle on success. + */ +RTDECL(int) RTJsonIteratorBeginArray(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt); + +/** + * Creates an iterator for a given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object. + * @retval VERR_JSON_IS_EMPTY if no members. + * @param hJsonVal The JSON value handle. + * @param phJsonIt Where to store the JSON iterator handle on success. + */ +RTDECL(int) RTJsonIteratorBeginObject(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt); + +/** + * Gets the value and optional name for the current iterator position. + * + * @returns IPRT status code. + * @param hJsonIt The JSON iterator handle. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param ppszName Where to store the object member name for an object. + * NULL is returned for arrays. + */ +RTDECL(int) RTJsonIteratorQueryValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName); + +/** + * Advances to the next element in the referenced JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_ITERATOR_END if the end for this iterator was reached. + * @param hJsonIt The JSON iterator handle. + */ +RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt); + +/** + * Frees a given JSON iterator. + * + * @param hJsonIt The JSON iterator to free. + */ +RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_json_h */ + diff --git a/include/iprt/krnlmod.h b/include/iprt/krnlmod.h new file mode 100644 index 00000000..9b1eb12c --- /dev/null +++ b/include/iprt/krnlmod.h @@ -0,0 +1,202 @@ +/** @file + * IPRT - Kernel module. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_krnlmod_h +#define IPRT_INCLUDED_krnlmod_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_kmod RTKrnlMod - Kernel module/driver userspace side API. + * @ingroup grp_rt + * @{ + */ + +/** + * Checks whether the given kernel module was loaded. + * + * @returns IPRT status code. + * @param pszName The driver name to check. + * @param pfLoaded Where to store the flag whether the module is loaded on success. + */ +RTDECL(int) RTKrnlModQueryLoaded(const char *pszName, bool *pfLoaded); + +/** + * Returns the kernel module information handle for the given loaded kernel module. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the kernel driver is not loaded. + * @param pszName The driver name. + * @param phKrnlModInfo Where to store the handle to the kernel module information record. + */ +RTDECL(int) RTKrnlModLoadedQueryInfo(const char *pszName, PRTKRNLMODINFO phKrnlModInfo); + +/** + * Returns the number of kernel modules loaded on the host system. + * + * @returns Number of kernel modules loaded. + */ +RTDECL(uint32_t) RTKrnlModLoadedGetCount(void); + +/** + * Returns all loaded kernel modules on the host. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if there are not enough entries in the passed handle array. + * The required number of entries will be returned in pcEntries. + * @param pahKrnlModInfo Where to store the handles to the kernel module information records + * on success. + * @param cEntriesMax Maximum number of entries fitting in the given array. + * @param pcEntries Where to store the number of entries used/required. + */ +RTDECL(int) RTKrnlModLoadedQueryInfoAll(PRTKRNLMODINFO pahKrnlModInfo, uint32_t cEntriesMax, + uint32_t *pcEntries); + +/** + * Retains the given kernel module information record handle. + * + * @returns New reference count. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(uint32_t) RTKrnlModInfoRetain(RTKRNLMODINFO hKrnlModInfo); + +/** + * Releases the given kernel module information record handle. + * + * @returns New reference count, on 0 the handle is destroyed. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(uint32_t) RTKrnlModInfoRelease(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the number of references held onto the kernel module by other + * drivers or userspace clients. + * + * @returns Number of references held on the kernel module. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(uint32_t) RTKrnlModInfoGetRefCnt(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the name of the kernel module. + * + * @returns Pointer to the kernel module name. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(const char *) RTKrnlModInfoGetName(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the filepath of the kernel module. + * + * @returns Pointer to the kernel module path. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(const char *) RTKrnlModInfoGetFilePath(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the size of the kernel module. + * + * @returns Size of the kernel module in bytes. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(size_t) RTKrnlModInfoGetSize(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the load address of the kernel module. + * + * @returns Load address of the kernel module. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(RTR0UINTPTR) RTKrnlModInfoGetLoadAddr(RTKRNLMODINFO hKrnlModInfo); + +/** + * Query the kernel information record for a referencing kernel module of the + * given record. + * + * @returns IPRT status code. + * @param hKrnlModInfo The kernel module information record handle. + * @param idx Referencing kernel module index (< reference count + * as retrieved by RTKrnlModInfoGetRefCnt() ). + * @param phKrnlModInfoRef Where to store the handle to the referencing kernel module + * information record. + */ +RTDECL(int) RTKrnlModInfoQueryRefModInfo(RTKRNLMODINFO hKrnlModInfo, uint32_t idx, + PRTKRNLMODINFO phKrnlModInfoRef); + +/** + * Tries to load a kernel module by the given name. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported by or implemented for the platform. + * @param pszName The name of the kernel module. This is highly platform + * dependent. + * + * @note On macOS for example the name is the bundle ID. + */ +RTDECL(int) RTKrnlModLoadByName(const char *pszName); + +/** + * Tries to load a kernel module by the given file path. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported by or implemented for the platform. + * @param pszPath The path of the kernel module. + */ +RTDECL(int) RTKrnlModLoadByPath(const char *pszPath); + +/** + * Tries to unload a kernel module by the given name. + * + * @returns IPRT status code. + * @param pszName The name of the kernel module. This is highly platform + * dependent and should be queried with RTKrnlModInfoGetName() + * when checking whether the module was actually loaded. + * + * @note On macOS for example the name is the bundle ID. + */ +RTDECL(int) RTKrnlModUnloadByName(const char *pszName); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_krnlmod_h */ + diff --git a/include/iprt/latin1.h b/include/iprt/latin1.h new file mode 100644 index 00000000..074c1e65 --- /dev/null +++ b/include/iprt/latin1.h @@ -0,0 +1,404 @@ +/** @file + * IPRT - String Manipulation, Latin-1 (ISO-8859-1) encoding. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_latin1_h +#define IPRT_INCLUDED_latin1_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include /* VERR_END_OF_STRING */ + +RT_C_DECLS_BEGIN + + +/** @defgroup rt_str_latin1 Latin-1 (ISO-8859-1) String Manipulation + * @ingroup grp_rt_str + * + * Deals with Latin-1 encoded strings. + * + * @warning Make sure to name all variables dealing with Latin-1 strings + * suchthat there is no way to mistake them for normal UTF-8 strings. + * There may be severe security issues resulting from mistaking Latin-1 + * for UTF-8! + * + * @{ + */ + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param pszLatin1 The Latin-1 string. + */ +DECLINLINE(RTUNICP) RTLatin1GetCp(const char *pszLatin1) +{ + return *(const unsigned char *)pszLatin1; +} + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppszLatin1 Pointer to the string pointer. This will be updated to + * point to the char following the current code point. This + * is advanced one character forward on failure. + * @param pCp Where to store the code point. RTUNICP_INVALID is stored + * here on failure. + */ +DECLINLINE(int) RTLatin1GetCpEx(const char **ppszLatin1, PRTUNICP pCp) +{ + const unsigned char uch = **(const unsigned char **)ppszLatin1; + (*ppszLatin1)++; + *pCp = uch; + return VINF_SUCCESS; +} + +/** + * Get the unicode code point at the given string position for a string of a + * given maximum length. + * + * @returns iprt status code. + * @retval VERR_END_OF_STRING if *pcch is 0. *pCp is set to RTUNICP_INVALID. + * + * @param ppszLatin1 Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pcchLatin1 Pointer to the maximum string length. This will be + * decremented by the size of the code point found. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + */ +DECLINLINE(int) RTLatin1GetCpNEx(const char **ppszLatin1, size_t *pcchLatin1, PRTUNICP pCp) +{ + if (RT_LIKELY(*pcchLatin1 != 0)) + { + const unsigned char uch = **(const unsigned char **)ppszLatin1; + (*ppszLatin1)++; + (*pcchLatin1)--; + *pCp = uch; + return VINF_SUCCESS; + } + *pCp = RTUNICP_INVALID; + return VERR_END_OF_STRING; +} + +/** + * Get the Latin-1 size in characters of a given Unicode code point. + * + * The code point is expected to be a valid Unicode one, but not necessarily in + * the range supported by Latin-1. + * + * @returns the size in characters, or zero if there is no Latin-1 encoding + */ +DECLINLINE(size_t) RTLatin1CpSize(RTUNICP CodePoint) +{ + if (CodePoint < 0x100) + return 1; + return 0; +} + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by psz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param pszLatin1 The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the Latin-1 range. + */ +DECLINLINE(char *) RTLatin1PutCp(char *pszLatin1, RTUNICP CodePoint) +{ + AssertReturn(CodePoint < 0x100, NULL); + *pszLatin1++ = (unsigned char)CodePoint; + return pszLatin1; +} + +/** + * Skips ahead, past the current code point. + * + * @returns Pointer to the char after the current code point. + * @param pszLatin1 Pointer to the current code point. + * @remark This will not move the next valid code point, only past the current one. + */ +DECLINLINE(char *) RTLatin1NextCp(const char *pszLatin1) +{ + pszLatin1++; + return (char *)pszLatin1; +} + +/** + * Skips back to the previous code point. + * + * @returns Pointer to the char before the current code point. + * @returns pszLatin1Start on failure. + * @param pszLatin1Start Pointer to the start of the string. + * @param pszLatin1 Pointer to the current code point. + */ +DECLINLINE(char *) RTLatin1PrevCp(const char *pszLatin1Start, const char *pszLatin1) +{ + if ((uintptr_t)pszLatin1 > (uintptr_t)pszLatin1Start) + { + pszLatin1--; + return (char *)pszLatin1; + } + return (char *)pszLatin1Start; +} + +/** + * Translate a Latin1 string into a UTF-8 allocating the result buffer (default + * tag). + * + * @returns iprt status code. + * @param pszLatin1 Latin1 string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTLatin1ToUtf8(pszLatin1, ppszString) RTLatin1ToUtf8Tag((pszLatin1), (ppszString), RTSTR_TAG) + +/** + * Translate a Latin-1 string into a UTF-8 allocating the result buffer. + * + * @returns iprt status code. + * @param pszLatin1 Latin-1 string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTLatin1ToUtf8Tag(const char *pszLatin1, char **ppszString, const char *pszTag); + +/** + * Translates Latin-1 to UTF-8 using buffer provided by the caller or a fittingly + * sized buffer allocated by the function (default tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param cchLatin1 The number of Latin-1 characters to translate from + * pszLatin1. The translation will stop when reaching + * cchLatin1 or the terminator ('\\0'). Use RTSTR_MAX + * to translate the entire string. + * @param ppsz If @a cch is non-zero, this must either be pointing + * to a pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppsz is NULL or + * @a cch is zero a buffer of at least @a cch chars + * will be allocated to hold the translated string. If + * a buffer was requested it must be freed using + * RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTLatin1ToUtf8Ex(pszLatin1, cchLatin1, ppsz, cch, pcch) \ + RTLatin1ToUtf8ExTag((pszLatin1), (cchLatin1), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates Latin1 to UTF-8 using buffer provided by the caller or a fittingly + * sized buffer allocated by the function (custom tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin1 string to convert. + * @param cchLatin1 The number of Latin1 characters to translate from + * pwszString. The translation will stop when + * reaching cchLatin1 or the terminator ('\\0'). Use + * RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to + * a pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppsz is NULL or cch + * is zero a buffer of at least cch chars will be + * allocated to hold the translated string. If a + * buffer was requested it must be freed using + * RTStrFree(). + * @param cch The buffer size in chars (the type). This includes + * the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTLatin1ToUtf8ExTag(const char *pszLatin1, size_t cchLatin1, char **ppsz, size_t cch, size_t *pcch, + const char *pszTag); + +/** + * Calculates the length of the Latin-1 string in UTF-8 chars (bytes). + * + * The primary purpose of this function is to help allocate buffers for + * RTLatin1ToUtf8() of the correct size. For most other purposes + * RTLatin1ToUtf8Ex() should be used. + * + * @returns Number of chars (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pszLatin1 The Latin-1 string. + */ +RTDECL(size_t) RTLatin1CalcUtf8Len(const char *pszLatin1); + +/** + * Calculates the length of the Latin-1 string in UTF-8 chars (bytes). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string. + * @param cchLatin1 The max string length. Use RTSTR_MAX to process the + * entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTLatin1CalcUtf8LenEx(const char *pszLatin1, size_t cchLatin1, size_t *pcch); + +/** + * Calculates the length of the Latin-1 (ISO-8859-1) string in RTUTF16 items. + * + * @returns Number of RTUTF16 items. + * @param pszLatin1 The Latin-1 string. + */ +RTDECL(size_t) RTLatin1CalcUtf16Len(const char *pszLatin1); + +/** + * Calculates the length of the Latin-1 (ISO-8859-1) string in RTUTF16 items. + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string. + * @param cchLatin1 The max string length. Use RTSTR_MAX to process the + * entire string. + * @param pcwc Where to store the string length. Optional. + * This is undefined on failure. + */ +RTDECL(int) RTLatin1CalcUtf16LenEx(const char *pszLatin1, size_t cchLatin1, size_t *pcwc); + +/** + * Translate a Latin-1 (ISO-8859-1) string into a UTF-16 allocating the result + * buffer (default tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16 string. The + * returned string must be freed using RTUtf16Free(). + */ +#define RTLatin1ToUtf16(pszLatin1, ppwszString) RTLatin1ToUtf16Tag((pszLatin1), (ppwszString), RTSTR_TAG) + +/** + * Translate a Latin-1 (ISO-8859-1) string into a UTF-16 allocating the result + * buffer (custom tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16 string. The + * returned string must be freed using RTUtf16Free(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTLatin1ToUtf16Tag(const char *pszLatin1, PRTUTF16 *ppwszString, const char *pszTag); + +/** + * Translates pszLatin1 from Latin-1 (ISO-8859-1) to UTF-16, allocating the + * result buffer if requested (default tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param cchLatin1 The maximum size in chars (the type) to convert. The + * conversion stops when it reaches cchLatin1 or the + * string terminator ('\\0'). Use RTSTR_MAX to + * translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing + * to pointer to a buffer of the specified size, or + * pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at + * least cwc items will be allocated to hold the + * translated string. If a buffer was requested it + * must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the + * terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTLatin1ToUtf16Ex(pszLatin1, cchLatin1, ppwsz, cwc, pcwc) \ + RTLatin1ToUtf16ExTag((pszLatin1), (cchLatin1), (ppwsz), (cwc), (pcwc), RTSTR_TAG) + +/** + * Translates pszLatin1 from Latin-1 (ISO-8859-1) to UTF-16, allocating the + * result buffer if requested. + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param cchLatin1 The maximum size in chars (the type) to convert. The + * conversion stops when it reaches cchLatin1 or the + * string terminator ('\\0'). Use RTSTR_MAX to + * translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing + * to pointer to a buffer of the specified size, or + * pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at + * least cwc items will be allocated to hold the + * translated string. If a buffer was requested it + * must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the + * terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTLatin1ToUtf16ExTag(const char *pszLatin1, size_t cchLatin1, + PRTUTF16 *ppwsz, size_t cwc, size_t *pcwc, const char *pszTag); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_latin1_h */ + diff --git a/include/iprt/ldr.h b/include/iprt/ldr.h new file mode 100644 index 00000000..aa67646e --- /dev/null +++ b/include/iprt/ldr.h @@ -0,0 +1,1340 @@ +/** @file + * IPRT - Loader. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ldr_h +#define IPRT_INCLUDED_ldr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_ldr RTLdr - Loader + * @ingroup grp_rt + * @{ + */ + + +RT_C_DECLS_BEGIN + +/** Loader address (unsigned integer). */ +typedef RTUINTPTR RTLDRADDR; +/** Pointer to a loader address. */ +typedef RTLDRADDR *PRTLDRADDR; +/** Pointer to a const loader address. */ +typedef RTLDRADDR const *PCRTLDRADDR; +/** The max loader address value. */ +#define RTLDRADDR_MAX RTUINTPTR_MAX +/** NIL loader address value. */ +#define NIL_RTLDRADDR RTLDRADDR_MAX + + +/** + * Loader module format. + */ +typedef enum RTLDRFMT +{ + /** The usual invalid 0 format. */ + RTLDRFMT_INVALID = 0, + /** The native OS loader. */ + RTLDRFMT_NATIVE, + /** The AOUT loader. */ + RTLDRFMT_AOUT, + /** The ELF loader. */ + RTLDRFMT_ELF, + /** The LX loader. */ + RTLDRFMT_LX, + /** The Mach-O loader. */ + RTLDRFMT_MACHO, + /** The PE loader. */ + RTLDRFMT_PE, + /** The end of the valid format values (exclusive). */ + RTLDRFMT_END, + /** Hack to blow the type up to 32-bit. */ + RTLDRFMT_32BIT_HACK = 0x7fffffff +} RTLDRFMT; + + +/** + * Loader module type. + */ +typedef enum RTLDRTYPE +{ + /** The usual invalid 0 type. */ + RTLDRTYPE_INVALID = 0, + /** Object file. */ + RTLDRTYPE_OBJECT, + /** Executable module, fixed load address. */ + RTLDRTYPE_EXECUTABLE_FIXED, + /** Executable module, relocatable, non-fixed load address. */ + RTLDRTYPE_EXECUTABLE_RELOCATABLE, + /** Executable module, position independent code, non-fixed load address. */ + RTLDRTYPE_EXECUTABLE_PIC, + /** Shared library, fixed load address. + * Typically a system library. */ + RTLDRTYPE_SHARED_LIBRARY_FIXED, + /** Shared library, relocatable, non-fixed load address. */ + RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE, + /** Shared library, position independent code, non-fixed load address. */ + RTLDRTYPE_SHARED_LIBRARY_PIC, + /** DLL that contains no code or data only imports and exports. (Chiefly OS/2.) */ + RTLDRTYPE_FORWARDER_DLL, + /** Core or dump. */ + RTLDRTYPE_CORE, + /** Debug module (debug info with empty code & data segments). */ + RTLDRTYPE_DEBUG_INFO, + /** The end of the valid types values (exclusive). */ + RTLDRTYPE_END, + /** Hack to blow the type up to 32-bit. */ + RTLDRTYPE_32BIT_HACK = 0x7fffffff +} RTLDRTYPE; + + +/** + * Loader endian indicator. + */ +typedef enum RTLDRENDIAN +{ + /** The usual invalid endian. */ + RTLDRENDIAN_INVALID, + /** Little endian. */ + RTLDRENDIAN_LITTLE, + /** Bit endian. */ + RTLDRENDIAN_BIG, + /** Endianness doesn't have a meaning in the context. */ + RTLDRENDIAN_NA, + /** The end of the valid endian values (exclusive). */ + RTLDRENDIAN_END, + /** Hack to blow the type up to 32-bit. */ + RTLDRENDIAN_32BIT_HACK = 0x7fffffff +} RTLDRENDIAN; + + +/** Pointer to a loader reader instance. */ +typedef struct RTLDRREADER *PRTLDRREADER; +/** + * Loader image reader instance. + * + * @remarks The reader will typically have a larger structure wrapping this one + * for storing necessary instance variables. + * + * The loader ASSUMES the caller serializes all access to the + * individual loader module handlers, thus no serialization is required + * when implementing this interface. + */ +typedef struct RTLDRREADER +{ + /** Magic value (RTLDRREADER_MAGIC). */ + uintptr_t uMagic; + + /** + * Reads bytes at a give place in the raw image. + * + * @returns iprt status code. + * @param pReader Pointer to the reader instance. + * @param pvBuf Where to store the bits. + * @param cb Number of bytes to read. + * @param off Where to start reading relative to the start of the raw image. + */ + DECLCALLBACKMEMBER(int, pfnRead,(PRTLDRREADER pReader, void *pvBuf, size_t cb, RTFOFF off)); + + /** + * Tells end position of last read. + * + * @returns position relative to start of the raw image. + * @param pReader Pointer to the reader instance. + */ + DECLCALLBACKMEMBER(RTFOFF, pfnTell,(PRTLDRREADER pReader)); + + /** + * Gets the size of the raw image bits. + * + * @returns size of raw image bits in bytes. + * @param pReader Pointer to the reader instance. + */ + DECLCALLBACKMEMBER(uint64_t, pfnSize,(PRTLDRREADER pReader)); + + /** + * Map the bits into memory. + * + * The mapping will be freed upon calling pfnDestroy() if not pfnUnmap() + * is called before that. The mapping is read only. + * + * @returns iprt status code. + * @param pReader Pointer to the reader instance. + * @param ppvBits Where to store the address of the memory mapping on success. + * The size of the mapping can be obtained by calling pfnSize(). + */ + DECLCALLBACKMEMBER(int, pfnMap,(PRTLDRREADER pReader, const void **ppvBits)); + + /** + * Unmap bits. + * + * @returns iprt status code. + * @param pReader Pointer to the reader instance. + * @param pvBits Memory pointer returned by pfnMap(). + */ + DECLCALLBACKMEMBER(int, pfnUnmap,(PRTLDRREADER pReader, const void *pvBits)); + + /** + * Gets the most appropriate log name. + * + * @returns Pointer to readonly log name. + * @param pReader Pointer to the reader instance. + */ + DECLCALLBACKMEMBER(const char *, pfnLogName,(PRTLDRREADER pReader)); + + /** + * Releases all resources associated with the reader instance. + * The instance is invalid after this call returns. + * + * @returns iprt status code. + * @param pReader Pointer to the reader instance. + */ + DECLCALLBACKMEMBER(int, pfnDestroy,(PRTLDRREADER pReader)); +} RTLDRREADER; + +/** Magic value for RTLDRREADER (Gordon Matthew Thomas Sumner / Sting). */ +#define RTLDRREADER_MAGIC UINT32_C(0x19511002) + + +/** + * Gets the default file suffix for DLL/SO/DYLIB/whatever. + * + * @returns The stuff (readonly). + */ +RTDECL(const char *) RTLdrGetSuff(void); + +/** + * Checks if a library is loadable or not. + * + * This may attempt load and unload the library. + * + * @returns true/false accordingly. + * @param pszFilename Image filename. + */ +RTDECL(bool) RTLdrIsLoadable(const char *pszFilename); + +/** + * Loads a dynamic load library (/shared object) image file using native + * OS facilities. + * + * The filename will be appended the default DLL/SO extension of + * the platform if it have been omitted. This means that it's not + * possible to load DLLs/SOs with no extension using this interface, + * but that's not a bad tradeoff. + * + * If no path is specified in the filename, the OS will usually search it's library + * path to find the image file. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param phLdrMod Where to store the handle to the loader module. + */ +RTDECL(int) RTLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod); + +/** + * Loads a dynamic load library (/shared object) image file using native + * OS facilities. + * + * The filename will be appended the default DLL/SO extension of + * the platform if it have been omitted. This means that it's not + * possible to load DLLs/SOs with no extension using this interface, + * but that's not a bad tradeoff. + * + * If no path is specified in the filename, the OS will usually search it's library + * path to find the image file. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param phLdrMod Where to store the handle to the loader module. + * @param fFlags See RTLDRLOAD_FLAGS_XXX. + * @param pErrInfo Where to return extended error information. Optional. + */ +RTDECL(int) RTLdrLoadEx(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** @defgroup RTLDRLOAD_FLAGS_XXX Flags for RTLdrLoadEx, RTLdrLoadSystemEx and RTLdrGetSystemSymbolEx + * @{ */ +/** Symbols defined in this library are not made available to resolve + * references in subsequently loaded libraries (default). */ +#define RTLDRLOAD_FLAGS_LOCAL UINT32_C(0) +/** Symbols defined in this library will be made available for symbol + * resolution of subsequently loaded libraries. */ +#define RTLDRLOAD_FLAGS_GLOBAL RT_BIT_32(0) +/** Do not unload the library upon RTLdrClose. (For system libs.) */ +#define RTLDRLOAD_FLAGS_NO_UNLOAD RT_BIT_32(1) +/** Windows/NT: Search the DLL load directory for imported DLLs - W7, + * Vista, and W2K8 requires KB2533623 to be installed to support this; not + * supported on XP, W2K3 or earlier. Ignored on other platforms. */ +#define RTLDRLOAD_FLAGS_NT_SEARCH_DLL_LOAD_DIR RT_BIT_32(2) +/** Do not append default suffix. */ +#define RTLDRLOAD_FLAGS_NO_SUFFIX RT_BIT_32(3) +/** Shift for the first .so.MAJOR version number to try. + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). */ +#define RTLDRLOAD_FLAGS_SO_VER_BEGIN_SHIFT 12 +/** Mask for the first .so.MAJOR version number to try. + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). */ +#define RTLDRLOAD_FLAGS_SO_VER_BEGIN_MASK UINT32_C(0x003ff000) +/** Shift for the end .so.MAJOR version number (exclusive). + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). */ +#define RTLDRLOAD_FLAGS_SO_VER_END_SHIFT 22 +/** Mask for the end .so.MAJOR version number (exclusive). + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). */ +#define RTLDRLOAD_FLAGS_SO_VER_END_MASK UINT32_C(0xffc00000) +/** Specifies the range for the .so.MAJOR version number. + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). + * Ignored on systems not using .so. + * @param a_uBegin The first version to try. + * @param a_uEnd The version number to stop at (exclusive). + */ +#define RTLDRLOAD_FLAGS_SO_VER_RANGE(a_uBegin, a_uEnd) \ + ( ((a_uBegin) << RTLDRLOAD_FLAGS_SO_VER_BEGIN_SHIFT) | ((a_uEnd) << RTLDRLOAD_FLAGS_SO_VER_END_SHIFT) ) +/** The mask of valid flag bits. + * The shared object major version range is excluded. */ +#define RTLDRLOAD_FLAGS_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Loads a dynamic load library (/shared object) image file residing in one of + * the default system library locations. + * + * Only the system library locations are searched. No suffix is required. + * + * @returns iprt status code. + * @param pszFilename Image filename. No path. + * @param fNoUnload Do not unload the library when RTLdrClose is called. + * @param phLdrMod Where to store the handle to the loaded module. + */ +RTDECL(int) RTLdrLoadSystem(const char *pszFilename, bool fNoUnload, PRTLDRMOD phLdrMod); + +/** + * Loads a dynamic load library (/shared object) image file residing in one of + * the default system library locations, extended version. + * + * Only the system library locations are searched. No suffix is required. + * + * @returns iprt status code. + * @param pszFilename Image filename. No path. + * @param fFlags RTLDRLOAD_FLAGS_XXX, including RTLDRLOAD_FLAGS_SO_VER_XXX. + * @param phLdrMod Where to store the handle to the loaded module. + */ +RTDECL(int) RTLdrLoadSystemEx(const char *pszFilename, uint32_t fFlags, PRTLDRMOD phLdrMod); + +/** + * Combines RTLdrLoadSystem and RTLdrGetSymbol, with fNoUnload set to true. + * + * @returns The symbol value, NULL on failure. (If you care for a less boolean + * status, go thru the necessary API calls yourself.) + * @param pszFilename Image filename. No path. + * @param pszSymbol Symbol name. + */ +RTDECL(void *) RTLdrGetSystemSymbol(const char *pszFilename, const char *pszSymbol); + +/** + * Combines RTLdrLoadSystemEx and RTLdrGetSymbol. + * + * @returns The symbol value, NULL on failure. (If you care for a less boolean + * status, go thru the necessary API calls yourself.) + * @param pszFilename Image filename. No path. + * @param pszSymbol Symbol name. + * @param fFlags RTLDRLOAD_FLAGS_XXX, including RTLDRLOAD_FLAGS_SO_VER_XXX. + */ +RTDECL(void *) RTLdrGetSystemSymbolEx(const char *pszFilename, const char *pszSymbol, uint32_t fFlags); + +/** + * Loads a dynamic load library (/shared object) image file residing in the + * RTPathAppPrivateArch() directory. + * + * Suffix is not required. + * + * @returns iprt status code. + * @param pszFilename Image filename. No path. + * @param phLdrMod Where to store the handle to the loaded module. + */ +RTDECL(int) RTLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod); + +/** + * Gets the native module handle for a module loaded by RTLdrLoad, RTLdrLoadEx, + * RTLdrLoadSystem, or RTLdrLoadAppPriv. + * + * @returns Native handle on success, ~(uintptr_t)0 on failure. + * @param hLdrMod The loader module handle. + */ +RTDECL(uintptr_t) RTLdrGetNativeHandle(RTLDRMOD hLdrMod); + + +/** + * Image architecuture specifier for RTLdrOpenEx. + */ +typedef enum RTLDRARCH +{ + RTLDRARCH_INVALID = 0, + /** Whatever. */ + RTLDRARCH_WHATEVER, + /** The host architecture. */ + RTLDRARCH_HOST, + /** 16-bit x86. */ + RTLDRARCH_X86_16, + /** 32-bit x86. */ + RTLDRARCH_X86_32, + /** AMD64 (64-bit x86 if you like). */ + RTLDRARCH_AMD64, + /** 32-bit ARM. */ + RTLDRARCH_ARM32, + /** 64-bit ARM. */ + RTLDRARCH_ARM64, + /** End of the valid values. */ + RTLDRARCH_END, + /** Make sure the type is a full 32-bit. */ + RTLDRARCH_32BIT_HACK = 0x7fffffff +} RTLDRARCH; +/** Pointer to a RTLDRARCH. */ +typedef RTLDRARCH *PRTLDRARCH; + +/** + * Translates a RTLDRARCH value to a string. + * + * @returns Name corresponding to @a enmArch + * @param enmArch The value to name. + */ +RTDECL(const char *) RTLdrArchName(RTLDRARCH enmArch); + +/** + * Returns the host architecture. + * + * @returns Host architecture or RTLDRARCH_WHATEVER if no match. + */ +RTDECL(RTLDRARCH) RTLdrGetHostArch(void); + + +/** @name RTLDR_O_XXX - RTLdrOpen flags. + * @{ */ +/** Open for debugging or introspection reasons. + * This will skip a few of the stricter validations when loading images. */ +#define RTLDR_O_FOR_DEBUG RT_BIT_32(0) +/** Open for signature validation. */ +#define RTLDR_O_FOR_VALIDATION RT_BIT_32(1) +/** The arch specification is just a guideline for FAT binaries. */ +#define RTLDR_O_WHATEVER_ARCH RT_BIT_32(2) +/** Ignore the architecture specification if there is no code. */ +#define RTLDR_O_IGNORE_ARCH_IF_NO_CODE RT_BIT_32(3) +/** Mach-O: Include the __LINKEDIT segment (ignored by the others). */ +#define RTLDR_O_MACHO_LOAD_LINKEDIT RT_BIT_32(4) +/** Mask of valid flags. */ +#define RTLDR_O_VALID_MASK UINT32_C(0x0000001f) +/** @} */ + +/** + * Open a binary image file. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch CPU architecture specifier for the image to be loaded. + * @param phLdrMod Where to store the handle to the loader module. + */ +RTDECL(int) RTLdrOpen(const char *pszFilename, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod); + +/** + * Open a binary image file, extended version. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch CPU architecture specifier for the image to be loaded. + * @param phLdrMod Where to store the handle to the loader module. + * @param pErrInfo Where to return extended error information. Optional. + */ +RTDECL(int) RTLdrOpenEx(const char *pszFilename, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo); + +/** + * Open a binary image file allowing VFS chains in the filename. + * + * @returns iprt status code. + * @param pszFilename Image filename, VFS chain specifiers allowed. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch CPU architecture specifier for the image to be loaded. + * @param phLdrMod Where to store the handle to the loader module. + * @param poffError Where to return the offset into @a pszFilename of an VFS + * chain element causing trouble. Optional. + * @param pErrInfo Where to return extended error information. Optional. + */ +RTDECL(int) RTLdrOpenVfsChain(const char *pszFilename, uint32_t fFlags, RTLDRARCH enmArch, + PRTLDRMOD phLdrMod, uint32_t *poffError, PRTERRINFO pErrInfo); + +/** + * Open part with reader. + * + * @returns iprt status code. + * @param pReader The loader reader instance which will provide the raw + * image bits. The reader instance will be consumed on + * success. On failure, the caller has to do the cleaning + * up. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch Architecture specifier. + * @param phMod Where to store the handle. + * @param pErrInfo Where to return extended error information. Optional. + */ +RTDECL(int) RTLdrOpenWithReader(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phMod, PRTERRINFO pErrInfo); + +/** + * Called to read @a cb bytes at @a off into @a pvBuf. + * + * @returns IPRT status code + * @param pvBuf The output buffer. + * @param cb The number of bytes to read. + * @param off Where to start reading. + * @param pvUser The user parameter. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRRDRMEMREAD,(void *pvBuf, size_t cb, size_t off, void *pvUser)); +/** Pointer to a RTLdrOpenInMemory reader callback. */ +typedef FNRTLDRRDRMEMREAD *PFNRTLDRRDRMEMREAD; + +/** + * Called to when the module is unloaded (or done loading) to release resources + * associated with it (@a pvUser). + * + * @returns IPRT status code + * @param pvUser The user parameter. + * @param cbImage The image size. + */ +typedef DECLCALLBACKTYPE(void, FNRTLDRRDRMEMDTOR,(void *pvUser, size_t cbImage)); +/** Pointer to a RTLdrOpenInMemory destructor callback. */ +typedef FNRTLDRRDRMEMDTOR *PFNRTLDRRDRMEMDTOR; + +/** + * Open a in-memory image or an image with a custom reader callback. + * + * @returns IPRT status code. + * @param pszName The image name. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch CPU architecture specifier for the image to be loaded. + * @param cbImage The size of the image (fake file). + * @param pfnRead The read function. If NULL is passed in, a default + * reader function is provided that assumes @a pvUser + * points to the raw image bits, at least @a cbImage of + * valid memory. + * @param pfnDtor The destructor function. If NULL is passed, a default + * destructor will be provided that passes @a pvUser to + * RTMemFree. + * @param pvUser The user argument or, if any of the callbacks are NULL, + * a pointer to a memory block. + * @param phLdrMod Where to return the module handle. + * @param pErrInfo Pointer to an error info buffer, optional. + * + * @remarks With the exception of invalid @a pfnDtor and/or @a pvUser + * parameters, the pfnDtor methods (or the default one if NULL) will + * always be invoked. The destruction of pvUser is entirely in the + * hands of this method once it's called. + */ +RTDECL(int) RTLdrOpenInMemory(const char *pszName, uint32_t fFlags, RTLDRARCH enmArch, size_t cbImage, + PFNRTLDRRDRMEMREAD pfnRead, PFNRTLDRRDRMEMDTOR pfnDtor, void *pvUser, + PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo); + +/** + * Closes a loader module handle. + * + * The handle can be obtained using any of the RTLdrLoad(), RTLdrOpen() + * and RTLdrOpenInMemory() functions. + * + * @returns iprt status code. + * @param hLdrMod The loader module handle. + */ +RTDECL(int) RTLdrClose(RTLDRMOD hLdrMod); + +/** + * Gets the address of a named exported symbol. + * + * @returns iprt status code. + * @retval VERR_LDR_FORWARDER forwarder, use pfnQueryForwarderInfo. Buffer size + * hint in @a ppvValue. + * @param hLdrMod The loader module handle. + * @param pszSymbol Symbol name. + * @param ppvValue Where to store the symbol value. Note that this is restricted to the + * pointer size used on the host! + */ +RTDECL(int) RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue); + +/** + * Gets the address of a named exported symbol. + * + * This function differs from the plain one in that it can deal with + * both GC and HC address sizes, and that it can calculate the symbol + * value relative to any given base address. + * + * @returns iprt status code. + * @retval VERR_LDR_FORWARDER forwarder, use pfnQueryForwarderInfo. Buffer size + * hint in @a pValue. + * @param hLdrMod The loader module handle. + * @param pvBits Optional pointer to the loaded image. + * Set this to NULL if no RTLdrGetBits() processed image bits are available. + * Not supported for RTLdrLoad() images. + * @param BaseAddress Image load address. + * Not supported for RTLdrLoad() images. + * @param iOrdinal Symbol ordinal number, pass UINT32_MAX if pszSymbol + * should be used instead. + * @param pszSymbol Symbol name. + * @param pValue Where to store the symbol value. + */ +RTDECL(int) RTLdrGetSymbolEx(RTLDRMOD hLdrMod, const void *pvBits, RTLDRADDR BaseAddress, + uint32_t iOrdinal, const char *pszSymbol, PRTLDRADDR pValue); + +/** + * Gets the address of a named exported function. + * + * Same as RTLdrGetSymbol, but skips the status code and pointer to return + * variable stuff. + * + * @returns Pointer to the function if found, NULL if not. + * @param hLdrMod The loader module handle. + * @param pszSymbol Function name. + */ +RTDECL(PFNRT) RTLdrGetFunction(RTLDRMOD hLdrMod, const char *pszSymbol); + +/** + * Information about an imported symbol. + */ +typedef struct RTLDRIMPORTINFO +{ + /** Symbol table entry number, UINT32_MAX if not available. */ + uint32_t iSelfOrdinal; + /** The ordinal of the imported symbol in szModule, UINT32_MAX if not used. */ + uint32_t iOrdinal; + /** The symbol name, NULL if not used. This points to the char immediately + * following szModule when returned by RTLdrQueryForwarderInfo. */ + const char *pszSymbol; + /** The name of the module being imported from. */ + char szModule[1]; +} RTLDRIMPORTINFO; +/** Pointer to information about an imported symbol. */ +typedef RTLDRIMPORTINFO *PRTLDRIMPORTINFO; +/** Pointer to const information about an imported symbol. */ +typedef RTLDRIMPORTINFO const *PCRTLDRIMPORTINFO; + +/** + * Query information about a forwarded symbol. + * + * @returns IPRT status code. + * @param hLdrMod The loader module handle. + * @param pvBits Optional pointer to the loaded image. + * Set this to NULL if no RTLdrGetBits() processed image bits are available. + * Not supported for RTLdrLoad() images. + * @param iOrdinal Symbol ordinal number, pass UINT32_MAX if pszSymbol + * should be used instead. + * @param pszSymbol Symbol name. + * @param pInfo Where to return the forwarder info. + * @param cbInfo Size of the buffer @a pInfo points to. For a size + * hint, see @a pValue when RTLdrGetSymbolEx returns + * VERR_LDR_FORWARDER. + */ +RTDECL(int) RTLdrQueryForwarderInfo(RTLDRMOD hLdrMod, const void *pvBits, uint32_t iOrdinal, const char *pszSymbol, + PRTLDRIMPORTINFO pInfo, size_t cbInfo); + + +/** + * Gets the size of the loaded image. + * + * This is not necessarily available for images that has been loaded using + * RTLdrLoad(). + * + * @returns image size (in bytes). + * @returns ~(size_t)0 on if not available. + * @param hLdrMod Handle to the loader module. + */ +RTDECL(size_t) RTLdrSize(RTLDRMOD hLdrMod); + +/** + * Resolve an external symbol during RTLdrGetBits(). + * + * @returns iprt status code. + * @param hLdrMod The loader module handle. + * @param pszModule Module name. + * @param pszSymbol Symbol name, NULL if uSymbol should be used. + * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used. + * @param pValue Where to store the symbol value (address). + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRIMPORT,(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, + PRTLDRADDR pValue, void *pvUser)); +/** Pointer to a FNRTLDRIMPORT() callback function. */ +typedef FNRTLDRIMPORT *PFNRTLDRIMPORT; + +/** + * Loads the image into a buffer provided by the user and applies fixups + * for the given base address. + * + * @returns iprt status code. + * @param hLdrMod The load module handle. + * @param pvBits Where to put the bits. + * Must be as large as RTLdrSize() suggests. + * @param BaseAddress The base address. + * @param pfnGetImport Callback function for resolving imports one by one. + * @param pvUser User argument for the callback. + * @remark Not supported for RTLdrLoad() images. + */ +RTDECL(int) RTLdrGetBits(RTLDRMOD hLdrMod, void *pvBits, RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser); + +/** + * Relocates bits after getting them. + * Useful for code which moves around a bit. + * + * @returns iprt status code. + * @param hLdrMod The loader module handle. + * @param pvBits Where the image bits are. + * Must have been passed to RTLdrGetBits(). + * @param NewBaseAddress The new base address. + * @param OldBaseAddress The old base address. + * @param pfnGetImport Callback function for resolving imports one by one. + * @param pvUser User argument for the callback. + * @remark Not supported for RTLdrLoad() images. + */ +RTDECL(int) RTLdrRelocate(RTLDRMOD hLdrMod, void *pvBits, RTLDRADDR NewBaseAddress, RTLDRADDR OldBaseAddress, + PFNRTLDRIMPORT pfnGetImport, void *pvUser); + +/** + * Enumeration callback function used by RTLdrEnumSymbols(). + * + * @returns iprt status code. Failure will stop the enumeration. + * @param hLdrMod The loader module handle. + * @param pszSymbol Symbol name. NULL if ordinal only. + * @param uSymbol Symbol ordinal, ~0 if not used. + * @param Value Symbol value. + * @param pvUser The user argument specified to RTLdrEnumSymbols(). + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRENUMSYMS,(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTLDRADDR Value, void *pvUser)); +/** Pointer to a FNRTLDRENUMSYMS() callback function. */ +typedef FNRTLDRENUMSYMS *PFNRTLDRENUMSYMS; + +/** + * Enumerates all symbols in a module. + * + * @returns iprt status code. + * @param hLdrMod The loader module handle. + * @param fFlags Flags indicating what to return and such. + * @param pvBits Optional pointer to the loaded image. (RTLDR_ENUM_SYMBOL_FLAGS_*) + * Set this to NULL if no RTLdrGetBits() processed image bits are available. + * @param BaseAddress Image load address. + * @param pfnCallback Callback function. + * @param pvUser User argument for the callback. + * @remark Not supported for RTLdrLoad() images. + */ +RTDECL(int) RTLdrEnumSymbols(RTLDRMOD hLdrMod, unsigned fFlags, const void *pvBits, RTLDRADDR BaseAddress, PFNRTLDRENUMSYMS pfnCallback, void *pvUser); + +/** @name RTLdrEnumSymbols flags. + * @{ */ +/** Returns ALL kinds of symbols. The default is to only return public/exported symbols. */ +#define RTLDR_ENUM_SYMBOL_FLAGS_ALL RT_BIT(1) +/** Ignore forwarders rather than reporting them with RTLDR_ENUM_SYMBOL_FWD_ADDRESS as value. */ +#define RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD RT_BIT(2) +/** @} */ + +/** Special symbol for forwarder symbols, since they cannot be resolved with + * the current API. */ +#if (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +# define RTLDR_ENUM_SYMBOL_FWD_ADDRESS UINT64_C(0xff4242fffd4242fd) +#else +# define RTLDR_ENUM_SYMBOL_FWD_ADDRESS UINT32_C(0xff4242fd) +#endif + + +/** + * Debug info type (as far the loader can tell). + */ +typedef enum RTLDRDBGINFOTYPE +{ + /** The invalid 0 value. */ + RTLDRDBGINFOTYPE_INVALID = 0, + /** Unknown debug info format. */ + RTLDRDBGINFOTYPE_UNKNOWN, + /** Stabs. */ + RTLDRDBGINFOTYPE_STABS, + /** Debug With Arbitrary Record Format (DWARF). */ + RTLDRDBGINFOTYPE_DWARF, + /** Debug With Arbitrary Record Format (DWARF), in external file (DWO). */ + RTLDRDBGINFOTYPE_DWARF_DWO, + /** Microsoft Codeview debug info. */ + RTLDRDBGINFOTYPE_CODEVIEW, + /** Microsoft Codeview debug info, in external v2.0+ program database (PDB). */ + RTLDRDBGINFOTYPE_CODEVIEW_PDB20, + /** Microsoft Codeview debug info, in external v7.0+ program database (PDB). */ + RTLDRDBGINFOTYPE_CODEVIEW_PDB70, + /** Microsoft Codeview debug info, in external file (DBG). */ + RTLDRDBGINFOTYPE_CODEVIEW_DBG, + /** Microsoft COFF debug info. */ + RTLDRDBGINFOTYPE_COFF, + /** Watcom debug info. */ + RTLDRDBGINFOTYPE_WATCOM, + /** IBM High Level Language debug info. */ + RTLDRDBGINFOTYPE_HLL, + /** The end of the valid debug info values (exclusive). */ + RTLDRDBGINFOTYPE_END, + /** Blow the type up to 32-bits. */ + RTLDRDBGINFOTYPE_32BIT_HACK = 0x7fffffff +} RTLDRDBGINFOTYPE; + + +/** + * Debug info details for the enumeration callback. + */ +typedef struct RTLDRDBGINFO +{ + /** The kind of debug info. */ + RTLDRDBGINFOTYPE enmType; + /** The debug info ordinal number / id. */ + uint32_t iDbgInfo; + /** The file offset *if* this type has one specific location in the executable + * image file. This is -1 if there isn't any specific file location. */ + RTFOFF offFile; + /** The link address of the debug info if it's loadable. NIL_RTLDRADDR if not + * loadable*/ + RTLDRADDR LinkAddress; + /** The size of the debug information. -1 is used if this isn't applicable.*/ + RTLDRADDR cb; + /** This is set if the debug information is found in an external file. NULL + * if no external file involved. + * @note Putting it outside the union to allow lazy callback implementation. */ + const char *pszExtFile; + /** Type (enmType) specific information. */ + union + { + /** RTLDRDBGINFOTYPE_DWARF */ + struct + { + /** The section name. */ + const char *pszSection; + } Dwarf; + + /** RTLDRDBGINFOTYPE_DWARF_DWO */ + struct + { + /** The CRC32 of the external file. */ + uint32_t uCrc32; + } Dwo; + + /** RTLDRDBGINFOTYPE_CODEVIEW, RTLDRDBGINFOTYPE_COFF */ + struct + { + /** The PE image size. */ + uint32_t cbImage; + /** The timestamp. */ + uint32_t uTimestamp; + /** The major version from the entry. */ + uint32_t uMajorVer; + /** The minor version from the entry. */ + uint32_t uMinorVer; + } Cv, Coff; + + /** RTLDRDBGINFOTYPE_CODEVIEW_DBG */ + struct + { + /** The PE image size. */ + uint32_t cbImage; + /** The timestamp. */ + uint32_t uTimestamp; + } Dbg; + + /** RTLDRDBGINFOTYPE_CODEVIEW_PDB20*/ + struct + { + /** The PE image size. */ + uint32_t cbImage; + /** The timestamp. */ + uint32_t uTimestamp; + /** The PDB age. */ + uint32_t uAge; + } Pdb20; + + /** RTLDRDBGINFOTYPE_CODEVIEW_PDB70 */ + struct + { + /** The PE image size. */ + uint32_t cbImage; + /** The PDB age. */ + uint32_t uAge; + /** The UUID. */ + RTUUID Uuid; + } Pdb70; + } u; +} RTLDRDBGINFO; +/** Pointer to debug info details. */ +typedef RTLDRDBGINFO *PRTLDRDBGINFO; +/** Pointer to read only debug info details. */ +typedef RTLDRDBGINFO const *PCRTLDRDBGINFO; + + +/** + * Debug info enumerator callback. + * + * @returns VINF_SUCCESS to continue the enumeration. Any other status code + * will cause RTLdrEnumDbgInfo to immediately return with that status. + * + * @param hLdrMod The module handle. + * @param pDbgInfo Pointer to a read only structure with the details. + * @param pvUser The user parameter specified to RTLdrEnumDbgInfo. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRENUMDBG,(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)); +/** Pointer to a debug info enumerator callback. */ +typedef FNRTLDRENUMDBG *PFNRTLDRENUMDBG; + +/** + * Enumerate the debug info contained in the executable image. + * + * @returns IPRT status code or whatever pfnCallback returns. + * + * @param hLdrMod The module handle. + * @param pvBits Optional pointer to bits returned by + * RTLdrGetBits(). This can be used by some module + * interpreters to reduce memory consumption. + * @param pfnCallback The callback function. + * @param pvUser The user argument. + */ +RTDECL(int) RTLdrEnumDbgInfo(RTLDRMOD hLdrMod, const void *pvBits, PFNRTLDRENUMDBG pfnCallback, void *pvUser); + + +/** + * Loader segment. + */ +typedef struct RTLDRSEG +{ + /** The segment name. Always set to something. */ + const char *pszName; + /** The length of the segment name. */ + uint32_t cchName; + /** The flat selector to use for the segment (i.e. data/code). + * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ + uint16_t SelFlat; + /** The 16-bit selector to use for the segment. + * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ + uint16_t Sel16bit; + /** Segment flags. */ + uint32_t fFlags; + /** The segment protection (RTMEM_PROT_XXX). */ + uint32_t fProt; + /** The size of the segment. */ + RTLDRADDR cb; + /** The required segment alignment. + * The to 0 if the segment isn't supposed to be mapped. */ + RTLDRADDR Alignment; + /** The link address. + * Set to NIL_RTLDRADDR if the segment isn't supposed to be mapped or if + * the image doesn't have link addresses. */ + RTLDRADDR LinkAddress; + /** File offset of the segment. + * Set to -1 if no file backing (like BSS). */ + RTFOFF offFile; + /** Size of the file bits of the segment. + * Set to -1 if no file backing (like BSS). */ + RTFOFF cbFile; + /** The relative virtual address when mapped. + * Set to NIL_RTLDRADDR if the segment isn't supposed to be mapped. */ + RTLDRADDR RVA; + /** The size of the segment including the alignment gap up to the next segment when mapped. + * This is set to NIL_RTLDRADDR if not implemented. */ + RTLDRADDR cbMapped; +} RTLDRSEG; +/** Pointer to a loader segment. */ +typedef RTLDRSEG *PRTLDRSEG; +/** Pointer to a read only loader segment. */ +typedef RTLDRSEG const *PCRTLDRSEG; + + +/** @name Segment flags + * @{ */ +/** The segment is 16-bit. When not set the default of the target architecture is assumed. */ +#define RTLDRSEG_FLAG_16BIT UINT32_C(1) +/** The segment requires a 16-bit selector alias. (OS/2) */ +#define RTLDRSEG_FLAG_OS2_ALIAS16 UINT32_C(2) +/** Conforming segment (x86 weirdness). (OS/2) */ +#define RTLDRSEG_FLAG_OS2_CONFORM UINT32_C(4) +/** IOPL (ring-2) segment. (OS/2) */ +#define RTLDRSEG_FLAG_OS2_IOPL UINT32_C(8) +/** @} */ + +/** + * Segment enumerator callback. + * + * @returns VINF_SUCCESS to continue the enumeration. Any other status code + * will cause RTLdrEnumSegments to immediately return with that + * status. + * + * @param hLdrMod The module handle. + * @param pSeg The segment information. + * @param pvUser The user parameter specified to RTLdrEnumSegments. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRENUMSEGS,(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)); +/** Pointer to a segment enumerator callback. */ +typedef FNRTLDRENUMSEGS *PFNRTLDRENUMSEGS; + +/** + * Enumerate the debug info contained in the executable image. + * + * @returns IPRT status code or whatever pfnCallback returns. + * + * @param hLdrMod The module handle. + * @param pfnCallback The callback function. + * @param pvUser The user argument. + */ +RTDECL(int) RTLdrEnumSegments(RTLDRMOD hLdrMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser); + +/** + * Converts a link address to a segment:offset address. + * + * @returns IPRT status code. + * + * @param hLdrMod The module handle. + * @param LinkAddress The link address to convert. + * @param piSeg Where to return the segment index. + * @param poffSeg Where to return the segment offset. + */ +RTDECL(int) RTLdrLinkAddressToSegOffset(RTLDRMOD hLdrMod, RTLDRADDR LinkAddress, uint32_t *piSeg, PRTLDRADDR poffSeg); + +/** + * Converts a link address to an image relative virtual address (RVA). + * + * @returns IPRT status code. + * + * @param hLdrMod The module handle. + * @param LinkAddress The link address to convert. + * @param pRva Where to return the RVA. + */ +RTDECL(int) RTLdrLinkAddressToRva(RTLDRMOD hLdrMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva); + +/** + * Converts an image relative virtual address (RVA) to a segment:offset. + * + * @returns IPRT status code. + * + * @param hLdrMod The module handle. + * @param iSeg The segment index. + * @param offSeg The segment offset. + * @param pRva Where to return the RVA. + */ +RTDECL(int) RTLdrSegOffsetToRva(RTLDRMOD hLdrMod, uint32_t iSeg, RTLDRADDR offSeg, PRTLDRADDR pRva); + +/** + * Converts a segment:offset into an image relative virtual address (RVA). + * + * @returns IPRT status code. + * + * @param hLdrMod The module handle. + * @param Rva The link address to convert. + * @param piSeg Where to return the segment index. + * @param poffSeg Where to return the segment offset. + */ +RTDECL(int) RTLdrRvaToSegOffset(RTLDRMOD hLdrMod, RTLDRADDR Rva, uint32_t *piSeg, PRTLDRADDR poffSeg); + +/** + * Gets the image format. + * + * @returns Valid image format on success. RTLDRFMT_INVALID on invalid handle or + * other errors. + * @param hLdrMod The module handle. + */ +RTDECL(RTLDRFMT) RTLdrGetFormat(RTLDRMOD hLdrMod); + +/** + * Gets the image type. + * + * @returns Valid image type value on success. RTLDRTYPE_INVALID on + * invalid handle or other errors. + * @param hLdrMod The module handle. + */ +RTDECL(RTLDRTYPE) RTLdrGetType(RTLDRMOD hLdrMod); + +/** + * Gets the image endian-ness. + * + * @returns Valid image endian value on success. RTLDRENDIAN_INVALID on invalid + * handle or other errors. + * @param hLdrMod The module handle. + */ +RTDECL(RTLDRENDIAN) RTLdrGetEndian(RTLDRMOD hLdrMod); + +/** + * Gets the image endian-ness. + * + * @returns Valid image architecture value on success. + * RTLDRARCH_INVALID on invalid handle or other errors. + * @param hLdrMod The module handle. + */ +RTDECL(RTLDRARCH) RTLdrGetArch(RTLDRMOD hLdrMod); + +/** + * Loader properties that can be queried thru RTLdrQueryProp. + */ +typedef enum RTLDRPROP +{ + RTLDRPROP_INVALID = 0, + /** The image UUID (Mach-O). + * Returns a RTUUID in the buffer. */ + RTLDRPROP_UUID, + /** The image timestamp in seconds, genrally since unix epoc. + * Returns a 32-bit or 64-bit signed integer value in the buffer. */ + RTLDRPROP_TIMESTAMP_SECONDS, + /** Checks if the image is signed. + * Returns a bool. */ + RTLDRPROP_IS_SIGNED, + /** Retrives the PKCS \#7 SignedData blob that signs the image. + * Returns variable sized buffer containing the ASN.1 BER encoding. + * + * @remarks This generally starts with a PKCS \#7 Content structure, the + * SignedData bit is found a few levels down into this as per RFC. */ + RTLDRPROP_PKCS7_SIGNED_DATA, + /** Query the number of pages that needs hashing. + * This is for RTLDRPROP_SHA1_PAGE_HASHES and RTLDRPROP_SHA256_PAGE_HASHES + * buffer size calculations. */ + RTLDRPROP_HASHABLE_PAGES, + /** Query the SHA-1 page hashes. + * Returns an array with entries made of a 32-bit file offset and a SHA-1 + * digest. Use RTLDRPROP_HASHABLE_PAGES to calculate the buffer size. */ + RTLDRPROP_SHA1_PAGE_HASHES, + /** Query the SHA-256 page hashes. + * Returns an array with entries made of a 32-bit file offset and a SHA-256 + * digest. Use RTLDRPROP_HASHABLE_PAGES to calculate the buffer size. */ + RTLDRPROP_SHA256_PAGE_HASHES, + + /** Query whether code signature checks are enabled. */ + RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, + + /** Number of import or needed modules. */ + RTLDRPROP_IMPORT_COUNT, + /** Import module by index (32-bit) stored in the buffer. */ + RTLDRPROP_IMPORT_MODULE, + /** The file offset of the main executable header. + * This is mainly for PE, NE and LX headers, but also Mach-O FAT. */ + RTLDRPROP_FILE_OFF_HEADER, + /** The internal module name. + * This is the SONAME for ELF, export table name for PE, and zero'th resident + * name table entry for LX. + * Returns zero terminated string. */ + RTLDRPROP_INTERNAL_NAME, + /** The raw unwind table if available. + * For PE this means IMAGE_DIRECTORY_ENTRY_EXCEPTION content, for AMD64 this + * is the lookup table (IMAGE_RUNTIME_FUNCTION_ENTRY). + * Not implemented any others yet. */ + RTLDRPROP_UNWIND_TABLE, + /** Read unwind info at given RVA and up to buffer size. The RVA is stored + * as uint32_t in the buffer when making the call. + * This is only implemented for PE. */ + RTLDRPROP_UNWIND_INFO, + /** The image build-id (ELF/GNU). + * Returns usually a SHA1 checksum in the buffer. */ + RTLDRPROP_BUILDID, + + /** End of valid properties. */ + RTLDRPROP_END, + /** Blow the type up to 32 bits. */ + RTLDRPROP_32BIT_HACK = 0x7fffffff +} RTLDRPROP; + +/** + * Generic method for querying image properties. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the property query isn't supported (either all + * or that specific property). The caller must handle this result. + * @retval VERR_NOT_FOUND the property was not found in the module. The caller + * must also normally deal with this. + * @retval VERR_INVALID_FUNCTION if the function value is wrong. + * @retval VERR_INVALID_PARAMETER if the buffer size is wrong. + * @retval VERR_BUFFER_OVERFLOW if the function doesn't have a fixed size + * buffer and the buffer isn't big enough. Use RTLdrQueryPropEx. + * @retval VERR_INVALID_HANDLE if the handle is invalid. + * + * @param hLdrMod The module handle. + * @param enmProp The property to query. + * @param pvBuf Pointer to the input / output buffer. In most cases + * it's only used for returning data. + * @param cbBuf The size of the buffer. + */ +RTDECL(int) RTLdrQueryProp(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf); + +/** + * Generic method for querying image properties, extended version. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the property query isn't supported (either all + * or that specific property). The caller must handle this result. + * @retval VERR_NOT_FOUND the property was not found in the module. The caller + * must also normally deal with this. + * @retval VERR_INVALID_FUNCTION if the function value is wrong. + * @retval VERR_INVALID_PARAMETER if the fixed buffer size is wrong. Correct + * size in @a *pcbRet. + * @retval VERR_BUFFER_OVERFLOW if the function doesn't have a fixed size + * buffer and the buffer isn't big enough. Correct size in @a *pcbRet. + * @retval VERR_INVALID_HANDLE if the handle is invalid. + * + * @param hLdrMod The module handle. + * @param enmProp The property to query. + * @param pvBits Optional pointer to bits returned by + * RTLdrGetBits(). This can be utilized by some module + * interpreters to reduce memory consumption and file + * access. + * @param pvBuf Pointer to the input / output buffer. In most cases + * it's only used for returning data. + * @param cbBuf The size of the buffer. + * @param pcbRet Where to return the amount of data returned. On + * buffer size errors, this is set to the correct size. + * Optional. + */ +RTDECL(int) RTLdrQueryPropEx(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBits, void *pvBuf, size_t cbBuf, size_t *pcbRet); + + +/** + * Signature type, see FNRTLDRVALIDATESIGNEDDATA. + */ +typedef enum RTLDRSIGNATURETYPE +{ + /** Invalid value. */ + RTLDRSIGNATURETYPE_INVALID = 0, + /** A RTPKCS7CONTENTINFO structure w/ RTPKCS7SIGNEDDATA inside. + * It's parsed, so the whole binary ASN.1 representation can be found by + * using RTASN1CORE_GET_RAW_ASN1_PTR() and RTASN1CORE_GET_RAW_ASN1_SIZE(). */ + RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA, + /** End of valid values. */ + RTLDRSIGNATURETYPE_END, + /** Make sure the size is 32-bit. */ + RTLDRSIGNATURETYPE_32BIT_HACK = 0x7fffffff +} RTLDRSIGNATURETYPE; + +/** + * Signature information provided by FNRTLDRVALIDATESIGNEDDATA. + */ +typedef struct RTLDRSIGNATUREINFO +{ + /** The signature number (0-based). */ + uint16_t iSignature; + /** The total number of signatures. */ + uint16_t cSignatures; + /** Sginature format type. */ + RTLDRSIGNATURETYPE enmType; + /** The signature data (formatted according to enmType). */ + void const *pvSignature; + /** The size of the buffer pvSignature points to. */ + size_t cbSignature; + /** Pointer to the signed data, if external. + * NULL if the data is internal to the signature structure. */ + void const *pvExternalData; + /** Size of the signed data, if external. + * 0 if internal to the signature structure. */ + size_t cbExternalData; +} RTLDRSIGNATUREINFO; +/** Pointer to a signature structure. */ +typedef RTLDRSIGNATUREINFO *PRTLDRSIGNATUREINFO; +/** Pointer to a const signature structure. */ +typedef RTLDRSIGNATUREINFO const *PCRTLDRSIGNATUREINFO; + +/** + * Callback used by RTLdrVerifySignature to verify the signature and associated + * certificates. + * + * This is called multiple times when the executable contains more than one + * signature (PE only at the moment). The RTLDRSIGNATUREINFO::cSignatures gives + * the total number of signatures (and thereby callbacks) and + * RTLDRSIGNATUREINFO::iSignature indicates the current one. + * + * @returns IPRT status code. A status code other than VINF_SUCCESS will + * prevent callbacks the remaining signatures (if any). + * @param hLdrMod The module handle. + * @param pInfo Signature information. + * @param pErrInfo Pointer to an error info buffer, optional. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRVALIDATESIGNEDDATA,(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREINFO pInfo, + PRTERRINFO pErrInfo, void *pvUser)); +/** Pointer to a signature verification callback. */ +typedef FNRTLDRVALIDATESIGNEDDATA *PFNRTLDRVALIDATESIGNEDDATA; + +/** + * Verify the image signature. + * + * This may permform additional integrity checks on the image structures that + * was not done when opening the image. + * + * @returns IPRT status code. + * @retval VERR_LDRVI_NOT_SIGNED if not signed. + * + * @param hLdrMod The module handle. + * @param pfnCallback Callback that does the signature and certificate + * verficiation. + * @param pvUser User argument for the callback. + * @param pErrInfo Pointer to an error info buffer. Optional. + */ +RTDECL(int) RTLdrVerifySignature(RTLDRMOD hLdrMod, PFNRTLDRVALIDATESIGNEDDATA pfnCallback, void *pvUser, PRTERRINFO pErrInfo); + +/** + * Calculate the image hash according the image signing rules. + * + * @returns IPRT status code. + * @param hLdrMod The module handle. + * @param enmDigest Which kind of digest. + * @param pabHash Where to store the image hash. + * @param cbHash Size of the buffer @a pabHash points at. The + * required and returned size can be derived from the + * digest type (@a enmDigest). + */ +RTDECL(int) RTLdrHashImage(RTLDRMOD hLdrMod, RTDIGESTTYPE enmDigest, uint8_t *pabHash, size_t cbHash); + +/** + * Try use unwind information to unwind one frame. + * + * @returns IPRT status code. Last informational status from stack reader callback. + * @retval VERR_DBG_NO_UNWIND_INFO if the module contains no unwind information. + * @retval VERR_DBG_UNWIND_INFO_NOT_FOUND if no unwind information was found + * for the location given by iSeg:off. + * + * @param hLdrMod The module handle. + * @param pvBits Optional pointer to bits returned by + * RTLdrGetBits(). This can be utilized by some module + * interpreters to reduce memory consumption and file + * access. + * @param iSeg The segment number of the program counter. UINT32_MAX if RVA. + * @param off The offset into @a iSeg. Together with @a iSeg + * this corresponds to the RTDBGUNWINDSTATE::uPc + * value pointed to by @a pState. + * @param pState The unwind state to work. + * + * @sa RTDbgModUnwindFrame + */ +RTDECL(int) RTLdrUnwindFrame(RTLDRMOD hLdrMod, void const *pvBits, uint32_t iSeg, RTLDRADDR off, PRTDBGUNWINDSTATE pState); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_ldr_h */ + diff --git a/include/iprt/ldrlazy.h b/include/iprt/ldrlazy.h new file mode 100644 index 00000000..0fa788da --- /dev/null +++ b/include/iprt/ldrlazy.h @@ -0,0 +1,122 @@ +/** @file + * IPRT - Lazy share library linking (2nd try). + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ldrlazy_h +#define IPRT_INCLUDED_ldrlazy_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_ldrlazy RTLdrLazy - Lazy shared library linking. + * @ingroup grp_rt + * + * This is a set of macros which will produce code for dynamically loading and + * resolving symbols in shared libraries (DLLs). + * + * There is an assembly language alternative to this that only requires writing + * a list of symbols in a format similar to what the microsoft linkers take as + * input when producing DLLs and import libraries. That is probably preferable + * over this code. See src/bldprog/VBoxDef2LazyLoad.cpp. + * + * @{ + */ + + +/** + * Defines a module for use in lazy resolving. + * + * @param a_Mod The module name (C name). + * @param a_pszFile The file to tell RTLdrLoad to load. + */ +#define RTLDRLAZY_MODULE(a_Mod, a_pszFile) \ + RTLDRLAZY_MODULE_EX(a_Mod, a_pszFile, RTLdrLoad) + +/** + * Defines a module for use in lazy resolving. + * + * @param a_Mod The module name (C name). + * @param a_pszFile The file to tell RTLdrLoad to load. + * @param a_pfnLoadIt Function to call for loading the DLL, replacing + * RTLdrLoad. + */ +#define RTLDRLAZY_MODULE_EX(a_Mod, a_pszFile, a_pfnLoadIt) \ + static bool rtLdrLazy_##a_Mod##_Resolve(const char *pszName, void **ppvSymbol) \ + { \ + static RTLDRMOD volatile s_hMod = NIL_RTLDRMOD; \ + static bool volatile s_fLoaded = false; \ + RTLDRMOD hMod; \ + int rc; \ + if (!s_fLoaded) \ + { \ + rc = a_pfnLoadIt(a_pszFile, &hMod); \ + s_hMod = RT_SUCCESS(rc) ? hMod : NIL_RTLDRMOD; \ + s_fLoaded = true; \ + if (RT_FAILURE(rc)) \ + return false; \ + } \ + hMod = s_hMod; \ + if (hMod == NIL_RTLDRMOD) \ + return false; \ + rc = RTLdrGetSymbol(hMod, pszName, ppvSymbol); \ + return RT_SUCCESS(rc); \ + } + + + +/** Function name mangler for preventing collision with system prototypes. */ +#define RTLDRLAZY_FUNC_NAME(a_Mod, a_Name) a_Mod##__##a_Name + +/** + * Defines a function that should be lazily resolved. + */ +#define RTLDRLAZY_FUNC(a_Mod, a_RetType, a_CallConv, a_Name, a_ParamDecl, a_ParamNames, a_ErrRet) \ + DECLINLINE(a_RetType) RTLDRLAZY_FUNC_NAME(a_Mod, a_Name) a_ParamDecl \ + { \ + static a_RetType (a_CallConv * s_pfn) a_ParamDecl; \ + if (!s_pfn) \ + { \ + if (!rtLdrLazy_##a_Mod##_Resolve(#a_Name, (void **)&s_pfn)) \ + return a_ErrRet; \ + } \ + return s_pfn a_ParamNames; \ + } + + +/** @} */ + +#endif /* !IPRT_INCLUDED_ldrlazy_h */ + diff --git a/include/iprt/linux/Makefile.kup b/include/iprt/linux/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/linux/symvers.h b/include/iprt/linux/symvers.h new file mode 100644 index 00000000..0a8ef1b7 --- /dev/null +++ b/include/iprt/linux/symvers.h @@ -0,0 +1,89 @@ +/** @file + * IPRT - Linux symver and compatibility definitions. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/* Various tricks to produce binaries which can be run on old Linux + * distributions. This will almost certainly need updating as time + * goes by. */ + +#ifndef IPRT_INCLUDED_linux_symvers_h +#define IPRT_INCLUDED_linux_symvers_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Please use -fno-stack-protector on the command line to avoid stack check + * functions which are not available in EL3 for 32-bit builds. */ + +/* Use versions of glibc symbols which are available in 32-bit EL3 or + * 64-bit EL4. Currently only those symbols needed by the Additions, + * though this could probably be extended to work for host builds too. */ +#if defined(RT_ARCH_AMD64) +__asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); +__asm__(".symver posix_spawn,posix_spawn@GLIBC_2.2.5"); +#else /* RT_ARCH_X86 */ +__asm__(".symver posix_spawn,posix_spawn@GLIBC_2.2"); +#endif + +/* Do not use *_chk functions */ +#undef _FORTIFY_SOURCE + +/* Do not use __isoc99_* functions */ +#undef __USE_GNU +#define __USE_GNU 1 + +/* And EL5 wants this too with __USE_GNU */ +#undef _GNU_SOURCE +#define _GNU_SOURCE 1 + +/* Tell IPRT not to use newer functions */ +#include +#undef __GLIBC_MINOR__ +#define __GLIBC_MINOR__ 3 + +/* Do not use fcntl64 */ +#include +#ifdef fnctl +# undef fcntl +#endif +#if defined(RT_ARCH_AMD64) +__asm__(".symver fcntl64,fcntl@GLIBC_2.2.5"); +#else +__asm__(".symver fcntl64,fcntl@GLIBC_2.0"); +#endif + +/* Do not use ISO C99 scanf which has a glibc 2.7 dependency. */ +#undef __GLIBC_USE_DEPRECATED_SCANF +#define __GLIBC_USE_DEPRECATED_SCANF 1 +#endif /* !IPRT_INCLUDED_linux_symvers_h */ diff --git a/include/iprt/linux/sysfs.h b/include/iprt/linux/sysfs.h new file mode 100644 index 00000000..02c3af39 --- /dev/null +++ b/include/iprt/linux/sysfs.h @@ -0,0 +1,487 @@ +/* $Id: sysfs.h $ */ +/** @file + * IPRT - Linux sysfs access. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_linux_sysfs_h +#define IPRT_INCLUDED_linux_sysfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include /* for dev_t */ + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_linux_sysfs RTLinuxSysfs - Linux sysfs + * @ingroup grp_rt + * @{ + */ + +/** + * Checks if a sysfs file (or directory, device, symlink, whatever) exists. + * + * @returns true if the sysfs object exists. + * false otherwise or if an error occurred. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + */ +RTDECL(bool) RTLinuxSysFsExistsV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Checks if a sysfs object (directory, device, symlink, whatever) exists. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the sysfs object exists. + * @retval VERR_FILE_NOT_FOUND if the sysfs object does not exist. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + */ +RTDECL(int) RTLinuxSysFsExistsExV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Checks if a sysfs file (or directory, device, symlink, whatever) exists. + * + * @returns true if the sysfs object exists. + * false otherwise or if an error occurred. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + */ +RTDECL(bool) RTLinuxSysFsExists(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Checks if a sysfs object (directory, device, symlink, whatever) exists. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the sysfs object exists. + * @retval VERR_FILE_NOT_FOUND if the sysfs object does not exist. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + */ +RTDECL(int) RTLinuxSysFsExistsEx(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Opens a sysfs file for reading. + * + * @returns IPRT status code. + * @param phFile Where to store the file handle on success. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + * + * @note Close the file using RTFileClose(). + */ +RTDECL(int) RTLinuxSysFsOpenV(PRTFILE phFile, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Opens a sysfs file - extended version. + * + * @returns IPRT status code. + * @param phFile Where to store the file handle on success. + * @param fOpen Open flags, see RTFileOpen(). + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + */ +RTDECL(int) RTLinuxSysFsOpenExV(PRTFILE phFile, uint64_t fOpen, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Opens a sysfs file. + * + * @returns IPRT status code. + * @param phFile Where to store the file handle on success. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + * + * @note Close the file using RTFileClose(). + */ +RTDECL(int) RTLinuxSysFsOpen(PRTFILE phFile, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Opens a sysfs file - extended version. + * + * @returns IPRT status code. + * @param phFile Where to store the file handle on success. + * @param fOpen Open flags, see RTFileOpen(). + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + */ +RTDECL(int) RTLinuxSysFsOpenEx(PRTFILE phFile, uint64_t fOpen, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Reads a string from a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV. + * + * Expects to read the whole file, mind, and will return VERR_BUFFER_OVERFLOW if + * that is not possible with the given buffer size. + * + * @returns IPRT status code. + * @param hFile The file descriptor returned by RTLinuxSysFsOpen or RTLinuxSysFsOpenV. + * @param pszBuf Where to store the string. + * @param cchBuf The size of the buffer. Must be at least 2 bytes. + * @param pcchRead Where to store the amount of characters read on success - optional. + */ +RTDECL(int) RTLinuxSysFsReadStr(RTFILE hFile, char *pszBuf, size_t cchBuf, size_t *pcchRead); + +/** + * Writes a string to a file opened with RTLinuxSysFsOpenEx or RTLinuxSysFsOpenExV for writing. + * + * @returns IPRT status code. + * @param hFile The file descriptor returned by RTLinuxSysFsOpenEx or RTLinuxSysFsOpenExV. + * @param pszBuf The string to write. + * @param cchBuf The length of the string to write - if 0 is given + * the string length is determined before writing it including the zero terminator. + * @param pcchWritten Where to store the amount of characters written on success - optional. + */ +RTDECL(int) RTLinuxSysFsWriteStr(RTFILE hFile, const char *pszBuf, size_t cchBuf, size_t *pcchWritten); + +/** + * Reads the remainder of a file opened with RTLinuxSysFsOpen or + * RTLinuxSysFsOpenV. + * + * @returns IPRT status code. + * @param hFile The file descriptor returned by RTLinuxSysFsOpen or RTLinuxSysFsOpenV. + * @param pvBuf Where to store the bits from the file. + * @param cbBuf The size of the buffer. + * @param pcbRead Where to return the number of bytes read. Optional. + */ +RTDECL(int) RTLinuxSysFsReadFile(RTFILE hFile, void *pvBuf, size_t cbBuf, size_t *pcbRead); + +/** + * Writes the given buffer to a file opened with RTLinuxSysFsOpenEx or + * RTLinuxSysFsOpenExV. + * + * @returns IPRT status code. + * @param hFile The file descriptor returned by RTLinuxSysFsOpenEx or RTLinuxSysFsOpenExV. + * @param pvBuf The data to write. + * @param cbBuf The size of the buffer. + * @param pcbWritten Where to return the number of bytes read. Optional. + */ +RTDECL(int) RTLinuxSysFsWriteFile(RTFILE hFile, void *pvBuf, size_t cbBuf, size_t *pcbWritten); + +/** + * Reads a number from a sysfs file. + * + * @returns IPRT status code. + * @param uBase The number base, 0 for autodetect. + * @param pi64 Where to store the 64-bit signed on success. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsReadIntFileV(unsigned uBase, int64_t *pi64, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Reads a number from a sysfs file. + * + * @returns IPRT status code. + * @param uBase The number base, 0 for autodetect. + * @param pi64 Where to store the 64-bit signed on success. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsReadIntFile(unsigned uBase, int64_t *pi64, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Writes an unsigned 8-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u8 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU8FileV(unsigned uBase, uint8_t u8, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Writes an unsigned 8-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u8 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU8File(unsigned uBase, uint8_t u8, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Writes an unsigned 16-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u16 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU16FileV(unsigned uBase, uint16_t u16, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Writes an unsigned 16-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u16 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU16File(unsigned uBase, uint16_t u16, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Writes an unsigned 32-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u32 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU32FileV(unsigned uBase, uint32_t u32, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Writes an unsigned 8-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u32 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU32File(unsigned uBase, uint32_t u32, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Writes an unsigned 64-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u64 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU64FileV(unsigned uBase, uint64_t u64, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Writes an unsigned 8-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u64 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU64File(unsigned uBase, uint32_t u64, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Reads a device number from a sysfs file. + * + * @returns IPRT status code. + * @param pDevNum Where to store the device number on success. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsReadDevNumFileV(dev_t *pDevNum, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Reads a device number from a sysfs file. + * + * @returns IPRT status code. + * @param pDevNum Where to store the device number on success. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsReadDevNumFile(dev_t *pDevNum, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Reads a string from a sysfs file. + * + * If the file contains a newline, we only return the text up until there. This + * differs from the RTLinuxSysFsReadStr() behaviour. + * + * @returns IPRT status code. + * @param pszBuf Where to store the path element. Must be at least two + * characters, but a longer buffer would be advisable. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pcchRead Where to store the amount of characters read on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, size_t *pcchRead, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Reads a string from a sysfs file. If the file contains a newline, we only + * return the text up until there. + * + * @returns IPRT status code. + * @param pszBuf Where to store the path element. Must be at least two + * characters, but a longer buffer would be advisable. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pcchRead Where to store the amount of characters read on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsReadStrFile(char *pszBuf, size_t cchBuf, size_t *pcchRead, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Writes a string to a sysfs file. + * + * @returns IPRT status code. + * @param pszBuf The string to write. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pcchWritten Where to store the amount of characters written on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteStrFileV(const char *pszBuf, size_t cchBuf, size_t *pcchWritten, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Writes a string to a sysfs file. + * + * @returns IPRT status code. + * @param pszBuf The string to write. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pcchWritten Where to store the amount of characters written on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteStrFile(const char *pszBuf, size_t cchBuf, size_t *pcchWritten, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Reads the last element of the path of the file pointed to by the symbolic + * link specified. + * + * This is needed at least to get the name of the driver associated with a + * device, where pszFormat should be the "driver" link in the devices sysfs + * directory. + * + * @returns IPRT status code. + * @param pszBuf Where to store the path element. Must be at least two + * characters, but a longer buffer would be advisable. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pchBuf Where to store the length of the returned string on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsGetLinkDestV(char *pszBuf, size_t cchBuf, size_t *pchBuf, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Reads the last element of the path of the file pointed to by the symbolic + * link specified. + * + * This is needed at least to get the name of the driver associated with a + * device, where pszFormat should be the "driver" link in the devices sysfs + * directory. + * + * @returns IPRT status code. + * @param pszBuf Where to store the path element. Must be at least two + * characters, but a longer buffer would be advisable. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pchBuf Where to store the length of the returned string on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, size_t *pchBuf, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Check the path of a device node under /dev, given the device number and a + * pattern and store the path into @a pszBuf. + * + * @returns IPRT status code. + * @retval VERR_FILE_NOT_FOUND if no matching device node could be found. + * @param DevNum The device number to search for. + * @param fMode The type of device - only RTFS_TYPE_DEV_CHAR and + * RTFS_TYPE_DEV_BLOCK are valid values. + * @param pszBuf Where to store the path. + * @param cchBuf The size of the buffer. + * @param pszPattern The expected path format of the device node, either + * absolute or relative to "/dev". + * @param va Format args. + */ +RTDECL(int) RTLinuxCheckDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, + const char *pszPattern, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * Check the path of a device node under /dev, given the device number and a + * pattern and store the path into @a pszBuf. + * + * @returns IPRT status code. + * @retval VERR_FILE_NOT_FOUND if no matching device node could be found. + * @param DevNum The device number to search for + * @param fMode The type of device - only RTFS_TYPE_DEV_CHAR and + * RTFS_TYPE_DEV_BLOCK are valid values + * @param pszBuf Where to store the path. + * @param cchBuf The size of the buffer. + * @param pszPattern The expected path format of the device node, either + * absolute or relative to "/dev". + * @param ... Format args. + */ +RTDECL(int) RTLinuxCheckDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, + const char *pszPattern, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Constructs the path of a sysfs file from the format parameters passed, + * prepending "/sys/" if the path is relative. + * + * @returns IPRT status code. + * @param pszPath Where to write the path. + * @param cbPath The size of the buffer pointed to by @a pszPath. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + */ +RTDECL(int) RTLinuxConstructPathV(char *pszPath, size_t cbPath, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Constructs the path of a sysfs file from the format parameters passed, + * prepending "/sys/" if the path is relative. + * + * @returns IPRT status code. + * @param pszPath Where to write the path. + * @param cbPath The size of the buffer pointed to by @a pszPath. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + */ +RTDECL(int) RTLinuxConstructPath(char *pszPath, size_t cbPath, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_linux_sysfs_h */ + diff --git a/include/iprt/linux/version.h b/include/iprt/linux/version.h new file mode 100644 index 00000000..6badeab0 --- /dev/null +++ b/include/iprt/linux/version.h @@ -0,0 +1,205 @@ +/* $Id: version.h $ */ +/** @file + * IPRT - Linux kernel version. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_linux_version_h +#define IPRT_INCLUDED_linux_version_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* We need utsrelease.h in order to detect Ubuntu kernel, + * i.e. check if UTS_UBUNTU_RELEASE_ABI is defined. Support kernels + * starting from Ubuntu 14.04 Trusty which is based on upstream + * kernel 3.13.x. */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)) +# include +# include +#endif + +/** @def RTLNX_VER_MIN + * Evaluates to true if the linux kernel version is equal or higher to the + * one specfied. */ +#define RTLNX_VER_MIN(a_Major, a_Minor, a_Patch) \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(a_Major, a_Minor, a_Patch)) + +/** @def RTLNX_VER_MAX + * Evaluates to true if the linux kernel version is less to the one specfied + * (exclusive). */ +#define RTLNX_VER_MAX(a_Major, a_Minor, a_Patch) \ + (LINUX_VERSION_CODE < KERNEL_VERSION(a_Major, a_Minor, a_Patch)) + +/** @def RTLNX_VER_RANGE + * Evaluates to true if the linux kernel version is equal or higher to the given + * minimum version and less (but not equal) to the maximum version (exclusive). */ +#define RTLNX_VER_RANGE(a_MajorMin, a_MinorMin, a_PatchMin, a_MajorMax, a_MinorMax, a_PatchMax) \ + ( LINUX_VERSION_CODE >= KERNEL_VERSION(a_MajorMin, a_MinorMin, a_PatchMin) \ + && LINUX_VERSION_CODE < KERNEL_VERSION(a_MajorMax, a_MinorMax, a_PatchMax) ) + + +/** @def RTLNX_RHEL_MIN + * Require a minium RedHat release. + * @param a_iMajor The major release number (RHEL_MAJOR). + * @param a_iMinor The minor release number (RHEL_MINOR). + * @sa RTLNX_RHEL_MAX, RTLNX_RHEL_RANGE, RTLNX_RHEL_MAJ_PREREQ + */ +#if defined(RHEL_MAJOR) && defined(RHEL_MINOR) +# define RTLNX_RHEL_MIN(a_iMajor, a_iMinor) \ + ((RHEL_MAJOR) > (a_iMajor) || ((RHEL_MAJOR) == (a_iMajor) && (RHEL_MINOR) >= (a_iMinor))) +#else +# define RTLNX_RHEL_MIN(a_iMajor, a_iMinor) (0) +#endif + +/** @def RTLNX_RHEL_MAX + * Require a maximum RedHat release, true for all RHEL versions below it. + * @param a_iMajor The major release number (RHEL_MAJOR). + * @param a_iMinor The minor release number (RHEL_MINOR). + * @sa RTLNX_RHEL_MIN, RTLNX_RHEL_RANGE, RTLNX_RHEL_MAJ_PREREQ + */ +#if defined(RHEL_MAJOR) && defined(RHEL_MINOR) +# define RTLNX_RHEL_MAX(a_iMajor, a_iMinor) \ + ((RHEL_MAJOR) < (a_iMajor) || ((RHEL_MAJOR) == (a_iMajor) && (RHEL_MINOR) < (a_iMinor))) +#else +# define RTLNX_RHEL_MAX(a_iMajor, a_iMinor) (0) +#endif + +/** @def RTLNX_RHEL_RANGE + * Check that it's a RedHat kernel in the given version range. + * The max version is exclusive, the minimum inclusive. + * @sa RTLNX_RHEL_MIN, RTLNX_RHEL_MAX, RTLNX_RHEL_MAJ_PREREQ + */ +#if defined(RHEL_MAJOR) && defined(RHEL_MINOR) +# define RTLNX_RHEL_RANGE(a_iMajorMin, a_iMinorMin, a_iMajorMax, a_iMinorMax) \ + (RTLNX_RHEL_MIN(a_iMajorMin, a_iMinorMin) && RTLNX_RHEL_MAX(a_iMajorMax, a_iMinorMax)) +#else +# define RTLNX_RHEL_RANGE(a_iMajorMin, a_iMinorMin, a_iMajorMax, a_iMinorMax) (0) +#endif + +/** @def RTLNX_RHEL_MAJ_PREREQ + * Require a minimum minor release number for the given RedHat release. + * @param a_iMajor RHEL_MAJOR must _equal_ this. + * @param a_iMinor RHEL_MINOR must be greater or equal to this. + * @sa RTLNX_RHEL_MIN, RTLNX_RHEL_MAX + */ +#if defined(RHEL_MAJOR) && defined(RHEL_MINOR) +# define RTLNX_RHEL_MAJ_PREREQ(a_iMajor, a_iMinor) ((RHEL_MAJOR) == (a_iMajor) && (RHEL_MINOR) >= (a_iMinor)) +#else +# define RTLNX_RHEL_MAJ_PREREQ(a_iMajor, a_iMinor) (0) +#endif + + +/** @def RTLNX_SUSE_MAJ_PREREQ + * Require a minimum minor release number for the given SUSE release. + * @param a_iMajor CONFIG_SUSE_VERSION must _equal_ this. + * @param a_iMinor CONFIG_SUSE_PATCHLEVEL must be greater or equal to this. + */ +#if defined(CONFIG_SUSE_VERSION) && defined(CONFIG_SUSE_PATCHLEVEL) +# define RTLNX_SUSE_MAJ_PREREQ(a_iMajor, a_iMinor) ((CONFIG_SUSE_VERSION) == (a_iMajor) && (CONFIG_SUSE_PATCHLEVEL) >= (a_iMinor)) +#else +# define RTLNX_SUSE_MAJ_PREREQ(a_iMajor, a_iMinor) (0) +#endif + + +#if defined(UTS_UBUNTU_RELEASE_ABI) || defined(DOXYGEN_RUNNING) + +/** Hack to make the UTS_UBUNTU_RELEASE_ABI palatable by the C preprocesor. + * + * While the Ubuntu kernel ABI version looks like a decimal number, some + * kernels has a leading zero (e.g. 050818) that makes the preprocessor think + * it's an octal number. To work around that, we turn it into an hexadecimal + * number by prefixing it with '0x'. */ +# define RTLNX_UBUNTU_ABI(a_iAbi) (RT_CONCAT(0x,a_iAbi)) + +/** @def RTLNX_UBUNTU_ABI_MIN + * Require Ubuntu release ABI to be equal or newer than specified version. + * + * The kernel version should exactly match the specified @a a_iMajor, @a + * a_iMinor and @a a_iPatch. The @a a_iAbi number should be equal to or greater + * than the current ABI version. + * + * @param a_iMajor The major kernel version number. + * @param a_iMinor The minor kernel version number. + * @param a_iPatch The kernel patch level. + * @param a_iAbi Ubuntu kernel ABI version number (inclusive). + */ +# define RTLNX_UBUNTU_ABI_MIN(a_iMajor, a_iMinor, a_iPatch, a_iAbi) \ + ( KERNEL_VERSION(a_iMajor, a_iMinor, a_iPatch) == LINUX_VERSION_CODE \ + && RTLNX_UBUNTU_ABI(UTS_UBUNTU_RELEASE_ABI) >= RTLNX_UBUNTU_ABI(a_iAbi)) + +/** @def RTLNX_UBUNTU_ABI_MAX + * Require Ubuntu release ABI to be older than specified version. + * + * The kernel version should exactly match the specified @a a_iMajor, @a + * a_iMinor and @a a_iPatch. The @a a_iAbi number should be less than the + * current ABI version. + * + * @param a_iMajor The major kernel version number. + * @param a_iMinor The minor kernel version number. + * @param a_iPatch The kernel patch level. + * @param a_iAbi Ubuntu kernel ABI version number (exclusive). + */ +# define RTLNX_UBUNTU_ABI_MAX(a_iMajor, a_iMinor, a_iPatch, a_iAbi) \ + ( KERNEL_VERSION(a_iMajor, a_iMinor, a_iPatch) == LINUX_VERSION_CODE \ + && RTLNX_UBUNTU_ABI(UTS_UBUNTU_RELEASE_ABI) < RTLNX_UBUNTU_ABI(a_iAbi)) + +/** @def RTLNX_UBUNTU_ABI_RANGE + * Require Ubuntu release ABI to be in specified range. + * + * The kernel version should exactly match the specified @a a_iMajor, @a + * a_iMinor and @a a_iPatch. The numbers @a a_iAbiMin and @a a_iAbiMax specify + * ABI versions range. The max ABI version is exclusive, the minimum inclusive. + * + * @param a_iMajor The major kernel version number. + * @param a_iMinor The minor kernel version number. + * @param a_iPatch The kernel patch level. + * @param a_iAbiMin The minimum Ubuntu kernel ABI version number (inclusive). + * @param a_iAbiMax The maximum Ubuntu kernel ABI version number (exclusive). + */ +# define RTLNX_UBUNTU_ABI_RANGE(a_iMajor, a_iMinor, a_iPatch, a_iAbiMin, a_iAbiMax) \ + ( RTLNX_UBUNTU_ABI_MIN(a_iMajor, a_iMinor, a_iPatch, a_iAbiMin) \ + && RTLNX_UBUNTU_ABI_MAX(a_iMajor, a_iMinor, a_iPatch, a_iAbiMax)) + +#else /* !UTS_UBUNTU_RELEASE_ABI */ + +# define RTLNX_UBUNTU_ABI_MIN(a_iMajor, a_iMinor, a_iPatch, a_iAbi) (0) +# define RTLNX_UBUNTU_ABI_MAX(a_iMajor, a_iMinor, a_iPatch, a_iAbi) (0) +# define RTLNX_UBUNTU_ABI_RANGE(a_iMajorMin, a_iMinorMin, a_iPatchMin, a_iAbiMin, a_iAbiMax) (0) + +#endif /* !UTS_UBUNTU_RELEASE_ABI */ + +#endif /* !IPRT_INCLUDED_linux_version_h */ + diff --git a/include/iprt/list-off32.h b/include/iprt/list-off32.h new file mode 100644 index 00000000..69a4efcf --- /dev/null +++ b/include/iprt/list-off32.h @@ -0,0 +1,514 @@ +/** @file + * IPRT - Generic Doubly Linked List, using 32-bit offset instead of pointers. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_list_off32_h +#define IPRT_INCLUDED_list_off32_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_list_off32 RTListOff32 - Generic Doubly Linked List based on 32-bit offset. + * @ingroup grp_rt + * + * This is the same as @ref grp_rt_list , except that instead of pointers we use + * 32-bit offsets. The list implementation is circular, with a dummy node as + * anchor. Be careful with the dummy node when walking the list. + * + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * A list node of a doubly linked list. + */ +typedef struct RTLISTOFF32NODE +{ + /** Offset to the next list node, relative to this structure. */ + int32_t offNext; + /** Offset to the previous list node, relative to this structure. */ + int32_t offPrev; +} RTLISTOFF32NODE; +/** Pointer to a list node. */ +typedef RTLISTOFF32NODE *PRTLISTOFF32NODE; +/** Pointer to a const list node. */ +typedef RTLISTOFF32NODE const *PCRTLISTOFF32NODE; +/** Pointer to a list node pointer. */ +typedef PRTLISTOFF32NODE *PPRTLISTOFF32NODE; + +/** The anchor (head/tail) of a doubly linked list. + * + * @remarks Please always use this instead of RTLISTOFF32NODE to indicate a list + * head/tail. It makes the code so much easier to read. Also, + * always mention the actual list node type(s) in the comment. + * @remarks Must be allocated in a similar manner as the nodes, so as to + * keep it within a 32-bit distance from them. + */ +typedef RTLISTOFF32NODE RTLISTOFF32ANCHOR; +/** Pointer to a doubly linked list anchor. */ +typedef RTLISTOFF32ANCHOR *PRTLISTOFF32ANCHOR; +/** Pointer to a const doubly linked list anchor. */ +typedef RTLISTOFF32ANCHOR const *PCRTLISTOFF32ANCHOR; + + +/** + * Initialize a list. + * + * @param pList Pointer to an unitialised list. + */ +DECLINLINE(void) RTListOff32Init(PRTLISTOFF32NODE pList) +{ + pList->offNext = 0; + pList->offPrev = 0; +} + +/** + * Internal macro for converting an offset to a pointer. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node the offset is relative to. + * @param a_off The offset. + */ +#define RTLISTOFF32_TO_PTR(a_pNode, a_off) ((PRTLISTOFF32NODE)((intptr_t)(a_pNode) + (a_off))) + +/** + * Internal macro for getting the pointer to the next node. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node the offset is relative to. + */ +#define RTLISTOFF32_NEXT_PTR(a_pNode) RTLISTOFF32_TO_PTR(a_pNode, (a_pNode)->offNext) + +/** + * Internal macro for getting the pointer to the previous node. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node the offset is relative to. + */ +#define RTLISTOFF32_PREV_PTR(a_pNode) RTLISTOFF32_TO_PTR(a_pNode, (a_pNode)->offPrev) + +/** + * Internal macro for converting an a pointer to an offset. + * @returns offset + * @param a_pNode The node the offset is relative to. + * @param a_pOtherNode The pointer to convert. + */ +#define RTLISTOFF32_TO_OFF(a_pNode, a_pOtherNode) ((int32_t)((intptr_t)(a_pOtherNode) - (intptr_t)(a_pNode))) + +/** + * Internal macro for getting the pointer to the next node. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node which offNext member should be set. + * @param a_pNewNext Pointer to the new next node. + */ +#define RTLISTOFF32_SET_NEXT_PTR(a_pNode, a_pNewNext) \ + do { (a_pNode)->offNext = RTLISTOFF32_TO_OFF(a_pNode, a_pNewNext); } while (0) + +/** + * Internal macro for getting the pointer to the previous node. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node which offPrev member should be set. + * @param a_pNewPrev Pointer to the new previous node. + */ +#define RTLISTOFF32_SET_PREV_PTR(a_pNode, a_pNewPrev) \ + do { (a_pNode)->offPrev = RTLISTOFF32_TO_OFF(a_pNode, a_pNewPrev); } while (0) + + + +/** + * Append a node to the end of the list. + * + * @param pList The list to append the node to. + * @param pNode The node to append. + */ +DECLINLINE(void) RTListOff32Append(PRTLISTOFF32NODE pList, PRTLISTOFF32NODE pNode) +{ + PRTLISTOFF32NODE pLast = RTLISTOFF32_PREV_PTR(pList); + RTLISTOFF32_SET_NEXT_PTR(pLast, pNode); + RTLISTOFF32_SET_PREV_PTR(pNode, pLast); + RTLISTOFF32_SET_NEXT_PTR(pNode, pList); + RTLISTOFF32_SET_PREV_PTR(pList, pNode); +} + +/** + * Add a node as the first element of the list. + * + * @param pList The list to prepend the node to. + * @param pNode The node to prepend. + */ +DECLINLINE(void) RTListOff32Prepend(PRTLISTOFF32NODE pList, PRTLISTOFF32NODE pNode) +{ + PRTLISTOFF32NODE pFirst = RTLISTOFF32_NEXT_PTR(pList); + RTLISTOFF32_SET_PREV_PTR(pFirst, pNode); + RTLISTOFF32_SET_NEXT_PTR(pNode, pFirst); + RTLISTOFF32_SET_PREV_PTR(pNode, pList); + RTLISTOFF32_SET_NEXT_PTR(pList, pNode); +} + +/** + * Inserts a node after the specified one. + * + * @param pCurNode The current node. + * @param pNewNode The node to insert. + */ +DECLINLINE(void) RTListOff32NodeInsertAfter(PRTLISTOFF32NODE pCurNode, PRTLISTOFF32NODE pNewNode) +{ + RTListOff32Prepend(pCurNode, pNewNode); +} + +/** + * Inserts a node before the specified one. + * + * @param pCurNode The current node. + * @param pNewNode The node to insert. + */ +DECLINLINE(void) RTListOff32NodeInsertBefore(PRTLISTOFF32NODE pCurNode, PRTLISTOFF32NODE pNewNode) +{ + RTListOff32Append(pCurNode, pNewNode); +} + +/** + * Remove a node from a list. + * + * @param pNode The node to remove. + */ +DECLINLINE(void) RTListOff32NodeRemove(PRTLISTOFF32NODE pNode) +{ + PRTLISTOFF32NODE pPrev = RTLISTOFF32_PREV_PTR(pNode); + PRTLISTOFF32NODE pNext = RTLISTOFF32_NEXT_PTR(pNode); + + RTLISTOFF32_SET_NEXT_PTR(pPrev, pNext); + RTLISTOFF32_SET_PREV_PTR(pNext, pPrev); + + /* poison */ + pNode->offNext = INT32_MAX / 2; + pNode->offPrev = INT32_MAX / 2; +} + +/** + * Checks if a node is the last element in the list. + * + * @retval true if the node is the last element in the list. + * @retval false otherwise + * + * @param pList The list. + * @param pNode The node to check. + */ +#define RTListOff32NodeIsLast(pList, pNode) (RTLISTOFF32_NEXT_PTR(pNode) == (pList)) + +/** + * Checks if a node is the first element in the list. + * + * @retval true if the node is the first element in the list. + * @retval false otherwise. + * + * @param pList The list. + * @param pNode The node to check. + */ +#define RTListOff32NodeIsFirst(pList, pNode) (RTLISTOFF32_PREV_PTR(pNode) == (pList)) + +/** + * Checks if a type converted node is actually the dummy element (@a pList). + * + * @retval true if the node is the dummy element in the list. + * @retval false otherwise. + * + * @param pList The list. + * @param pNode The node structure to check. Typically + * something obtained from RTListOff32NodeGetNext() + * or RTListOff32NodeGetPrev(). This is NOT a + * PRTLISTOFF32NODE but something that contains a + * RTLISTOFF32NODE member! + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32NodeIsDummy(pList, pNode, Type, Member) \ + ( (pNode) == RT_FROM_MEMBER((pList), Type, Member) ) +/** @copydoc RTListOff32NodeIsDummy */ +#define RTListOff32NodeIsDummyCpp(pList, pNode, Type, Member) \ + ( (pNode) == RT_FROM_CPP_MEMBER((pList), Type, Member) ) + +/** + * Checks if a list is empty. + * + * @retval true if the list is empty. + * @retval false otherwise. + * + * @param pList The list to check. + */ +#define RTListOff32IsEmpty(pList) ((pList)->offNext == 0) + +/** + * Returns the next node in the list. + * + * @returns The next node. + * + * @param pCurNode The current node. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32NodeGetNext(pCurNode, Type, Member) \ + RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(pCurNode), Type, Member) +/** @copydoc RTListOff32NodeGetNext */ +#define RTListOff32NodeGetNextCpp(pCurNode, Type, Member) \ + RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(pCurNode), Type, Member) + +/** + * Returns the previous node in the list. + * + * @returns The previous node. + * + * @param pCurNode The current node. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32NodeGetPrev(pCurNode, Type, Member) \ + RT_FROM_MEMBER(RTLISTOFF32_PREV_PTR(pCurNode), Type, Member) +/** @copydoc RTListOff32NodeGetPrev */ +#define RTListOff32NodeGetPrevCpp(pCurNode, Type, Member) \ + RT_FROM_CPP_MEMBER(RTLISTOFF32_PREV_PTR(pCurNode), Type, Member) + +/** + * Returns the first element in the list (checks for empty list). + * + * @retval Pointer to the first list element. + * @retval NULL if the list is empty. + * + * @param pList List to get the first element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32GetFirst(pList, Type, Member) \ + ((pList)->offNext != 0 ? RTListOff32NodeGetNext(pList, Type, Member) : NULL) +/** @copydoc RTListOff32GetFirst */ +#define RTListOff32GetFirstCpp(pList, Type, Member) \ + ((pList)->offNext != 0 ? RTListOff32NodeGetNextCpp(pList, Type, Member) : NULL) + +/** + * Returns the last element in the list (checks for empty list). + * + * @retval Pointer to the last list element. + * @retval NULL if the list is empty. + * + * @param pList List to get the last element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32GetLast(pList, Type, Member) \ + ((pList)->offPrev != 0 ? RTListOff32NodeGetPrev(pList, Type, Member) : NULL) +/** @copydoc RTListOff32GetLast */ +#define RTListOff32GetLastCpp(pList, Type, Member) \ + ((pList)->offPrev != 0 ? RTListOff32NodeGetPrevCpp(pList, Type, Member) : NULL) + +/** + * Returns the next node in the list or NULL if the end has been reached. + * + * @returns The next node or NULL. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32GetNext(pList, pCurNode, Type, Member) \ + ( RTLISTOFF32_NEXT_PTR(&(pCurNode)->Member) != (pList) \ + ? RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pCurNode)->Member), Type, Member) : NULL ) +/** @copydoc RTListOff32GetNext */ +#define RTListOff32GetNextCpp(pList, pCurNode, Type, Member) \ + ( RTLISTOFF32_NEXT_PTR(&(pCurNode)->Member) != (pList) \ + ? RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pCurNode)->Member), Type, Member) : NULL ) + +/** + * Returns the previous node in the list or NULL if the start has been reached. + * + * @returns The previous node or NULL. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32GetPrev(pList, pCurNode, Type, Member) \ + ( RTLISTOFF32_PREV_PTR(&(pCurNode)->Member) != (pList) \ + ? RT_FROM_MEMBER(RTLISTOFF32_PREV_PTR(&(pCurNode)->Member), Type, Member) : NULL ) +/** @copydoc RTListOff32GetPrev */ +#define RTListOff32GetPrevCpp(pList, pCurNode, Type, Member) \ + ( RTLISTOFF32_PREV_PTR(&(pCurNode)->Member) != (pList) \ + ? RT_FROM_CPP_MEMBER(RTLISTOFF32_PREV_PTR(&(pCurNode)->Member), Type, Member) : NULL ) + +/** + * Enumerate the list in head to tail order. + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListOff32ForEach(pList, pIterator, Type, Member) \ + for (pIterator = RTListOff32NodeGetNext(pList, Type, Member); \ + !RTListOff32NodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) +/** @copydoc RTListOff32ForEach */ +#define RTListOff32ForEachCpp(pList, pIterator, Type, Member) \ + for (pIterator = RTListOff32NodeGetNextCpp(pList, Type, Member); \ + !RTListOff32NodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) + + +/** + * Enumerate the list in head to tail order, safe against removal of the + * current node. + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param pIterNext The name of the variable saving the pointer to + * the next element. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListOff32ForEachSafe(pList, pIterator, pIterNext, Type, Member) \ + for (pIterator = RTListOff32NodeGetNext(pList, Type, Member), \ + pIterNext = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member); \ + !RTListOff32NodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = pIterNext, \ + pIterNext = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) +/** @copydoc RTListOff32ForEachSafe */ +#define RTListOff32ForEachSafeCpp(pList, pIterator, pIterNext, Type, Member) \ + for (pIterator = RTListOff32NodeGetNextCpp(pList, Type, Member), \ + pIterNext = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member); \ + !RTListOff32NodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = pIterNext, \ + pIterNext = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) + + +/** + * Enumerate the list in reverse order (tail to head). + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListOff32ForEachReverse(pList, pIterator, Type, Member) \ + for (pIterator = RTListOff32NodeGetPrev(pList, Type, Member); \ + !RTListOff32NodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) +/** @copydoc RTListOff32ForEachReverse */ +#define RTListOff32ForEachReverseCpp(pList, pIterator, Type, Member) \ + for (pIterator = RTListOff32NodeGetPrevCpp(pList, Type, Member); \ + !RTListOff32NodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_CPP_MEMBER(RTLISTOFF32_PREV_PTR(&(pIterator)->Member), Type, Member) ) + + +/** + * Enumerate the list in reverse order (tail to head). + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param pIterPrev The name of the variable saving the pointer to + * the previous element. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListOff32ForEachReverseSafe(pList, pIterator, pIterPrev, Type, Member) \ + for (pIterator = RTListOff32NodeGetPrev(pList, Type, Member), \ + pIterPrev = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member); \ + !RTListOff32NodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = pIterPrev, \ + pIterPrev = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) +/** @copydoc RTListOff32ForEachReverseSafe */ +#define RTListOff32ForEachReverseSafeCpp(pList, pIterator, pIterPrev, Type, Member) \ + for (pIterator = RTListOff32NodeGetPrevCpp(pList, Type, Member), \ + pIterPrev = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member); \ + !RTListOff32NodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = pIterPrev, \ + pIterPrev = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) + + +/** + * Move the given list to a new list header. + * + * @param pListDst The new list. + * @param pListSrc The list to move. + */ +DECLINLINE(void) RTListOff32Move(PRTLISTOFF32NODE pListDst, PRTLISTOFF32NODE pListSrc) +{ + if (!RTListOff32IsEmpty(pListSrc)) + { + PRTLISTOFF32NODE pFirst = RTLISTOFF32_NEXT_PTR(pListSrc); + PRTLISTOFF32NODE pLast = RTLISTOFF32_PREV_PTR(pListSrc); + + RTLISTOFF32_SET_NEXT_PTR(pListDst, pFirst); + RTLISTOFF32_SET_PREV_PTR(pListDst, pLast); + + /* Adjust the first and last element links */ + RTLISTOFF32_SET_NEXT_PTR(pLast, pListDst); + RTLISTOFF32_SET_PREV_PTR(pFirst, pListDst); + + /* Finally remove the elements from the source list */ + RTListOff32Init(pListSrc); + } +} + +/** + * List concatenation. + * + * @returns nothing. + * @param pListDst The destination list. + * @param pListSrc The source list to concatenate. + */ +DECLINLINE(void) RTListOff32Concatenate(PRTLISTOFF32ANCHOR pListDst, PRTLISTOFF32ANCHOR pListSrc) +{ + if (!RTListOff32IsEmpty(pListSrc)) + { + PRTLISTOFF32NODE pFirstSrc = RTLISTOFF32_NEXT_PTR(pListSrc); + PRTLISTOFF32NODE pLastSrc = RTLISTOFF32_PREV_PTR(pListSrc); + PRTLISTOFF32NODE pLastDst = RTLISTOFF32_PREV_PTR(pListDst); + + RTLISTOFF32_SET_NEXT_PTR(pLastDst, pFirstSrc); + RTLISTOFF32_SET_PREV_PTR(pFirstSrc, pLastDst); + + RTLISTOFF32_SET_NEXT_PTR(pLastSrc, pListDst); + RTLISTOFF32_SET_PREV_PTR(pListDst, pLastSrc); + + /* Finally remove the elements from the source list */ + RTListOff32Init(pListSrc); + } +} + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_list_off32_h */ + diff --git a/include/iprt/list.h b/include/iprt/list.h new file mode 100644 index 00000000..dbc1946f --- /dev/null +++ b/include/iprt/list.h @@ -0,0 +1,560 @@ +/** @file + * IPRT - Generic Doubly Linked List. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_list_h +#define IPRT_INCLUDED_list_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_list RTList - Generic Doubly Linked List + * @ingroup grp_rt + * + * The list implementation is circular without any type wise distintion between + * the list and its nodes. This can be confusing since the list head usually + * resides in a different structure than the nodes, so care must be taken when + * walking the list. + * + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * A list node of a doubly linked list. + */ +typedef struct RTLISTNODE +{ + /** Pointer to the next list node. */ + struct RTLISTNODE *pNext; + /** Pointer to the previous list node. */ + struct RTLISTNODE *pPrev; +} RTLISTNODE; +/** Pointer to a list node. */ +typedef RTLISTNODE *PRTLISTNODE; +/** Pointer to a const list node. */ +typedef RTLISTNODE const *PCRTLISTNODE; +/** Pointer to a list node pointer. */ +typedef PRTLISTNODE *PPRTLISTNODE; + +/** The anchor (head/tail) of a doubly linked list. + * + * @remarks Please use this instead of RTLISTNODE to indicate a list + * head/tail. It makes the code so much easier to read. Also, + * always mention the actual list node type(s) in the comment. */ +typedef RTLISTNODE RTLISTANCHOR; +/** Pointer to a doubly linked list anchor. */ +typedef RTLISTANCHOR *PRTLISTANCHOR; +/** Pointer to a const doubly linked list anchor. */ +typedef RTLISTANCHOR const *PCRTLISTANCHOR; + +/** Version of RTLISTNODE for holding a ring-3 only list in data which gets + * shared between multiple contexts. */ +#ifdef IN_RING3 +typedef RTLISTNODE RTLISTNODER3; +#else +typedef struct { RTR3PTR aOffLimits[2]; } RTLISTNODER3; +#endif +/** Version of RTLISTANCHOR for holding a ring-3 only list in data which gets + * shared between multiple contexts. */ +typedef RTLISTNODER3 RTLISTANCHORR3; + +/** Version of RTLISTNODE for holding a ring-0 only list in data which gets + * shared between multiple contexts. */ +#ifdef IN_RING0 +typedef RTLISTNODE RTLISTNODER0; +#else +typedef struct { RTR0PTR aOffLimits[2]; } RTLISTNODER0; +#endif +/** Version of RTLISTANCHOR for holding a ring-0 only list in data which gets + * shared between multiple contexts. */ +typedef RTLISTNODER0 RTLISTANCHORR0; + + +/** + * Initialize a list. + * + * @param pList Pointer to an unitialised list. + */ +DECLINLINE(void) RTListInit(PRTLISTNODE pList) +{ + pList->pNext = pList; + pList->pPrev = pList; +} + +/** + * Append a node to the end of the list. + * + * @param pList The list to append the node to. + * @param pNode The node to append. + */ +DECLINLINE(void) RTListAppend(PRTLISTNODE pList, PRTLISTNODE pNode) +{ + pList->pPrev->pNext = pNode; + pNode->pPrev = pList->pPrev; + pNode->pNext = pList; + pList->pPrev = pNode; +} + +/** + * Add a node as the first element of the list. + * + * @param pList The list to prepend the node to. + * @param pNode The node to prepend. + */ +DECLINLINE(void) RTListPrepend(PRTLISTNODE pList, PRTLISTNODE pNode) +{ + pList->pNext->pPrev = pNode; + pNode->pNext = pList->pNext; + pNode->pPrev = pList; + pList->pNext = pNode; +} + +/** + * Inserts a node after the specified one. + * + * @param pCurNode The current node. + * @param pNewNode The node to insert. + */ +DECLINLINE(void) RTListNodeInsertAfter(PRTLISTNODE pCurNode, PRTLISTNODE pNewNode) +{ + RTListPrepend(pCurNode, pNewNode); +} + +/** + * Inserts a node before the specified one. + * + * @param pCurNode The current node. + * @param pNewNode The node to insert. + */ +DECLINLINE(void) RTListNodeInsertBefore(PRTLISTNODE pCurNode, PRTLISTNODE pNewNode) +{ + RTListAppend(pCurNode, pNewNode); +} + +/** + * Remove a node from a list. + * + * @param pNode The node to remove. + */ +DECLINLINE(void) RTListNodeRemove(PRTLISTNODE pNode) +{ + PRTLISTNODE pPrev = pNode->pPrev; + PRTLISTNODE pNext = pNode->pNext; + + pPrev->pNext = pNext; + pNext->pPrev = pPrev; + + /* poison */ + pNode->pNext = NULL; + pNode->pPrev = NULL; +} + + +/** + * Remove a node from a list, returns value. + * + * @returns pNode + * @param pNode The node to remove. + */ +DECLINLINE(PRTLISTNODE) RTListNodeRemoveRet(PRTLISTNODE pNode) +{ + PRTLISTNODE pPrev = pNode->pPrev; + PRTLISTNODE pNext = pNode->pNext; + + pPrev->pNext = pNext; + pNext->pPrev = pPrev; + + /* poison */ + pNode->pNext = NULL; + pNode->pPrev = NULL; + + return pNode; +} + +/** + * Checks if a node is the last element in the list. + * + * @retval true if the node is the last element in the list. + * @retval false otherwise + * + * @param pList The list. + * @param pNode The node to check. + */ +#define RTListNodeIsLast(pList, pNode) ((pNode)->pNext == (pList)) + +/** + * Checks if a node is the first element in the list. + * + * @retval true if the node is the first element in the list. + * @retval false otherwise. + * + * @param pList The list. + * @param pNode The node to check. + */ +#define RTListNodeIsFirst(pList, pNode) ((pNode)->pPrev == (pList)) + +/** + * Checks if a type converted node is actually the dummy element (@a pList). + * + * @retval true if the node is the dummy element in the list. + * @retval false otherwise. + * + * @param pList The list. + * @param pNode The node structure to check. Typically + * something obtained from RTListNodeGetNext() or + * RTListNodeGetPrev(). This is NOT a PRTLISTNODE + * but something that contains a RTLISTNODE member! + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListNodeIsDummy(pList, pNode, Type, Member) \ + ( (pNode) == RT_FROM_MEMBER((pList), Type, Member) ) +/** @copydoc RTListNodeIsDummy */ +#define RTListNodeIsDummyCpp(pList, pNode, Type, Member) \ + ( (pNode) == RT_FROM_CPP_MEMBER((pList), Type, Member) ) + +/** + * Checks if a list is empty. + * + * @retval true if the list is empty. + * @retval false otherwise. + * + * @param pList The list to check. + */ +#define RTListIsEmpty(pList) ((pList)->pPrev == (pList)) + +/** + * Returns the next node in the list. + * + * @returns The next node. + * + * @param pCurNode The current node. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListNodeGetNext(pCurNode, Type, Member) \ + RT_FROM_MEMBER((pCurNode)->pNext, Type, Member) +/** @copydoc RTListNodeGetNext */ +#define RTListNodeGetNextCpp(pCurNode, Type, Member) \ + RT_FROM_CPP_MEMBER((pCurNode)->pNext, Type, Member) + +/** + * Returns the previous node in the list. + * + * @returns The previous node. + * + * @param pCurNode The current node. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListNodeGetPrev(pCurNode, Type, Member) \ + RT_FROM_MEMBER((pCurNode)->pPrev, Type, Member) +/** @copydoc RTListNodeGetPrev */ +#define RTListNodeGetPrevCpp(pCurNode, Type, Member) \ + RT_FROM_CPP_MEMBER((pCurNode)->pPrev, Type, Member) + +/** + * Returns the first element in the list (checks for empty list). + * + * @returns Pointer to the first list element, or NULL if empty list. + * + * @param pList List to get the first element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListGetFirst(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RTListNodeGetNext(pList, Type, Member) : NULL) +/** @copydoc RTListGetFirst */ +#define RTListGetFirstCpp(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RTListNodeGetNextCpp(pList, Type, Member) : NULL) + +/** + * Returns the last element in the list (checks for empty list). + * + * @returns Pointer to the last list element, or NULL if empty list. + * + * @param pList List to get the last element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListGetLast(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RTListNodeGetPrev(pList, Type, Member) : NULL) +/** @copydoc RTListGetLast */ +#define RTListGetLastCpp(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RTListNodeGetPrevCpp(pList, Type, Member) : NULL) + +/** + * Returns the next node in the list or NULL if the end has been reached. + * + * @returns The next node, or NULL if end of list. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListGetNext(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER((pCurNode)->Member.pNext, Type, Member) : NULL ) +/** @copydoc RTListGetNext */ +#define RTListGetNextCpp(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER((pCurNode)->Member.pNext, Type, Member) : NULL ) + +/** + * Returns the previous node in the list or NULL if the start has been reached. + * + * @returns The previous node, or NULL if end of list. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListGetPrev(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pPrev != (pList) ? RT_FROM_MEMBER((pCurNode)->Member.pPrev, Type, Member) : NULL ) +/** @copydoc RTListGetPrev */ +#define RTListGetPrevCpp(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pPrev != (pList) ? RT_FROM_CPP_MEMBER((pCurNode)->Member.pPrev, Type, Member) : NULL ) + + +/** + * Removes and returns the first element in the list (checks for empty list). + * + * @returns Pointer to the first list element, or NULL if empty list. + * + * @param pList List to get the first element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListRemoveFirst(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pList)->pNext), Type, Member) : NULL) +/** @copydoc RTListRemoveFirst */ +#define RTListRemoveFirstCpp(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pList)->pNext), Type, Member) : NULL) + +/** + * Removes and returns the last element in the list (checks for empty list). + * + * @returns Pointer to the last list element, or NULL if empty list. + * + * @param pList List to get the last element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListRemoveLast(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pList)->pPrev), Type, Member) : NULL) +/** @copydoc RTListRemoveLast */ +#define RTListRemoveLastCpp(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pList)->pPrev), Type, Member) : NULL) + +/** + * Removes and returns the next node in the list or NULL if the end has been + * reached. + * + * @returns The next node, or NULL if end of list. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListRemoveNext(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pNext), Type, Member) : NULL ) +/** @copydoc RTListRemoveNext */ +#define RTListRemoveNextCpp(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pNext), Type, Member) : NULL ) + +/** + * Removes and returns the previous node in the list or NULL if the start has + * been reached. + * + * @returns The previous node, or NULL if end of list. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListRemovePrev(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pPrev), Type, Member) : NULL ) +/** @copydoc RTListRemovePrev */ +#define RTListRemovePrevCpp(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pPrev), Type, Member) : NULL ) + + +/** + * Enumerate the list in head to tail order. + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListForEach(pList, pIterator, Type, Member) \ + for (pIterator = RTListNodeGetNext(pList, Type, Member); \ + !RTListNodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_MEMBER((pIterator)->Member.pNext, Type, Member) ) +/** @copydoc RTListForEach */ +#define RTListForEachCpp(pList, pIterator, Type, Member) \ + for (pIterator = RTListNodeGetNextCpp(pList, Type, Member); \ + !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_CPP_MEMBER((pIterator)->Member.pNext, Type, Member) ) + + +/** + * Enumerate the list in head to tail order, safe against removal of the + * current node. + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param pIterNext The name of the variable saving the pointer to + * the next element. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListForEachSafe(pList, pIterator, pIterNext, Type, Member) \ + for (pIterator = RTListNodeGetNext(pList, Type, Member), \ + pIterNext = RT_FROM_MEMBER((pIterator)->Member.pNext, Type, Member); \ + !RTListNodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = pIterNext, \ + pIterNext = RT_FROM_MEMBER((pIterator)->Member.pNext, Type, Member) ) +/** @copydoc RTListForEachSafe */ +#define RTListForEachSafeCpp(pList, pIterator, pIterNext, Type, Member) \ + for (pIterator = RTListNodeGetNextCpp(pList, Type, Member), \ + pIterNext = RT_FROM_CPP_MEMBER((pIterator)->Member.pNext, Type, Member); \ + !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = pIterNext, \ + pIterNext = RT_FROM_CPP_MEMBER((pIterator)->Member.pNext, Type, Member) ) + + +/** + * Enumerate the list in reverse order (tail to head). + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListForEachReverse(pList, pIterator, Type, Member) \ + for (pIterator = RTListNodeGetPrev(pList, Type, Member); \ + !RTListNodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_MEMBER((pIterator)->Member.pPrev, Type, Member) ) +/** @copydoc RTListForEachReverse */ +#define RTListForEachReverseCpp(pList, pIterator, Type, Member) \ + for (pIterator = RTListNodeGetPrevCpp(pList, Type, Member); \ + !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_CPP_MEMBER((pIterator)->Member.pPrev, Type, Member) ) + + +/** + * Enumerate the list in reverse order (tail to head). + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param pIterPrev The name of the variable saving the pointer to + * the previous element. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListForEachReverseSafe(pList, pIterator, pIterPrev, Type, Member) \ + for (pIterator = RTListNodeGetPrev(pList, Type, Member), \ + pIterPrev = RT_FROM_MEMBER((pIterator)->Member.pPrev, Type, Member); \ + !RTListNodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = pIterPrev, \ + pIterPrev = RT_FROM_MEMBER((pIterator)->Member.pPrev, Type, Member) ) +/** @copydoc RTListForEachReverseSafe */ +#define RTListForEachReverseSafeCpp(pList, pIterator, pIterPrev, Type, Member) \ + for (pIterator = RTListNodeGetPrevCpp(pList, Type, Member), \ + pIterPrev = RT_FROM_CPP_MEMBER((pIterator)->Member.pPrev, Type, Member); \ + !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = pIterPrev, \ + pIterPrev = RT_FROM_CPP_MEMBER((pIterator)->Member.pPrev, Type, Member) ) + + +/** + * Move the given list to a new list header. + * + * @param pListDst The new list. + * @param pListSrc The list to move. + */ +DECLINLINE(void) RTListMove(PRTLISTNODE pListDst, PRTLISTNODE pListSrc) +{ + if (!RTListIsEmpty(pListSrc)) + { + pListDst->pNext = pListSrc->pNext; + pListDst->pPrev = pListSrc->pPrev; + + /* Adjust the first and last element links */ + pListDst->pNext->pPrev = pListDst; + pListDst->pPrev->pNext = pListDst; + + /* Finally remove the elements from the source list */ + RTListInit(pListSrc); + } + else + RTListInit(pListDst); +} + +/** + * List concatenation. + * + * @returns nothing. + * @param pListDst The destination list. + * @param pListSrc The source list to concatenate. + */ +DECLINLINE(void) RTListConcatenate(PRTLISTANCHOR pListDst, PRTLISTANCHOR pListSrc) +{ + if (!RTListIsEmpty(pListSrc)) + { + PRTLISTNODE pFirst = pListSrc->pNext; + PRTLISTNODE pLast = pListSrc->pPrev; + + pListDst->pPrev->pNext = pFirst; + pFirst->pPrev = pListDst->pPrev; + pLast->pNext = pListDst; + pListDst->pPrev = pLast; + + /* Finally remove the elements from the source list */ + RTListInit(pListSrc); + } +} + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_list_h */ diff --git a/include/iprt/locale.h b/include/iprt/locale.h new file mode 100644 index 00000000..3a83a5f5 --- /dev/null +++ b/include/iprt/locale.h @@ -0,0 +1,113 @@ +/** @file + * IPRT - Locale and Related Info. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_locale_h +#define IPRT_INCLUDED_locale_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_locale RTLocale - Locale and Related Info + * @ingroup grp_rt + * @{ + */ + +/** + * Returns the setlocale(LC_ALL,NULL) return value. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported. + * @param pszName Where to return the name. + * @param cbName The size of the name buffer. + */ +RTDECL(int) RTLocaleQueryLocaleName(char *pszName, size_t cbName); + +/** + * Returns a normalized base locale name ('{ll}_{CC}' or 'C'). + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported. + * @param pszName Where to return the name. + * @param cbName The size of the name buffer. + * + * @sa RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2 + */ +RTDECL(int) RTLocaleQueryNormalizedBaseLocaleName(char *pszName, size_t cbName); + +/** + * Gets the two letter country code (ISO 3166-1 alpha-2) for the current user. + * + * This is not necessarily the country from the locale name, when possible the + * source is a different setting (host specific). + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported. + * @param pszCountryCode Pointer buffer that's at least three bytes in size. + * The country code will be returned here on success. + */ +RTDECL(int) RTLocaleQueryUserCountryCode(char pszCountryCode[3]); + + +/** + * Checks whether @a a_psz seems to start with a + * language-code-underscore-country-code sequence. + * + * We perform a check for a likely ISO 639-1 language code, followed by an + * underscore, followed by a likely ISO 3166-1 alpha-2 country code. + * + * @return true if probable '{ll}_{CC}' sequence, false if surely not. + * @param a_psz The string to test the start of. + * + * @note User must include iprt/ctype.h separately. + */ +#define RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2(a_psz) \ + ( RT_C_IS_LOWER((a_psz)[0]) \ + && RT_C_IS_LOWER((a_psz)[1]) \ + && (a_psz)[2] == '_' \ + && RT_C_IS_UPPER((a_psz)[3]) \ + && RT_C_IS_UPPER((a_psz)[4]) ) + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_locale_h */ + diff --git a/include/iprt/localipc.h b/include/iprt/localipc.h new file mode 100644 index 00000000..e5baa5ab --- /dev/null +++ b/include/iprt/localipc.h @@ -0,0 +1,354 @@ +/** @file + * IPRT - Local IPC Server & Client. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_localipc_h +#define IPRT_INCLUDED_localipc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#ifdef IN_RING0 +# error "There are no RTLocalIpc APIs available Ring-0 Host Context!" +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_localipc RTLocalIpc - Local IPC + * @ingroup grp_rt + * @{ + */ + +/** Handle to a local IPC server instance. */ +typedef struct RTLOCALIPCSERVERINT *RTLOCALIPCSERVER; +/** Pointer to a local IPC server handle. */ +typedef RTLOCALIPCSERVER *PRTLOCALIPCSERVER; +/** Local IPC server handle nil value. */ +#define NIL_RTLOCALIPCSERVER ((RTLOCALIPCSERVER)0) + +/** Handle to a local ICP session instance. */ +typedef struct RTLOCALIPCSESSIONINT *RTLOCALIPCSESSION; +/** Pointer to a local ICP session handle. */ +typedef RTLOCALIPCSESSION *PRTLOCALIPCSESSION; +/** Local ICP session handle nil value. */ +#define NIL_RTLOCALIPCSESSION ((RTLOCALIPCSESSION)0) + + + +/** + * Create a local IPC server. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success and *phServer containing the instance handle. + * + * @param phServer Where to put the server instance handle. + * @param pszName The server name. This must be unique and not include + * any special chars or slashes. It will be morphed into a + * unique platform specific identifier. + * @param fFlags Flags, see RTLOCALIPC_FLAGS_*. + */ +RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszName, uint32_t fFlags); + +/** @name RTLocalIpcServerCreate flags + * @{ */ +/** Native name, as apposed to a portable one. */ +#define RTLOCALIPC_FLAGS_NATIVE_NAME RT_BIT_32(0) +/** The mask of valid flags. */ +#define RTLOCALIPC_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Destroys a local IPC server. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if still other references or NIL. + * @retval VINF_OBJECT_DESTROYED if actually destroyed. + * + * @param hServer The server handle. The nil value is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer); + +/** + * Grant the specified group access to the local IPC server socket. + * + * @returns IPRT status code. + * @param hServer The server handle. + * @param gid Group ID. + */ +RTDECL(int) RTLocalIpcServerGrantGroupAccess(RTLOCALIPCSERVER hServer, RTGID gid); + +/** + * Set access mode for IPC server socket. + * + * @returns IPRT status code. + * @param hServer The server handle. + * @param fMode Access mode. + */ +RTDECL(int) RTLocalIpcServerSetAccessMode(RTLOCALIPCSERVER hServer, RTFMODE fMode); + +/** + * Listen for clients. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success and *phClientSession containing the session handle. + * @retval VERR_CANCELLED if the listening was interrupted by RTLocalIpcServerCancel(). + * + * @param hServer The server handle. + * @param phClientSession Where to store the client session handle on success. + * + */ +RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION phClientSession); + +/** + * Cancel the current or subsequent RTLocalIpcServerListen call. + * + * @returns IPRT status code. + * @param hServer The server handle. The nil value is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer); + + +/** + * Connects to a local IPC server. + * + * This is used a client process (or thread). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success and *phSession holding the session handle. + * + * @param phSession Where to store the sesson handle on success. + * @param pszName The server name (see RTLocalIpcServerCreate for details). + * @param fFlags Flags, RTLOCALIPC_C_FLAGS_XXX. + */ +RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags); + +/** @name RTLOCALIPC_C_FLAGS_XXX - RTLocalIpcSessionConnect flags + * @{ */ +/** Native name, as apposed to a portable one. */ +#define RTLOCALIPC_C_FLAGS_NATIVE_NAME RT_BIT_32(0) +/** The mask of valid flags. */ +#define RTLOCALIPC_C_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Closes the local IPC session. + * + * This can be used with sessions created by both RTLocalIpcSessionConnect + * and RTLocalIpcServerListen. It will release one cancel pending I/O and + * relase one reference (typically the implict reference from the create API). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if still other references or NIL. + * @retval VINF_OBJECT_DESTROYED if session destroyed. + * + * @param hSession The session handle. The nil value is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession); + +/** + * Retain a refence to the given session. + * + * @returns New reference count, UINT32_MAX if the handle is invalid. + * @param hSession The session handle. + */ +RTDECL(uint32_t) RTLocalIpcSessionRetain(RTLOCALIPCSESSION hSession); + +/** + * Releases a refence to the given session. + * + * This differs from RTLocalIpcSessionClose in that it won't cancel any pending + * I/O. So, better call RTLocalIpcSessionClose if you want to terminate the + * session. + * + * @returns New reference count, 0 if NIL handle, UINT32_MAX if the handle is + * invalid. + * @param hSession The session handle. + */ +RTDECL(uint32_t) RTLocalIpcSessionRelease(RTLOCALIPCSESSION hSession); + + +/** + * Receive data from the other end of an local IPC session. + * + * This will block if there isn't any data. + * + * @returns IPRT status code. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * + * @param hSession The session handle. + * @param pvBuf Where to store the data. + * @param cbToRead How much to read. This is exact request if + * pcbRead is NULL, otherwise it's an upper limit. + * @param pcbRead Optional argument for indicating a partial read + * and returning the number of bytes actually read. + */ +RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Receive pending data from the other end of an local IPC session. + * + * This will not block to wait for data. + * + * @returns IPRT status code. + * @retval VINF_TRY_AGAIN if no pending data (*pcbRead is set to 0). + * @retval VERR_CANCELLED if a previous operation was cancelled by + * RTLocalIpcSessionCancel (this operation isn't cancellable). + * + * @param hSession The session handle. + * @param pvBuf Where to store the data. + * @param cbToRead How much to read (upper limit). + * @param pcbRead Where to return exactly how much was read. + */ +RTDECL(int) RTLocalIpcSessionReadNB(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Send data to the other end of an local IPC session. + * + * This may or may not block until the data is received by the other party, + * this is an implementation detail. If you want to make sure that the data + * has been received you should always call RTLocalIpcSessionFlush(). + * + * @returns IPRT status code. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * + * @param hSession The session handle. + * @param pvBuf The data to write. + * @param cbToWrite How much to write. + */ +RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuf, size_t cbToWrite); + +/** + * Flush any buffered data and (perhaps) wait for the other party to receive it. + * + * The waiting for the other party to receive the data is + * implementation dependent. + * + * @returns IPRT status code. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * + * @param hSession The session handle. + */ +RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession); + +/** + * Wait for data to become ready for reading or for the session to be + * disconnected. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS when there is data to read. + * @retval VERR_TIMEOUT if no data became available within the specified period (@a cMillies) + * @retval VERR_BROKEN_PIPE if the session was disconnected. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * + * @param hSession The session handle. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT + * to wait forever. + * + * @remark VERR_INTERRUPTED will not be returned. If this is desired at some later point + * add a RTLocalIpcSessionWaitForDataNoResume() variant like we're using elsewhere. + */ +RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies); + +/** + * Cancells a pending or subsequent operation. + * + * Not all methods are cancellable, only those which are specfied + * returning VERR_CANCELLED. The others are assumed to not be blocking + * for ever and ever. However, the cancel is sticky, so the session must + * basically be trashed (closed) after calling this method. + * + * @returns IPRT status code. + * + * @param hSession The session handle. + */ +RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession); + +/** + * Query the process ID of the other party. + * + * This is an optional feature which may not be implemented, so don't + * depend on it and check for VERR_NOT_SUPPORTED. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pProcess on success. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * @retval VERR_NOT_SUPPORTED and *pProcess = NIL_RTPROCESS if not supported. + * + * @param hSession The session handle. + * @param pProcess Where to store the process ID. + */ +RTDECL(int) RTLocalIpcSessionQueryProcess(RTLOCALIPCSESSION hSession, PRTPROCESS pProcess); + +/** + * Query the user ID of the other party. + * + * This is an optional feature which may not be implemented, so don't + * depend on it and check for VERR_NOT_SUPPORTED. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pUid on success. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * @retval VERR_NOT_SUPPORTED and *pUid = NIL_RTUID if not supported. + * + * @param hSession The session handle. + * @param pUid Where to store the user ID on success. + */ +RTDECL(int) RTLocalIpcSessionQueryUserId(RTLOCALIPCSESSION hSession, PRTUID pUid); + +/** + * Query the group ID of the other party. + * + * This is an optional feature which may not be implemented, so don't + * depend on it and check for VERR_NOT_SUPPORTED. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pUid on success. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * @retval VERR_NOT_SUPPORTED and *pGid = NIL_RTUID if not supported. + * + * @param hSession The session handle. + * @param pGid Where to store the group ID on success. + */ +RTDECL(int) RTLocalIpcSessionQueryGroupId(RTLOCALIPCSESSION hSession, PRTGID pGid); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_localipc_h */ + diff --git a/include/iprt/lockvalidator.h b/include/iprt/lockvalidator.h new file mode 100644 index 00000000..829ed9f2 --- /dev/null +++ b/include/iprt/lockvalidator.h @@ -0,0 +1,1143 @@ +/** @file + * IPRT - Lock Validator. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_lockvalidator_h +#define IPRT_INCLUDED_lockvalidator_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + + +/** @defgroup grp_rtlockval RTLockValidator - Lock Validator + * @ingroup grp_rt + * @{ + */ + +RT_C_DECLS_BEGIN + +/** Pointer to a record union. + * @internal */ +typedef union RTLOCKVALRECUNION *PRTLOCKVALRECUNION; + +/** + * Source position. + */ +typedef struct RTLOCKVALSRCPOS +{ + /** The file where the lock was taken. */ + R3R0PTRTYPE(const char * volatile) pszFile; + /** The function where the lock was taken. */ + R3R0PTRTYPE(const char * volatile) pszFunction; + /** Some ID indicating where the lock was taken, typically an address. */ + RTHCUINTPTR volatile uId; + /** The line number in the file. */ + uint32_t volatile uLine; +#if HC_ARCH_BITS == 64 + uint32_t u32Padding; /**< Alignment padding. */ +#endif +} RTLOCKVALSRCPOS; +AssertCompileSize(RTLOCKVALSRCPOS, HC_ARCH_BITS == 32 ? 16 : 32); +/* The pointer types are defined in iprt/types.h. */ + +/** @def RTLOCKVALSRCPOS_INIT + * Initializer for a RTLOCKVALSRCPOS variable. + * + * @param pszFile The file name. Optional (NULL). + * @param uLine The line number in that file. Optional (0). + * @param pszFunction The function. Optional (NULL). + * @param uId Some location ID, normally the return address. + * Optional (NULL). + */ +#if HC_ARCH_BITS == 64 +# define RTLOCKVALSRCPOS_INIT(pszFile, uLine, pszFunction, uId) \ + { (pszFile), (pszFunction), (uId), (uLine), 0 } +#else +# define RTLOCKVALSRCPOS_INIT(pszFile, uLine, pszFunction, uId) \ + { (pszFile), (pszFunction), (uId), (uLine) } +#endif + +/** @def RTLOCKVALSRCPOS_INIT_DEBUG_API + * Initializer for a RTLOCKVALSRCPOS variable in a typicial debug API + * variant. Assumes RT_SRC_POS_DECL and RTHCUINTPTR uId as arguments. + */ +#define RTLOCKVALSRCPOS_INIT_DEBUG_API() \ + RTLOCKVALSRCPOS_INIT(pszFile, iLine, pszFunction, uId) + +/** @def RTLOCKVALSRCPOS_INIT_NORMAL_API + * Initializer for a RTLOCKVALSRCPOS variable in a normal API + * variant. Assumes iprt/asm.h is included. + */ +#define RTLOCKVALSRCPOS_INIT_NORMAL_API() \ + RTLOCKVALSRCPOS_INIT(__FILE__, __LINE__, __PRETTY_FUNCTION__, (uintptr_t)ASMReturnAddress()) + +/** @def RTLOCKVALSRCPOS_INIT_POS_NO_ID + * Initializer for a RTLOCKVALSRCPOS variable when no @c uId is present. + * Assumes iprt/asm.h is included. + */ +#define RTLOCKVALSRCPOS_INIT_POS_NO_ID() \ + RTLOCKVALSRCPOS_INIT(pszFile, iLine, pszFunction, (uintptr_t)ASMReturnAddress()) + + +/** + * Lock validator record core. + */ +typedef struct RTLOCKVALRECORE +{ + /** The magic value indicating the record type. */ + uint32_t volatile u32Magic; +} RTLOCKVALRECCORE; +/** Pointer to a lock validator record core. */ +typedef RTLOCKVALRECCORE *PRTLOCKVALRECCORE; +/** Pointer to a const lock validator record core. */ +typedef RTLOCKVALRECCORE const *PCRTLOCKVALRECCORE; + + +/** + * Record recording the exclusive ownership of a lock. + * + * This is typically part of the per-lock data structure when compiling with + * the lock validator. + */ +typedef struct RTLOCKVALRECEXCL +{ + /** Record core with RTLOCKVALRECEXCL_MAGIC as the magic value. */ + RTLOCKVALRECCORE Core; + /** Whether it's enabled or not. */ + bool fEnabled; + /** Reserved. */ + bool afReserved[3]; + /** Source position where the lock was taken. */ + RTLOCKVALSRCPOS SrcPos; + /** The current owner thread. */ + RTTHREAD volatile hThread; + /** Pointer to the lock record below us. Only accessed by the owner. */ + R3R0PTRTYPE(PRTLOCKVALRECUNION) pDown; + /** Recursion count */ + uint32_t cRecursion; + /** The lock sub-class. */ + uint32_t volatile uSubClass; + /** The lock class. */ + RTLOCKVALCLASS hClass; + /** Pointer to the lock. */ + RTHCPTR hLock; + /** Pointer to the next sibling record. + * This is used to find the read side of a read-write lock. */ + R3R0PTRTYPE(PRTLOCKVALRECUNION) pSibling; + /** The lock name. + * @remarks The bytes beyond 32 are for better size alignment and can be + * taken and used for other purposes if it becomes necessary. */ + char szName[32 + (HC_ARCH_BITS == 32 ? 12 : 8)]; +} RTLOCKVALRECEXCL; +AssertCompileSize(RTLOCKVALRECEXCL, HC_ARCH_BITS == 32 ? 0x60 : 0x80); +/* The pointer type is defined in iprt/types.h. */ + +/** + * For recording the one ownership share. + */ +typedef struct RTLOCKVALRECSHRDOWN +{ + /** Record core with RTLOCKVALRECSHRDOWN_MAGIC as the magic value. */ + RTLOCKVALRECCORE Core; + /** Recursion count */ + uint16_t cRecursion; + /** Static (true) or dynamic (false) allocated record. */ + bool fStaticAlloc; + /** Reserved. */ + bool fReserved; + /** The current owner thread. */ + RTTHREAD volatile hThread; + /** Pointer to the lock record below us. Only accessed by the owner. */ + R3R0PTRTYPE(PRTLOCKVALRECUNION) pDown; + /** Pointer back to the shared record. */ + R3R0PTRTYPE(PRTLOCKVALRECSHRD) pSharedRec; +#if HC_ARCH_BITS == 32 + /** Reserved. */ + RTHCPTR pvReserved; +#endif + /** Source position where the lock was taken. */ + RTLOCKVALSRCPOS SrcPos; +} RTLOCKVALRECSHRDOWN; +AssertCompileSize(RTLOCKVALRECSHRDOWN, HC_ARCH_BITS == 32 ? 24 + 16 : 32 + 32); +/** Pointer to a RTLOCKVALRECSHRDOWN. */ +typedef RTLOCKVALRECSHRDOWN *PRTLOCKVALRECSHRDOWN; + +/** + * Record recording the shared ownership of a lock. + * + * This is typically part of the per-lock data structure when compiling with + * the lock validator. + */ +typedef struct RTLOCKVALRECSHRD +{ + /** Record core with RTLOCKVALRECSHRD_MAGIC as the magic value. */ + RTLOCKVALRECCORE Core; + /** The lock sub-class. */ + uint32_t volatile uSubClass; + /** The lock class. */ + RTLOCKVALCLASS hClass; + /** Pointer to the lock. */ + RTHCPTR hLock; + /** Pointer to the next sibling record. + * This is used to find the write side of a read-write lock. */ + R3R0PTRTYPE(PRTLOCKVALRECUNION) pSibling; + + /** The number of entries in the table. + * Updated before inserting and after removal. */ + uint32_t volatile cEntries; + /** The index of the last entry (approximately). */ + uint32_t volatile iLastEntry; + /** The max table size. */ + uint32_t volatile cAllocated; + /** Set if the table is being reallocated, clear if not. + * This is used together with rtLockValidatorSerializeDetectionEnter to make + * sure there is exactly one thread doing the reallocation and that nobody is + * using the table at that point. */ + bool volatile fReallocating; + /** Whether it's enabled or not. */ + bool fEnabled; + /** Set if event semaphore signaller, clear if read-write semaphore. */ + bool fSignaller; + /** Alignment padding. */ + bool fPadding; + /** Pointer to a table containing pointers to records of all the owners. */ + R3R0PTRTYPE(PRTLOCKVALRECSHRDOWN volatile *) papOwners; + + /** The lock name. + * @remarks The bytes beyond 32 are for better size alignment and can be + * taken and used for other purposes if it becomes necessary. */ + char szName[32 + (HC_ARCH_BITS == 32 ? 8 : 8)]; +} RTLOCKVALRECSHRD; +AssertCompileSize(RTLOCKVALRECSHRD, HC_ARCH_BITS == 32 ? 0x50 : 0x60); + + +/** + * Makes the two records siblings. + * + * @returns VINF_SUCCESS on success, VERR_SEM_LV_INVALID_PARAMETER if either of + * the records are invalid. + * @param pRec1 Record 1. + * @param pRec2 Record 2. + */ +RTDECL(int) RTLockValidatorRecMakeSiblings(PRTLOCKVALRECCORE pRec1, PRTLOCKVALRECCORE pRec2); + +/** + * Initialize a lock validator record. + * + * Use RTLockValidatorRecExclDelete to deinitialize it. + * + * @param pRec The record. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(void) RTLockValidatorRecExclInit(PRTLOCKVALRECEXCL pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, void *hLock, + bool fEnabled, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 7); +/** + * Initialize a lock validator record. + * + * Use RTLockValidatorRecExclDelete to deinitialize it. + * + * @param pRec The record. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param va Format string arguments. + */ +RTDECL(void) RTLockValidatorRecExclInitV(PRTLOCKVALRECEXCL pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, void *hLock, + bool fEnabled, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 0); +/** + * Uninitialize a lock validator record previously initialized by + * RTLockRecValidatorInit. + * + * @param pRec The record. Must be valid. + */ +RTDECL(void) RTLockValidatorRecExclDelete(PRTLOCKVALRECEXCL pRec); + +/** + * Create and initialize a lock validator record. + * + * Use RTLockValidatorRecExclDestroy to deinitialize and destroy the returned + * record. + * + * @return VINF_SUCCESS or VERR_NO_MEMORY. + * @param ppRec Where to return the record pointer. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTLockValidatorRecExclCreate(PRTLOCKVALRECEXCL *ppRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, void *hLock, + bool fEnabled, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 7); + +/** + * Create and initialize a lock validator record. + * + * Use RTLockValidatorRecExclDestroy to deinitialize and destroy the returned + * record. + * + * @return VINF_SUCCESS or VERR_NO_MEMORY. + * @param ppRec Where to return the record pointer. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param va Format string arguments. + */ +RTDECL(int) RTLockValidatorRecExclCreateV(PRTLOCKVALRECEXCL *ppRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, void *hLock, + bool fEnabled, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 0); + +/** + * Deinitialize and destroy a record created by RTLockValidatorRecExclCreate. + * + * @param ppRec Pointer to the record pointer. Will be set to + * NULL. + */ +RTDECL(void) RTLockValidatorRecExclDestroy(PRTLOCKVALRECEXCL *ppRec); + +/** + * Sets the sub-class of the record. + * + * It is recommended to try make sure that nobody is using this class while + * changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param pRec The validator record. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTLockValidatorRecExclSetSubClass(PRTLOCKVALRECEXCL pRec, uint32_t uSubClass); + +/** + * Record the specified thread as lock owner and increment the write lock count. + * + * This function is typically called after acquiring the lock. It accounts for + * recursions so it can be used instead of RTLockValidatorRecExclRecursion. Use + * RTLockValidatorRecExclReleaseOwner to reverse the effect. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. If not known, + * pass NIL_RTTHREAD and we'll figure it out. + * @param pSrcPos The source position of the lock operation. + * @param fFirstRecursion Set if it is the first recursion, clear if not + * sure. + */ +RTDECL(void) RTLockValidatorRecExclSetOwner(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fFirstRecursion); + +/** + * Check the exit order and release (unset) the ownership. + * + * This is called by routines implementing releasing an exclusive lock, + * typically before getting down to the final lock releasing. Can be used for + * recursive releasing instead of RTLockValidatorRecExclUnwind. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_RELEASE_ORDER if the order is wrong. Will have + * done all necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param fFinalRecursion Set if it's the final recursion, clear if not + * sure. + */ +RTDECL(int) RTLockValidatorRecExclReleaseOwner(PRTLOCKVALRECEXCL pRec, bool fFinalRecursion); + +/** + * Clear the lock ownership and decrement the write lock count. + * + * This is only for special cases where we wish to drop lock validation + * recording. See RTLockValidatorRecExclCheckAndRelease. + * + * @param pRec The validator record. + */ +RTDECL(void) RTLockValidatorRecExclReleaseOwnerUnchecked(PRTLOCKVALRECEXCL pRec); + +/** + * Checks and records a lock recursion. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_NESTED if the semaphore class forbids recursion. Gone + * thru the motions. + * @retval VERR_SEM_LV_WRONG_ORDER if the locking order is wrong. Gone thru + * the motions. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param pSrcPos The source position of the lock operation. + */ +RTDECL(int) RTLockValidatorRecExclRecursion(PRTLOCKVALRECEXCL pRec, PCRTLOCKVALSRCPOS pSrcPos); + +/** + * Checks and records a lock unwind (releasing one recursion). + * + * This should be coupled with called to RTLockValidatorRecExclRecursion. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_RELEASE_ORDER if the release order is wrong. Gone + * thru the motions. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + */ +RTDECL(int) RTLockValidatorRecExclUnwind(PRTLOCKVALRECEXCL pRec); + +/** + * Checks and records a mixed recursion. + * + * An example of a mixed recursion is a writer requesting read access to a + * SemRW. + * + * This should be coupled with called to RTLockValidatorRecExclUnwindMixed. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_NESTED if the semaphore class forbids recursion. Gone + * thru the motions. + * @retval VERR_SEM_LV_WRONG_ORDER if the locking order is wrong. Gone thru + * the motions. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record it to accounted it to. + * @param pRecMixed The validator record it came in on. + * @param pSrcPos The source position of the lock operation. + */ +RTDECL(int) RTLockValidatorRecExclRecursionMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed, PCRTLOCKVALSRCPOS pSrcPos); + +/** + * Checks and records the unwinding of a mixed recursion. + * + * This should be coupled with called to RTLockValidatorRecExclRecursionMixed. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_RELEASE_ORDER if the release order is wrong. Gone + * thru the motions. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record it was accounted to. + * @param pRecMixed The validator record it came in on. + */ +RTDECL(int) RTLockValidatorRecExclUnwindMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed); + +/** + * Check the exclusive locking order. + * + * This is called by routines implementing exclusive lock acquisition. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_ORDER if the order is wrong. Will have done all + * necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. If not known, + * pass NIL_RTTHREAD and we'll figure it out. + * @param pSrcPos The source position of the lock operation. + * @param cMillies The timeout, in milliseconds. + */ +RTDECL(int) RTLockValidatorRecExclCheckOrder(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, RTMSINTERVAL cMillies); + +/** + * Do deadlock detection before blocking on exclusive access to a lock and + * change the thread state. + * + * @retval VINF_SUCCESS - thread is in the specified sleep state. + * @retval VERR_SEM_LV_DEADLOCK if blocking would deadlock. Gone thru the + * motions. + * @retval VERR_SEM_LV_NESTED if the semaphore isn't recursive and hThread is + * already the owner. Gone thru the motions. + * @retval VERR_SEM_LV_ILLEGAL_UPGRADE if it's a deadlock on the same lock. + * The caller must handle any legal upgrades without invoking this + * function (for now). + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record we're blocking on. + * @param hThreadSelf The current thread. Shall not be NIL_RTTHREAD! + * @param pSrcPos The source position of the lock operation. + * @param fRecursiveOk Whether it's ok to recurse. + * @param cMillies The timeout, in milliseconds. + * @param enmSleepState The sleep state to enter on successful return. + * @param fReallySleeping Is it really going to sleep now or not. Use + * false before calls to other IPRT synchronization + * methods. + */ +RTDECL(int) RTLockValidatorRecExclCheckBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies, + RTTHREADSTATE enmSleepState, bool fReallySleeping); + +/** + * RTLockValidatorRecExclCheckOrder and RTLockValidatorRecExclCheckBlocking + * baked into one call. + * + * @returns Any of the statuses returned by the two APIs. + * @param pRec The validator record. + * @param hThreadSelf The current thread. Shall not be NIL_RTTHREAD! + * @param pSrcPos The source position of the lock operation. + * @param fRecursiveOk Whether it's ok to recurse. + * @param cMillies The timeout, in milliseconds. + * @param enmSleepState The sleep state to enter on successful return. + * @param fReallySleeping Is it really going to sleep now or not. Use + * false before calls to other IPRT synchronization + * methods. + */ +RTDECL(int) RTLockValidatorRecExclCheckOrderAndBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies, + RTTHREADSTATE enmSleepState, bool fReallySleeping); + +/** + * Initialize a lock validator record for a shared lock. + * + * Use RTLockValidatorRecSharedDelete to deinitialize it. + * + * @param pRec The shared lock record. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fSignaller Set if event semaphore signaller logic should be + * applied to this record, clear if read-write + * semaphore logic should be used. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, + void *hLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(7, 8); + +/** + * Initialize a lock validator record for a shared lock. + * + * Use RTLockValidatorRecSharedDelete to deinitialize it. + * + * @param pRec The shared lock record. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fSignaller Set if event semaphore signaller logic should be + * applied to this record, clear if read-write + * semaphore logic should be used. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param va Format string arguments. + */ +RTDECL(void) RTLockValidatorRecSharedInitV(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, + void *hLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(7, 0); + +/** + * Uninitialize a lock validator record previously initialized by + * RTLockValidatorRecSharedInit. + * + * @param pRec The shared lock record. Must be valid. + */ +RTDECL(void) RTLockValidatorRecSharedDelete(PRTLOCKVALRECSHRD pRec); + +/** + * Create and initialize a lock validator record for a shared lock. + * + * Use RTLockValidatorRecSharedDestroy to deinitialize and destroy the returned + * record. + * + * @returns IPRT status code. + * @param ppRec Where to return the record pointer. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param pvLock The lock handle or address. + * @param fSignaller Set if event semaphore signaller logic should be + * applied to this record, clear if read-write + * semaphore logic should be used. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTLockValidatorRecSharedCreate(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, + void *pvLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(7, 8); + +/** + * Create and initialize a lock validator record for a shared lock. + * + * Use RTLockValidatorRecSharedDestroy to deinitialize and destroy the returned + * record. + * + * @returns IPRT status code. + * @param ppRec Where to return the record pointer. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param pvLock The lock handle or address. + * @param fSignaller Set if event semaphore signaller logic should be + * applied to this record, clear if read-write + * semaphore logic should be used. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param va Format string arguments. + */ +RTDECL(int) RTLockValidatorRecSharedCreateV(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, + void *pvLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(7, 0); + +/** + * Deinitialize and destroy a record created by RTLockValidatorRecSharedCreate. + * + * @param ppRec Pointer to the record pointer. Will be set to + * NULL. + */ +RTDECL(void) RTLockValidatorRecSharedDestroy(PRTLOCKVALRECSHRD *ppRec); + +/** + * Sets the sub-class of the record. + * + * It is recommended to try make sure that nobody is using this class while + * changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param pRec The validator record. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTLockValidatorRecSharedSetSubClass(PRTLOCKVALRECSHRD pRec, uint32_t uSubClass); + +/** + * Check the shared locking order. + * + * This is called by routines implementing shared lock acquisition. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_ORDER if the order is wrong. Will have done all + * necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. If not known, + * pass NIL_RTTHREAD and we'll figure it out. + * @param pSrcPos The source position of the lock operation. + * @param cMillies Intended sleep time in milliseconds. + */ +RTDECL(int) RTLockValidatorRecSharedCheckOrder(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, RTMSINTERVAL cMillies); + +/** + * Do deadlock detection before blocking on shared access to a lock and change + * the thread state. + * + * @retval VINF_SUCCESS - thread is in the specified sleep state. + * @retval VERR_SEM_LV_DEADLOCK if blocking would deadlock. Gone thru the + * motions. + * @retval VERR_SEM_LV_NESTED if the semaphore isn't recursive and hThread is + * already the owner. Gone thru the motions. + * @retval VERR_SEM_LV_ILLEGAL_UPGRADE if it's a deadlock on the same lock. + * The caller must handle any legal upgrades without invoking this + * function (for now). + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record we're blocking on. + * @param hThreadSelf The current thread. Shall not be NIL_RTTHREAD! + * @param pSrcPos The source position of the lock operation. + * @param fRecursiveOk Whether it's ok to recurse. + * @param cMillies Intended sleep time in milliseconds. + * @param enmSleepState The sleep state to enter on successful return. + * @param fReallySleeping Is it really going to sleep now or not. Use + * false before calls to other IPRT synchronization + * methods. + */ +RTDECL(int) RTLockValidatorRecSharedCheckBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies, + RTTHREADSTATE enmSleepState, bool fReallySleeping); + +/** + * RTLockValidatorRecSharedCheckOrder and RTLockValidatorRecSharedCheckBlocking + * baked into one call. + * + * @returns Any of the statuses returned by the two APIs. + * @param pRec The validator record. + * @param hThreadSelf The current thread. Shall not be NIL_RTTHREAD! + * @param pSrcPos The source position of the lock operation. + * @param fRecursiveOk Whether it's ok to recurse. + * @param cMillies Intended sleep time in milliseconds. + * @param enmSleepState The sleep state to enter on successful return. + * @param fReallySleeping Is it really going to sleep now or not. Use + * false before calls to other IPRT synchronization + * methods. + */ +RTDECL(int) RTLockValidatorRecSharedCheckOrderAndBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies, + RTTHREADSTATE enmSleepState, bool fReallySleeping); + +/** + * Removes all current owners and makes hThread the only owner. + * + * @param pRec The validator record. + * @param hThread The thread handle of the owner. NIL_RTTHREAD is + * an alias for the current thread. + * @param pSrcPos The source position of the lock operation. + */ +RTDECL(void) RTLockValidatorRecSharedResetOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos); + +/** + * Adds an owner to a shared locking record. + * + * Takes recursion into account. This function is typically called after + * acquiring the lock in shared mode. + * + * @param pRec The validator record. + * @param hThread The thread handle of the owner. NIL_RTTHREAD is + * an alias for the current thread. + * @param pSrcPos The source position of the lock operation. + */ +RTDECL(void) RTLockValidatorRecSharedAddOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos); + +/** + * Removes an owner from a shared locking record. + * + * Takes recursion into account. This function is typically called before + * releasing the lock. + * + * @param pRec The validator record. + * @param hThread The thread handle of the owner. NIL_RTTHREAD is + * an alias for the current thread. + */ +RTDECL(void) RTLockValidatorRecSharedRemoveOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread); + +/** + * Checks if the specified thread is one of the owners. + * + * @returns true if it is, false if not. + * + * @param pRec The validator record. + * @param hThread The thread handle of the owner. NIL_RTTHREAD is + * an alias for the current thread. + */ +RTDECL(bool) RTLockValidatorRecSharedIsOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread); + +/** + * Check the exit order and release (unset) the shared ownership. + * + * This is called by routines implementing releasing the read/write lock. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_RELEASE_ORDER if the order is wrong. Will have + * done all necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. NIL_RTTHREAD + * is an alias for the current thread. + */ +RTDECL(int) RTLockValidatorRecSharedCheckAndRelease(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf); + +/** + * Check the signaller of an event. + * + * This is called by routines implementing releasing the event semaphore (both + * kinds). + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_NOT_SIGNALLER if the thread is not in the record. Will + * have done all necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. NIL_RTTHREAD + * is an alias for the current thread. + */ +RTDECL(int) RTLockValidatorRecSharedCheckSignaller(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf); + +/** + * Gets the number of write locks and critical sections the specified + * thread owns. + * + * This number does not include any nested lock/critect entries. + * + * Note that it probably will return 0 for non-strict builds since + * release builds doesn't do unnecessary diagnostic counting like this. + * + * @returns Number of locks on success (0+) and VERR_INVALID_HANDLER on failure + * @param Thread The thread we're inquiring about. + * @remarks Will only work for strict builds. + */ +RTDECL(int32_t) RTLockValidatorWriteLockGetCount(RTTHREAD Thread); + +/** + * Works the THREADINT::cWriteLocks member, mostly internal. + * + * @param Thread The current thread. + */ +RTDECL(void) RTLockValidatorWriteLockInc(RTTHREAD Thread); + +/** + * Works the THREADINT::cWriteLocks member, mostly internal. + * + * @param Thread The current thread. + */ +RTDECL(void) RTLockValidatorWriteLockDec(RTTHREAD Thread); + +/** + * Gets the number of read locks the specified thread owns. + * + * Note that nesting read lock entry will be included in the + * total sum. And that it probably will return 0 for non-strict + * builds since release builds doesn't do unnecessary diagnostic + * counting like this. + * + * @returns Number of read locks on success (0+) and VERR_INVALID_HANDLER on failure + * @param Thread The thread we're inquiring about. + */ +RTDECL(int32_t) RTLockValidatorReadLockGetCount(RTTHREAD Thread); + +/** + * Works the THREADINT::cReadLocks member. + * + * @param Thread The current thread. + */ +RTDECL(void) RTLockValidatorReadLockInc(RTTHREAD Thread); + +/** + * Works the THREADINT::cReadLocks member. + * + * @param Thread The current thread. + */ +RTDECL(void) RTLockValidatorReadLockDec(RTTHREAD Thread); + +/** + * Query which lock the specified thread is waiting on. + * + * @returns The lock handle value or NULL. + * @param hThread The thread in question. + */ +RTDECL(void *) RTLockValidatorQueryBlocking(RTTHREAD hThread); + +/** + * Checks if the thread is running in the lock validator after it has entered a + * block state. + * + * @returns true if it is, false if it isn't. + * @param hThread The thread in question. + */ +RTDECL(bool) RTLockValidatorIsBlockedThreadInValidator(RTTHREAD hThread); + +/** + * Checks if the calling thread is holding a lock in the specified class. + * + * @returns true if it holds a lock in the specific class, false if it + * doesn't. + * + * @param hCurrentThread The current thread. Pass NIL_RTTHREAD if you're + * lazy. + * @param hClass The class. + */ +RTDECL(bool) RTLockValidatorHoldsLocksInClass(RTTHREAD hCurrentThread, RTLOCKVALCLASS hClass); + +/** + * Checks if the calling thread is holding a lock in the specified sub-class. + * + * @returns true if it holds a lock in the specific sub-class, false if it + * doesn't. + * + * @param hCurrentThread The current thread. Pass NIL_RTTHREAD if you're + * lazy. + * @param hClass The class. + * @param uSubClass The new sub-class value. + */ +RTDECL(bool) RTLockValidatorHoldsLocksInSubClass(RTTHREAD hCurrentThread, RTLOCKVALCLASS hClass, uint32_t uSubClass); + + + +/** + * Creates a new lock validator class, all properties specified. + * + * @returns IPRT status code + * @param phClass Where to return the class handle. + * @param pSrcPos The source position of the create call. + * @param fAutodidact Whether the class should be allowed to teach + * itself new locking order rules (true), or if the + * user will teach it all it needs to know (false). + * @param fRecursionOk Whether to allow lock recursion or not. + * @param fStrictReleaseOrder Enforce strict lock release order or not. + * @param cMsMinDeadlock Used to raise the sleep interval at which + * deadlock detection kicks in. Minimum is 1 ms, + * while RT_INDEFINITE_WAIT will disable it. + * @param cMsMinOrder Used to raise the sleep interval at which lock + * order validation kicks in. Minimum is 1 ms, + * while RT_INDEFINITE_WAIT will disable it. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param ... Format string arguments. + * + * @remarks The properties can be modified after creation by the + * RTLockValidatorClassSet* methods. + */ +RTDECL(int) RTLockValidatorClassCreateEx(PRTLOCKVALCLASS phClass, PCRTLOCKVALSRCPOS pSrcPos, + bool fAutodidact, bool fRecursionOk, bool fStrictReleaseOrder, + RTMSINTERVAL cMsMinDeadlock, RTMSINTERVAL cMsMinOrder, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(8, 9); + +/** + * Creates a new lock validator class, all properties specified. + * + * @returns IPRT status code + * @param phClass Where to return the class handle. + * @param pSrcPos The source position of the create call. + * @param fAutodidact Whether the class should be allowed to teach + * itself new locking order rules (true), or if the + * user will teach it all it needs to know (false). + * @param fRecursionOk Whether to allow lock recursion or not. + * @param fStrictReleaseOrder Enforce strict lock release order or not. + * @param cMsMinDeadlock Used to raise the sleep interval at which + * deadlock detection kicks in. Minimum is 1 ms, + * while RT_INDEFINITE_WAIT will disable it. + * @param cMsMinOrder Used to raise the sleep interval at which lock + * order validation kicks in. Minimum is 1 ms, + * while RT_INDEFINITE_WAIT will disable it. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param va Format string arguments. + * + * @remarks The properties can be modified after creation by the + * RTLockValidatorClassSet* methods. + */ +RTDECL(int) RTLockValidatorClassCreateExV(PRTLOCKVALCLASS phClass, PCRTLOCKVALSRCPOS pSrcPos, + bool fAutodidact, bool fRecursionOk, bool fStrictReleaseOrder, + RTMSINTERVAL cMsMinDeadlock, RTMSINTERVAL cMsMinOrder, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(8, 0); + +/** + * Creates a new lock validator class. + * + * @returns IPRT status code + * @param phClass Where to return the class handle. + * @param fAutodidact Whether the class should be allowed to teach + * itself new locking order rules (true), or if the + * user will teach it all it needs to know (false). + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTLockValidatorClassCreate(PRTLOCKVALCLASS phClass, bool fAutodidact, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 7); + +/** + * Creates a new lock validator class with a reference that is consumed by the + * first call to RTLockValidatorClassRetain. + * + * This is tailored for use in the parameter list of a semaphore constructor. + * + * @returns Class handle with a reference that is automatically consumed by the + * first retainer. NIL_RTLOCKVALCLASS if we run into trouble. + * + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(RTLOCKVALCLASS) RTLockValidatorClassCreateUnique(RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5); + +/** + * Finds a class for the specified source position. + * + * @returns A handle to the class (not retained!) or NIL_RTLOCKVALCLASS. + * @param pSrcPos The source position. + */ +RTDECL(RTLOCKVALCLASS) RTLockValidatorClassFindForSrcPos(PRTLOCKVALSRCPOS pSrcPos); + +/** + * Finds or creates a class given the source position. + * + * @returns Class handle (not retained!) or NIL_RTLOCKVALCLASS. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(RTLOCKVALCLASS) RTLockValidatorClassForSrcPos(RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5); + +/** + * Retains a reference to a lock validator class. + * + * @returns New reference count; UINT32_MAX if the handle is invalid. + * @param hClass Handle to the class. + */ +RTDECL(uint32_t) RTLockValidatorClassRetain(RTLOCKVALCLASS hClass); + +/** + * Releases a reference to a lock validator class. + * + * @returns New reference count. 0 if hClass is NIL_RTLOCKVALCLASS. UINT32_MAX + * if the handle is invalid. + * @param hClass Handle to the class. + */ +RTDECL(uint32_t) RTLockValidatorClassRelease(RTLOCKVALCLASS hClass); + +/** + * Teaches the class @a hClass that locks in the class @a hPriorClass can be + * held when taking a lock of class @a hClass + * + * @returns IPRT status. + * @param hClass Handle to the pupil class. + * @param hPriorClass Handle to the class that can be held prior to + * taking a lock in the pupil class. (No reference + * is consumed.) + */ +RTDECL(int) RTLockValidatorClassAddPriorClass(RTLOCKVALCLASS hClass, RTLOCKVALCLASS hPriorClass); + +/** + * Enables or disables the strict release order enforcing. + * + * @returns IPRT status. + * @param hClass Handle to the class to change. + * @param fEnabled Enable it (true) or disable it (false). + */ +RTDECL(int) RTLockValidatorClassEnforceStrictReleaseOrder(RTLOCKVALCLASS hClass, bool fEnabled); + +/** + * Enables / disables the lock validator for new locks. + * + * @returns The old setting. + * @param fEnabled The new setting. + */ +RTDECL(bool) RTLockValidatorSetEnabled(bool fEnabled); + +/** + * Is the lock validator enabled? + * + * @returns True if enabled, false if not. + */ +RTDECL(bool) RTLockValidatorIsEnabled(void); + +/** + * Controls whether the lock validator should be quiet or noisy (default). + * + * @returns The old setting. + * @param fQuiet The new setting. + */ +RTDECL(bool) RTLockValidatorSetQuiet(bool fQuiet); + +/** + * Is the lock validator quiet or noisy? + * + * @returns True if it is quiet, false if noisy. + */ +RTDECL(bool) RTLockValidatorIsQuiet(void); + +/** + * Makes the lock validator panic (default) or not. + * + * @returns The old setting. + * @param fPanic The new setting. + */ +RTDECL(bool) RTLockValidatorSetMayPanic(bool fPanic); + +/** + * Can the lock validator cause panic. + * + * @returns True if it can, false if not. + */ +RTDECL(bool) RTLockValidatorMayPanic(void); + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_lockvalidator_h */ + diff --git a/include/iprt/log.h b/include/iprt/log.h new file mode 100644 index 00000000..fd677b71 --- /dev/null +++ b/include/iprt/log.h @@ -0,0 +1,2869 @@ +/** @file + * IPRT - Logging. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_log_h +#define IPRT_INCLUDED_log_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_log RTLog - Logging + * @ingroup grp_rt + * @{ + */ + +/** + * IPRT Logging Groups. + * (Remember to update RT_LOGGROUP_NAMES!) + * + * @remark It should be pretty obvious, but just to have + * mentioned it, the values are sorted alphabetically (using the + * english alphabet) except for _DEFAULT which is always first. + * + * If anyone might be wondering what the alphabet looks like: + * a b c d e f g h i j k l m n o p q r s t u v w x y z + */ +typedef enum RTLOGGROUP +{ + /** Default logging group. */ + RTLOGGROUP_DEFAULT, + RTLOGGROUP_CRYPTO, + RTLOGGROUP_DBG, + RTLOGGROUP_DBG_DWARF, + RTLOGGROUP_DIR, + RTLOGGROUP_FILE, + RTLOGGROUP_FS, + RTLOGGROUP_FTP, + RTLOGGROUP_HTTP, + RTLOGGROUP_IOQUEUE, + RTLOGGROUP_LDR, + RTLOGGROUP_LOCALIPC, + RTLOGGROUP_PATH, + RTLOGGROUP_PROCESS, + RTLOGGROUP_REST, + RTLOGGROUP_SYMLINK, + RTLOGGROUP_THREAD, + RTLOGGROUP_TIME, + RTLOGGROUP_TIMER, + RTLOGGROUP_VFS, + RTLOGGROUP_ZIP = 31, + RTLOGGROUP_FIRST_USER = 32 +} RTLOGGROUP; + +/** @def RT_LOGGROUP_NAMES + * IPRT Logging group names. + * + * Must correspond 100% to RTLOGGROUP! + * Don't forget commas! + * + * @remark It should be pretty obvious, but just to have + * mentioned it, the values are sorted alphabetically (using the + * english alphabet) except for _DEFAULT which is always first. + * + * If anyone might be wondering what the alphabet looks like: + * a b c d e f g h i j k l m n o p q r s t u v w x y z + * + * The RT_XX log group names are placeholders for new modules being added, + * to make sure that there always is a total of 32 log group entries. + */ +#define RT_LOGGROUP_NAMES \ + "DEFAULT", \ + "RT_CRYPTO", \ + "RT_DBG", \ + "RT_DBG_DWARF", \ + "RT_DIR", \ + "RT_FILE", \ + "RT_FS", \ + "RT_FTP", \ + "RT_HTTP", \ + "RT_IOQUEUE", \ + "RT_LDR", \ + "RT_LOCALIPC", \ + "RT_PATH", \ + "RT_PROCESS", \ + "RT_REST", \ + "RT_SYMLINK", \ + "RT_THREAD", \ + "RT_TIME", \ + "RT_TIMER", \ + "RT_VFS", \ + "RT_20", \ + "RT_21", \ + "RT_22", \ + "RT_23", \ + "RT_24", \ + "RT_25", \ + "RT_26", \ + "RT_27", \ + "RT_28", \ + "RT_29", \ + "RT_30", \ + "RT_ZIP" + + +/** @def LOG_GROUP + * Active logging group. + */ +#ifndef LOG_GROUP +# define LOG_GROUP RTLOGGROUP_DEFAULT +#endif + +/** @def LOG_FN_FMT + * You can use this to specify your desired way of printing __PRETTY_FUNCTION__ + * if you dislike the default one. + */ +#ifndef LOG_FN_FMT +# define LOG_FN_FMT "%Rfn" +#endif + +#ifdef LOG_INSTANCE +# error "LOG_INSTANCE is no longer supported." +#endif +#ifdef LOG_REL_INSTANCE +# error "LOG_REL_INSTANCE is no longer supported." +#endif + +/** Logger structure. */ +typedef struct RTLOGGER RTLOGGER; +/** Pointer to logger structure. */ +typedef RTLOGGER *PRTLOGGER; +/** Pointer to const logger structure. */ +typedef const RTLOGGER *PCRTLOGGER; + + +/** Pointer to a log buffer descriptor. */ +typedef struct RTLOGBUFFERDESC *PRTLOGBUFFERDESC; + + +/** + * Logger phase. + * + * Used for signalling the log header/footer callback what to do. + */ +typedef enum RTLOGPHASE +{ + /** Begin of the logging. */ + RTLOGPHASE_BEGIN = 0, + /** End of the logging. */ + RTLOGPHASE_END, + /** Before rotating the log file. */ + RTLOGPHASE_PREROTATE, + /** After rotating the log file. */ + RTLOGPHASE_POSTROTATE, + /** 32-bit type blow up hack. */ + RTLOGPHASE_32BIT_HACK = 0x7fffffff +} RTLOGPHASE; + + +#if 0 /* retired */ +/** + * Logger function. + * + * @param pszFormat Format string. + * @param ... Optional arguments as specified in the format string. + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGGER,(const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(1, 2); +/** Pointer to logger function. */ +typedef FNRTLOGGER *PFNRTLOGGER; +#endif + +/** + * Custom buffer flushing function. + * + * @retval true if flushed and the buffer can be reused. + * @retval false for switching to the next buffer because an async flush of + * @a pBufDesc is still pending. The implementation is responsible for + * only returning when the next buffer is ready for reuse, the generic + * logger code has no facility to make sure of this. + * + * @param pLogger Pointer to the logger instance which is to be flushed. + * @param pBufDesc The descriptor of the buffer to be flushed. + */ +typedef DECLCALLBACKTYPE(bool, FNRTLOGFLUSH,(PRTLOGGER pLogger, PRTLOGBUFFERDESC pBufDesc)); +/** Pointer to flush function. */ +typedef FNRTLOGFLUSH *PFNRTLOGFLUSH; + +/** + * Header/footer message callback. + * + * @param pLogger Pointer to the logger instance. + * @param pszFormat Format string. + * @param ... Optional arguments specified in the format string. + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGPHASEMSG,(PRTLOGGER pLogger, const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(2, 3); +/** Pointer to header/footer message callback function. */ +typedef FNRTLOGPHASEMSG *PFNRTLOGPHASEMSG; + +/** + * Log file header/footer callback. + * + * @param pLogger Pointer to the logger instance. + * @param enmLogPhase Indicates at what time the callback is invoked. + * @param pfnLogPhaseMsg Callback for writing the header/footer (RTLogPrintf + * and others are out of bounds). + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGPHASE,(PRTLOGGER pLogger, RTLOGPHASE enmLogPhase, PFNRTLOGPHASEMSG pfnLogPhaseMsg)); +/** Pointer to log header/footer callback function. */ +typedef FNRTLOGPHASE *PFNRTLOGPHASE; + +/** + * Custom log prefix callback. + * + * + * @returns The number of chars written. + * + * @param pLogger Pointer to the logger instance. + * @param pchBuf Output buffer pointer. + * No need to terminate the output. + * @param cchBuf The size of the output buffer. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTLOGPREFIX,(PRTLOGGER pLogger, char *pchBuf, size_t cchBuf, void *pvUser)); +/** Pointer to prefix callback function. */ +typedef FNRTLOGPREFIX *PFNRTLOGPREFIX; + + +/** Pointer to a constant log output interface. */ +typedef const struct RTLOGOUTPUTIF *PCRTLOGOUTPUTIF; + +/** + * Logging output interface. + */ +typedef struct RTLOGOUTPUTIF +{ + /** + * Opens a new log file with the given name. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pszFilename The filename to open. + * @param fFlags Open flags, combination of RTFILE_O_XXX. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (PCRTLOGOUTPUTIF pIf, void *pvUser, const char *pszFilename, uint32_t fFlags)); + + /** + * Closes the currently open file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (PCRTLOGOUTPUTIF pIf, void *pvUser)); + + /** + * Deletes the given file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pszFilename The filename to delete. + */ + DECLR3CALLBACKMEMBER(int, pfnDelete, (PCRTLOGOUTPUTIF pIf, void *pvUser, const char *pszFilename)); + + /** + * Renames the given file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pszFilenameOld The old filename to rename. + * @param pszFilenameNew The new filename. + * @param fFlags Flags for the operation, combination of RTFILEMOVE_FLAGS_XXX. + */ + DECLR3CALLBACKMEMBER(int, pfnRename, (PCRTLOGOUTPUTIF pIf, void *pvUser, const char *pszFilenameOld, + const char *pszFilenameNew, uint32_t fFlags)); + + /** + * Queries the size of the log file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pcbFile Where to store the file size in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQuerySize, (PCRTLOGOUTPUTIF pIf, void *pvUser, uint64_t *pcbSize)); + + /** + * Writes data to the log file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pvBuf The data to write. + * @param cbWrite Number of bytes to write. + * @param pcbWritten Where to store the actual number of bytes written on success. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite, (PCRTLOGOUTPUTIF pIf, void *pvUser, const void *pvBuf, + size_t cbWrite, size_t *pcbWritten)); + + /** + * Flushes data to the underlying storage medium. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (PCRTLOGOUTPUTIF pIf, void *pvUser)); +} RTLOGOUTPUTIF; +/** Pointer to a logging output interface. */ +typedef struct RTLOGOUTPUTIF *PRTLOGOUTPUTIF; + + +/** + * Auxiliary buffer descriptor. + * + * This is what we share we ring-3 and use for flushing ring-0 EMT loggers when + * we return to ring-3. + */ +typedef struct RTLOGBUFFERAUXDESC +{ + /** Flush indicator. + * Ring-3 sets this if it flushed the buffer, ring-0 clears it again after + * writing. */ + bool volatile fFlushedIndicator; + bool afPadding[3]; + /** Copy of RTLOGBUFFERDESC::offBuf. */ + uint32_t offBuf; +} RTLOGBUFFERAUXDESC; +/** Pointer to auxiliary buffer descriptor. */ +typedef RTLOGBUFFERAUXDESC *PRTLOGBUFFERAUXDESC; + +/** + * Log buffer desciptor. + */ +typedef struct RTLOGBUFFERDESC +{ + /** Magic value / eye catcher (RTLOGBUFFERDESC_MAGIC). */ + uint32_t u32Magic; + /** Padding. */ + uint32_t uReserved; + /** The buffer size. */ + uint32_t cbBuf; + /** The current buffer offset. */ + uint32_t offBuf; + /** Pointer to the buffer. */ + char *pchBuf; + /** Pointer to auxiliary desciptor, NULL if not used. */ + PRTLOGBUFFERAUXDESC pAux; +} RTLOGBUFFERDESC; + +/** RTLOGBUFFERDESC::u32Magic value. (Avram Noam Chomsky) */ +#define RTLOGBUFFERDESC_MAGIC UINT32_C(0x19281207) + +/** + * The public logger instance part. + * + * The logger instance is mostly abstract and kept as RTLOGGERINTERNAL within + * log.cpp. This public part is at the start of RTLOGGERINTERNAL. + */ +struct RTLOGGER +{ + /** Magic number (RTLOGGER_MAGIC). */ + uint32_t u32Magic; + /** User value \#1, initialized to zero. */ + uint32_t u32UserValue1; + /** User value \#2, initialized to zero. */ + uint64_t u64UserValue2; + /** User value \#3, initialized to zero. */ + uint64_t u64UserValue3; +#if 0 + /** Pointer to the logger function (used in non-C99 mode only). + * + * This is actually pointer to a wrapper/stub function which will push a pointer + * to the instance pointer onto the stack before jumping to the real logger + * function. A very unfortunate hack to work around the missing variadic macro + * support in older C++/C standards. (The memory is allocated using + * RTMemExecAlloc(), except for agnostic R0 code.) */ + PFNRTLOGGER pfnLogger; +#else + /** Unused. */ + uintptr_t uUsedToBeNonC99Logger; +#endif +#if ARCH_BITS == 32 + /** Explicit padding. */ + uint32_t uReserved1; +#endif +}; + +/** RTLOGGER::u32Magic value. (John Rogers Searle) */ +#define RTLOGGER_MAGIC UINT32_C(0x19320731) + +/** + * Logger flags. + */ +typedef enum RTLOGFLAGS +{ + /** The logger instance is disabled for normal output. */ + RTLOGFLAGS_DISABLED = 0x00000001, + /** The logger instance is using buffered output. */ + RTLOGFLAGS_BUFFERED = 0x00000002, + /** The logger instance expands LF to CR/LF. */ + RTLOGFLAGS_USECRLF = 0x00000010, + /** Append to the log destination where applicable. */ + RTLOGFLAGS_APPEND = 0x00000020, + /** Show relative timestamps with PREFIX_TSC and PREFIX_TS */ + RTLOGFLAGS_REL_TS = 0x00000040, + /** Show decimal timestamps with PREFIX_TSC and PREFIX_TS */ + RTLOGFLAGS_DECIMAL_TS = 0x00000080, + /** Open the file in write through mode. */ + RTLOGFLAGS_WRITE_THROUGH = 0x00000100, + /** Flush the file to disk when flushing the buffer. */ + RTLOGFLAGS_FLUSH = 0x00000200, + /** Restrict the number of log entries per group. */ + RTLOGFLAGS_RESTRICT_GROUPS = 0x00000400, + /** New lines should be prefixed with the write and read lock counts. */ + RTLOGFLAGS_PREFIX_LOCK_COUNTS = 0x00008000, + /** New lines should be prefixed with the CPU id (ApicID on intel/amd). */ + RTLOGFLAGS_PREFIX_CPUID = 0x00010000, + /** New lines should be prefixed with the native process id. */ + RTLOGFLAGS_PREFIX_PID = 0x00020000, + /** New lines should be prefixed with group flag number causing the output. */ + RTLOGFLAGS_PREFIX_FLAG_NO = 0x00040000, + /** New lines should be prefixed with group flag name causing the output. */ + RTLOGFLAGS_PREFIX_FLAG = 0x00080000, + /** New lines should be prefixed with group number. */ + RTLOGFLAGS_PREFIX_GROUP_NO = 0x00100000, + /** New lines should be prefixed with group name. */ + RTLOGFLAGS_PREFIX_GROUP = 0x00200000, + /** New lines should be prefixed with the native thread id. */ + RTLOGFLAGS_PREFIX_TID = 0x00400000, + /** New lines should be prefixed with thread name. */ + RTLOGFLAGS_PREFIX_THREAD = 0x00800000, + /** New lines should be prefixed with data from a custom callback. */ + RTLOGFLAGS_PREFIX_CUSTOM = 0x01000000, + /** New lines should be prefixed with formatted timestamp since program start. */ + RTLOGFLAGS_PREFIX_TIME_PROG = 0x04000000, + /** New lines should be prefixed with formatted timestamp (UCT). */ + RTLOGFLAGS_PREFIX_TIME = 0x08000000, + /** New lines should be prefixed with milliseconds since program start. */ + RTLOGFLAGS_PREFIX_MS_PROG = 0x10000000, + /** New lines should be prefixed with timestamp. */ + RTLOGFLAGS_PREFIX_TSC = 0x20000000, + /** New lines should be prefixed with timestamp. */ + RTLOGFLAGS_PREFIX_TS = 0x40000000, + /** The prefix mask. */ + RTLOGFLAGS_PREFIX_MASK = 0x7dff8000 +} RTLOGFLAGS; +/** Don't use locking. */ +#define RTLOG_F_NO_LOCKING RT_BIT_64(63) +/** Mask with all valid log flags (for validation). */ +#define RTLOG_F_VALID_MASK UINT64_C(0x800000007fff87f3) + +/** + * Logger per group flags. + * + * @remarks We only use the lower 16 bits here. We'll be combining it with the + * group number in a few places. + */ +typedef enum RTLOGGRPFLAGS +{ + /** Enabled. */ + RTLOGGRPFLAGS_ENABLED = 0x0001, + /** Flow logging. */ + RTLOGGRPFLAGS_FLOW = 0x0002, + /** Warnings logging. */ + RTLOGGRPFLAGS_WARN = 0x0004, + /* 0x0008 for later. */ + /** Level 1 logging. */ + RTLOGGRPFLAGS_LEVEL_1 = 0x0010, + /** Level 2 logging. */ + RTLOGGRPFLAGS_LEVEL_2 = 0x0020, + /** Level 3 logging. */ + RTLOGGRPFLAGS_LEVEL_3 = 0x0040, + /** Level 4 logging. */ + RTLOGGRPFLAGS_LEVEL_4 = 0x0080, + /** Level 5 logging. */ + RTLOGGRPFLAGS_LEVEL_5 = 0x0100, + /** Level 6 logging. */ + RTLOGGRPFLAGS_LEVEL_6 = 0x0200, + /** Level 7 logging. */ + RTLOGGRPFLAGS_LEVEL_7 = 0x0400, + /** Level 8 logging. */ + RTLOGGRPFLAGS_LEVEL_8 = 0x0800, + /** Level 9 logging. */ + RTLOGGRPFLAGS_LEVEL_9 = 0x1000, + /** Level 10 logging. */ + RTLOGGRPFLAGS_LEVEL_10 = 0x2000, + /** Level 11 logging. */ + RTLOGGRPFLAGS_LEVEL_11 = 0x4000, + /** Level 12 logging. */ + RTLOGGRPFLAGS_LEVEL_12 = 0x8000, + + /** Restrict the number of log entries. */ + RTLOGGRPFLAGS_RESTRICT = 0x40000000, + /** Blow up the type. */ + RTLOGGRPFLAGS_32BIT_HACK = 0x7fffffff +} RTLOGGRPFLAGS; + +/** + * Logger destination types and flags. + */ +typedef enum RTLOGDEST +{ + /** Log to file. */ + RTLOGDEST_FILE = 0x00000001, + /** Log to stdout. */ + RTLOGDEST_STDOUT = 0x00000002, + /** Log to stderr. */ + RTLOGDEST_STDERR = 0x00000004, + /** Log to debugger (win32 only). */ + RTLOGDEST_DEBUGGER = 0x00000008, + /** Log to com port. */ + RTLOGDEST_COM = 0x00000010, + /** Log a memory ring buffer. */ + RTLOGDEST_RINGBUF = 0x00000020, + /** The parent VMM debug log. */ + RTLOGDEST_VMM = 0x00000040, + /** The parent VMM release log. */ + RTLOGDEST_VMM_REL = 0x00000080, + /** Open files with no deny (share read, write, delete) on Windows. */ + RTLOGDEST_F_NO_DENY = 0x00010000, + /** Delay opening the log file, logging to the buffer untill + * RTLogClearFileDelayFlag is called. */ + RTLOGDEST_F_DELAY_FILE = 0x00020000, + /** Don't allow changes to the filename or mode of opening it. */ + RTLOGDEST_FIXED_FILE = 0x01000000, + /** Don't allow changing the directory. */ + RTLOGDEST_FIXED_DIR = 0x02000000, + /** Just a dummy flag to be used when no other flag applies. */ + RTLOGDEST_DUMMY = 0x20000000, + /** Log to a user defined output stream. */ + RTLOGDEST_USER = 0x40000000 +} RTLOGDEST; +/** Valid log destinations. */ +#define RTLOG_DST_VALID_MASK UINT32_C(0x630300ff) +/** Log destinations that can be changed via RTLogChangeDestinations. */ +#define RTLOG_DST_CHANGE_MASK UINT32_C(0x400000de) + + +#ifdef DOXYGEN_RUNNING +# define LOG_DISABLED +# define LOG_ENABLED +# define LOG_ENABLE_FLOW +#endif + +/** @def LOG_DISABLED + * Use this compile time define to disable all logging macros. It can + * be overridden for each of the logging macros by the LOG_ENABLE* + * compile time defines. + */ + +/** @def LOG_ENABLED + * Use this compile time define to enable logging when not in debug mode + * or LOG_DISABLED is set. + * This will enable Log() only. + */ + +/** @def LOG_ENABLE_FLOW + * Use this compile time define to enable flow logging when not in + * debug mode or LOG_DISABLED is defined. + * This will enable LogFlow() only. + */ + +/* + * Determine whether logging is enabled and forcefully normalize the indicators. + */ +#if (defined(DEBUG) || defined(LOG_ENABLED)) && !defined(LOG_DISABLED) +# undef LOG_DISABLED +# undef LOG_ENABLED +# define LOG_ENABLED +#else +# undef LOG_ENABLED +# undef LOG_DISABLED +# define LOG_DISABLED +#endif + + +/** @def LOG_USE_C99 + * Governs the use of variadic macros. + */ +#ifndef LOG_USE_C99 +# define LOG_USE_C99 +#endif + + +/** @name Macros for checking whether a log level is enabled. + * @{ */ +/** @def LogIsItEnabled + * Checks whether the specified logging group is enabled or not. + */ +#ifdef LOG_ENABLED +# define LogIsItEnabled(a_fFlags, a_iGroup) ( RTLogDefaultInstanceEx(RT_MAKE_U32(a_fFlags, a_iGroup)) != NULL ) +#else +# define LogIsItEnabled(a_fFlags, a_iGroup) (false) +#endif + +/** @def LogIsEnabled + * Checks whether level 1 logging is enabled. + */ +#define LogIsEnabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP) + +/** @def LogIs2Enabled + * Checks whether level 2 logging is enabled. + */ +#define LogIs2Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP) + +/** @def LogIs3Enabled + * Checks whether level 3 logging is enabled. + */ +#define LogIs3Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP) + +/** @def LogIs4Enabled + * Checks whether level 4 logging is enabled. + */ +#define LogIs4Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP) + +/** @def LogIs5Enabled + * Checks whether level 5 logging is enabled. + */ +#define LogIs5Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP) + +/** @def LogIs6Enabled + * Checks whether level 6 logging is enabled. + */ +#define LogIs6Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP) + +/** @def LogIs7Enabled + * Checks whether level 7 logging is enabled. + */ +#define LogIs7Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP) + +/** @def LogIs8Enabled + * Checks whether level 8 logging is enabled. + */ +#define LogIs8Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP) + +/** @def LogIs9Enabled + * Checks whether level 9 logging is enabled. + */ +#define LogIs9Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP) + +/** @def LogIs10Enabled + * Checks whether level 10 logging is enabled. + */ +#define LogIs10Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP) + +/** @def LogIs11Enabled + * Checks whether level 11 logging is enabled. + */ +#define LogIs11Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP) + +/** @def LogIs12Enabled + * Checks whether level 12 logging is enabled. + */ +#define LogIs12Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP) + +/** @def LogIsFlowEnabled + * Checks whether execution flow logging is enabled. + */ +#define LogIsFlowEnabled() LogIsItEnabled(RTLOGGRPFLAGS_FLOW, LOG_GROUP) + +/** @def LogIsWarnEnabled + * Checks whether execution flow logging is enabled. + */ +#define LogIsWarnEnabled() LogIsItEnabled(RTLOGGRPFLAGS_WARN, LOG_GROUP) +/** @} */ + + +/** @def LogIt + * Write to specific logger if group enabled. + */ +#ifdef LOG_ENABLED +# if defined(LOG_USE_C99) +# define _LogRemoveParentheseis(...) __VA_ARGS__ +# define _LogIt(a_fFlags, a_iGroup, ...) \ + do \ + { \ + PRTLOGGER LogIt_pLogger = RTLogDefaultInstanceEx(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (RT_LIKELY(!LogIt_pLogger)) \ + { /* likely */ } \ + else \ + RTLogLoggerEx(LogIt_pLogger, a_fFlags, a_iGroup, __VA_ARGS__); \ + } while (0) +# define LogIt(a_fFlags, a_iGroup, fmtargs) _LogIt(a_fFlags, a_iGroup, _LogRemoveParentheseis fmtargs) +# define _LogItAlways(a_fFlags, a_iGroup, ...) RTLogLoggerEx(NULL, a_fFlags, UINT32_MAX, __VA_ARGS__) +# define LogItAlways(a_fFlags, a_iGroup, fmtargs) _LogItAlways(a_fFlags, a_iGroup, _LogRemoveParentheseis fmtargs) + /** @todo invent a flag or something for skipping the group check so we can pass iGroup. LogItAlways. */ +# else +# define LogIt(a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogIt_pLogger = RTLogDefaultInstanceEx(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (RT_LIKELY(!LogIt_pLogger)) \ + { /* likely */ } \ + else \ + { \ + LogIt_pLogger->pfnLogger fmtargs; \ + } \ + } while (0) +# define LogItAlways(a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogIt_pLogger = RTLogDefaultInstanceEx(RT_MAKE_U32(0, UINT16_MAX)); \ + if (LogIt_pLogger) \ + LogIt_pLogger->pfnLogger fmtargs; \ + } while (0) +# endif +#else +# define LogIt(a_fFlags, a_iGroup, fmtargs) do { } while (0) +# define LogItAlways(a_fFlags, a_iGroup, fmtargs) do { } while (0) +# if defined(LOG_USE_C99) +# define _LogRemoveParentheseis(...) __VA_ARGS__ +# define _LogIt(a_fFlags, a_iGroup, ...) do { } while (0) +# define _LogItAlways(a_fFlags, a_iGroup, ...) do { } while (0) +# endif +#endif + + +/** @name Basic logging macros + * @{ */ +/** @def Log + * Level 1 logging that works regardless of the group settings. + */ +#define LogAlways(a) LogItAlways(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, a) + +/** @def Log + * Level 1 logging. + */ +#define Log(a) LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, a) + +/** @def Log2 + * Level 2 logging. + */ +#define Log2(a) LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, a) + +/** @def Log3 + * Level 3 logging. + */ +#define Log3(a) LogIt(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, a) + +/** @def Log4 + * Level 4 logging. + */ +#define Log4(a) LogIt(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, a) + +/** @def Log5 + * Level 5 logging. + */ +#define Log5(a) LogIt(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, a) + +/** @def Log6 + * Level 6 logging. + */ +#define Log6(a) LogIt(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, a) + +/** @def Log7 + * Level 7 logging. + */ +#define Log7(a) LogIt(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, a) + +/** @def Log8 + * Level 8 logging. + */ +#define Log8(a) LogIt(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, a) + +/** @def Log9 + * Level 9 logging. + */ +#define Log9(a) LogIt(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, a) + +/** @def Log10 + * Level 10 logging. + */ +#define Log10(a) LogIt(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, a) + +/** @def Log11 + * Level 11 logging. + */ +#define Log11(a) LogIt(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, a) + +/** @def Log12 + * Level 12 logging. + */ +#define Log12(a) LogIt(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, a) + +/** @def LogFlow + * Logging of execution flow. + */ +#define LogFlow(a) LogIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, a) + +/** @def LogWarn + * Logging of warnings. + */ +#define LogWarn(a) LogIt(RTLOGGRPFLAGS_WARN, LOG_GROUP, a) +/** @} */ + + +/** @name Logging macros prefixing the current function name. + * @{ */ +/** @def LogFunc + * Level 1 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define LogFunc(a) _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogFunc(a) do { Log((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log(a); } while (0) +#endif + +/** @def Log2Func + * Level 2 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log2Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log2Func(a) do { Log2((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log2(a); } while (0) +#endif + +/** @def Log3Func + * Level 3 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log3Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log3Func(a) do { Log3((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log3(a); } while (0) +#endif + +/** @def Log4Func + * Level 4 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log4Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log4Func(a) do { Log4((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log4(a); } while (0) +#endif + +/** @def Log5Func + * Level 5 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log5Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log5Func(a) do { Log5((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log5(a); } while (0) +#endif + +/** @def Log6Func + * Level 6 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log6Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log6Func(a) do { Log6((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log6(a); } while (0) +#endif + +/** @def Log7Func + * Level 7 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log7Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log7Func(a) do { Log7((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log7(a); } while (0) +#endif + +/** @def Log8Func + * Level 8 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log8Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log8Func(a) do { Log8((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log8(a); } while (0) +#endif + +/** @def Log9Func + * Level 9 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log9Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log9Func(a) do { Log9((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log9(a); } while (0) +#endif + +/** @def Log10Func + * Level 10 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log10Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log10Func(a) do { Log10((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log10(a); } while (0) +#endif + +/** @def Log11Func + * Level 11 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log11Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log11Func(a) do { Log11((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log11(a); } while (0) +#endif + +/** @def Log12Func + * Level 12 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log12Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log12Func(a) do { Log12((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log12(a); } while (0) +#endif + +/** @def LogFlowFunc + * Macro to log the execution flow inside C/C++ functions. + * + * Prepends the given log message with the function name followed by + * a semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define LogFlowFunc(a) \ + _LogIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogFlowFunc(a) \ + do { LogFlow((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogFlow(a); } while (0) +#endif + +/** @def LogWarnFunc + * Macro to log a warning inside C/C++ functions. + * + * Prepends the given log message with the function name followed by + * a semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define LogWarnFunc(a) \ + _LogIt(RTLOGGRPFLAGS_WARN, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogWarnFunc(a) \ + do { LogFlow((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogFlow(a); } while (0) +#endif +/** @} */ + + +/** @name Logging macros prefixing the this pointer value and method name. + * @{ */ + +/** @def LogThisFunc + * Level 1 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define LogThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogThisFunc(a) do { Log(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log(a); } while (0) +#endif + +/** @def Log2ThisFunc + * Level 2 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log2ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log2ThisFunc(a) do { Log2(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log2(a); } while (0) +#endif + +/** @def Log3ThisFunc + * Level 3 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log3ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log3ThisFunc(a) do { Log3(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log3(a); } while (0) +#endif + +/** @def Log4ThisFunc + * Level 4 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log4ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log4ThisFunc(a) do { Log4(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log4(a); } while (0) +#endif + +/** @def Log5ThisFunc + * Level 5 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log5ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log5ThisFunc(a) do { Log5(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log5(a); } while (0) +#endif + +/** @def Log6ThisFunc + * Level 6 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log6ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log6ThisFunc(a) do { Log6(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log6(a); } while (0) +#endif + +/** @def Log7ThisFunc + * Level 7 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log7ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log7ThisFunc(a) do { Log7(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log7(a); } while (0) +#endif + +/** @def Log8ThisFunc + * Level 8 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log8ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log8ThisFunc(a) do { Log8(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log8(a); } while (0) +#endif + +/** @def Log9ThisFunc + * Level 9 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log9ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log9ThisFunc(a) do { Log9(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log9(a); } while (0) +#endif + +/** @def Log10ThisFunc + * Level 10 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log10ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log10ThisFunc(a) do { Log10(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log10(a); } while (0) +#endif + +/** @def Log11ThisFunc + * Level 11 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log11ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log11ThisFunc(a) do { Log11(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log11(a); } while (0) +#endif + +/** @def Log12ThisFunc + * Level 12 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log12ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log12ThisFunc(a) do { Log12(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log12(a); } while (0) +#endif + +/** @def LogFlowThisFunc + * Flow level logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define LogFlowThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogFlowThisFunc(a) do { LogFlow(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogFlow(a); } while (0) +#endif + +/** @def LogWarnThisFunc + * Warning level logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define LogWarnThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_WARN, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogWarnThisFunc(a) do { LogWarn(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogWarn(a); } while (0) +#endif +/** @} */ + + +/** @name Misc Logging Macros + * @{ */ + +/** @def Log1Warning + * The same as Log(), but prepents a "WARNING! " string to the message. + * + * @param a Custom log message in format ("string\n" [, args]). + */ +#if defined(LOG_USE_C99) +# define Log1Warning(a) _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "WARNING! %M", _LogRemoveParentheseis a ) +#else +# define Log1Warning(a) do { Log(("WARNING! ")); Log(a); } while (0) +#endif + +/** @def Log1WarningFunc + * The same as LogWarning(), but prepents the log message with the function name. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log1WarningFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, LOG_FN_FMT ": WARNING! %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log1WarningFunc(a) \ + do { Log((LOG_FN_FMT ": WARNING! ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log(a); } while (0) +#endif + +/** @def Log1WarningThisFunc + * The same as LogWarningFunc() but for class functions (methods): the resulting + * log line is additionally prepended with a hex value of |this| pointer. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define Log1WarningThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "{%p} " LOG_FN_FMT ": WARNING! %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log1WarningThisFunc(a) \ + do { Log(("{%p} " LOG_FN_FMT ": WARNING! ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log(a); } while (0) +#endif + + +/** Shortcut to |LogFlowFunc ("ENTER\n")|, marks the beginnig of the function. */ +#define LogFlowFuncEnter() LogFlowFunc(("ENTER\n")) + +/** Shortcut to |LogFlowFunc ("LEAVE\n")|, marks the end of the function. */ +#define LogFlowFuncLeave() LogFlowFunc(("LEAVE\n")) + +/** Shortcut to |LogFlowFunc ("LEAVE: %Rrc\n")|, marks the end of the function. */ +#define LogFlowFuncLeaveRC(rc) LogFlowFunc(("LEAVE: %Rrc\n", (rc))) + +/** Shortcut to |LogFlowThisFunc ("ENTER\n")|, marks the beginnig of the function. */ +#define LogFlowThisFuncEnter() LogFlowThisFunc(("ENTER\n")) + +/** Shortcut to |LogFlowThisFunc ("LEAVE\n")|, marks the end of the function. */ +#define LogFlowThisFuncLeave() LogFlowThisFunc(("LEAVE\n")) + + +/** @def LogObjRefCnt + * Helper macro to print the current reference count of the given COM object + * to the log file. + * + * @param pObj Pointer to the object in question (must be a pointer to an + * IUnknown subclass or simply define COM-style AddRef() and + * Release() methods) + */ +#define LogObjRefCnt(pObj) \ + do { \ + if (LogIsFlowEnabled()) \ + { \ + int cRefsForLog = (pObj)->AddRef(); \ + LogFlow((#pObj "{%p}.refCnt=%d\n", (pObj), cRefsForLog - 1)); \ + (pObj)->Release(); \ + } \ + } while (0) +/** @} */ + + + +/** @name Passing Function Call Position When Logging. + * + * This is a little bit ugly as we have to omit the comma before the + * position parameters so that we don't inccur any overhead in non-logging + * builds (!defined(LOG_ENABLED). + * + * @{ */ +/** Source position for passing to a function call. */ +#ifdef LOG_ENABLED +# define RTLOG_COMMA_SRC_POS , __FILE__, __LINE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__ +#else +# define RTLOG_COMMA_SRC_POS RT_NOTHING +#endif +/** Source position declaration. */ +#ifdef LOG_ENABLED +# define RTLOG_COMMA_SRC_POS_DECL , const char *pszFile, unsigned iLine, const char *pszFunction +#else +# define RTLOG_COMMA_SRC_POS_DECL RT_NOTHING +#endif +/** Source position arguments. */ +#ifdef LOG_ENABLED +# define RTLOG_COMMA_SRC_POS_ARGS , pszFile, iLine, pszFunction +#else +# define RTLOG_COMMA_SRC_POS_ARGS RT_NOTHING +#endif +/** Applies NOREF() to the source position arguments. */ +#ifdef LOG_ENABLED +# define RTLOG_SRC_POS_NOREF() do { NOREF(pszFile); NOREF(iLine); NOREF(pszFunction); } while (0) +#else +# define RTLOG_SRC_POS_NOREF() do { } while (0) +#endif +/** @} */ + + + +/** @defgroup grp_rt_log_rel Release Logging + * @{ + */ + +#ifdef DOXYGEN_RUNNING +# define RTLOG_REL_DISABLED +# define RTLOG_REL_ENABLED +#endif + +/** @def RTLOG_REL_DISABLED + * Use this compile time define to disable all release logging + * macros. + */ + +/** @def RTLOG_REL_ENABLED + * Use this compile time define to override RTLOG_REL_DISABLE. + */ + +/* + * Determine whether release logging is enabled and forcefully normalize the indicators. + */ +#if !defined(RTLOG_REL_DISABLED) || defined(RTLOG_REL_ENABLED) +# undef RTLOG_REL_DISABLED +# undef RTLOG_REL_ENABLED +# define RTLOG_REL_ENABLED +#else +# undef RTLOG_REL_ENABLED +# undef RTLOG_REL_DISABLED +# define RTLOG_REL_DISABLED +#endif + +/** @name Macros for checking whether a release log level is enabled. + * @{ */ +/** @def LogRelIsItEnabled + * Checks whether the specified release logging group is enabled or not. + */ +#define LogRelIsItEnabled(a_fFlags, a_iGroup) ( RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)) != NULL ) + +/** @def LogRelIsEnabled + * Checks whether level 1 release logging is enabled. + */ +#define LogRelIsEnabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP) + +/** @def LogRelIs2Enabled + * Checks whether level 2 release logging is enabled. + */ +#define LogRelIs2Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP) + +/** @def LogRelIs3Enabled + * Checks whether level 3 release logging is enabled. + */ +#define LogRelIs3Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP) + +/** @def LogRelIs4Enabled + * Checks whether level 4 release logging is enabled. + */ +#define LogRelIs4Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP) + +/** @def LogRelIs5Enabled + * Checks whether level 5 release logging is enabled. + */ +#define LogRelIs5Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP) + +/** @def LogRelIs6Enabled + * Checks whether level 6 release logging is enabled. + */ +#define LogRelIs6Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP) + +/** @def LogRelIs7Enabled + * Checks whether level 7 release logging is enabled. + */ +#define LogRelIs7Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP) + +/** @def LogRelIs8Enabled + * Checks whether level 8 release logging is enabled. + */ +#define LogRelIs8Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP) + +/** @def LogRelIs2Enabled + * Checks whether level 9 release logging is enabled. + */ +#define LogRelIs9Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP) + +/** @def LogRelIs10Enabled + * Checks whether level 10 release logging is enabled. + */ +#define LogRelIs10Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP) + +/** @def LogRelIs11Enabled + * Checks whether level 10 release logging is enabled. + */ +#define LogRelIs11Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP) + +/** @def LogRelIs12Enabled + * Checks whether level 12 release logging is enabled. + */ +#define LogRelIs12Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP) + +/** @def LogRelIsFlowEnabled + * Checks whether execution flow release logging is enabled. + */ +#define LogRelIsFlowEnabled() LogRelIsItEnabled(RTLOGGRPFLAGS_FLOW, LOG_GROUP) + +/** @def LogRelIsWarnEnabled + * Checks whether warning level release logging is enabled. + */ +#define LogRelIsWarnEnabled() LogRelIsItEnabled(RTLOGGRPFLAGS_FLOW, LOG_GROUP) +/** @} */ + + +/** @def LogRelIt + * Write to specific logger if group enabled. + */ +/** @def LogRelItLikely + * Write to specific logger if group enabled, assuming it likely it is enabled. + */ +/** @def LogRelMaxIt + * Write to specific logger if group enabled and at less than a_cMax messages + * have hit the log. Uses a static variable to count. + */ +#ifdef RTLOG_REL_ENABLED +# if defined(LOG_USE_C99) +# define _LogRelRemoveParentheseis(...) __VA_ARGS__ +# define _LogRelIt(a_fFlags, a_iGroup, ...) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (RT_LIKELY(!LogRelIt_pLogger)) \ + { /* likely */ } \ + else \ + RTLogLoggerExWeak(LogRelIt_pLogger, a_fFlags, a_iGroup, __VA_ARGS__); \ + _LogIt(a_fFlags, a_iGroup, __VA_ARGS__); \ + } while (0) +# define LogRelIt(a_fFlags, a_iGroup, fmtargs) \ + _LogRelIt(a_fFlags, a_iGroup, _LogRelRemoveParentheseis fmtargs) +# define _LogRelItLikely(a_fFlags, a_iGroup, ...) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (LogRelIt_pLogger) \ + RTLogLoggerExWeak(LogRelIt_pLogger, a_fFlags, a_iGroup, __VA_ARGS__); \ + _LogIt(a_fFlags, a_iGroup, __VA_ARGS__); \ + } while (0) +# define LogRelItLikely(a_fFlags, a_iGroup, fmtargs) \ + _LogRelItLikely(a_fFlags, a_iGroup, _LogRelRemoveParentheseis fmtargs) +# define _LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, ...) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (LogRelIt_pLogger) \ + { \ + static uint32_t s_LogRelMaxIt_cLogged = 0; \ + if (s_LogRelMaxIt_cLogged < (a_cMax)) \ + { \ + s_LogRelMaxIt_cLogged++; \ + RTLogLoggerExWeak(LogRelIt_pLogger, a_fFlags, a_iGroup, __VA_ARGS__); \ + } \ + } \ + _LogIt(a_fFlags, a_iGroup, __VA_ARGS__); \ + } while (0) +# define LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, fmtargs) \ + _LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, _LogRelRemoveParentheseis fmtargs) +# else +# define LogRelItLikely(a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (LogRelIt_pLogger) \ + { \ + LogRelIt_pLogger->pfnLogger fmtargs; \ + } \ + LogIt(a_fFlags, a_iGroup, fmtargs); \ + } while (0) +# define LogRelIt(a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (RT_LIKELY(!LogRelIt_pLogger)) \ + { /* likely */ } \ + else \ + { \ + LogRelIt_pLogger->pfnLogger fmtargs; \ + } \ + LogIt(a_fFlags, a_iGroup, fmtargs); \ + } while (0) +# define LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (LogRelIt_pLogger) \ + { \ + static uint32_t s_LogRelMaxIt_cLogged = 0; \ + if (s_LogRelMaxIt_cLogged < (a_cMax)) \ + { \ + s_LogRelMaxIt_cLogged++; \ + LogRelIt_pLogger->pfnLogger fmtargs; \ + } \ + } \ + LogIt(a_fFlags, a_iGroup, fmtargs); \ + } while (0) +# endif +#else /* !RTLOG_REL_ENABLED */ +# define LogRelIt(a_fFlags, a_iGroup, fmtargs) do { } while (0) +# define LogRelItLikely(a_fFlags, a_iGroup, fmtargs) do { } while (0) +# define LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, fmtargs) do { } while (0) +# if defined(LOG_USE_C99) +# define _LogRelRemoveParentheseis(...) __VA_ARGS__ +# define _LogRelIt(a_fFlags, a_iGroup, ...) do { } while (0) +# define _LogRelItLikely(a_fFlags, a_iGroup, ...) do { } while (0) +# define _LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, ...) do { } while (0) +# endif +#endif /* !RTLOG_REL_ENABLED */ + + +/** @name Basic release logging macros + * @{ */ +/** @def LogRel + * Level 1 release logging. + */ +#define LogRel(a) LogRelItLikely(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, a) + +/** @def LogRel2 + * Level 2 release logging. + */ +#define LogRel2(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, a) + +/** @def LogRel3 + * Level 3 release logging. + */ +#define LogRel3(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, a) + +/** @def LogRel4 + * Level 4 release logging. + */ +#define LogRel4(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, a) + +/** @def LogRel5 + * Level 5 release logging. + */ +#define LogRel5(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, a) + +/** @def LogRel6 + * Level 6 release logging. + */ +#define LogRel6(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, a) + +/** @def LogRel7 + * Level 7 release logging. + */ +#define LogRel7(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, a) + +/** @def LogRel8 + * Level 8 release logging. + */ +#define LogRel8(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, a) + +/** @def LogRel9 + * Level 9 release logging. + */ +#define LogRel9(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, a) + +/** @def LogRel10 + * Level 10 release logging. + */ +#define LogRel10(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, a) + +/** @def LogRel11 + * Level 11 release logging. + */ +#define LogRel11(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, a) + +/** @def LogRel12 + * Level 12 release logging. + */ +#define LogRel12(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, a) + +/** @def LogRelFlow + * Logging of execution flow. + */ +#define LogRelFlow(a) LogRelIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, a) + +/** @def LogRelWarn + * Warning level release logging. + */ +#define LogRelWarn(a) LogRelIt(RTLOGGRPFLAGS_WARN, LOG_GROUP, a) +/** @} */ + + + +/** @name Basic release logging macros with local max + * @{ */ +/** @def LogRelMax + * Level 1 release logging with a max number of log entries. + */ +#define LogRelMax(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, a) + +/** @def LogRelMax2 + * Level 2 release logging with a max number of log entries. + */ +#define LogRelMax2(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, a) + +/** @def LogRelMax3 + * Level 3 release logging with a max number of log entries. + */ +#define LogRelMax3(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, a) + +/** @def LogRelMax4 + * Level 4 release logging with a max number of log entries. + */ +#define LogRelMax4(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, a) + +/** @def LogRelMax5 + * Level 5 release logging with a max number of log entries. + */ +#define LogRelMax5(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, a) + +/** @def LogRelMax6 + * Level 6 release logging with a max number of log entries. + */ +#define LogRelMax6(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, a) + +/** @def LogRelMax7 + * Level 7 release logging with a max number of log entries. + */ +#define LogRelMax7(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, a) + +/** @def LogRelMax8 + * Level 8 release logging with a max number of log entries. + */ +#define LogRelMax8(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, a) + +/** @def LogRelMax9 + * Level 9 release logging with a max number of log entries. + */ +#define LogRelMax9(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, a) + +/** @def LogRelMax10 + * Level 10 release logging with a max number of log entries. + */ +#define LogRelMax10(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, a) + +/** @def LogRelMax11 + * Level 11 release logging with a max number of log entries. + */ +#define LogRelMax11(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, a) + +/** @def LogRelMax12 + * Level 12 release logging with a max number of log entries. + */ +#define LogRelMax12(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, a) + +/** @def LogRelMaxFlow + * Logging of execution flow with a max number of log entries. + */ +#define LogRelMaxFlow(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_FLOW, LOG_GROUP, a) +/** @} */ + + +/** @name Release logging macros prefixing the current function name. + * @{ */ + +/** @def LogRelFunc + * Release logging. Prepends the given log message with the function name + * followed by a semicolon and space. + */ +#ifdef LOG_USE_C99 +# define LogRelFunc(a) \ + _LogRelItLikely(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelFunc(a) do { LogRel((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRel(a); } while (0) +#endif + +/** @def LogRelFlowFunc + * Release logging. Macro to log the execution flow inside C/C++ functions. + * + * Prepends the given log message with the function name followed by + * a semicolon and space. + * + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define LogRelFlowFunc(a) _LogRelIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelFlowFunc(a) do { LogRelFlow((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelFlow(a); } while (0) +#endif + +/** @def LogRelMaxFunc + * Release logging. Prepends the given log message with the function name + * followed by a semicolon and space. + */ +#ifdef LOG_USE_C99 +# define LogRelMaxFunc(a_cMax, a) \ + _LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelMaxFunc(a_cMax, a) \ + do { LogRelMax(a_cMax, (LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelMax(a_cMax, a); } while (0) +#endif + +/** @def LogRelMaxFlowFunc + * Release logging. Macro to log the execution flow inside C/C++ functions. + * + * Prepends the given log message with the function name followed by + * a semicolon and space. + * + * @param a_cMax Max number of times this should hit the log. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define LogRelMaxFlowFunc(a_cMax, a) \ + _LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_FLOW, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelMaxFlowFunc(a_cMax, a) \ + do { LogRelMaxFlow(a_cMax, (LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelFlow(a_cMax, a); } while (0) +#endif + +/** @} */ + + +/** @name Release Logging macros prefixing the this pointer value and method name. + * @{ */ + +/** @def LogRelThisFunc + * The same as LogRelFunc but for class functions (methods): the resulting log + * line is additionally prepended with a hex value of |this| pointer. + */ +#ifdef LOG_USE_C99 +# define LogRelThisFunc(a) \ + _LogRelItLikely(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelThisFunc(a) \ + do { LogRel(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRel(a); } while (0) +#endif + +/** @def LogRelMaxThisFunc + * The same as LogRelFunc but for class functions (methods): the resulting log + * line is additionally prepended with a hex value of |this| pointer. + * @param a_cMax Max number of times this should hit the log. + * @param a Log message in format ("string\n" [, args]). + */ +#ifdef LOG_USE_C99 +# define LogRelMaxThisFunc(a_cMax, a) \ + _LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelMaxThisFunc(a_cMax, a) \ + do { LogRelMax(a_cMax, ("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelMax(a_cMax, a); } while (0) +#endif + +/** @def LogRelFlowThisFunc + * The same as LogRelFlowFunc but for class functions (methods): the resulting + * log line is additionally prepended with a hex value of |this| pointer. + */ +#ifdef LOG_USE_C99 +# define LogRelFlowThisFunc(a) \ + _LogRelIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelFlowThisFunc(a) do { LogRelFlow(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelFlow(a); } while (0) +#endif + + +/** Shortcut to |LogRelFlowFunc ("ENTER\n")|, marks the beginnig of the function. */ +#define LogRelFlowFuncEnter() LogRelFlowFunc(("ENTER\n")) + +/** Shortcut to |LogRelFlowFunc ("LEAVE\n")|, marks the end of the function. */ +#define LogRelFlowFuncLeave() LogRelFlowFunc(("LEAVE\n")) + +/** Shortcut to |LogRelFlowFunc ("LEAVE: %Rrc\n")|, marks the end of the function. */ +#define LogRelFlowFuncLeaveRC(rc) LogRelFlowFunc(("LEAVE: %Rrc\n", (rc))) + +/** Shortcut to |LogRelFlowThisFunc ("ENTER\n")|, marks the beginnig of the function. */ +#define LogRelFlowThisFuncEnter() LogRelFlowThisFunc(("ENTER\n")) + +/** Shortcut to |LogRelFlowThisFunc ("LEAVE\n")|, marks the end of the function. */ +#define LogRelFlowThisFuncLeave() LogRelFlowThisFunc(("LEAVE\n")) + +/** @} */ + + +/** + * Sets the default release logger instance. + * + * @returns The old default instance. + * @param pLogger The new default release logger instance. + */ +RTDECL(PRTLOGGER) RTLogRelSetDefaultInstance(PRTLOGGER pLogger); + +/** + * Gets the default release logger instance. + * + * @returns Pointer to default release logger instance if availble, otherwise NULL. + */ +RTDECL(PRTLOGGER) RTLogRelGetDefaultInstance(void); + +/** @copydoc RTLogRelGetDefaultInstance */ +typedef DECLCALLBACKTYPE(PRTLOGGER, FNLOGRELGETDEFAULTINSTANCE,(void)); +/** Pointer to RTLogRelGetDefaultInstance. */ +typedef FNLOGRELGETDEFAULTINSTANCE *PFNLOGRELGETDEFAULTINSTANCE; + +/** "Weak symbol" emulation for RTLogRelGetDefaultInstance. + * @note This is first set when RTLogRelSetDefaultInstance is called. */ +extern RTDATADECL(PFNLOGRELGETDEFAULTINSTANCE) g_pfnRTLogRelGetDefaultInstance; + +/** "Weak symbol" wrapper for RTLogRelGetDefaultInstance. */ +DECL_FORCE_INLINE(PRTLOGGER) RTLogRelGetDefaultInstanceWeak(void) +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogRelGetDefaultInstance) + return g_pfnRTLogRelGetDefaultInstance(); + return NULL; +#else + return RTLogRelGetDefaultInstance(); +#endif +} + +/** + * Gets the default release logger instance. + * + * @returns Pointer to default release logger instance if availble, otherwise NULL. + * @param fFlagsAndGroup The flags in the lower 16 bits, the group number in + * the high 16 bits. + */ +RTDECL(PRTLOGGER) RTLogRelGetDefaultInstanceEx(uint32_t fFlagsAndGroup); + +/** @copydoc RTLogRelGetDefaultInstanceEx */ +typedef DECLCALLBACKTYPE(PRTLOGGER, FNLOGRELGETDEFAULTINSTANCEEX,(uint32_t fFlagsAndGroup)); +/** Pointer to RTLogRelGetDefaultInstanceEx. */ +typedef FNLOGRELGETDEFAULTINSTANCEEX *PFNLOGRELGETDEFAULTINSTANCEEX; + +/** "Weak symbol" emulation for RTLogRelGetDefaultInstanceEx. + * @note This is first set when RTLogRelSetDefaultInstance is called. */ +extern RTDATADECL(PFNLOGRELGETDEFAULTINSTANCEEX) g_pfnRTLogRelGetDefaultInstanceEx; + +/** "Weak symbol" wrapper for RTLogRelGetDefaultInstanceEx. */ +DECL_FORCE_INLINE(PRTLOGGER) RTLogRelGetDefaultInstanceExWeak(uint32_t fFlagsAndGroup) +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogRelGetDefaultInstanceEx) + return g_pfnRTLogRelGetDefaultInstanceEx(fFlagsAndGroup); + return NULL; +#else + return RTLogRelGetDefaultInstanceEx(fFlagsAndGroup); +#endif +} + + +/** + * Write to a logger instance, defaulting to the release one. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @param pLogger Pointer to logger instance. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param ... Format arguments. + * @remark This is a worker function for LogRelIt. + */ +RTDECL(void) RTLogRelLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Write to a logger instance, defaulting to the release one. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @param pLogger Pointer to logger instance. If NULL the default release instance is attempted. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param args Format arguments. + */ +RTDECL(void) RTLogRelLoggerV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * printf like function for writing to the default release log. + * + * @param pszFormat Printf like format string. + * @param ... Optional arguments as specified in pszFormat. + * + * @remark The API doesn't support formatting of floating point numbers at the moment. + */ +RTDECL(void) RTLogRelPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * vprintf like function for writing to the default release log. + * + * @param pszFormat Printf like format string. + * @param args Optional arguments as specified in pszFormat. + * + * @remark The API doesn't support formatting of floating point numbers at the moment. + */ +RTDECL(void) RTLogRelPrintfV(const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Changes the buffering setting of the default release logger. + * + * This can be used for optimizing longish logging sequences. + * + * @returns The old state. + * @param fBuffered The new state. + */ +RTDECL(bool) RTLogRelSetBuffering(bool fBuffered); + +/** @} */ + + + +/** @name COM port logging + * @{ + */ + +#ifdef DOXYGEN_RUNNING +# define LOG_TO_COM +# define LOG_NO_COM +#endif + +/** @def LOG_TO_COM + * Redirects the normal logging macros to the serial versions. + */ + +/** @def LOG_NO_COM + * Disables all LogCom* macros. + */ + +/** @def LogCom + * Generic logging to serial port. + */ +#if defined(LOG_ENABLED) && !defined(LOG_NO_COM) +# define LogCom(a) RTLogComPrintf a +#else +# define LogCom(a) do { } while (0) +#endif + +/** @def LogComFlow + * Logging to serial port of execution flow. + */ +#if defined(LOG_ENABLED) && defined(LOG_ENABLE_FLOW) && !defined(LOG_NO_COM) +# define LogComFlow(a) RTLogComPrintf a +#else +# define LogComFlow(a) do { } while (0) +#endif + +#ifdef LOG_TO_COM +# undef Log +# define Log(a) LogCom(a) +# undef LogFlow +# define LogFlow(a) LogComFlow(a) +#endif + +/** @} */ + + +/** @name Backdoor Logging + * @{ + */ + +#ifdef DOXYGEN_RUNNING +# define LOG_TO_BACKDOOR +# define LOG_NO_BACKDOOR +#endif + +/** @def LOG_TO_BACKDOOR + * Redirects the normal logging macros to the backdoor versions. + */ + +/** @def LOG_NO_BACKDOOR + * Disables all LogBackdoor* macros. + */ + +/** @def LogBackdoor + * Generic logging to the VBox backdoor via port I/O. + */ +#if defined(LOG_ENABLED) && !defined(LOG_NO_BACKDOOR) +# define LogBackdoor(a) RTLogBackdoorPrintf a +#else +# define LogBackdoor(a) do { } while (0) +#endif + +/** @def LogBackdoorFlow + * Logging of execution flow messages to the backdoor I/O port. + */ +#if defined(LOG_ENABLED) && !defined(LOG_NO_BACKDOOR) +# define LogBackdoorFlow(a) RTLogBackdoorPrintf a +#else +# define LogBackdoorFlow(a) do { } while (0) +#endif + +/** @def LogRelBackdoor + * Release logging to the VBox backdoor via port I/O. + */ +#if !defined(LOG_NO_BACKDOOR) +# define LogRelBackdoor(a) RTLogBackdoorPrintf a +#else +# define LogRelBackdoor(a) do { } while (0) +#endif + +#ifdef LOG_TO_BACKDOOR +# undef Log +# define Log(a) LogBackdoor(a) +# undef LogFlow +# define LogFlow(a) LogBackdoorFlow(a) +# undef LogRel +# define LogRel(a) LogRelBackdoor(a) +# if defined(LOG_USE_C99) +# undef _LogIt +# define _LogIt(a_fFlags, a_iGroup, ...) LogBackdoor((__VA_ARGS__)) +# endif +#endif + +/** @} */ + + + +/** + * Gets the default logger instance, creating it if necessary. + * + * @returns Pointer to default logger instance if availble, otherwise NULL. + */ +RTDECL(PRTLOGGER) RTLogDefaultInstance(void); + +/** + * Gets the logger instance if enabled, creating it if necessary. + * + * @returns Pointer to default logger instance, if group has the specified + * flags enabled. Otherwise NULL is returned. + * @param fFlagsAndGroup The flags in the lower 16 bits, the group number in + * the high 16 bits. + */ +RTDECL(PRTLOGGER) RTLogDefaultInstanceEx(uint32_t fFlagsAndGroup); + +/** + * Gets the default logger instance (does not create one). + * + * @returns Pointer to default logger instance if availble, otherwise NULL. + */ +RTDECL(PRTLOGGER) RTLogGetDefaultInstance(void); + +/** @copydoc RTLogGetDefaultInstance */ +typedef DECLCALLBACKTYPE(PRTLOGGER, FNLOGGETDEFAULTINSTANCE,(void)); +/** Pointer to RTLogGetDefaultInstance. */ +typedef FNLOGGETDEFAULTINSTANCE *PFNLOGGETDEFAULTINSTANCE; + +/** "Weak symbol" emulation for RTLogGetDefaultInstance. + * @note This is first set when RTLogSetDefaultInstance is called. */ +extern RTDATADECL(PFNLOGGETDEFAULTINSTANCE) g_pfnRTLogGetDefaultInstance; + +/** "Weak symbol" wrapper for RTLogGetDefaultInstance. */ +DECL_FORCE_INLINE(PRTLOGGER) RTLogGetDefaultInstanceWeak(void) +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogGetDefaultInstance) + return g_pfnRTLogGetDefaultInstance(); + return NULL; +#else + return RTLogGetDefaultInstance(); +#endif +} + +/** + * Gets the default logger instance if enabled (does not create one). + * + * @returns Pointer to default logger instance, if group has the specified + * flags enabled. Otherwise NULL is returned. + * @param fFlagsAndGroup The flags in the lower 16 bits, the group number in + * the high 16 bits. + */ +RTDECL(PRTLOGGER) RTLogGetDefaultInstanceEx(uint32_t fFlagsAndGroup); + +/** @copydoc RTLogGetDefaultInstanceEx */ +typedef DECLCALLBACKTYPE(PRTLOGGER, FNLOGGETDEFAULTINSTANCEEX,(uint32_t fFlagsAndGroup)); +/** Pointer to RTLogGetDefaultInstanceEx. */ +typedef FNLOGGETDEFAULTINSTANCEEX *PFNLOGGETDEFAULTINSTANCEEX; + +/** "Weak symbol" emulation for RTLogGetDefaultInstanceEx. + * @note This is first set when RTLogSetDefaultInstance is called. */ +extern RTDATADECL(PFNLOGGETDEFAULTINSTANCEEX) g_pfnRTLogGetDefaultInstanceEx; + +/** "Weak symbol" wrapper for RTLogGetDefaultInstanceEx. */ +DECL_FORCE_INLINE(PRTLOGGER) RTLogGetDefaultInstanceExWeak(uint32_t fFlagsAndGroup) +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogGetDefaultInstanceEx) + return g_pfnRTLogGetDefaultInstanceEx(fFlagsAndGroup); + return NULL; +#else + return RTLogGetDefaultInstanceEx(fFlagsAndGroup); +#endif +} + +/** + * Sets the default logger instance. + * + * @returns The old default instance. + * @param pLogger The new default logger instance. + */ +RTDECL(PRTLOGGER) RTLogSetDefaultInstance(PRTLOGGER pLogger); + +#ifdef IN_RING0 +/** + * Changes the default logger instance for the current thread. + * + * @returns IPRT status code. + * @param pLogger The logger instance. Pass NULL for deregistration. + * @param uKey Associated key for cleanup purposes. If pLogger is NULL, + * all instances with this key will be deregistered. So in + * order to only deregister the instance associated with the + * current thread use 0. + */ +RTR0DECL(int) RTLogSetDefaultInstanceThread(PRTLOGGER pLogger, uintptr_t uKey); +#endif /* IN_RING0 */ + +/** + * Creates the default logger instance for IPRT users. + * + * Any user of the logging features will need to implement + * this or use the generic dummy. + * + * @returns Pointer to the logger instance. + */ +RTDECL(PRTLOGGER) RTLogDefaultInit(void); + +/** + * This is the 2nd half of what RTLogGetDefaultInstanceEx() and + * RTLogRelGetDefaultInstanceEx() does. + * + * @returns If the group has the specified flags enabled @a pLogger will be + * returned returned. Otherwise NULL is returned. + * @param pLogger The logger. NULL is NULL. + * @param fFlagsAndGroup The flags in the lower 16 bits, the group number in + * the high 16 bits. + */ +RTDECL(PRTLOGGER) RTLogCheckGroupFlags(PRTLOGGER pLogger, uint32_t fFlagsAndGroup); + +/** + * Create a logger instance. + * + * @returns iprt status code. + * + * @param ppLogger Where to store the logger instance. + * @param fFlags Logger instance flags, a combination of the + * RTLOGFLAGS_* values. + * @param pszGroupSettings The initial group settings. + * @param pszEnvVarBase Base name for the environment variables for + * this instance. + * @param cGroups Number of groups in the array. + * @param papszGroups Pointer to array of groups. This must stick + * around for the life of the logger instance. + * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed + * if pszFilenameFmt specified. + * @param pszFilenameFmt Log filename format string. Standard + * RTStrFormat(). + * @param ... Format arguments. + */ +RTDECL(int) RTLogCreate(PRTLOGGER *ppLogger, uint64_t fFlags, const char *pszGroupSettings, + const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups, + uint32_t fDestFlags, const char *pszFilenameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(8, 9); + +/** + * Create a logger instance. + * + * @returns iprt status code. + * + * @param ppLogger Where to store the logger instance. + * @param pszEnvVarBase Base name for the environment variables for + * this instance (ring-3 only). + * @param fFlags Logger instance flags, a combination of the + * RTLOGFLAGS_* values. + * @param pszGroupSettings The initial group settings. + * @param cGroups Number of groups in the array. + * @param papszGroups Pointer to array of groups. This must stick + * around for the life of the logger instance. + * @param cMaxEntriesPerGroup The max number of entries per group. UINT32_MAX + * or zero for unlimited. + * @param cBufDescs Number of buffer descriptors that @a paBufDescs + * points to. Zero for defaults. + * @param paBufDescs Buffer descriptors, optional. + * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed + * if pszFilenameFmt specified. + * @param pfnPhase Callback function for starting logging and for + * ending or starting a new file for log history + * rotation. NULL is OK. + * @param cHistory Number of old log files to keep when performing + * log history rotation. 0 means no history. + * @param cbHistoryFileMax Maximum size of log file when performing + * history rotation. 0 means no size limit. + * @param cSecsHistoryTimeSlot Maximum time interval per log file when + * performing history rotation, in seconds. + * 0 means time limit. + * @param pOutputIf The optional file output interface, can be NULL which will + * make use of the default one. + * @param pvOutputIfUser The opaque user data to pass to the callbacks in the output interface. + * @param pErrInfo Where to return extended error information. + * Optional. + * @param pszFilenameFmt Log filename format string. Standard RTStrFormat(). + * @param ... Format arguments. + */ +RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, const char *pszEnvVarBase, uint64_t fFlags, const char *pszGroupSettings, + unsigned cGroups, const char * const *papszGroups, uint32_t cMaxEntriesPerGroup, + uint32_t cBufDescs, PRTLOGBUFFERDESC paBufDescs, uint32_t fDestFlags, + PFNRTLOGPHASE pfnPhase, uint32_t cHistory, uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot, + PCRTLOGOUTPUTIF pOutputIf, void *pvOutputIfUser, + PRTERRINFO pErrInfo, const char *pszFilenameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(18, 19); + +/** + * Create a logger instance. + * + * @returns iprt status code. + * + * @param ppLogger Where to store the logger instance. + * @param pszEnvVarBase Base name for the environment variables for + * this instance (ring-3 only). + * @param fFlags Logger instance flags, a combination of the + * RTLOGFLAGS_* values. + * @param pszGroupSettings The initial group settings. + * @param cGroups Number of groups in the array. + * @param papszGroups Pointer to array of groups. This must stick + * around for the life of the logger instance. + * @param cMaxEntriesPerGroup The max number of entries per group. UINT32_MAX + * or zero for unlimited. + * @param cBufDescs Number of buffer descriptors that @a paBufDescs + * points to. Zero for defaults. + * @param paBufDescs Buffer descriptors, optional. + * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed + * if pszFilenameFmt specified. + * @param pfnPhase Callback function for starting logging and for + * ending or starting a new file for log history + * rotation. + * @param cHistory Number of old log files to keep when performing + * log history rotation. 0 means no history. + * @param cbHistoryFileMax Maximum size of log file when performing + * history rotation. 0 means no size limit. + * @param cSecsHistoryTimeSlot Maximum time interval per log file when + * performing history rotation, in seconds. + * 0 means no time limit. + * @param pOutputIf The optional file output interface, can be NULL which will + * make use of the default one. + * @param pvOutputIfUser The opaque user data to pass to the callbacks in the output interface. + * @param pErrInfo Where to return extended error information. + * Optional. + * @param pszFilenameFmt Log filename format string. Standard + * RTStrFormat(). + * @param va Format arguments. + */ +RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, const char *pszEnvVarBase, uint64_t fFlags, const char *pszGroupSettings, + uint32_t cGroups, const char * const *papszGroups, uint32_t cMaxEntriesPerGroup, + uint32_t cBufDescs, PRTLOGBUFFERDESC paBufDescs, uint32_t fDestFlags, + PFNRTLOGPHASE pfnPhase, uint32_t cHistory, uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot, + PCRTLOGOUTPUTIF pOutputIf, void *pvOutputIfUser, + PRTERRINFO pErrInfo, const char *pszFilenameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(18, 0); + +/** + * Destroys a logger instance. + * + * The instance is flushed and all output destinations closed (where applicable). + * + * @returns iprt status code. + * @param pLogger The logger instance which close destroyed. NULL is fine. + */ +RTDECL(int) RTLogDestroy(PRTLOGGER pLogger); + +/** + * Sets the custom prefix callback. + * + * @returns IPRT status code. + * @param pLogger The logger instance. + * @param pfnCallback The callback. + * @param pvUser The user argument for the callback. + * */ +RTDECL(int) RTLogSetCustomPrefixCallback(PRTLOGGER pLogger, PFNRTLOGPREFIX pfnCallback, void *pvUser); + +/** + * Sets the custom flush callback. + * + * This can be handy for special loggers like the per-EMT ones in ring-0, + * but also for implementing a log viewer in the debugger GUI. + * + * @returns IPRT status code. + * @retval VWRN_ALREADY_EXISTS if it was set to a different flusher. + * @param pLogger The logger instance. + * @param pfnFlush The flush callback. + */ +RTDECL(int) RTLogSetFlushCallback(PRTLOGGER pLogger, PFNRTLOGFLUSH pfnFlush); + +/** + * Sets the thread name for a thread specific ring-0 logger. + * + * @returns IPRT status code. + * @param pLogger The logger. NULL is not allowed. + * @param pszNameFmt The format string for the thread name. + * @param ... Format arguments. + */ +RTR0DECL(int) RTLogSetR0ThreadNameF(PRTLOGGER pLogger, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Sets the thread name for a thread specific ring-0 logger. + * + * @returns IPRT status code. + * @param pLogger The logger. NULL is not allowed. + * @param pszNameFmt The format string for the thread name. + * @param va Format arguments. + */ +RTR0DECL(int) RTLogSetR0ThreadNameV(PRTLOGGER pLogger, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Sets the program start time for a thread specific ring-0 logger. + * + * @returns IPRT status code. + * @param pLogger The logger. NULL is not allowed. + * @param nsStart The RTTimeNanoTS() value at program start. + */ +RTR0DECL(int) RTLogSetR0ProgramStart(PRTLOGGER pLogger, uint64_t nsStart); + +/** + * Get the current log group settings as a string. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pLogger Logger instance (NULL for default logger). + * @param pszBuf The output buffer. + * @param cchBuf The size of the output buffer. Must be greater than + * zero. + */ +RTDECL(int) RTLogQueryGroupSettings(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf); + +/** + * Updates the group settings for the logger instance using the specified + * specification string. + * + * @returns iprt status code. + * Failures can safely be ignored. + * @param pLogger Logger instance (NULL for default logger). + * @param pszValue Value to parse. + */ +RTDECL(int) RTLogGroupSettings(PRTLOGGER pLogger, const char *pszValue); + +/** + * Sets the max number of entries per group. + * + * @returns Old restriction. + * + * @param pLogger The logger instance (NULL is an alias for the + * default logger). + * @param cMaxEntriesPerGroup The max number of entries per group. + * + * @remarks Lowering the limit of an active logger may quietly mute groups. + * Raising it may reactive already muted groups. + */ +RTDECL(uint32_t) RTLogSetGroupLimit(PRTLOGGER pLogger, uint32_t cMaxEntriesPerGroup); + +/** + * Gets the current flag settings for the given logger. + * + * @returns Logger flags, UINT64_MAX if no logger. + * @param pLogger Logger instance (NULL for default logger). + */ +RTDECL(uint64_t) RTLogGetFlags(PRTLOGGER pLogger); + +/** + * Modifies the flag settings for the given logger. + * + * @returns IPRT status code. Returns VINF_LOG_NO_LOGGER if no default logger + * and @a pLogger is NULL. + * @param pLogger Logger instance (NULL for default logger). + * @param fSet Mask of flags to set (OR). + * @param fClear Mask of flags to clear (NAND). This is allowed to + * include invalid flags - e.g. UINT64_MAX is okay. + */ +RTDECL(int) RTLogChangeFlags(PRTLOGGER pLogger, uint64_t fSet, uint64_t fClear); + +/** + * Updates the flags for the logger instance using the specified + * specification string. + * + * @returns iprt status code. + * Failures can safely be ignored. + * @param pLogger Logger instance (NULL for default logger). + * @param pszValue Value to parse. + */ +RTDECL(int) RTLogFlags(PRTLOGGER pLogger, const char *pszValue); + +/** + * Changes the buffering setting of the specified logger. + * + * This can be used for optimizing longish logging sequences. + * + * @returns The old state. + * @param pLogger The logger instance (NULL is an alias for the default + * logger). + * @param fBuffered The new state. + */ +RTDECL(bool) RTLogSetBuffering(PRTLOGGER pLogger, bool fBuffered); + +/** + * Get the current log flags as a string. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pLogger Logger instance (NULL for default logger). + * @param pszBuf The output buffer. + * @param cchBuf The size of the output buffer. Must be greater than + * zero. + */ +RTDECL(int) RTLogQueryFlags(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf); + +/** + * Gets the current destinations flags for the given logger. + * + * @returns Logger destination flags, UINT32_MAX if no logger. + * @param pLogger Logger instance (NULL for default logger). + */ +RTDECL(uint32_t) RTLogGetDestinations(PRTLOGGER pLogger); + +/** + * Modifies the log destinations settings for the given logger. + * + * This is only suitable for simple destination settings that doesn't take + * additional arguments, like RTLOGDEST_FILE. + * + * @returns IPRT status code. Returns VINF_LOG_NO_LOGGER if no default logger + * and @a pLogger is NULL. + * @param pLogger Logger instance (NULL for default logger). + * @param fSet Mask of destinations to set (OR). + * @param fClear Mask of destinations to clear (NAND). + */ +RTDECL(int) RTLogChangeDestinations(PRTLOGGER pLogger, uint32_t fSet, uint32_t fClear); + +/** + * Updates the logger destination using the specified string. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pLogger Logger instance (NULL for default logger). + * @param pszValue The value to parse. + */ +RTDECL(int) RTLogDestinations(PRTLOGGER pLogger, char const *pszValue); + +/** + * Clear the file delay flag if set, opening the destination and flushing. + * + * @returns IPRT status code. + * @param pLogger Logger instance (NULL for default logger). + * @param pErrInfo Where to return extended error info. Optional. + */ +RTDECL(int) RTLogClearFileDelayFlag(PRTLOGGER pLogger, PRTERRINFO pErrInfo); + +/** + * Get the current log destinations as a string. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pLogger Logger instance (NULL for default logger). + * @param pszBuf The output buffer. + * @param cchBuf The size of the output buffer. Must be greater than 0. + */ +RTDECL(int) RTLogQueryDestinations(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf); + +/** + * Performs a bulk update of logger flags and group flags. + * + * This is for instanced used for copying settings from ring-3 to ring-0 + * loggers. + * + * @returns IPRT status code. + * @param pLogger The logger instance (NULL for default logger). + * @param fFlags The new logger flags. + * @param uGroupCrc32 The CRC32 of the group name strings. + * @param cGroups Number of groups. + * @param pafGroups Array of group flags. + * @sa RTLogQueryBulk + */ +RTDECL(int) RTLogBulkUpdate(PRTLOGGER pLogger, uint64_t fFlags, uint32_t uGroupCrc32, uint32_t cGroups, uint32_t const *pafGroups); + +/** + * Queries data for a bulk update of logger flags and group flags. + * + * This is for instanced used for copying settings from ring-3 to ring-0 + * loggers. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if pafGroups is too small, @a pcGroups will be + * set to the actual number of groups. + * @param pLogger The logger instance (NULL for default logger). + * @param pfFlags Where to return the logger flags. + * @param puGroupCrc32 Where to return the CRC32 of the group names. + * @param pcGroups Input: Size of the @a pafGroups allocation. + * Output: Actual number of groups returned. + * @param pafGroups Where to return the flags for each group. + * @sa RTLogBulkUpdate + */ +RTDECL(int) RTLogQueryBulk(PRTLOGGER pLogger, uint64_t *pfFlags, uint32_t *puGroupCrc32, uint32_t *pcGroups, uint32_t *pafGroups); + +/** + * Write/copy bulk log data from another logger. + * + * This is used for transferring stuff from the ring-0 loggers and into the + * ring-3 one. The text goes in as-is w/o any processing (i.e. prefixing or + * newline fun). + * + * @returns IRPT status code. + * @param pLogger The logger instance (NULL for default logger). + * @param pszBefore Text to log before the bulk text. Optional. + * @param pch Pointer to the block of bulk log text to write. + * @param cch Size of the block of bulk log text to write. + * @param pszAfter Text to log after the bulk text. Optional. + */ +RTDECL(int) RTLogBulkWrite(PRTLOGGER pLogger, const char *pszBefore, const char *pch, size_t cch, const char *pszAfter); + +/** + * Write/copy bulk log data from a nested VM logger. + * + * This is used for + * + * @returns IRPT status code. + * @param pLogger The logger instance (NULL for default logger). + * @param pch Pointer to the block of bulk log text to write. + * @param cch Size of the block of bulk log text to write. + * @param pszInfix String to put after the line prefixes and the + * line content. + */ +RTDECL(int) RTLogBulkNestedWrite(PRTLOGGER pLogger, const char *pch, size_t cch, const char *pszInfix); + +/** + * Flushes the specified logger. + * + * @returns IRPT status code. + * @param pLogger The logger instance to flush. + * If NULL the default instance is used. The default instance + * will not be initialized by this call. + */ +RTDECL(int) RTLogFlush(PRTLOGGER pLogger); + +/** + * Write to a logger instance. + * + * @param pLogger Pointer to logger instance. + * @param pvCallerRet Ignored. + * @param pszFormat Format string. + * @param ... Format arguments. + */ +RTDECL(void) RTLogLogger(PRTLOGGER pLogger, void *pvCallerRet, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Write to a logger instance, weak version. + * + * @param pLogger Pointer to logger instance. + * @param pvCallerRet Ignored. + * @param pszFormat Format string. + * @param ... Format arguments. + */ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) +RTDECL(void) RTLogLoggerWeak(PRTLOGGER pLogger, void *pvCallerRet, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +#else /* Cannot use a DECL_FORCE_INLINE because older GCC versions doesn't support inlining va_start. */ +# undef RTLogLoggerWeak /* in case of mangling */ +# define RTLogLoggerWeak RTLogLogger +#endif + +/** + * Write to a logger instance. + * + * @param pLogger Pointer to logger instance. + * @param pszFormat Format string. + * @param args Format arguments. + */ +RTDECL(void) RTLogLoggerV(PRTLOGGER pLogger, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Write to a logger instance. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @param pLogger Pointer to logger instance. If NULL the default logger instance will be attempted. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param ... Format arguments. + * @remark This is a worker function of LogIt. + */ +RTDECL(void) RTLogLoggerEx(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Write to a logger instance, weak version. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @param pLogger Pointer to logger instance. If NULL the default logger instance will be attempted. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param ... Format arguments. + * @remark This is a worker function of LogIt. + */ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) +RTDECL(void) RTLogLoggerExWeak(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); +#else /* Cannot use a DECL_FORCE_INLINE because older GCC versions doesn't support inlining va_start. */ +# undef RTLogLoggerExWeak /* in case of mangling */ +# define RTLogLoggerExWeak RTLogLoggerEx +#endif + +/** + * Write to a logger instance. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @returns VINF_SUCCESS, VINF_LOG_NO_LOGGER, VINF_LOG_DISABLED, or IPRT error + * status. + * @param pLogger Pointer to logger instance. If NULL the default logger instance will be attempted. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param args Format arguments. + */ +RTDECL(int) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(4, 0); + +/** @copydoc RTLogLoggerExV */ +typedef DECLCALLBACKTYPE(int, FNRTLOGLOGGEREXV,(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, va_list args)) RT_IPRT_FORMAT_ATTR(4, 0); +/** Pointer to RTLogLoggerExV. */ +typedef FNRTLOGLOGGEREXV *PFNRTLOGLOGGEREXV; +/** "Weak symbol" emulation for RTLogLoggerExV. + * @note This is first set when RTLogCreateEx or RTLogCreate is called. */ +extern RTDATADECL(PFNRTLOGLOGGEREXV) g_pfnRTLogLoggerExV; + +/** "Weak symbol" wrapper for RTLogLoggerExV. */ +DECL_FORCE_INLINE(int) RTLogLoggerExVWeak(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, va_list args) /* RT_IPRT_FORMAT_ATTR(4, 0) */ +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogLoggerExV) + return g_pfnRTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args); + return 22301; /* VINF_LOG_DISABLED, don't want err.h dependency here. */ +#else + return RTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args); +#endif +} + +/** + * printf like function for writing to the default log. + * + * @param pszFormat Printf like format string. + * @param ... Optional arguments as specified in pszFormat. + * + * @remark The API doesn't support formatting of floating point numbers at the moment. + */ +RTDECL(void) RTLogPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * vprintf like function for writing to the default log. + * + * @param pszFormat Printf like format string. + * @param va Optional arguments as specified in pszFormat. + * + * @remark The API doesn't support formatting of floating point numbers at the moment. + */ +RTDECL(void) RTLogPrintfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Dumper vprintf-like function outputting to a logger. + * + * @param pvUser Pointer to the logger instance to use, NULL for default + * instance. + * @param pszFormat Format string. + * @param va Format arguments. + */ +RTDECL(void) RTLogDumpPrintfV(void *pvUser, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Used for logging assertions, debug and release log as appropriate. + * + * Implies flushing. + * + * @param pszFormat Format string. + * @param ... Format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGASSERTION,(const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(1, 2); +/** Pointer to an assertion logger, ellipsis variant. */ +typedef FNRTLOGASSERTION *PFNRTLOGASSERTION; + +/** + * Used for logging assertions, debug and release log as appropriate. + * + * Implies flushing. + * + * @param pszFormat Format string. + * @param va Format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGASSERTIONV,(const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(1, 0); +/** Pointer to an assertion logger, va_list variant. */ +typedef FNRTLOGASSERTIONV *PFNRTLOGASSERTIONV; + +/** @copydoc FNRTLOGASSERTION */ +RTDECL(void) RTLogAssert(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); +/** @copydoc FNRTLOGASSERTIONV */ +RTDECL(void) RTLogAssertV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** "Weak symbol" emulation for RTLogAssert. */ +extern RTDATADECL(PFNRTLOGASSERTION) g_pfnRTLogAssert; +/** "Weak symbol" emulation for RTLogAssertV. */ +extern RTDATADECL(PFNRTLOGASSERTIONV) g_pfnRTLogAssertV; + + +#ifndef DECLARED_FNRTSTROUTPUT /* duplicated in iprt/string.h & iprt/errcore.h */ +#define DECLARED_FNRTSTROUTPUT +/** + * Output callback. + * + * @returns number of bytes written. + * @param pvArg User argument. + * @param pachChars Pointer to an array of utf-8 characters. + * @param cbChars Number of bytes in the character array pointed to by pachChars. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSTROUTPUT,(void *pvArg, const char *pachChars, size_t cbChars)); +/** Pointer to callback function. */ +typedef FNRTSTROUTPUT *PFNRTSTROUTPUT; +#endif + +/** + * Partial vsprintf worker implementation. + * + * @returns number of bytes formatted. + * @param pfnOutput Output worker. + * Called in two ways. Normally with a string an it's length. + * For termination, it's called with NULL for string, 0 for length. + * @param pvArg Argument to output worker. + * @param pszFormat Format string. + * @param args Argument list. + */ +RTDECL(size_t) RTLogFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArg, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Write log buffer to COM port. + * + * @param pach Pointer to the buffer to write. + * @param cb Number of bytes to write. + */ +RTDECL(void) RTLogWriteCom(const char *pach, size_t cb); + +/** + * Prints a formatted string to the serial port used for logging. + * + * @returns Number of bytes written. + * @param pszFormat Format string. + * @param ... Optional arguments specified in the format string. + */ +RTDECL(size_t) RTLogComPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Prints a formatted string to the serial port used for logging. + * + * @returns Number of bytes written. + * @param pszFormat Format string. + * @param args Optional arguments specified in the format string. + */ +RTDECL(size_t) RTLogComPrintfV(const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Write log buffer to a debugger (RTLOGDEST_DEBUGGER). + * + * @param pach What to write. + * @param cb How much to write. + * @remark When linking statically, this function can be replaced by defining your own. + */ +RTDECL(void) RTLogWriteDebugger(const char *pach, size_t cb); + +/** + * Write log buffer to a user defined output stream (RTLOGDEST_USER). + * + * @param pach What to write. + * @param cb How much to write. + * @remark When linking statically, this function can be replaced by defining your own. + */ +RTDECL(void) RTLogWriteUser(const char *pach, size_t cb); + +/** + * Write log buffer to a parent VMM (hypervisor). + * + * @param pach What to write. + * @param cb How much to write. + * @param fRelease Set if targeting the release log, clear if debug log. + * + * @note Currently only available on AMD64 and x86. + */ +RTDECL(void) RTLogWriteVmm(const char *pach, size_t cb, bool fRelease); + +/** + * Write log buffer to stdout (RTLOGDEST_STDOUT). + * + * @param pach What to write. + * @param cb How much to write. + * @remark When linking statically, this function can be replaced by defining your own. + */ +RTDECL(void) RTLogWriteStdOut(const char *pach, size_t cb); + +/** + * Write log buffer to stdout (RTLOGDEST_STDERR). + * + * @param pach What to write. + * @param cb How much to write. + * @remark When linking statically, this function can be replaced by defining your own. + */ +RTDECL(void) RTLogWriteStdErr(const char *pach, size_t cb); + +#ifdef VBOX + +/** + * Prints a formatted string to the backdoor port. + * + * @returns Number of bytes written. + * @param pszFormat Format string. + * @param ... Optional arguments specified in the format string. + */ +RTDECL(size_t) RTLogBackdoorPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Prints a formatted string to the backdoor port. + * + * @returns Number of bytes written. + * @param pszFormat Format string. + * @param args Optional arguments specified in the format string. + */ +RTDECL(size_t) RTLogBackdoorPrintfV(const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(1, 0); + +#endif /* VBOX */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_log_h */ + diff --git a/include/iprt/mangling.h b/include/iprt/mangling.h new file mode 100644 index 00000000..eef92f51 --- /dev/null +++ b/include/iprt/mangling.h @@ -0,0 +1,4320 @@ +/** @file + * IPRT - Symbol Mangling. + * + * This header is used to mangle public IPRT symbol to make it possible to have + * several IPRT version loaded into one symbol space at the same time. To + * enable symbol mangling you create a header which the compiler includes for + * every compilation unit (check out the -include option of gcc). Your header + * will define RT_MANGLER(name) and then include this header to set up the + * actual mappings. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_mangling_h +#define IPRT_INCLUDED_mangling_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef RT_MANGLER +# error "RT_MANGLER is not defined." +#endif + +#ifndef DOXYGEN_RUNNING + +/** @def RT_WITH_MANGLING + * Indicates that we're mangling symbols. */ +# define RT_WITH_MANGLING + + +/* + * Stable functions (alphabetical order): + */ +/* ASM*: + grep -h DECLASM include/iprt/asm.h include/iprt/asm-amd64-x86.h \ + | kmk_sed -e 's/^DECLASM.[^)]*. *\(ASM[^(]*\)[(].*$/# define \1 :RT_MANGLER(\1)\n# define \1_EndProc :RT_MANGLER(\1_EndProc)/' \ + | sort \ + | awk -F: '{ printf("%-55s %s\n", $1, $2);' */ +# define ASMAddFlags RT_MANGLER(ASMAddFlags) +# define ASMAddFlags_EndProc RT_MANGLER(ASMAddFlags_EndProc) +# define ASMAtomicAddU16 RT_MANGLER(ASMAtomicAddU16) +# define ASMAtomicAddU16_EndProc RT_MANGLER(ASMAtomicAddU16_EndProc) +# define ASMAtomicAddU32 RT_MANGLER(ASMAtomicAddU32) +# define ASMAtomicAddU32_EndProc RT_MANGLER(ASMAtomicAddU32_EndProc) +# define ASMAtomicAddU64 RT_MANGLER(ASMAtomicAddU64) +# define ASMAtomicAddU64_EndProc RT_MANGLER(ASMAtomicAddU64_EndProc) +# define ASMAtomicAndU32 RT_MANGLER(ASMAtomicAndU32) +# define ASMAtomicAndU32_EndProc RT_MANGLER(ASMAtomicAndU32_EndProc) +# define ASMAtomicAndU64 RT_MANGLER(ASMAtomicAndU64) +# define ASMAtomicAndU64_EndProc RT_MANGLER(ASMAtomicAndU64_EndProc) +# define ASMAtomicBitClear RT_MANGLER(ASMAtomicBitClear) +# define ASMAtomicBitClear_EndProc RT_MANGLER(ASMAtomicBitClear_EndProc) +# define ASMAtomicBitSet RT_MANGLER(ASMAtomicBitSet) +# define ASMAtomicBitSet_EndProc RT_MANGLER(ASMAtomicBitSet_EndProc) +# define ASMAtomicBitTestAndClear RT_MANGLER(ASMAtomicBitTestAndClear) +# define ASMAtomicBitTestAndClear_EndProc RT_MANGLER(ASMAtomicBitTestAndClear_EndProc) +# define ASMAtomicBitTestAndSet RT_MANGLER(ASMAtomicBitTestAndSet) +# define ASMAtomicBitTestAndSet_EndProc RT_MANGLER(ASMAtomicBitTestAndSet_EndProc) +# define ASMAtomicBitTestAndToggle RT_MANGLER(ASMAtomicBitTestAndToggle) +# define ASMAtomicBitTestAndToggle_EndProc RT_MANGLER(ASMAtomicBitTestAndToggle_EndProc) +# define ASMAtomicBitToggle RT_MANGLER(ASMAtomicBitToggle) +# define ASMAtomicBitToggle_EndProc RT_MANGLER(ASMAtomicBitToggle_EndProc) +# define ASMAtomicCmpXchgExU32 RT_MANGLER(ASMAtomicCmpXchgExU32) +# define ASMAtomicCmpXchgExU32_EndProc RT_MANGLER(ASMAtomicCmpXchgExU32_EndProc) +# define ASMAtomicCmpXchgExU64 RT_MANGLER(ASMAtomicCmpXchgExU64) +# define ASMAtomicCmpXchgExU64_EndProc RT_MANGLER(ASMAtomicCmpXchgExU64_EndProc) +# define ASMAtomicCmpXchgU32 RT_MANGLER(ASMAtomicCmpXchgU32) +# define ASMAtomicCmpXchgU32_EndProc RT_MANGLER(ASMAtomicCmpXchgU32_EndProc) +# define ASMAtomicCmpXchgU64 RT_MANGLER(ASMAtomicCmpXchgU64) +# define ASMAtomicCmpXchgU64_EndProc RT_MANGLER(ASMAtomicCmpXchgU64_EndProc) +# define ASMAtomicCmpXchgU8 RT_MANGLER(ASMAtomicCmpXchgU8) +# define ASMAtomicCmpXchgU8_EndProc RT_MANGLER(ASMAtomicCmpXchgU8_EndProc) +# define ASMAtomicDecU16 RT_MANGLER(ASMAtomicDecU16) +# define ASMAtomicDecU16_EndProc RT_MANGLER(ASMAtomicDecU16_EndProc) +# define ASMAtomicDecU32 RT_MANGLER(ASMAtomicDecU32) +# define ASMAtomicDecU32_EndProc RT_MANGLER(ASMAtomicDecU32_EndProc) +# define ASMAtomicDecU64 RT_MANGLER(ASMAtomicDecU64) +# define ASMAtomicDecU64_EndProc RT_MANGLER(ASMAtomicDecU64_EndProc) +# define ASMAtomicIncU16 RT_MANGLER(ASMAtomicIncU16) +# define ASMAtomicIncU16_EndProc RT_MANGLER(ASMAtomicIncU16_EndProc) +# define ASMAtomicIncU32 RT_MANGLER(ASMAtomicIncU32) +# define ASMAtomicIncU32_EndProc RT_MANGLER(ASMAtomicIncU32_EndProc) +# define ASMAtomicIncU64 RT_MANGLER(ASMAtomicIncU64) +# define ASMAtomicIncU64_EndProc RT_MANGLER(ASMAtomicIncU64_EndProc) +# define ASMAtomicOrU32 RT_MANGLER(ASMAtomicOrU32) +# define ASMAtomicOrU32_EndProc RT_MANGLER(ASMAtomicOrU32_EndProc) +# define ASMAtomicOrU64 RT_MANGLER(ASMAtomicOrU64) +# define ASMAtomicOrU64_EndProc RT_MANGLER(ASMAtomicOrU64_EndProc) +# define ASMAtomicReadU64 RT_MANGLER(ASMAtomicReadU64) +# define ASMAtomicReadU64_EndProc RT_MANGLER(ASMAtomicReadU64_EndProc) +# define ASMAtomicUoAndU32 RT_MANGLER(ASMAtomicUoAndU32) +# define ASMAtomicUoAndU32_EndProc RT_MANGLER(ASMAtomicUoAndU32_EndProc) +# define ASMAtomicUoAndU64 RT_MANGLER(ASMAtomicUoAndU64) +# define ASMAtomicUoAndU64_EndProc RT_MANGLER(ASMAtomicUoAndU64_EndProc) +# define ASMAtomicUoDecU32 RT_MANGLER(ASMAtomicUoDecU32) +# define ASMAtomicUoDecU32_EndProc RT_MANGLER(ASMAtomicUoDecU32_EndProc) +# define ASMAtomicUoIncU32 RT_MANGLER(ASMAtomicUoIncU32) +# define ASMAtomicUoIncU32_EndProc RT_MANGLER(ASMAtomicUoIncU32_EndProc) +# define ASMAtomicUoOrU32 RT_MANGLER(ASMAtomicUoOrU32) +# define ASMAtomicUoOrU32_EndProc RT_MANGLER(ASMAtomicUoOrU32_EndProc) +# define ASMAtomicUoOrU64 RT_MANGLER(ASMAtomicUoOrU64) +# define ASMAtomicUoOrU64_EndProc RT_MANGLER(ASMAtomicUoOrU64_EndProc) +# define ASMAtomicUoReadU64 RT_MANGLER(ASMAtomicUoReadU64) +# define ASMAtomicUoReadU64_EndProc RT_MANGLER(ASMAtomicUoReadU64_EndProc) +# define ASMAtomicUoXorU32 RT_MANGLER(ASMAtomicUoXorU32) +# define ASMAtomicXchgU16 RT_MANGLER(ASMAtomicXchgU16) +# define ASMAtomicXchgU16_EndProc RT_MANGLER(ASMAtomicXchgU16_EndProc) +# define ASMAtomicXchgU32 RT_MANGLER(ASMAtomicXchgU32) +# define ASMAtomicXchgU32_EndProc RT_MANGLER(ASMAtomicXchgU32_EndProc) +# define ASMAtomicXchgU64 RT_MANGLER(ASMAtomicXchgU64) +# define ASMAtomicXchgU64_EndProc RT_MANGLER(ASMAtomicXchgU64_EndProc) +# define ASMAtomicXchgU8 RT_MANGLER(ASMAtomicXchgU8) +# define ASMAtomicXchgU8_EndProc RT_MANGLER(ASMAtomicXchgU8_EndProc) +# define ASMBitClear RT_MANGLER(ASMBitClear) +# define ASMBitClear_EndProc RT_MANGLER(ASMBitClear_EndProc) +# define ASMBitFirstClear RT_MANGLER(ASMBitFirstClear) +# define ASMBitFirstClear_EndProc RT_MANGLER(ASMBitFirstClear_EndProc) +# define ASMBitFirstSet RT_MANGLER(ASMBitFirstSet) +# define ASMBitFirstSet_EndProc RT_MANGLER(ASMBitFirstSet_EndProc) +# define ASMBitFirstSetU16 RT_MANGLER(ASMBitFirstSetU16) +# define ASMBitFirstSetU16_EndProc RT_MANGLER(ASMBitFirstSetU16_EndProc) +# define ASMBitFirstSetU32 RT_MANGLER(ASMBitFirstSetU32) +# define ASMBitFirstSetU32_EndProc RT_MANGLER(ASMBitFirstSetU32_EndProc) +# define ASMBitFirstSetU64 RT_MANGLER(ASMBitFirstSetU64) +# define ASMBitFirstSetU64_EndProc RT_MANGLER(ASMBitFirstSetU64_EndProc) +# define ASMBitLastSetU16 RT_MANGLER(ASMBitLastSetU16) +# define ASMBitLastSetU16_EndProc RT_MANGLER(ASMBitLastSetU16_EndProc) +# define ASMBitLastSetU32 RT_MANGLER(ASMBitLastSetU32) +# define ASMBitLastSetU32_EndProc RT_MANGLER(ASMBitLastSetU32_EndProc) +# define ASMBitLastSetU64 RT_MANGLER(ASMBitLastSetU64) +# define ASMBitLastSetU64_EndProc RT_MANGLER(ASMBitLastSetU64_EndProc) +# define ASMBitNextClear RT_MANGLER(ASMBitNextClear) +# define ASMBitNextClear_EndProc RT_MANGLER(ASMBitNextClear_EndProc) +# define ASMBitNextSet RT_MANGLER(ASMBitNextSet) +# define ASMBitNextSet_EndProc RT_MANGLER(ASMBitNextSet_EndProc) +# define ASMBitSet RT_MANGLER(ASMBitSet) +# define ASMBitSet_EndProc RT_MANGLER(ASMBitSet_EndProc) +# define ASMBitTest RT_MANGLER(ASMBitTest) +# define ASMBitTest_EndProc RT_MANGLER(ASMBitTest_EndProc) +# define ASMBitTestAndClear RT_MANGLER(ASMBitTestAndClear) +# define ASMBitTestAndClear_EndProc RT_MANGLER(ASMBitTestAndClear_EndProc) +# define ASMBitTestAndSet RT_MANGLER(ASMBitTestAndSet) +# define ASMBitTestAndSet_EndProc RT_MANGLER(ASMBitTestAndSet_EndProc) +# define ASMBitTestAndToggle RT_MANGLER(ASMBitTestAndToggle) +# define ASMBitTestAndToggle_EndProc RT_MANGLER(ASMBitTestAndToggle_EndProc) +# define ASMBitToggle RT_MANGLER(ASMBitToggle) +# define ASMBitToggle_EndProc RT_MANGLER(ASMBitToggle_EndProc) +# define ASMByteSwapU16 RT_MANGLER(ASMByteSwapU16) +# define ASMByteSwapU16_EndProc RT_MANGLER(ASMByteSwapU16_EndProc) +# define ASMByteSwapU32 RT_MANGLER(ASMByteSwapU32) +# define ASMByteSwapU32_EndProc RT_MANGLER(ASMByteSwapU32_EndProc) +# define ASMChangeFlags RT_MANGLER(ASMChangeFlags) +# define ASMChangeFlags_EndProc RT_MANGLER(ASMChangeFlags_EndProc) +# define ASMClearFlags RT_MANGLER(ASMClearFlags) +# define ASMClearFlags_EndProc RT_MANGLER(ASMClearFlags_EndProc) +# define ASMCpuId RT_MANGLER(ASMCpuId) +# define ASMCpuId_EAX RT_MANGLER(ASMCpuId_EAX) +# define ASMCpuId_EAX_EndProc RT_MANGLER(ASMCpuId_EAX_EndProc) +# define ASMCpuId_EBX RT_MANGLER(ASMCpuId_EBX) +# define ASMCpuId_EBX_EndProc RT_MANGLER(ASMCpuId_EBX_EndProc) +# define ASMCpuId_ECX RT_MANGLER(ASMCpuId_ECX) +# define ASMCpuId_ECX_EDX RT_MANGLER(ASMCpuId_ECX_EDX) +# define ASMCpuId_ECX_EDX_EndProc RT_MANGLER(ASMCpuId_ECX_EDX_EndProc) +# define ASMCpuId_ECX_EndProc RT_MANGLER(ASMCpuId_ECX_EndProc) +# define ASMCpuId_EDX RT_MANGLER(ASMCpuId_EDX) +# define ASMCpuId_EDX_EndProc RT_MANGLER(ASMCpuId_EDX_EndProc) +# define ASMCpuId_EndProc RT_MANGLER(ASMCpuId_EndProc) +# define ASMCpuId_Idx_ECX RT_MANGLER(ASMCpuId_Idx_ECX) +# define ASMCpuId_Idx_ECX_EndProc RT_MANGLER(ASMCpuId_Idx_ECX_EndProc) +# define ASMCpuIdExSlow RT_MANGLER(ASMCpuIdExSlow) +# define ASMCpuIdExSlow_EndProc RT_MANGLER(ASMCpuIdExSlow_EndProc) +# define ASMGetAndClearDR6 RT_MANGLER(ASMGetAndClearDR6) +# define ASMGetAndClearDR6_EndProc RT_MANGLER(ASMGetAndClearDR6_EndProc) +# define ASMGetApicId RT_MANGLER(ASMGetApicId) +# define ASMGetApicId_EndProc RT_MANGLER(ASMGetApicId_EndProc) +# define ASMGetCR0 RT_MANGLER(ASMGetCR0) +# define ASMGetCR0_EndProc RT_MANGLER(ASMGetCR0_EndProc) +# define ASMGetCR2 RT_MANGLER(ASMGetCR2) +# define ASMGetCR2_EndProc RT_MANGLER(ASMGetCR2_EndProc) +# define ASMGetCR3 RT_MANGLER(ASMGetCR3) +# define ASMGetCR3_EndProc RT_MANGLER(ASMGetCR3_EndProc) +# define ASMGetCR4 RT_MANGLER(ASMGetCR4) +# define ASMGetCR4_EndProc RT_MANGLER(ASMGetCR4_EndProc) +# define ASMGetCR8 RT_MANGLER(ASMGetCR8) +# define ASMGetCR8_EndProc RT_MANGLER(ASMGetCR8_EndProc) +# define ASMGetCS RT_MANGLER(ASMGetCS) +# define ASMGetCS_EndProc RT_MANGLER(ASMGetCS_EndProc) +# define ASMGetDR0 RT_MANGLER(ASMGetDR0) +# define ASMGetDR0_EndProc RT_MANGLER(ASMGetDR0_EndProc) +# define ASMGetDR1 RT_MANGLER(ASMGetDR1) +# define ASMGetDR1_EndProc RT_MANGLER(ASMGetDR1_EndProc) +# define ASMGetDR2 RT_MANGLER(ASMGetDR2) +# define ASMGetDR2_EndProc RT_MANGLER(ASMGetDR2_EndProc) +# define ASMGetDR3 RT_MANGLER(ASMGetDR3) +# define ASMGetDR3_EndProc RT_MANGLER(ASMGetDR3_EndProc) +# define ASMGetDR6 RT_MANGLER(ASMGetDR6) +# define ASMGetDR6_EndProc RT_MANGLER(ASMGetDR6_EndProc) +# define ASMGetDR7 RT_MANGLER(ASMGetDR7) +# define ASMGetDR7_EndProc RT_MANGLER(ASMGetDR7_EndProc) +# define ASMGetDS RT_MANGLER(ASMGetDS) +# define ASMGetDS_EndProc RT_MANGLER(ASMGetDS_EndProc) +# define ASMGetES RT_MANGLER(ASMGetES) +# define ASMGetES_EndProc RT_MANGLER(ASMGetES_EndProc) +# define ASMGetFlags RT_MANGLER(ASMGetFlags) +# define ASMGetFlags_EndProc RT_MANGLER(ASMGetFlags_EndProc) +# define ASMGetFS RT_MANGLER(ASMGetFS) +# define ASMGetFS_EndProc RT_MANGLER(ASMGetFS_EndProc) +# define ASMGetGDTR RT_MANGLER(ASMGetGDTR) +# define ASMGetGDTR_EndProc RT_MANGLER(ASMGetGDTR_EndProc) +# define ASMGetGS RT_MANGLER(ASMGetGS) +# define ASMGetGS_EndProc RT_MANGLER(ASMGetGS_EndProc) +# define ASMGetIDTR RT_MANGLER(ASMGetIDTR) +# define ASMGetIDTR_EndProc RT_MANGLER(ASMGetIDTR_EndProc) +# define ASMGetIdtrLimit RT_MANGLER(ASMGetIdtrLimit) +# define ASMGetIdtrLimit_EndProc RT_MANGLER(ASMGetIdtrLimit_EndProc) +# define ASMGetLDTR RT_MANGLER(ASMGetLDTR) +# define ASMGetLDTR_EndProc RT_MANGLER(ASMGetLDTR_EndProc) +# define ASMGetSegAttr RT_MANGLER(ASMGetSegAttr) +# define ASMGetSegAttr_EndProc RT_MANGLER(ASMGetSegAttr_EndProc) +# define ASMGetSS RT_MANGLER(ASMGetSS) +# define ASMGetSS_EndProc RT_MANGLER(ASMGetSS_EndProc) +# define ASMGetTR RT_MANGLER(ASMGetTR) +# define ASMGetTR_EndProc RT_MANGLER(ASMGetTR_EndProc) +# define ASMGetXcr0 RT_MANGLER(ASMGetXcr0) +# define ASMGetXcr0_EndProc RT_MANGLER(ASMGetXcr0_EndProc) +# define ASMHalt RT_MANGLER(ASMHalt) +# define ASMHalt_EndProc RT_MANGLER(ASMHalt_EndProc) +# define ASMInStrU16 RT_MANGLER(ASMInStrU16) +# define ASMInStrU16_EndProc RT_MANGLER(ASMInStrU16_EndProc) +# define ASMInStrU32 RT_MANGLER(ASMInStrU32) +# define ASMInStrU32_EndProc RT_MANGLER(ASMInStrU32_EndProc) +# define ASMInStrU8 RT_MANGLER(ASMInStrU8) +# define ASMInStrU8_EndProc RT_MANGLER(ASMInStrU8_EndProc) +# define ASMIntDisable RT_MANGLER(ASMIntDisable) +# define ASMIntDisable_EndProc RT_MANGLER(ASMIntDisable_EndProc) +# define ASMIntDisableFlags RT_MANGLER(ASMIntDisableFlags) +# define ASMIntDisableFlags_EndProc RT_MANGLER(ASMIntDisableFlags_EndProc) +# define ASMIntEnable RT_MANGLER(ASMIntEnable) +# define ASMIntEnable_EndProc RT_MANGLER(ASMIntEnable_EndProc) +# define ASMInU16 RT_MANGLER(ASMInU16) +# define ASMInU16_EndProc RT_MANGLER(ASMInU16_EndProc) +# define ASMInU32 RT_MANGLER(ASMInU32) +# define ASMInU32_EndProc RT_MANGLER(ASMInU32_EndProc) +# define ASMInU8 RT_MANGLER(ASMInU8) +# define ASMInU8_EndProc RT_MANGLER(ASMInU8_EndProc) +# define ASMInvalidateInternalCaches RT_MANGLER(ASMInvalidateInternalCaches) +# define ASMInvalidateInternalCaches_EndProc RT_MANGLER(ASMInvalidateInternalCaches_EndProc) +# define ASMInvalidatePage RT_MANGLER(ASMInvalidatePage) +# define ASMInvalidatePage_EndProc RT_MANGLER(ASMInvalidatePage_EndProc) +# define ASMMemFill32 RT_MANGLER(ASMMemFill32) +# define ASMMemFill32_EndProc RT_MANGLER(ASMMemFill32_EndProc) +# define ASMMemFirstNonZero RT_MANGLER(ASMMemFirstNonZero) +# define ASMMemFirstNonZero_EndProc RT_MANGLER(ASMMemFirstNonZero_EndProc) +# define ASMMemFirstMismatchingU8 RT_MANGLER(ASMMemFirstMismatchingU8) +# define ASMMemFirstMismatchingU8_EndProc RT_MANGLER(ASMMemFirstMismatchingU8_EndProc) +# define ASMMemFirstMismatchingU32 RT_MANGLER(ASMMemFirstMismatchingU32) +# define ASMMemFirstMismatchingU32_EndProc RT_MANGLER(ASMMemFirstMismatchingU32_EndProc) +# define ASMMemIsZero RT_MANGLER(ASMMemIsZero) +# define ASMMemIsZero_EndProc RT_MANGLER(ASMMemIsZero_EndProc) +# define ASMMemIsAllU8 RT_MANGLER(ASMMemIsAllU8) +# define ASMMemIsAllU8_EndProc RT_MANGLER(ASMMemIsAllU8_EndProc) +# define ASMMemZero32 RT_MANGLER(ASMMemZero32) +# define ASMMemZero32_EndProc RT_MANGLER(ASMMemZero32_EndProc) +# define ASMMemZeroPage RT_MANGLER(ASMMemZeroPage) +# define ASMMemZeroPage_EndProc RT_MANGLER(ASMMemZeroPage_EndProc) +# define ASMMultU64ByU32DivByU32 RT_MANGLER(ASMMultU64ByU32DivByU32) +# define ASMMultU64ByU32DivByU32_EndProc RT_MANGLER(ASMMultU64ByU32DivByU32_EndProc) +# define ASMNopPause RT_MANGLER(ASMNopPause) +# define ASMNopPause_EndProc RT_MANGLER(ASMNopPause_EndProc) +# define ASMOutStrU16 RT_MANGLER(ASMOutStrU16) +# define ASMOutStrU16_EndProc RT_MANGLER(ASMOutStrU16_EndProc) +# define ASMOutStrU32 RT_MANGLER(ASMOutStrU32) +# define ASMOutStrU32_EndProc RT_MANGLER(ASMOutStrU32_EndProc) +# define ASMOutStrU8 RT_MANGLER(ASMOutStrU8) +# define ASMOutStrU8_EndProc RT_MANGLER(ASMOutStrU8_EndProc) +# define ASMOutU16 RT_MANGLER(ASMOutU16) +# define ASMOutU16_EndProc RT_MANGLER(ASMOutU16_EndProc) +# define ASMOutU32 RT_MANGLER(ASMOutU32) +# define ASMOutU32_EndProc RT_MANGLER(ASMOutU32_EndProc) +# define ASMOutU8 RT_MANGLER(ASMOutU8) +# define ASMOutU8_EndProc RT_MANGLER(ASMOutU8_EndProc) +# define ASMProbeReadByte RT_MANGLER(ASMProbeReadByte) +# define ASMProbeReadByte_EndProc RT_MANGLER(ASMProbeReadByte_EndProc) +# define ASMRdMsr RT_MANGLER(ASMRdMsr) +# define ASMRdMsr_EndProc RT_MANGLER(ASMRdMsr_EndProc) +# define ASMRdMsr_High RT_MANGLER(ASMRdMsr_High) +# define ASMRdMsr_High_EndProc RT_MANGLER(ASMRdMsr_High_EndProc) +# define ASMRdMsr_Low RT_MANGLER(ASMRdMsr_Low) +# define ASMRdMsr_Low_EndProc RT_MANGLER(ASMRdMsr_Low_EndProc) +# define ASMRdMsrEx RT_MANGLER(ASMRdMsrEx) +# define ASMRdMsrEx_EndProc RT_MANGLER(ASMRdMsrEx_EndProc) +# define ASMReadTSC RT_MANGLER(ASMReadTSC) +# define ASMReadTSC_EndProc RT_MANGLER(ASMReadTSC_EndProc) +# define ASMReadTscWithAux RT_MANGLER(ASMReadTscWithAux) +# define ASMReadTscWithAux_EndProc RT_MANGLER(ASMReadTscWithAux_EndProc) +# define ASMReloadCR3 RT_MANGLER(ASMReloadCR3) +# define ASMReloadCR3_EndProc RT_MANGLER(ASMReloadCR3_EndProc) +# define ASMRotateLeftU32 RT_MANGLER(ASMRotateLeftU32) +# define ASMRotateLeftU32_EndProc RT_MANGLER(ASMRotateLeftU32_EndProc) +# define ASMRotateRightU32 RT_MANGLER(ASMRotateRightU32) +# define ASMRotateRightU32_EndProc RT_MANGLER(ASMRotateRightU32_EndProc) +# define ASMSerializeInstructionCpuId RT_MANGLER(ASMSerializeInstructionCpuId) +# define ASMSerializeInstructionCpuId_EndProc RT_MANGLER(ASMSerializeInstructionCpuId_EndProc) +# define ASMSerializeInstructionIRet RT_MANGLER(ASMSerializeInstructionIRet) +# define ASMSerializeInstructionIRet_EndProc RT_MANGLER(ASMSerializeInstructionIRet_EndProc) +# define ASMSerializeInstructionRdTscp RT_MANGLER(ASMSerializeInstructionRdTscp) +# define ASMSerializeInstructionRdTscp_EndProc RT_MANGLER(ASMSerializeInstructionRdTscp_EndProc) +# define ASMSetCR0 RT_MANGLER(ASMSetCR0) +# define ASMSetCR0_EndProc RT_MANGLER(ASMSetCR0_EndProc) +# define ASMSetCR2 RT_MANGLER(ASMSetCR2) +# define ASMSetCR2_EndProc RT_MANGLER(ASMSetCR2_EndProc) +# define ASMSetCR3 RT_MANGLER(ASMSetCR3) +# define ASMSetCR3_EndProc RT_MANGLER(ASMSetCR3_EndProc) +# define ASMSetCR4 RT_MANGLER(ASMSetCR4) +# define ASMSetCR4_EndProc RT_MANGLER(ASMSetCR4_EndProc) +# define ASMSetDR0 RT_MANGLER(ASMSetDR0) +# define ASMSetDR0_EndProc RT_MANGLER(ASMSetDR0_EndProc) +# define ASMSetDR1 RT_MANGLER(ASMSetDR1) +# define ASMSetDR1_EndProc RT_MANGLER(ASMSetDR1_EndProc) +# define ASMSetDR2 RT_MANGLER(ASMSetDR2) +# define ASMSetDR2_EndProc RT_MANGLER(ASMSetDR2_EndProc) +# define ASMSetDR3 RT_MANGLER(ASMSetDR3) +# define ASMSetDR3_EndProc RT_MANGLER(ASMSetDR3_EndProc) +# define ASMSetDR6 RT_MANGLER(ASMSetDR6) +# define ASMSetDR6_EndProc RT_MANGLER(ASMSetDR6_EndProc) +# define ASMSetDR7 RT_MANGLER(ASMSetDR7) +# define ASMSetDR7_EndProc RT_MANGLER(ASMSetDR7_EndProc) +# define ASMSetFlags RT_MANGLER(ASMSetFlags) +# define ASMSetFlags_EndProc RT_MANGLER(ASMSetFlags_EndProc) +# define ASMSetGDTR RT_MANGLER(ASMSetGDTR) +# define ASMSetGDTR_EndProc RT_MANGLER(ASMSetGDTR_EndProc) +# define ASMSetIDTR RT_MANGLER(ASMSetIDTR) +# define ASMSetIDTR_EndProc RT_MANGLER(ASMSetIDTR_EndProc) +# define ASMSetXcr0 RT_MANGLER(ASMSetXcr0) +# define ASMSetXcr0_EndProc RT_MANGLER(ASMSetXcr0_EndProc) +# define ASMWriteBackAndInvalidateCaches RT_MANGLER(ASMWriteBackAndInvalidateCaches) +# define ASMWriteBackAndInvalidateCaches_EndProc RT_MANGLER(ASMWriteBackAndInvalidateCaches_EndProc) +# define ASMWrMsr RT_MANGLER(ASMWrMsr) +# define ASMWrMsr_EndProc RT_MANGLER(ASMWrMsr_EndProc) +# define ASMWrMsrEx RT_MANGLER(ASMWrMsrEx) +# define ASMWrMsrEx_EndProc RT_MANGLER(ASMWrMsrEx_EndProc) +# define ASMXRstor RT_MANGLER(ASMXRstor) +# define ASMXRstor_EndProc RT_MANGLER(ASMXRstor_EndProc) +# define ASMXSave RT_MANGLER(ASMXSave) +# define ASMXSave_EndProc RT_MANGLER(ASMXSave_EndProc) +# define ASMFxRstor RT_MANGLER(ASMFxRstor) +# define ASMFxRstor_EndProc RT_MANGLER(ASMFxRstor_EndProc) +# define ASMFxSave RT_MANGLER(ASMFxSave) +# define ASMFxSave_EndProc RT_MANGLER(ASMFxSave_EndProc) + +# define RTAssertAreQuiet RT_MANGLER(RTAssertAreQuiet) +# define RTAssertMayPanic RT_MANGLER(RTAssertMayPanic) +# define RTAssertMsg1 RT_MANGLER(RTAssertMsg1) +# define RTAssertMsg1Weak RT_MANGLER(RTAssertMsg1Weak) +# define RTAssertMsg2 RT_MANGLER(RTAssertMsg2) +# define RTAssertMsg2Add RT_MANGLER(RTAssertMsg2Add) +# define RTAssertMsg2AddV RT_MANGLER(RTAssertMsg2AddV) +# define RTAssertMsg2AddWeak RT_MANGLER(RTAssertMsg2AddWeak) +# define RTAssertMsg2AddWeakV RT_MANGLER(RTAssertMsg2AddWeakV) +# define RTAssertMsg2V RT_MANGLER(RTAssertMsg2V) +# define RTAssertMsg2Weak RT_MANGLER(RTAssertMsg2Weak) +# define RTAssertMsg2WeakV RT_MANGLER(RTAssertMsg2WeakV) +# define RTAssertSetMayPanic RT_MANGLER(RTAssertSetMayPanic) +# define RTAssertSetQuiet RT_MANGLER(RTAssertSetQuiet) +# define RTAssertShouldPanic RT_MANGLER(RTAssertShouldPanic) +# define RTAvlGCPhysDestroy RT_MANGLER(RTAvlGCPhysDestroy) +# define RTAvlGCPhysDoWithAll RT_MANGLER(RTAvlGCPhysDoWithAll) +# define RTAvlGCPhysGet RT_MANGLER(RTAvlGCPhysGet) +# define RTAvlGCPhysGetBestFit RT_MANGLER(RTAvlGCPhysGetBestFit) +# define RTAvlGCPhysInsert RT_MANGLER(RTAvlGCPhysInsert) +# define RTAvlGCPhysRemove RT_MANGLER(RTAvlGCPhysRemove) +# define RTAvlGCPhysRemoveBestFit RT_MANGLER(RTAvlGCPhysRemoveBestFit) +# define RTAvlGCPtrDestroy RT_MANGLER(RTAvlGCPtrDestroy) +# define RTAvlGCPtrDoWithAll RT_MANGLER(RTAvlGCPtrDoWithAll) +# define RTAvlGCPtrGet RT_MANGLER(RTAvlGCPtrGet) +# define RTAvlGCPtrGetBestFit RT_MANGLER(RTAvlGCPtrGetBestFit) +# define RTAvlGCPtrInsert RT_MANGLER(RTAvlGCPtrInsert) +# define RTAvlGCPtrRemove RT_MANGLER(RTAvlGCPtrRemove) +# define RTAvlGCPtrRemoveBestFit RT_MANGLER(RTAvlGCPtrRemoveBestFit) +# define RTAvlHCPhysDestroy RT_MANGLER(RTAvlHCPhysDestroy) +# define RTAvlHCPhysDoWithAll RT_MANGLER(RTAvlHCPhysDoWithAll) +# define RTAvlHCPhysGet RT_MANGLER(RTAvlHCPhysGet) +# define RTAvlHCPhysGetBestFit RT_MANGLER(RTAvlHCPhysGetBestFit) +# define RTAvlHCPhysInsert RT_MANGLER(RTAvlHCPhysInsert) +# define RTAvlHCPhysRemove RT_MANGLER(RTAvlHCPhysRemove) +# define RTAvlHCPhysRemoveBestFit RT_MANGLER(RTAvlHCPhysRemoveBestFit) +# define RTAvllU32Destroy RT_MANGLER(RTAvllU32Destroy) +# define RTAvllU32DoWithAll RT_MANGLER(RTAvllU32DoWithAll) +# define RTAvllU32Get RT_MANGLER(RTAvllU32Get) +# define RTAvllU32GetBestFit RT_MANGLER(RTAvllU32GetBestFit) +# define RTAvllU32Insert RT_MANGLER(RTAvllU32Insert) +# define RTAvllU32Remove RT_MANGLER(RTAvllU32Remove) +# define RTAvllU32RemoveBestFit RT_MANGLER(RTAvllU32RemoveBestFit) +# define RTAvllU32RemoveNode RT_MANGLER(RTAvllU32RemoveNode) +# define RTAvloGCPhysDestroy RT_MANGLER(RTAvloGCPhysDestroy) +# define RTAvloGCPhysDoWithAll RT_MANGLER(RTAvloGCPhysDoWithAll) +# define RTAvloGCPhysGet RT_MANGLER(RTAvloGCPhysGet) +# define RTAvloGCPhysGetBestFit RT_MANGLER(RTAvloGCPhysGetBestFit) +# define RTAvloGCPhysInsert RT_MANGLER(RTAvloGCPhysInsert) +# define RTAvloGCPhysRemove RT_MANGLER(RTAvloGCPhysRemove) +# define RTAvloGCPhysRemoveBestFit RT_MANGLER(RTAvloGCPhysRemoveBestFit) +# define RTAvloGCPtrDestroy RT_MANGLER(RTAvloGCPtrDestroy) +# define RTAvloGCPtrDoWithAll RT_MANGLER(RTAvloGCPtrDoWithAll) +# define RTAvloGCPtrGet RT_MANGLER(RTAvloGCPtrGet) +# define RTAvloGCPtrGetBestFit RT_MANGLER(RTAvloGCPtrGetBestFit) +# define RTAvloGCPtrInsert RT_MANGLER(RTAvloGCPtrInsert) +# define RTAvloGCPtrRemove RT_MANGLER(RTAvloGCPtrRemove) +# define RTAvloGCPtrRemoveBestFit RT_MANGLER(RTAvloGCPtrRemoveBestFit) +# define RTAvloHCPhysDestroy RT_MANGLER(RTAvloHCPhysDestroy) +# define RTAvloHCPhysDoWithAll RT_MANGLER(RTAvloHCPhysDoWithAll) +# define RTAvloHCPhysGet RT_MANGLER(RTAvloHCPhysGet) +# define RTAvloHCPhysGetBestFit RT_MANGLER(RTAvloHCPhysGetBestFit) +# define RTAvloHCPhysInsert RT_MANGLER(RTAvloHCPhysInsert) +# define RTAvloHCPhysRemove RT_MANGLER(RTAvloHCPhysRemove) +# define RTAvloHCPhysRemoveBestFit RT_MANGLER(RTAvloHCPhysRemoveBestFit) +# define RTAvloIOPortDestroy RT_MANGLER(RTAvloIOPortDestroy) +# define RTAvloIOPortDoWithAll RT_MANGLER(RTAvloIOPortDoWithAll) +# define RTAvloIOPortGet RT_MANGLER(RTAvloIOPortGet) +# define RTAvloIOPortGetBestFit RT_MANGLER(RTAvloIOPortGetBestFit) +# define RTAvloIOPortInsert RT_MANGLER(RTAvloIOPortInsert) +# define RTAvloIOPortRemove RT_MANGLER(RTAvloIOPortRemove) +# define RTAvloIOPortRemoveBestFit RT_MANGLER(RTAvloIOPortRemoveBestFit) +# define RTAvloU32Destroy RT_MANGLER(RTAvloU32Destroy) +# define RTAvloU32DoWithAll RT_MANGLER(RTAvloU32DoWithAll) +# define RTAvloU32Get RT_MANGLER(RTAvloU32Get) +# define RTAvloU32GetBestFit RT_MANGLER(RTAvloU32GetBestFit) +# define RTAvloU32Insert RT_MANGLER(RTAvloU32Insert) +# define RTAvloU32Remove RT_MANGLER(RTAvloU32Remove) +# define RTAvloU32RemoveBestFit RT_MANGLER(RTAvloU32RemoveBestFit) +# define RTAvlPVDestroy RT_MANGLER(RTAvlPVDestroy) +# define RTAvlPVDoWithAll RT_MANGLER(RTAvlPVDoWithAll) +# define RTAvlPVGet RT_MANGLER(RTAvlPVGet) +# define RTAvlPVGetBestFit RT_MANGLER(RTAvlPVGetBestFit) +# define RTAvlPVInsert RT_MANGLER(RTAvlPVInsert) +# define RTAvlPVRemove RT_MANGLER(RTAvlPVRemove) +# define RTAvlPVRemoveBestFit RT_MANGLER(RTAvlPVRemoveBestFit) +# define RTAvlrFileOffsetDestroy RT_MANGLER(RTAvlrFileOffsetDestroy) +# define RTAvlrFileOffsetDoWithAll RT_MANGLER(RTAvlrFileOffsetDoWithAll) +# define RTAvlrFileOffsetGet RT_MANGLER(RTAvlrFileOffsetGet) +# define RTAvlrFileOffsetGetBestFit RT_MANGLER(RTAvlrFileOffsetGetBestFit) +# define RTAvlrFileOffsetGetLeft RT_MANGLER(RTAvlrFileOffsetGetLeft) +# define RTAvlrFileOffsetGetRight RT_MANGLER(RTAvlrFileOffsetGetRight) +# define RTAvlrFileOffsetGetRoot RT_MANGLER(RTAvlrFileOffsetGetRoot) +# define RTAvlrFileOffsetInsert RT_MANGLER(RTAvlrFileOffsetInsert) +# define RTAvlrFileOffsetRangeGet RT_MANGLER(RTAvlrFileOffsetRangeGet) +# define RTAvlrFileOffsetRangeRemove RT_MANGLER(RTAvlrFileOffsetRangeRemove) +# define RTAvlrFileOffsetRemove RT_MANGLER(RTAvlrFileOffsetRemove) +# define RTAvlrGCPtrDestroy RT_MANGLER(RTAvlrGCPtrDestroy) +# define RTAvlrGCPtrDoWithAll RT_MANGLER(RTAvlrGCPtrDoWithAll) +# define RTAvlrGCPtrGet RT_MANGLER(RTAvlrGCPtrGet) +# define RTAvlrGCPtrGetBestFit RT_MANGLER(RTAvlrGCPtrGetBestFit) +# define RTAvlrGCPtrGetLeft RT_MANGLER(RTAvlrGCPtrGetLeft) +# define RTAvlrGCPtrGetRight RT_MANGLER(RTAvlrGCPtrGetRight) +# define RTAvlrGCPtrGetRoot RT_MANGLER(RTAvlrGCPtrGetRoot) +# define RTAvlrGCPtrInsert RT_MANGLER(RTAvlrGCPtrInsert) +# define RTAvlrGCPtrRangeGet RT_MANGLER(RTAvlrGCPtrRangeGet) +# define RTAvlrGCPtrRangeRemove RT_MANGLER(RTAvlrGCPtrRangeRemove) +# define RTAvlrGCPtrRemove RT_MANGLER(RTAvlrGCPtrRemove) +# define RTAvlroGCPhysDestroy RT_MANGLER(RTAvlroGCPhysDestroy) +# define RTAvlroGCPhysDoWithAll RT_MANGLER(RTAvlroGCPhysDoWithAll) +# define RTAvlroGCPhysGet RT_MANGLER(RTAvlroGCPhysGet) +# define RTAvlroGCPhysGetBestFit RT_MANGLER(RTAvlroGCPhysGetBestFit) +# define RTAvlroGCPhysGetLeft RT_MANGLER(RTAvlroGCPhysGetLeft) +# define RTAvlroGCPhysGetRight RT_MANGLER(RTAvlroGCPhysGetRight) +# define RTAvlroGCPhysGetRoot RT_MANGLER(RTAvlroGCPhysGetRoot) +# define RTAvlroGCPhysInsert RT_MANGLER(RTAvlroGCPhysInsert) +# define RTAvlroGCPhysRangeGet RT_MANGLER(RTAvlroGCPhysRangeGet) +# define RTAvlroGCPhysRangeRemove RT_MANGLER(RTAvlroGCPhysRangeRemove) +# define RTAvlroGCPhysRemove RT_MANGLER(RTAvlroGCPhysRemove) +# define RTAvlroGCPtrDestroy RT_MANGLER(RTAvlroGCPtrDestroy) +# define RTAvlroGCPtrDoWithAll RT_MANGLER(RTAvlroGCPtrDoWithAll) +# define RTAvlroGCPtrGet RT_MANGLER(RTAvlroGCPtrGet) +# define RTAvlroGCPtrGetBestFit RT_MANGLER(RTAvlroGCPtrGetBestFit) +# define RTAvlroGCPtrGetLeft RT_MANGLER(RTAvlroGCPtrGetLeft) +# define RTAvlroGCPtrGetRight RT_MANGLER(RTAvlroGCPtrGetRight) +# define RTAvlroGCPtrGetRoot RT_MANGLER(RTAvlroGCPtrGetRoot) +# define RTAvlroGCPtrInsert RT_MANGLER(RTAvlroGCPtrInsert) +# define RTAvlroGCPtrRangeGet RT_MANGLER(RTAvlroGCPtrRangeGet) +# define RTAvlroGCPtrRangeRemove RT_MANGLER(RTAvlroGCPtrRangeRemove) +# define RTAvlroGCPtrRemove RT_MANGLER(RTAvlroGCPtrRemove) +# define RTAvlroIOPortDestroy RT_MANGLER(RTAvlroIOPortDestroy) +# define RTAvlroIOPortDoWithAll RT_MANGLER(RTAvlroIOPortDoWithAll) +# define RTAvlroIOPortGet RT_MANGLER(RTAvlroIOPortGet) +# define RTAvlroIOPortInsert RT_MANGLER(RTAvlroIOPortInsert) +# define RTAvlroIOPortRangeGet RT_MANGLER(RTAvlroIOPortRangeGet) +# define RTAvlroIOPortRangeRemove RT_MANGLER(RTAvlroIOPortRangeRemove) +# define RTAvlroIOPortRemove RT_MANGLER(RTAvlroIOPortRemove) +# define RTAvlrooGCPtrDestroy RT_MANGLER(RTAvlrooGCPtrDestroy) +# define RTAvlrooGCPtrDoWithAll RT_MANGLER(RTAvlrooGCPtrDoWithAll) +# define RTAvlrooGCPtrGet RT_MANGLER(RTAvlrooGCPtrGet) +# define RTAvlrooGCPtrGetBestFit RT_MANGLER(RTAvlrooGCPtrGetBestFit) +# define RTAvlrooGCPtrGetLeft RT_MANGLER(RTAvlrooGCPtrGetLeft) +# define RTAvlrooGCPtrGetNextEqual RT_MANGLER(RTAvlrooGCPtrGetNextEqual) +# define RTAvlrooGCPtrGetRight RT_MANGLER(RTAvlrooGCPtrGetRight) +# define RTAvlrooGCPtrGetRoot RT_MANGLER(RTAvlrooGCPtrGetRoot) +# define RTAvlrooGCPtrInsert RT_MANGLER(RTAvlrooGCPtrInsert) +# define RTAvlrooGCPtrRangeGet RT_MANGLER(RTAvlrooGCPtrRangeGet) +# define RTAvlrooGCPtrRangeRemove RT_MANGLER(RTAvlrooGCPtrRangeRemove) +# define RTAvlrooGCPtrRemove RT_MANGLER(RTAvlrooGCPtrRemove) +# define RTAvlrPVDestroy RT_MANGLER(RTAvlrPVDestroy) +# define RTAvlrPVDoWithAll RT_MANGLER(RTAvlrPVDoWithAll) +# define RTAvlrPVGet RT_MANGLER(RTAvlrPVGet) +# define RTAvlrPVGetBestFit RT_MANGLER(RTAvlrPVGetBestFit) +# define RTAvlrPVInsert RT_MANGLER(RTAvlrPVInsert) +# define RTAvlrPVRangeGet RT_MANGLER(RTAvlrPVRangeGet) +# define RTAvlrPVRangeRemove RT_MANGLER(RTAvlrPVRangeRemove) +# define RTAvlrPVRemove RT_MANGLER(RTAvlrPVRemove) +# define RTAvlrPVRemoveBestFit RT_MANGLER(RTAvlrPVRemoveBestFit) +# define RTAvlrU64Destroy RT_MANGLER(RTAvlrU64Destroy) +# define RTAvlrU64DoWithAll RT_MANGLER(RTAvlrU64DoWithAll) +# define RTAvlrU64Get RT_MANGLER(RTAvlrU64Get) +# define RTAvlrU64GetBestFit RT_MANGLER(RTAvlrU64GetBestFit) +# define RTAvlrU64Insert RT_MANGLER(RTAvlrU64Insert) +# define RTAvlrU64RangeGet RT_MANGLER(RTAvlrU64RangeGet) +# define RTAvlrU64RangeRemove RT_MANGLER(RTAvlrU64RangeRemove) +# define RTAvlrU64Remove RT_MANGLER(RTAvlrU64Remove) +# define RTAvlrU64RemoveBestFit RT_MANGLER(RTAvlrU64RemoveBestFit) +# define RTAvlrUIntPtrDestroy RT_MANGLER(RTAvlrUIntPtrDestroy) +# define RTAvlrUIntPtrDoWithAll RT_MANGLER(RTAvlrUIntPtrDoWithAll) +# define RTAvlrUIntPtrGet RT_MANGLER(RTAvlrUIntPtrGet) +# define RTAvlrUIntPtrGetBestFit RT_MANGLER(RTAvlrUIntPtrGetBestFit) +# define RTAvlrUIntPtrGetLeft RT_MANGLER(RTAvlrUIntPtrGetLeft) +# define RTAvlrUIntPtrGetRight RT_MANGLER(RTAvlrUIntPtrGetRight) +# define RTAvlrUIntPtrGetRoot RT_MANGLER(RTAvlrUIntPtrGetRoot) +# define RTAvlrUIntPtrInsert RT_MANGLER(RTAvlrUIntPtrInsert) +# define RTAvlrUIntPtrRangeGet RT_MANGLER(RTAvlrUIntPtrRangeGet) +# define RTAvlrUIntPtrRangeRemove RT_MANGLER(RTAvlrUIntPtrRangeRemove) +# define RTAvlrUIntPtrRemove RT_MANGLER(RTAvlrUIntPtrRemove) +# define RTAvlU32Destroy RT_MANGLER(RTAvlU32Destroy) +# define RTAvlU32DoWithAll RT_MANGLER(RTAvlU32DoWithAll) +# define RTAvlU32Get RT_MANGLER(RTAvlU32Get) +# define RTAvlU32GetBestFit RT_MANGLER(RTAvlU32GetBestFit) +# define RTAvlU32Insert RT_MANGLER(RTAvlU32Insert) +# define RTAvlU32Remove RT_MANGLER(RTAvlU32Remove) +# define RTAvlU32RemoveBestFit RT_MANGLER(RTAvlU32RemoveBestFit) +# define RTAvlU64Destroy RT_MANGLER(RTAvlU64Destroy) +# define RTAvlU64DoWithAll RT_MANGLER(RTAvlU64DoWithAll) +# define RTAvlU64Get RT_MANGLER(RTAvlU64Get) +# define RTAvlU64GetBestFit RT_MANGLER(RTAvlU64GetBestFit) +# define RTAvlU64Insert RT_MANGLER(RTAvlU64Insert) +# define RTAvlU64Remove RT_MANGLER(RTAvlU64Remove) +# define RTAvlU64RemoveBestFit RT_MANGLER(RTAvlU64RemoveBestFit) +# define RTAvlUIntPtrDestroy RT_MANGLER(RTAvlUIntPtrDestroy) +# define RTAvlUIntPtrDoWithAll RT_MANGLER(RTAvlUIntPtrDoWithAll) +# define RTAvlUIntPtrGet RT_MANGLER(RTAvlUIntPtrGet) +# define RTAvlUIntPtrGetBestFit RT_MANGLER(RTAvlUIntPtrGetBestFit) +# define RTAvlUIntPtrGetLeft RT_MANGLER(RTAvlUIntPtrGetLeft) +# define RTAvlUIntPtrGetRight RT_MANGLER(RTAvlUIntPtrGetRight) +# define RTAvlUIntPtrGetRoot RT_MANGLER(RTAvlUIntPtrGetRoot) +# define RTAvlUIntPtrInsert RT_MANGLER(RTAvlUIntPtrInsert) +# define RTAvlUIntPtrRemove RT_MANGLER(RTAvlUIntPtrRemove) +# define RTAvlULDestroy RT_MANGLER(RTAvlULDestroy) +# define RTAvlULDoWithAll RT_MANGLER(RTAvlULDoWithAll) +# define RTAvlULGet RT_MANGLER(RTAvlULGet) +# define RTAvlULGetBestFit RT_MANGLER(RTAvlULGetBestFit) +# define RTAvlULInsert RT_MANGLER(RTAvlULInsert) +# define RTAvlULRemove RT_MANGLER(RTAvlULRemove) +# define RTAvlULRemoveBestFit RT_MANGLER(RTAvlULRemoveBestFit) +# define RTBase64Decode RT_MANGLER(RTBase64Decode) +# define RTBase64DecodeEx RT_MANGLER(RTBase64DecodeEx) +# define RTBase64DecodedSize RT_MANGLER(RTBase64DecodedSize) +# define RTBase64DecodedSizeEx RT_MANGLER(RTBase64DecodedSizeEx) +# define RTBase64DecodeUtf16 RT_MANGLER(RTBase64DecodeUtf16) +# define RTBase64DecodeUtf16Ex RT_MANGLER(RTBase64DecodeUtf16Ex) +# define RTBase64DecodedUtf16Size RT_MANGLER(RTBase64DecodedUtf16Size) +# define RTBase64DecodedUtf16SizeEx RT_MANGLER(RTBase64DecodedUtf16SizeEx) +# define RTBase64Encode RT_MANGLER(RTBase64Encode) +# define RTBase64EncodeEx RT_MANGLER(RTBase64EncodeEx) +# define RTBase64EncodedLength RT_MANGLER(RTBase64EncodedLength) +# define RTBase64EncodedLengthEx RT_MANGLER(RTBase64EncodedLengthEx) +# define RTBase64EncodeUtf16 RT_MANGLER(RTBase64EncodeUtf16) +# define RTBase64EncodeUtf16Ex RT_MANGLER(RTBase64EncodeUtf16Ex) +# define RTBase64EncodedUtf16Length RT_MANGLER(RTBase64EncodedUtf16Length) +# define RTBase64EncodedUtf16LengthEx RT_MANGLER(RTBase64EncodedUtf16LengthEx) +# define RTBldCfgCompiler RT_MANGLER(RTBldCfgCompiler) +# define RTBldCfgRevision RT_MANGLER(RTBldCfgRevision) +# define RTBldCfgRevisionStr RT_MANGLER(RTBldCfgRevisionStr) +# define RTBldCfgTarget RT_MANGLER(RTBldCfgTarget) +# define RTBldCfgTargetArch RT_MANGLER(RTBldCfgTargetArch) +# define RTBldCfgTargetDotArch RT_MANGLER(RTBldCfgTargetDotArch) +# define RTBldCfgType RT_MANGLER(RTBldCfgType) +# define RTBldCfgVersion RT_MANGLER(RTBldCfgVersion) +# define RTBldCfgVersionBuild RT_MANGLER(RTBldCfgVersionBuild) +# define RTBldCfgVersionMajor RT_MANGLER(RTBldCfgVersionMajor) +# define RTBldCfgVersionMinor RT_MANGLER(RTBldCfgVersionMinor) +# define RTCdromOpen RT_MANGLER(RTCdromOpen) +# define RTCdromRetain RT_MANGLER(RTCdromRetain) +# define RTCdromRelease RT_MANGLER(RTCdromRelease) +# define RTCdromQueryMountPoint RT_MANGLER(RTCdromQueryMountPoint) +# define RTCdromUnmount RT_MANGLER(RTCdromUnmount) +# define RTCdromEject RT_MANGLER(RTCdromEject) +# define RTCdromLock RT_MANGLER(RTCdromLock) +# define RTCdromUnlock RT_MANGLER(RTCdromUnlock) +# define RTCdromCount RT_MANGLER(RTCdromCount) +# define RTCdromOrdinalToName RT_MANGLER(RTCdromOrdinalToName) +# define RTCdromOpenByOrdinal RT_MANGLER(RTCdromOpenByOrdinal) +# define RTCidrStrToIPv4 RT_MANGLER(RTCidrStrToIPv4) +# define RTCircBufAcquireReadBlock RT_MANGLER(RTCircBufAcquireReadBlock) +# define RTCircBufAcquireWriteBlock RT_MANGLER(RTCircBufAcquireWriteBlock) +# define RTCircBufCreate RT_MANGLER(RTCircBufCreate) +# define RTCircBufDestroy RT_MANGLER(RTCircBufDestroy) +# define RTCircBufFree RT_MANGLER(RTCircBufFree) +# define RTCircBufIsReading RT_MANGLER(RTCircBufIsReading) +# define RTCircBufIsWriting RT_MANGLER(RTCircBufIsWriting) +# define RTCircBufOffsetRead RT_MANGLER(RTCircBufOffsetRead) +# define RTCircBufOffsetWrite RT_MANGLER(RTCircBufOffsetWrite) +# define RTCircBufReleaseReadBlock RT_MANGLER(RTCircBufReleaseReadBlock) +# define RTCircBufReleaseWriteBlock RT_MANGLER(RTCircBufReleaseWriteBlock) +# define RTCircBufReset RT_MANGLER(RTCircBufReset) +# define RTCircBufSize RT_MANGLER(RTCircBufSize) +# define RTCircBufUsed RT_MANGLER(RTCircBufUsed) +# define RTCoreDumperDisable RT_MANGLER(RTCoreDumperDisable) /* solaris */ +# define RTCoreDumperSetup RT_MANGLER(RTCoreDumperSetup) /* solaris */ +# define RTCoreDumperTakeDump RT_MANGLER(RTCoreDumperTakeDump) /* solaris */ +# define RTCrc16Ccitt RT_MANGLER(RTCrc16Ccitt) +# define RTCrc16CcittProcess RT_MANGLER(RTCrc16CcittProcess) +# define RTCrc16CcittFinish RT_MANGLER(RTCrc16CcittFinish) +# define RTCrc16CcittStart RT_MANGLER(RTCrc16CcittStart) +# define RTCrc32 RT_MANGLER(RTCrc32) +# define RTCrc32Finish RT_MANGLER(RTCrc32Finish) +# define RTCrc32Process RT_MANGLER(RTCrc32Process) +# define RTCrc32Start RT_MANGLER(RTCrc32Start) +# define RTCrc32C RT_MANGLER(RTCrc32C) +# define RTCrc32CFinish RT_MANGLER(RTCrc32CFinish) +# define RTCrc32CProcess RT_MANGLER(RTCrc32CProcess) +# define RTCrc32CStart RT_MANGLER(RTCrc32CStart) +# define RTCrc64 RT_MANGLER(RTCrc64) +# define RTCrc64Finish RT_MANGLER(RTCrc64Finish) +# define RTCrc64Process RT_MANGLER(RTCrc64Process) +# define RTCrc64Start RT_MANGLER(RTCrc64Start) +# define RTCrcAdler32 RT_MANGLER(RTCrcAdler32) +# define RTCrcAdler32Finish RT_MANGLER(RTCrcAdler32Finish) +# define RTCrcAdler32Process RT_MANGLER(RTCrcAdler32Process) +# define RTCrcAdler32Start RT_MANGLER(RTCrcAdler32Start) +# define RTCritSectDelete RT_MANGLER(RTCritSectDelete) +# define RTCritSectEnter RT_MANGLER(RTCritSectEnter) +# define RTCritSectEnterDebug RT_MANGLER(RTCritSectEnterDebug) +# define RTCritSectEnterMultiple RT_MANGLER(RTCritSectEnterMultiple) +# define RTCritSectEnterMultipleDebug RT_MANGLER(RTCritSectEnterMultipleDebug) +# define RTCritSectInit RT_MANGLER(RTCritSectInit) +# define RTCritSectInitEx RT_MANGLER(RTCritSectInitEx) +# define RTCritSectLeave RT_MANGLER(RTCritSectLeave) +# define RTCritSectLeaveMultiple RT_MANGLER(RTCritSectLeaveMultiple) +# define RTCritSectSetSubClass RT_MANGLER(RTCritSectSetSubClass) +# define RTCritSectTryEnter RT_MANGLER(RTCritSectTryEnter) +# define RTCritSectTryEnterDebug RT_MANGLER(RTCritSectTryEnterDebug) +# define RTCritSectRwDelete RT_MANGLER(RTCritSectRwDelete) +# define RTCritSectRwEnterExcl RT_MANGLER(RTCritSectRwEnterExcl) +# define RTCritSectRwEnterExclDebug RT_MANGLER(RTCritSectRwEnterExclDebug) +# define RTCritSectRwEnterShared RT_MANGLER(RTCritSectRwEnterShared) +# define RTCritSectRwEnterSharedDebug RT_MANGLER(RTCritSectRwEnterSharedDebug) +# define RTCritSectRwGetReadCount RT_MANGLER(RTCritSectRwGetReadCount) +# define RTCritSectRwGetWriteRecursion RT_MANGLER(RTCritSectRwGetWriteRecursion) +# define RTCritSectRwGetWriterReadRecursion RT_MANGLER(RTCritSectRwGetWriterReadRecursion) +# define RTCritSectRwInit RT_MANGLER(RTCritSectRwInit) +# define RTCritSectRwInitEx RT_MANGLER(RTCritSectRwInitEx) +# define RTCritSectRwIsReadOwner RT_MANGLER(RTCritSectRwIsReadOwner) +# define RTCritSectRwIsWriteOwner RT_MANGLER(RTCritSectRwIsWriteOwner) +# define RTCritSectRwLeaveExcl RT_MANGLER(RTCritSectRwLeaveExcl) +# define RTCritSectRwLeaveShared RT_MANGLER(RTCritSectRwLeaveShared) +# define RTCritSectRwSetSubClass RT_MANGLER(RTCritSectRwSetSubClass) +# define RTCritSectRwTryEnterExcl RT_MANGLER(RTCritSectRwTryEnterExcl) +# define RTCritSectRwTryEnterExclDebug RT_MANGLER(RTCritSectRwTryEnterExclDebug) +# define RTCritSectRwTryEnterShared RT_MANGLER(RTCritSectRwTryEnterShared) +# define RTCritSectRwTryEnterSharedDebug RT_MANGLER(RTCritSectRwTryEnterSharedDebug) +# define RTDbgAsCreate RT_MANGLER(RTDbgAsCreate) +# define RTDbgAsCreateF RT_MANGLER(RTDbgAsCreateF) +# define RTDbgAsCreateV RT_MANGLER(RTDbgAsCreateV) +# define RTDbgAsFirstAddr RT_MANGLER(RTDbgAsFirstAddr) +# define RTDbgAsLastAddr RT_MANGLER(RTDbgAsLastAddr) +# define RTDbgAsLineAdd RT_MANGLER(RTDbgAsLineAdd) +# define RTDbgAsLineByAddr RT_MANGLER(RTDbgAsLineByAddr) +# define RTDbgAsLineByAddrA RT_MANGLER(RTDbgAsLineByAddrA) +# define RTDbgAsLockExcl RT_MANGLER(RTDbgAsLockExcl) +# define RTDbgAsModuleByAddr RT_MANGLER(RTDbgAsModuleByAddr) +# define RTDbgAsModuleByIndex RT_MANGLER(RTDbgAsModuleByIndex) +# define RTDbgAsModuleByName RT_MANGLER(RTDbgAsModuleByName) +# define RTDbgAsModuleCount RT_MANGLER(RTDbgAsModuleCount) +# define RTDbgAsModuleLink RT_MANGLER(RTDbgAsModuleLink) +# define RTDbgAsModuleLinkSeg RT_MANGLER(RTDbgAsModuleLinkSeg) +# define RTDbgAsModuleQueryMapByIndex RT_MANGLER(RTDbgAsModuleQueryMapByIndex) +# define RTDbgAsModuleUnlink RT_MANGLER(RTDbgAsModuleUnlink) +# define RTDbgAsModuleUnlinkByAddr RT_MANGLER(RTDbgAsModuleUnlinkByAddr) +# define RTDbgAsName RT_MANGLER(RTDbgAsName) +# define RTDbgAsRelease RT_MANGLER(RTDbgAsRelease) +# define RTDbgAsRetain RT_MANGLER(RTDbgAsRetain) +# define RTDbgAsSymbolAdd RT_MANGLER(RTDbgAsSymbolAdd) +# define RTDbgAsSymbolByAddr RT_MANGLER(RTDbgAsSymbolByAddr) +# define RTDbgAsSymbolByAddrA RT_MANGLER(RTDbgAsSymbolByAddrA) +# define RTDbgAsSymbolByName RT_MANGLER(RTDbgAsSymbolByName) +# define RTDbgAsSymbolByNameA RT_MANGLER(RTDbgAsSymbolByNameA) +# define RTDbgAsUnlockExcl RT_MANGLER(RTDbgAsUnlockExcl) +# define RTDbgCfgCreate RT_MANGLER(RTDbgCfgCreate) +# define RTDbgCfgRetain RT_MANGLER(RTDbgCfgRetain) +# define RTDbgCfgRelease RT_MANGLER(RTDbgCfgRelease) +# define RTDbgCfgChangeString RT_MANGLER(RTDbgCfgChangeString) +# define RTDbgCfgChangeUInt RT_MANGLER(RTDbgCfgChangeUInt) +# define RTDbgCfgQueryString RT_MANGLER(RTDbgCfgQueryString) +# define RTDbgCfgQueryUInt RT_MANGLER(RTDbgCfgQueryUInt) +# define RTDbgCfgOpenEx RT_MANGLER(RTDbgCfgOpenEx) +# define RTDbgCfgOpenDbg RT_MANGLER(RTDbgCfgOpenDbg) +# define RTDbgCfgOpenDsymBundle RT_MANGLER(RTDbgCfgOpenDsymBundle) +# define RTDbgCfgOpenMachOImage RT_MANGLER(RTDbgCfgOpenMachOImage) +# define RTDbgCfgOpenDwo RT_MANGLER(RTDbgCfgOpenDwo) +# define RTDbgCfgOpenDwoBuildId RT_MANGLER(RTDbgCfgOpenDwoBuildId) +# define RTDbgCfgOpenPdb70 RT_MANGLER(RTDbgCfgOpenPdb70) +# define RTDbgCfgOpenPdb20 RT_MANGLER(RTDbgCfgOpenPdb20) +# define RTDbgCfgOpenPeImage RT_MANGLER(RTDbgCfgOpenPeImage) +# define RTDbgCfgSetLogCallback RT_MANGLER(RTDbgCfgSetLogCallback) +# define RTDbgLineAlloc RT_MANGLER(RTDbgLineAlloc) +# define RTDbgLineDup RT_MANGLER(RTDbgLineDup) +# define RTDbgLineFree RT_MANGLER(RTDbgLineFree) +# define RTDbgModCreate RT_MANGLER(RTDbgModCreate) +# define RTDbgModCreateFromDbg RT_MANGLER(RTDbgModCreateFromDbg) +# define RTDbgModCreateFromDwo RT_MANGLER(RTDbgModCreateFromDwo) +# define RTDbgModCreateFromImage RT_MANGLER(RTDbgModCreateFromImage) +# define RTDbgModCreateFromMap RT_MANGLER(RTDbgModCreateFromMap) +# define RTDbgModCreateFromPdb RT_MANGLER(RTDbgModCreateFromPdb) +# define RTDbgModCreateFromPeImage RT_MANGLER(RTDbgModCreateFromPeImage) +# define RTDbgModCreateFromMachOImage RT_MANGLER(RTDbgModCreateFromMachOImage) +# define RTDbgModGetTag RT_MANGLER(RTDbgModGetTag) +# define RTDbgModImageGetArch RT_MANGLER(RTDbgModImageGetArch) +# define RTDbgModImageGetFormat RT_MANGLER(RTDbgModImageGetFormat) +# define RTDbgModImageSize RT_MANGLER(RTDbgModImageSize) +# define RTDbgModImageQueryProp RT_MANGLER(RTDbgModImageQueryProp) +# define RTDbgModIsDeferred RT_MANGLER(RTDbgModIsDeferred) +# define RTDbgModIsExports RT_MANGLER(RTDbgModIsExports) +# define RTDbgModLineAdd RT_MANGLER(RTDbgModLineAdd) +# define RTDbgModLineByAddr RT_MANGLER(RTDbgModLineByAddr) +# define RTDbgModLineByAddrA RT_MANGLER(RTDbgModLineByAddrA) +# define RTDbgModLineByOrdinal RT_MANGLER(RTDbgModLineByOrdinal) +# define RTDbgModLineByOrdinalA RT_MANGLER(RTDbgModLineByOrdinalA) +# define RTDbgModLineCount RT_MANGLER(RTDbgModLineCount) +# define RTDbgModName RT_MANGLER(RTDbgModName) +# define RTDbgModDebugFile RT_MANGLER(RTDbgModDebugFile) +# define RTDbgModImageFile RT_MANGLER(RTDbgModImageFile) +# define RTDbgModImageFileUsed RT_MANGLER(RTDbgModImageFileUsed) +# define RTDbgModRelease RT_MANGLER(RTDbgModRelease) +# define RTDbgModRemoveAll RT_MANGLER(RTDbgModRemoveAll) +# define RTDbgModRetain RT_MANGLER(RTDbgModRetain) +# define RTDbgModRvaToSegOff RT_MANGLER(RTDbgModRvaToSegOff) +# define RTDbgModSegmentAdd RT_MANGLER(RTDbgModSegmentAdd) +# define RTDbgModSegmentByIndex RT_MANGLER(RTDbgModSegmentByIndex) +# define RTDbgModSegmentCount RT_MANGLER(RTDbgModSegmentCount) +# define RTDbgModSegmentRva RT_MANGLER(RTDbgModSegmentRva) +# define RTDbgModSegmentSize RT_MANGLER(RTDbgModSegmentSize) +# define RTDbgModSetTag RT_MANGLER(RTDbgModSetTag) +# define RTDbgModSymbolAdd RT_MANGLER(RTDbgModSymbolAdd) +# define RTDbgModSymbolByAddr RT_MANGLER(RTDbgModSymbolByAddr) +# define RTDbgModSymbolByAddrA RT_MANGLER(RTDbgModSymbolByAddrA) +# define RTDbgModSymbolByName RT_MANGLER(RTDbgModSymbolByName) +# define RTDbgModSymbolByNameA RT_MANGLER(RTDbgModSymbolByNameA) +# define RTDbgModSymbolByOrdinal RT_MANGLER(RTDbgModSymbolByOrdinal) +# define RTDbgModSymbolByOrdinalA RT_MANGLER(RTDbgModSymbolByOrdinalA) +# define RTDbgModSymbolCount RT_MANGLER(RTDbgModSymbolCount) +# define RTDbgModUnwindFrame RT_MANGLER(RTDbgModUnwindFrame) +# define RTDbgStackDumpSelf RT_MANGLER(RTDbgStackDumpSelf) +# define RTDbgStackDumpSelf_EndProc RT_MANGLER(RTDbgStackDumpSelf_EndProc) +# define RTDbgSymbolAlloc RT_MANGLER(RTDbgSymbolAlloc) +# define RTDbgSymbolDup RT_MANGLER(RTDbgSymbolDup) +# define RTDbgSymbolFree RT_MANGLER(RTDbgSymbolFree) +# define RTDirClose RT_MANGLER(RTDirClose) +# define RTDirCreate RT_MANGLER(RTDirCreate) +# define RTDirCreateFullPath RT_MANGLER(RTDirCreateFullPath) +# define RTDirCreateFullPathEx RT_MANGLER(RTDirCreateFullPathEx) +# define RTDirCreateTemp RT_MANGLER(RTDirCreateTemp) +# define RTDirCreateTempSecure RT_MANGLER(RTDirCreateTempSecure) +# define RTDirCreateUniqueNumbered RT_MANGLER(RTDirCreateUniqueNumbered) +# define RTDirEntryIsStdDotLink RT_MANGLER(RTDirEntryIsStdDotLink) +# define RTDirEntryExIsStdDotLink RT_MANGLER(RTDirEntryExIsStdDotLink) +# define RTDirExists RT_MANGLER(RTDirExists) +# define RTDirFlush RT_MANGLER(RTDirFlush) +# define RTDirFlushParent RT_MANGLER(RTDirFlushParent) +# define RTDirIsValid RT_MANGLER(RTDirIsValid) +# define RTDirOpen RT_MANGLER(RTDirOpen) +# define RTDirOpenFiltered RT_MANGLER(RTDirOpenFiltered) +# define RTDirQueryInfo RT_MANGLER(RTDirQueryInfo) +# define RTDirQueryUnknownType RT_MANGLER(RTDirQueryUnknownType) +# define RTDirQueryUnknownTypeEx RT_MANGLER(RTDirQueryUnknownTypeEx) +# define RTDirRead RT_MANGLER(RTDirRead) +# define RTDirReadEx RT_MANGLER(RTDirReadEx) +# define RTDirReadExA RT_MANGLER(RTDirReadExA) +# define RTDirReadExAFree RT_MANGLER(RTDirReadExAFree) +# define RTDirRemove RT_MANGLER(RTDirRemove) +# define RTDirRemoveRecursive RT_MANGLER(RTDirRemoveRecursive) +# define RTDirRename RT_MANGLER(RTDirRename) +# define RTDirRewind RT_MANGLER(RTDirRewind) +# define RTDirSetMode RT_MANGLER(RTDirSetMode) +# define RTDirSetTimes RT_MANGLER(RTDirSetTimes) +# define RTDirRelFileOpen RT_MANGLER(RTDirRelFileOpen) +# define RTDirRelDirOpen RT_MANGLER(RTDirRelDirOpen) +# define RTDirRelDirOpenFiltered RT_MANGLER(RTDirRelDirOpenFiltered) +# define RTDirRelDirCreate RT_MANGLER(RTDirRelDirCreate) +# define RTDirRelDirRemove RT_MANGLER(RTDirRelDirRemove) +# define RTDirRelPathQueryInfo RT_MANGLER(RTDirRelPathQueryInfo) +# define RTDirRelPathSetMode RT_MANGLER(RTDirRelPathSetMode) +# define RTDirRelPathSetTimes RT_MANGLER(RTDirRelPathSetTimes) +# define RTDirRelPathSetOwner RT_MANGLER(RTDirRelPathSetOwner) +# define RTDirRelPathRename RT_MANGLER(RTDirRelPathRename) +# define RTDirRelPathUnlink RT_MANGLER(RTDirRelPathUnlink) +# define RTDirRelSymlinkCreate RT_MANGLER(RTDirRelSymlinkCreate) +# define RTDirRelSymlinkRead RT_MANGLER(RTDirRelSymlinkRead) +# define RTVfsDirOpenDir RT_MANGLER(RTVfsDirOpenDir) +# define RTVfsDirFromRTDir RT_MANGLER(RTVfsDirFromRTDir) +# define RTVfsDirOpenNormal RT_MANGLER(RTVfsDirOpenNormal) +# define RTVfsDirIsStdDir RT_MANGLER(RTVfsDirIsStdDir) +# define RTDvmCreate RT_MANGLER(RTDvmCreate) +# define RTDvmCreateFromVfsFile RT_MANGLER(RTDvmCreateFromVfsFile) +# define RTDvmRetain RT_MANGLER(RTDvmRetain) +# define RTDvmRelease RT_MANGLER(RTDvmRelease) +# define RTDvmMapOpen RT_MANGLER(RTDvmMapOpen) +# define RTDvmMapInitialize RT_MANGLER(RTDvmMapInitialize) +# define RTDvmMapGetFormatName RT_MANGLER(RTDvmMapGetFormatName) +# define RTDvmMapGetFormatType RT_MANGLER(RTDvmMapGetFormatType) +# define RTDvmMapGetValidVolumes RT_MANGLER(RTDvmMapGetValidVolumes) +# define RTDvmMapGetMaxVolumes RT_MANGLER(RTDvmMapGetMaxVolumes) +# define RTDvmMapQueryBlockStatus RT_MANGLER(RTDvmMapQueryBlockStatus) +# define RTDvmMapQueryFirstVolume RT_MANGLER(RTDvmMapQueryFirstVolume) +# define RTDvmMapQueryNextVolume RT_MANGLER(RTDvmMapQueryNextVolume) +# define RTDvmMapQueryDiskUuid RT_MANGLER(RTDvmMapQueryDiskUuid) +# define RTDvmMapQueryTableLocations RT_MANGLER(RTDvmMapQueryTableLocations) +# define RTDvmVolumeRetain RT_MANGLER(RTDvmVolumeRetain) +# define RTDvmVolumeRelease RT_MANGLER(RTDvmVolumeRelease) +# define RTDvmVolumeGetIndex RT_MANGLER(RTDvmVolumeGetIndex) +# define RTDvmVolumeGetPropU64 RT_MANGLER(RTDvmVolumeGetPropU64) +# define RTDvmVolumeGetSize RT_MANGLER(RTDvmVolumeGetSize) +# define RTDvmVolumeQueryName RT_MANGLER(RTDvmVolumeQueryName) +# define RTDvmVolumeQueryProp RT_MANGLER(RTDvmVolumeQueryProp) +# define RTDvmVolumeQueryTableLocation RT_MANGLER(RTDvmVolumeQueryTableLocation) +# define RTDvmVolumeGetType RT_MANGLER(RTDvmVolumeGetType) +# define RTDvmVolumeGetFlags RT_MANGLER(RTDvmVolumeGetFlags) +# define RTDvmVolumeQueryRange RT_MANGLER(RTDvmVolumeQueryRange) +# define RTDvmVolumeRead RT_MANGLER(RTDvmVolumeRead) +# define RTDvmVolumeWrite RT_MANGLER(RTDvmVolumeWrite) +# define RTDvmVolumeSetQueryBlockStatusCallback RT_MANGLER(RTDvmVolumeSetQueryBlockStatusCallback) +# define RTDvmVolumeTypeGetDescr RT_MANGLER(RTDvmVolumeTypeGetDescr) +# define RTDvmVolumeCreateVfsFile RT_MANGLER(RTDvmVolumeCreateVfsFile) +# define RTEfiGuidCompare RT_MANGLER(RTEfiGuidCompare) +# define RTEfiGuidFromUuid RT_MANGLER(RTEfiGuidFromUuid) +# define RTEfiGuidToUuid RT_MANGLER(RTEfiGuidToUuid) +# define RTEfiSigDbAddFromExistingDb RT_MANGLER(RTEfiSigDbAddFromExistingDb) +# define RTEfiSigDbAddSignatureFromFile RT_MANGLER(RTEfiSigDbAddSignatureFromFile) +# define RTEfiSigDbAddSignatureFromBuf RT_MANGLER(RTEfiSigDbAddSignatureFromBuf) +# define RTEfiSigDbCreate RT_MANGLER(RTEfiSigDbCreate) +# define RTEfiSigDbDestroy RT_MANGLER(RTEfiSigDbDestroy) +# define RTEfiSigDbEnum RT_MANGLER(RTEfiSigDbEnum) +# define RTEfiSigDbTypeGetGuid RT_MANGLER(RTEfiSigDbTypeGetGuid) +# define RTEfiSigDbTypeStringify RT_MANGLER(RTEfiSigDbTypeStringify) +# define RTEfiSigDbWriteToFile RT_MANGLER(RTEfiSigDbWriteToFile) +# define RTEfiTimeFromTimeSpec RT_MANGLER(RTEfiTimeFromTimeSpec) +# define RTEfiTimeToTimeSpec RT_MANGLER(RTEfiTimeToTimeSpec) +# define RTEfiVarStoreCreate RT_MANGLER(RTEfiVarStoreCreate) +# define RTEfiVarStoreOpenAsVfs RT_MANGLER(RTEfiVarStoreOpenAsVfs) +# define RTEnvApplyChanges RT_MANGLER(RTEnvApplyChanges) +# define RTEnvClone RT_MANGLER(RTEnvClone) +# define RTEnvCloneUtf16Block RT_MANGLER(RTEnvCloneUtf16Block) +# define RTEnvCountEx RT_MANGLER(RTEnvCountEx) +# define RTEnvCreate RT_MANGLER(RTEnvCreate) +# define RTEnvCreateEx RT_MANGLER(RTEnvCreateEx) +# define RTEnvCreateChangeRecord RT_MANGLER(RTEnvCreateChangeRecord) +# define RTEnvCreateChangeRecordEx RT_MANGLER(RTEnvCreateChangeRecordEx) +# define RTEnvDestroy RT_MANGLER(RTEnvDestroy) +# define RTEnvDup RT_MANGLER(RTEnvDup) +# define RTEnvDupEx RT_MANGLER(RTEnvDupEx) +# define RTEnvExist RT_MANGLER(RTEnvExist) +# define RTEnvExistsBad RT_MANGLER(RTEnvExistsBad) +# define RTEnvExistsUtf8 RT_MANGLER(RTEnvExistsUtf8) +# define RTEnvExistEx RT_MANGLER(RTEnvExistEx) +# define RTEnvFreeUtf8Block RT_MANGLER(RTEnvFreeUtf8Block) +# define RTEnvFreeUtf16Block RT_MANGLER(RTEnvFreeUtf16Block) +# define RTEnvGet RT_MANGLER(RTEnvGet) +# define RTEnvGetBad RT_MANGLER(RTEnvGetBad) +# define RTEnvGetByIndexEx RT_MANGLER(RTEnvGetByIndexEx) +# define RTEnvGetByIndexRawEx RT_MANGLER(RTEnvGetByIndexRawEx) +# define RTEnvGetUtf8 RT_MANGLER(RTEnvGetUtf8) +# define RTEnvGetEx RT_MANGLER(RTEnvGetEx) +# define RTEnvGetExecEnvP RT_MANGLER(RTEnvGetExecEnvP) +# define RTEnvIsChangeRecord RT_MANGLER(RTEnvIsChangeRecord) +# define RTEnvPut RT_MANGLER(RTEnvPut) +# define RTEnvPutBad RT_MANGLER(RTEnvPutBad) +# define RTEnvPutUtf8 RT_MANGLER(RTEnvPutUtf8) +# define RTEnvPutEx RT_MANGLER(RTEnvPutEx) +# define RTEnvQueryUtf16Block RT_MANGLER(RTEnvQueryUtf16Block) +# define RTEnvQueryUtf8Block RT_MANGLER(RTEnvQueryUtf8Block) +# define RTEnvReset RT_MANGLER(RTEnvReset) +# define RTEnvSet RT_MANGLER(RTEnvSet) +# define RTEnvSetBad RT_MANGLER(RTEnvSetBad) +# define RTEnvSetUtf8 RT_MANGLER(RTEnvSetUtf8) +# define RTEnvSetEx RT_MANGLER(RTEnvSetEx) +# define RTEnvUnset RT_MANGLER(RTEnvUnset) +# define RTEnvUnsetBad RT_MANGLER(RTEnvUnsetBad) +# define RTEnvUnsetUtf8 RT_MANGLER(RTEnvUnsetUtf8) +# define RTEnvUnsetEx RT_MANGLER(RTEnvUnsetEx) +# define RTErrCOMGet RT_MANGLER(RTErrCOMGet) +# define RTErrConvertFromErrno RT_MANGLER(RTErrConvertFromErrno) +# define RTErrConvertToErrno RT_MANGLER(RTErrConvertToErrno) +# define RTErrIsKnown RT_MANGLER(RTErrIsKnown) +# define RTErrQueryDefine RT_MANGLER(RTErrQueryDefine) +# define RTErrQueryMsgShort RT_MANGLER(RTErrQueryMsgShort) +# define RTErrQueryMsgFull RT_MANGLER(RTErrQueryMsgFull) +# define RTErrFormatDefine RT_MANGLER(RTErrFormatDefine) +# define RTErrFormatMsgShort RT_MANGLER(RTErrFormatMsgShort) +# define RTErrFormatMsgFull RT_MANGLER(RTErrFormatMsgFull) +# define RTErrFormatMsgAll RT_MANGLER(RTErrFormatMsgAll) +# define RTErrInfoAlloc RT_MANGLER(RTErrInfoAlloc) +# define RTErrInfoAllocEx RT_MANGLER(RTErrInfoAllocEx) +# define RTErrInfoFree RT_MANGLER(RTErrInfoFree) +# define RTErrInfoSet RT_MANGLER(RTErrInfoSet) +# define RTErrInfoSetF RT_MANGLER(RTErrInfoSetF) +# define RTErrInfoSetV RT_MANGLER(RTErrInfoSetV) +# define RTErrInfoLogAndSet RT_MANGLER(RTErrInfoLogAndSet) +# define RTErrInfoLogAndSetF RT_MANGLER(RTErrInfoLogAndSetF) +# define RTErrInfoLogAndSetV RT_MANGLER(RTErrInfoLogAndSetV) +# define RTErrInfoLogAndAdd RT_MANGLER(RTErrInfoLogAndAdd) +# define RTErrInfoLogAndAddF RT_MANGLER(RTErrInfoLogAndAddF) +# define RTErrInfoLogAndAddV RT_MANGLER(RTErrInfoLogAndAddV) +# define RTErrVarsAreEqual RT_MANGLER(RTErrVarsAreEqual) +# define RTErrVarsHaveChanged RT_MANGLER(RTErrVarsHaveChanged) +# define RTErrVarsRestore RT_MANGLER(RTErrVarsRestore) +# define RTErrVarsSave RT_MANGLER(RTErrVarsSave) +# define RTFileAioCtxAssociateWithFile RT_MANGLER(RTFileAioCtxAssociateWithFile) +# define RTFileAioCtxCreate RT_MANGLER(RTFileAioCtxCreate) +# define RTFileAioCtxDestroy RT_MANGLER(RTFileAioCtxDestroy) +# define RTFileAioCtxGetMaxReqCount RT_MANGLER(RTFileAioCtxGetMaxReqCount) +# define RTFileAioCtxSubmit RT_MANGLER(RTFileAioCtxSubmit) +# define RTFileAioCtxWait RT_MANGLER(RTFileAioCtxWait) +# define RTFileAioCtxWakeup RT_MANGLER(RTFileAioCtxWakeup) +# define RTFileAioGetLimits RT_MANGLER(RTFileAioGetLimits) +# define RTFileAioReqCancel RT_MANGLER(RTFileAioReqCancel) +# define RTFileAioReqCreate RT_MANGLER(RTFileAioReqCreate) +# define RTFileAioReqDestroy RT_MANGLER(RTFileAioReqDestroy) +# define RTFileAioReqGetRC RT_MANGLER(RTFileAioReqGetRC) +# define RTFileAioReqGetUser RT_MANGLER(RTFileAioReqGetUser) +# define RTFileAioReqPrepareFlush RT_MANGLER(RTFileAioReqPrepareFlush) +# define RTFileAioReqPrepareRead RT_MANGLER(RTFileAioReqPrepareRead) +# define RTFileAioReqPrepareWrite RT_MANGLER(RTFileAioReqPrepareWrite) +# define RTFileChangeLock RT_MANGLER(RTFileChangeLock) +# define RTFileClose RT_MANGLER(RTFileClose) +# define RTFileCompare RT_MANGLER(RTFileCompare) +# define RTFileCompareByHandles RT_MANGLER(RTFileCompareByHandles) +# define RTFileCompareByHandlesEx RT_MANGLER(RTFileCompareByHandlesEx) +# define RTFileCompareEx RT_MANGLER(RTFileCompareEx) +# define RTFileCopy RT_MANGLER(RTFileCopy) +# define RTFileCopyAttributes RT_MANGLER(RTFileCopyAttributes) +# define RTFileCopyByHandles RT_MANGLER(RTFileCopyByHandles) +# define RTFileCopyByHandlesEx RT_MANGLER(RTFileCopyByHandlesEx) +# define RTFileCopyEx RT_MANGLER(RTFileCopyEx) +# define RTFileCopyPart RT_MANGLER(RTFileCopyPart) +# define RTFileCopyPartCleanup RT_MANGLER(RTFileCopyPartCleanup) +# define RTFileCopyPartEx RT_MANGLER(RTFileCopyPartEx) +# define RTFileCopyPartPrep RT_MANGLER(RTFileCopyPartPrep) +# define RTFileCreateUnique RT_MANGLER(RTFileCreateUnique) +# define RTFileCreateTemp RT_MANGLER(RTFileCreateTemp) +# define RTFileCreateTempSecure RT_MANGLER(RTFileCreateTempSecure) +# define RTFileDelete RT_MANGLER(RTFileDelete) +# define RTFileDup RT_MANGLER(RTFileDup) +# define RTFileExists RT_MANGLER(RTFileExists) +# define RTFileFlush RT_MANGLER(RTFileFlush) +# define RTFileFromNative RT_MANGLER(RTFileFromNative) +# define RTFileGetMaxSize RT_MANGLER(RTFileGetMaxSize) +# define RTFileQueryMaxSizeEx RT_MANGLER(RTFileQueryMaxSizeEx) +# define RTFileQuerySizeByPath RT_MANGLER(RTFileQuerySizeByPath) +# define RTFileIoCtl RT_MANGLER(RTFileIoCtl) +# define RTFileIsValid RT_MANGLER(RTFileIsValid) +# define RTFileLock RT_MANGLER(RTFileLock) +# define RTFileModeToFlags RT_MANGLER(RTFileModeToFlags) +# define RTFileModeToFlagsEx RT_MANGLER(RTFileModeToFlagsEx) +# define RTFileMove RT_MANGLER(RTFileMove) +# define RTFileOpen RT_MANGLER(RTFileOpen) +# define RTFileOpenBitBucket RT_MANGLER(RTFileOpenBitBucket) +# define RTFileOpenEx RT_MANGLER(RTFileOpenEx) +# define RTFileOpenF RT_MANGLER(RTFileOpenF) +# define RTFileOpenV RT_MANGLER(RTFileOpenV) +# define RTFileOpenTemp RT_MANGLER(RTFileOpenTemp) +# define RTFileQueryFsSizes RT_MANGLER(RTFileQueryFsSizes) +# define RTFileQueryInfo RT_MANGLER(RTFileQueryInfo) +# define RTFileQuerySectorSize RT_MANGLER(RTFileQuerySectorSize) +# define RTFileQuerySize RT_MANGLER(RTFileQuerySize) +# define RTFileRead RT_MANGLER(RTFileRead) +# define RTFileReadAll RT_MANGLER(RTFileReadAll) +# define RTFileReadAllByHandle RT_MANGLER(RTFileReadAllByHandle) +# define RTFileReadAllByHandleEx RT_MANGLER(RTFileReadAllByHandleEx) +# define RTFileReadAllEx RT_MANGLER(RTFileReadAllEx) +# define RTFileReadAllFree RT_MANGLER(RTFileReadAllFree) +# define RTFileReadAt RT_MANGLER(RTFileReadAt) +# define RTFileRename RT_MANGLER(RTFileRename) +# define RTFileSeek RT_MANGLER(RTFileSeek) +# define RTFileSetAllocationSize RT_MANGLER(RTFileSetAllocationSize) +# define RTFileSetForceFlags RT_MANGLER(RTFileSetForceFlags) +# define RTFileSetMode RT_MANGLER(RTFileSetMode) +# define RTFileSetOwner RT_MANGLER(RTFileSetOwner) +# define RTFileSetSize RT_MANGLER(RTFileSetSize) +# define RTFileSetTimes RT_MANGLER(RTFileSetTimes) +# define RTFileSgRead RT_MANGLER(RTFileSgRead) +# define RTFileSgReadAt RT_MANGLER(RTFileSgReadAt) +# define RTFileSgWrite RT_MANGLER(RTFileSgWrite) +# define RTFileSgWriteAt RT_MANGLER(RTFileSgWriteAt) +# define RTFileTell RT_MANGLER(RTFileTell) +# define RTFileToNative RT_MANGLER(RTFileToNative) +# define RTFileUnlock RT_MANGLER(RTFileUnlock) +# define RTFileWrite RT_MANGLER(RTFileWrite) +# define RTFileWriteAt RT_MANGLER(RTFileWriteAt) +# define RTFilesystemVfsFromFile RT_MANGLER(RTFilesystemVfsFromFile) +# define RTFsIsCaseSensitive RT_MANGLER(RTFsIsCaseSensitive) +# define RTFsQueryProperties RT_MANGLER(RTFsQueryProperties) +# define RTFsQuerySerial RT_MANGLER(RTFsQuerySerial) +# define RTFsQuerySizes RT_MANGLER(RTFsQuerySizes) +# define RTFsQueryType RT_MANGLER(RTFsQueryType) +# define RTFsTypeName RT_MANGLER(RTFsTypeName) +# define RTFsExtVolOpen RT_MANGLER(RTFsExtVolOpen) +# define RTFsFatVolOpen RT_MANGLER(RTFsFatVolOpen) +# define RTFsFatVolFormat RT_MANGLER(RTFsFatVolFormat) +# define RTFsFatVolFormat144 RT_MANGLER(RTFsFatVolFormat144) +# define RTFsFatVolFormat288 RT_MANGLER(RTFsFatVolFormat288) +# define RTFsCmdLs RT_MANGLER(RTFsCmdLs) +# define RTFsIso9660VolOpen RT_MANGLER(RTFsIso9660VolOpen) +# define RTFsIsoMakerCreate RT_MANGLER(RTFsIsoMakerCreate) +# define RTFsIsoMakerRetain RT_MANGLER(RTFsIsoMakerRetain) +# define RTFsIsoMakerRelease RT_MANGLER(RTFsIsoMakerRelease) +# define RTFsIsoMakerBootCatSetFile RT_MANGLER(RTFsIsoMakerBootCatSetFile) +# define RTFsIsoMakerBootCatSetValidationEntry RT_MANGLER(RTFsIsoMakerBootCatSetValidationEntry) +# define RTFsIsoMakerBootCatSetSectionEntry RT_MANGLER(RTFsIsoMakerBootCatSetSectionEntry) +# define RTFsIsoMakerBootCatSetSectionHeaderEntry RT_MANGLER(RTFsIsoMakerBootCatSetSectionHeaderEntry) +# define RTFsIsoMakerQueryObjIdxForBootCatalog RT_MANGLER(RTFsIsoMakerQueryObjIdxForBootCatalog) +# define RTFsIsoMakerGetPopulatedNamespaces RT_MANGLER(RTFsIsoMakerGetPopulatedNamespaces) +# define RTFsIsoMakerGetIso9660Level RT_MANGLER(RTFsIsoMakerGetIso9660Level) +# define RTFsIsoMakerGetRockRidgeLevel RT_MANGLER(RTFsIsoMakerGetRockRidgeLevel) +# define RTFsIsoMakerGetJolietRockRidgeLevel RT_MANGLER(RTFsIsoMakerGetJolietRockRidgeLevel) +# define RTFsIsoMakerSetImagePadding RT_MANGLER(RTFsIsoMakerSetImagePadding) +# define RTFsIsoMakerSetIso9660Level RT_MANGLER(RTFsIsoMakerSetIso9660Level) +# define RTFsIsoMakerSetJolietUcs2Level RT_MANGLER(RTFsIsoMakerSetJolietUcs2Level) +# define RTFsIsoMakerSetRockRidgeLevel RT_MANGLER(RTFsIsoMakerSetRockRidgeLevel) +# define RTFsIsoMakerSetJolietRockRidgeLevel RT_MANGLER(RTFsIsoMakerSetJolietRockRidgeLevel) +# define RTFsIsoMakerSetAttribInheritStyle RT_MANGLER(RTFsIsoMakerSetAttribInheritStyle) +# define RTFsIsoMakerSetDefaultDirMode RT_MANGLER(RTFsIsoMakerSetDefaultDirMode) +# define RTFsIsoMakerSetDefaultFileMode RT_MANGLER(RTFsIsoMakerSetDefaultFileMode) +# define RTFsIsoMakerSetForcedDirMode RT_MANGLER(RTFsIsoMakerSetForcedDirMode) +# define RTFsIsoMakerSetForcedFileMode RT_MANGLER(RTFsIsoMakerSetForcedFileMode) +# define RTFsIsoMakerSetPathGroupId RT_MANGLER(RTFsIsoMakerSetPathGroupId) +# define RTFsIsoMakerSetPathMode RT_MANGLER(RTFsIsoMakerSetPathMode) +# define RTFsIsoMakerSetPathOwnerId RT_MANGLER(RTFsIsoMakerSetPathOwnerId) +# define RTFsIsoMakerSetSysAreaContent RT_MANGLER(RTFsIsoMakerSetSysAreaContent) +# define RTFsIsoMakerSetStringProp RT_MANGLER(RTFsIsoMakerSetStringProp) +# define RTFsIsoMakerGetObjIdxForPath RT_MANGLER(RTFsIsoMakerGetObjIdxForPath) +# define RTFsIsoMakerObjEnableBootInfoTablePatching RT_MANGLER(RTFsIsoMakerObjEnableBootInfoTablePatching) +# define RTFsIsoMakerObjQueryDataSize RT_MANGLER(RTFsIsoMakerObjQueryDataSize) +# define RTFsIsoMakerObjRemove RT_MANGLER(RTFsIsoMakerObjRemove) +# define RTFsIsoMakerObjSetPath RT_MANGLER(RTFsIsoMakerObjSetPath) +# define RTFsIsoMakerObjSetNameAndParent RT_MANGLER(RTFsIsoMakerObjSetNameAndParent) +# define RTFsIsoMakerObjSetRockName RT_MANGLER(RTFsIsoMakerObjSetRockName) +# define RTFsIsoMakerAddUnnamedDir RT_MANGLER(RTFsIsoMakerAddUnnamedDir) +# define RTFsIsoMakerAddDir RT_MANGLER(RTFsIsoMakerAddDir) +# define RTFsIsoMakerAddFileWithSrcPath RT_MANGLER(RTFsIsoMakerAddFileWithSrcPath) +# define RTFsIsoMakerAddFileWithVfsFile RT_MANGLER(RTFsIsoMakerAddFileWithVfsFile) +# define RTFsIsoMakerAddUnnamedFileWithSrcPath RT_MANGLER(RTFsIsoMakerAddUnnamedFileWithSrcPath) +# define RTFsIsoMakerAddUnnamedFileWithVfsFile RT_MANGLER(RTFsIsoMakerAddUnnamedFileWithVfsFile) +# define RTFsIsoMakerAddUnnamedFileWithCommonSrc RT_MANGLER(RTFsIsoMakerAddUnnamedFileWithCommonSrc) +# define RTFsIsoMakerAddSymlink RT_MANGLER(RTFsIsoMakerAddSymlink) +# define RTFsIsoMakerAddUnnamedSymlink RT_MANGLER(RTFsIsoMakerAddUnnamedSymlink) +# define RTFsIsoMakerAddCommonSourceFile RT_MANGLER(RTFsIsoMakerAddCommonSourceFile) +# define RTFsIsoMakerImport RT_MANGLER(RTFsIsoMakerImport) +# define RTFsIsoMakerFinalize RT_MANGLER(RTFsIsoMakerFinalize) +# define RTFsIsoMakerCreateVfsOutputFile RT_MANGLER(RTFsIsoMakerCreateVfsOutputFile) +# define RTFsIsoMakerCmd RT_MANGLER(RTFsIsoMakerCmd) +# define RTFsIsoMakerCmdEx RT_MANGLER(RTFsIsoMakerCmdEx) +# define RTFsNtfsVolOpen RT_MANGLER(RTFsNtfsVolOpen) +# define RTFtpServerCreate RT_MANGLER(RTFtpServerCreate) +# define RTFtpServerDestroy RT_MANGLER(RTFtpServerDestroy) +# define RTFuzzCmdMaster RT_MANGLER(RTFuzzCmdMaster) +# define RTFuzzCfgCreateFromFile RT_MANGLER(RTFuzzCfgCreateFromFile) +# define RTFuzzCfgCreateFromVfsFile RT_MANGLER(RTFuzzCfgCreateFromVfsFile) +# define RTFuzzCfgRetain RT_MANGLER(RTFuzzCfgRetain) +# define RTFuzzCfgRelease RT_MANGLER(RTFuzzCfgRelease) +# define RTFuzzCfgImport RT_MANGLER(RTFuzzCfgImport) +# define RTFuzzCfgQueryCustomCfg RT_MANGLER(RTFuzzCfgQueryCustomCfg) +# define RTFuzzCtxCfgGetBehavioralFlags RT_MANGLER(RTFuzzCtxCfgGetBehavioralFlags) +# define RTFuzzCtxCfgGetInputSeedMaximum RT_MANGLER(RTFuzzCtxCfgGetInputSeedMaximum) +# define RTFuzzCtxCfgGetTmpDirectory RT_MANGLER(RTFuzzCtxCfgGetTmpDirectory) +# define RTFuzzCtxCfgSetBehavioralFlags RT_MANGLER(RTFuzzCtxCfgSetBehavioralFlags) +# define RTFuzzCtxCfgSetInputSeedMaximum RT_MANGLER(RTFuzzCtxCfgSetInputSeedMaximum) +# define RTFuzzCtxCfgSetMutationRange RT_MANGLER(RTFuzzCtxCfgSetMutationRange) +# define RTFuzzCtxCfgSetTmpDirectory RT_MANGLER(RTFuzzCtxCfgSetTmpDirectory) +# define RTFuzzCtxCorpusInputAdd RT_MANGLER(RTFuzzCtxCorpusInputAdd) +# define RTFuzzCtxCorpusInputAddEx RT_MANGLER(RTFuzzCtxCorpusInputAddEx) +# define RTFuzzCtxCorpusInputAddFromDirPath RT_MANGLER(RTFuzzCtxCorpusInputAddFromDirPath) +# define RTFuzzCtxCorpusInputAddFromFile RT_MANGLER(RTFuzzCtxCorpusInputAddFromFile) +# define RTFuzzCtxCorpusInputAddFromFileEx RT_MANGLER(RTFuzzCtxCorpusInputAddFromFileEx) +# define RTFuzzCtxCorpusInputAddFromVfsFile RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsFile) +# define RTFuzzCtxCorpusInputAddFromVfsFileEx RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsFileEx) +# define RTFuzzCtxCorpusInputAddFromVfsIoStrm RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsIoStrm) +# define RTFuzzCtxCorpusInputAddFromVfsIoStrmEx RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsIoStrmEx) +# define RTFuzzCtxCreate RT_MANGLER(RTFuzzCtxCreate) +# define RTFuzzCtxCreateFromState RT_MANGLER(RTFuzzCtxCreateFromState) +# define RTFuzzCtxCreateFromStateFile RT_MANGLER(RTFuzzCtxCreateFromStateFile) +# define RTFuzzCtxCreateFromStateMem RT_MANGLER(RTFuzzCtxCreateFromStateMem) +# define RTFuzzCtxInputGenerate RT_MANGLER(RTFuzzCtxInputGenerate) +# define RTFuzzCtxQueryStats RT_MANGLER(RTFuzzCtxQueryStats) +# define RTFuzzCtxRelease RT_MANGLER(RTFuzzCtxRelease) +# define RTFuzzCtxReseed RT_MANGLER(RTFuzzCtxReseed) +# define RTFuzzCtxRetain RT_MANGLER(RTFuzzCtxRetain) +# define RTFuzzCtxStateExport RT_MANGLER(RTFuzzCtxStateExport) +# define RTFuzzCtxStateExportToFile RT_MANGLER(RTFuzzCtxStateExportToFile) +# define RTFuzzCtxStateExportToMem RT_MANGLER(RTFuzzCtxStateExportToMem) +# define RTFuzzInputAddToCtxCorpus RT_MANGLER(RTFuzzInputAddToCtxCorpus) +# define RTFuzzInputMutateStreamData RT_MANGLER(RTFuzzInputMutateStreamData) +# define RTFuzzInputQueryBlobData RT_MANGLER(RTFuzzInputQueryBlobData) +# define RTFuzzInputQueryDigestString RT_MANGLER(RTFuzzInputQueryDigestString) +# define RTFuzzInputRelease RT_MANGLER(RTFuzzInputRelease) +# define RTFuzzInputRemoveFromCtxCorpus RT_MANGLER(RTFuzzInputRemoveFromCtxCorpus) +# define RTFuzzInputRetain RT_MANGLER(RTFuzzInputRetain) +# define RTFuzzInputWriteToFile RT_MANGLER(RTFuzzInputWriteToFile) +# define RTFuzzObsCreate RT_MANGLER(RTFuzzObsCreate) +# define RTFuzzObsDestroy RT_MANGLER(RTFuzzObsDestroy) +# define RTFuzzObsExecStart RT_MANGLER(RTFuzzObsExecStart) +# define RTFuzzObsExecStop RT_MANGLER(RTFuzzObsExecStop) +# define RTFuzzObsQueryCtx RT_MANGLER(RTFuzzObsQueryCtx) +# define RTFuzzObsQueryStats RT_MANGLER(RTFuzzObsQueryStats) +# define RTFuzzObsSetResultDirectory RT_MANGLER(RTFuzzObsSetResultDirectory) +# define RTFuzzObsSetTestBinary RT_MANGLER(RTFuzzObsSetTestBinary) +# define RTFuzzObsSetTestBinaryArgs RT_MANGLER(RTFuzzObsSetTestBinaryArgs) +# define RTFuzzObsSetTestBinaryEnv RT_MANGLER(RTFuzzObsSetTestBinaryEnv) +# define RTFuzzObsSetTestBinarySanitizers RT_MANGLER(RTFuzzObsSetTestBinarySanitizers) +# define RTFuzzObsSetTestBinaryTimeout RT_MANGLER(RTFuzzObsSetTestBinaryTimeout) +# define RTFuzzObsSetTmpDirectory RT_MANGLER(RTFuzzObsSetTmpDirectory) +# define RTFuzzTgtRecorderCreate RT_MANGLER(RTFuzzTgtRecorderCreate) +# define RTFuzzTgtRecorderCreateNewState RT_MANGLER(RTFuzzTgtRecorderCreateNewState) +# define RTFuzzTgtRecorderRelease RT_MANGLER(RTFuzzTgtRecorderRelease) +# define RTFuzzTgtRecorderRetain RT_MANGLER(RTFuzzTgtRecorderRetain) +# define RTFuzzTgtStateAddProcSts RT_MANGLER(RTFuzzTgtStateAddProcSts) +# define RTFuzzTgtStateAddSanCovReportFromFile RT_MANGLER(RTFuzzTgtStateAddSanCovReportFromFile) +# define RTFuzzTgtStateAddToRecorder RT_MANGLER(RTFuzzTgtStateAddToRecorder) +# define RTFuzzTgtStateAppendStderrFromBuf RT_MANGLER(RTFuzzTgtStateAppendStderrFromBuf) +# define RTFuzzTgtStateAppendStderrFromPipe RT_MANGLER(RTFuzzTgtStateAppendStderrFromPipe) +# define RTFuzzTgtStateAppendStdoutFromBuf RT_MANGLER(RTFuzzTgtStateAppendStdoutFromBuf) +# define RTFuzzTgtStateAppendStdoutFromPipe RT_MANGLER(RTFuzzTgtStateAppendStdoutFromPipe) +# define RTFuzzTgtStateDumpToDir RT_MANGLER(RTFuzzTgtStateDumpToDir) +# define RTFuzzTgtStateFinalize RT_MANGLER(RTFuzzTgtStateFinalize) +# define RTFuzzTgtStateRelease RT_MANGLER(RTFuzzTgtStateRelease) +# define RTFuzzTgtStateReset RT_MANGLER(RTFuzzTgtStateReset) +# define RTFuzzTgtStateRetain RT_MANGLER(RTFuzzTgtStateRetain) +# define RTGetOpt RT_MANGLER(RTGetOpt) +# define RTGetOptArgvFree RT_MANGLER(RTGetOptArgvFree) +# define RTGetOptArgvFreeEx RT_MANGLER(RTGetOptArgvFreeEx) +# define RTGetOptArgvFromString RT_MANGLER(RTGetOptArgvFromString) +# define RTGetOptArgvToString RT_MANGLER(RTGetOptArgvToString) +# define RTGetOptArgvToUtf16String RT_MANGLER(RTGetOptArgvToUtf16String) +# define RTGetOptFetchValue RT_MANGLER(RTGetOptFetchValue) +# define RTGetOptInit RT_MANGLER(RTGetOptInit) +# define RTGetOptNonOptionArrayPtr RT_MANGLER(RTGetOptNonOptionArrayPtr) +# define RTGetOptFormatError RT_MANGLER(RTGetOptFormatError) +# define RTGetOptPrintError RT_MANGLER(RTGetOptPrintError) +# define RTHandleClose RT_MANGLER(RTHandleClose) +# define RTHandleGetStandard RT_MANGLER(RTHandleGetStandard) +# define RTHandleTableAlloc RT_MANGLER(RTHandleTableAlloc) +# define RTHandleTableAllocWithCtx RT_MANGLER(RTHandleTableAllocWithCtx) +# define RTHandleTableCreate RT_MANGLER(RTHandleTableCreate) +# define RTHandleTableCreateEx RT_MANGLER(RTHandleTableCreateEx) +# define RTHandleTableDestroy RT_MANGLER(RTHandleTableDestroy) +# define RTHandleTableFree RT_MANGLER(RTHandleTableFree) +# define RTHandleTableFreeWithCtx RT_MANGLER(RTHandleTableFreeWithCtx) +# define RTHandleTableLookup RT_MANGLER(RTHandleTableLookup) +# define RTHandleTableLookupWithCtx RT_MANGLER(RTHandleTableLookupWithCtx) +# define RTHeapOffsetAlloc RT_MANGLER(RTHeapOffsetAlloc) +# define RTHeapOffsetAllocZ RT_MANGLER(RTHeapOffsetAllocZ) +# define RTHeapOffsetDump RT_MANGLER(RTHeapOffsetDump) +# define RTHeapOffsetFree RT_MANGLER(RTHeapOffsetFree) +# define RTHeapOffsetGetFreeSize RT_MANGLER(RTHeapOffsetGetFreeSize) +# define RTHeapOffsetGetHeapSize RT_MANGLER(RTHeapOffsetGetHeapSize) +# define RTHeapOffsetInit RT_MANGLER(RTHeapOffsetInit) +# define RTHeapOffsetSize RT_MANGLER(RTHeapOffsetSize) +# define RTHeapSimpleAlloc RT_MANGLER(RTHeapSimpleAlloc) +# define RTHeapSimpleAllocZ RT_MANGLER(RTHeapSimpleAllocZ) +# define RTHeapSimpleDump RT_MANGLER(RTHeapSimpleDump) +# define RTHeapSimpleFree RT_MANGLER(RTHeapSimpleFree) +# define RTHeapSimpleGetFreeSize RT_MANGLER(RTHeapSimpleGetFreeSize) +# define RTHeapSimpleGetHeapSize RT_MANGLER(RTHeapSimpleGetHeapSize) +# define RTHeapSimpleInit RT_MANGLER(RTHeapSimpleInit) +# define RTHeapSimpleRelocate RT_MANGLER(RTHeapSimpleRelocate) +# define RTHeapSimpleSize RT_MANGLER(RTHeapSimpleSize) +# define RTHttpGetFile RT_MANGLER(RTHttpGetFile) +# define RTHttpGetFollowRedirects RT_MANGLER(RTHttpGetFollowRedirects) +# define RTHttpSetFollowRedirects RT_MANGLER(RTHttpSetFollowRedirects) +# define RTHttpGetVerifyPeer RT_MANGLER(RTHttpGetVerifyPeer) +# define RTHttpHeaderListInit RT_MANGLER(RTHttpHeaderListInit) +# define RTHttpHeaderListDestroy RT_MANGLER(RTHttpHeaderListDestroy) +# define RTHttpHeaderListSet RT_MANGLER(RTHttpHeaderListSet) +# define RTHttpHeaderListAddRaw RT_MANGLER(RTHttpHeaderListAddRaw) +# define RTHttpHeaderListAdd RT_MANGLER(RTHttpHeaderListAdd) +# define RTHttpHeaderListGet RT_MANGLER(RTHttpHeaderListGet) +# define RTHttpHeaderListGetCount RT_MANGLER(RTHttpHeaderListGetCount) +# define RTHttpHeaderListGetByOrdinal RT_MANGLER(RTHttpHeaderListGetByOrdinal) +# define RTHttpMethodToStr RT_MANGLER(RTHttpMethodToStr) +# define RTHttpSetVerifyPeer RT_MANGLER(RTHttpSetVerifyPeer) +# define RTHttpUseSystemProxySettings RT_MANGLER(RTHttpUseSystemProxySettings) +# define RTHttpServerCreate RT_MANGLER(RTHttpServerCreate) +# define RTHttpServerDestroy RT_MANGLER(RTHttpServerDestroy) +# define RTHttpServerResponseInitEx RT_MANGLER(RTHttpServerResponseInitEx) +# define RTHttpServerResponseInit RT_MANGLER(RTHttpServerResponseInit) +# define RTHttpServerResponseDestroy RT_MANGLER(RTHttpServerResponseDestroy) +# define RTHttpStatusToStr RT_MANGLER(RTHttpStatusToStr) +# define RTIniFileCreateFromVfsFile RT_MANGLER(RTIniFileCreateFromVfsFile) +# define RTIniFileRetain RT_MANGLER(RTIniFileRetain) +# define RTIniFileRelease RT_MANGLER(RTIniFileRelease) +# define RTIniFileQueryPair RT_MANGLER(RTIniFileQueryPair) +# define RTIniFileQueryValue RT_MANGLER(RTIniFileQueryValue) +# define RTIoQueueCommit RT_MANGLER(RTIoQueueCommit) +# define RTIoQueueCreate RT_MANGLER(RTIoQueueCreate) +# define RTIoQueueDestroy RT_MANGLER(RTIoQueueDestroy) +# define RTIoQueueEvtWait RT_MANGLER(RTIoQueueEvtWait) +# define RTIoQueueEvtWaitWakeup RT_MANGLER(RTIoQueueEvtWaitWakeup) +# define RTIoQueueHandleDeregister RT_MANGLER(RTIoQueueHandleDeregister) +# define RTIoQueueHandleRegister RT_MANGLER(RTIoQueueHandleRegister) +# define RTIoQueueProviderGetBestForHndType RT_MANGLER(RTIoQueueProviderGetBestForHndType) +# define RTIoQueueProviderGetById RT_MANGLER(RTIoQueueProviderGetById) +# define RTIoQueueRequestPrepare RT_MANGLER(RTIoQueueRequestPrepare) +# define RTIoQueueRequestPrepareSg RT_MANGLER(RTIoQueueRequestPrepareSg) +# define RTJsonIteratorBegin RT_MANGLER(RTJsonIteratorBegin) +# define RTJsonIteratorBeginArray RT_MANGLER(RTJsonIteratorBeginArray) +# define RTJsonIteratorBeginObject RT_MANGLER(RTJsonIteratorBeginObject) +# define RTJsonIteratorFree RT_MANGLER(RTJsonIteratorFree) +# define RTJsonIteratorNext RT_MANGLER(RTJsonIteratorNext) +# define RTJsonIteratorQueryValue RT_MANGLER(RTJsonIteratorQueryValue) +# define RTJsonParseFromBuf RT_MANGLER(RTJsonParseFromBuf) +# define RTJsonParseFromFile RT_MANGLER(RTJsonParseFromFile) +# define RTJsonParseFromString RT_MANGLER(RTJsonParseFromString) +# define RTJsonParseFromVfsFile RT_MANGLER(RTJsonParseFromVfsFile) +# define RTJsonValueGetArraySize RT_MANGLER(RTJsonValueGetArraySize) +# define RTJsonValueGetString RT_MANGLER(RTJsonValueGetString) +# define RTJsonValueGetType RT_MANGLER(RTJsonValueGetType) +# define RTJsonValueQueryArraySizeEx RT_MANGLER(RTJsonValueQueryArraySize) +# define RTJsonValueQueryBooleanByName RT_MANGLER(RTJsonValueQueryBooleanByName) +# define RTJsonValueQueryByIndex RT_MANGLER(RTJsonValueQueryByIndex) +# define RTJsonValueQueryByName RT_MANGLER(RTJsonValueQueryByName) +# define RTJsonValueQueryInteger RT_MANGLER(RTJsonValueQueryInteger) +# define RTJsonValueQueryIntegerByName RT_MANGLER(RTJsonValueQueryIntegerByName) +# define RTJsonValueQueryNumber RT_MANGLER(RTJsonValueQueryNumber) +# define RTJsonValueQueryNumberByName RT_MANGLER(RTJsonValueQueryNumberByName) +# define RTJsonValueQueryString RT_MANGLER(RTJsonValueQueryString) +# define RTJsonValueQueryStringByName RT_MANGLER(RTJsonValueQueryStringByName) +# define RTJsonValueRelease RT_MANGLER(RTJsonValueRelease) +# define RTJsonValueRetain RT_MANGLER(RTJsonValueRetain) +# define RTJsonValueTypeName RT_MANGLER(RTJsonValueTypeName) +# define RTKrnlModInfoGetFilePath RT_MANGLER(RTKrnlModInfoGetFilePath) +# define RTKrnlModInfoGetLoadAddr RT_MANGLER(RTKrnlModInfoGetLoadAddr) +# define RTKrnlModInfoGetName RT_MANGLER(RTKrnlModInfoGetName) +# define RTKrnlModInfoGetRefCnt RT_MANGLER(RTKrnlModInfoGetRefCnt) +# define RTKrnlModInfoGetSize RT_MANGLER(RTKrnlModInfoGetSize) +# define RTKrnlModInfoQueryRefModInfo RT_MANGLER(RTKrnlModInfoQueryRefModInfo) +# define RTKrnlModInfoRetain RT_MANGLER(RTKrnlModInfoRetain) +# define RTKrnlModInfoRelease RT_MANGLER(RTKrnlModInfoRelease) +# define RTKrnlModLoadByName RT_MANGLER(RTKrnlModLoadByName) +# define RTKrnlModLoadByPath RT_MANGLER(RTKrnlModLoadByPath) +# define RTKrnlModLoadedGetCount RT_MANGLER(RTKrnlModLoadedGetCount) +# define RTKrnlModLoadedQueryInfo RT_MANGLER(RTKrnlModLoadedQueryInfo) +# define RTKrnlModLoadedQueryInfoAll RT_MANGLER(RTKrnlModLoadedQueryInfoAll) +# define RTKrnlModQueryLoaded RT_MANGLER(RTKrnlModQueryLoaded) +# define RTKrnlModUnloadByName RT_MANGLER(RTKrnlModUnloadByName) +# define RTLatin1CalcUtf16Len RT_MANGLER(RTLatin1CalcUtf16Len) +# define RTLatin1CalcUtf16LenEx RT_MANGLER(RTLatin1CalcUtf16LenEx) +# define RTLatin1CalcUtf8Len RT_MANGLER(RTLatin1CalcUtf8Len) +# define RTLatin1CalcUtf8LenEx RT_MANGLER(RTLatin1CalcUtf8LenEx) +# define RTLatin1ToUtf16ExTag RT_MANGLER(RTLatin1ToUtf16ExTag) +# define RTLatin1ToUtf16Tag RT_MANGLER(RTLatin1ToUtf16Tag) +# define RTLatin1ToUtf8ExTag RT_MANGLER(RTLatin1ToUtf8ExTag) +# define RTLatin1ToUtf8Tag RT_MANGLER(RTLatin1ToUtf8Tag) +# define RTLdrArchName RT_MANGLER(RTLdrArchName) +# define RTLdrClose RT_MANGLER(RTLdrClose) +# define RTLdrEnumDbgInfo RT_MANGLER(RTLdrEnumDbgInfo) +# define RTLdrEnumSegments RT_MANGLER(RTLdrEnumSegments) +# define RTLdrEnumSymbols RT_MANGLER(RTLdrEnumSymbols) +# define RTLdrGetArch RT_MANGLER(RTLdrGetArch) +# define RTLdrGetBits RT_MANGLER(RTLdrGetBits) +# define RTLdrGetEndian RT_MANGLER(RTLdrGetEndian) +# define RTLdrGetFormat RT_MANGLER(RTLdrGetFormat) +# define RTLdrGetFunction RT_MANGLER(RTLdrGetFunction) +# define RTLdrGetHostArch RT_MANGLER(RTLdrGetHostArch) +# define RTLdrGetNativeHandle RT_MANGLER(RTLdrGetNativeHandle) +# define RTLdrGetSuff RT_MANGLER(RTLdrGetSuff) +# define RTLdrGetSymbol RT_MANGLER(RTLdrGetSymbol) +# define RTLdrGetSymbolEx RT_MANGLER(RTLdrGetSymbolEx) +# define RTLdrGetSystemSymbol RT_MANGLER(RTLdrGetSystemSymbol) +# define RTLdrGetSystemSymbolEx RT_MANGLER(RTLdrGetSystemSymbolEx) +# define RTLdrGetType RT_MANGLER(RTLdrGetType) +# define RTLdrIsLoadable RT_MANGLER(RTLdrIsLoadable) +# define RTLdrLinkAddressToRva RT_MANGLER(RTLdrLinkAddressToRva) +# define RTLdrLinkAddressToSegOffset RT_MANGLER(RTLdrLinkAddressToSegOffset) +# define RTLdrLoad RT_MANGLER(RTLdrLoad) +# define RTLdrLoadAppPriv RT_MANGLER(RTLdrLoadAppPriv) +# define RTLdrLoadEx RT_MANGLER(RTLdrLoadEx) +# define RTLdrLoadSystem RT_MANGLER(RTLdrLoadSystem) +# define RTLdrLoadSystemEx RT_MANGLER(RTLdrLoadSystemEx) +# define RTLdrOpen RT_MANGLER(RTLdrOpen) +# define RTLdrOpenEx RT_MANGLER(RTLdrOpenEx) +# define RTLdrOpenInMemory RT_MANGLER(RTLdrOpenInMemory) +# define RTLdrOpenVfsChain RT_MANGLER(RTLdrOpenVfsChain) +# define RTLdrRelocate RT_MANGLER(RTLdrRelocate) +# define RTLdrRvaToSegOffset RT_MANGLER(RTLdrRvaToSegOffset) +# define RTLdrQueryForwarderInfo RT_MANGLER(RTLdrQueryForwarderInfo) +# define RTLdrQueryProp RT_MANGLER(RTLdrQueryProp) +# define RTLdrSegOffsetToRva RT_MANGLER(RTLdrSegOffsetToRva) +# define RTLdrSize RT_MANGLER(RTLdrSize) +# define RTLdrUnwindFrame RT_MANGLER(RTLdrUnwindFrame) +# define RTLinuxCheckDevicePath RT_MANGLER(RTLinuxCheckDevicePath) +# define RTLinuxCheckDevicePathV RT_MANGLER(RTLinuxCheckDevicePathV) +# define RTLinuxConstructPath RT_MANGLER(RTLinuxConstructPath) +# define RTLinuxConstructPathV RT_MANGLER(RTLinuxConstructPathV) +# define RTLinuxSysFsClose RT_MANGLER(RTLinuxSysFsClose) +# define RTLinuxSysFsExists RT_MANGLER(RTLinuxSysFsExists) +# define RTLinuxSysFsExistsEx RT_MANGLER(RTLinuxSysFsExistsEx) +# define RTLinuxSysFsExistsExV RT_MANGLER(RTLinuxSysFsExistsExV) +# define RTLinuxSysFsExistsV RT_MANGLER(RTLinuxSysFsExistsV) +# define RTLinuxSysFsGetLinkDest RT_MANGLER(RTLinuxSysFsGetLinkDest) +# define RTLinuxSysFsGetLinkDestV RT_MANGLER(RTLinuxSysFsGetLinkDestV) +# define RTLinuxSysFsOpen RT_MANGLER(RTLinuxSysFsOpen) +# define RTLinuxSysFsOpenEx RT_MANGLER(RTLinuxSysFsOpenEx) +# define RTLinuxSysFsOpenExV RT_MANGLER(RTLinuxSysFsOpenExV) +# define RTLinuxSysFsOpenV RT_MANGLER(RTLinuxSysFsOpenV) +# define RTLinuxSysFsReadDevNumFile RT_MANGLER(RTLinuxSysFsReadDevNumFile) +# define RTLinuxSysFsReadDevNumFileV RT_MANGLER(RTLinuxSysFsReadDevNumFileV) +# define RTLinuxSysFsReadFile RT_MANGLER(RTLinuxSysFsReadFile) +# define RTLinuxSysFsReadIntFile RT_MANGLER(RTLinuxSysFsReadIntFile) +# define RTLinuxSysFsReadIntFileV RT_MANGLER(RTLinuxSysFsReadIntFileV) +# define RTLinuxSysFsReadStr RT_MANGLER(RTLinuxSysFsReadStr) +# define RTLinuxSysFsReadStrFile RT_MANGLER(RTLinuxSysFsReadStrFile) +# define RTLinuxSysFsReadStrFileV RT_MANGLER(RTLinuxSysFsReadStrFileV) +# define RTLinuxSysFsWriteFile RT_MANGLER(RTLinuxSysFsWriteFile) +# define RTLinuxSysFsWriteStr RT_MANGLER(RTLinuxSysFsWriteStr) +# define RTLinuxSysFsWriteStrFile RT_MANGLER(RTLinuxSysFsWriteStrFile) +# define RTLinuxSysFsWriteStrFileV RT_MANGLER(RTLinuxSysFsWriteStrFileV) +# define RTLinuxSysFsWriteU8File RT_MANGLER(RTLinuxSysFsWriteU8File) +# define RTLinuxSysFsWriteU8FileV RT_MANGLER(RTLinuxSysFsWriteU8FileV) +# define RTLinuxSysFsWriteU16File RT_MANGLER(RTLinuxSysFsWriteU16File) +# define RTLinuxSysFsWriteU16FileV RT_MANGLER(RTLinuxSysFsWriteU16FileV) +# define RTLinuxSysFsWriteU32File RT_MANGLER(RTLinuxSysFsWriteU32File) +# define RTLinuxSysFsWriteU32FileV RT_MANGLER(RTLinuxSysFsWriteU32FileV) +# define RTLinuxSysFsWriteU64File RT_MANGLER(RTLinuxSysFsWriteU64File) +# define RTLinuxSysFsWriteU64FileV RT_MANGLER(RTLinuxSysFsWriteU64FileV) +# define RTLocalIpcServerCreate RT_MANGLER(RTLocalIpcServerCreate) +# define RTLocalIpcServerDestroy RT_MANGLER(RTLocalIpcServerDestroy) +# define RTLocalIpcServerGrantGroupAccess RT_MANGLER(RTLocalIpcServerGrantGroupAccess) +# define RTLocalIpcServerSetAccessMode RT_MANGLER(RTLocalIpcServerSetAccessMode); +# define RTLocalIpcServerCancel RT_MANGLER(RTLocalIpcServerCancel) +# define RTLocalIpcServerListen RT_MANGLER(RTLocalIpcServerListen) +# define RTLocalIpcSessionConnect RT_MANGLER(RTLocalIpcSessionConnect) +# define RTLocalIpcSessionClose RT_MANGLER(RTLocalIpcSessionClose) +# define RTLocalIpcSessionCancel RT_MANGLER(RTLocalIpcSessionCancel) +# define RTLocalIpcSessionRead RT_MANGLER(RTLocalIpcSessionRead) +# define RTLocalIpcSessionReadNB RT_MANGLER(RTLocalIpcSessionReadNB) +# define RTLocalIpcSessionRetain RT_MANGLER(RTLocalIpcSessionRetain) +# define RTLocalIpcSessionRelease RT_MANGLER(RTLocalIpcSessionRelease) +# define RTLocalIpcSessionWrite RT_MANGLER(RTLocalIpcSessionWrite) +# define RTLocalIpcSessionFlush RT_MANGLER(RTLocalIpcSessionFlush) +# define RTLocalIpcSessionWaitForData RT_MANGLER(RTLocalIpcSessionWaitForData) +# define RTLocalIpcSessionQueryProcess RT_MANGLER(RTLocalIpcSessionQueryProcess) +# define RTLocalIpcSessionQueryUserId RT_MANGLER(RTLocalIpcSessionQueryUserId) +# define RTLocalIpcSessionQueryGroupId RT_MANGLER(RTLocalIpcSessionQueryGroupId) +# define RTLocaleQueryLocaleName RT_MANGLER(RTLocaleQueryLocaleName) +# define RTLocaleQueryNormalizedBaseLocaleName RT_MANGLER(RTLocaleQueryNormalizedBaseLocaleName) +# define RTLocaleQueryUserCountryCode RT_MANGLER(RTLocaleQueryUserCountryCode) +# define RTLockValidatorClassAddPriorClass RT_MANGLER(RTLockValidatorClassAddPriorClass) +# define RTLockValidatorClassCreate RT_MANGLER(RTLockValidatorClassCreate) +# define RTLockValidatorClassCreateEx RT_MANGLER(RTLockValidatorClassCreateEx) +# define RTLockValidatorClassCreateExV RT_MANGLER(RTLockValidatorClassCreateExV) +# define RTLockValidatorClassCreateUnique RT_MANGLER(RTLockValidatorClassCreateUnique) +# define RTLockValidatorClassEnforceStrictReleaseOrder RT_MANGLER(RTLockValidatorClassEnforceStrictReleaseOrder) +# define RTLockValidatorClassFindForSrcPos RT_MANGLER(RTLockValidatorClassFindForSrcPos) +# define RTLockValidatorClassForSrcPos RT_MANGLER(RTLockValidatorClassForSrcPos) +# define RTLockValidatorClassRelease RT_MANGLER(RTLockValidatorClassRelease) +# define RTLockValidatorClassRetain RT_MANGLER(RTLockValidatorClassRetain) +# define RTLockValidatorHoldsLocksInClass RT_MANGLER(RTLockValidatorHoldsLocksInClass) +# define RTLockValidatorHoldsLocksInSubClass RT_MANGLER(RTLockValidatorHoldsLocksInSubClass) +# define RTLockValidatorIsBlockedThreadInValidator RT_MANGLER(RTLockValidatorIsBlockedThreadInValidator) +# define RTLockValidatorIsEnabled RT_MANGLER(RTLockValidatorIsEnabled) +# define RTLockValidatorIsQuiet RT_MANGLER(RTLockValidatorIsQuiet) +# define RTLockValidatorMayPanic RT_MANGLER(RTLockValidatorMayPanic) +# define RTLockValidatorQueryBlocking RT_MANGLER(RTLockValidatorQueryBlocking) +# define RTLockValidatorReadLockDec RT_MANGLER(RTLockValidatorReadLockDec) +# define RTLockValidatorReadLockGetCount RT_MANGLER(RTLockValidatorReadLockGetCount) +# define RTLockValidatorReadLockInc RT_MANGLER(RTLockValidatorReadLockInc) +# define RTLockValidatorRecExclCheckBlocking RT_MANGLER(RTLockValidatorRecExclCheckBlocking) +# define RTLockValidatorRecExclCheckOrder RT_MANGLER(RTLockValidatorRecExclCheckOrder) +# define RTLockValidatorRecExclCheckOrderAndBlocking RT_MANGLER(RTLockValidatorRecExclCheckOrderAndBlocking) +# define RTLockValidatorRecExclCreate RT_MANGLER(RTLockValidatorRecExclCreate) +# define RTLockValidatorRecExclCreateV RT_MANGLER(RTLockValidatorRecExclCreateV) +# define RTLockValidatorRecExclDelete RT_MANGLER(RTLockValidatorRecExclDelete) +# define RTLockValidatorRecExclDestroy RT_MANGLER(RTLockValidatorRecExclDestroy) +# define RTLockValidatorRecExclInit RT_MANGLER(RTLockValidatorRecExclInit) +# define RTLockValidatorRecExclInitV RT_MANGLER(RTLockValidatorRecExclInitV) +# define RTLockValidatorRecExclRecursion RT_MANGLER(RTLockValidatorRecExclRecursion) +# define RTLockValidatorRecExclRecursionMixed RT_MANGLER(RTLockValidatorRecExclRecursionMixed) +# define RTLockValidatorRecExclReleaseOwner RT_MANGLER(RTLockValidatorRecExclReleaseOwner) +# define RTLockValidatorRecExclReleaseOwnerUnchecked RT_MANGLER(RTLockValidatorRecExclReleaseOwnerUnchecked) +# define RTLockValidatorRecExclSetOwner RT_MANGLER(RTLockValidatorRecExclSetOwner) +# define RTLockValidatorRecExclSetSubClass RT_MANGLER(RTLockValidatorRecExclSetSubClass) +# define RTLockValidatorRecExclUnwind RT_MANGLER(RTLockValidatorRecExclUnwind) +# define RTLockValidatorRecExclUnwindMixed RT_MANGLER(RTLockValidatorRecExclUnwindMixed) +# define RTLockValidatorRecMakeSiblings RT_MANGLER(RTLockValidatorRecMakeSiblings) +# define RTLockValidatorRecSharedAddOwner RT_MANGLER(RTLockValidatorRecSharedAddOwner) +# define RTLockValidatorRecSharedCheckAndRelease RT_MANGLER(RTLockValidatorRecSharedCheckAndRelease) +# define RTLockValidatorRecSharedCheckBlocking RT_MANGLER(RTLockValidatorRecSharedCheckBlocking) +# define RTLockValidatorRecSharedCheckOrder RT_MANGLER(RTLockValidatorRecSharedCheckOrder) +# define RTLockValidatorRecSharedCheckOrderAndBlocking RT_MANGLER(RTLockValidatorRecSharedCheckOrderAndBlocking) +# define RTLockValidatorRecSharedCheckSignaller RT_MANGLER(RTLockValidatorRecSharedCheckSignaller) +# define RTLockValidatorRecSharedCreate RT_MANGLER(RTLockValidatorRecSharedCreate) +# define RTLockValidatorRecSharedCreateV RT_MANGLER(RTLockValidatorRecSharedCreateV) +# define RTLockValidatorRecSharedDelete RT_MANGLER(RTLockValidatorRecSharedDelete) +# define RTLockValidatorRecSharedDestroy RT_MANGLER(RTLockValidatorRecSharedDestroy) +# define RTLockValidatorRecSharedInit RT_MANGLER(RTLockValidatorRecSharedInit) +# define RTLockValidatorRecSharedInitV RT_MANGLER(RTLockValidatorRecSharedInitV) +# define RTLockValidatorRecSharedIsOwner RT_MANGLER(RTLockValidatorRecSharedIsOwner) +# define RTLockValidatorRecSharedRemoveOwner RT_MANGLER(RTLockValidatorRecSharedRemoveOwner) +# define RTLockValidatorRecSharedResetOwner RT_MANGLER(RTLockValidatorRecSharedResetOwner) +# define RTLockValidatorRecSharedSetSubClass RT_MANGLER(RTLockValidatorRecSharedSetSubClass) +# define RTLockValidatorSetEnabled RT_MANGLER(RTLockValidatorSetEnabled) +# define RTLockValidatorSetMayPanic RT_MANGLER(RTLockValidatorSetMayPanic) +# define RTLockValidatorSetQuiet RT_MANGLER(RTLockValidatorSetQuiet) +# define RTLockValidatorWriteLockDec RT_MANGLER(RTLockValidatorWriteLockDec) +# define RTLockValidatorWriteLockGetCount RT_MANGLER(RTLockValidatorWriteLockGetCount) +# define RTLockValidatorWriteLockInc RT_MANGLER(RTLockValidatorWriteLockInc) +# define RTLogAssert RT_MANGLER(RTLogAssert) +# define RTLogAssertV RT_MANGLER(RTLogAssertV) +# define RTLogBackdoorPrintf RT_MANGLER(RTLogBackdoorPrintf) /* r0drv-guest */ +# define RTLogBackdoorPrintfV RT_MANGLER(RTLogBackdoorPrintfV) /* r0drv-guest */ +# define RTLogBulkUpdate RT_MANGLER(RTLogBulkUpdate) +# define RTLogBulkWrite RT_MANGLER(RTLogBulkWrite) +# define RTLogBulkNestedWrite RT_MANGLER(RTLogBulkNestedWrite) +# define RTLogChangeDestinations RT_MANGLER(RTLogChangeDestinations) +# define RTLogChangeFlags RT_MANGLER(RTLogChangeFlags) +# define RTLogCheckGroupFlags RT_MANGLER(RTLogCheckGroupFlags) +# define RTLogClearFileDelayFlag RT_MANGLER(RTLogClearFileDelayFlag) +# define RTLogCloneRC RT_MANGLER(RTLogCloneRC) +# define RTLogComPrintf RT_MANGLER(RTLogComPrintf) +# define RTLogComPrintfV RT_MANGLER(RTLogComPrintfV) +# define RTLogCreate RT_MANGLER(RTLogCreate) +# define RTLogCreateEx RT_MANGLER(RTLogCreateEx) +# define RTLogCreateExV RT_MANGLER(RTLogCreateExV) +# define RTLogDefaultInit RT_MANGLER(RTLogDefaultInit) +# define RTLogDefaultInstance RT_MANGLER(RTLogDefaultInstance) +# define RTLogDefaultInstanceEx RT_MANGLER(RTLogDefaultInstanceEx) +# define RTLogDestinations RT_MANGLER(RTLogDestinations) +# define RTLogDestroy RT_MANGLER(RTLogDestroy) +# define RTLogFlags RT_MANGLER(RTLogFlags) +# define RTLogFlush RT_MANGLER(RTLogFlush) +# define RTLogFormatV RT_MANGLER(RTLogFormatV) +# define RTLogGetDefaultInstance RT_MANGLER(RTLogGetDefaultInstance) +# define RTLogGetDefaultInstanceEx RT_MANGLER(RTLogGetDefaultInstanceEx) +# define RTLogGetDestinations RT_MANGLER(RTLogGetDestinations) +# define RTLogGetFlags RT_MANGLER(RTLogGetFlags) +# define RTLogGroupSettings RT_MANGLER(RTLogGroupSettings) +# define RTLogLogger RT_MANGLER(RTLogLogger) +# define RTLogLoggerWeak RT_MANGLER(RTLogLoggerWeak) +# define RTLogLoggerEx RT_MANGLER(RTLogLoggerEx) +# define RTLogLoggerExWeak RT_MANGLER(RTLogLoggerExWeak) +# define RTLogLoggerExV RT_MANGLER(RTLogLoggerExV) +# define RTLogLoggerV RT_MANGLER(RTLogLoggerV) +# define RTLogPrintf RT_MANGLER(RTLogPrintf) +# define RTLogPrintfV RT_MANGLER(RTLogPrintfV) +# define RTLogDumpPrintfV RT_MANGLER(RTLogDumpPrintfV) +# define RTLogQueryBulk RT_MANGLER(RTLogQueryBulk) +# define RTLogQueryDestinations RT_MANGLER(RTLogQueryDestinations) +# define RTLogQueryFlags RT_MANGLER(RTLogQueryFlags) +# define RTLogQueryGroupSettings RT_MANGLER(RTLogQueryGroupSettings) +# define RTLogRelGetDefaultInstance RT_MANGLER(RTLogRelGetDefaultInstance) +# define RTLogRelGetDefaultInstanceEx RT_MANGLER(RTLogRelGetDefaultInstanceEx) +# define RTLogRelLogger RT_MANGLER(RTLogRelLogger) +# define RTLogRelLoggerV RT_MANGLER(RTLogRelLoggerV) +# define RTLogRelPrintf RT_MANGLER(RTLogRelPrintf) +# define RTLogRelPrintfV RT_MANGLER(RTLogRelPrintfV) +# define RTLogRelSetBuffering RT_MANGLER(RTLogRelSetBuffering) +# define RTLogRelSetDefaultInstance RT_MANGLER(RTLogRelSetDefaultInstance) +# define RTLogSetBuffering RT_MANGLER(RTLogSetBuffering) +# define RTLogSetCustomPrefixCallback RT_MANGLER(RTLogSetCustomPrefixCallback) +# define RTLogSetFlushCallback RT_MANGLER(RTLogSetFlushCallback) +# define RTLogSetDefaultInstance RT_MANGLER(RTLogSetDefaultInstance) +# define RTLogSetDefaultInstanceThread RT_MANGLER(RTLogSetDefaultInstanceThread) /* r0drv */ +# define RTLogSetGroupLimit RT_MANGLER(RTLogSetGroupLimit) +# define RTLogSetR0ProgramStart RT_MANGLER(RTLogSetR0ProgramStart) /* r0drv */ +# define RTLogSetR0ThreadNameF RT_MANGLER(RTLogSetR0ThreadNameF) /* r0drv */ +# define RTLogSetR0ThreadNameV RT_MANGLER(RTLogSetR0ThreadNameV) /* r0drv */ +# define RTLogWriteCom RT_MANGLER(RTLogWriteCom) +# define RTLogWriteDebugger RT_MANGLER(RTLogWriteDebugger) +# define RTLogWriteStdErr RT_MANGLER(RTLogWriteStdErr) +# define RTLogWriteStdOut RT_MANGLER(RTLogWriteStdOut) +# define RTLogWriteUser RT_MANGLER(RTLogWriteUser) +# define RTLogWriteVmm RT_MANGLER(RTLogWriteVmm) +# define RTLogWriteVmm_EndProc RT_MANGLER(RTLogWriteVmm_EndProc) +# define RTManifestCreate RT_MANGLER(RTManifestCreate) +# define RTManifestDup RT_MANGLER(RTManifestDup) +# define RTManifestEntryAdd RT_MANGLER(RTManifestEntryAdd) +# define RTManifestEntryAddIoStream RT_MANGLER(RTManifestEntryAddIoStream) +# define RTManifestEntryAddPassthruIoStream RT_MANGLER(RTManifestEntryAddPassthruIoStream) +# define RTManifestEntryExists RT_MANGLER(RTManifestEntryExists) +# define RTManifestEntryRemove RT_MANGLER(RTManifestEntryRemove) +# define RTManifestEntryQueryAttr RT_MANGLER(RTManifestEntryQueryAttr) +# define RTManifestEntrySetAttr RT_MANGLER(RTManifestEntrySetAttr) +# define RTManifestEntryUnsetAttr RT_MANGLER(RTManifestEntryUnsetAttr) +# define RTManifestEquals RT_MANGLER(RTManifestEquals) +# define RTManifestEqualsEx RT_MANGLER(RTManifestEqualsEx) +# define RTManifestPtIosAddEntryNow RT_MANGLER(RTManifestPtIosAddEntryNow) +# define RTManifestPtIosIsInstanceOf RT_MANGLER(RTManifestPtIosIsInstanceOf) +# define RTManifestQueryAllAttrTypes RT_MANGLER(RTManifestQueryAllAttrTypes) +# define RTManifestQueryAttr RT_MANGLER(RTManifestQueryAttr) +# define RTManifestReadStandard RT_MANGLER(RTManifestReadStandard) +# define RTManifestReadStandardEx RT_MANGLER(RTManifestReadStandardEx) +# define RTManifestReadStandardFromFile RT_MANGLER(RTManifestReadStandardFromFile) +# define RTManifestRelease RT_MANGLER(RTManifestRelease) +# define RTManifestRetain RT_MANGLER(RTManifestRetain) +# define RTManifestSetAttr RT_MANGLER(RTManifestSetAttr) +# define RTManifestUnsetAttr RT_MANGLER(RTManifestUnsetAttr) +# define RTManifestVerify RT_MANGLER(RTManifestVerify) +# define RTManifestVerifyDigestType RT_MANGLER(RTManifestVerifyDigestType) +# define RTManifestVerifyFiles RT_MANGLER(RTManifestVerifyFiles) +# define RTManifestVerifyFilesBuf RT_MANGLER(RTManifestVerifyFilesBuf) +# define RTManifestWriteFiles RT_MANGLER(RTManifestWriteFiles) +# define RTManifestWriteFilesBuf RT_MANGLER(RTManifestWriteFilesBuf) +# define RTManifestWriteStandard RT_MANGLER(RTManifestWriteStandard) +# define RTManifestWriteStandardToFile RT_MANGLER(RTManifestWriteStandardToFile) +# define RTMd4 RT_MANGLER(RTMd4) +# define RTMd4Final RT_MANGLER(RTMd4Final) +# define RTMd4FromString RT_MANGLER(RTMd4FromString) +# define RTMd4Init RT_MANGLER(RTMd4Init) +# define RTMd4ToString RT_MANGLER(RTMd4ToString) +# define RTMd4Update RT_MANGLER(RTMd4Update) +# define RTMd5 RT_MANGLER(RTMd5) +# define RTMd5Final RT_MANGLER(RTMd5Final) +# define RTMd5FromString RT_MANGLER(RTMd5FromString) +# define RTMd5Init RT_MANGLER(RTMd5Init) +# define RTMd5ToString RT_MANGLER(RTMd5ToString) +# define RTMd5Update RT_MANGLER(RTMd5Update) +# define RTMemAllocExTag RT_MANGLER(RTMemAllocExTag) +# define RTMemAllocTag RT_MANGLER(RTMemAllocTag) +# define RTMemAllocVarTag RT_MANGLER(RTMemAllocVarTag) +# define RTMemAllocZTag RT_MANGLER(RTMemAllocZTag) +# define RTMemAllocZVarTag RT_MANGLER(RTMemAllocZVarTag) +# define RTMemCacheAlloc RT_MANGLER(RTMemCacheAlloc) +# define RTMemCacheAllocEx RT_MANGLER(RTMemCacheAllocEx) +# define RTMemCacheCreate RT_MANGLER(RTMemCacheCreate) +# define RTMemCacheDestroy RT_MANGLER(RTMemCacheDestroy) +# define RTMemCacheFree RT_MANGLER(RTMemCacheFree) +# define RTMemContAlloc RT_MANGLER(RTMemContAlloc) /* r0drv */ +# define RTMemContFree RT_MANGLER(RTMemContFree) /* r0drv */ +# define RTMemDump RT_MANGLER(RTMemDump) +# define RTMemDumpFreed RT_MANGLER(RTMemDumpFreed) +# define RTMemDupExTag RT_MANGLER(RTMemDupExTag) +# define RTMemDupTag RT_MANGLER(RTMemDupTag) +# define RTMemEfAlloc RT_MANGLER(RTMemEfAlloc) +# define RTMemEfAllocNP RT_MANGLER(RTMemEfAllocNP) +# define RTMemEfAllocVar RT_MANGLER(RTMemEfAllocVar) +# define RTMemEfAllocVarNP RT_MANGLER(RTMemEfAllocVarNP) +# define RTMemEfAllocZ RT_MANGLER(RTMemEfAllocZ) +# define RTMemEfAllocZNP RT_MANGLER(RTMemEfAllocZNP) +# define RTMemEfAllocZVar RT_MANGLER(RTMemEfAllocZVar) +# define RTMemEfAllocZVarNP RT_MANGLER(RTMemEfAllocZVarNP) +# define RTMemEfDup RT_MANGLER(RTMemEfDup) +# define RTMemEfDupEx RT_MANGLER(RTMemEfDupEx) +# define RTMemEfDupExNP RT_MANGLER(RTMemEfDupExNP) +# define RTMemEfDupNP RT_MANGLER(RTMemEfDupNP) +# define RTMemEfFree RT_MANGLER(RTMemEfFree) +# define RTMemEfFreeNP RT_MANGLER(RTMemEfFreeNP) +# define RTMemEfFreeZ RT_MANGLER(RTMemEfFreeZ) +# define RTMemEfFreeZNP RT_MANGLER(RTMemEfFreeZNP) +# define RTMemEfRealloc RT_MANGLER(RTMemEfRealloc) +# define RTMemEfReallocNP RT_MANGLER(RTMemEfReallocNP) +# define RTMemEfReallocZ RT_MANGLER(RTMemEfReallocZ) +# define RTMemEfReallocZNP RT_MANGLER(RTMemEfReallocZNP) +# define RTMemEfTmpAlloc RT_MANGLER(RTMemEfTmpAlloc) +# define RTMemEfTmpAllocNP RT_MANGLER(RTMemEfTmpAllocNP) +# define RTMemEfTmpAllocZ RT_MANGLER(RTMemEfTmpAllocZ) +# define RTMemEfTmpAllocZNP RT_MANGLER(RTMemEfTmpAllocZNP) +# define RTMemEfTmpFree RT_MANGLER(RTMemEfTmpFree) +# define RTMemEfTmpFreeNP RT_MANGLER(RTMemEfTmpFreeNP) +# define RTMemEfTmpFreeZ RT_MANGLER(RTMemEfTmpFreeZ) +# define RTMemEfTmpFreeZNP RT_MANGLER(RTMemEfTmpFreeZNP) +# define RTMemFree RT_MANGLER(RTMemFree) +# define RTMemFreeZ RT_MANGLER(RTMemFreeZ) +# define RTMemFreeEx RT_MANGLER(RTMemFreeEx) +# define RTMemPageAllocTag RT_MANGLER(RTMemPageAllocTag) +# define RTMemPageAllocExTag RT_MANGLER(RTMemPageAllocExTag) +# define RTMemPageAllocZTag RT_MANGLER(RTMemPageAllocZTag) +# define RTMemPageFree RT_MANGLER(RTMemPageFree) +# define RTMemPoolAlloc RT_MANGLER(RTMemPoolAlloc) +# define RTMemPoolAllocZ RT_MANGLER(RTMemPoolAllocZ) +# define RTMemPoolCreate RT_MANGLER(RTMemPoolCreate) +# define RTMemPoolDestroy RT_MANGLER(RTMemPoolDestroy) +# define RTMemPoolDup RT_MANGLER(RTMemPoolDup) +# define RTMemPoolDupEx RT_MANGLER(RTMemPoolDupEx) +# define RTMemPoolFree RT_MANGLER(RTMemPoolFree) +# define RTMemPoolRealloc RT_MANGLER(RTMemPoolRealloc) +# define RTMemPoolRefCount RT_MANGLER(RTMemPoolRefCount) +# define RTMemPoolRelease RT_MANGLER(RTMemPoolRelease) +# define RTMemPoolRetain RT_MANGLER(RTMemPoolRetain) +# define RTMemProtect RT_MANGLER(RTMemProtect) +# define RTMemReallocTag RT_MANGLER(RTMemReallocTag) +# define RTMemReallocZTag RT_MANGLER(RTMemReallocZTag) +# define RTMemTmpAllocTag RT_MANGLER(RTMemTmpAllocTag) +# define RTMemTmpAllocZTag RT_MANGLER(RTMemTmpAllocZTag) +# define RTMemTmpFree RT_MANGLER(RTMemTmpFree) +# define RTMemTmpFreeZ RT_MANGLER(RTMemTmpFreeZ) +# define RTMemTrackerDumpAllToFile RT_MANGLER(RTMemTrackerDumpAllToFile) +# define RTMemTrackerDumpAllToLog RT_MANGLER(RTMemTrackerDumpAllToLog) +# define RTMemTrackerDumpAllToLogRel RT_MANGLER(RTMemTrackerDumpAllToLogRel) +# define RTMemTrackerDumpAllToStdErr RT_MANGLER(RTMemTrackerDumpAllToStdErr) +# define RTMemTrackerDumpAllToStdOut RT_MANGLER(RTMemTrackerDumpAllToStdOut) +# define RTMemTrackerDumpStatsToFile RT_MANGLER(RTMemTrackerDumpStatsToFile) +# define RTMemTrackerDumpStatsToLog RT_MANGLER(RTMemTrackerDumpStatsToLog) +# define RTMemTrackerDumpStatsToLogRel RT_MANGLER(RTMemTrackerDumpStatsToLogRel) +# define RTMemTrackerDumpStatsToStdErr RT_MANGLER(RTMemTrackerDumpStatsToStdErr) +# define RTMemTrackerDumpStatsToStdOut RT_MANGLER(RTMemTrackerDumpStatsToStdOut) +# define RTMemTrackerHdrAlloc RT_MANGLER(RTMemTrackerHdrAlloc) +# define RTMemTrackerHdrFree RT_MANGLER(RTMemTrackerHdrFree) +# define RTMemTrackerHdrReallocDone RT_MANGLER(RTMemTrackerHdrReallocDone) +# define RTMemTrackerHdrReallocPrep RT_MANGLER(RTMemTrackerHdrReallocPrep) +# define RTMemWipeThoroughly RT_MANGLER(RTMemWipeThoroughly) +# define RTMpCpuId RT_MANGLER(RTMpCpuId) +# define RTMpCpuIdFromSetIndex RT_MANGLER(RTMpCpuIdFromSetIndex) +# define RTMpCpuIdToSetIndex RT_MANGLER(RTMpCpuIdToSetIndex) +# define RTMpCurSetIndex RT_MANGLER(RTMpCurSetIndex) +# define RTMpCurSetIndexAndId RT_MANGLER(RTMpCurSetIndexAndId) +# define RTMpGetArraySize RT_MANGLER(RTMpGetArraySize) +# define RTMpGetCount RT_MANGLER(RTMpGetCount) +# define RTMpGetCurFrequency RT_MANGLER(RTMpGetCurFrequency) +# define RTMpGetDescription RT_MANGLER(RTMpGetDescription) +# define RTMpGetCpuGroupCounts RT_MANGLER(RTMpGetCpuGroupCounts) +# define RTMpGetMaxCpuGroupCount RT_MANGLER(RTMpGetMaxCpuGroupCount) +# define RTMpGetMaxCpuId RT_MANGLER(RTMpGetMaxCpuId) +# define RTMpGetMaxFrequency RT_MANGLER(RTMpGetMaxFrequency) +# define RTMpGetOnlineCount RT_MANGLER(RTMpGetOnlineCount) +# define RTMpGetOnlineCoreCount RT_MANGLER(RTMpGetOnlineCoreCount) +# define RTMpGetOnlineSet RT_MANGLER(RTMpGetOnlineSet) +# define RTMpGetPresentCount RT_MANGLER(RTMpGetPresentCount) +# define RTMpGetPresentCoreCount RT_MANGLER(RTMpGetPresentCoreCount) +# define RTMpGetPresentSet RT_MANGLER(RTMpGetPresentSet) +# define RTMpGetSet RT_MANGLER(RTMpGetSet) +# define RTMpGetCoreCount RT_MANGLER(RTMpGetCoreCount) +# define RTMpIsCpuOnline RT_MANGLER(RTMpIsCpuOnline) +# define RTMpIsCpuPossible RT_MANGLER(RTMpIsCpuPossible) /* r0drv */ +# define RTMpIsCpuPresent RT_MANGLER(RTMpIsCpuPresent) +# define RTMpIsCpuWorkPending RT_MANGLER(RTMpIsCpuWorkPending) +# define RTMpNotificationDeregister RT_MANGLER(RTMpNotificationDeregister) /* r0drv */ +# define RTMpNotificationRegister RT_MANGLER(RTMpNotificationRegister) /* r0drv */ +# define RTMpOnAll RT_MANGLER(RTMpOnAll) /* r0drv */ +# define RTMpOnAllIsConcurrentSafe RT_MANGLER(RTMpOnAllIsConcurrentSafe) /* r0drv */ +# define RTMpOnOthers RT_MANGLER(RTMpOnOthers) /* r0drv */ +# define RTMpOnPair RT_MANGLER(RTMpOnPair) /* r0drv */ +# define RTMpOnPairIsConcurrentExecSupported RT_MANGLER(RTMpOnPairIsConcurrentExecSupported) /* r0drv */ +# define RTMpOnSpecific RT_MANGLER(RTMpOnSpecific) /* r0drv */ +# define RTMpPokeCpu RT_MANGLER(RTMpPokeCpu) /* r0drv */ +# define RTMpSetIndexFromCpuGroupMember RT_MANGLER(RTMpSetIndexFromCpuGroupMember) +# define RTMsgError RT_MANGLER(RTMsgError) +# define RTMsgErrorExit RT_MANGLER(RTMsgErrorExit) +# define RTMsgErrorExitV RT_MANGLER(RTMsgErrorExitV) +# define RTMsgErrorExitFailure RT_MANGLER(RTMsgErrorExitFailure) +# define RTMsgErrorExitFailureV RT_MANGLER(RTMsgErrorExitFailureV) +# define RTMsgErrorRc RT_MANGLER(RTMsgErrorRc) +# define RTMsgErrorRcV RT_MANGLER(RTMsgErrorRcV) +# define RTMsgErrorV RT_MANGLER(RTMsgErrorV) +# define RTMsgInfo RT_MANGLER(RTMsgInfo) +# define RTMsgInfoV RT_MANGLER(RTMsgInfoV) +# define RTMsgInitFailure RT_MANGLER(RTMsgInitFailure) +# define RTMsgSetProgName RT_MANGLER(RTMsgSetProgName) +# define RTMsgSyntax RT_MANGLER(RTMsgSyntax) +# define RTMsgSyntaxV RT_MANGLER(RTMsgSyntaxV) +# define RTMsgWarning RT_MANGLER(RTMsgWarning) +# define RTMsgWarningV RT_MANGLER(RTMsgWarningV) +# define RTMsgRefEntryPrintStringTable RT_MANGLER(RTMsgRefEntryPrintStringTable) +# define RTMsgRefEntrySynopsisEx RT_MANGLER(RTMsgRefEntrySynopsisEx) +# define RTMsgRefEntrySynopsis RT_MANGLER(RTMsgRefEntrySynopsis) +# define RTMsgRefEntryHelpEx RT_MANGLER(RTMsgRefEntryHelpEx) +# define RTMsgRefEntryHelp RT_MANGLER(RTMsgRefEntryHelp) +# define RTNetIPv4AddDataChecksum RT_MANGLER(RTNetIPv4AddDataChecksum) +# define RTNetIPv4AddTCPChecksum RT_MANGLER(RTNetIPv4AddTCPChecksum) +# define RTNetIPv4AddUDPChecksum RT_MANGLER(RTNetIPv4AddUDPChecksum) +# define RTNetIPv4FinalizeChecksum RT_MANGLER(RTNetIPv4FinalizeChecksum) +# define RTNetIPv4HdrChecksum RT_MANGLER(RTNetIPv4HdrChecksum) +# define RTNetIPv4IsDHCPValid RT_MANGLER(RTNetIPv4IsDHCPValid) +# define RTNetIPv4IsHdrValid RT_MANGLER(RTNetIPv4IsHdrValid) +# define RTNetIPv4IsTCPSizeValid RT_MANGLER(RTNetIPv4IsTCPSizeValid) +# define RTNetIPv4IsTCPValid RT_MANGLER(RTNetIPv4IsTCPValid) +# define RTNetIPv4IsUDPSizeValid RT_MANGLER(RTNetIPv4IsUDPSizeValid) +# define RTNetIPv4IsUDPValid RT_MANGLER(RTNetIPv4IsUDPValid) +# define RTNetIPv4PseudoChecksum RT_MANGLER(RTNetIPv4PseudoChecksum) +# define RTNetIPv4PseudoChecksumBits RT_MANGLER(RTNetIPv4PseudoChecksumBits) +# define RTNetIPv4TCPChecksum RT_MANGLER(RTNetIPv4TCPChecksum) +# define RTNetIPv4UDPChecksum RT_MANGLER(RTNetIPv4UDPChecksum) +# define RTNetIPv6PseudoChecksum RT_MANGLER(RTNetIPv6PseudoChecksum) +# define RTNetIPv6PseudoChecksumBits RT_MANGLER(RTNetIPv6PseudoChecksumBits) +# define RTNetIPv6PseudoChecksumEx RT_MANGLER(RTNetIPv6PseudoChecksumEx) +# define RTNetIsIPv4AddrStr RT_MANGLER(RTNetIsIPv4AddrStr) +# define RTNetIsIPv6AddrStr RT_MANGLER(RTNetIsIPv6AddrStr) +# define RTNetMaskToPrefixIPv4 RT_MANGLER(RTNetMaskToPrefixIPv4) +# define RTNetMaskToPrefixIPv6 RT_MANGLER(RTNetMaskToPrefixIPv6) +# define RTNetPrefixToMaskIPv4 RT_MANGLER(RTNetPrefixToMaskIPv4) +# define RTNetPrefixToMaskIPv6 RT_MANGLER(RTNetPrefixToMaskIPv6) +# define RTNetStrIsIPv4AddrAny RT_MANGLER(RTNetStrIsIPv4AddrAny) +# define RTNetStrIsIPv6AddrAny RT_MANGLER(RTNetStrIsIPv6AddrAny) +# define RTNetStrToIPv4Addr RT_MANGLER(RTNetStrToIPv4Addr) +# define RTNetStrToIPv4AddrEx RT_MANGLER(RTNetStrToIPv4AddrEx) +# define RTNetStrToIPv4Cidr RT_MANGLER(RTNetStrToIPv4Cidr) +# define RTNetStrToIPv6Addr RT_MANGLER(RTNetStrToIPv6Addr) +# define RTNetStrToIPv6AddrEx RT_MANGLER(RTNetStrToIPv6AddrEx) +# define RTNetStrToIPv6Cidr RT_MANGLER(RTNetStrToIPv6Cidr) +# define RTNetStrToMacAddr RT_MANGLER(RTNetStrToMacAddr) +# define RTNetTCPChecksum RT_MANGLER(RTNetTCPChecksum) +# define RTNetUDPChecksum RT_MANGLER(RTNetUDPChecksum) +# define RTOnceSlow RT_MANGLER(RTOnceSlow) +# define RTOnceReset RT_MANGLER(RTOnceReset) +# define RTPathAbs RT_MANGLER(RTPathAbs) +# define RTPathAbsDup RT_MANGLER(RTPathAbsDup) +# define RTPathAbsEx RT_MANGLER(RTPathAbsEx) +# define RTPathAbsExDup RT_MANGLER(RTPathAbsExDup) +# define RTPathAppDocs RT_MANGLER(RTPathAppDocs) +# define RTPathAppend RT_MANGLER(RTPathAppend) +# define RTPathAppendEx RT_MANGLER(RTPathAppendEx) +# define RTPathAppPrivateArch RT_MANGLER(RTPathAppPrivateArch) +# define RTPathAppPrivateArchTop RT_MANGLER(RTPathAppPrivateArchTop) +# define RTPathAppPrivateNoArch RT_MANGLER(RTPathAppPrivateNoArch) +# define RTPathCalcRelative RT_MANGLER(RTPathCalcRelative) +# define RTPathChangeToDosSlashes RT_MANGLER(RTPathChangeToDosSlashes) +# define RTPathChangeToUnixSlashes RT_MANGLER(RTPathChangeToUnixSlashes) +# define RTPathCompare RT_MANGLER(RTPathCompare) +# define RTPathCopyComponents RT_MANGLER(RTPathCopyComponents) +# define RTPathCountComponents RT_MANGLER(RTPathCountComponents) +# define RTPathEnsureTrailingSeparator RT_MANGLER(RTPathEnsureTrailingSeparator) +# define RTPathEnsureTrailingSeparatorEx RT_MANGLER(RTPathEnsureTrailingSeparatorEx) +# define RTPathExecDir RT_MANGLER(RTPathExecDir) +# define RTPathExists RT_MANGLER(RTPathExists) +# define RTPathExistsEx RT_MANGLER(RTPathExistsEx) +# define RTPathSuffix RT_MANGLER(RTPathSuffix) +# define RTPathFilename RT_MANGLER(RTPathFilename) +# define RTPathFilenameUtf16 RT_MANGLER(RTPathFilenameUtf16) +# define RTPathFilenameEx RT_MANGLER(RTPathFilenameEx) +# define RTPathFilenameExUtf16 RT_MANGLER(RTPathFilenameExUtf16) +# define RTPathFindCommon RT_MANGLER(RTPathFindCommon) +# define RTPathFindCommonEx RT_MANGLER(RTPathFindCommonEx) +# define RTPathGetCurrent RT_MANGLER(RTPathGetCurrent) +# define RTPathGetCurrentDrive RT_MANGLER(RTPathGetCurrentDrive) +# define RTPathGetCurrentOnDrive RT_MANGLER(RTPathGetCurrentOnDrive) +# define RTPathGetMode RT_MANGLER(RTPathGetMode) +# define RTPathGlob RT_MANGLER(RTPathGlob) +# define RTPathGlobFree RT_MANGLER(RTPathGlobFree) +# define RTPathHasSuffix RT_MANGLER(RTPathHasSuffix) +# define RTPathHasPath RT_MANGLER(RTPathHasPath) +# define RTPathIsSame RT_MANGLER(RTPathIsSame) +# define RTPathJoin RT_MANGLER(RTPathJoin) +# define RTPathJoinA RT_MANGLER(RTPathJoinA) +# define RTPathJoinEx RT_MANGLER(RTPathJoinEx) +# define RTPathParentLength RT_MANGLER(RTPathParentLength) +# define RTPathParentLengthEx RT_MANGLER(RTPathParentLengthEx) +# define RTPathParse RT_MANGLER(RTPathParse) +# define RTPathParsedReassemble RT_MANGLER(RTPathParsedReassemble) +# define RTPathParseSimple RT_MANGLER(RTPathParseSimple) +# define RTPathPurgeFilename RT_MANGLER(RTPathPurgeFilename) +# define RTPathQueryInfo RT_MANGLER(RTPathQueryInfo) +# define RTPathQueryInfoEx RT_MANGLER(RTPathQueryInfoEx) +# define RTPathReal RT_MANGLER(RTPathReal) +# define RTPathRealDup RT_MANGLER(RTPathRealDup) +# define RTPathRename RT_MANGLER(RTPathRename) +# define RTPathRmCmd RT_MANGLER(RTPathRmCmd) +# define RTPathSetCurrent RT_MANGLER(RTPathSetCurrent) +# define RTPathSetMode RT_MANGLER(RTPathSetMode) /* not-win */ +# define RTPathSetOwner RT_MANGLER(RTPathSetOwner) /* not-win */ +# define RTPathSetOwnerEx RT_MANGLER(RTPathSetOwnerEx) /* not-win */ +# define RTPathSetTimes RT_MANGLER(RTPathSetTimes) +# define RTPathSetTimesEx RT_MANGLER(RTPathSetTimesEx) +# define RTPathSharedLibs RT_MANGLER(RTPathSharedLibs) +# define RTPathSkipRootSpec RT_MANGLER(RTPathSkipRootSpec) +# define RTPathSplit RT_MANGLER(RTPathSplit) +# define RTPathSplitATag RT_MANGLER(RTPathSplitATag) +# define RTPathSplitFree RT_MANGLER(RTPathSplitFree) +# define RTPathSplitReassemble RT_MANGLER(RTPathSplitReassemble) +# define RTPathStartsWith RT_MANGLER(RTPathStartsWith) +# define RTPathStartsWithRoot RT_MANGLER(RTPathStartsWithRoot) +# define RTPathStripSuffix RT_MANGLER(RTPathStripSuffix) +# define RTPathStripFilename RT_MANGLER(RTPathStripFilename) +# define RTPathStripTrailingSlash RT_MANGLER(RTPathStripTrailingSlash) +# define RTPathTemp RT_MANGLER(RTPathTemp) +# define RTPathTraverseList RT_MANGLER(RTPathTraverseList) +# define RTPathUnlink RT_MANGLER(RTPathUnlink) +# define RTPathUserDocuments RT_MANGLER(RTPathUserDocuments) +# define RTPathUserHome RT_MANGLER(RTPathUserHome) +# define RTPipeClose RT_MANGLER(RTPipeClose) +# define RTPipeCloseEx RT_MANGLER(RTPipeCloseEx) +# define RTPipeCreate RT_MANGLER(RTPipeCreate) +# define RTPipeFlush RT_MANGLER(RTPipeFlush) +# define RTPipeFromNative RT_MANGLER(RTPipeFromNative) +# define RTPipeQueryInfo RT_MANGLER(RTPipeQueryInfo) +# define RTPipeQueryReadable RT_MANGLER(RTPipeQueryReadable) +# define RTPipeRead RT_MANGLER(RTPipeRead) +# define RTPipeReadBlocking RT_MANGLER(RTPipeReadBlocking) +# define RTPipeSelectOne RT_MANGLER(RTPipeSelectOne) +# define RTPipeToNative RT_MANGLER(RTPipeToNative) +# define RTPipeWrite RT_MANGLER(RTPipeWrite) +# define RTPipeWriteBlocking RT_MANGLER(RTPipeWriteBlocking) +# define RTPoll RT_MANGLER(RTPoll) +# define RTPollNoResume RT_MANGLER(RTPollNoResume) +# define RTPollSetAdd RT_MANGLER(RTPollSetAdd) +# define RTPollSetCreate RT_MANGLER(RTPollSetCreate) +# define RTPollSetDestroy RT_MANGLER(RTPollSetDestroy) +# define RTPollSetEventsChange RT_MANGLER(RTPollSetEventsChange) +# define RTPollSetGetCount RT_MANGLER(RTPollSetGetCount) +# define RTPollSetQueryHandle RT_MANGLER(RTPollSetQueryHandle) +# define RTPollSetRemove RT_MANGLER(RTPollSetRemove) +# define RTPowerNotificationDeregister RT_MANGLER(RTPowerNotificationDeregister) /* r0drv */ +# define RTPowerNotificationRegister RT_MANGLER(RTPowerNotificationRegister) /* r0drv */ +# define RTPowerSignalEvent RT_MANGLER(RTPowerSignalEvent) /* r0drv */ +# define RTPrintf RT_MANGLER(RTPrintf) +# define RTPrintfV RT_MANGLER(RTPrintfV) +# define RTProcCreate RT_MANGLER(RTProcCreate) +# define RTProcCreateEx RT_MANGLER(RTProcCreateEx) +# define RTProcDaemonize RT_MANGLER(RTProcDaemonize) +# define RTProcDaemonizeUsingFork RT_MANGLER(RTProcDaemonizeUsingFork) +# define RTProcExecutablePath RT_MANGLER(RTProcExecutablePath) +# define RTProcGetAffinityMask RT_MANGLER(RTProcGetAffinityMask) +# define RTProcGetExecutablePath RT_MANGLER(RTProcGetExecutablePath) +# define RTProcGetPriority RT_MANGLER(RTProcGetPriority) +# define RTProcIsRunningByName RT_MANGLER(RTProcIsRunningByName) +# define RTProcQueryParent RT_MANGLER(RTProcQueryParent) +# define RTProcQueryUsername RT_MANGLER(RTProcQueryUsername) +# define RTProcQueryUsernameA RT_MANGLER(RTProcQueryUsernameA) +# define RTProcSelf RT_MANGLER(RTProcSelf) +# define RTProcSetPriority RT_MANGLER(RTProcSetPriority) +# define RTProcShortName RT_MANGLER(RTProcShortName) +# define RTProcSignalName RT_MANGLER(RTProcSignalName) +# define RTProcTerminate RT_MANGLER(RTProcTerminate) +# define RTProcWait RT_MANGLER(RTProcWait) +# define RTProcWaitNoResume RT_MANGLER(RTProcWaitNoResume) +# define RTR0AssertPanicSystem RT_MANGLER(RTR0AssertPanicSystem) /* r0drv */ +# define RTR0DbgKrnlInfoOpen RT_MANGLER(RTR0DbgKrnlInfoOpen) /* r0drv */ +# define RTR0DbgKrnlInfoQueryMember RT_MANGLER(RTR0DbgKrnlInfoQueryMember) /* r0drv */ +# define RTR0DbgKrnlInfoQuerySize RT_MANGLER(RTR0DbgKrnlInfoQuerySize) /* r0drv */ +# define RTR0DbgKrnlInfoQuerySymbol RT_MANGLER(RTR0DbgKrnlInfoQuerySymbol) /* r0drv */ +# define RTR0DbgKrnlInfoGetSymbol RT_MANGLER(RTR0DbgKrnlInfoGetSymbol) /* r0drv */ +# define RTR0DbgKrnlInfoRelease RT_MANGLER(RTR0DbgKrnlInfoRelease) /* r0drv */ +# define RTR0DbgKrnlInfoRetain RT_MANGLER(RTR0DbgKrnlInfoRetain) /* r0drv */ +# define RTR0Init RT_MANGLER(RTR0Init) /* r0drv */ +# define RTR0MemAreKrnlAndUsrDifferent RT_MANGLER(RTR0MemAreKrnlAndUsrDifferent) /* r0drv */ +# define RTR0MemKernelIsValidAddr RT_MANGLER(RTR0MemKernelIsValidAddr) /* r0drv */ +# define RTR0MemObjAddress RT_MANGLER(RTR0MemObjAddress) /* r0drv */ +# define RTR0MemObjAddressR3 RT_MANGLER(RTR0MemObjAddressR3) /* r0drv */ +# define RTR0MemKernelCopyFrom RT_MANGLER(RTR0MemKernelCopyFrom) /* r0drv */ +# define RTR0MemKernelCopyTo RT_MANGLER(RTR0MemKernelCopyTo) /* r0drv */ +# define RTR0MemObjAllocContTag RT_MANGLER(RTR0MemObjAllocContTag) /* r0drv */ +# define RTR0MemObjAllocLargeTag RT_MANGLER(RTR0MemObjAllocLargeTag) /* r0drv */ +# define RTR0MemObjAllocLowTag RT_MANGLER(RTR0MemObjAllocLowTag) /* r0drv */ +# define RTR0MemObjAllocPageTag RT_MANGLER(RTR0MemObjAllocPageTag) /* r0drv */ +# define RTR0MemObjAllocPhysExTag RT_MANGLER(RTR0MemObjAllocPhysExTag) /* r0drv */ +# define RTR0MemObjAllocPhysNCTag RT_MANGLER(RTR0MemObjAllocPhysNCTag) /* r0drv */ +# define RTR0MemObjAllocPhysTag RT_MANGLER(RTR0MemObjAllocPhysTag) /* r0drv */ +# define RTR0MemObjEnterPhysTag RT_MANGLER(RTR0MemObjEnterPhysTag) /* r0drv */ +# define RTR0MemObjFree RT_MANGLER(RTR0MemObjFree) /* r0drv */ +# define RTR0MemObjGetPagePhysAddr RT_MANGLER(RTR0MemObjGetPagePhysAddr) /* r0drv */ +# define RTR0MemObjIsMapping RT_MANGLER(RTR0MemObjIsMapping) /* r0drv */ +# define RTR0MemObjLockKernelTag RT_MANGLER(RTR0MemObjLockKernelTag) /* r0drv */ +# define RTR0MemObjLockUserTag RT_MANGLER(RTR0MemObjLockUserTag) /* r0drv */ +# define RTR0MemObjMapKernelExTag RT_MANGLER(RTR0MemObjMapKernelExTag) /* r0drv */ +# define RTR0MemObjMapKernelTag RT_MANGLER(RTR0MemObjMapKernelTag) /* r0drv */ +# define RTR0MemObjMapUserTag RT_MANGLER(RTR0MemObjMapUserTag) /* r0drv */ +# define RTR0MemObjMapUserExTag RT_MANGLER(RTR0MemObjMapUserExTag) /* r0drv */ +# define RTR0MemObjProtect RT_MANGLER(RTR0MemObjProtect) /* r0drv */ +# define RTR0MemObjReserveKernelTag RT_MANGLER(RTR0MemObjReserveKernelTag) /* r0drv */ +# define RTR0MemObjReserveUserTag RT_MANGLER(RTR0MemObjReserveUserTag) /* r0drv */ +# define RTR0MemObjSize RT_MANGLER(RTR0MemObjSize) /* r0drv */ +# define RTR0MemObjWasZeroInitialized RT_MANGLER(RTR0MemObjWasZeroInitialized)/* r0drv */ +# define RTR0MemUserCopyFrom RT_MANGLER(RTR0MemUserCopyFrom) /* r0drv */ +# define RTR0MemUserCopyTo RT_MANGLER(RTR0MemUserCopyTo) /* r0drv */ +# define RTR0MemUserIsValidAddr RT_MANGLER(RTR0MemUserIsValidAddr) /* r0drv */ +# define rtR0MemObjLinuxVirtToPage RT_MANGLER(rtR0MemObjLinuxVirtToPage) /* r0drv linux-only */ +# define RTR0ProcHandleSelf RT_MANGLER(RTR0ProcHandleSelf) /* r0drv */ +# define RTR0Term RT_MANGLER(RTR0Term) /* r0drv */ +# define RTR0TermForced RT_MANGLER(RTR0TermForced) /* r0drv */ +# define RTR3InitDll RT_MANGLER(RTR3InitDll) +# define RTR3InitExe RT_MANGLER(RTR3InitExe) +# define RTR3InitExeNoArguments RT_MANGLER(RTR3InitExeNoArguments) +# define RTR3InitEx RT_MANGLER(RTR3InitEx) +# define RTR3InitIsInitialized RT_MANGLER(RTR3InitIsInitialized) +# define RTR3InitIsUnobtrusive RT_MANGLER(RTR3InitIsUnobtrusive) +# define rtR3MemAlloc RT_MANGLER(rtR3MemAlloc) +# define rtR3MemFree RT_MANGLER(rtR3MemFree) +# define rtR3MemRealloc RT_MANGLER(rtR3MemRealloc) +# define RTRCInit RT_MANGLER(RTRCInit) +# define RTRCTerm RT_MANGLER(RTRCTerm) +# define RTRandAdvBytes RT_MANGLER(RTRandAdvBytes) +# define RTRandAdvCreateParkMiller RT_MANGLER(RTRandAdvCreateParkMiller) +# define RTRandAdvCreateSystemFaster RT_MANGLER(RTRandAdvCreateSystemFaster) +# define RTRandAdvCreateSystemTruer RT_MANGLER(RTRandAdvCreateSystemTruer) +# define RTRandAdvDestroy RT_MANGLER(RTRandAdvDestroy) +# define RTRandAdvRestoreState RT_MANGLER(RTRandAdvRestoreState) +# define RTRandAdvS32 RT_MANGLER(RTRandAdvS32) +# define RTRandAdvS32Ex RT_MANGLER(RTRandAdvS32Ex) +# define RTRandAdvS64 RT_MANGLER(RTRandAdvS64) +# define RTRandAdvS64Ex RT_MANGLER(RTRandAdvS64Ex) +# define RTRandAdvSaveState RT_MANGLER(RTRandAdvSaveState) +# define RTRandAdvSeed RT_MANGLER(RTRandAdvSeed) +# define RTRandAdvU32 RT_MANGLER(RTRandAdvU32) +# define RTRandAdvU32Ex RT_MANGLER(RTRandAdvU32Ex) +# define RTRandAdvU64 RT_MANGLER(RTRandAdvU64) +# define RTRandAdvU64Ex RT_MANGLER(RTRandAdvU64Ex) +# define RTRandBytes RT_MANGLER(RTRandBytes) +# define RTRandS32 RT_MANGLER(RTRandS32) +# define RTRandS32Ex RT_MANGLER(RTRandS32Ex) +# define RTRandS64 RT_MANGLER(RTRandS64) +# define RTRandS64Ex RT_MANGLER(RTRandS64Ex) +# define RTRandU32 RT_MANGLER(RTRandU32) +# define RTRandU32Ex RT_MANGLER(RTRandU32Ex) +# define RTRandU64 RT_MANGLER(RTRandU64) +# define RTRandU64Ex RT_MANGLER(RTRandU64Ex) +# define RTReqPoolAlloc RT_MANGLER(RTReqPoolAlloc) +# define RTReqPoolCallEx RT_MANGLER(RTReqPoolCallEx) +# define RTReqPoolCallExV RT_MANGLER(RTReqPoolCallExV) +# define RTReqPoolCallWait RT_MANGLER(RTReqPoolCallWait) +# define RTReqPoolCallNoWait RT_MANGLER(RTReqPoolCallNoWait) +# define RTReqPoolCallVoidWait RT_MANGLER(RTReqPoolCallVoidWait) +# define RTReqPoolCallVoidNoWait RT_MANGLER(RTReqPoolCallVoidNoWait) +# define RTReqPoolCreate RT_MANGLER(RTReqPoolCreate) +# define RTReqPoolGetCfgVar RT_MANGLER(RTReqPoolGetCfgVar) +# define RTReqPoolGetStat RT_MANGLER(RTReqPoolGetStat) +# define RTReqPoolRetain RT_MANGLER(RTReqPoolRetain) +# define RTReqPoolRelease RT_MANGLER(RTReqPoolRelease) +# define RTReqPoolSetCfgVar RT_MANGLER(RTReqPoolSetCfgVar) +# define RTReqQueueAlloc RT_MANGLER(RTReqQueueAlloc) +# define RTReqQueueCall RT_MANGLER(RTReqQueueCall) +# define RTReqQueueCallEx RT_MANGLER(RTReqQueueCallEx) +# define RTReqQueueCallV RT_MANGLER(RTReqQueueCallV) +# define RTReqQueueCallVoid RT_MANGLER(RTReqQueueCallVoid) +# define RTReqQueueCreate RT_MANGLER(RTReqQueueCreate) +# define RTReqQueueDestroy RT_MANGLER(RTReqQueueDestroy) +# define RTReqQueueIsBusy RT_MANGLER(RTReqQueueIsBusy) +# define RTReqQueueProcess RT_MANGLER(RTReqQueueProcess) +# define RTReqCancel RT_MANGLER(RTReqCancel) +# define RTReqRelease RT_MANGLER(RTReqRelease) +# define RTReqRetain RT_MANGLER(RTReqRetain) +# define RTReqSubmit RT_MANGLER(RTReqSubmit) +# define RTReqWait RT_MANGLER(RTReqWait) +# define RTReqGetStatus RT_MANGLER(RTReqGetStatus) +# define RTS3BucketsDestroy RT_MANGLER(RTS3BucketsDestroy) +# define RTS3Create RT_MANGLER(RTS3Create) +# define RTS3CreateBucket RT_MANGLER(RTS3CreateBucket) +# define RTS3DeleteBucket RT_MANGLER(RTS3DeleteBucket) +# define RTS3DeleteKey RT_MANGLER(RTS3DeleteKey) +# define RTS3Destroy RT_MANGLER(RTS3Destroy) +# define RTS3GetBucketKeys RT_MANGLER(RTS3GetBucketKeys) +# define RTS3GetBuckets RT_MANGLER(RTS3GetBuckets) +# define RTS3GetKey RT_MANGLER(RTS3GetKey) +# define RTS3KeysDestroy RT_MANGLER(RTS3KeysDestroy) +# define RTS3PutKey RT_MANGLER(RTS3PutKey) +# define RTS3SetProgressCallback RT_MANGLER(RTS3SetProgressCallback) +# define RTSemEventAddSignaller RT_MANGLER(RTSemEventAddSignaller) +# define RTSemEventCreate RT_MANGLER(RTSemEventCreate) +# define RTSemEventCreateEx RT_MANGLER(RTSemEventCreateEx) +# define RTSemEventDestroy RT_MANGLER(RTSemEventDestroy) +# define RTSemEventGetResolution RT_MANGLER(RTSemEventGetResolution) /* r0drv */ +# define RTSemEventIsSignalSafe RT_MANGLER(RTSemEventIsSignalSafe) /* r0drv */ +# define RTSemEventMultiAddSignaller RT_MANGLER(RTSemEventMultiAddSignaller) +# define RTSemEventMultiCreate RT_MANGLER(RTSemEventMultiCreate) +# define RTSemEventMultiCreateEx RT_MANGLER(RTSemEventMultiCreateEx) +# define RTSemEventMultiDestroy RT_MANGLER(RTSemEventMultiDestroy) +# define RTSemEventMultiGetResolution RT_MANGLER(RTSemEventMultiGetResolution) /* r0drv */ +# define RTSemEventMultiIsSignalSafe RT_MANGLER(RTSemEventMultiIsSignalSafe) /* r0drv */ +# define RTSemEventMultiRemoveSignaller RT_MANGLER(RTSemEventMultiRemoveSignaller) +# define RTSemEventMultiReset RT_MANGLER(RTSemEventMultiReset) +# define RTSemEventMultiSetSignaller RT_MANGLER(RTSemEventMultiSetSignaller) +# define RTSemEventMultiSignal RT_MANGLER(RTSemEventMultiSignal) +# define RTSemEventMultiWait RT_MANGLER(RTSemEventMultiWait) +# define RTSemEventMultiWaitEx RT_MANGLER(RTSemEventMultiWaitEx) +# define RTSemEventMultiWaitEx RT_MANGLER(RTSemEventMultiWaitEx) /* r0drv */ +# define RTSemEventMultiWaitExDebug RT_MANGLER(RTSemEventMultiWaitExDebug) +# define RTSemEventMultiWaitExDebug RT_MANGLER(RTSemEventMultiWaitExDebug) /* r0drv */ +# define RTSemEventMultiWaitNoResume RT_MANGLER(RTSemEventMultiWaitNoResume) +# define RTSemEventRemoveSignaller RT_MANGLER(RTSemEventRemoveSignaller) +# define RTSemEventSetSignaller RT_MANGLER(RTSemEventSetSignaller) +# define RTSemEventSignal RT_MANGLER(RTSemEventSignal) +# define RTSemEventWait RT_MANGLER(RTSemEventWait) +# define RTSemEventWaitEx RT_MANGLER(RTSemEventWaitEx) /* r0drv */ +# define RTSemEventWaitExDebug RT_MANGLER(RTSemEventWaitExDebug) /* r0drv */ +# define RTSemEventWaitNoResume RT_MANGLER(RTSemEventWaitNoResume) +# define RTSemFastMutexCreate RT_MANGLER(RTSemFastMutexCreate) +# define RTSemFastMutexDestroy RT_MANGLER(RTSemFastMutexDestroy) +# define RTSemFastMutexRelease RT_MANGLER(RTSemFastMutexRelease) +# define RTSemFastMutexRequest RT_MANGLER(RTSemFastMutexRequest) +# define RTSemMutexCreate RT_MANGLER(RTSemMutexCreate) +# define RTSemMutexCreateEx RT_MANGLER(RTSemMutexCreateEx) +# define RTSemMutexDestroy RT_MANGLER(RTSemMutexDestroy) +# define RTSemMutexIsOwned RT_MANGLER(RTSemMutexIsOwned) +# define RTSemMutexRelease RT_MANGLER(RTSemMutexRelease) +# define RTSemMutexRequest RT_MANGLER(RTSemMutexRequest) +# define RTSemMutexRequestDebug RT_MANGLER(RTSemMutexRequestDebug) +# define RTSemMutexRequestNoResume RT_MANGLER(RTSemMutexRequestNoResume) +# define RTSemMutexRequestNoResumeDebug RT_MANGLER(RTSemMutexRequestNoResumeDebug) +# define RTSemMutexSetSubClass RT_MANGLER(RTSemMutexSetSubClass) +# define RTSemPing RT_MANGLER(RTSemPing) +# define RTSemPingPongDelete RT_MANGLER(RTSemPingPongDelete) +# define RTSemPingPongInit RT_MANGLER(RTSemPingPongInit) +# define RTSemPingWait RT_MANGLER(RTSemPingWait) +# define RTSemPong RT_MANGLER(RTSemPong) +# define RTSemPongWait RT_MANGLER(RTSemPongWait) +# define RTSemRWCreate RT_MANGLER(RTSemRWCreate) +# define RTSemRWCreateEx RT_MANGLER(RTSemRWCreateEx) +# define RTSemRWDestroy RT_MANGLER(RTSemRWDestroy) +# define RTSemRWGetReadCount RT_MANGLER(RTSemRWGetReadCount) +# define RTSemRWGetWriteRecursion RT_MANGLER(RTSemRWGetWriteRecursion) +# define RTSemRWGetWriterReadRecursion RT_MANGLER(RTSemRWGetWriterReadRecursion) +# define RTSemRWIsReadOwner RT_MANGLER(RTSemRWIsReadOwner) +# define RTSemRWIsWriteOwner RT_MANGLER(RTSemRWIsWriteOwner) +# define RTSemRWReleaseRead RT_MANGLER(RTSemRWReleaseRead) +# define RTSemRWReleaseWrite RT_MANGLER(RTSemRWReleaseWrite) +# define RTSemRWRequestRead RT_MANGLER(RTSemRWRequestRead) +# define RTSemRWRequestReadDebug RT_MANGLER(RTSemRWRequestReadDebug) +# define RTSemRWRequestReadNoResume RT_MANGLER(RTSemRWRequestReadNoResume) +# define RTSemRWRequestReadNoResumeDebug RT_MANGLER(RTSemRWRequestReadNoResumeDebug) +# define RTSemRWRequestWrite RT_MANGLER(RTSemRWRequestWrite) +# define RTSemRWRequestWriteDebug RT_MANGLER(RTSemRWRequestWriteDebug) +# define RTSemRWRequestWriteNoResume RT_MANGLER(RTSemRWRequestWriteNoResume) +# define RTSemRWRequestWriteNoResumeDebug RT_MANGLER(RTSemRWRequestWriteNoResumeDebug) +# define RTSemRWSetSubClass RT_MANGLER(RTSemRWSetSubClass) +# define RTSemSpinMutexCreate RT_MANGLER(RTSemSpinMutexCreate) +# define RTSemSpinMutexDestroy RT_MANGLER(RTSemSpinMutexDestroy) +# define RTSemSpinMutexRelease RT_MANGLER(RTSemSpinMutexRelease) +# define RTSemSpinMutexRequest RT_MANGLER(RTSemSpinMutexRequest) +# define RTSemSpinMutexTryRequest RT_MANGLER(RTSemSpinMutexTryRequest) +# define RTSemXRoadsCreate RT_MANGLER(RTSemXRoadsCreate) +# define RTSemXRoadsDestroy RT_MANGLER(RTSemXRoadsDestroy) +# define RTSemXRoadsEWEnter RT_MANGLER(RTSemXRoadsEWEnter) +# define RTSemXRoadsEWLeave RT_MANGLER(RTSemXRoadsEWLeave) +# define RTSemXRoadsNSEnter RT_MANGLER(RTSemXRoadsNSEnter) +# define RTSemXRoadsNSLeave RT_MANGLER(RTSemXRoadsNSLeave) +# define RTSerialPortOpen RT_MANGLER(RTSerialPortOpen) +# define RTSerialPortClose RT_MANGLER(RTSerialPortClose) +# define RTSerialPortToNative RT_MANGLER(RTSerialPortToNative) +# define RTSerialPortRead RT_MANGLER(RTSerialPortRead) +# define RTSerialPortReadNB RT_MANGLER(RTSerialPortReadNB) +# define RTSerialPortWrite RT_MANGLER(RTSerialPortWrite) +# define RTSerialPortWriteNB RT_MANGLER(RTSerialPortWriteNB) +# define RTSerialPortCfgQueryCurrent RT_MANGLER(RTSerialPortCfgQueryCurrent) +# define RTSerialPortCfgSet RT_MANGLER(RTSerialPortCfgSet) +# define RTSerialPortEvtPoll RT_MANGLER(RTSerialPortEvtPoll) +# define RTSerialPortEvtPollInterrupt RT_MANGLER(RTSerialPortEvtPollInterrupt) +# define RTSerialPortChgBreakCondition RT_MANGLER(RTSerialPortChgBreakCondition) +# define RTSerialPortChgStatusLines RT_MANGLER(RTSerialPortChgStatusLines) +# define RTSerialPortQueryStatusLines RT_MANGLER(RTSerialPortQueryStatusLines) +# define RTSgBufAdvance RT_MANGLER(RTSgBufAdvance) +# define RTSgBufClone RT_MANGLER(RTSgBufClone) +# define RTSgBufCmp RT_MANGLER(RTSgBufCmp) +# define RTSgBufCmpEx RT_MANGLER(RTSgBufCmpEx) +# define RTSgBufCopy RT_MANGLER(RTSgBufCopy) +# define RTSgBufCopyFromBuf RT_MANGLER(RTSgBufCopyFromBuf) +# define RTSgBufCopyFromFn RT_MANGLER(RTSgBufCopyFromFn) +# define RTSgBufCopyToBuf RT_MANGLER(RTSgBufCopyToBuf) +# define RTSgBufCopyToFn RT_MANGLER(RTSgBufCopyToFn) +# define RTSgBufInit RT_MANGLER(RTSgBufInit) +# define RTSgBufIsZero RT_MANGLER(RTSgBufIsZero) +# define RTSgBufReset RT_MANGLER(RTSgBufReset) +# define RTSgBufSegArrayCreate RT_MANGLER(RTSgBufSegArrayCreate) +# define RTSgBufSet RT_MANGLER(RTSgBufSet) +# define RTSgBufGetNextSegment RT_MANGLER(RTSgBufGetNextSegment) +# define RTSha1 RT_MANGLER(RTSha1) +# define RTSha1Check RT_MANGLER(RTSha1Check) +# define RTSha1Digest RT_MANGLER(RTSha1Digest) +# define RTSha1DigestFromFile RT_MANGLER(RTSha1DigestFromFile) +# define RTSha1Final RT_MANGLER(RTSha1Final) +# define RTSha1FromString RT_MANGLER(RTSha1FromString) +# define RTSha1Init RT_MANGLER(RTSha1Init) +# define RTSha1ToString RT_MANGLER(RTSha1ToString) +# define RTSha1Update RT_MANGLER(RTSha1Update) +# define RTSha224 RT_MANGLER(RTSha224) +# define RTSha224Check RT_MANGLER(RTSha224Check) +# define RTSha224Final RT_MANGLER(RTSha224Final) +# define RTSha224FromString RT_MANGLER(RTSha224FromString) +# define RTSha224Init RT_MANGLER(RTSha224Init) +# define RTSha224ToString RT_MANGLER(RTSha224ToString) +# define RTSha224Update RT_MANGLER(RTSha224Update) +# define RTSha224Digest RT_MANGLER(RTSha224Digest) +# define RTSha224DigestFromFile RT_MANGLER(RTSha224DigestFromFile) +# define RTSha256 RT_MANGLER(RTSha256) +# define RTSha256Check RT_MANGLER(RTSha256Check) +# define RTSha256Final RT_MANGLER(RTSha256Final) +# define RTSha256FromString RT_MANGLER(RTSha256FromString) +# define RTSha256Init RT_MANGLER(RTSha256Init) +# define RTSha256ToString RT_MANGLER(RTSha256ToString) +# define RTSha256Update RT_MANGLER(RTSha256Update) +# define RTSha256Digest RT_MANGLER(RTSha256Digest) +# define RTSha256DigestFromFile RT_MANGLER(RTSha256DigestFromFile) +# define RTSha384 RT_MANGLER(RTSha384) +# define RTSha384Check RT_MANGLER(RTSha384Check) +# define RTSha384Final RT_MANGLER(RTSha384Final) +# define RTSha384FromString RT_MANGLER(RTSha384FromString) +# define RTSha384Init RT_MANGLER(RTSha384Init) +# define RTSha384ToString RT_MANGLER(RTSha384ToString) +# define RTSha384Update RT_MANGLER(RTSha384Update) +# define RTSha512 RT_MANGLER(RTSha512) +# define RTSha512Check RT_MANGLER(RTSha512Check) +# define RTSha512Final RT_MANGLER(RTSha512Final) +# define RTSha512FromString RT_MANGLER(RTSha512FromString) +# define RTSha512Init RT_MANGLER(RTSha512Init) +# define RTSha512ToString RT_MANGLER(RTSha512ToString) +# define RTSha512Update RT_MANGLER(RTSha512Update) +# define RTSha512t224 RT_MANGLER(RTSha512t224) +# define RTSha512t224Check RT_MANGLER(RTSha512t224Check) +# define RTSha512t224Final RT_MANGLER(RTSha512t224Final) +# define RTSha512t224FromString RT_MANGLER(RTSha512t224FromString) +# define RTSha512t224Init RT_MANGLER(RTSha512t224Init) +# define RTSha512t224ToString RT_MANGLER(RTSha512t224ToString) +# define RTSha512t224Update RT_MANGLER(RTSha512t224Update) +# define RTSha512t256 RT_MANGLER(RTSha512t256) +# define RTSha512t256Check RT_MANGLER(RTSha512t256Check) +# define RTSha512t256Final RT_MANGLER(RTSha512t256Final) +# define RTSha512t256FromString RT_MANGLER(RTSha512t256FromString) +# define RTSha512t256Init RT_MANGLER(RTSha512t256Init) +# define RTSha512t256ToString RT_MANGLER(RTSha512t256ToString) +# define RTSha512t256Update RT_MANGLER(RTSha512t256Update) +# define RTSha3t224 RT_MANGLER(RTSha3t224) +# define RTSha3t224Check RT_MANGLER(RTSha3t224Check) +# define RTSha3t224Cleanup RT_MANGLER(RTSha3t224Cleanup) +# define RTSha3t224Clone RT_MANGLER(RTSha3t224Clone) +# define RTSha3t224Init RT_MANGLER(RTSha3t224Init) +# define RTSha3t224Final RT_MANGLER(RTSha3t224Final) +# define RTSha3t224FromString RT_MANGLER(RTSha3t224FromString) +# define RTSha3t224ToString RT_MANGLER(RTSha3t224ToString) +# define RTSha3t224Update RT_MANGLER(RTSha3t224Update) +# define RTSha3t256 RT_MANGLER(RTSha3t256) +# define RTSha3t256Check RT_MANGLER(RTSha3t256Check) +# define RTSha3t256Cleanup RT_MANGLER(RTSha3t256Cleanup) +# define RTSha3t256Clone RT_MANGLER(RTSha3t256Clone) +# define RTSha3t256Init RT_MANGLER(RTSha3t256Init) +# define RTSha3t256Final RT_MANGLER(RTSha3t256Final) +# define RTSha3t256FromString RT_MANGLER(RTSha3t256FromString) +# define RTSha3t256ToString RT_MANGLER(RTSha3t256ToString) +# define RTSha3t256Update RT_MANGLER(RTSha3t256Update) +# define RTSha3t384 RT_MANGLER(RTSha3t384) +# define RTSha3t384Check RT_MANGLER(RTSha3t384Check) +# define RTSha3t384Cleanup RT_MANGLER(RTSha3t384Cleanup) +# define RTSha3t384Clone RT_MANGLER(RTSha3t384Clone) +# define RTSha3t384Init RT_MANGLER(RTSha3t384Init) +# define RTSha3t384Final RT_MANGLER(RTSha3t384Final) +# define RTSha3t384FromString RT_MANGLER(RTSha3t384FromString) +# define RTSha3t384ToString RT_MANGLER(RTSha3t384ToString) +# define RTSha3t384Update RT_MANGLER(RTSha3t384Update) +# define RTSha3t512 RT_MANGLER(RTSha3t512) +# define RTSha3t512Check RT_MANGLER(RTSha3t512Check) +# define RTSha3t512Cleanup RT_MANGLER(RTSha3t512Cleanup) +# define RTSha3t512Clone RT_MANGLER(RTSha3t512Clone) +# define RTSha3t512Init RT_MANGLER(RTSha3t512Init) +# define RTSha3t512Final RT_MANGLER(RTSha3t512Final) +# define RTSha3t512FromString RT_MANGLER(RTSha3t512FromString) +# define RTSha3t512ToString RT_MANGLER(RTSha3t512ToString) +# define RTSha3t512Update RT_MANGLER(RTSha3t512Update) +# define RTShMemClose RT_MANGLER(RTShMemClose) +# define RTShMemDelete RT_MANGLER(RTShMemDelete) +# define RTShMemMapRegion RT_MANGLER(RTShMemMapRegion) +# define RTShMemOpen RT_MANGLER(RTShMemOpen) +# define RTShMemQuerySize RT_MANGLER(RTShMemQuerySize) +# define RTShMemRefCount RT_MANGLER(RTShMemRefCount) +# define RTShMemSetSize RT_MANGLER(RTShMemSetSize) +# define RTShMemUnmapRegion RT_MANGLER(RTShMemUnmapRegion) +# define RTSocketClose RT_MANGLER(RTSocketClose) +# define RTSocketFromNative RT_MANGLER(RTSocketFromNative) +# define RTSocketQueryAddressStr RT_MANGLER(RTSocketQueryAddressStr) +# define RTSocketGetLocalAddress RT_MANGLER(RTSocketGetLocalAddress) +# define RTSocketGetPeerAddress RT_MANGLER(RTSocketGetPeerAddress) +# define RTSocketParseInetAddress RT_MANGLER(RTSocketParseInetAddress) +# define RTSocketRead RT_MANGLER(RTSocketRead) +# define RTSocketReadFrom RT_MANGLER(RTSocketReadFrom) +# define RTSocketReadNB RT_MANGLER(RTSocketReadNB) +# define RTSocketRelease RT_MANGLER(RTSocketRelease) +# define RTSocketRetain RT_MANGLER(RTSocketRetain) +# define RTSocketSelectOne RT_MANGLER(RTSocketSelectOne) +# define RTSocketSelectOneEx RT_MANGLER(RTSocketSelectOneEx) +# define RTSocketSetInheritance RT_MANGLER(RTSocketSetInheritance) +# define RTSocketSgWrite RT_MANGLER(RTSocketSgWrite) +# define RTSocketSgWriteL RT_MANGLER(RTSocketSgWriteL) +# define RTSocketSgWriteLNB RT_MANGLER(RTSocketSgWriteLNB) +# define RTSocketSgWriteLV RT_MANGLER(RTSocketSgWriteLV) +# define RTSocketSgWriteLVNB RT_MANGLER(RTSocketSgWriteLVNB) +# define RTSocketSgWriteNB RT_MANGLER(RTSocketSgWriteNB) +# define RTSocketShutdown RT_MANGLER(RTSocketShutdown) +# define RTSocketToNative RT_MANGLER(RTSocketToNative) +# define RTSocketWrite RT_MANGLER(RTSocketWrite) +# define RTSocketWriteNB RT_MANGLER(RTSocketWriteNB) +# define RTSocketWriteTo RT_MANGLER(RTSocketWriteTo) +# define RTSocketWriteToNB RT_MANGLER(RTSocketWriteToNB) +# define RTSortApvIsSorted RT_MANGLER(RTSortApvIsSorted) +# define RTSortApvShell RT_MANGLER(RTSortApvShell) +# define RTSortIsSorted RT_MANGLER(RTSortIsSorted) +# define RTSortShell RT_MANGLER(RTSortShell) +# define RTSpinlockAcquire RT_MANGLER(RTSpinlockAcquire) +# define RTSpinlockAcquireNoInts RT_MANGLER(RTSpinlockAcquireNoInts) +# define RTSpinlockCreate RT_MANGLER(RTSpinlockCreate) +# define RTSpinlockDestroy RT_MANGLER(RTSpinlockDestroy) +# define RTSpinlockRelease RT_MANGLER(RTSpinlockRelease) +# define RTStrAAppendExNVTag RT_MANGLER(RTStrAAppendExNVTag) +# define RTStrAAppendNTag RT_MANGLER(RTStrAAppendNTag) +# define RTStrAAppendTag RT_MANGLER(RTStrAAppendTag) +# define RTStrAllocExTag RT_MANGLER(RTStrAllocExTag) +# define RTStrAllocTag RT_MANGLER(RTStrAllocTag) +# define RTStrAPrintf2VTag RT_MANGLER(RTStrAPrintf2VTag) +# define RTStrAPrintfVTag RT_MANGLER(RTStrAPrintfVTag) +# define RTStrATruncateTag RT_MANGLER(RTStrATruncateTag) +# define RTStrCacheCreate RT_MANGLER(RTStrCacheCreate) +# define RTStrCacheDestroy RT_MANGLER(RTStrCacheDestroy) +# define RTStrCacheEnter RT_MANGLER(RTStrCacheEnter) +# define RTStrCacheEnterLower RT_MANGLER(RTStrCacheEnterLower) +# define RTStrCacheEnterLowerN RT_MANGLER(RTStrCacheEnterLowerN) +# define RTStrCacheEnterN RT_MANGLER(RTStrCacheEnterN) +# define RTStrCacheGetStats RT_MANGLER(RTStrCacheGetStats) +# define RTStrCacheIsRealImpl RT_MANGLER(RTStrCacheIsRealImpl) +# define RTStrCacheLength RT_MANGLER(RTStrCacheLength) +# define RTStrCacheRelease RT_MANGLER(RTStrCacheRelease) +# define RTStrCacheRetain RT_MANGLER(RTStrCacheRetain) +# define RTStrCalcLatin1Len RT_MANGLER(RTStrCalcLatin1Len) +# define RTStrCalcLatin1LenEx RT_MANGLER(RTStrCalcLatin1LenEx) +# define RTStrCalcUtf16Len RT_MANGLER(RTStrCalcUtf16Len) +# define RTStrCalcUtf16LenEx RT_MANGLER(RTStrCalcUtf16LenEx) +# define RTStrCat RT_MANGLER(RTStrCat) +# define RTStrCatEx RT_MANGLER(RTStrCatEx) +# define RTStrCatP RT_MANGLER(RTStrCatP) +# define RTStrCatPEx RT_MANGLER(RTStrCatPEx) +# define RTStrCmp RT_MANGLER(RTStrCmp) +# define RTStrConvertHexBytes RT_MANGLER(RTStrConvertHexBytes) +# define RTStrConvertHexBytesEx RT_MANGLER(RTStrConvertHexBytesEx) +# define RTStrCopy RT_MANGLER(RTStrCopy) +# define RTStrCopyEx RT_MANGLER(RTStrCopyEx) +# define RTStrCopyP RT_MANGLER(RTStrCopyP) +# define RTStrCopyPEx RT_MANGLER(RTStrCopyPEx) +# define RTStrCurrentCPToUtf8Tag RT_MANGLER(RTStrCurrentCPToUtf8Tag) +# define RTStrConsoleCPToUtf8Tag RT_MANGLER(RTStrConsoleCPToUtf8Tag) +# define RTStrDupExTag RT_MANGLER(RTStrDupExTag) +# define RTStrDupNTag RT_MANGLER(RTStrDupNTag) +# define RTStrDupNExTag RT_MANGLER(RTStrDupNExTag) +# define RTStrDupTag RT_MANGLER(RTStrDupTag) +# define RTStrEnd RT_MANGLER(RTStrEnd) +# define RTStrEnd_EndProc RT_MANGLER(RTStrEnd_EndProc) +# define RTStrFormat RT_MANGLER(RTStrFormat) +# define RTStrFormatNumber RT_MANGLER(RTStrFormatNumber) +# define RTStrFormatR32 RT_MANGLER(RTStrFormatR32) +# define RTStrFormatR64 RT_MANGLER(RTStrFormatR64) +# define RTStrFormatR80 RT_MANGLER(RTStrFormatR80) +# define RTStrFormatR80u2 RT_MANGLER(RTStrFormatR80u2) +# define RTStrFormatTypeDeregister RT_MANGLER(RTStrFormatTypeDeregister) +# define RTStrFormatTypeRegister RT_MANGLER(RTStrFormatTypeRegister) +# define RTStrFormatTypeSetUser RT_MANGLER(RTStrFormatTypeSetUser) +# define RTStrFormatU128 RT_MANGLER(RTStrFormatU128) +# define RTStrFormatU256 RT_MANGLER(RTStrFormatU256) +# define RTStrFormatU512 RT_MANGLER(RTStrFormatU512) +# define RTStrFormatU16 RT_MANGLER(RTStrFormatU16) +# define RTStrFormatU32 RT_MANGLER(RTStrFormatU32) +# define RTStrFormatU64 RT_MANGLER(RTStrFormatU64) +# define RTStrFormatU8 RT_MANGLER(RTStrFormatU8) +# define RTStrFormatV RT_MANGLER(RTStrFormatV) +# define RTStrFree RT_MANGLER(RTStrFree) +# define RTStrGetCpExInternal RT_MANGLER(RTStrGetCpExInternal) +# define RTStrGetCpInternal RT_MANGLER(RTStrGetCpInternal) +# define RTStrGetCpNExInternal RT_MANGLER(RTStrGetCpNExInternal) +# define RTStrHash1 RT_MANGLER(RTStrHash1) +# define RTStrHash1ExN RT_MANGLER(RTStrHash1ExN) +# define RTStrHash1ExNV RT_MANGLER(RTStrHash1ExNV) +# define RTStrHash1N RT_MANGLER(RTStrHash1N) +# define RTStrICmp RT_MANGLER(RTStrICmp) +# define RTStrICmpAscii RT_MANGLER(RTStrICmpAscii) +# define RTStrIStartsWith RT_MANGLER(RTStrIStartsWith) +# define RTStrIStr RT_MANGLER(RTStrIStr) +# define RTStrIsCaseFoldable RT_MANGLER(RTStrIsCaseFoldable) +# define RTStrIsLowerCased RT_MANGLER(RTStrIsLowerCased) +# define RTStrIsUpperCased RT_MANGLER(RTStrIsUpperCased) +# define RTStrIsValidEncoding RT_MANGLER(RTStrIsValidEncoding) +# define RTStrMemFind16 RT_MANGLER(RTStrMemFind16) +# define RTStrMemFind16_EndProc RT_MANGLER(RTStrMemFind16_EndProc) +# define RTStrMemFind32 RT_MANGLER(RTStrMemFind32) +# define RTStrMemFind32_EndProc RT_MANGLER(RTStrMemFind32_EndProc) +# define RTStrMemFind64 RT_MANGLER(RTStrMemFind64) +# define RTStrMemFind64_EndProc RT_MANGLER(RTStrMemFind64_EndProc) +# define RTStrSplit RT_MANGLER(RTStrSplit) +# define RTStrmClearError RT_MANGLER(RTStrmClearError) +# define RTStrmClose RT_MANGLER(RTStrmClose) +# define RTStrmError RT_MANGLER(RTStrmError) +# define RTStrmFlush RT_MANGLER(RTStrmFlush) +# define RTStrmGetCh RT_MANGLER(RTStrmGetCh) +# define RTStrmGetLine RT_MANGLER(RTStrmGetLine) +# define RTStrmOpen RT_MANGLER(RTStrmOpen) +# define RTStrmOpenF RT_MANGLER(RTStrmOpenF) +# define RTStrmOpenFV RT_MANGLER(RTStrmOpenFV) +# define RTStrmOpenFileHandle RT_MANGLER(RTStrmOpenFileHandle) +# define RTStrmQueryFileHandle RT_MANGLER(RTStrmQueryFileHandle) +# define RTStrmPrintf RT_MANGLER(RTStrmPrintf) +# define RTStrmPrintfV RT_MANGLER(RTStrmPrintfV) +# define RTStrmWrappedPrintf RT_MANGLER(RTStrmWrappedPrintf) +# define RTStrmWrappedPrintfV RT_MANGLER(RTStrmWrappedPrintfV) +# define RTStrmDumpPrintfV RT_MANGLER(RTStrmDumpPrintfV) +# define RTStrmPutCh RT_MANGLER(RTStrmPutCh) +# define RTStrmPutStr RT_MANGLER(RTStrmPutStr) +# define RTStrmReadEx RT_MANGLER(RTStrmReadEx) +# define RTStrmRewind RT_MANGLER(RTStrmRewind) +# define RTStrmSetBufferingMode RT_MANGLER(RTStrmSetBufferingMode) +# define RTStrmSetMode RT_MANGLER(RTStrmSetMode) +# define RTStrmSeek RT_MANGLER(RTStrmSeek) +# define RTStrmTell RT_MANGLER(RTStrmTell) +# define RTStrmWriteEx RT_MANGLER(RTStrmWriteEx) +# define RTStrmIsTerminal RT_MANGLER(RTStrmIsTerminal) +# define RTStrmInputGetEchoChars RT_MANGLER(RTStrmInputGetEchoChars) +# define RTStrmInputSetEchoChars RT_MANGLER(RTStrmInputSetEchoChars) +# define RTStrmQueryTerminalWidth RT_MANGLER(RTStrmQueryTerminalWidth) +# define RTStrNanLongDouble RT_MANGLER(RTStrNanLongDouble) +# define RTStrNanDouble RT_MANGLER(RTStrNanDouble) +# define RTStrNanFloat RT_MANGLER(RTStrNanFloat) +# define RTStrNCmp RT_MANGLER(RTStrNCmp) +# define RTStrNICmp RT_MANGLER(RTStrNICmp) +# define RTStrNICmpAscii RT_MANGLER(RTStrNICmpAscii) +# define RTStrNLen RT_MANGLER(RTStrNLen) +# define RTStrNLenEx RT_MANGLER(RTStrNLenEx) +# define RTStrPrevCp RT_MANGLER(RTStrPrevCp) +# define RTStrPrintf RT_MANGLER(RTStrPrintf) +# define RTStrPrintfEx RT_MANGLER(RTStrPrintfEx) +# define RTStrPrintfExV RT_MANGLER(RTStrPrintfExV) +# define RTStrPrintfV RT_MANGLER(RTStrPrintfV) +# define RTStrPrintf2 RT_MANGLER(RTStrPrintf2) +# define RTStrPrintf2Ex RT_MANGLER(RTStrPrintf2Ex) +# define RTStrPrintf2ExV RT_MANGLER(RTStrPrintf2ExV) +# define RTStrPrintf2V RT_MANGLER(RTStrPrintf2V) +# define RTStrPrintHexBytes RT_MANGLER(RTStrPrintHexBytes) +# define RTStrPurgeEncoding RT_MANGLER(RTStrPurgeEncoding) +# define RTStrPurgeComplementSet RT_MANGLER(RTStrPurgeComplementSet) +# define RTStrPutCpInternal RT_MANGLER(RTStrPutCpInternal) +# define RTStrReallocTag RT_MANGLER(RTStrReallocTag) +# define RTStrSimplePatternMatch RT_MANGLER(RTStrSimplePatternMatch) +# define RTStrSimplePatternMultiMatch RT_MANGLER(RTStrSimplePatternMultiMatch) +# define RTStrSimplePatternNMatch RT_MANGLER(RTStrSimplePatternNMatch) +# define RTStrSpaceDestroy RT_MANGLER(RTStrSpaceDestroy) +# define RTStrSpaceEnumerate RT_MANGLER(RTStrSpaceEnumerate) +# define RTStrSpaceGet RT_MANGLER(RTStrSpaceGet) +# define RTStrSpaceGetN RT_MANGLER(RTStrSpaceGetN) +# define RTStrSpaceInsert RT_MANGLER(RTStrSpaceInsert) +# define RTStrSpaceRemove RT_MANGLER(RTStrSpaceRemove) +# define RTStrStartsWith RT_MANGLER(RTStrStartsWith) +# define RTStrStr RT_MANGLER(RTStrStr) +# define RTStrStrip RT_MANGLER(RTStrStrip) +# define RTStrStripL RT_MANGLER(RTStrStripL) +# define RTStrStripR RT_MANGLER(RTStrStripR) +# define RTStrToInt16 RT_MANGLER(RTStrToInt16) +# define RTStrToInt16Ex RT_MANGLER(RTStrToInt16Ex) +# define RTStrToInt16Full RT_MANGLER(RTStrToInt16Full) +# define RTStrToInt32 RT_MANGLER(RTStrToInt32) +# define RTStrToInt32Ex RT_MANGLER(RTStrToInt32Ex) +# define RTStrToInt32Full RT_MANGLER(RTStrToInt32Full) +# define RTStrToInt64 RT_MANGLER(RTStrToInt64) +# define RTStrToInt64Ex RT_MANGLER(RTStrToInt64Ex) +# define RTStrToInt64Full RT_MANGLER(RTStrToInt64Full) +# define RTStrToInt8 RT_MANGLER(RTStrToInt8) +# define RTStrToInt8Ex RT_MANGLER(RTStrToInt8Ex) +# define RTStrToInt8Full RT_MANGLER(RTStrToInt8Full) +# define RTStrToLatin1ExTag RT_MANGLER(RTStrToLatin1ExTag) +# define RTStrToLatin1Tag RT_MANGLER(RTStrToLatin1Tag) +# define RTStrToLower RT_MANGLER(RTStrToLower) +# define RTStrToUInt16 RT_MANGLER(RTStrToUInt16) +# define RTStrToUInt16Ex RT_MANGLER(RTStrToUInt16Ex) +# define RTStrToUInt16Full RT_MANGLER(RTStrToUInt16Full) +# define RTStrToUInt32 RT_MANGLER(RTStrToUInt32) +# define RTStrToUInt32Ex RT_MANGLER(RTStrToUInt32Ex) +# define RTStrToUInt32Full RT_MANGLER(RTStrToUInt32Full) +# define RTStrToUInt64 RT_MANGLER(RTStrToUInt64) +# define RTStrToUInt64Ex RT_MANGLER(RTStrToUInt64Ex) +# define RTStrToUInt64Full RT_MANGLER(RTStrToUInt64Full) +# define RTStrToUInt8 RT_MANGLER(RTStrToUInt8) +# define RTStrToUInt8Ex RT_MANGLER(RTStrToUInt8Ex) +# define RTStrToUInt8Full RT_MANGLER(RTStrToUInt8Full) +# define RTStrToFloatEx RT_MANGLER(RTStrToFloatEx) +# define RTStrToDoubleEx RT_MANGLER(RTStrToDoubleEx) +# define RTStrToLongDoubleEx RT_MANGLER(RTStrToLongDoubleEx) +# define RTStrToUni RT_MANGLER(RTStrToUni) +# define RTStrToUniEx RT_MANGLER(RTStrToUniEx) +# define RTStrToUpper RT_MANGLER(RTStrToUpper) +# define RTStrToUtf16BigExTag RT_MANGLER(RTStrToUtf16BigExTag) +# define RTStrToUtf16BigTag RT_MANGLER(RTStrToUtf16BigTag) +# define RTStrToUtf16ExTag RT_MANGLER(RTStrToUtf16ExTag) +# define RTStrToUtf16Tag RT_MANGLER(RTStrToUtf16Tag) +# define RTStrUniLen RT_MANGLER(RTStrUniLen) +# define RTStrUniLenEx RT_MANGLER(RTStrUniLenEx) +# define RTStrUtf8ToCurrentCPTag RT_MANGLER(RTStrUtf8ToCurrentCPTag) +# define RTStrUtf8ToCurrentCPExTag RT_MANGLER(RTStrUtf8ToCurrentCPExTag) +# define RTStrValidateEncoding RT_MANGLER(RTStrValidateEncoding) +# define RTStrValidateEncodingEx RT_MANGLER(RTStrValidateEncodingEx) +# define RTStrVersionCompare RT_MANGLER(RTStrVersionCompare) +# define RTSymlinkCreate RT_MANGLER(RTSymlinkCreate) +# define RTSymlinkDelete RT_MANGLER(RTSymlinkDelete) +# define RTSymlinkExists RT_MANGLER(RTSymlinkExists) +# define RTSymlinkIsDangling RT_MANGLER(RTSymlinkIsDangling) +# define RTSymlinkRead RT_MANGLER(RTSymlinkRead) +# define RTSymlinkReadA RT_MANGLER(RTSymlinkReadA) +# define RTSystemQueryFirmwareType RT_MANGLER(RTSystemQueryFirmwareType) +# define RTSystemQueryFirmwareBoolean RT_MANGLER(RTSystemQueryFirmwareBoolean) +# define RTSystemFirmwareTypeName RT_MANGLER(RTSystemFirmwareTypeName) +# define RTSystemIsInsideVM RT_MANGLER(RTSystemIsInsideVM) +# define RTSystemQueryAvailableRam RT_MANGLER(RTSystemQueryAvailableRam) +# define RTSystemQueryDmiString RT_MANGLER(RTSystemQueryDmiString) +# define RTSystemQueryOSInfo RT_MANGLER(RTSystemQueryOSInfo) +# define RTSystemQueryTotalRam RT_MANGLER(RTSystemQueryTotalRam) +# define RTSystemShutdown RT_MANGLER(RTSystemShutdown) +# define RTTarClose RT_MANGLER(RTTarClose) +# define RTTarFileClose RT_MANGLER(RTTarFileClose) +# define RTTarFileGetSize RT_MANGLER(RTTarFileGetSize) +# define RTTarFileOpen RT_MANGLER(RTTarFileOpen) +# define RTTarFileReadAt RT_MANGLER(RTTarFileReadAt) +# define RTTarFileSetSize RT_MANGLER(RTTarFileSetSize) +# define RTTarFileWriteAt RT_MANGLER(RTTarFileWriteAt) +# define RTTarOpen RT_MANGLER(RTTarOpen) +# define RTTcpClientCancelConnect RT_MANGLER(RTTcpClientCancelConnect) +# define RTTcpClientClose RT_MANGLER(RTTcpClientClose) +# define RTTcpClientCloseEx RT_MANGLER(RTTcpClientCloseEx) +# define RTTcpClientConnect RT_MANGLER(RTTcpClientConnect) +# define RTTcpClientConnectEx RT_MANGLER(RTTcpClientConnectEx) +# define RTTcpCreatePair RT_MANGLER(RTTcpCreatePair) +# define RTTcpFlush RT_MANGLER(RTTcpFlush) +# define RTTcpGetLocalAddress RT_MANGLER(RTTcpGetLocalAddress) +# define RTTcpGetPeerAddress RT_MANGLER(RTTcpGetPeerAddress) +# define RTTcpRead RT_MANGLER(RTTcpRead) +# define RTTcpReadNB RT_MANGLER(RTTcpReadNB) +# define RTTcpSelectOne RT_MANGLER(RTTcpSelectOne) +# define RTTcpSelectOneEx RT_MANGLER(RTTcpSelectOneEx) +# define RTTcpServerCreate RT_MANGLER(RTTcpServerCreate) +# define RTTcpServerCreateEx RT_MANGLER(RTTcpServerCreateEx) +# define RTTcpServerDestroy RT_MANGLER(RTTcpServerDestroy) +# define RTTcpServerDisconnectClient RT_MANGLER(RTTcpServerDisconnectClient) +# define RTTcpServerDisconnectClient2 RT_MANGLER(RTTcpServerDisconnectClient2) +# define RTTcpServerListen RT_MANGLER(RTTcpServerListen) +# define RTTcpServerListen2 RT_MANGLER(RTTcpServerListen2) +# define RTTcpServerShutdown RT_MANGLER(RTTcpServerShutdown) +# define RTTcpSetSendCoalescing RT_MANGLER(RTTcpSetSendCoalescing) +# define RTTcpSetBufferSize RT_MANGLER(RTTcpSetBufferSize) +# define RTTcpSgWrite RT_MANGLER(RTTcpSgWrite) +# define RTTcpSgWriteL RT_MANGLER(RTTcpSgWriteL) +# define RTTcpSgWriteLNB RT_MANGLER(RTTcpSgWriteLNB) +# define RTTcpSgWriteLV RT_MANGLER(RTTcpSgWriteLV) +# define RTTcpSgWriteLVNB RT_MANGLER(RTTcpSgWriteLVNB) +# define RTTcpSgWriteNB RT_MANGLER(RTTcpSgWriteNB) +# define RTTcpWrite RT_MANGLER(RTTcpWrite) +# define RTTcpWriteNB RT_MANGLER(RTTcpWriteNB) +# define RTTermDeregisterCallback RT_MANGLER(RTTermDeregisterCallback) +# define RTTermRegisterCallback RT_MANGLER(RTTermRegisterCallback) +# define RTTermRunCallbacks RT_MANGLER(RTTermRunCallbacks) +# define RTTestBanner RT_MANGLER(RTTestBanner) +# define RTTestChangeName RT_MANGLER(RTTestChangeName) +# define RTTestCreate RT_MANGLER(RTTestCreate) +# define RTTestCreateChild RT_MANGLER(RTTestCreateChild) +# define RTTestCreateEx RT_MANGLER(RTTestCreateEx) +# define RTTestDestroy RT_MANGLER(RTTestDestroy) +# define RTTestDisableAssertions RT_MANGLER(RTTestDisableAssertions) +# define RTTestErrContext RT_MANGLER(RTTestErrContext) +# define RTTestErrContextV RT_MANGLER(RTTestErrContextV) +# define RTTestErrorCount RT_MANGLER(RTTestErrorCount) +# define RTTestErrorInc RT_MANGLER(RTTestErrorInc) +# define RTTestFailed RT_MANGLER(RTTestFailed) +# define RTTestFailedV RT_MANGLER(RTTestFailedV) +# define RTTestFailureDetails RT_MANGLER(RTTestFailureDetails) +# define RTTestFailureDetailsV RT_MANGLER(RTTestFailureDetailsV) +# define RTTestGuardedAlloc RT_MANGLER(RTTestGuardedAlloc) +# define RTTestGuardedAllocHead RT_MANGLER(RTTestGuardedAllocHead) +# define RTTestGuardedAllocTail RT_MANGLER(RTTestGuardedAllocTail) +# define RTTestGuardedFree RT_MANGLER(RTTestGuardedFree) +# define RTTestIDisableAssertions RT_MANGLER(RTTestIDisableAssertions) +# define RTTestIErrContext RT_MANGLER(RTTestIErrContext) +# define RTTestIErrContextV RT_MANGLER(RTTestIErrContextV) +# define RTTestIErrorCount RT_MANGLER(RTTestIErrorCount) +# define RTTestIErrorInc RT_MANGLER(RTTestIErrorInc) +# define RTTestIFailed RT_MANGLER(RTTestIFailed) +# define RTTestIFailedRc RT_MANGLER(RTTestIFailedRc) +# define RTTestIFailedRcV RT_MANGLER(RTTestIFailedRcV) +# define RTTestIFailedV RT_MANGLER(RTTestIFailedV) +# define RTTestIFailureDetails RT_MANGLER(RTTestIFailureDetails) +# define RTTestIFailureDetailsV RT_MANGLER(RTTestIFailureDetailsV) +# define RTTestInitAndCreate RT_MANGLER(RTTestInitAndCreate) +# define RTTestInitExAndCreate RT_MANGLER(RTTestInitExAndCreate) +# define RTTestIPassed RT_MANGLER(RTTestIPassed) +# define RTTestIPassedV RT_MANGLER(RTTestIPassedV) +# define RTTestIPrintf RT_MANGLER(RTTestIPrintf) +# define RTTestIPrintfV RT_MANGLER(RTTestIPrintfV) +# define RTTestIRestoreAssertions RT_MANGLER(RTTestIRestoreAssertions) +# define RTTestISub RT_MANGLER(RTTestISub) +# define RTTestISubDone RT_MANGLER(RTTestISubDone) +# define RTTestISubF RT_MANGLER(RTTestISubF) +# define RTTestISubV RT_MANGLER(RTTestISubV) +# define RTTestIValue RT_MANGLER(RTTestIValue) +# define RTTestIValueF RT_MANGLER(RTTestIValueF) +# define RTTestIValueV RT_MANGLER(RTTestIValueV) +# define RTTestPassed RT_MANGLER(RTTestPassed) +# define RTTestPassedV RT_MANGLER(RTTestPassedV) +# define RTTestPrintf RT_MANGLER(RTTestPrintf) +# define RTTestPrintfNl RT_MANGLER(RTTestPrintfNl) +# define RTTestPrintfNlV RT_MANGLER(RTTestPrintfNlV) +# define RTTestPrintfV RT_MANGLER(RTTestPrintfV) +# define RTTestRestoreAssertions RT_MANGLER(RTTestRestoreAssertions) +# define RTTestSetDefault RT_MANGLER(RTTestSetDefault) +# define RTTestSkipAndDestroy RT_MANGLER(RTTestSkipAndDestroy) +# define RTTestSkipAndDestroyV RT_MANGLER(RTTestSkipAndDestroyV) +# define RTTestSkipped RT_MANGLER(RTTestSkipped) +# define RTTestSkippedV RT_MANGLER(RTTestSkippedV) +# define RTTestSub RT_MANGLER(RTTestSub) +# define RTTestSubDone RT_MANGLER(RTTestSubDone) +# define RTTestSubErrorCount RT_MANGLER(RTTestSubErrorCount) +# define RTTestSubF RT_MANGLER(RTTestSubF) +# define RTTestSubV RT_MANGLER(RTTestSubV) +# define RTTestSummaryAndDestroy RT_MANGLER(RTTestSummaryAndDestroy) +# define RTTestValue RT_MANGLER(RTTestValue) +# define RTTestValueF RT_MANGLER(RTTestValueF) +# define RTTestValueV RT_MANGLER(RTTestValueV) +# define RTThreadAdopt RT_MANGLER(RTThreadAdopt) +# define RTThreadBlocking RT_MANGLER(RTThreadBlocking) +# define RTThreadCreate RT_MANGLER(RTThreadCreate) +# define RTThreadCreateF RT_MANGLER(RTThreadCreateF) +# define RTThreadCreateV RT_MANGLER(RTThreadCreateV) +# define RTThreadCtxHookIsEnabled RT_MANGLER(RTThreadCtxHookIsEnabled) /* r0drv */ +# define RTThreadCtxHookCreate RT_MANGLER(RTThreadCtxHookCreate) /* r0drv */ +# define RTThreadCtxHookDestroy RT_MANGLER(RTThreadCtxHookDestroy) /* r0drv */ +# define RTThreadCtxHookDisable RT_MANGLER(RTThreadCtxHookDisable) /* r0drv */ +# define RTThreadCtxHookEnable RT_MANGLER(RTThreadCtxHookEnable) /* r0drv */ +# define RTThreadFromNative RT_MANGLER(RTThreadFromNative) +# define RTThreadGetAffinity RT_MANGLER(RTThreadGetAffinity) +# define RTThreadGetExecutionTimeMilli RT_MANGLER(RTThreadGetExecutionTimeMilli) +# define RTThreadGetName RT_MANGLER(RTThreadGetName) +# define RTThreadGetNative RT_MANGLER(RTThreadGetNative) +# define RTThreadGetNativeHandle RT_MANGLER(RTThreadGetNativeHandle) +# define RTThreadGetNativeState RT_MANGLER(RTThreadGetNativeState) +# define RTThreadGetReallySleeping RT_MANGLER(RTThreadGetReallySleeping) +# define RTThreadGetState RT_MANGLER(RTThreadGetState) +# define RTThreadGetType RT_MANGLER(RTThreadGetType) +# define RTThreadIsInInterrupt RT_MANGLER(RTThreadIsInInterrupt) /* r0drv */ +# define RTThreadIsInitialized RT_MANGLER(RTThreadIsInitialized) +# define RTThreadIsMain RT_MANGLER(RTThreadIsMain) +# define RTThreadIsSelfAlive RT_MANGLER(RTThreadIsSelfAlive) +# define RTThreadIsSelfKnown RT_MANGLER(RTThreadIsSelfKnown) +# define RTThreadNativeSelf RT_MANGLER(RTThreadNativeSelf) +# define RTThreadControlPokeSignal RT_MANGLER(RTThreadControlPokeSignal) /* not-win not-os2 */ +# define RTThreadPoke RT_MANGLER(RTThreadPoke) /* not-win not-os2 */ +# define RTThreadPreemptDisable RT_MANGLER(RTThreadPreemptDisable) /* r0drv */ +# define RTThreadPreemptIsEnabled RT_MANGLER(RTThreadPreemptIsEnabled) /* r0drv */ +# define RTThreadPreemptIsPending RT_MANGLER(RTThreadPreemptIsPending) /* r0drv */ +# define RTThreadPreemptIsPendingTrusty RT_MANGLER(RTThreadPreemptIsPendingTrusty) /* r0drv */ +# define RTThreadPreemptIsPossible RT_MANGLER(RTThreadPreemptIsPossible) /* r0drv */ +# define RTThreadPreemptRestore RT_MANGLER(RTThreadPreemptRestore) /* r0drv */ +# define RTThreadQueryTerminationStatus RT_MANGLER(RTThreadQueryTerminationStatus) /* r0drv */ +# define RTThreadSelf RT_MANGLER(RTThreadSelf) +# define RTThreadSelfAutoAdopt RT_MANGLER(RTThreadSelfAutoAdopt) +# define RTThreadSelfName RT_MANGLER(RTThreadSelfName) +# define RTThreadSetAffinity RT_MANGLER(RTThreadSetAffinity) +# define RTThreadSetAffinityToCpu RT_MANGLER(RTThreadSetAffinityToCpu) +# define RTThreadSetName RT_MANGLER(RTThreadSetName) +# define RTThreadSetType RT_MANGLER(RTThreadSetType) +# define RTThreadSleep RT_MANGLER(RTThreadSleep) +# define RTThreadSleepNoLog RT_MANGLER(RTThreadSleepNoLog) +# define RTThreadStateName RT_MANGLER(RTThreadStateName) +# define RTThreadUnblocked RT_MANGLER(RTThreadUnblocked) +# define RTThreadUserReset RT_MANGLER(RTThreadUserReset) +# define RTThreadUserSignal RT_MANGLER(RTThreadUserSignal) +# define RTThreadUserWait RT_MANGLER(RTThreadUserWait) +# define RTThreadUserWaitNoResume RT_MANGLER(RTThreadUserWaitNoResume) +# define RTThreadWait RT_MANGLER(RTThreadWait) +# define RTThreadWaitNoResume RT_MANGLER(RTThreadWaitNoResume) +# define RTThreadYield RT_MANGLER(RTThreadYield) +# define RTTimeCompare RT_MANGLER(RTTimeCompare) +# define RTTimeConvertToZulu RT_MANGLER(RTTimeConvertToZulu) +# define RTTimeDbgBad RT_MANGLER(RTTimeDbgBad) +# define RTTimeDbgExpired RT_MANGLER(RTTimeDbgExpired) +# define RTTimeDbgRaces RT_MANGLER(RTTimeDbgRaces) +# define RTTimeDbgSteps RT_MANGLER(RTTimeDbgSteps) +# define RTTimeFormatDuration RT_MANGLER(RTTimeFormatDuration) +# define RTTimeFormatDurationEx RT_MANGLER(RTTimeFormatDurationEx) +# define RTTimeExplode RT_MANGLER(RTTimeExplode) +# define RTTimeImplode RT_MANGLER(RTTimeImplode) +# define RTTimeIsLeapYear RT_MANGLER(RTTimeIsLeapYear) +# define RTTimeLocalDeltaNano RT_MANGLER(RTTimeLocalDeltaNano) +# define RTTimeLocalDeltaNanoFor RT_MANGLER(RTTimeLocalDeltaNanoFor) +# define RTTimeLocalExplode RT_MANGLER(RTTimeLocalExplode) +# define RTTimeLocalNormalize RT_MANGLER(RTTimeLocalNormalize) +# define RTTimeLocalNow RT_MANGLER(RTTimeLocalNow) +# define RTTimeMilliTS RT_MANGLER(RTTimeMilliTS) +# define RTTimeNanoTS RT_MANGLER(RTTimeNanoTS) +# define RTTimeNanoTSLegacyAsync RT_MANGLER(RTTimeNanoTSLegacyAsync) +# define RTTimeNanoTSLegacyAsync_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsync_EndProc) +# define RTTimeNanoTSLegacyAsyncUseApicId RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicId) +# define RTTimeNanoTSLegacyAsyncUseApicId_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicId_EndProc) +# define RTTimeNanoTSLegacyAsyncUseApicIdExt0B RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicIdExt0B) +# define RTTimeNanoTSLegacyAsyncUseApicIdExt0B_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicIdExt0B_EndProc) +# define RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E) +# define RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E_EndProc) +# define RTTimeNanoTSLegacyAsyncUseRdtscp RT_MANGLER(RTTimeNanoTSLegacyAsyncUseRdtscp) +# define RTTimeNanoTSLegacyAsyncUseRdtscp_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseRdtscp_EndProc) +# define RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl RT_MANGLER(RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl) +# define RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl_EndProc) +# define RTTimeNanoTSLegacyAsyncUseIdtrLim RT_MANGLER(RTTimeNanoTSLegacyAsyncUseIdtrLim) +# define RTTimeNanoTSLegacyAsyncUseIdtrLim_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseIdtrLim_EndProc) +# define RTTimeNanoTSLegacySyncInvarNoDelta RT_MANGLER(RTTimeNanoTSLegacySyncInvarNoDelta) +# define RTTimeNanoTSLegacySyncInvarNoDelta_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarNoDelta_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDelta RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDelta) +# define RTTimeNanoTSLegacySyncInvarWithDelta_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDelta_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim_EndProc) +# define RTTimeNanoTSLFenceAsync RT_MANGLER(RTTimeNanoTSLFenceAsync) +# define RTTimeNanoTSLFenceAsync_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsync_EndProc) +# define RTTimeNanoTSLFenceAsyncUseApicId RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicId) +# define RTTimeNanoTSLFenceAsyncUseApicId_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicId_EndProc) +# define RTTimeNanoTSLFenceAsyncUseApicIdExt0B RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicIdExt0B) +# define RTTimeNanoTSLFenceAsyncUseApicIdExt0B_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicIdExt0B_EndProc) +# define RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E) +# define RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E_EndProc) +# define RTTimeNanoTSLFenceAsyncUseRdtscp RT_MANGLER(RTTimeNanoTSLFenceAsyncUseRdtscp) +# define RTTimeNanoTSLFenceAsyncUseRdtscp_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseRdtscp_EndProc) +# define RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl RT_MANGLER(RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl) +# define RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl_EndProc) +# define RTTimeNanoTSLFenceAsyncUseIdtrLim RT_MANGLER(RTTimeNanoTSLFenceAsyncUseIdtrLim) +# define RTTimeNanoTSLFenceAsyncUseIdtrLim_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseIdtrLim_EndProc) +# define RTTimeNanoTSLFenceSyncInvarNoDelta RT_MANGLER(RTTimeNanoTSLFenceSyncInvarNoDelta) +# define RTTimeNanoTSLFenceSyncInvarNoDelta_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarNoDelta_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDelta RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDelta) +# define RTTimeNanoTSLFenceSyncInvarWithDelta_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDelta_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim_EndProc) +# define RTTimeNanoTSWorkerName RT_MANGLER(RTTimeNanoTSWorkerName) +# define RTTimeNormalize RT_MANGLER(RTTimeNormalize) +# define RTTimeNow RT_MANGLER(RTTimeNow) +# define RTTimeProgramMicroTS RT_MANGLER(RTTimeProgramMicroTS) +# define RTTimeProgramMilliTS RT_MANGLER(RTTimeProgramMilliTS) +# define RTTimeProgramNanoTS RT_MANGLER(RTTimeProgramNanoTS) +# define RTTimeProgramSecTS RT_MANGLER(RTTimeProgramSecTS) +# define RTTimeProgramStartNanoTS RT_MANGLER(RTTimeProgramStartNanoTS) +# define RTTimerCanDoHighResolution RT_MANGLER(RTTimerCanDoHighResolution) +# define RTTimerChangeInterval RT_MANGLER(RTTimerChangeInterval) +# define RTTimerCreate RT_MANGLER(RTTimerCreate) +# define RTTimerCreateEx RT_MANGLER(RTTimerCreateEx) +# define RTTimerDestroy RT_MANGLER(RTTimerDestroy) +# define RTTimerGetSystemGranularity RT_MANGLER(RTTimerGetSystemGranularity) /* r0drv */ +# define RTTimerLRCreate RT_MANGLER(RTTimerLRCreate) +# define RTTimerLRCreateEx RT_MANGLER(RTTimerLRCreateEx) +# define RTTimerLRDestroy RT_MANGLER(RTTimerLRDestroy) +# define RTTimerLRStart RT_MANGLER(RTTimerLRStart) +# define RTTimerLRStop RT_MANGLER(RTTimerLRStop) +# define RTTimerLRChangeInterval RT_MANGLER(RTTimerLRChangeInterval) +# define RTTimerReleaseSystemGranularity RT_MANGLER(RTTimerReleaseSystemGranularity) /* r0drv */ +# define RTTimerRequestSystemGranularity RT_MANGLER(RTTimerRequestSystemGranularity) /* r0drv */ +# define RTTimerStart RT_MANGLER(RTTimerStart) +# define RTTimerStop RT_MANGLER(RTTimerStop) +# define RTTimeSet RT_MANGLER(RTTimeSet) +# define RTTimeSpecFromString RT_MANGLER(RTTimeSpecFromString) +# define RTTimeSpecToString RT_MANGLER(RTTimeSpecToString) +# define RTTimeSystemMilliTS RT_MANGLER(RTTimeSystemMilliTS) +# define RTTimeSystemNanoTS RT_MANGLER(RTTimeSystemNanoTS) +# define RTTimeFromString RT_MANGLER(RTTimeFromString) +# define RTTimeFromRfc2822 RT_MANGLER(RTTimeFromRfc2822) +# define RTTimeToString RT_MANGLER(RTTimeToString) +# define RTTimeToStringEx RT_MANGLER(RTTimeToStringEx) +# define RTTimeToRfc2822 RT_MANGLER(RTTimeToRfc2822) +# define RTTimeZoneGetInfoByUnixName RT_MANGLER(RTTimeZoneGetInfoByUnixName) +# define RTTimeZoneGetInfoByWindowsName RT_MANGLER(RTTimeZoneGetInfoByWindowsName) +# define RTTimeZoneGetInfoByWindowsIndex RT_MANGLER(RTTimeZoneGetInfoByWindowsIndex) +# define RTTimeZoneGetCurrent RT_MANGLER(RTTimeZoneGetCurrent) +# define RTTlsAlloc RT_MANGLER(RTTlsAlloc) +# define RTTlsAllocEx RT_MANGLER(RTTlsAllocEx) +# define RTTlsFree RT_MANGLER(RTTlsFree) +# define RTTlsGet RT_MANGLER(RTTlsGet) +# define RTTlsGetEx RT_MANGLER(RTTlsGetEx) +# define RTTlsSet RT_MANGLER(RTTlsSet) +# define RTTpmOpen RT_MANGLER(RTTpmOpen) +# define RTTpmClose RT_MANGLER(RTTpmClose) +# define RTTpmGetLocalityMax RT_MANGLER(RTTpmGetLocalityMax) +# define RTTpmGetVersion RT_MANGLER(RTTpmGetVersion) +# define RTTpmReqCancel RT_MANGLER(RTTpmReqCancel) +# define RTTpmReqExec RT_MANGLER(RTTpmReqExec) +# define RTTraceBufAddMsg RT_MANGLER(RTTraceBufAddMsg) +# define RTTraceBufAddMsgEx RT_MANGLER(RTTraceBufAddMsgEx) +# define RTTraceBufAddMsgF RT_MANGLER(RTTraceBufAddMsgF) +# define RTTraceBufAddMsgV RT_MANGLER(RTTraceBufAddMsgV) +# define RTTraceBufAddPos RT_MANGLER(RTTraceBufAddPos) +# define RTTraceBufAddPosMsg RT_MANGLER(RTTraceBufAddPosMsg) +# define RTTraceBufAddPosMsgEx RT_MANGLER(RTTraceBufAddPosMsgEx) +# define RTTraceBufAddPosMsgF RT_MANGLER(RTTraceBufAddPosMsgF) +# define RTTraceBufAddPosMsgV RT_MANGLER(RTTraceBufAddPosMsgV) +# define RTTraceBufCarve RT_MANGLER(RTTraceBufCarve) +# define RTTraceBufCreate RT_MANGLER(RTTraceBufCreate) +# define RTTraceBufDisable RT_MANGLER(RTTraceBufDisable) +# define RTTraceBufDumpToAssert RT_MANGLER(RTTraceBufDumpToAssert) +# define RTTraceBufDumpToLog RT_MANGLER(RTTraceBufDumpToLog) +# define RTTraceBufEnable RT_MANGLER(RTTraceBufEnable) +# define RTTraceBufEnumEntries RT_MANGLER(RTTraceBufEnumEntries) +# define RTTraceBufGetEntryCount RT_MANGLER(RTTraceBufGetEntryCount) +# define RTTraceBufGetEntrySize RT_MANGLER(RTTraceBufGetEntrySize) +# define RTTraceBufRelease RT_MANGLER(RTTraceBufRelease) +# define RTTraceBufRetain RT_MANGLER(RTTraceBufRetain) +# define RTTraceGetDefaultBuf RT_MANGLER(RTTraceGetDefaultBuf) +# define RTTraceLogRdrCreate RT_MANGLER(RTTraceLogRdrCreate) +# define RTTraceLogRdrCreateFromFile RT_MANGLER(RTTraceLogRdrCreateFromFile) +# define RTTraceLogRdrDestroy RT_MANGLER(RTTraceLogRdrDestroy) +# define RTTraceLogRdrEvtFillVals RT_MANGLER(RTTraceLogRdrEvtFillVals) +# define RTTraceLogRdrEvtGetDesc RT_MANGLER(RTTraceLogRdrEvtGetDesc) +# define RTTraceLogRdrEvtGetSeqNo RT_MANGLER(RTTraceLogRdrEvtGetSeqNo) +# define RTTraceLogRdrEvtGetTs RT_MANGLER(RTTraceLogRdrEvtGetTs) +# define RTTraceLogRdrEvtIsGrouped RT_MANGLER(RTTraceLogRdrEvtIsGrouped) +# define RTTraceLogRdrEvtMapToStruct RT_MANGLER(RTTraceLogRdrEvtMapToStruct) +# define RTTraceLogRdrEvtMapFree RT_MANGLER(RTTraceLogRdrEvtMapFree) +# define RTTraceLogRdrEvtPoll RT_MANGLER(RTTraceLogRdrEvtPoll) +# define RTTraceLogRdrEvtQueryVal RT_MANGLER(RTTraceLogRdrEvtQueryVal) +# define RTTraceLogRdrIteratorFree RT_MANGLER(RTTraceLogRdrIteratorFree) +# define RTTraceLogRdrIteratorNext RT_MANGLER(RTTraceLogRdrIteratorNext) +# define RTTraceLogRdrIteratorQueryEvent RT_MANGLER(RTTraceLogRdrIteratorQueryEvent) +# define RTTraceLogRdrQueryIterator RT_MANGLER(RTTraceLogRdrQueryIterator) +# define RTTraceLogRdrQueryLastEvt RT_MANGLER(RTTraceLogRdrQueryLastEvt) +# define RTTraceLogWrAddEvtDesc RT_MANGLER(RTTraceLogWrAddEvtDesc) +# define RTTraceLogWrCreate RT_MANGLER(RTTraceLogWrCreate) +# define RTTraceLogWrCreateFile RT_MANGLER(RTTraceLogWrCreateFile) +# define RTTraceLogWrCreateTcpClient RT_MANGLER(RTTraceLogWrCreateTcpClient) +# define RTTraceLogWrCreateTcpServer RT_MANGLER(RTTraceLogWrCreateTcpServer) +# define RTTraceLogWrDestroy RT_MANGLER(RTTraceLogWrDestroy) +# define RTTraceLogWrEvtAdd RT_MANGLER(RTTraceLogWrEvtAdd) +# define RTTraceLogWrEvtAddL RT_MANGLER(RTTraceLogWrEvtAddL) +# define RTTraceLogWrEvtAddLV RT_MANGLER(RTTraceLogWrEvtAddLV) +# define RTTraceLogWrEvtAddSg RT_MANGLER(RTTraceLogWrEvtAddSg) +# define RTTraceSetDefaultBuf RT_MANGLER(RTTraceSetDefaultBuf) +# define RTUdpCreateClientSocket RT_MANGLER(RTUdpCreateClientSocket) +# define RTUdpCreateServerSocket RT_MANGLER(RTUdpCreateServerSocket) +# define RTUdpRead RT_MANGLER(RTUdpRead) +# define RTUdpServerCreate RT_MANGLER(RTUdpServerCreate) +# define RTUdpServerCreateEx RT_MANGLER(RTUdpServerCreateEx) +# define RTUdpServerDestroy RT_MANGLER(RTUdpServerDestroy) +# define RTUdpServerListen RT_MANGLER(RTUdpServerListen) +# define RTUdpServerShutdown RT_MANGLER(RTUdpServerShutdown) +# define RTUdpWrite RT_MANGLER(RTUdpWrite) +# define RTUniFree RT_MANGLER(RTUniFree) +# define RTUriCreate RT_MANGLER(RTUriCreate) +# define RTUriFileCreate RT_MANGLER(RTUriFileCreate) +# define RTUriFileCreateEx RT_MANGLER(RTUriFileCreateEx) +# define RTUriFilePath RT_MANGLER(RTUriFilePath) +# define RTUriFilePathEx RT_MANGLER(RTUriFilePathEx) +# define RTUriParse RT_MANGLER(RTUriParse) +# define RTUriParsedAuthority RT_MANGLER(RTUriParsedAuthority) +# define RTUriParsedAuthorityHost RT_MANGLER(RTUriParsedAuthorityHost) +# define RTUriParsedAuthorityPassword RT_MANGLER(RTUriParsedAuthorityPassword) +# define RTUriParsedAuthorityPort RT_MANGLER(RTUriParsedAuthorityPort) +# define RTUriParsedAuthorityUsername RT_MANGLER(RTUriParsedAuthorityUsername) +# define RTUriParsedFragment RT_MANGLER(RTUriParsedFragment) +# define RTUriParsedPath RT_MANGLER(RTUriParsedPath) +# define RTUriParsedScheme RT_MANGLER(RTUriParsedScheme) +# define RTUriParsedQuery RT_MANGLER(RTUriParsedQuery) +# define RTUriIsSchemeMatch RT_MANGLER(RTUriIsSchemeMatch) +# define RTUtf16AllocTag RT_MANGLER(RTUtf16AllocTag) +# define RTUtf16ReallocTag RT_MANGLER(RTUtf16ReallocTag) +# define RTUtf16CalcLatin1Len RT_MANGLER(RTUtf16CalcLatin1Len) +# define RTUtf16CalcLatin1LenEx RT_MANGLER(RTUtf16CalcLatin1LenEx) +# define RTUtf16CalcUtf8Len RT_MANGLER(RTUtf16CalcUtf8Len) +# define RTUtf16CalcUtf8LenEx RT_MANGLER(RTUtf16CalcUtf8LenEx) +# define RTUtf16BigCalcUtf8Len RT_MANGLER(RTUtf16BigCalcUtf8Len) +# define RTUtf16BigCalcUtf8LenEx RT_MANGLER(RTUtf16BigCalcUtf8LenEx) +# define RTUtf16LittleCalcUtf8Len RT_MANGLER(RTUtf16LittleCalcUtf8Len) +# define RTUtf16LittleCalcUtf8LenEx RT_MANGLER(RTUtf16LittleCalcUtf8LenEx) +# define RTUtf16Cmp RT_MANGLER(RTUtf16Cmp) +# define RTUtf16CmpAscii RT_MANGLER(RTUtf16CmpAscii) +# define RTUtf16CmpUtf8 RT_MANGLER(RTUtf16CmpUtf8) +# define RTUtf16DupExTag RT_MANGLER(RTUtf16DupExTag) +# define RTUtf16DupTag RT_MANGLER(RTUtf16DupTag) +# define RTUtf16Free RT_MANGLER(RTUtf16Free) +# define RTUtf16GetCpExInternal RT_MANGLER(RTUtf16GetCpExInternal) +# define RTUtf16GetCpNExInternal RT_MANGLER(RTUtf16GetCpNExInternal) +# define RTUtf16BigGetCpExInternal RT_MANGLER(RTUtf16BigGetCpExInternal) +# define RTUtf16GetCpInternal RT_MANGLER(RTUtf16GetCpInternal) +# define RTUtf16BigGetCpInternal RT_MANGLER(RTUtf16BigGetCpInternal) +# define RTUtf16NCmp RT_MANGLER(RTUtf16NCmp) +# define RTUtf16NCmpAscii RT_MANGLER(RTUtf16NCmpAscii) +# define RTUtf16NCmpUtf8 RT_MANGLER(RTUtf16NCmpUtf8) +# define RTUtf16ICmp RT_MANGLER(RTUtf16ICmp) +# define RTUtf16BigICmp RT_MANGLER(RTUtf16BigICmp) +# define RTUtf16ICmpUtf8 RT_MANGLER(RTUtf16ICmpUtf8) +# define RTUtf16NICmp RT_MANGLER(RTUtf16NICmp) +# define RTUtf16BigNICmp RT_MANGLER(RTUtf16BigNICmp) +# define RTUtf16FindAscii RT_MANGLER(RTUtf16FindAscii) +# define RTUtf16IsValidEncoding RT_MANGLER(RTUtf16IsValidEncoding) +# define RTUtf16Len RT_MANGLER(RTUtf16Len) +# define RTUtf16LocaleICmp RT_MANGLER(RTUtf16LocaleICmp) +# define RTUtf16PutCpInternal RT_MANGLER(RTUtf16PutCpInternal) +# define RTUtf16BigPutCpInternal RT_MANGLER(RTUtf16BigPutCpInternal) +# define RTUtf16ToLatin1ExTag RT_MANGLER(RTUtf16ToLatin1ExTag) +# define RTUtf16ToLatin1Tag RT_MANGLER(RTUtf16ToLatin1Tag) +# define RTUtf16ToLower RT_MANGLER(RTUtf16ToLower) +# define RTUtf16ToUpper RT_MANGLER(RTUtf16ToUpper) +# define RTUtf16PurgeComplementSet RT_MANGLER(RTUtf16PurgeComplementSet) +# define RTUtf16ToUtf8ExTag RT_MANGLER(RTUtf16ToUtf8ExTag) +# define RTUtf16BigToUtf8ExTag RT_MANGLER(RTUtf16BigToUtf8ExTag) +# define RTUtf16LittleToUtf8ExTag RT_MANGLER(RTUtf16LittleToUtf8ExTag) +# define RTUtf16ToUtf8Tag RT_MANGLER(RTUtf16ToUtf8Tag) +# define RTUtf16BigToUtf8Tag RT_MANGLER(RTUtf16BigToUtf8Tag) +# define RTUtf16LittleToUtf8Tag RT_MANGLER(RTUtf16LittleToUtf8Tag) +# define RTUtf16ValidateEncoding RT_MANGLER(RTUtf16ValidateEncoding) +# define RTUtf16ValidateEncodingEx RT_MANGLER(RTUtf16ValidateEncodingEx) +# define RTUtf16Printf RT_MANGLER(RTUtf16Printf) +# define RTUtf16PrintfV RT_MANGLER(RTUtf16PrintfV) +# define RTUtf16PrintfEx RT_MANGLER(RTUtf16PrintfEx) +# define RTUtf16PrintfExV RT_MANGLER(RTUtf16PrintfExV) +# define RTUuidClear RT_MANGLER(RTUuidClear) +# define RTUuidCompare RT_MANGLER(RTUuidCompare) +# define RTUuidCompare2Strs RT_MANGLER(RTUuidCompare2Strs) +# define RTUuidCompareStr RT_MANGLER(RTUuidCompareStr) +# define RTUuidCreate RT_MANGLER(RTUuidCreate) +# define RTUuidFromStr RT_MANGLER(RTUuidFromStr) +# define RTUuidFromUtf16 RT_MANGLER(RTUuidFromUtf16) +# define RTUuidIsNull RT_MANGLER(RTUuidIsNull) +# define RTUuidToStr RT_MANGLER(RTUuidToStr) +# define RTUuidToUtf16 RT_MANGLER(RTUuidToUtf16) +# define RTVfsChainElementDeregisterProvider RT_MANGLER(RTVfsChainElementDeregisterProvider) +# define RTVfsChainElementRegisterProvider RT_MANGLER(RTVfsChainElementRegisterProvider) +# define RTVfsChainIsSpec RT_MANGLER(RTVfsChainIsSpec) +# define RTVfsChainMsgError RT_MANGLER(RTVfsChainMsgError) +# define RTVfsChainMsgErrorExitFailure RT_MANGLER(RTVfsChainMsgErrorExitFailure) +# define RTVfsChainOpenObj RT_MANGLER(RTVfsChainOpenObj) +# define RTVfsChainOpenDir RT_MANGLER(RTVfsChainOpenDir) +# define RTVfsChainOpenParentDir RT_MANGLER(RTVfsChainOpenParentDir) +# define RTVfsChainOpenFile RT_MANGLER(RTVfsChainOpenFile) +# define RTVfsChainOpenIoStream RT_MANGLER(RTVfsChainOpenIoStream) +# define RTVfsChainQueryFinalPath RT_MANGLER(RTVfsChainQueryFinalPath) +# define RTVfsChainQueryInfo RT_MANGLER(RTVfsChainQueryInfo) +# define RTVfsChainSpecCheckAndSetup RT_MANGLER(RTVfsChainSpecCheckAndSetup) +# define RTVfsChainSpecFree RT_MANGLER(RTVfsChainSpecFree) +# define RTVfsChainSpecParse RT_MANGLER(RTVfsChainSpecParse) +# define RTVfsChainSplitOffFinalPath RT_MANGLER(RTVfsChainSplitOffFinalPath) +# define RTVfsChainValidateOpenFileOrIoStream RT_MANGLER(RTVfsChainValidateOpenFileOrIoStream) +# define RTVfsDirRelease RT_MANGLER(RTVfsDirRelease) +# define RTVfsDirRetain RT_MANGLER(RTVfsDirRetain) +# define RTVfsDirRetainDebug RT_MANGLER(RTVfsDirRetainDebug) +# define RTVfsDirOpen RT_MANGLER(RTVfsDirOpen) +# define RTVfsDirOpenDir RT_MANGLER(RTVfsDirOpenDir) +# define RTVfsDirCreateDir RT_MANGLER(RTVfsDirCreateDir) +# define RTVfsDirOpenFile RT_MANGLER(RTVfsDirOpenFile) +# define RTVfsDirOpenFileAsIoStream RT_MANGLER(RTVfsDirOpenFileAsIoStream) +# define RTVfsDirOpenObj RT_MANGLER(RTVfsDirOpenObj) +# define RTVfsDirQueryPathInfo RT_MANGLER(RTVfsDirQueryPathInfo) +# define RTVfsDirReadEx RT_MANGLER(RTVfsDirReadEx) +# define RTVfsDirRemoveDir RT_MANGLER(RTVfsDirRemoveDir) +# define RTVfsDirRewind RT_MANGLER(RTVfsDirRewind) +# define RTVfsDirSetPathMode RT_MANGLER(RTVfsDirSetPathMode) +# define RTVfsDirToPrivate RT_MANGLER(RTVfsDirToPrivate) +# define RTVfsFileFlush RT_MANGLER(RTVfsFileFlush) +# define RTVfsFileFromBuffer RT_MANGLER(RTVfsFileFromBuffer) +# define RTVfsFileFromRTFile RT_MANGLER(RTVfsFileFromRTFile) +# define RTVfsFileGetOpenFlags RT_MANGLER(RTVfsFileGetOpenFlags) +# define RTVfsFileQuerySize RT_MANGLER(RTVfsFileQuerySize) +# define RTVfsFileGetMaxSize RT_MANGLER(RTVfsFileGetMaxSize) +# define RTVfsFileOpen RT_MANGLER(RTVfsFileOpen) +# define RTVfsFileOpenNormal RT_MANGLER(RTVfsFileOpenNormal) +# define RTVfsFilePoll RT_MANGLER(RTVfsFilePoll) +# define RTVfsFilePrintf RT_MANGLER(RTVfsFilePrintf) +# define RTVfsFilePrintfV RT_MANGLER(RTVfsFilePrintfV) +# define RTVfsFileQueryInfo RT_MANGLER(RTVfsFileQueryInfo) +# define RTVfsFileQueryMaxSize RT_MANGLER(RTVfsFileQueryMaxSize) +# define RTVfsFileRead RT_MANGLER(RTVfsFileRead) +# define RTVfsFileReadAt RT_MANGLER(RTVfsFileReadAt) +# define RTVfsFileRelease RT_MANGLER(RTVfsFileRelease) +# define RTVfsFileRetain RT_MANGLER(RTVfsFileRetain) +# define RTVfsFileRetainDebug RT_MANGLER(RTVfsFileRetainDebug) +# define RTVfsFileSeek RT_MANGLER(RTVfsFileSeek) +# define RTVfsFileSetSize RT_MANGLER(RTVfsFileSetSize) +# define RTVfsFileSgRead RT_MANGLER(RTVfsFileSgRead) +# define RTVfsFileSgWrite RT_MANGLER(RTVfsFileSgWrite) +# define RTVfsFileTell RT_MANGLER(RTVfsFileTell) +# define RTVfsFileToIoStream RT_MANGLER(RTVfsFileToIoStream) +# define RTVfsFileWrite RT_MANGLER(RTVfsFileWrite) +# define RTVfsFileWriteAt RT_MANGLER(RTVfsFileWriteAt) +# define RTVfsFsStreamToPrivate RT_MANGLER(RTVfsFsStreamToPrivate) +# define RTVfsFsStrmAdd RT_MANGLER(RTVfsFsStrmAdd) +# define RTVfsFsStrmEnd RT_MANGLER(RTVfsFsStrmEnd) +# define RTVfsFsStrmNext RT_MANGLER(RTVfsFsStrmNext) +# define RTVfsFsStrmPushFile RT_MANGLER(RTVfsFsStrmPushFile) +# define RTVfsFsStrmQueryInfo RT_MANGLER(RTVfsFsStrmQueryInfo) +# define RTVfsFsStrmRelease RT_MANGLER(RTVfsFsStrmRelease) +# define RTVfsFsStrmRetain RT_MANGLER(RTVfsFsStrmRetain) +# define RTVfsFsStrmRetainDebug RT_MANGLER(RTVfsFsStrmRetainDebug) +# define RTVfsFsStrmToDir RT_MANGLER(RTVfsFsStrmToDir) +# define RTVfsFsStrmToNormalDir RT_MANGLER(RTVfsFsStrmToNormalDir) +# define RTVfsFsStrmToDirUndo RT_MANGLER(RTVfsFsStrmToDirUndo) +# define RTVfsIoStreamToPrivate RT_MANGLER(RTVfsIoStreamToPrivate) +# define RTVfsIoStrmFlush RT_MANGLER(RTVfsIoStrmFlush) +# define RTVfsIoStrmFromBuffer RT_MANGLER(RTVfsIoStrmFromBuffer) +# define RTVfsIoStrmFromRTFile RT_MANGLER(RTVfsIoStrmFromRTFile) +# define RTVfsIoStrmFromRTPipe RT_MANGLER(RTVfsIoStrmFromRTPipe) +# define RTVfsIoStrmFromStdHandle RT_MANGLER(RTVfsIoStrmFromStdHandle) +# define RTVfsIoStrmGetOpenFlags RT_MANGLER(RTVfsIoStrmGetOpenFlags) +# define RTVfsIoStrmIsAtEnd RT_MANGLER(RTVfsIoStrmIsAtEnd) +# define RTVfsIoStrmOpenNormal RT_MANGLER(RTVfsIoStrmOpenNormal) +# define RTVfsIoStrmPoll RT_MANGLER(RTVfsIoStrmPoll) +# define RTVfsIoStrmPrintf RT_MANGLER(RTVfsIoStrmPrintf) +# define RTVfsIoStrmPrintfV RT_MANGLER(RTVfsIoStrmPrintfV) +# define RTVfsIoStrmQueryInfo RT_MANGLER(RTVfsIoStrmQueryInfo) +# define RTVfsIoStrmRead RT_MANGLER(RTVfsIoStrmRead) +# define RTVfsIoStrmReadAt RT_MANGLER(RTVfsIoStrmReadAt) +# define RTVfsIoStrmReadAll RT_MANGLER(RTVfsIoStrmReadAll) +# define RTVfsIoStrmReadAllFree RT_MANGLER(RTVfsIoStrmReadAllFree) +# define RTVfsIoStrmRelease RT_MANGLER(RTVfsIoStrmRelease) +# define RTVfsIoStrmRetain RT_MANGLER(RTVfsIoStrmRetain) +# define RTVfsIoStrmRetainDebug RT_MANGLER(RTVfsIoStrmRetainDebug) +# define RTVfsIoStrmSgRead RT_MANGLER(RTVfsIoStrmSgRead) +# define RTVfsIoStrmSgWrite RT_MANGLER(RTVfsIoStrmSgWrite) +# define RTVfsIoStrmSkip RT_MANGLER(RTVfsIoStrmSkip) +# define RTVfsIoStrmStrOutputCallback RT_MANGLER(RTVfsIoStrmStrOutputCallback) +# define RTVfsIoStrmTell RT_MANGLER(RTVfsIoStrmTell) +# define RTVfsIoStrmToFile RT_MANGLER(RTVfsIoStrmToFile) +# define RTVfsIoStrmValidateUtf8Encoding RT_MANGLER(RTVfsIoStrmValidateUtf8Encoding) +# define RTVfsIoStrmWrite RT_MANGLER(RTVfsIoStrmWrite) +# define RTVfsIoStrmWriteAt RT_MANGLER(RTVfsIoStrmWriteAt) +# define RTVfsIoStrmZeroFill RT_MANGLER(RTVfsIoStrmZeroFill) +# define RTVfsQueryLabel RT_MANGLER(RTVfsQueryLabel) +# define RTVfsQueryRangeState RT_MANGLER(RTVfsQueryRangeState) +# define RTVfsLockAcquireReadSlow RT_MANGLER(RTVfsLockAcquireReadSlow) +# define RTVfsLockAcquireWriteSlow RT_MANGLER(RTVfsLockAcquireWriteSlow) +# define RTVfsLockRelease RT_MANGLER(RTVfsLockRelease) +# define RTVfsLockReleaseReadSlow RT_MANGLER(RTVfsLockReleaseReadSlow) +# define RTVfsLockReleaseWriteSlow RT_MANGLER(RTVfsLockReleaseWriteSlow) +# define RTVfsLockRetain RT_MANGLER(RTVfsLockRetain) +# define RTVfsLockRetainDebug RT_MANGLER(RTVfsLockRetainDebug) +# define RTVfsMemFileCreate RT_MANGLER(RTVfsMemFileCreate) +# define RTVfsMemIoStrmCreate RT_MANGLER(RTVfsMemIoStrmCreate) +# define RTVfsMemorizeIoStreamAsFile RT_MANGLER(RTVfsMemorizeIoStreamAsFile) +# define RTVfsNew RT_MANGLER(RTVfsNew) +# define RTVfsNewBaseObj RT_MANGLER(RTVfsNewBaseObj) +# define RTVfsNewDir RT_MANGLER(RTVfsNewDir) +# define RTVfsNewFile RT_MANGLER(RTVfsNewFile) +# define RTVfsNewFsStream RT_MANGLER(RTVfsNewFsStream) +# define RTVfsNewIoStream RT_MANGLER(RTVfsNewIoStream) +# define RTVfsNewSymlink RT_MANGLER(RTVfsNewSymlink) +# define RTVfsObjFromDir RT_MANGLER(RTVfsObjFromDir) +# define RTVfsObjFromFile RT_MANGLER(RTVfsObjFromFile) +# define RTVfsObjFromFsStream RT_MANGLER(RTVfsObjFromFsStream) +# define RTVfsObjFromIoStream RT_MANGLER(RTVfsObjFromIoStream) +# define RTVfsObjFromSymlink RT_MANGLER(RTVfsObjFromSymlink) +# define RTVfsObjFromVfs RT_MANGLER(RTVfsObjFromVfs) +# define RTVfsObjGetType RT_MANGLER(RTVfsObjGetType) +# define RTVfsObjOpen RT_MANGLER(RTVfsObjOpen) +# define RTVfsObjQueryInfo RT_MANGLER(RTVfsObjQueryInfo) +# define RTVfsObjRelease RT_MANGLER(RTVfsObjRelease) +# define RTVfsObjRetain RT_MANGLER(RTVfsObjRetain) +# define RTVfsObjRetainDebug RT_MANGLER(RTVfsObjRetainDebug) +# define RTVfsObjSetMode RT_MANGLER(RTVfsObjSetMode) +# define RTVfsObjSetOwner RT_MANGLER(RTVfsObjSetOwner) +# define RTVfsObjSetTimes RT_MANGLER(RTVfsObjSetTimes) +# define RTVfsObjToDir RT_MANGLER(RTVfsObjToDir) +# define RTVfsObjToFile RT_MANGLER(RTVfsObjToFile) +# define RTVfsObjToFsStream RT_MANGLER(RTVfsObjToFsStream) +# define RTVfsObjToIoStream RT_MANGLER(RTVfsObjToIoStream) +# define RTVfsObjToPrivate RT_MANGLER(RTVfsObjToPrivate) +# define RTVfsObjToSymlink RT_MANGLER(RTVfsObjToSymlink) +# define RTVfsObjToVfs RT_MANGLER(RTVfsObjToVfs) +# define RTVfsParsePath RT_MANGLER(RTVfsParsePath) +# define RTVfsParsePathA RT_MANGLER(RTVfsParsePathA) +# define RTVfsParsePathAppend RT_MANGLER(RTVfsParsePathAppend) +# define RTVfsParsePathFree RT_MANGLER(RTVfsParsePathFree) +# define RTVfsRelease RT_MANGLER(RTVfsRelease) +# define RTVfsOpenRoot RT_MANGLER(RTVfsOpenRoot) +# define RTVfsQuerPathInfo RT_MANGLER(RTVfsQueryPathInfo) +# define RTVfsMountVol RT_MANGLER(RTVfsMountVol) +# define RTVfsRetain RT_MANGLER(RTVfsRetain) +# define RTVfsRetainDebug RT_MANGLER(RTVfsRetainDebug) +# define RTVfsSymlinkQueryInfo RT_MANGLER(RTVfsSymlinkQueryInfo) +# define RTVfsSymlinkRead RT_MANGLER(RTVfsSymlinkRead) +# define RTVfsSymlinkRelease RT_MANGLER(RTVfsSymlinkRelease) +# define RTVfsSymlinkRetain RT_MANGLER(RTVfsSymlinkRetain) +# define RTVfsSymlinkRetainDebug RT_MANGLER(RTVfsSymlinkRetainDebug) +# define RTVfsSymlinkSetMode RT_MANGLER(RTVfsSymlinkSetMode) +# define RTVfsSymlinkSetOwner RT_MANGLER(RTVfsSymlinkSetOwner) +# define RTVfsSymlinkSetTimes RT_MANGLER(RTVfsSymlinkSetTimes) +# define RTVfsSymlinkToPrivate RT_MANGLER(RTVfsSymlinkToPrivate) +# define RTVfsTypeName RT_MANGLER(RTVfsTypeName) +# define RTVfsUtilDummyPollOne RT_MANGLER(RTVfsUtilDummyPollOne) +# define RTVfsUtilPumpIoStreams RT_MANGLER(RTVfsUtilPumpIoStreams) +# define RTVfsCreateProgressForFile RT_MANGLER(RTVfsCreateProgressForFile) +# define RTVfsCreateProgressForIoStream RT_MANGLER(RTVfsCreateProgressForIoStream) +# define RTVfsCreateReadAheadForFile RT_MANGLER(RTVfsCreateReadAheadForFile) +# define RTVfsCreateReadAheadForIoStream RT_MANGLER(RTVfsCreateReadAheadForIoStream) +# define RTZipBlockCompress RT_MANGLER(RTZipBlockCompress) +# define RTZipBlockDecompress RT_MANGLER(RTZipBlockDecompress) +# define RTZipCompCreate RT_MANGLER(RTZipCompCreate) +# define RTZipCompDestroy RT_MANGLER(RTZipCompDestroy) +# define RTZipCompFinish RT_MANGLER(RTZipCompFinish) +# define RTZipCompress RT_MANGLER(RTZipCompress) +# define RTZipDecompCreate RT_MANGLER(RTZipDecompCreate) +# define RTZipDecompDestroy RT_MANGLER(RTZipDecompDestroy) +# define RTZipDecompress RT_MANGLER(RTZipDecompress) +# define RTZipGzipCompressIoStream RT_MANGLER(RTZipGzipCompressIoStream) +# define RTZipGzipDecompressIoStream RT_MANGLER(RTZipGzipDecompressIoStream) +# define RTZipGzipCmd RT_MANGLER(RTZipGzipCmd) +# define RTZipPkzipFsStreamFromIoStream RT_MANGLER(RTZipPkzipFsStreamFromIoStream) +# define RTZipPkzipMemDecompress RT_MANGLER(RTZipPkzipMemDecompress) +# define RTZipTarCmd RT_MANGLER(RTZipTarCmd) +# define RTZipUnzipCmd RT_MANGLER(RTZipUnzipCmd) +# define RTZipTarFsStreamFromIoStream RT_MANGLER(RTZipTarFsStreamFromIoStream) +# define RTZipTarFsStreamToIoStream RT_MANGLER(RTZipTarFsStreamToIoStream) +# define RTZipTarFsStreamSetOwner RT_MANGLER(RTZipTarFsStreamSetOwner) +# define RTZipTarFsStreamSetGroup RT_MANGLER(RTZipTarFsStreamSetGroup) +# define RTZipTarFsStreamSetPrefix RT_MANGLER(RTZipTarFsStreamSetPrefix) +# define RTZipTarFsStreamSetFileMode RT_MANGLER(RTZipTarFsStreamSetFileMode) +# define RTZipTarFsStreamSetDirMode RT_MANGLER(RTZipTarFsStreamSetDirMode) +# define RTZipTarFsStreamSetModTime RT_MANGLER(RTZipTarFsStreamSetModTime) +# define RTZipTarFsStreamTruncate RT_MANGLER(RTZipTarFsStreamTruncate) +# define RTZipXarFsStreamFromIoStream RT_MANGLER(RTZipXarFsStreamFromIoStream) +# define RTZipTarFsStreamForFile RT_MANGLER(RTZipTarFsStreamForFile) +# define RTZipCpioFsStreamFromIoStream RT_MANGLER(RTZipCpioFsStreamFromIoStream) + +/* sort/merge into the above later: */ +# define RTAsn1ContentAllocZ RT_MANGLER(RTAsn1ContentAllocZ) +# define RTAsn1ContentDup RT_MANGLER(RTAsn1ContentDup) +# define RTAsn1ContentFree RT_MANGLER(RTAsn1ContentFree) +# define RTAsn1ContentReallocZ RT_MANGLER(RTAsn1ContentReallocZ) +# define RTAsn1ContextTagN_Clone RT_MANGLER(RTAsn1ContextTagN_Clone) +# define RTAsn1ContextTagN_Init RT_MANGLER(RTAsn1ContextTagN_Init) +# define RTAsn1Dummy_InitEx RT_MANGLER(RTAsn1Dummy_InitEx) +# define RTAsn1MemAllocZ RT_MANGLER(RTAsn1MemAllocZ) +# define RTAsn1MemDup RT_MANGLER(RTAsn1MemDup) +# define RTAsn1MemFree RT_MANGLER(RTAsn1MemFree) +# define RTAsn1MemFreeArray RT_MANGLER(RTAsn1MemFreeArray) +# define RTAsn1MemResizeArray RT_MANGLER(RTAsn1MemResizeArray) +# define RTAsn1MemInitAllocation RT_MANGLER(RTAsn1MemInitAllocation) +# define RTAsn1MemInitArrayAllocation RT_MANGLER(RTAsn1MemInitArrayAllocation) +# define RTAsn1SeqOfCore_Clone RT_MANGLER(RTAsn1SeqOfCore_Clone) +# define RTAsn1SeqOfCore_Init RT_MANGLER(RTAsn1SeqOfCore_Init) +# define RTAsn1SequenceCore_Clone RT_MANGLER(RTAsn1SequenceCore_Clone) +# define RTAsn1SequenceCore_Init RT_MANGLER(RTAsn1SequenceCore_Init) +# define RTAsn1SetCore_Clone RT_MANGLER(RTAsn1SetCore_Clone) +# define RTAsn1SetCore_Init RT_MANGLER(RTAsn1SetCore_Init) +# define RTAsn1SetOfCore_Clone RT_MANGLER(RTAsn1SetOfCore_Clone) +# define RTAsn1SetOfCore_Init RT_MANGLER(RTAsn1SetOfCore_Init) +# define RTAsn1VtCheckSanity RT_MANGLER(RTAsn1VtCheckSanity) +# define RTAsn1VtClone RT_MANGLER(RTAsn1VtClone) +# define RTAsn1VtCompare RT_MANGLER(RTAsn1VtCompare) +# define RTAsn1VtDeepEnum RT_MANGLER(RTAsn1VtDeepEnum) +# define RTAsn1VtDelete RT_MANGLER(RTAsn1VtDelete) +# define RTAsn1CursorCheckEnd RT_MANGLER(RTAsn1CursorCheckEnd) +# define RTAsn1CursorCheckOctStrEnd RT_MANGLER(RTAsn1CursorCheckOctStrEnd) +# define RTAsn1CursorCheckSeqEnd RT_MANGLER(RTAsn1CursorCheckSeqEnd) +# define RTAsn1CursorCheckSetEnd RT_MANGLER(RTAsn1CursorCheckSetEnd) +# define RTAsn1CursorGetBitString RT_MANGLER(RTAsn1CursorGetBitString) +# define RTAsn1CursorGetBitStringEx RT_MANGLER(RTAsn1CursorGetBitStringEx) +# define RTAsn1CursorGetBmpString RT_MANGLER(RTAsn1CursorGetBmpString) +# define RTAsn1CursorGetBoolean RT_MANGLER(RTAsn1CursorGetBoolean) +# define RTAsn1CursorGetContextTagNCursor RT_MANGLER(RTAsn1CursorGetContextTagNCursor) +# define RTAsn1CursorGetCore RT_MANGLER(RTAsn1CursorGetCore) +# define RTAsn1CursorGetDynType RT_MANGLER(RTAsn1CursorGetDynType) +# define RTAsn1CursorGetIa5String RT_MANGLER(RTAsn1CursorGetIa5String) +# define RTAsn1CursorGetInteger RT_MANGLER(RTAsn1CursorGetInteger) +# define RTAsn1CursorGetNull RT_MANGLER(RTAsn1CursorGetNull) +# define RTAsn1CursorGetObjId RT_MANGLER(RTAsn1CursorGetObjId) +# define RTAsn1CursorGetOctetString RT_MANGLER(RTAsn1CursorGetOctetString) +# define RTAsn1CursorGetSequenceCursor RT_MANGLER(RTAsn1CursorGetSequenceCursor) +# define RTAsn1CursorGetSetCursor RT_MANGLER(RTAsn1CursorGetSetCursor) +# define RTAsn1CursorGetString RT_MANGLER(RTAsn1CursorGetString) +# define RTAsn1CursorGetTime RT_MANGLER(RTAsn1CursorGetTime) +# define RTAsn1CursorGetUtf8String RT_MANGLER(RTAsn1CursorGetUtf8String) +# define RTAsn1CursorInitAllocation RT_MANGLER(RTAsn1CursorInitAllocation) +# define RTAsn1CursorInitArrayAllocation RT_MANGLER(RTAsn1CursorInitArrayAllocation) +# define RTAsn1CursorInitPrimary RT_MANGLER(RTAsn1CursorInitPrimary) +# define RTAsn1CursorInitSub RT_MANGLER(RTAsn1CursorInitSub) +# define RTAsn1CursorInitSubFromCore RT_MANGLER(RTAsn1CursorInitSubFromCore) +# define RTAsn1CursorIsNextEx RT_MANGLER(RTAsn1CursorIsNextEx) +# define RTAsn1CursorIsEnd RT_MANGLER(RTAsn1CursorIsEnd) +# define RTAsn1CursorMatchTagClassFlagsEx RT_MANGLER(RTAsn1CursorMatchTagClassFlagsEx) +# define RTAsn1CursorPeek RT_MANGLER(RTAsn1CursorPeek) +# define RTAsn1CursorReadHdr RT_MANGLER(RTAsn1CursorReadHdr) +# define RTAsn1CursorSetInfo RT_MANGLER(RTAsn1CursorSetInfo) +# define RTAsn1CursorSetInfoV RT_MANGLER(RTAsn1CursorSetInfoV) +# define RTAsn1Dump RT_MANGLER(RTAsn1Dump) +# define RTAsn1QueryObjIdName RT_MANGLER(RTAsn1QueryObjIdName) +# define RTAsn1EncodePrepare RT_MANGLER(RTAsn1EncodePrepare) +# define RTAsn1EncodeRecalcHdrSize RT_MANGLER(RTAsn1EncodeRecalcHdrSize) +# define RTAsn1EncodeToBuffer RT_MANGLER(RTAsn1EncodeToBuffer) +# define RTAsn1EncodeQueryRawBits RT_MANGLER(RTAsn1EncodeQueryRawBits) +# define RTAsn1EncodeWrite RT_MANGLER(RTAsn1EncodeWrite) +# define RTAsn1EncodeWriteHeader RT_MANGLER(RTAsn1EncodeWriteHeader) +# define RTAsn1BitString_CheckSanity RT_MANGLER(RTAsn1BitString_CheckSanity) +# define RTAsn1BitString_Clone RT_MANGLER(RTAsn1BitString_Clone) +# define RTAsn1BitString_Compare RT_MANGLER(RTAsn1BitString_Compare) +# define RTAsn1BitString_Delete RT_MANGLER(RTAsn1BitString_Delete) +# define RTAsn1BitString_Enum RT_MANGLER(RTAsn1BitString_Enum) +# define RTAsn1BitString_GetAsUInt64 RT_MANGLER(RTAsn1BitString_GetAsUInt64) +# define RTAsn1BitString_Init RT_MANGLER(RTAsn1BitString_Init) +# define RTAsn1BitString_InitWithData RT_MANGLER(RTAsn1BitString_InitWithData) +# define RTAsn1BitString_AreContentBitsValid RT_MANGLER(RTAsn1BitString_AreContentBitsValid) +# define RTAsn1BitString_RefreshContent RT_MANGLER(RTAsn1BitString_RefreshContent) +# define RTAsn1SeqOfBitStrings_CheckSanity RT_MANGLER(RTAsn1SeqOfBitStrings_CheckSanity) +# define RTAsn1SeqOfBitStrings_Clone RT_MANGLER(RTAsn1SeqOfBitStrings_Clone) +# define RTAsn1SeqOfBitStrings_Compare RT_MANGLER(RTAsn1SeqOfBitStrings_Compare) +# define RTAsn1SeqOfBitStrings_Delete RT_MANGLER(RTAsn1SeqOfBitStrings_Delete) +# define RTAsn1SeqOfBitStrings_Enum RT_MANGLER(RTAsn1SeqOfBitStrings_Enum) +# define RTAsn1SeqOfBitStrings_Init RT_MANGLER(RTAsn1SeqOfBitStrings_Init) +# define RTAsn1SetOfBitStrings_CheckSanity RT_MANGLER(RTAsn1SetOfBitStrings_CheckSanity) +# define RTAsn1SetOfBitStrings_Clone RT_MANGLER(RTAsn1SetOfBitStrings_Clone) +# define RTAsn1SetOfBitStrings_Compare RT_MANGLER(RTAsn1SetOfBitStrings_Compare) +# define RTAsn1SetOfBitStrings_Delete RT_MANGLER(RTAsn1SetOfBitStrings_Delete) +# define RTAsn1SetOfBitStrings_Enum RT_MANGLER(RTAsn1SetOfBitStrings_Enum) +# define RTAsn1SetOfBitStrings_Init RT_MANGLER(RTAsn1SetOfBitStrings_Init) +# define RTAsn1BitString_DecodeAsn1 RT_MANGLER(RTAsn1BitString_DecodeAsn1) +# define RTAsn1BitString_DecodeAsn1Ex RT_MANGLER(RTAsn1BitString_DecodeAsn1Ex) +# define RTAsn1SeqOfBitStrings_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfBitStrings_DecodeAsn1) +# define RTAsn1SetOfBitStrings_DecodeAsn1 RT_MANGLER(RTAsn1SetOfBitStrings_DecodeAsn1) +# define RTAsn1Boolean_CheckSanity RT_MANGLER(RTAsn1Boolean_CheckSanity) +# define RTAsn1Boolean_Clone RT_MANGLER(RTAsn1Boolean_Clone) +# define RTAsn1Boolean_Compare RT_MANGLER(RTAsn1Boolean_Compare) +# define RTAsn1Boolean_Delete RT_MANGLER(RTAsn1Boolean_Delete) +# define RTAsn1Boolean_Enum RT_MANGLER(RTAsn1Boolean_Enum) +# define RTAsn1Boolean_Init RT_MANGLER(RTAsn1Boolean_Init) +# define RTAsn1Boolean_InitDefault RT_MANGLER(RTAsn1Boolean_InitDefault) +# define RTAsn1Boolean_Set RT_MANGLER(RTAsn1Boolean_Set) +# define RTAsn1SeqOfBooleans_CheckSanity RT_MANGLER(RTAsn1SeqOfBooleans_CheckSanity) +# define RTAsn1SeqOfBooleans_Clone RT_MANGLER(RTAsn1SeqOfBooleans_Clone) +# define RTAsn1SeqOfBooleans_Compare RT_MANGLER(RTAsn1SeqOfBooleans_Compare) +# define RTAsn1SeqOfBooleans_Delete RT_MANGLER(RTAsn1SeqOfBooleans_Delete) +# define RTAsn1SeqOfBooleans_Enum RT_MANGLER(RTAsn1SeqOfBooleans_Enum) +# define RTAsn1SeqOfBooleans_Init RT_MANGLER(RTAsn1SeqOfBooleans_Init) +# define RTAsn1SetOfBooleans_CheckSanity RT_MANGLER(RTAsn1SetOfBooleans_CheckSanity) +# define RTAsn1SetOfBooleans_Clone RT_MANGLER(RTAsn1SetOfBooleans_Clone) +# define RTAsn1SetOfBooleans_Compare RT_MANGLER(RTAsn1SetOfBooleans_Compare) +# define RTAsn1SetOfBooleans_Delete RT_MANGLER(RTAsn1SetOfBooleans_Delete) +# define RTAsn1SetOfBooleans_Enum RT_MANGLER(RTAsn1SetOfBooleans_Enum) +# define RTAsn1SetOfBooleans_Init RT_MANGLER(RTAsn1SetOfBooleans_Init) +# define RTAsn1Boolean_DecodeAsn1 RT_MANGLER(RTAsn1Boolean_DecodeAsn1) +# define RTAsn1SeqOfBooleans_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfBooleans_DecodeAsn1) +# define RTAsn1SetOfBooleans_DecodeAsn1 RT_MANGLER(RTAsn1SetOfBooleans_DecodeAsn1) +# define RTAsn1Core_ChangeTag RT_MANGLER(RTAsn1Core_ChangeTag) +# define RTAsn1Core_CheckSanity RT_MANGLER(RTAsn1Core_CheckSanity) +# define RTAsn1Core_Clone RT_MANGLER(RTAsn1Core_Clone) +# define RTAsn1Core_CloneContent RT_MANGLER(RTAsn1Core_CloneContent) +# define RTAsn1Core_CloneNoContent RT_MANGLER(RTAsn1Core_CloneNoContent) +# define RTAsn1Core_Compare RT_MANGLER(RTAsn1Core_Compare) +# define RTAsn1Core_CompareEx RT_MANGLER(RTAsn1Core_CompareEx) +# define RTAsn1Core_Delete RT_MANGLER(RTAsn1Core_Delete) +# define RTAsn1Core_Enum RT_MANGLER(RTAsn1Core_Enum) +# define RTAsn1Core_Init RT_MANGLER(RTAsn1Core_Init) +# define RTAsn1Core_InitDefault RT_MANGLER(RTAsn1Core_InitDefault) +# define RTAsn1Core_InitEx RT_MANGLER(RTAsn1Core_InitEx) +# define RTAsn1Core_ResetImplict RT_MANGLER(RTAsn1Core_ResetImplict) +# define RTAsn1Core_SetTagAndFlags RT_MANGLER(RTAsn1Core_SetTagAndFlags) +# define RTAsn1SeqOfCores_CheckSanity RT_MANGLER(RTAsn1SeqOfCores_CheckSanity) +# define RTAsn1SeqOfCores_Clone RT_MANGLER(RTAsn1SeqOfCores_Clone) +# define RTAsn1SeqOfCores_Compare RT_MANGLER(RTAsn1SeqOfCores_Compare) +# define RTAsn1SeqOfCores_Delete RT_MANGLER(RTAsn1SeqOfCores_Delete) +# define RTAsn1SeqOfCores_Enum RT_MANGLER(RTAsn1SeqOfCores_Enum) +# define RTAsn1SeqOfCores_Init RT_MANGLER(RTAsn1SeqOfCores_Init) +# define RTAsn1SetOfCores_CheckSanity RT_MANGLER(RTAsn1SetOfCores_CheckSanity) +# define RTAsn1SetOfCores_Clone RT_MANGLER(RTAsn1SetOfCores_Clone) +# define RTAsn1SetOfCores_Compare RT_MANGLER(RTAsn1SetOfCores_Compare) +# define RTAsn1SetOfCores_Delete RT_MANGLER(RTAsn1SetOfCores_Delete) +# define RTAsn1SetOfCores_Enum RT_MANGLER(RTAsn1SetOfCores_Enum) +# define RTAsn1SetOfCores_Init RT_MANGLER(RTAsn1SetOfCores_Init) +# define RTAsn1Core_DecodeAsn1 RT_MANGLER(RTAsn1Core_DecodeAsn1) +# define RTAsn1SeqOfCores_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfCores_DecodeAsn1) +# define RTAsn1SetOfCores_DecodeAsn1 RT_MANGLER(RTAsn1SetOfCores_DecodeAsn1) +# define RTAsn1DynType_SetToNull RT_MANGLER(RTAsn1DynType_SetToNull) +# define RTAsn1DynType_CheckSanity RT_MANGLER(RTAsn1DynType_CheckSanity) +# define RTAsn1DynType_Clone RT_MANGLER(RTAsn1DynType_Clone) +# define RTAsn1DynType_Compare RT_MANGLER(RTAsn1DynType_Compare) +# define RTAsn1DynType_Delete RT_MANGLER(RTAsn1DynType_Delete) +# define RTAsn1DynType_Enum RT_MANGLER(RTAsn1DynType_Enum) +# define RTAsn1DynType_Init RT_MANGLER(RTAsn1DynType_Init) +# define RTAsn1DynType_DecodeAsn1 RT_MANGLER(RTAsn1DynType_DecodeAsn1) +# define RTAsn1Integer_CheckSanity RT_MANGLER(RTAsn1Integer_CheckSanity) +# define RTAsn1Integer_Clone RT_MANGLER(RTAsn1Integer_Clone) +# define RTAsn1Integer_Compare RT_MANGLER(RTAsn1Integer_Compare) +# define RTAsn1Integer_Delete RT_MANGLER(RTAsn1Integer_Delete) +# define RTAsn1Integer_Enum RT_MANGLER(RTAsn1Integer_Enum) +# define RTAsn1Integer_FromBigNum RT_MANGLER(RTAsn1Integer_FromBigNum) +# define RTAsn1Integer_Init RT_MANGLER(RTAsn1Integer_Init) +# define RTAsn1Integer_InitDefault RT_MANGLER(RTAsn1Integer_InitDefault) +# define RTAsn1Integer_InitU64 RT_MANGLER(RTAsn1Integer_InitU64) +# define RTAsn1Integer_ToBigNum RT_MANGLER(RTAsn1Integer_ToBigNum) +# define RTAsn1Integer_ToString RT_MANGLER(RTAsn1Integer_ToString) +# define RTAsn1Integer_UnsignedCompare RT_MANGLER(RTAsn1Integer_UnsignedCompare) +# define RTAsn1Integer_UnsignedCompareWithU32 RT_MANGLER(RTAsn1Integer_UnsignedCompareWithU32) +# define RTAsn1Integer_UnsignedCompareWithU64 RT_MANGLER(RTAsn1Integer_UnsignedCompareWithU64) +# define RTAsn1Integer_UnsignedLastBit RT_MANGLER(RTAsn1Integer_UnsignedLastBit) +# define RTAsn1SeqOfIntegers_CheckSanity RT_MANGLER(RTAsn1SeqOfIntegers_CheckSanity) +# define RTAsn1SeqOfIntegers_Clone RT_MANGLER(RTAsn1SeqOfIntegers_Clone) +# define RTAsn1SeqOfIntegers_Compare RT_MANGLER(RTAsn1SeqOfIntegers_Compare) +# define RTAsn1SeqOfIntegers_Delete RT_MANGLER(RTAsn1SeqOfIntegers_Delete) +# define RTAsn1SeqOfIntegers_Enum RT_MANGLER(RTAsn1SeqOfIntegers_Enum) +# define RTAsn1SeqOfIntegers_Init RT_MANGLER(RTAsn1SeqOfIntegers_Init) +# define RTAsn1SetOfIntegers_CheckSanity RT_MANGLER(RTAsn1SetOfIntegers_CheckSanity) +# define RTAsn1SetOfIntegers_Clone RT_MANGLER(RTAsn1SetOfIntegers_Clone) +# define RTAsn1SetOfIntegers_Compare RT_MANGLER(RTAsn1SetOfIntegers_Compare) +# define RTAsn1SetOfIntegers_Delete RT_MANGLER(RTAsn1SetOfIntegers_Delete) +# define RTAsn1SetOfIntegers_Enum RT_MANGLER(RTAsn1SetOfIntegers_Enum) +# define RTAsn1SetOfIntegers_Init RT_MANGLER(RTAsn1SetOfIntegers_Init) +# define RTAsn1Integer_DecodeAsn1 RT_MANGLER(RTAsn1Integer_DecodeAsn1) +# define RTAsn1SeqOfIntegers_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfIntegers_DecodeAsn1) +# define RTAsn1SetOfIntegers_DecodeAsn1 RT_MANGLER(RTAsn1SetOfIntegers_DecodeAsn1) +# define RTAsn1Null_CheckSanity RT_MANGLER(RTAsn1Null_CheckSanity) +# define RTAsn1Null_Clone RT_MANGLER(RTAsn1Null_Clone) +# define RTAsn1Null_Compare RT_MANGLER(RTAsn1Null_Compare) +# define RTAsn1Null_Delete RT_MANGLER(RTAsn1Null_Delete) +# define RTAsn1Null_Enum RT_MANGLER(RTAsn1Null_Enum) +# define RTAsn1Null_Init RT_MANGLER(RTAsn1Null_Init) +# define RTAsn1Null_DecodeAsn1 RT_MANGLER(RTAsn1Null_DecodeAsn1) +# define RTAsn1ObjIdCountComponents RT_MANGLER(RTAsn1ObjIdCountComponents) +# define RTAsn1ObjIdGetComponentsAsUInt32 RT_MANGLER(RTAsn1ObjIdGetComponentsAsUInt32) +# define RTAsn1ObjIdGetLastComponentsAsUInt32 RT_MANGLER(RTAsn1ObjIdGetLastComponentsAsUInt32) +# define RTAsn1ObjId_CheckSanity RT_MANGLER(RTAsn1ObjId_CheckSanity) +# define RTAsn1ObjId_Clone RT_MANGLER(RTAsn1ObjId_Clone) +# define RTAsn1ObjId_Compare RT_MANGLER(RTAsn1ObjId_Compare) +# define RTAsn1ObjId_CompareWithString RT_MANGLER(RTAsn1ObjId_CompareWithString) +# define RTAsn1ObjId_Delete RT_MANGLER(RTAsn1ObjId_Delete) +# define RTAsn1ObjId_Enum RT_MANGLER(RTAsn1ObjId_Enum) +# define RTAsn1ObjId_Init RT_MANGLER(RTAsn1ObjId_Init) +# define RTAsn1ObjId_InitFromString RT_MANGLER(RTAsn1ObjId_InitFromString) +# define RTAsn1ObjId_SetFromString RT_MANGLER(RTAsn1ObjId_SetFromString) +# define RTAsn1ObjId_StartsWith RT_MANGLER(RTAsn1ObjId_StartsWith) +# define RTAsn1SeqOfObjIds_CheckSanity RT_MANGLER(RTAsn1SeqOfObjIds_CheckSanity) +# define RTAsn1SeqOfObjIds_Clone RT_MANGLER(RTAsn1SeqOfObjIds_Clone) +# define RTAsn1SeqOfObjIds_Compare RT_MANGLER(RTAsn1SeqOfObjIds_Compare) +# define RTAsn1SeqOfObjIds_Delete RT_MANGLER(RTAsn1SeqOfObjIds_Delete) +# define RTAsn1SeqOfObjIds_Enum RT_MANGLER(RTAsn1SeqOfObjIds_Enum) +# define RTAsn1SeqOfObjIds_Init RT_MANGLER(RTAsn1SeqOfObjIds_Init) +# define RTAsn1SetOfObjIds_CheckSanity RT_MANGLER(RTAsn1SetOfObjIds_CheckSanity) +# define RTAsn1SetOfObjIds_Clone RT_MANGLER(RTAsn1SetOfObjIds_Clone) +# define RTAsn1SetOfObjIds_Compare RT_MANGLER(RTAsn1SetOfObjIds_Compare) +# define RTAsn1SetOfObjIds_Delete RT_MANGLER(RTAsn1SetOfObjIds_Delete) +# define RTAsn1SetOfObjIds_Enum RT_MANGLER(RTAsn1SetOfObjIds_Enum) +# define RTAsn1SetOfObjIds_Init RT_MANGLER(RTAsn1SetOfObjIds_Init) +# define RTAsn1SeqOfObjIdSeqs_CheckSanity RT_MANGLER(RTAsn1SeqOfObjIdSeqs_CheckSanity) +# define RTAsn1SeqOfObjIdSeqs_Clone RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Clone) +# define RTAsn1SeqOfObjIdSeqs_Compare RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Compare) +# define RTAsn1SetOfObjIdSeqs_DecodeAsn1 RT_MANGLER(RTAsn1SetOfObjIdSeqs_DecodeAsn1) +# define RTAsn1SeqOfObjIdSeqs_Delete RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Delete) +# define RTAsn1SeqOfObjIdSeqs_Enum RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Enum) +# define RTAsn1SeqOfObjIdSeqs_Init RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Init) +# define RTAsn1SetOfObjIdSeqs_CheckSanity RT_MANGLER(RTAsn1SetOfObjIdSeqs_CheckSanity) +# define RTAsn1SetOfObjIdSeqs_Clone RT_MANGLER(RTAsn1SetOfObjIdSeqs_Clone) +# define RTAsn1SetOfObjIdSeqs_Compare RT_MANGLER(RTAsn1SetOfObjIdSeqs_Compare) +# define RTAsn1SetOfObjIdSeqs_Delete RT_MANGLER(RTAsn1SetOfObjIdSeqs_Delete) +# define RTAsn1SetOfObjIdSeqs_Enum RT_MANGLER(RTAsn1SetOfObjIdSeqs_Enum) +# define RTAsn1SetOfObjIdSeqs_Init RT_MANGLER(RTAsn1SetOfObjIdSeqs_Init) +# define RTAsn1ObjId_DecodeAsn1 RT_MANGLER(RTAsn1ObjId_DecodeAsn1) +# define RTAsn1SeqOfObjIds_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfObjIds_DecodeAsn1) +# define RTAsn1SetOfObjIds_DecodeAsn1 RT_MANGLER(RTAsn1SetOfObjIds_DecodeAsn1) +# define RTAsn1OctetString_AllocContent RT_MANGLER(RTAsn1OctetString_AllocContent) +# define RTAsn1OctetString_SetContent RT_MANGLER(RTAsn1OctetString_SetContent) +# define RTAsn1OctetString_CheckSanity RT_MANGLER(RTAsn1OctetString_CheckSanity) +# define RTAsn1OctetString_Clone RT_MANGLER(RTAsn1OctetString_Clone) +# define RTAsn1OctetString_Compare RT_MANGLER(RTAsn1OctetString_Compare) +# define RTAsn1OctetString_Delete RT_MANGLER(RTAsn1OctetString_Delete) +# define RTAsn1OctetString_Enum RT_MANGLER(RTAsn1OctetString_Enum) +# define RTAsn1OctetString_Init RT_MANGLER(RTAsn1OctetString_Init) +# define RTAsn1OctetString_AreContentBytesValid RT_MANGLER(RTAsn1OctetString_AreContentBytesValid) +# define RTAsn1OctetString_RefreshContent RT_MANGLER(RTAsn1OctetString_RefreshContent) +# define RTAsn1SeqOfOctetStrings_CheckSanity RT_MANGLER(RTAsn1SeqOfOctetStrings_CheckSanity) +# define RTAsn1SeqOfOctetStrings_Clone RT_MANGLER(RTAsn1SeqOfOctetStrings_Clone) +# define RTAsn1SeqOfOctetStrings_Compare RT_MANGLER(RTAsn1SeqOfOctetStrings_Compare) +# define RTAsn1SeqOfOctetStrings_Delete RT_MANGLER(RTAsn1SeqOfOctetStrings_Delete) +# define RTAsn1SeqOfOctetStrings_Enum RT_MANGLER(RTAsn1SeqOfOctetStrings_Enum) +# define RTAsn1SeqOfOctetStrings_Init RT_MANGLER(RTAsn1SeqOfOctetStrings_Init) +# define RTAsn1SetOfOctetStrings_CheckSanity RT_MANGLER(RTAsn1SetOfOctetStrings_CheckSanity) +# define RTAsn1SetOfOctetStrings_Clone RT_MANGLER(RTAsn1SetOfOctetStrings_Clone) +# define RTAsn1SetOfOctetStrings_Compare RT_MANGLER(RTAsn1SetOfOctetStrings_Compare) +# define RTAsn1SetOfOctetStrings_Delete RT_MANGLER(RTAsn1SetOfOctetStrings_Delete) +# define RTAsn1SetOfOctetStrings_Enum RT_MANGLER(RTAsn1SetOfOctetStrings_Enum) +# define RTAsn1SetOfOctetStrings_Init RT_MANGLER(RTAsn1SetOfOctetStrings_Init) +# define RTAsn1OctetString_DecodeAsn1 RT_MANGLER(RTAsn1OctetString_DecodeAsn1) +# define RTAsn1SeqOfOctetStrings_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfOctetStrings_DecodeAsn1) +# define RTAsn1SetOfOctetStrings_DecodeAsn1 RT_MANGLER(RTAsn1SetOfOctetStrings_DecodeAsn1) +# define RTAsn1BmpString_CheckSanity RT_MANGLER(RTAsn1BmpString_CheckSanity) +# define RTAsn1BmpString_Clone RT_MANGLER(RTAsn1BmpString_Clone) +# define RTAsn1BmpString_Compare RT_MANGLER(RTAsn1BmpString_Compare) +# define RTAsn1BmpString_Delete RT_MANGLER(RTAsn1BmpString_Delete) +# define RTAsn1BmpString_Enum RT_MANGLER(RTAsn1BmpString_Enum) +# define RTAsn1BmpString_Init RT_MANGLER(RTAsn1BmpString_Init) +# define RTAsn1GeneralString_CheckSanity RT_MANGLER(RTAsn1GeneralString_CheckSanity) +# define RTAsn1GeneralString_Clone RT_MANGLER(RTAsn1GeneralString_Clone) +# define RTAsn1GeneralString_Compare RT_MANGLER(RTAsn1GeneralString_Compare) +# define RTAsn1GeneralString_Delete RT_MANGLER(RTAsn1GeneralString_Delete) +# define RTAsn1GeneralString_Enum RT_MANGLER(RTAsn1GeneralString_Enum) +# define RTAsn1GeneralString_Init RT_MANGLER(RTAsn1GeneralString_Init) +# define RTAsn1GraphicString_CheckSanity RT_MANGLER(RTAsn1GraphicString_CheckSanity) +# define RTAsn1GraphicString_Clone RT_MANGLER(RTAsn1GraphicString_Clone) +# define RTAsn1GraphicString_Compare RT_MANGLER(RTAsn1GraphicString_Compare) +# define RTAsn1GraphicString_Delete RT_MANGLER(RTAsn1GraphicString_Delete) +# define RTAsn1GraphicString_Enum RT_MANGLER(RTAsn1GraphicString_Enum) +# define RTAsn1GraphicString_Init RT_MANGLER(RTAsn1GraphicString_Init) +# define RTAsn1Ia5String_CheckSanity RT_MANGLER(RTAsn1Ia5String_CheckSanity) +# define RTAsn1Ia5String_Clone RT_MANGLER(RTAsn1Ia5String_Clone) +# define RTAsn1Ia5String_Compare RT_MANGLER(RTAsn1Ia5String_Compare) +# define RTAsn1Ia5String_Delete RT_MANGLER(RTAsn1Ia5String_Delete) +# define RTAsn1Ia5String_Enum RT_MANGLER(RTAsn1Ia5String_Enum) +# define RTAsn1Ia5String_Init RT_MANGLER(RTAsn1Ia5String_Init) +# define RTAsn1NumericString_CheckSanity RT_MANGLER(RTAsn1NumericString_CheckSanity) +# define RTAsn1NumericString_Clone RT_MANGLER(RTAsn1NumericString_Clone) +# define RTAsn1NumericString_Compare RT_MANGLER(RTAsn1NumericString_Compare) +# define RTAsn1NumericString_Delete RT_MANGLER(RTAsn1NumericString_Delete) +# define RTAsn1NumericString_Enum RT_MANGLER(RTAsn1NumericString_Enum) +# define RTAsn1NumericString_Init RT_MANGLER(RTAsn1NumericString_Init) +# define RTAsn1PrintableString_CheckSanity RT_MANGLER(RTAsn1PrintableString_CheckSanity) +# define RTAsn1PrintableString_Clone RT_MANGLER(RTAsn1PrintableString_Clone) +# define RTAsn1PrintableString_Compare RT_MANGLER(RTAsn1PrintableString_Compare) +# define RTAsn1PrintableString_Delete RT_MANGLER(RTAsn1PrintableString_Delete) +# define RTAsn1PrintableString_Enum RT_MANGLER(RTAsn1PrintableString_Enum) +# define RTAsn1PrintableString_Init RT_MANGLER(RTAsn1PrintableString_Init) +# define RTAsn1SeqOfStrings_CheckSanity RT_MANGLER(RTAsn1SeqOfStrings_CheckSanity) +# define RTAsn1SeqOfStrings_Clone RT_MANGLER(RTAsn1SeqOfStrings_Clone) +# define RTAsn1SeqOfStrings_Compare RT_MANGLER(RTAsn1SeqOfStrings_Compare) +# define RTAsn1SeqOfStrings_Delete RT_MANGLER(RTAsn1SeqOfStrings_Delete) +# define RTAsn1SeqOfStrings_Enum RT_MANGLER(RTAsn1SeqOfStrings_Enum) +# define RTAsn1SeqOfStrings_Init RT_MANGLER(RTAsn1SeqOfStrings_Init) +# define RTAsn1SetOfStrings_CheckSanity RT_MANGLER(RTAsn1SetOfStrings_CheckSanity) +# define RTAsn1SetOfStrings_Clone RT_MANGLER(RTAsn1SetOfStrings_Clone) +# define RTAsn1SetOfStrings_Compare RT_MANGLER(RTAsn1SetOfStrings_Compare) +# define RTAsn1SetOfStrings_Delete RT_MANGLER(RTAsn1SetOfStrings_Delete) +# define RTAsn1SetOfStrings_Enum RT_MANGLER(RTAsn1SetOfStrings_Enum) +# define RTAsn1SetOfStrings_Init RT_MANGLER(RTAsn1SetOfStrings_Init) +# define RTAsn1String_CheckSanity RT_MANGLER(RTAsn1String_CheckSanity) +# define RTAsn1String_Clone RT_MANGLER(RTAsn1String_Clone) +# define RTAsn1String_Compare RT_MANGLER(RTAsn1String_Compare) +# define RTAsn1String_CompareEx RT_MANGLER(RTAsn1String_CompareEx) +# define RTAsn1String_CompareValues RT_MANGLER(RTAsn1String_CompareValues) +# define RTAsn1String_CompareWithString RT_MANGLER(RTAsn1String_CompareWithString) +# define RTAsn1String_Delete RT_MANGLER(RTAsn1String_Delete) +# define RTAsn1String_Enum RT_MANGLER(RTAsn1String_Enum) +# define RTAsn1String_Init RT_MANGLER(RTAsn1String_Init) +# define RTAsn1String_InitEx RT_MANGLER(RTAsn1String_InitEx) +# define RTAsn1String_InitWithValue RT_MANGLER(RTAsn1String_InitWithValue) +# define RTAsn1String_QueryUtf8 RT_MANGLER(RTAsn1String_QueryUtf8) +# define RTAsn1String_QueryUtf8Len RT_MANGLER(RTAsn1String_QueryUtf8Len) +# define RTAsn1String_RecodeAsUtf8 RT_MANGLER(RTAsn1String_RecodeAsUtf8) +# define RTAsn1T61String_CheckSanity RT_MANGLER(RTAsn1T61String_CheckSanity) +# define RTAsn1T61String_Clone RT_MANGLER(RTAsn1T61String_Clone) +# define RTAsn1T61String_Compare RT_MANGLER(RTAsn1T61String_Compare) +# define RTAsn1T61String_Delete RT_MANGLER(RTAsn1T61String_Delete) +# define RTAsn1T61String_Enum RT_MANGLER(RTAsn1T61String_Enum) +# define RTAsn1T61String_Init RT_MANGLER(RTAsn1T61String_Init) +# define RTAsn1UniversalString_CheckSanity RT_MANGLER(RTAsn1UniversalString_CheckSanity) +# define RTAsn1UniversalString_Clone RT_MANGLER(RTAsn1UniversalString_Clone) +# define RTAsn1UniversalString_Compare RT_MANGLER(RTAsn1UniversalString_Compare) +# define RTAsn1UniversalString_Delete RT_MANGLER(RTAsn1UniversalString_Delete) +# define RTAsn1UniversalString_Enum RT_MANGLER(RTAsn1UniversalString_Enum) +# define RTAsn1UniversalString_Init RT_MANGLER(RTAsn1UniversalString_Init) +# define RTAsn1Utf8String_CheckSanity RT_MANGLER(RTAsn1Utf8String_CheckSanity) +# define RTAsn1Utf8String_Clone RT_MANGLER(RTAsn1Utf8String_Clone) +# define RTAsn1Utf8String_Compare RT_MANGLER(RTAsn1Utf8String_Compare) +# define RTAsn1Utf8String_Delete RT_MANGLER(RTAsn1Utf8String_Delete) +# define RTAsn1Utf8String_Enum RT_MANGLER(RTAsn1Utf8String_Enum) +# define RTAsn1Utf8String_Init RT_MANGLER(RTAsn1Utf8String_Init) +# define RTAsn1VisibleString_CheckSanity RT_MANGLER(RTAsn1VisibleString_CheckSanity) +# define RTAsn1VisibleString_Clone RT_MANGLER(RTAsn1VisibleString_Clone) +# define RTAsn1VisibleString_Compare RT_MANGLER(RTAsn1VisibleString_Compare) +# define RTAsn1VisibleString_Delete RT_MANGLER(RTAsn1VisibleString_Delete) +# define RTAsn1VisibleString_Enum RT_MANGLER(RTAsn1VisibleString_Enum) +# define RTAsn1VisibleString_Init RT_MANGLER(RTAsn1VisibleString_Init) +# define RTAsn1BmpString_DecodeAsn1 RT_MANGLER(RTAsn1BmpString_DecodeAsn1) +# define RTAsn1GeneralString_DecodeAsn1 RT_MANGLER(RTAsn1GeneralString_DecodeAsn1) +# define RTAsn1GraphicString_DecodeAsn1 RT_MANGLER(RTAsn1GraphicString_DecodeAsn1) +# define RTAsn1Ia5String_DecodeAsn1 RT_MANGLER(RTAsn1Ia5String_DecodeAsn1) +# define RTAsn1NumericString_DecodeAsn1 RT_MANGLER(RTAsn1NumericString_DecodeAsn1) +# define RTAsn1PrintableString_DecodeAsn1 RT_MANGLER(RTAsn1PrintableString_DecodeAsn1) +# define RTAsn1SeqOfStrings_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfStrings_DecodeAsn1) +# define RTAsn1SetOfStrings_DecodeAsn1 RT_MANGLER(RTAsn1SetOfStrings_DecodeAsn1) +# define RTAsn1String_DecodeAsn1 RT_MANGLER(RTAsn1String_DecodeAsn1) +# define RTAsn1T61String_DecodeAsn1 RT_MANGLER(RTAsn1T61String_DecodeAsn1) +# define RTAsn1UniversalString_DecodeAsn1 RT_MANGLER(RTAsn1UniversalString_DecodeAsn1) +# define RTAsn1Utf8String_DecodeAsn1 RT_MANGLER(RTAsn1Utf8String_DecodeAsn1) +# define RTAsn1VisibleString_DecodeAsn1 RT_MANGLER(RTAsn1VisibleString_DecodeAsn1) +# define RTAsn1GeneralizedTime_CheckSanity RT_MANGLER(RTAsn1GeneralizedTime_CheckSanity) +# define RTAsn1GeneralizedTime_Clone RT_MANGLER(RTAsn1GeneralizedTime_Clone) +# define RTAsn1GeneralizedTime_Compare RT_MANGLER(RTAsn1GeneralizedTime_Compare) +# define RTAsn1GeneralizedTime_Delete RT_MANGLER(RTAsn1GeneralizedTime_Delete) +# define RTAsn1GeneralizedTime_Enum RT_MANGLER(RTAsn1GeneralizedTime_Enum) +# define RTAsn1GeneralizedTime_Init RT_MANGLER(RTAsn1GeneralizedTime_Init) +# define RTAsn1SeqOfTimes_CheckSanity RT_MANGLER(RTAsn1SeqOfTimes_CheckSanity) +# define RTAsn1SeqOfTimes_Clone RT_MANGLER(RTAsn1SeqOfTimes_Clone) +# define RTAsn1SeqOfTimes_Compare RT_MANGLER(RTAsn1SeqOfTimes_Compare) +# define RTAsn1SeqOfTimes_Delete RT_MANGLER(RTAsn1SeqOfTimes_Delete) +# define RTAsn1SeqOfTimes_Enum RT_MANGLER(RTAsn1SeqOfTimes_Enum) +# define RTAsn1SeqOfTimes_Init RT_MANGLER(RTAsn1SeqOfTimes_Init) +# define RTAsn1SetOfTimes_CheckSanity RT_MANGLER(RTAsn1SetOfTimes_CheckSanity) +# define RTAsn1SetOfTimes_Clone RT_MANGLER(RTAsn1SetOfTimes_Clone) +# define RTAsn1SetOfTimes_Compare RT_MANGLER(RTAsn1SetOfTimes_Compare) +# define RTAsn1SetOfTimes_Delete RT_MANGLER(RTAsn1SetOfTimes_Delete) +# define RTAsn1SetOfTimes_Enum RT_MANGLER(RTAsn1SetOfTimes_Enum) +# define RTAsn1SetOfTimes_Init RT_MANGLER(RTAsn1SetOfTimes_Init) +# define RTAsn1Time_CheckSanity RT_MANGLER(RTAsn1Time_CheckSanity) +# define RTAsn1Time_Clone RT_MANGLER(RTAsn1Time_Clone) +# define RTAsn1Time_Compare RT_MANGLER(RTAsn1Time_Compare) +# define RTAsn1Time_CompareWithTimeSpec RT_MANGLER(RTAsn1Time_CompareWithTimeSpec) +# define RTAsn1Time_Delete RT_MANGLER(RTAsn1Time_Delete) +# define RTAsn1Time_Enum RT_MANGLER(RTAsn1Time_Enum) +# define RTAsn1Time_Init RT_MANGLER(RTAsn1Time_Init) +# define RTAsn1Time_InitEx RT_MANGLER(RTAsn1Time_InitEx) +# define RTAsn1Time_InitWithTime RT_MANGLER(RTAsn1Time_InitWithTime) +# define RTAsn1Time_SetTime RT_MANGLER(RTAsn1Time_SetTime) +# define RTAsn1Time_SetTimeSpec RT_MANGLER(RTAsn1Time_SetTimeSpec) +# define RTAsn1UtcTime_CheckSanity RT_MANGLER(RTAsn1UtcTime_CheckSanity) +# define RTAsn1UtcTime_Clone RT_MANGLER(RTAsn1UtcTime_Clone) +# define RTAsn1UtcTime_Compare RT_MANGLER(RTAsn1UtcTime_Compare) +# define RTAsn1UtcTime_Delete RT_MANGLER(RTAsn1UtcTime_Delete) +# define RTAsn1UtcTime_Enum RT_MANGLER(RTAsn1UtcTime_Enum) +# define RTAsn1UtcTime_Init RT_MANGLER(RTAsn1UtcTime_Init) +# define RTAsn1GeneralizedTime_DecodeAsn1 RT_MANGLER(RTAsn1GeneralizedTime_DecodeAsn1) +# define RTAsn1SeqOfTimes_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfTimes_DecodeAsn1) +# define RTAsn1SetOfTimes_DecodeAsn1 RT_MANGLER(RTAsn1SetOfTimes_DecodeAsn1) +# define RTAsn1Time_DecodeAsn1 RT_MANGLER(RTAsn1Time_DecodeAsn1) +# define RTAsn1UtcTime_DecodeAsn1 RT_MANGLER(RTAsn1UtcTime_DecodeAsn1) +# define RTMd2 RT_MANGLER(RTMd2) +# define RTMd2Final RT_MANGLER(RTMd2Final) +# define RTMd2Init RT_MANGLER(RTMd2Init) +# define RTMd2Update RT_MANGLER(RTMd2Update) +# define RTMd2FromString RT_MANGLER(RTMd2FromString) +# define RTMd2ToString RT_MANGLER(RTMd2ToString) +# define RTCrCipherDecrypt RT_MANGLER(RTCrCipherDecrypt) +# define RTCrCipherEncrypt RT_MANGLER(RTCrCipherEncrypt) +# define RTCrCipherGetBlockSize RT_MANGLER(RTCrCipherGetBlockSize) +# define RTCrCipherGetInitializationVectorLength RT_MANGLER(RTCrCipherGetInitializationVectorLength) +# define RTCrCipherGetKeyLength RT_MANGLER(RTCrCipherGetKeyLength) +# define RTCrCipherOpenByType RT_MANGLER(RTCrCipherOpenByType) +# define RTCrCipherRetain RT_MANGLER(RTCrCipherRetain) +# define RTCrCipherRelease RT_MANGLER(RTCrCipherRelease) +# define RTCrCipherCtxFree RT_MANGLER(RTCrCipherCtxFree) +# define RTCrCipherCtxDecryptInit RT_MANGLER(RTCrCipherCtxDecryptInit) +# define RTCrCipherCtxDecryptFinish RT_MANGLER(RTCrCipherCtxDecryptFinish) +# define RTCrCipherCtxDecryptProcess RT_MANGLER(RTCrCipherCtxDecryptProcess) +# define RTCrCipherCtxEncryptInit RT_MANLGER(RTCrCipherCtxEncryptInit) +# define RTCrCipherCtxEncryptFinish RT_MANGLER(RTCrCipherCtxEncryptFinish) +# define RTCrCipherCtxEncryptProcess RT_MANGLER(RTCrCipherCtxEncryptProcess) +# define RTCrCipherDecrypt RT_MANGLER(RTCrCipherDecrypt) +# define RTCrCipherDecryptEx RT_MANGLER(RTCrCipherDecryptEx) +# define RTCrCipherEncrypt RT_MANGLER(RTCrCipherEncrypt) +# define RTCrCipherEncryptEx RT_MANGLER(RTCrCipherEncryptEx) +# define RTCrDigestClone RT_MANGLER(RTCrDigestClone) +# define RTCrDigestCreate RT_MANGLER(RTCrDigestCreate) +# define RTCrDigestFinal RT_MANGLER(RTCrDigestFinal) +# define RTCrDigestGetConsumedSize RT_MANGLER(RTCrDigestGetConsumedSize) +# define RTCrDigestGetFlags RT_MANGLER(RTCrDigestGetFlags) +# define RTCrDigestGetHash RT_MANGLER(RTCrDigestGetHash) +# define RTCrDigestGetHashSize RT_MANGLER(RTCrDigestGetHashSize) +# define RTCrDigestGetType RT_MANGLER(RTCrDigestGetType) +# define RTCrDigestGetAlgorithmOid RT_MANGLER(RTCrDigestGetAlgorithmOid) +# define RTCrDigestIsFinalized RT_MANGLER(RTCrDigestIsFinalized) +# define RTCrDigestMatch RT_MANGLER(RTCrDigestMatch) +# define RTCrDigestRelease RT_MANGLER(RTCrDigestRelease) +# define RTCrDigestReset RT_MANGLER(RTCrDigestReset) +# define RTCrDigestRetain RT_MANGLER(RTCrDigestRetain) +# define RTCrDigestUpdate RT_MANGLER(RTCrDigestUpdate) +# define RTCrDigestUpdateFromVfsFile RT_MANGLER(RTCrDigestUpdateFromVfsFile) +# define RTCrDigestCreateByObjId RT_MANGLER(RTCrDigestCreateByObjId) +# define RTCrDigestCreateByObjIdString RT_MANGLER(RTCrDigestCreateByObjIdString) +# define RTCrDigestCreateByType RT_MANGLER(RTCrDigestCreateByType) +# define RTCrDigestFindByObjId RT_MANGLER(RTCrDigestFindByObjId) +# define RTCrDigestFindByObjIdString RT_MANGLER(RTCrDigestFindByObjIdString) +# define RTCrDigestFindByType RT_MANGLER(RTCrDigestFindByType) +# define RTCrDigestTypeToAlgorithmOid RT_MANGLER(RTCrDigestTypeToAlgorithmOid) +# define RTCrDigestTypeToName RT_MANGLER(RTCrDigestTypeToName) +# define RTCrDigestTypeToHashSize RT_MANGLER(RTCrDigestTypeToHashSize) +# define RTCrKeyCreateFromBuffer RT_MANGLER(RTCrKeyCreateFromBuffer) +# define RTCrKeyCreateFromFile RT_MANGLER(RTCrKeyCreateFromFile) +# define RTCrKeyCreateFromPemSection RT_MANGLER(RTCrKeyCreateFromPemSection) +# define RTCrKeyCreateFromPublicAlgorithmAndBits RT_MANGLER(RTCrKeyCreateFromPublicAlgorithmAndBits) +# define RTCrKeyCreateFromSubjectPublicKeyInfo RT_MANGLER(RTCrKeyCreateFromSubjectPublicKeyInfo) +# define RTCrKeyCreateNewRsa RT_MANGLER(RTCrKeyCreateNewRsa) +# define RTCrKeyGetBitCount RT_MANGLER(RTCrKeyGetBitCount) +# define RTCrKeyGetType RT_MANGLER(RTCrKeyGetType) +# define RTCrKeyHasPrivatePart RT_MANGLER(RTCrKeyHasPrivatePart) +# define RTCrKeyHasPublicPart RT_MANGLER(RTCrKeyHasPublicPart) +# define RTCrKeyRelease RT_MANGLER(RTCrKeyRelease) +# define RTCrKeyRetain RT_MANGLER(RTCrKeyRetain) +# define RTCrKeyQueryRsaModulus RT_MANGLER(RTCrKeyQueryRsaModulus) +# define RTCrKeyQueryRsaPrivateExponent RT_MANGLER(RTCrKeyQueryRsaPrivateExponent) +# define RTCrRc4 RT_MANGLER(RTCrRc4) +# define RTCrRc4SetKey RT_MANGLER(RTCrRc4SetKey) +# define RTCrRsaDigestInfo_DecodeAsn1 RT_MANGLER(RTCrRsaDigestInfo_DecodeAsn1) +# define RTCrRsaOtherPrimeInfo_DecodeAsn1 RT_MANGLER(RTCrRsaOtherPrimeInfo_DecodeAsn1) +# define RTCrRsaOtherPrimeInfos_DecodeAsn1 RT_MANGLER(RTCrRsaOtherPrimeInfos_DecodeAsn1) +# define RTCrRsaPrivateKey_DecodeAsn1 RT_MANGLER(RTCrRsaPrivateKey_DecodeAsn1) +# define RTCrRsaPublicKey_DecodeAsn1 RT_MANGLER(RTCrRsaPublicKey_DecodeAsn1) +# define RTCrRsaDigestInfo_Compare RT_MANGLER(RTCrRsaDigestInfo_Compare) +# define RTCrRsaDigestInfo_Delete RT_MANGLER(RTCrRsaDigestInfo_Delete) +# define RTCrRsaDigestInfo_Enum RT_MANGLER(RTCrRsaDigestInfo_Enum) +# define RTCrRsaOtherPrimeInfo_Compare RT_MANGLER(RTCrRsaOtherPrimeInfo_Compare) +# define RTCrRsaOtherPrimeInfo_Delete RT_MANGLER(RTCrRsaOtherPrimeInfo_Delete) +# define RTCrRsaOtherPrimeInfo_Enum RT_MANGLER(RTCrRsaOtherPrimeInfo_Enum) +# define RTCrRsaOtherPrimeInfos_Compare RT_MANGLER(RTCrRsaOtherPrimeInfos_Compare) +# define RTCrRsaOtherPrimeInfos_Delete RT_MANGLER(RTCrRsaOtherPrimeInfos_Delete) +# define RTCrRsaOtherPrimeInfos_Enum RT_MANGLER(RTCrRsaOtherPrimeInfos_Enum) +# define RTCrRsaPrivateKey_Compare RT_MANGLER(RTCrRsaPrivateKey_Compare) +# define RTCrRsaPrivateKey_Delete RT_MANGLER(RTCrRsaPrivateKey_Delete) +# define RTCrRsaPrivateKey_Enum RT_MANGLER(RTCrRsaPrivateKey_Enum) +# define RTCrRsaPublicKey_Compare RT_MANGLER(RTCrRsaPublicKey_Compare) +# define RTCrRsaPublicKey_Delete RT_MANGLER(RTCrRsaPublicKey_Delete) +# define RTCrRsaPublicKey_Enum RT_MANGLER(RTCrRsaPublicKey_Enum) +# define RTCrRsaDigestInfo_Clone RT_MANGLER(RTCrRsaDigestInfo_Clone) +# define RTCrRsaDigestInfo_Init RT_MANGLER(RTCrRsaDigestInfo_Init) +# define RTCrRsaOtherPrimeInfo_Clone RT_MANGLER(RTCrRsaOtherPrimeInfo_Clone) +# define RTCrRsaOtherPrimeInfo_Init RT_MANGLER(RTCrRsaOtherPrimeInfo_Init) +# define RTCrRsaOtherPrimeInfos_Clone RT_MANGLER(RTCrRsaOtherPrimeInfos_Clone) +# define RTCrRsaOtherPrimeInfos_Init RT_MANGLER(RTCrRsaOtherPrimeInfos_Init) +# define RTCrRsaPrivateKey_Clone RT_MANGLER(RTCrRsaPrivateKey_Clone) +# define RTCrRsaPrivateKey_Init RT_MANGLER(RTCrRsaPrivateKey_Init) +# define RTCrRsaPublicKey_Clone RT_MANGLER(RTCrRsaPublicKey_Clone) +# define RTCrRsaPublicKey_Init RT_MANGLER(RTCrRsaPublicKey_Init) +# define RTCrRsaDigestInfo_CheckSanity RT_MANGLER(RTCrRsaDigestInfo_CheckSanity) +# define RTCrRsaOtherPrimeInfo_CheckSanity RT_MANGLER(RTCrRsaOtherPrimeInfo_CheckSanity) +# define RTCrRsaOtherPrimeInfos_CheckSanity RT_MANGLER(RTCrRsaOtherPrimeInfos_CheckSanity) +# define RTCrRsaPrivateKey_CheckSanity RT_MANGLER(RTCrRsaPrivateKey_CheckSanity) +# define RTCrRsaPrivateKey_CanHandleDigestType RT_MANGLER(RTCrRsaPrivateKey_CanHandleDigestType) +# define RTCrRsaPublicKey_CheckSanity RT_MANGLER(RTCrRsaPublicKey_CheckSanity) +# define RTCrRsaPublicKey_CanHandleDigestType RT_MANGLER(RTCrRsaPublicKey_CanHandleDigestType) +# define RTCrPemFindFirstSectionInContent RT_MANGLER(RTCrPemFindFirstSectionInContent) +# define RTCrPemFreeSections RT_MANGLER(RTCrPemFreeSections) +# define RTCrPemParseContent RT_MANGLER(RTCrPemParseContent) +# define RTCrPemReadFile RT_MANGLER(RTCrPemReadFile) +# define RTCrPemWriteBlob RT_MANGLER(RTCrPemWriteBlob) +# define RTCrPemWriteBlobToVfsIoStrm RT_MANGLER(RTCrPemWriteBlobToVfsIoStrm) +# define RTCrPemWriteBlobToVfsFile RT_MANGLER(RTCrPemWriteBlobToVfsFile) +# define RTCrPemWriteAsn1 RT_MANGLER(RTCrPemWriteAsn1) +# define RTCrPemWriteAsn1ToVfsIoStrm RT_MANGLER(RTCrPemWriteAsn1ToVfsIoStrm) +# define RTCrPemWriteAsn1ToVfsFile RT_MANGLER(RTCrPemWriteAsn1ToVfsFile) +# define RTCrPkcs5Pbkdf2Hmac RT_MANGLER(RTCrPkcs5Pbkdf2Hmac) +# define RTCrPkcs7_ReadFromBuffer RT_MANGLER(RTCrPkcs7_ReadFromBuffer) +# define RTCrPkcs7Attribute_SetAppleMultiCdPlist RT_MANGLER(RTCrPkcs7Attribute_SetAppleMultiCdPlist) +# define RTCrPkcs7Attribute_SetContentType RT_MANGLER(RTCrPkcs7Attribute_SetContentType) +# define RTCrPkcs7Attribute_SetCounterSignatures RT_MANGLER(RTCrPkcs7Attribute_SetCounterSignatures) +# define RTCrPkcs7Attribute_SetMessageDigest RT_MANGLER(RTCrPkcs7Attribute_SetMessageDigest) +# define RTCrPkcs7Attribute_SetMsStatementType RT_MANGLER(RTCrPkcs7Attribute_SetMsStatementType) +# define RTCrPkcs7Attribute_SetMsNestedSignature RT_MANGLER(RTCrPkcs7Attribute_SetMsNestedSignature) +# define RTCrPkcs7Attribute_SetMsTimestamp RT_MANGLER(RTCrPkcs7Attribute_SetMsTimestamp) +# define RTCrPkcs7Attribute_SetSigningTime RT_MANGLER(RTCrPkcs7Attribute_SetSigningTime) +# define RTCrPkcs7Attributes_HashAttributes RT_MANGLER(RTCrPkcs7Attributes_HashAttributes) +# define RTCrPkcs7Attribute_DecodeAsn1 RT_MANGLER(RTCrPkcs7Attribute_DecodeAsn1) +# define RTCrPkcs7Attributes_DecodeAsn1 RT_MANGLER(RTCrPkcs7Attributes_DecodeAsn1) +# define RTCrPkcs7ContentInfo_DecodeAsn1 RT_MANGLER(RTCrPkcs7ContentInfo_DecodeAsn1) +# define RTCrPkcs7DigestInfo_DecodeAsn1 RT_MANGLER(RTCrPkcs7DigestInfo_DecodeAsn1) +# define RTCrPkcs7IssuerAndSerialNumber_DecodeAsn1 RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_DecodeAsn1) +# define RTCrPkcs7SignedData_SetCertificates RT_MANGLER(RTCrPkcs7SignedData_SetCertificates) +# define RTCrPkcs7SignedData_SetCrls RT_MANGLER(RTCrPkcs7SignedData_SetCrls) +# define RTCrPkcs7SignedData_DecodeAsn1 RT_MANGLER(RTCrPkcs7SignedData_DecodeAsn1) +# define RTCrPkcs7SignerInfo_SetAuthenticatedAttributes RT_MANGLER(RTCrPkcs7SignerInfo_SetAuthenticatedAttributes) +# define RTCrPkcs7SignerInfo_SetUnauthenticatedAttributes RT_MANGLER(RTCrPkcs7SignerInfo_SetUnauthenticatedAttributes) +# define RTCrPkcs7SignerInfo_DecodeAsn1 RT_MANGLER(RTCrPkcs7SignerInfo_DecodeAsn1) +# define RTCrPkcs7SignerInfos_DecodeAsn1 RT_MANGLER(RTCrPkcs7SignerInfos_DecodeAsn1) +# define RTCrPkcs7Attribute_Compare RT_MANGLER(RTCrPkcs7Attribute_Compare) +# define RTCrPkcs7Attribute_Delete RT_MANGLER(RTCrPkcs7Attribute_Delete) +# define RTCrPkcs7Attribute_Enum RT_MANGLER(RTCrPkcs7Attribute_Enum) +# define RTCrPkcs7Attributes_Compare RT_MANGLER(RTCrPkcs7Attributes_Compare) +# define RTCrPkcs7Attributes_Delete RT_MANGLER(RTCrPkcs7Attributes_Delete) +# define RTCrPkcs7Attributes_Enum RT_MANGLER(RTCrPkcs7Attributes_Enum) +# define RTCrPkcs7ContentInfo_Compare RT_MANGLER(RTCrPkcs7ContentInfo_Compare) +# define RTCrPkcs7ContentInfo_Delete RT_MANGLER(RTCrPkcs7ContentInfo_Delete) +# define RTCrPkcs7ContentInfo_Enum RT_MANGLER(RTCrPkcs7ContentInfo_Enum) +# define RTCrPkcs7ContentInfo_IsSignedData RT_MANGLER(RTCrPkcs7ContentInfo_IsSignedData) +# define RTCrPkcs7DigestInfo_Compare RT_MANGLER(RTCrPkcs7DigestInfo_Compare) +# define RTCrPkcs7DigestInfo_Delete RT_MANGLER(RTCrPkcs7DigestInfo_Delete) +# define RTCrPkcs7DigestInfo_Enum RT_MANGLER(RTCrPkcs7DigestInfo_Enum) +# define RTCrPkcs7IssuerAndSerialNumber_Compare RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Compare) +# define RTCrPkcs7IssuerAndSerialNumber_Delete RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Delete) +# define RTCrPkcs7IssuerAndSerialNumber_Enum RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Enum) +# define RTCrPkcs7SignedData_Compare RT_MANGLER(RTCrPkcs7SignedData_Compare) +# define RTCrPkcs7SignedData_Delete RT_MANGLER(RTCrPkcs7SignedData_Delete) +# define RTCrPkcs7SignedData_Enum RT_MANGLER(RTCrPkcs7SignedData_Enum) +# define RTCrPkcs7SignerInfo_Compare RT_MANGLER(RTCrPkcs7SignerInfo_Compare) +# define RTCrPkcs7SignerInfo_Delete RT_MANGLER(RTCrPkcs7SignerInfo_Delete) +# define RTCrPkcs7SignerInfo_Enum RT_MANGLER(RTCrPkcs7SignerInfo_Enum) +# define RTCrPkcs7SignerInfo_GetSigningTime RT_MANGLER(RTCrPkcs7SignerInfo_GetSigningTime) +# define RTCrPkcs7SignerInfo_GetMsTimestamp RT_MANGLER(RTCrPkcs7SignerInfo_GetMsTimestamp) +# define RTCrPkcs7SignerInfos_Compare RT_MANGLER(RTCrPkcs7SignerInfos_Compare) +# define RTCrPkcs7SignerInfos_Delete RT_MANGLER(RTCrPkcs7SignerInfos_Delete) +# define RTCrPkcs7SignerInfos_Enum RT_MANGLER(RTCrPkcs7SignerInfos_Enum) +# define RTCrPkcs7Attribute_Clone RT_MANGLER(RTCrPkcs7Attribute_Clone) +# define RTCrPkcs7Attribute_Init RT_MANGLER(RTCrPkcs7Attribute_Init) +# define RTCrPkcs7Attributes_Clone RT_MANGLER(RTCrPkcs7Attributes_Clone) +# define RTCrPkcs7Attributes_Init RT_MANGLER(RTCrPkcs7Attributes_Init) +# define RTCrPkcs7ContentInfo_Clone RT_MANGLER(RTCrPkcs7ContentInfo_Clone) +# define RTCrPkcs7ContentInfo_Init RT_MANGLER(RTCrPkcs7ContentInfo_Init) +# define RTCrPkcs7DigestInfo_Clone RT_MANGLER(RTCrPkcs7DigestInfo_Clone) +# define RTCrPkcs7DigestInfo_Init RT_MANGLER(RTCrPkcs7DigestInfo_Init) +# define RTCrPkcs7IssuerAndSerialNumber_Clone RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Clone) +# define RTCrPkcs7IssuerAndSerialNumber_Init RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Init) +# define RTCrPkcs7SignedData_Clone RT_MANGLER(RTCrPkcs7SignedData_Clone) +# define RTCrPkcs7SignedData_Init RT_MANGLER(RTCrPkcs7SignedData_Init) +# define RTCrPkcs7SignerInfo_Clone RT_MANGLER(RTCrPkcs7SignerInfo_Clone) +# define RTCrPkcs7SignerInfo_Init RT_MANGLER(RTCrPkcs7SignerInfo_Init) +# define RTCrPkcs7SignerInfos_Clone RT_MANGLER(RTCrPkcs7SignerInfos_Clone) +# define RTCrPkcs7SignerInfos_Init RT_MANGLER(RTCrPkcs7SignerInfos_Init) +# define RTCrPkcs7Attribute_CheckSanity RT_MANGLER(RTCrPkcs7Attribute_CheckSanity) +# define RTCrPkcs7Attributes_CheckSanity RT_MANGLER(RTCrPkcs7Attributes_CheckSanity) +# define RTCrPkcs7ContentInfo_CheckSanity RT_MANGLER(RTCrPkcs7ContentInfo_CheckSanity) +# define RTCrPkcs7DigestInfo_CheckSanity RT_MANGLER(RTCrPkcs7DigestInfo_CheckSanity) +# define RTCrPkcs7IssuerAndSerialNumber_CheckSanity RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_CheckSanity) +# define RTCrPkcs7SignedData_CheckSanity RT_MANGLER(RTCrPkcs7SignedData_CheckSanity) +# define RTCrPkcs7SignerInfo_CheckSanity RT_MANGLER(RTCrPkcs7SignerInfo_CheckSanity) +# define RTCrPkcs7SignerInfos_CheckSanity RT_MANGLER(RTCrPkcs7SignerInfos_CheckSanity) +# define RTCrPkcs7SimpleSignSignedData RT_MANGLER(RTCrPkcs7SimpleSignSignedData) +# define RTCrPkcs7VerifyCertCallbackCodeSigning RT_MANGLER(RTCrPkcs7VerifyCertCallbackCodeSigning) +# define RTCrPkcs7VerifyCertCallbackDefault RT_MANGLER(RTCrPkcs7VerifyCertCallbackDefault) +# define RTCrPkcs7VerifySignedData RT_MANGLER(RTCrPkcs7VerifySignedData) +# define RTCrPkcs7VerifySignedDataWithExternalData RT_MANGLER(RTCrPkcs7VerifySignedDataWithExternalData) +# define RTCrPkcs7Cert_SetX509Cert RT_MANGLER(RTCrPkcs7Cert_SetX509Cert) +# define RTCrPkcs7Cert_SetExtendedCert RT_MANGLER(RTCrPkcs7Cert_SetExtendedCert) +# define RTCrPkcs7Cert_SetAcV1 RT_MANGLER(RTCrPkcs7Cert_SetAcV1) +# define RTCrPkcs7Cert_SetAcV2 RT_MANGLER(RTCrPkcs7Cert_SetAcV2) +# define RTCrPkcs7Cert_SetOtherCert RT_MANGLER(RTCrPkcs7Cert_SetOtherCert) +# define RTCrPkcs7Cert_CheckSanity RT_MANGLER(RTCrPkcs7Cert_CheckSanity) +# define RTCrPkcs7Cert_Clone RT_MANGLER(RTCrPkcs7Cert_Clone) +# define RTCrPkcs7Cert_Compare RT_MANGLER(RTCrPkcs7Cert_Compare) +# define RTCrPkcs7Cert_DecodeAsn1 RT_MANGLER(RTCrPkcs7Cert_DecodeAsn1) +# define RTCrPkcs7Cert_Delete RT_MANGLER(RTCrPkcs7Cert_Delete) +# define RTCrPkcs7Cert_Enum RT_MANGLER(RTCrPkcs7Cert_Enum) +# define RTCrPkcs7Cert_Init RT_MANGLER(RTCrPkcs7Cert_Init) +# define RTCrPkcs7SetOfCerts_CheckSanity RT_MANGLER(RTCrPkcs7SetOfCerts_CheckSanity) +# define RTCrPkcs7SetOfCerts_Clone RT_MANGLER(RTCrPkcs7SetOfCerts_Clone) +# define RTCrPkcs7SetOfCerts_Compare RT_MANGLER(RTCrPkcs7SetOfCerts_Compare) +# define RTCrPkcs7SetOfCerts_DecodeAsn1 RT_MANGLER(RTCrPkcs7SetOfCerts_DecodeAsn1) +# define RTCrPkcs7SetOfCerts_Delete RT_MANGLER(RTCrPkcs7SetOfCerts_Delete) +# define RTCrPkcs7SetOfCerts_Enum RT_MANGLER(RTCrPkcs7SetOfCerts_Enum) +# define RTCrPkcs7SetOfCerts_Init RT_MANGLER(RTCrPkcs7SetOfCerts_Init) +# define RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber RT_MANGLER(RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber) +# define RTCrPkcs7SetOfContentInfos_CheckSanity RT_MANGLER(RTCrPkcs7SetOfContentInfos_CheckSanity) +# define RTCrPkcs7SetOfContentInfos_Clone RT_MANGLER(RTCrPkcs7SetOfContentInfos_Clone) +# define RTCrPkcs7SetOfContentInfos_Compare RT_MANGLER(RTCrPkcs7SetOfContentInfos_Compare) +# define RTCrPkcs7SetOfContentInfos_DecodeAsn1 RT_MANGLER(RTCrPkcs7SetOfContentInfos_DecodeAsn1) +# define RTCrPkcs7SetOfContentInfos_Delete RT_MANGLER(RTCrPkcs7SetOfContentInfos_Delete) +# define RTCrPkcs7SetOfContentInfos_Enum RT_MANGLER(RTCrPkcs7SetOfContentInfos_Enum) +# define RTCrPkcs7SetOfContentInfos_Init RT_MANGLER(RTCrPkcs7SetOfContentInfos_Init) +# define RTCrPkcs7SetOfSignedData_CheckSanity RT_MANGLER(RTCrPkcs7SetOfSignedData_CheckSanity) +# define RTCrPkcs7SetOfSignedData_Clone RT_MANGLER(RTCrPkcs7SetOfSignedData_Clone) +# define RTCrPkcs7SetOfSignedData_Compare RT_MANGLER(RTCrPkcs7SetOfSignedData_Compare) +# define RTCrPkcs7SetOfSignedData_DecodeAsn1 RT_MANGLER(RTCrPkcs7SetOfSignedData_DecodeAsn1) +# define RTCrPkcs7SetOfSignedData_Delete RT_MANGLER(RTCrPkcs7SetOfSignedData_Delete) +# define RTCrPkcs7SetOfSignedData_Enum RT_MANGLER(RTCrPkcs7SetOfSignedData_Enum) +# define RTCrPkcs7SetOfSignedData_Init RT_MANGLER(RTCrPkcs7SetOfSignedData_Init) +# define RTCrPkixSignatureCreateByObjId RT_MANGLER(RTCrPkixSignatureCreateByObjId) +# define RTCrPkixSignatureCreateByObjIdString RT_MANGLER(RTCrPkixSignatureCreateByObjIdString) +# define RTCrPkixSignatureCreate RT_MANGLER(RTCrPkixSignatureCreate) +# define RTCrPkixSignatureFindByObjId RT_MANGLER(RTCrPkixSignatureFindByObjId) +# define RTCrPkixSignatureFindByObjIdString RT_MANGLER(RTCrPkixSignatureFindByObjIdString) +# define RTCrPkixSignatureRelease RT_MANGLER(RTCrPkixSignatureRelease) +# define RTCrPkixSignatureRetain RT_MANGLER(RTCrPkixSignatureRetain) +# define RTCrPkixSignatureSign RT_MANGLER(RTCrPkixSignatureSign) +# define RTCrPkixSignatureVerify RT_MANGLER(RTCrPkixSignatureVerify) +# define RTCrPkixSignatureVerifyBitString RT_MANGLER(RTCrPkixSignatureVerifyBitString) +# define RTCrPkixSignatureVerifyOctetString RT_MANGLER(RTCrPkixSignatureVerifyOctetString) +# define RTCrPkixGetCiperOidFromSignatureAlgorithm RT_MANGLER(RTCrPkixGetCiperOidFromSignatureAlgorithm) +# define RTCrPkixPubKeySignDigest RT_MANGLER(RTCrPkixPubKeySignDigest) +# define RTCrPkixPubKeyVerifySignature RT_MANGLER(RTCrPkixPubKeyVerifySignature) +# define RTCrPkixPubKeyVerifySignedDigest RT_MANGLER(RTCrPkixPubKeyVerifySignedDigest) +# define RTCrPkixPubKeyVerifySignedDigestByCertPubKeyInfo RT_MANGLER(RTCrPkixPubKeyVerifySignedDigestByCertPubKeyInfo) +# define RTCrPkixPubKeyCanHandleDigestType RT_MANGLER(RTCrPkixPubKeyCanHandleDigestType) +# define RTCrPkixCanCertHandleDigestType RT_MANGLER(RTCrPkixCanCertHandleDigestType) +# define RTCrRandBytes RT_MANGLER(RTCrRandBytes) +# define RTCrSpcAttributeTypeAndOptionalValue_SetPeImage RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_SetPeImage) +# define RTCrSpcAttributeTypeAndOptionalValue_DecodeAsn1 RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_DecodeAsn1) +# define RTCrSpcIndirectDataContent_DecodeAsn1 RT_MANGLER(RTCrSpcIndirectDataContent_DecodeAsn1) +# define RTCrSpcLink_DecodeAsn1 RT_MANGLER(RTCrSpcLink_DecodeAsn1) +# define RTCrSpcPeImageData_SetFile RT_MANGLER(RTCrSpcPeImageData_SetFile) +# define RTCrSpcPeImageData_SetFlags RT_MANGLER(RTCrSpcPeImageData_SetFlags) +# define RTCrSpcPeImageData_DecodeAsn1 RT_MANGLER(RTCrSpcPeImageData_DecodeAsn1) +# define RTCrSpcSerializedObjectAttribute_SetV1Hashes RT_MANGLER(RTCrSpcSerializedObjectAttribute_SetV1Hashes) +# define RTCrSpcSerializedObjectAttribute_SetV2Hashes RT_MANGLER(RTCrSpcSerializedObjectAttribute_SetV2Hashes) +# define RTCrSpcSerializedObjectAttribute_DecodeAsn1 RT_MANGLER(RTCrSpcSerializedObjectAttribute_DecodeAsn1) +# define RTCrSpcSerializedObjectAttributes_DecodeAsn1 RT_MANGLER(RTCrSpcSerializedObjectAttributes_DecodeAsn1) +# define RTCrSpcSerializedObject_DecodeAsn1 RT_MANGLER(RTCrSpcSerializedObject_DecodeAsn1) +# define RTCrSpcSerializedPageHashes_DecodeAsn1 RT_MANGLER(RTCrSpcSerializedPageHashes_DecodeAsn1) +# define RTCrSpcString_DecodeAsn1 RT_MANGLER(RTCrSpcString_DecodeAsn1) +# define RTCrSpcAttributeTypeAndOptionalValue_Compare RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Compare) +# define RTCrSpcAttributeTypeAndOptionalValue_Delete RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Delete) +# define RTCrSpcAttributeTypeAndOptionalValue_Enum RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Enum) +# define RTCrSpcIndirectDataContent_Compare RT_MANGLER(RTCrSpcIndirectDataContent_Compare) +# define RTCrSpcIndirectDataContent_Delete RT_MANGLER(RTCrSpcIndirectDataContent_Delete) +# define RTCrSpcIndirectDataContent_Enum RT_MANGLER(RTCrSpcIndirectDataContent_Enum) +# define RTCrSpcIndirectDataContent_GetPeImageObjAttrib RT_MANGLER(RTCrSpcIndirectDataContent_GetPeImageObjAttrib) +# define RTCrSpcLink_SetFile RT_MANGLER(RTCrSpcLink_SetFile) +# define RTCrSpcLink_SetMoniker RT_MANGLER(RTCrSpcLink_SetMoniker) +# define RTCrSpcLink_SetUrl RT_MANGLER(RTCrSpcLink_SetUrl) +# define RTCrSpcLink_Compare RT_MANGLER(RTCrSpcLink_Compare) +# define RTCrSpcLink_Delete RT_MANGLER(RTCrSpcLink_Delete) +# define RTCrSpcLink_Enum RT_MANGLER(RTCrSpcLink_Enum) +# define RTCrSpcPeImageData_Compare RT_MANGLER(RTCrSpcPeImageData_Compare) +# define RTCrSpcPeImageData_Delete RT_MANGLER(RTCrSpcPeImageData_Delete) +# define RTCrSpcPeImageData_Enum RT_MANGLER(RTCrSpcPeImageData_Enum) +# define RTCrSpcSerializedObjectAttribute_Compare RT_MANGLER(RTCrSpcSerializedObjectAttribute_Compare) +# define RTCrSpcSerializedObjectAttribute_Delete RT_MANGLER(RTCrSpcSerializedObjectAttribute_Delete) +# define RTCrSpcSerializedObjectAttribute_Enum RT_MANGLER(RTCrSpcSerializedObjectAttribute_Enum) +# define RTCrSpcSerializedObjectAttributes_Compare RT_MANGLER(RTCrSpcSerializedObjectAttributes_Compare) +# define RTCrSpcSerializedObjectAttributes_Delete RT_MANGLER(RTCrSpcSerializedObjectAttributes_Delete) +# define RTCrSpcSerializedObjectAttributes_Enum RT_MANGLER(RTCrSpcSerializedObjectAttributes_Enum) +# define RTCrSpcSerializedObject_Compare RT_MANGLER(RTCrSpcSerializedObject_Compare) +# define RTCrSpcSerializedObject_Delete RT_MANGLER(RTCrSpcSerializedObject_Delete) +# define RTCrSpcSerializedObject_Enum RT_MANGLER(RTCrSpcSerializedObject_Enum) +# define RTCrSpcSerializedPageHashes_Compare RT_MANGLER(RTCrSpcSerializedPageHashes_Compare) +# define RTCrSpcSerializedPageHashes_Delete RT_MANGLER(RTCrSpcSerializedPageHashes_Delete) +# define RTCrSpcSerializedPageHashes_Enum RT_MANGLER(RTCrSpcSerializedPageHashes_Enum) +# define RTCrSpcSerializedPageHashes_UpdateDerivedData RT_MANGLER(RTCrSpcSerializedPageHashes_UpdateDerivedData) +# define RTCrSpcString_Compare RT_MANGLER(RTCrSpcString_Compare) +# define RTCrSpcString_Delete RT_MANGLER(RTCrSpcString_Delete) +# define RTCrSpcString_Enum RT_MANGLER(RTCrSpcString_Enum) +# define RTCrSpcAttributeTypeAndOptionalValue_Clone RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Clone) +# define RTCrSpcAttributeTypeAndOptionalValue_Init RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Init) +# define RTCrSpcIndirectDataContent_Clone RT_MANGLER(RTCrSpcIndirectDataContent_Clone) +# define RTCrSpcIndirectDataContent_Init RT_MANGLER(RTCrSpcIndirectDataContent_Init) +# define RTCrSpcString_SetAscii RT_MANGLER(RTCrSpcString_SetAscii) +# define RTCrSpcString_SetUcs2 RT_MANGLER(RTCrSpcString_SetUcs2) +# define RTCrSpcLink_Clone RT_MANGLER(RTCrSpcLink_Clone) +# define RTCrSpcLink_Init RT_MANGLER(RTCrSpcLink_Init) +# define RTCrSpcPeImageData_Clone RT_MANGLER(RTCrSpcPeImageData_Clone) +# define RTCrSpcPeImageData_Init RT_MANGLER(RTCrSpcPeImageData_Init) +# define RTCrSpcSerializedObjectAttribute_Clone RT_MANGLER(RTCrSpcSerializedObjectAttribute_Clone) +# define RTCrSpcSerializedObjectAttribute_Init RT_MANGLER(RTCrSpcSerializedObjectAttribute_Init) +# define RTCrSpcSerializedObjectAttributes_Clone RT_MANGLER(RTCrSpcSerializedObjectAttributes_Clone) +# define RTCrSpcSerializedObjectAttributes_Init RT_MANGLER(RTCrSpcSerializedObjectAttributes_Init) +# define RTCrSpcSerializedObject_Clone RT_MANGLER(RTCrSpcSerializedObject_Clone) +# define RTCrSpcSerializedObject_Init RT_MANGLER(RTCrSpcSerializedObject_Init) +# define RTCrSpcSerializedPageHashes_Clone RT_MANGLER(RTCrSpcSerializedPageHashes_Clone) +# define RTCrSpcSerializedPageHashes_Init RT_MANGLER(RTCrSpcSerializedPageHashes_Init) +# define RTCrSpcString_Clone RT_MANGLER(RTCrSpcString_Clone) +# define RTCrSpcString_Init RT_MANGLER(RTCrSpcString_Init) +# define RTCrSpcAttributeTypeAndOptionalValue_CheckSanity RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_CheckSanity) +# define RTCrSpcIndirectDataContent_CheckSanity RT_MANGLER(RTCrSpcIndirectDataContent_CheckSanity) +# define RTCrSpcIndirectDataContent_CheckSanityEx RT_MANGLER(RTCrSpcIndirectDataContent_CheckSanityEx) +# define RTCrSpcLink_CheckSanity RT_MANGLER(RTCrSpcLink_CheckSanity) +# define RTCrSpcPeImageData_CheckSanity RT_MANGLER(RTCrSpcPeImageData_CheckSanity) +# define RTCrSpcSerializedObjectAttribute_CheckSanity RT_MANGLER(RTCrSpcSerializedObjectAttribute_CheckSanity) +# define RTCrSpcSerializedObjectAttributes_CheckSanity RT_MANGLER(RTCrSpcSerializedObjectAttributes_CheckSanity) +# define RTCrSpcSerializedObject_CheckSanity RT_MANGLER(RTCrSpcSerializedObject_CheckSanity) +# define RTCrSpcSerializedPageHashes_CheckSanity RT_MANGLER(RTCrSpcSerializedPageHashes_CheckSanity) +# define RTCrSpcString_CheckSanity RT_MANGLER(RTCrSpcString_CheckSanity) +# define RTCrSslCreate RT_MANGLER(RTCrSslCreate) +# define RTCrSslCreateSessionForNativeSocket RT_MANGLER(RTCrSslCreateSessionForNativeSocket) +# define RTCrSslLoadTrustedRootCerts RT_MANGLER(RTCrSslLoadTrustedRootCerts) +# define RTCrSslRelease RT_MANGLER(RTCrSslRelease) +# define RTCrSslRetain RT_MANGLER(RTCrSslRetain) +# define RTCrSslSessionAccept RT_MANGLER(RTCrSslSessionAccept) +# define RTCrSslSessionConnect RT_MANGLER(RTCrSslSessionConnect) +# define RTCrSslSessionGetCertIssuerNameAsString RT_MANGLER(RTCrSslSessionGetCertIssuerNameAsString) +# define RTCrSslSessionGetVersion RT_MANGLER(RTCrSslSessionGetVersion) +# define RTCrSslSessionPending RT_MANGLER(RTCrSslSessionPending) +# define RTCrSslSessionRead RT_MANGLER(RTCrSslSessionRead) +# define RTCrSslSessionRelease RT_MANGLER(RTCrSslSessionRelease) +# define RTCrSslSessionRetain RT_MANGLER(RTCrSslSessionRetain) +# define RTCrSslSessionWrite RT_MANGLER(RTCrSslSessionWrite) +# define RTCrSslSetCertificateFile RT_MANGLER(RTCrSslSetCertificateFile) +# define RTCrSslSetNoPeerVerify RT_MANGLER(RTCrSslSetNoPeerVerify) +# define RTCrSslSetPrivateKeyFile RT_MANGLER(RTCrSslSetPrivateKeyFile) +# define RTCrX509AlgorithmIdentifier_DecodeAsn1 RT_MANGLER(RTCrX509AlgorithmIdentifier_DecodeAsn1) +# define RTCrX509AlgorithmIdentifiers_DecodeAsn1 RT_MANGLER(RTCrX509AlgorithmIdentifiers_DecodeAsn1) +# define RTCrX509AttributeTypeAndValue_DecodeAsn1 RT_MANGLER(RTCrX509AttributeTypeAndValue_DecodeAsn1) +# define RTCrX509AttributeTypeAndValues_DecodeAsn1 RT_MANGLER(RTCrX509AttributeTypeAndValues_DecodeAsn1) +# define RTCrX509AuthorityKeyIdentifier_DecodeAsn1 RT_MANGLER(RTCrX509AuthorityKeyIdentifier_DecodeAsn1) +# define RTCrX509BasicConstraints_DecodeAsn1 RT_MANGLER(RTCrX509BasicConstraints_DecodeAsn1) +# define RTCrX509CertificatePolicies_DecodeAsn1 RT_MANGLER(RTCrX509CertificatePolicies_DecodeAsn1) +# define RTCrX509Certificate_DecodeAsn1 RT_MANGLER(RTCrX509Certificate_DecodeAsn1) +# define RTCrX509Certificates_DecodeAsn1 RT_MANGLER(RTCrX509Certificates_DecodeAsn1) +# define RTCrX509Extension_DecodeAsn1 RT_MANGLER(RTCrX509Extension_DecodeAsn1) +# define RTCrX509Extension_ExtnValue_DecodeAsn1 RT_MANGLER(RTCrX509Extension_ExtnValue_DecodeAsn1) +# define RTCrX509Extensions_DecodeAsn1 RT_MANGLER(RTCrX509Extensions_DecodeAsn1) +# define RTCrX509GeneralName_DecodeAsn1 RT_MANGLER(RTCrX509GeneralName_DecodeAsn1) +# define RTCrX509GeneralNames_DecodeAsn1 RT_MANGLER(RTCrX509GeneralNames_DecodeAsn1) +# define RTCrX509GeneralSubtree_DecodeAsn1 RT_MANGLER(RTCrX509GeneralSubtree_DecodeAsn1) +# define RTCrX509GeneralSubtrees_DecodeAsn1 RT_MANGLER(RTCrX509GeneralSubtrees_DecodeAsn1) +# define RTCrX509NameConstraints_DecodeAsn1 RT_MANGLER(RTCrX509NameConstraints_DecodeAsn1) +# define RTCrX509Name_DecodeAsn1 RT_MANGLER(RTCrX509Name_DecodeAsn1) +# define RTCrX509OldAuthorityKeyIdentifier_DecodeAsn1 RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_DecodeAsn1) +# define RTCrX509OtherName_DecodeAsn1 RT_MANGLER(RTCrX509OtherName_DecodeAsn1) +# define RTCrX509PolicyConstraints_DecodeAsn1 RT_MANGLER(RTCrX509PolicyConstraints_DecodeAsn1) +# define RTCrX509PolicyInformation_DecodeAsn1 RT_MANGLER(RTCrX509PolicyInformation_DecodeAsn1) +# define RTCrX509PolicyMapping_DecodeAsn1 RT_MANGLER(RTCrX509PolicyMapping_DecodeAsn1) +# define RTCrX509PolicyMappings_DecodeAsn1 RT_MANGLER(RTCrX509PolicyMappings_DecodeAsn1) +# define RTCrX509PolicyQualifierInfo_DecodeAsn1 RT_MANGLER(RTCrX509PolicyQualifierInfo_DecodeAsn1) +# define RTCrX509PolicyQualifierInfos_DecodeAsn1 RT_MANGLER(RTCrX509PolicyQualifierInfos_DecodeAsn1) +# define RTCrX509SubjectPublicKeyInfo_DecodeAsn1 RT_MANGLER(RTCrX509SubjectPublicKeyInfo_DecodeAsn1) +# define RTCrX509TbsCertificate_DecodeAsn1 RT_MANGLER(RTCrX509TbsCertificate_DecodeAsn1) +# define RTCrX509Validity_DecodeAsn1 RT_MANGLER(RTCrX509Validity_DecodeAsn1) +# define RTCrX509CertPathsBuild RT_MANGLER(RTCrX509CertPathsBuild) +# define RTCrX509CertPathsCreate RT_MANGLER(RTCrX509CertPathsCreate) +# define RTCrX509CertPathsCreateEx RT_MANGLER(RTCrX509CertPathsCreateEx) +# define RTCrX509CertPathsDumpAll RT_MANGLER(RTCrX509CertPathsDumpAll) +# define RTCrX509CertPathsDumpOne RT_MANGLER(RTCrX509CertPathsDumpOne) +# define RTCrX509CertPathsGetPathCount RT_MANGLER(RTCrX509CertPathsGetPathCount) +# define RTCrX509CertPathsGetPathLength RT_MANGLER(RTCrX509CertPathsGetPathLength) +# define RTCrX509CertPathsGetPathNodeCert RT_MANGLER(RTCrX509CertPathsGetPathNodeCert) +# define RTCrX509CertPathsGetPathVerifyResult RT_MANGLER(RTCrX509CertPathsGetPathVerifyResult) +# define RTCrX509CertPathsQueryPathInfo RT_MANGLER(RTCrX509CertPathsQueryPathInfo) +# define RTCrX509CertPathsRelease RT_MANGLER(RTCrX509CertPathsRelease) +# define RTCrX509CertPathsRetain RT_MANGLER(RTCrX509CertPathsRetain) +# define RTCrX509CertPathsSetTrustedStore RT_MANGLER(RTCrX509CertPathsSetTrustedStore) +# define RTCrX509CertPathsSetTrustAnchorChecks RT_MANGLER(RTCrX509CertPathsSetTrustAnchorChecks) +# define RTCrX509CertPathsSetUntrustedArray RT_MANGLER(RTCrX509CertPathsSetUntrustedArray) +# define RTCrX509CertPathsSetUntrustedSet RT_MANGLER(RTCrX509CertPathsSetUntrustedSet) +# define RTCrX509CertPathsSetUntrustedStore RT_MANGLER(RTCrX509CertPathsSetUntrustedStore) +# define RTCrX509CertPathsSetValidTime RT_MANGLER(RTCrX509CertPathsSetValidTime) +# define RTCrX509CertPathsSetValidTimeSpec RT_MANGLER(RTCrX509CertPathsSetValidTimeSpec) +# define RTCrX509CertPathsValidateAll RT_MANGLER(RTCrX509CertPathsValidateAll) +# define RTCrX509CertPathsValidateOne RT_MANGLER(RTCrX509CertPathsValidateOne) +# define RTCrX509AlgorithmIdentifier_CombineEncryptionAndDigest RT_MANGLER(RTCrX509AlgorithmIdentifier_CombineEncryptionAndDigest) +# define RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid RT_MANGLER(RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid) +# define RTCrX509AlgorithmIdentifier_Compare RT_MANGLER(RTCrX509AlgorithmIdentifier_Compare) +# define RTCrX509AlgorithmIdentifier_CompareDigestAndEncryptedDigest RT_MANGLER(RTCrX509AlgorithmIdentifier_CompareDigestAndEncryptedDigest) +# define RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid RT_MANGLER(RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid) +# define RTCrX509AlgorithmIdentifier_CompareWithString RT_MANGLER(RTCrX509AlgorithmIdentifier_CompareWithString) +# define RTCrX509AlgorithmIdentifier_Delete RT_MANGLER(RTCrX509AlgorithmIdentifier_Delete) +# define RTCrX509AlgorithmIdentifier_Enum RT_MANGLER(RTCrX509AlgorithmIdentifier_Enum) +# define RTCrX509AlgorithmIdentifier_QueryDigestSize RT_MANGLER(RTCrX509AlgorithmIdentifier_QueryDigestSize) +# define RTCrX509AlgorithmIdentifier_QueryDigestType RT_MANGLER(RTCrX509AlgorithmIdentifier_QueryDigestType) +# define RTCrX509AlgorithmIdentifiers_Compare RT_MANGLER(RTCrX509AlgorithmIdentifiers_Compare) +# define RTCrX509AlgorithmIdentifiers_Delete RT_MANGLER(RTCrX509AlgorithmIdentifiers_Delete) +# define RTCrX509AlgorithmIdentifiers_Enum RT_MANGLER(RTCrX509AlgorithmIdentifiers_Enum) +# define RTCrX509AttributeTypeAndValue_Compare RT_MANGLER(RTCrX509AttributeTypeAndValue_Compare) +# define RTCrX509AttributeTypeAndValue_Delete RT_MANGLER(RTCrX509AttributeTypeAndValue_Delete) +# define RTCrX509AttributeTypeAndValue_Enum RT_MANGLER(RTCrX509AttributeTypeAndValue_Enum) +# define RTCrX509AttributeTypeAndValues_Compare RT_MANGLER(RTCrX509AttributeTypeAndValues_Compare) +# define RTCrX509AttributeTypeAndValues_Delete RT_MANGLER(RTCrX509AttributeTypeAndValues_Delete) +# define RTCrX509AttributeTypeAndValues_Enum RT_MANGLER(RTCrX509AttributeTypeAndValues_Enum) +# define RTCrX509AuthorityKeyIdentifier_Compare RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Compare) +# define RTCrX509AuthorityKeyIdentifier_Delete RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Delete) +# define RTCrX509AuthorityKeyIdentifier_Enum RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Enum) +# define RTCrX509BasicConstraints_Compare RT_MANGLER(RTCrX509BasicConstraints_Compare) +# define RTCrX509BasicConstraints_Delete RT_MANGLER(RTCrX509BasicConstraints_Delete) +# define RTCrX509BasicConstraints_Enum RT_MANGLER(RTCrX509BasicConstraints_Enum) +# define RTCrX509CertificatePolicies_Compare RT_MANGLER(RTCrX509CertificatePolicies_Compare) +# define RTCrX509CertificatePolicies_Delete RT_MANGLER(RTCrX509CertificatePolicies_Delete) +# define RTCrX509CertificatePolicies_Enum RT_MANGLER(RTCrX509CertificatePolicies_Enum) +# define RTCrX509Certificate_Compare RT_MANGLER(RTCrX509Certificate_Compare) +# define RTCrX509Certificate_Delete RT_MANGLER(RTCrX509Certificate_Delete) +# define RTCrX509Certificate_Enum RT_MANGLER(RTCrX509Certificate_Enum) +# define RTCrX509Certificate_IsSelfSigned RT_MANGLER(RTCrX509Certificate_IsSelfSigned) +# define RTCrX509Certificate_MatchIssuerAndSerialNumber RT_MANGLER(RTCrX509Certificate_MatchIssuerAndSerialNumber) +# define RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280 RT_MANGLER(RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280) +# define RTCrX509Certificates_Compare RT_MANGLER(RTCrX509Certificates_Compare) +# define RTCrX509Certificates_Delete RT_MANGLER(RTCrX509Certificates_Delete) +# define RTCrX509Certificates_Enum RT_MANGLER(RTCrX509Certificates_Enum) +# define RTCrX509Certificates_FindByIssuerAndSerialNumber RT_MANGLER(RTCrX509Certificates_FindByIssuerAndSerialNumber) +# define RTCrX509Extension_Compare RT_MANGLER(RTCrX509Extension_Compare) +# define RTCrX509Extension_Delete RT_MANGLER(RTCrX509Extension_Delete) +# define RTCrX509Extension_Enum RT_MANGLER(RTCrX509Extension_Enum) +# define RTCrX509Extensions_Compare RT_MANGLER(RTCrX509Extensions_Compare) +# define RTCrX509Extensions_Delete RT_MANGLER(RTCrX509Extensions_Delete) +# define RTCrX509Extensions_Enum RT_MANGLER(RTCrX509Extensions_Enum) +# define RTCrX509GeneralName_Compare RT_MANGLER(RTCrX509GeneralName_Compare) +# define RTCrX509GeneralName_ConstraintMatch RT_MANGLER(RTCrX509GeneralName_ConstraintMatch) +# define RTCrX509GeneralName_Delete RT_MANGLER(RTCrX509GeneralName_Delete) +# define RTCrX509GeneralName_Enum RT_MANGLER(RTCrX509GeneralName_Enum) +# define RTCrX509GeneralNames_Compare RT_MANGLER(RTCrX509GeneralNames_Compare) +# define RTCrX509GeneralNames_Delete RT_MANGLER(RTCrX509GeneralNames_Delete) +# define RTCrX509GeneralNames_Enum RT_MANGLER(RTCrX509GeneralNames_Enum) +# define RTCrX509GeneralSubtree_Compare RT_MANGLER(RTCrX509GeneralSubtree_Compare) +# define RTCrX509GeneralSubtree_ConstraintMatch RT_MANGLER(RTCrX509GeneralSubtree_ConstraintMatch) +# define RTCrX509GeneralSubtree_Delete RT_MANGLER(RTCrX509GeneralSubtree_Delete) +# define RTCrX509GeneralSubtree_Enum RT_MANGLER(RTCrX509GeneralSubtree_Enum) +# define RTCrX509GeneralSubtrees_Compare RT_MANGLER(RTCrX509GeneralSubtrees_Compare) +# define RTCrX509GeneralSubtrees_Delete RT_MANGLER(RTCrX509GeneralSubtrees_Delete) +# define RTCrX509GeneralSubtrees_Enum RT_MANGLER(RTCrX509GeneralSubtrees_Enum) +# define RTCrX509NameConstraints_Compare RT_MANGLER(RTCrX509NameConstraints_Compare) +# define RTCrX509NameConstraints_Delete RT_MANGLER(RTCrX509NameConstraints_Delete) +# define RTCrX509NameConstraints_Enum RT_MANGLER(RTCrX509NameConstraints_Enum) +# define RTCrX509Name_Compare RT_MANGLER(RTCrX509Name_Compare) +# define RTCrX509Name_ConstraintMatch RT_MANGLER(RTCrX509Name_ConstraintMatch) +# define RTCrX509Name_Delete RT_MANGLER(RTCrX509Name_Delete) +# define RTCrX509Name_Enum RT_MANGLER(RTCrX509Name_Enum) +# define RTCrX509Name_FormatAsString RT_MANGLER(RTCrX509Name_FormatAsString) +# define RTCrX509Name_MatchByRfc5280 RT_MANGLER(RTCrX509Name_MatchByRfc5280) +# define RTCrX509Name_MatchWithString RT_MANGLER(RTCrX509Name_MatchWithString) +# define RTCrX509Name_GetShortRdn RT_MANGLER(RTCrX509Name_GetShortRdn) +# define RTCrX509OldAuthorityKeyIdentifier_Compare RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Compare) +# define RTCrX509OldAuthorityKeyIdentifier_Delete RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Delete) +# define RTCrX509OldAuthorityKeyIdentifier_Enum RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Enum) +# define RTCrX509OtherName_Compare RT_MANGLER(RTCrX509OtherName_Compare) +# define RTCrX509OtherName_Delete RT_MANGLER(RTCrX509OtherName_Delete) +# define RTCrX509OtherName_Enum RT_MANGLER(RTCrX509OtherName_Enum) +# define RTCrX509PolicyConstraints_Compare RT_MANGLER(RTCrX509PolicyConstraints_Compare) +# define RTCrX509PolicyConstraints_Delete RT_MANGLER(RTCrX509PolicyConstraints_Delete) +# define RTCrX509PolicyConstraints_Enum RT_MANGLER(RTCrX509PolicyConstraints_Enum) +# define RTCrX509PolicyInformation_Compare RT_MANGLER(RTCrX509PolicyInformation_Compare) +# define RTCrX509PolicyInformation_Delete RT_MANGLER(RTCrX509PolicyInformation_Delete) +# define RTCrX509PolicyInformation_Enum RT_MANGLER(RTCrX509PolicyInformation_Enum) +# define RTCrX509PolicyMapping_Compare RT_MANGLER(RTCrX509PolicyMapping_Compare) +# define RTCrX509PolicyMapping_Delete RT_MANGLER(RTCrX509PolicyMapping_Delete) +# define RTCrX509PolicyMapping_Enum RT_MANGLER(RTCrX509PolicyMapping_Enum) +# define RTCrX509PolicyMappings_Compare RT_MANGLER(RTCrX509PolicyMappings_Compare) +# define RTCrX509PolicyMappings_Delete RT_MANGLER(RTCrX509PolicyMappings_Delete) +# define RTCrX509PolicyMappings_Enum RT_MANGLER(RTCrX509PolicyMappings_Enum) +# define RTCrX509PolicyQualifierInfo_Compare RT_MANGLER(RTCrX509PolicyQualifierInfo_Compare) +# define RTCrX509PolicyQualifierInfo_Delete RT_MANGLER(RTCrX509PolicyQualifierInfo_Delete) +# define RTCrX509PolicyQualifierInfo_Enum RT_MANGLER(RTCrX509PolicyQualifierInfo_Enum) +# define RTCrX509PolicyQualifierInfos_Compare RT_MANGLER(RTCrX509PolicyQualifierInfos_Compare) +# define RTCrX509PolicyQualifierInfos_Delete RT_MANGLER(RTCrX509PolicyQualifierInfos_Delete) +# define RTCrX509PolicyQualifierInfos_Enum RT_MANGLER(RTCrX509PolicyQualifierInfos_Enum) +# define RTCrX509SubjectPublicKeyInfo_Compare RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Compare) +# define RTCrX509SubjectPublicKeyInfo_Delete RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Delete) +# define RTCrX509SubjectPublicKeyInfo_Enum RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Enum) +# define RTCrX509TbsCertificate_Compare RT_MANGLER(RTCrX509TbsCertificate_Compare) +# define RTCrX509TbsCertificate_Delete RT_MANGLER(RTCrX509TbsCertificate_Delete) +# define RTCrX509TbsCertificate_Enum RT_MANGLER(RTCrX509TbsCertificate_Enum) +# define RTCrX509TbsCertificate_ReprocessExtensions RT_MANGLER(RTCrX509TbsCertificate_ReprocessExtensions) +# define RTCrX509Validity_Compare RT_MANGLER(RTCrX509Validity_Compare) +# define RTCrX509Validity_Delete RT_MANGLER(RTCrX509Validity_Delete) +# define RTCrX509Validity_Enum RT_MANGLER(RTCrX509Validity_Enum) +# define RTCrX509Validity_IsValidAtTimeSpec RT_MANGLER(RTCrX509Validity_IsValidAtTimeSpec) +# define RTCrX509Certificate_ReadFromFile RT_MANGLER(RTCrX509Certificate_ReadFromFile) +# define RTCrX509Certificate_ReadFromBuffer RT_MANGLER(RTCrX509Certificate_ReadFromBuffer) +# define RTCrX509AlgorithmIdentifier_Clone RT_MANGLER(RTCrX509AlgorithmIdentifier_Clone) +# define RTCrX509AlgorithmIdentifier_Init RT_MANGLER(RTCrX509AlgorithmIdentifier_Init) +# define RTCrX509AlgorithmIdentifiers_Clone RT_MANGLER(RTCrX509AlgorithmIdentifiers_Clone) +# define RTCrX509AlgorithmIdentifiers_Init RT_MANGLER(RTCrX509AlgorithmIdentifiers_Init) +# define RTCrX509AttributeTypeAndValue_Clone RT_MANGLER(RTCrX509AttributeTypeAndValue_Clone) +# define RTCrX509AttributeTypeAndValue_Init RT_MANGLER(RTCrX509AttributeTypeAndValue_Init) +# define RTCrX509AttributeTypeAndValues_Clone RT_MANGLER(RTCrX509AttributeTypeAndValues_Clone) +# define RTCrX509AttributeTypeAndValues_Init RT_MANGLER(RTCrX509AttributeTypeAndValues_Init) +# define RTCrX509AuthorityKeyIdentifier_Clone RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Clone) +# define RTCrX509AuthorityKeyIdentifier_Init RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Init) +# define RTCrX509BasicConstraints_Clone RT_MANGLER(RTCrX509BasicConstraints_Clone) +# define RTCrX509BasicConstraints_Init RT_MANGLER(RTCrX509BasicConstraints_Init) +# define RTCrX509CertificatePolicies_Clone RT_MANGLER(RTCrX509CertificatePolicies_Clone) +# define RTCrX509CertificatePolicies_Init RT_MANGLER(RTCrX509CertificatePolicies_Init) +# define RTCrX509Certificate_Clone RT_MANGLER(RTCrX509Certificate_Clone) +# define RTCrX509Certificate_Init RT_MANGLER(RTCrX509Certificate_Init) +# define RTCrX509Certificates_Clone RT_MANGLER(RTCrX509Certificates_Clone) +# define RTCrX509Certificates_Init RT_MANGLER(RTCrX509Certificates_Init) +# define RTCrX509Extension_Clone RT_MANGLER(RTCrX509Extension_Clone) +# define RTCrX509Extension_Init RT_MANGLER(RTCrX509Extension_Init) +# define RTCrX509Extensions_Clone RT_MANGLER(RTCrX509Extensions_Clone) +# define RTCrX509Extensions_Init RT_MANGLER(RTCrX509Extensions_Init) +# define RTCrX509GeneralName_Clone RT_MANGLER(RTCrX509GeneralName_Clone) +# define RTCrX509GeneralName_Init RT_MANGLER(RTCrX509GeneralName_Init) +# define RTCrX509GeneralNames_Clone RT_MANGLER(RTCrX509GeneralNames_Clone) +# define RTCrX509GeneralNames_Init RT_MANGLER(RTCrX509GeneralNames_Init) +# define RTCrX509GeneralSubtree_Clone RT_MANGLER(RTCrX509GeneralSubtree_Clone) +# define RTCrX509GeneralSubtree_Init RT_MANGLER(RTCrX509GeneralSubtree_Init) +# define RTCrX509GeneralSubtrees_Clone RT_MANGLER(RTCrX509GeneralSubtrees_Clone) +# define RTCrX509GeneralSubtrees_Init RT_MANGLER(RTCrX509GeneralSubtrees_Init) +# define RTCrX509NameConstraints_Clone RT_MANGLER(RTCrX509NameConstraints_Clone) +# define RTCrX509NameConstraints_Init RT_MANGLER(RTCrX509NameConstraints_Init) +# define RTCrX509Name_Clone RT_MANGLER(RTCrX509Name_Clone) +# define RTCrX509Name_Init RT_MANGLER(RTCrX509Name_Init) +# define RTCrX509Name_RecodeAsUtf8 RT_MANGLER(RTCrX509Name_RecodeAsUtf8) +# define RTCrX509OldAuthorityKeyIdentifier_Clone RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Clone) +# define RTCrX509OldAuthorityKeyIdentifier_Init RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Init) +# define RTCrX509OtherName_Clone RT_MANGLER(RTCrX509OtherName_Clone) +# define RTCrX509OtherName_Init RT_MANGLER(RTCrX509OtherName_Init) +# define RTCrX509PolicyConstraints_Clone RT_MANGLER(RTCrX509PolicyConstraints_Clone) +# define RTCrX509PolicyConstraints_Init RT_MANGLER(RTCrX509PolicyConstraints_Init) +# define RTCrX509PolicyInformation_Clone RT_MANGLER(RTCrX509PolicyInformation_Clone) +# define RTCrX509PolicyInformation_Init RT_MANGLER(RTCrX509PolicyInformation_Init) +# define RTCrX509PolicyMapping_Clone RT_MANGLER(RTCrX509PolicyMapping_Clone) +# define RTCrX509PolicyMapping_Init RT_MANGLER(RTCrX509PolicyMapping_Init) +# define RTCrX509PolicyMappings_Clone RT_MANGLER(RTCrX509PolicyMappings_Clone) +# define RTCrX509PolicyMappings_Init RT_MANGLER(RTCrX509PolicyMappings_Init) +# define RTCrX509PolicyQualifierInfo_Clone RT_MANGLER(RTCrX509PolicyQualifierInfo_Clone) +# define RTCrX509PolicyQualifierInfo_Init RT_MANGLER(RTCrX509PolicyQualifierInfo_Init) +# define RTCrX509PolicyQualifierInfos_Clone RT_MANGLER(RTCrX509PolicyQualifierInfos_Clone) +# define RTCrX509PolicyQualifierInfos_Init RT_MANGLER(RTCrX509PolicyQualifierInfos_Init) +# define RTCrRsaPrivateKey_ReadFromFile RT_MANGLER(RTCrRsaPrivateKey_ReadFromFile) +# define RTCrRsaPrivateKey_ReadFromBuffer RT_MANGLER(RTCrRsaPrivateKey_ReadFromBuffer) +# define RTCrRsaPublicKey_ReadFromFile RT_MANGLER(RTCrRsaPublicKey_ReadFromFile) +# define RTCrRsaPublicKey_ReadFromBuffer RT_MANGLER(RTCrRsaPublicKey_ReadFromBuffer) +# define RTCrX509SubjectPublicKeyInfo_Clone RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Clone) +# define RTCrX509SubjectPublicKeyInfo_Init RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Init) +# define RTCrX509TbsCertificate_Clone RT_MANGLER(RTCrX509TbsCertificate_Clone) +# define RTCrX509TbsCertificate_Init RT_MANGLER(RTCrX509TbsCertificate_Init) +# define RTCrX509Validity_Clone RT_MANGLER(RTCrX509Validity_Clone) +# define RTCrX509Validity_Init RT_MANGLER(RTCrX509Validity_Init) +# define RTCrX509AlgorithmIdentifier_CheckSanity RT_MANGLER(RTCrX509AlgorithmIdentifier_CheckSanity) +# define RTCrX509AlgorithmIdentifiers_CheckSanity RT_MANGLER(RTCrX509AlgorithmIdentifiers_CheckSanity) +# define RTCrX509AttributeTypeAndValue_CheckSanity RT_MANGLER(RTCrX509AttributeTypeAndValue_CheckSanity) +# define RTCrX509AttributeTypeAndValues_CheckSanity RT_MANGLER(RTCrX509AttributeTypeAndValues_CheckSanity) +# define RTCrX509AuthorityKeyIdentifier_CheckSanity RT_MANGLER(RTCrX509AuthorityKeyIdentifier_CheckSanity) +# define RTCrX509BasicConstraints_CheckSanity RT_MANGLER(RTCrX509BasicConstraints_CheckSanity) +# define RTCrX509CertificatePolicies_CheckSanity RT_MANGLER(RTCrX509CertificatePolicies_CheckSanity) +# define RTCrX509Certificate_CheckSanity RT_MANGLER(RTCrX509Certificate_CheckSanity) +# define RTCrX509Certificates_CheckSanity RT_MANGLER(RTCrX509Certificates_CheckSanity) +# define RTCrX509Extension_CheckSanity RT_MANGLER(RTCrX509Extension_CheckSanity) +# define RTCrX509Extensions_CheckSanity RT_MANGLER(RTCrX509Extensions_CheckSanity) +# define RTCrX509GeneralName_CheckSanity RT_MANGLER(RTCrX509GeneralName_CheckSanity) +# define RTCrX509GeneralNames_CheckSanity RT_MANGLER(RTCrX509GeneralNames_CheckSanity) +# define RTCrX509GeneralSubtree_CheckSanity RT_MANGLER(RTCrX509GeneralSubtree_CheckSanity) +# define RTCrX509GeneralSubtrees_CheckSanity RT_MANGLER(RTCrX509GeneralSubtrees_CheckSanity) +# define RTCrX509NameConstraints_CheckSanity RT_MANGLER(RTCrX509NameConstraints_CheckSanity) +# define RTCrX509Name_CheckSanity RT_MANGLER(RTCrX509Name_CheckSanity) +# define RTCrX509OldAuthorityKeyIdentifier_CheckSanity RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_CheckSanity) +# define RTCrX509OtherName_CheckSanity RT_MANGLER(RTCrX509OtherName_CheckSanity) +# define RTCrX509PolicyConstraints_CheckSanity RT_MANGLER(RTCrX509PolicyConstraints_CheckSanity) +# define RTCrX509PolicyInformation_CheckSanity RT_MANGLER(RTCrX509PolicyInformation_CheckSanity) +# define RTCrX509PolicyMapping_CheckSanity RT_MANGLER(RTCrX509PolicyMapping_CheckSanity) +# define RTCrX509PolicyMappings_CheckSanity RT_MANGLER(RTCrX509PolicyMappings_CheckSanity) +# define RTCrX509PolicyQualifierInfo_CheckSanity RT_MANGLER(RTCrX509PolicyQualifierInfo_CheckSanity) +# define RTCrX509PolicyQualifierInfos_CheckSanity RT_MANGLER(RTCrX509PolicyQualifierInfos_CheckSanity) +# define RTCrX509SubjectPublicKeyInfo_CheckSanity RT_MANGLER(RTCrX509SubjectPublicKeyInfo_CheckSanity) +# define RTCrX509TbsCertificate_CheckSanity RT_MANGLER(RTCrX509TbsCertificate_CheckSanity) +# define RTCrX509Validity_CheckSanity RT_MANGLER(RTCrX509Validity_CheckSanity) +# define RTCrX509Certificate_VerifySignature RT_MANGLER(RTCrX509Certificate_VerifySignature) +# define RTCrX509Certificate_VerifySignatureSelfSigned RT_MANGLER(RTCrX509Certificate_VerifySignatureSelfSigned) +# define RTCrTafCertPathControls_DecodeAsn1 RT_MANGLER(RTCrTafCertPathControls_DecodeAsn1) +# define RTCrTafTrustAnchorChoice_DecodeAsn1 RT_MANGLER(RTCrTafTrustAnchorChoice_DecodeAsn1) +# define RTCrTafTrustAnchorInfo_DecodeAsn1 RT_MANGLER(RTCrTafTrustAnchorInfo_DecodeAsn1) +# define RTCrTafTrustAnchorList_DecodeAsn1 RT_MANGLER(RTCrTafTrustAnchorList_DecodeAsn1) +# define RTCrTafCertPathControls_Compare RT_MANGLER(RTCrTafCertPathControls_Compare) +# define RTCrTafCertPathControls_Delete RT_MANGLER(RTCrTafCertPathControls_Delete) +# define RTCrTafCertPathControls_Enum RT_MANGLER(RTCrTafCertPathControls_Enum) +# define RTCrTafTrustAnchorChoice_Compare RT_MANGLER(RTCrTafTrustAnchorChoice_Compare) +# define RTCrTafTrustAnchorChoice_Delete RT_MANGLER(RTCrTafTrustAnchorChoice_Delete) +# define RTCrTafTrustAnchorChoice_Enum RT_MANGLER(RTCrTafTrustAnchorChoice_Enum) +# define RTCrTafTrustAnchorInfo_Compare RT_MANGLER(RTCrTafTrustAnchorInfo_Compare) +# define RTCrTafTrustAnchorInfo_Delete RT_MANGLER(RTCrTafTrustAnchorInfo_Delete) +# define RTCrTafTrustAnchorInfo_Enum RT_MANGLER(RTCrTafTrustAnchorInfo_Enum) +# define RTCrTafTrustAnchorList_Compare RT_MANGLER(RTCrTafTrustAnchorList_Compare) +# define RTCrTafTrustAnchorList_Delete RT_MANGLER(RTCrTafTrustAnchorList_Delete) +# define RTCrTafTrustAnchorList_Enum RT_MANGLER(RTCrTafTrustAnchorList_Enum) +# define RTCrTafCertPathControls_Clone RT_MANGLER(RTCrTafCertPathControls_Clone) +# define RTCrTafCertPathControls_Init RT_MANGLER(RTCrTafCertPathControls_Init) +# define RTCrTafTrustAnchorChoice_Clone RT_MANGLER(RTCrTafTrustAnchorChoice_Clone) +# define RTCrTafTrustAnchorChoice_Init RT_MANGLER(RTCrTafTrustAnchorChoice_Init) +# define RTCrTafTrustAnchorInfo_Clone RT_MANGLER(RTCrTafTrustAnchorInfo_Clone) +# define RTCrTafTrustAnchorInfo_Init RT_MANGLER(RTCrTafTrustAnchorInfo_Init) +# define RTCrTafTrustAnchorList_Clone RT_MANGLER(RTCrTafTrustAnchorList_Clone) +# define RTCrTafTrustAnchorList_Init RT_MANGLER(RTCrTafTrustAnchorList_Init) +# define RTCrTafCertPathControls_CheckSanity RT_MANGLER(RTCrTafCertPathControls_CheckSanity) +# define RTCrTafTrustAnchorChoice_CheckSanity RT_MANGLER(RTCrTafTrustAnchorChoice_CheckSanity) +# define RTCrTafTrustAnchorInfo_CheckSanity RT_MANGLER(RTCrTafTrustAnchorInfo_CheckSanity) +# define RTCrTafTrustAnchorList_CheckSanity RT_MANGLER(RTCrTafTrustAnchorList_CheckSanity) +# define RTCrTspAccuracy_CheckSanity RT_MANGLER(RTCrTspAccuracy_CheckSanity) +# define RTCrTspAccuracy_Clone RT_MANGLER(RTCrTspAccuracy_Clone) +# define RTCrTspAccuracy_Compare RT_MANGLER(RTCrTspAccuracy_Compare) +# define RTCrTspAccuracy_DecodeAsn1 RT_MANGLER(RTCrTspAccuracy_DecodeAsn1) +# define RTCrTspAccuracy_Delete RT_MANGLER(RTCrTspAccuracy_Delete) +# define RTCrTspAccuracy_Enum RT_MANGLER(RTCrTspAccuracy_Enum) +# define RTCrTspAccuracy_Init RT_MANGLER(RTCrTspAccuracy_Init) +# define RTCrTspMessageImprint_CheckSanity RT_MANGLER(RTCrTspMessageImprint_CheckSanity) +# define RTCrTspMessageImprint_Clone RT_MANGLER(RTCrTspMessageImprint_Clone) +# define RTCrTspMessageImprint_Compare RT_MANGLER(RTCrTspMessageImprint_Compare) +# define RTCrTspMessageImprint_DecodeAsn1 RT_MANGLER(RTCrTspMessageImprint_DecodeAsn1) +# define RTCrTspMessageImprint_Delete RT_MANGLER(RTCrTspMessageImprint_Delete) +# define RTCrTspMessageImprint_Enum RT_MANGLER(RTCrTspMessageImprint_Enum) +# define RTCrTspMessageImprint_Init RT_MANGLER(RTCrTspMessageImprint_Init) +# define RTCrTspTstInfo_CheckSanity RT_MANGLER(RTCrTspTstInfo_CheckSanity) +# define RTCrTspTstInfo_Clone RT_MANGLER(RTCrTspTstInfo_Clone) +# define RTCrTspTstInfo_Compare RT_MANGLER(RTCrTspTstInfo_Compare) +# define RTCrTspTstInfo_DecodeAsn1 RT_MANGLER(RTCrTspTstInfo_DecodeAsn1) +# define RTCrTspTstInfo_Delete RT_MANGLER(RTCrTspTstInfo_Delete) +# define RTCrTspTstInfo_Enum RT_MANGLER(RTCrTspTstInfo_Enum) +# define RTCrTspTstInfo_Init RT_MANGLER(RTCrTspTstInfo_Init) +# define RTCrCertCtxRelease RT_MANGLER(RTCrCertCtxRelease) +# define RTCrCertCtxRetain RT_MANGLER(RTCrCertCtxRetain) +# define RTCrStoreCertAddEncoded RT_MANGLER(RTCrStoreCertAddEncoded) +# define RTCrStoreCertAddX509 RT_MANGLER(RTCrStoreCertAddX509) +# define RTCrStoreCertByIssuerAndSerialNo RT_MANGLER(RTCrStoreCertByIssuerAndSerialNo) +# define RTCrStoreCertCount RT_MANGLER(RTCrStoreCertCount) +# define RTCrStoreCertFindAll RT_MANGLER(RTCrStoreCertFindAll) +# define RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280 RT_MANGLER(RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280) +# define RTCrStoreCertSearchDestroy RT_MANGLER(RTCrStoreCertSearchDestroy) +# define RTCrStoreCertSearchNext RT_MANGLER(RTCrStoreCertSearchNext) +# define RTCrStoreConvertToOpenSslCertStack RT_MANGLER(RTCrStoreConvertToOpenSslCertStack) +# define RTCrStoreConvertToOpenSslCertStore RT_MANGLER(RTCrStoreConvertToOpenSslCertStore) +# define RTCrStoreRelease RT_MANGLER(RTCrStoreRelease) +# define RTCrStoreRetain RT_MANGLER(RTCrStoreRetain) +# define RTCrStoreCreateInMem RT_MANGLER(RTCrStoreCreateInMem) +# define RTCrStoreCreateInMemEx RT_MANGLER(RTCrStoreCreateInMemEx) +# define RTCrStoreCreateSnapshotById RT_MANGLER(RTCrStoreCreateSnapshotById) +# define RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts RT_MANGLER(RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts) +# define RTCrStoreCertAddFromDir RT_MANGLER(RTCrStoreCertAddFromDir) +# define RTCrStoreCertAddFromFile RT_MANGLER(RTCrStoreCertAddFromFile) +# define RTCrStoreCertAddFromJavaKeyStore RT_MANGLER(RTCrStoreCertAddFromJavaKeyStore) +# define RTCrStoreCertAddFromJavaKeyStoreInMem RT_MANGLER(RTCrStoreCertAddFromJavaKeyStoreInMem) +# define RTCrStoreCertAddFromStore RT_MANGLER(RTCrStoreCertAddFromStore) +# define RTCrStoreCertAddWantedFromDir RT_MANGLER(RTCrStoreCertAddWantedFromDir) +# define RTCrStoreCertAddWantedFromFile RT_MANGLER(RTCrStoreCertAddWantedFromFile) +# define RTCrStoreCertAddWantedFromStore RT_MANGLER(RTCrStoreCertAddWantedFromStore) +# define RTCrStoreCertAddWantedFromFishingExpedition RT_MANGLER(RTCrStoreCertAddWantedFromFishingExpedition) +# define RTCrStoreCertCheckWanted RT_MANGLER(RTCrStoreCertCheckWanted) +# define RTCrStoreCertExportAsPem RT_MANGLER(RTCrStoreCertExportAsPem) +# define RTErrInfoAdd RT_MANGLER(RTErrInfoAdd) +# define RTErrInfoAddF RT_MANGLER(RTErrInfoAddF) +# define RTErrInfoAddV RT_MANGLER(RTErrInfoAddV) +# define RTExprEvalCreate RT_MANGLER(RTExprEvalCreate) +# define RTExprEvalRelease RT_MANGLER(RTExprEvalRelease) +# define RTExprEvalRetain RT_MANGLER(RTExprEvalRetain) +# define RTExprEvalToBool RT_MANGLER(RTExprEvalToBool) +# define RTExprEvalToInteger RT_MANGLER(RTExprEvalToInteger) +# define RTExprEvalToString RT_MANGLER(RTExprEvalToString) +# define RTLdrHashImage RT_MANGLER(RTLdrHashImage) +# define RTLdrOpenWithReader RT_MANGLER(RTLdrOpenWithReader) +# define RTLdrQueryPropEx RT_MANGLER(RTLdrQueryPropEx) +# define RTLdrVerifySignature RT_MANGLER(RTLdrVerifySignature) +# define RTBigNumAdd RT_MANGLER(RTBigNumAdd) +# define RTBigNumAssign RT_MANGLER(RTBigNumAssign) +# define RTBigNumBitWidth RT_MANGLER(RTBigNumBitWidth) +# define RTBigNumByteWidth RT_MANGLER(RTBigNumByteWidth) +# define RTBigNumClone RT_MANGLER(RTBigNumClone) +# define RTBigNumCompare RT_MANGLER(RTBigNumCompare) +# define RTBigNumCompareWithS64 RT_MANGLER(RTBigNumCompareWithS64) +# define RTBigNumCompareWithU64 RT_MANGLER(RTBigNumCompareWithU64) +# define RTBigNumDestroy RT_MANGLER(RTBigNumDestroy) +# define RTBigNumDivide RT_MANGLER(RTBigNumDivide) +# define RTBigNumDivideKnuth RT_MANGLER(RTBigNumDivideKnuth) +# define RTBigNumDivideLong RT_MANGLER(RTBigNumDivideLong) +# define RTBigNumExponentiate RT_MANGLER(RTBigNumExponentiate) +# define RTBigNumInit RT_MANGLER(RTBigNumInit) +# define RTBigNumInitZero RT_MANGLER(RTBigNumInitZero) +# define RTBigNumModExp RT_MANGLER(RTBigNumModExp) +# define RTBigNumModulo RT_MANGLER(RTBigNumModulo) +# define RTBigNumMultiply RT_MANGLER(RTBigNumMultiply) +# define RTBigNumNegate RT_MANGLER(RTBigNumNegate) +# define RTBigNumNegateThis RT_MANGLER(RTBigNumNegateThis) +# define RTBigNumShiftLeft RT_MANGLER(RTBigNumShiftLeft) +# define RTBigNumShiftRight RT_MANGLER(RTBigNumShiftRight) +# define RTBigNumSubtract RT_MANGLER(RTBigNumSubtract) +# define RTBigNumToBytesBigEndian RT_MANGLER(RTBigNumToBytesBigEndian) +# define RTUInt128MulByU64 RT_MANGLER(RTUInt128MulByU64) +# define RTUInt128MulByU64_EndProc RT_MANGLER(RTUInt128MulByU64_EndProc) +# define RTUInt128MulByU64Ex RT_MANGLER(RTUInt128MulByU64Ex) +# define RTUInt128MulByU64Ex_EndProc RT_MANGLER(RTUInt128MulByU64Ex_EndProc) +# define RTUtf16Copy RT_MANGLER(RTUtf16Copy) +# define RTUtf16CopyAscii RT_MANGLER(RTUtf16CopyAscii) +# define RTUtf16CopyEx RT_MANGLER(RTUtf16CopyEx) +# define RTUtf16Cat RT_MANGLER(RTUtf16Cat) +# define RTUtf16CatAscii RT_MANGLER(RTUtf16CatAscii) +# define RTUtf16Chr RT_MANGLER(RTUtf16Chr) +# define RTUtf16End RT_MANGLER(RTUtf16End) +# define RTUtf16ICmpAscii RT_MANGLER(RTUtf16ICmpAscii) +# define RTUtf16NICmpAscii RT_MANGLER(RTUtf16NICmpAscii) +# define RTUtf16NLen RT_MANGLER(RTUtf16NLen) +# define RTUtf16NLenEx RT_MANGLER(RTUtf16NLenEx) +# define RTUtf16PrintHexBytes RT_MANGLER(RTUtf16PrintHexBytes) +# define RTMemSaferAllocZExTag RT_MANGLER(RTMemSaferAllocZExTag) +# define RTMemSaferAllocZTag RT_MANGLER(RTMemSaferAllocZTag) +# define RTMemSaferFree RT_MANGLER(RTMemSaferFree) +# define RTMemSaferGetSize RT_MANGLER(RTMemSaferGetSize) +# define RTMemSaferReallocZExTag RT_MANGLER(RTMemSaferReallocZExTag) +# define RTMemSaferReallocZTag RT_MANGLER(RTMemSaferReallocZTag) +# define RTMemSaferScramble RT_MANGLER(RTMemSaferScramble) +# define RTMemSaferUnscramble RT_MANGLER(RTMemSaferUnscramble) +# define RTErrConvertFromDarwin RT_MANGLER(RTErrConvertFromDarwin) +# define RTErrConvertFromDarwinCOM RT_MANGLER(RTErrConvertFromDarwinCOM) +# define RTErrConvertFromDarwinIO RT_MANGLER(RTErrConvertFromDarwinIO) +# define RTErrConvertFromDarwinKern RT_MANGLER(RTErrConvertFromDarwinKern) +# define RTErrConvertFromDarwin RT_MANGLER(RTErrConvertFromDarwin) +# define RTErrConvertFromDarwinIO RT_MANGLER(RTErrConvertFromDarwinIO) +# define RTErrConvertFromDarwinKern RT_MANGLER(RTErrConvertFromDarwinKern) + +# define RTAsn1SeqOfBitStrings_Erase RT_MANGLER(RTAsn1SeqOfBitStrings_Erase) +# define RTAsn1SeqOfBitStrings_InsertEx RT_MANGLER(RTAsn1SeqOfBitStrings_InsertEx) +# define RTAsn1SeqOfBooleans_Erase RT_MANGLER(RTAsn1SeqOfBooleans_Erase) +# define RTAsn1SeqOfBooleans_InsertEx RT_MANGLER(RTAsn1SeqOfBooleans_InsertEx) +# define RTAsn1SeqOfCores_Erase RT_MANGLER(RTAsn1SeqOfCores_Erase) +# define RTAsn1SeqOfCores_InsertEx RT_MANGLER(RTAsn1SeqOfCores_InsertEx) +# define RTAsn1SeqOfIntegers_Erase RT_MANGLER(RTAsn1SeqOfIntegers_Erase) +# define RTAsn1SeqOfIntegers_InsertEx RT_MANGLER(RTAsn1SeqOfIntegers_InsertEx) +# define RTAsn1SeqOfObjIds_Erase RT_MANGLER(RTAsn1SeqOfObjIds_Erase) +# define RTAsn1SeqOfObjIds_InsertEx RT_MANGLER(RTAsn1SeqOfObjIds_InsertEx) +# define RTAsn1SeqOfOctetStrings_Erase RT_MANGLER(RTAsn1SeqOfOctetStrings_Erase) +# define RTAsn1SeqOfOctetStrings_InsertEx RT_MANGLER(RTAsn1SeqOfOctetStrings_InsertEx) +# define RTAsn1SeqOfStrings_Erase RT_MANGLER(RTAsn1SeqOfStrings_Erase) +# define RTAsn1SeqOfStrings_InsertEx RT_MANGLER(RTAsn1SeqOfStrings_InsertEx) +# define RTAsn1SeqOfTimes_Erase RT_MANGLER(RTAsn1SeqOfTimes_Erase) +# define RTAsn1SeqOfTimes_InsertEx RT_MANGLER(RTAsn1SeqOfTimes_InsertEx) +# define RTAsn1SetOfBitStrings_Erase RT_MANGLER(RTAsn1SetOfBitStrings_Erase) +# define RTAsn1SetOfBitStrings_InsertEx RT_MANGLER(RTAsn1SetOfBitStrings_InsertEx) +# define RTAsn1SetOfBooleans_Erase RT_MANGLER(RTAsn1SetOfBooleans_Erase) +# define RTAsn1SetOfBooleans_InsertEx RT_MANGLER(RTAsn1SetOfBooleans_InsertEx) +# define RTAsn1SetOfCores_Erase RT_MANGLER(RTAsn1SetOfCores_Erase) +# define RTAsn1SetOfCores_InsertEx RT_MANGLER(RTAsn1SetOfCores_InsertEx) +# define RTAsn1SetOfIntegers_Erase RT_MANGLER(RTAsn1SetOfIntegers_Erase) +# define RTAsn1SetOfIntegers_InsertEx RT_MANGLER(RTAsn1SetOfIntegers_InsertEx) +# define RTAsn1SetOfObjIds_Erase RT_MANGLER(RTAsn1SetOfObjIds_Erase) +# define RTAsn1SetOfObjIds_InsertEx RT_MANGLER(RTAsn1SetOfObjIds_InsertEx) +# define RTAsn1SetOfObjIdSeqs_Erase RT_MANGLER(RTAsn1SetOfObjIdSeqs_Erase) +# define RTAsn1SetOfObjIdSeqs_InsertEx RT_MANGLER(RTAsn1SetOfObjIdSeqs_InsertEx) +# define RTAsn1SetOfOctetStrings_Erase RT_MANGLER(RTAsn1SetOfOctetStrings_Erase) +# define RTAsn1SetOfOctetStrings_InsertEx RT_MANGLER(RTAsn1SetOfOctetStrings_InsertEx) +# define RTAsn1SetOfStrings_Erase RT_MANGLER(RTAsn1SetOfStrings_Erase) +# define RTAsn1SetOfStrings_InsertEx RT_MANGLER(RTAsn1SetOfStrings_InsertEx) +# define RTAsn1SetOfTimes_Erase RT_MANGLER(RTAsn1SetOfTimes_Erase) +# define RTAsn1SetOfTimes_InsertEx RT_MANGLER(RTAsn1SetOfTimes_InsertEx) +# define RTCrPkcs7Attributes_Erase RT_MANGLER(RTCrPkcs7Attributes_Erase) +# define RTCrPkcs7Attributes_InsertEx RT_MANGLER(RTCrPkcs7Attributes_InsertEx) +# define RTCrPkcs7SetOfCerts_Erase RT_MANGLER(RTCrPkcs7SetOfCerts_Erase) +# define RTCrPkcs7SetOfCerts_InsertEx RT_MANGLER(RTCrPkcs7SetOfCerts_InsertEx) +# define RTCrPkcs7SetOfContentInfos_Erase RT_MANGLER(RTCrPkcs7SetOfContentInfos_Erase) +# define RTCrPkcs7SetOfContentInfos_InsertEx RT_MANGLER(RTCrPkcs7SetOfContentInfos_InsertEx) +# define RTCrPkcs7SetOfSignedData_Erase RT_MANGLER(RTCrPkcs7SetOfSignedData_Erase) +# define RTCrPkcs7SetOfSignedData_InsertEx RT_MANGLER(RTCrPkcs7SetOfSignedData_InsertEx) +# define RTCrPkcs7SignerInfos_Erase RT_MANGLER(RTCrPkcs7SignerInfos_Erase) +# define RTCrPkcs7SignerInfos_InsertEx RT_MANGLER(RTCrPkcs7SignerInfos_InsertEx) +# define RTCrRsaOtherPrimeInfos_Erase RT_MANGLER(RTCrRsaOtherPrimeInfos_Erase) +# define RTCrRsaOtherPrimeInfos_InsertEx RT_MANGLER(RTCrRsaOtherPrimeInfos_InsertEx) +# define RTCrSpcSerializedObjectAttributes_Erase RT_MANGLER(RTCrSpcSerializedObjectAttributes_Erase) +# define RTCrSpcSerializedObjectAttributes_InsertEx RT_MANGLER(RTCrSpcSerializedObjectAttributes_InsertEx) +# define RTCrTafTrustAnchorList_Erase RT_MANGLER(RTCrTafTrustAnchorList_Erase) +# define RTCrTafTrustAnchorList_InsertEx RT_MANGLER(RTCrTafTrustAnchorList_InsertEx) +# define RTCrX509AlgorithmIdentifiers_Erase RT_MANGLER(RTCrX509AlgorithmIdentifiers_Erase) +# define RTCrX509AlgorithmIdentifiers_InsertEx RT_MANGLER(RTCrX509AlgorithmIdentifiers_InsertEx) +# define RTCrX509AttributeTypeAndValues_Erase RT_MANGLER(RTCrX509AttributeTypeAndValues_Erase) +# define RTCrX509AttributeTypeAndValues_InsertEx RT_MANGLER(RTCrX509AttributeTypeAndValues_InsertEx) +# define RTCrX509CertificatePolicies_Erase RT_MANGLER(RTCrX509CertificatePolicies_Erase) +# define RTCrX509CertificatePolicies_InsertEx RT_MANGLER(RTCrX509CertificatePolicies_InsertEx) +# define RTCrX509Certificates_Erase RT_MANGLER(RTCrX509Certificates_Erase) +# define RTCrX509Certificates_InsertEx RT_MANGLER(RTCrX509Certificates_InsertEx) +# define RTCrX509Extensions_Erase RT_MANGLER(RTCrX509Extensions_Erase) +# define RTCrX509Extensions_InsertEx RT_MANGLER(RTCrX509Extensions_InsertEx) +# define RTCrX509GeneralNames_Erase RT_MANGLER(RTCrX509GeneralNames_Erase) +# define RTCrX509GeneralNames_InsertEx RT_MANGLER(RTCrX509GeneralNames_InsertEx) +# define RTCrX509GeneralSubtrees_Erase RT_MANGLER(RTCrX509GeneralSubtrees_Erase) +# define RTCrX509GeneralSubtrees_InsertEx RT_MANGLER(RTCrX509GeneralSubtrees_InsertEx) +# define RTCrX509Name_Erase RT_MANGLER(RTCrX509Name_Erase) +# define RTCrX509Name_InsertEx RT_MANGLER(RTCrX509Name_InsertEx) +# define RTCrX509PolicyMappings_Erase RT_MANGLER(RTCrX509PolicyMappings_Erase) +# define RTCrX509PolicyMappings_InsertEx RT_MANGLER(RTCrX509PolicyMappings_InsertEx) +# define RTCrX509PolicyQualifierInfos_Erase RT_MANGLER(RTCrX509PolicyQualifierInfos_Erase) +# define RTCrX509PolicyQualifierInfos_InsertEx RT_MANGLER(RTCrX509PolicyQualifierInfos_InsertEx) + + +/* + * Stable variables (alphabetical order): + */ +# define g_apfnRTZlibDeps RT_MANGLER(g_apfnRTZlibDeps) /* os2 win solaris */ +# define g_aRTUniFlagsRanges RT_MANGLER(g_aRTUniFlagsRanges) +# define g_aRTUniLowerRanges RT_MANGLER(g_aRTUniLowerRanges) +# define g_aRTUniUpperRanges RT_MANGLER(g_aRTUniUpperRanges) +# define g_fRTAlignmentChecks RT_MANGLER(g_fRTAlignmentChecks) +# define g_hKrnlDbgInfo RT_MANGLER(g_hKrnlDbgInfo) /* solaris */ +# define g_pStdErr RT_MANGLER(g_pStdErr) +# define g_pStdIn RT_MANGLER(g_pStdIn) +# define g_pStdOut RT_MANGLER(g_pStdOut) +# define g_pfnRTLogAssert RT_MANGLER(g_pfnRTLogAssert) +# define g_pfnRTLogAssertV RT_MANGLER(g_pfnRTLogAssertV) +# define g_pfnRTLogGetDefaultInstance RT_MANGLER(g_pfnRTLogGetDefaultInstance) +# define g_pfnRTLogGetDefaultInstanceEx RT_MANGLER(g_pfnRTLogGetDefaultInstanceEx) +# define g_pfnRTLogLoggerExV RT_MANGLER(g_pfnRTLogLoggerExV) +# define g_pfnRTLogRelGetDefaultInstance RT_MANGLER(g_pfnRTLogRelGetDefaultInstance) +# define g_pfnRTLogRelGetDefaultInstanceEx RT_MANGLER(g_pfnRTLogRelGetDefaultInstanceEx) +# define g_pszRTAssertExpr RT_MANGLER(g_pszRTAssertExpr) +# define g_pszRTAssertFile RT_MANGLER(g_pszRTAssertFile) +# define g_pszRTAssertFunction RT_MANGLER(g_pszRTAssertFunction) +# define g_szRTAssertMsg1 RT_MANGLER(g_szRTAssertMsg1) +# define g_szRTAssertMsg2 RT_MANGLER(g_szRTAssertMsg2) +# define g_u32RTAssertLine RT_MANGLER(g_u32RTAssertLine) + +/* sort/merge into the above later: */ +# define g_RTAsn1Time_Vtable RT_MANGLER(g_RTAsn1Time_Vtable) +# define g_RTAsn1String_Vtable RT_MANGLER(g_RTAsn1String_Vtable) +# define g_RTAsn1OctetString_Vtable RT_MANGLER(g_RTAsn1OctetString_Vtable) +# define g_RTAsn1ObjId_Vtable RT_MANGLER(g_RTAsn1ObjId_Vtable) +# define g_RTAsn1Null_Vtable RT_MANGLER(g_RTAsn1Null_Vtable) +# define g_RTAsn1Integer_Vtable RT_MANGLER(g_RTAsn1Integer_Vtable) +# define g_RTAsn1Core_Vtable RT_MANGLER(g_RTAsn1Core_Vtable) +# define g_RTAsn1Boolean_Vtable RT_MANGLER(g_RTAsn1Boolean_Vtable) +# define g_RTAsn1BitString_Vtable RT_MANGLER(g_RTAsn1BitString_Vtable) +# define g_RTAsn1DefaultAllocator RT_MANGLER(g_RTAsn1DefaultAllocator) +# define g_RTAsn1EFenceAllocator RT_MANGLER(g_RTAsn1EFenceAllocator) +# define g_RTAsn1SaferAllocator RT_MANGLER(g_RTAsn1SaferAllocator) +# define g_aRTCrPkcs7Markers RT_MANGLER(g_aRTCrPkcs7Markers) +# define g_cRTCrPkcs7Markers RT_MANGLER(g_cRTCrPkcs7Markers) +# define g_aRTCrX509CertificateMarkers RT_MANGLER(g_aRTCrX509CertificateMarkers) +# define g_cRTCrX509CertificateMarkers RT_MANGLER(g_cRTCrX509CertificateMarkers) +# define g_aRTCrKeyPublicMarkers RT_MANGLER(g_aRTCrKeyPublicMarkers) +# define g_cRTCrKeyPublicMarkers RT_MANGLER(g_cRTCrKeyPublicMarkers) +# define g_aRTCrKeyPrivateMarkers RT_MANGLER(g_aRTCrKeyPrivateMarkers) +# define g_cRTCrKeyPrivateMarkers RT_MANGLER(g_cRTCrKeyPrivateMarkers) +# define g_aRTCrKeyAllMarkers RT_MANGLER(g_aRTCrKeyAllMarkers) +# define g_cRTCrKeyAllMarkers RT_MANGLER(g_cRTCrKeyAllMarkers) +# define g_acRTThreadTypeStats RT_MANGLER(g_acRTThreadTypeStats) /* internal */ +# define g_RTIoQueueStdFileProv RT_MANGLER(g_RTIoQueueStdFileProv) /* internal */ +# define g_RTIoQueueAioFileProv RT_MANGLER(g_RTIoQueueAioFileProv) /* internal */ +# define g_RTIoQueueLnxIoURingProv RT_MANGLER(g_RTIoQueueLnxIoURingProv) /* internal */ + +#if 0 /* Disabled for now as I'm not sure the assmbler supports mangling yet. */ +# define g_abRTZeroPage RT_MANGLER(g_abRTZeroPage) +# define g_abRTZero4K RT_MANGLER(g_abRTZero4K) +# define g_abRTZero8K RT_MANGLER(g_abRTZero8K) +# define g_abRTZero16K RT_MANGLER(g_abRTZero16K) +# define g_abRTZero32K RT_MANGLER(g_abRTZero32K) +# define g_abRTZero64K RT_MANGLER(g_abRTZero64K) +#endif + + +/* + * Unstable functions (alphabetical order): + */ +/** @todo the list is incomplete! See the .def files + libraries. */ + + +/* + * Unstable variables (alphabetical order): + */ +/* none */ + +#endif /* !DOXYGEN_RUNNING */ + +#endif /* !IPRT_INCLUDED_mangling_h */ + diff --git a/include/iprt/manifest.h b/include/iprt/manifest.h new file mode 100644 index 00000000..ececd07f --- /dev/null +++ b/include/iprt/manifest.h @@ -0,0 +1,560 @@ +/** @file + * IPRT - Manifest file handling. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_manifest_h +#define IPRT_INCLUDED_manifest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_manifest RTManifest - Manifest file creation and checking + * @ingroup grp_rt + * @{ + */ + +/** @name Manifest attribute types. + * The types can be ORed together to form a set. + * @{ */ +/** For use with other attributes. Representation unknown. */ +#define RTMANIFEST_ATTR_UNKNOWN 0 +/** The size of the content. Represented as a decimal number. */ +#define RTMANIFEST_ATTR_SIZE RT_BIT_32(0) +/** The MD5 of the content. Represented as a hex string. */ +#define RTMANIFEST_ATTR_MD5 RT_BIT_32(1) +/** The SHA-1 of the content. Represented as a hex string. */ +#define RTMANIFEST_ATTR_SHA1 RT_BIT_32(2) +/** The SHA-256 of the content. Represented as a hex string. */ +#define RTMANIFEST_ATTR_SHA256 RT_BIT_32(3) +/** The SHA-512 of the content. Represented as a hex string. */ +#define RTMANIFEST_ATTR_SHA512 RT_BIT_32(4) +/** The end of the valid values. */ +#define RTMANIFEST_ATTR_END RT_BIT_32(5) +/** Wildcard for use in queries. */ +#define RTMANIFEST_ATTR_ANY UINT32_C(0xffffffff) +/** @} */ + + +/** + * Creates an empty manifest. + * + * @returns IPRT status code. + * @param fFlags Flags, MBZ. + * @param phManifest Where to return the handle to the manifest. + */ +RTDECL(int) RTManifestCreate(uint32_t fFlags, PRTMANIFEST phManifest); + +/** + * Retains a reference to the manifest handle. + * + * @returns The new reference count, UINT32_MAX if the handle is invalid. + * @param hManifest The handle to retain. + */ +RTDECL(uint32_t) RTManifestRetain(RTMANIFEST hManifest); + +/** + * Releases a reference to the manifest handle. + * + * @returns The new reference count, 0 if free. UINT32_MAX is returned if the + * handle is invalid. + * @param hManifest The handle to release. + * NIL is quietly ignored (returns 0). + */ +RTDECL(uint32_t) RTManifestRelease(RTMANIFEST hManifest); + +/** + * Creates a duplicate of the specified manifest. + * + * @returns IPRT status code + * @param hManifestSrc The manifest to clone. + * @param phManifestDst Where to store the handle to the duplicate. + */ +RTDECL(int) RTManifestDup(RTMANIFEST hManifestSrc, PRTMANIFEST phManifestDst); + +/** + * Compares two manifests for equality. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param hManifest1 The first manifest. + * @param hManifest2 The second manifest. + * @param papszIgnoreEntries Entries to ignore. Ends with a NULL entry. + * @param papszIgnoreAttrs Attributes to ignore. Ends with a NULL entry. + * @param fFlags A combination of RTMANIFEST_EQUALS_XXX values. + * @param pszError Where to store the name of the mismatching + * entry, or as much of the name as there is room + * for. This is always set. Optional. + * @param cbError The size of the buffer pointed to by @a + * pszError. + */ +RTDECL(int) RTManifestEqualsEx(RTMANIFEST hManifest1, RTMANIFEST hManifest2, const char * const *papszIgnoreEntries, + const char * const *papszIgnoreAttrs, uint32_t fFlags, char *pszError, size_t cbError); + +/** @defgroup RTMANIFEST_EQUALS_XXX RTManifestEqualsEx flags + * @{ */ +/** Ignore missing attributes if there is one or more to compare. */ +#define RTMANIFEST_EQUALS_IGN_MISSING_ATTRS RT_BIT_32(0) +/** Ignore attributes missing in the 1st manifest. + * @todo implement this */ +#define RTMANIFEST_EQUALS_IGN_MISSING_ATTRS_1ST RT_BIT_32(1) +/** Ignore missing entries in the 2nd manifest. */ +#define RTMANIFEST_EQUALS_IGN_MISSING_ENTRIES_2ND RT_BIT_32(2) +/** Mask of valid flags. */ +#define RTMANIFEST_EQUALS_VALID_MASK UINT32_C(0x00000005) +/** @} */ + +/** + * Compares two manifests for equality. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param hManifest1 The first manifest. + * @param hManifest2 The second manifest. + */ +RTDECL(int) RTManifestEquals(RTMANIFEST hManifest1, RTMANIFEST hManifest2); + +/** + * + * @returns IPRT status code. + * @param hManifest Handle to the manifest. + * @param fEntriesOnly Whether to only gather attribute types from the + * entries (@c true), or also include the manifest + * attributes (@c false). + * @param pfTypes Where to return the attributes. + */ +RTDECL(int) RTManifestQueryAllAttrTypes(RTMANIFEST hManifest, bool fEntriesOnly, uint32_t *pfTypes); + +/** + * Sets a manifest attribute. + * + * @returns IPRT status code. + * @param hManifest The manifest handle. + * @param pszAttr The attribute name, if NULL it will be termined from @a + * fType gives it. If this already exists, its value will + * be replaced. + * @param pszValue The value string. + * @param fType The attribute type. If not know, pass + * RTMANIFEST_ATTR_UNKNOWN with a valid attribute + * name string (@a pszAttr). + */ +RTDECL(int) RTManifestSetAttr(RTMANIFEST hManifest, const char *pszAttr, const char *pszValue, uint32_t fType); + +/** + * Unsets (removes) a manifest attribute if it exists. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if not found. + * + * @param hManifest The manifest handle. + * @param pszAttr The attribute name. + */ +RTDECL(int) RTManifestUnsetAttr(RTMANIFEST hManifest, const char *pszAttr); + +/** + * Query a manifest attribute. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the value buffer is too small. The @a + * pszValue buffer will not be modified. + * @retval VERR_MANIFEST_ATTR_NOT_FOUND + * @retval VERR_MANIFEST_ATTR_TYPE_NOT_FOUND + * @retval VERR_MANIFEST_ATTR_TYPE_MISMATCH + * + * @param hManifest The manifest handle. + * @param pszAttr The attribute name. If NULL, it will be + * selected by @a fType alone. + * @param fType The attribute types the entry should match. Pass + * Pass RTMANIFEST_ATTR_ANY match any. If more + * than one is given, the first matching one is + * returned. + * @param pszValue Where to return value. + * @param cbValue The size of the buffer @a pszValue points to. + * @param pfType Where to return the attribute type value. + */ +RTDECL(int) RTManifestQueryAttr(RTMANIFEST hManifest, const char *pszAttr, uint32_t fType, + char *pszValue, size_t cbValue, uint32_t *pfType); + +/** + * Sets an attribute of a manifest entry. + * + * @returns IPRT status code. + * @param hManifest The manifest handle. + * @param pszEntry The entry name. This will automatically be + * added if there was no previous call to + * RTManifestEntryAdd for this name. See + * RTManifestEntryAdd for the entry name rules. + * @param pszAttr The attribute name, if NULL it will be termined from @a + * fType gives it. If this already exists, its value will + * be replaced. + * @param pszValue The value string. + * @param fType The attribute type. If not know, pass + * RTMANIFEST_ATTR_UNKNOWN with a valid attribute + * name string (@a pszAttr). + */ +RTDECL(int) RTManifestEntrySetAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr, + const char *pszValue, uint32_t fType); + +/** + * Unsets (removes) an attribute of a manifest entry if they both exist. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if not found. + * + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + * @param pszAttr The attribute name. + */ +RTDECL(int) RTManifestEntryUnsetAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr); + +/** + * Query a manifest entry attribute. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the value buffer is too small. The @a + * pszValue buffer will not be modified. + * @retval VERR_NOT_FOUND if the entry was not found. + * @retval VERR_MANIFEST_ATTR_NOT_FOUND + * @retval VERR_MANIFEST_ATTR_TYPE_NOT_FOUND + * @retval VERR_MANIFEST_ATTR_TYPE_MISMATCH + * + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + * @param pszAttr The attribute name. If NULL, it will be + * selected by @a fType alone. + * @param fType The attribute types the entry should match. Pass + * Pass RTMANIFEST_ATTR_ANY match any. If more + * than one is given, the first matching one is + * returned. + * @param pszValue Where to return value. + * @param cbValue The size of the buffer @a pszValue points to. + * @param pfType Where to return the attribute type value. + */ +RTDECL(int) RTManifestEntryQueryAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr, uint32_t fType, + char *pszValue, size_t cbValue, uint32_t *pfType); + +/** + * Adds a new entry to a manifest. + * + * The entry name rules: + * - The entry name can contain any character defined by unicode, except + * control characters, ':', '(' and ')'. The exceptions are mainly there + * because of uncertainty around how various formats handles these. + * - It is considered case sensitive. + * - Forward (unix) and backward (dos) slashes are considered path + * separators and converted to forward slashes. + * + * @returns IPRT status code. + * @retval VWRN_ALREADY_EXISTS if the entry already exists. + * + * @param hManifest The manifest handle. + * @param pszEntry The entry name (UTF-8). + * + * @remarks Some manifest formats will not be able to store an entry without + * any attributes. So, this is just here in case it comes in handy + * when dealing with formats which can. + */ +RTDECL(int) RTManifestEntryAdd(RTMANIFEST hManifest, const char *pszEntry); + +/** + * Removes an entry. + * + * @returns IPRT status code. + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + */ +RTDECL(int) RTManifestEntryRemove(RTMANIFEST hManifest, const char *pszEntry); + +/** + * Add an entry for an I/O stream using a passthru stream. + * + * The passthru I/O stream will hash all the data read from or written to the + * stream and automatically add an entry to the manifest with the desired + * attributes when it is released. Alternatively one can call + * RTManifestPtIosAddEntryNow() to have more control over exactly when this + * action is performed and which status it yields. + * + * @returns IPRT status code. + * @param hManifest The manifest to add the entry to. + * @param hVfsIos The I/O stream to pass thru to/from. + * @param pszEntry The entry name. + * @param fAttrs The attributes to create for this stream. + * @param fReadOrWrite Whether it's a read or write I/O stream. + * @param phVfsIosPassthru Where to return the new handle. + */ +RTDECL(int) RTManifestEntryAddPassthruIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, + uint32_t fAttrs, bool fReadOrWrite, PRTVFSIOSTREAM phVfsIosPassthru); + +/** + * Adds the entry to the manifest right now. + * + * @returns IPRT status code. + * @param hVfsPtIos The manifest passthru I/O stream returned by + * RTManifestEntryAddPassthruIoStream(). + */ +RTDECL(int) RTManifestPtIosAddEntryNow(RTVFSIOSTREAM hVfsPtIos); + +/** + * Checks if the give I/O stream is a manifest passthru instance or not. + * + * @returns true if it's a manifest passthru I/O stream, false if not. + * @param hVfsPtIos Possible the manifest passthru I/O stream handle. + */ +RTDECL(bool) RTManifestPtIosIsInstanceOf(RTVFSIOSTREAM hVfsPtIos); + +/** + * Adds an entry for a file with the specified set of attributes. + * + * @returns IPRT status code. + * + * @param hManifest The manifest handle. + * @param hVfsIos The I/O stream handle of the entry. This will + * be processed to its end on successful return. + * (Must be positioned at the start to get + * the expected results.) + * @param pszEntry The entry name. + * @param fAttrs The attributes to create for this stream. See + * RTMANIFEST_ATTR_XXX. + */ +RTDECL(int) RTManifestEntryAddIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, uint32_t fAttrs); + +/** + * Checks if there is a manifest entry by the given name. + * + * @returns true if there is, false if not or if the handle is invalid. + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + */ +RTDECL(bool) RTManifestEntryExists(RTMANIFEST hManifest, const char *pszEntry); + +/** + * Reads in a "standard" manifest. + * + * This reads the format used by OVF, the distinfo in FreeBSD ports, and + * others. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest where to add the + * manifest that's read in. + * @param hVfsIos The I/O stream to read the manifest from. + */ +RTDECL(int) RTManifestReadStandard(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos); + +/** + * Reads in a "standard" manifest. + * + * This reads the format used by OVF, the distinfo in FreeBSD ports, and + * others. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest where to add the + * manifest that's read in. + * @param hVfsIos The I/O stream to read the manifest from. + * @param pszErr Where to return extended error info on failure. + * Optional. + * @param cbErr The size of the buffer @a pszErr points to. + */ +RTDECL(int) RTManifestReadStandardEx(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, char *pszErr, size_t cbErr); + +/** + * Reads in a "standard" manifest from the specified file. + * + * This reads the format used by OVF, the distinfo in FreeBSD ports, and + * others. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest where to add the + * manifest that's read in. + * @param pszFilename The name of the file to read in. + */ +RTDECL(int) RTManifestReadStandardFromFile(RTMANIFEST hManifest, const char *pszFilename); + +/** + * Writes a "standard" manifest. + * + * This writes the format used by OVF, the distinfo in FreeBSD ports, and + * others. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest to write. + * @param hVfsIos The I/O stream to read the manifest from. + */ +RTDECL(int) RTManifestWriteStandard(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos); + +/** + * Writes a "standard" manifest to the specified file. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest to write. + * @param pszFilename The name of the file. + */ +RTDECL(int) RTManifestWriteStandardToFile(RTMANIFEST hManifest, const char *pszFilename); + + + + + +/** + * Input structure for RTManifestVerify() which contains the filename & the + * SHA1/SHA256 digest. + */ +typedef struct RTMANIFESTTEST +{ + /** The filename. */ + const char *pszTestFile; + /** The SHA1/SHA256 digest of the file. */ + const char *pszTestDigest; +} RTMANIFESTTEST; +/** Pointer to the input structure. */ +typedef RTMANIFESTTEST* PRTMANIFESTTEST; + + +/** + * Verify the given SHA1 digests against the entries in the manifest file. + * + * Please note that not only the various digest have to match, but the + * filenames as well. If there are more or even less files listed in the + * manifest file than provided by paTests, VERR_MANIFEST_FILE_MISMATCH will be + * returned. + * + * @returns iprt status code. + * + * @param pszManifestFile Filename of the manifest file to verify. + * @param paTests Array of files & SHA1 sums. + * @param cTests Number of entries in paTests. + * @param piFailed A index to paTests in the + * VERR_MANIFEST_DIGEST_MISMATCH error case + * (optional). + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestVerify(const char *pszManifestFile, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed); + +/** + * This is analogous to function RTManifestVerify(), but calculates the SHA1 + * sums of the given files itself. + * + * @returns iprt status code. + * + * @param pszManifestFile Filename of the manifest file to verify. + * @param papszFiles Array of files to check SHA1 sums. + * @param cFiles Number of entries in papszFiles. + * @param piFailed A index to papszFiles in the + * VERR_MANIFEST_DIGEST_MISMATCH error case + * (optional). + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestVerifyFiles(const char *pszManifestFile, const char * const *papszFiles, size_t cFiles, size_t *piFailed, + PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Creates a manifest file for a set of files. The manifest file contains SHA1 + * sums of every provided file and could be used to verify the data integrity + * of them. + * + * @returns iprt status code. + * + * @param pszManifestFile Filename of the manifest file to create. + * @param enmDigestType The digest type (RTDIGESTTYPE_*) + * @param papszFiles Array of files to create SHA1 sums for. + * @param cFiles Number of entries in papszFiles. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestWriteFiles(const char *pszManifestFile, RTDIGESTTYPE enmDigestType, + const char * const *papszFiles, size_t cFiles, + PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Queries the first digest type found in the given manifest. + * + * @returns iprt status code. + * + * @param pvBuf Pointer to memory buffer of the manifest file. + * @param cbSize Size of the memory buffer. + * @param penmDigestType Where to return the first digest type found in + * the manifest. + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestVerifyDigestType(void const *pvBuf, size_t cbSize, RTDIGESTTYPE *penmDigestType); + +/** + * Verify the given SHA1 digests against the entries in the manifest file in + * memory. + * + * @returns iprt status code. + * + * @param pvBuf Pointer to memory buffer of the manifest file. + * @param cbSize Size of the memory buffer. + * @param paTests Array of file names and digests. + * @param cTests Number of entries in paTests. + * @param piFailed A index to paTests in the + * VERR_MANIFEST_DIGEST_MISMATCH error case + * (optional). + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed); + +/** + * Creates a manifest file in memory for a set of files. The manifest file + * contains SHA1 sums of every provided file and could be used to verify the + * data integrity of them. + * + * @returns iprt status code. + * + * @param ppvBuf Pointer to resulting memory buffer. + * @param pcbSize Pointer for the size of the memory buffer. + * @param enmDigestType Which type of digest ("SHA1", "SHA256", ...) + * @param paFiles Array of file names and digests. + * @param cFiles Number of entries in paFiles. + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestWriteFilesBuf(void **ppvBuf, size_t *pcbSize, RTDIGESTTYPE enmDigestType, PRTMANIFESTTEST paFiles, size_t cFiles); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_manifest_h */ + diff --git a/include/iprt/md2.h b/include/iprt/md2.h new file mode 100644 index 00000000..0b408424 --- /dev/null +++ b/include/iprt/md2.h @@ -0,0 +1,139 @@ +/** @file + * IPRT - Message-Digest Algorithm 2. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_md2_h +#define IPRT_INCLUDED_md2_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_md2 RTMd2 - Message-Digest algorithm 2 + * @ingroup grp_rt + * @{ + */ + +/** Size of a MD2 hash. */ +#define RTMD2_HASH_SIZE 16 +/** The length of a MD2 digest string. The terminator is not included. */ +#define RTMD2_DIGEST_LEN 32 + +/** + * MD2 hash algorithm context. + */ +typedef union RTMD2CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[4 + 16 + 16*4 + 16*4]; +#ifdef RT_MD2_PRIVATE_CONTEXT + MD2_CTX Private; +#endif +#ifdef RT_MD2_PRIVATE_ALT_CONTEXT + RTMD2ALTPRIVATECTX AltPrivate; +#endif +} RTMD2CONTEXT; + +/** Pointer to MD2 hash algorithm context. */ +typedef RTMD2CONTEXT *PRTMD2CONTEXT; + + +/** + * Compute the MD2 hash of the data. + * + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + * @param pabDigest Where to store the hash. + * (What's passed is a pointer to the caller's buffer.) + */ +RTDECL(void) RTMd2(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD2_HASH_SIZE]); + +/** + * Initialize MD2 context. + * + * @param pCtx Pointer to the MD2 context to initialize. + */ +RTDECL(void) RTMd2Init(PRTMD2CONTEXT pCtx); + +/** + * Feed data into the MD2 computation. + * + * @param pCtx Pointer to the MD2 context. + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + */ +RTDECL(void) RTMd2Update(PRTMD2CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the MD2 hash of the data. + * + * @param pCtx Pointer to the MD2 context. + * @param pabDigest Where to store the hash. (What's passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTMd2Final(PRTMD2CONTEXT pCtx, uint8_t pabDigest[RTMD2_HASH_SIZE]); + +/** + * Converts a MD2 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabDigest The binary digest returned by RTMd2Final or RTMd2. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTMD2_STRING_LEN + 1 bytes. + */ +RTDECL(int) RTMd2ToString(uint8_t const pabDigest[RTMD2_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a MD2 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabDigest Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTMd2FromString(char const *pszDigest, uint8_t pabDigest[RTMD2_HASH_SIZE]); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_md2_h */ + diff --git a/include/iprt/md4.h b/include/iprt/md4.h new file mode 100644 index 00000000..a95d2e25 --- /dev/null +++ b/include/iprt/md4.h @@ -0,0 +1,142 @@ +/** @file + * IPRT - Message-Digest Algorithm 4. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_md4_h +#define IPRT_INCLUDED_md4_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_md4 RTMd4 - Message-Digest algorithm 4 + * @ingroup grp_rt + * + * @note This is just for backwards compatibility and completeness. + * + * @{ + */ + +/** Size of a MD4 hash. */ +#define RTMD4_HASH_SIZE 16 +/** The length of a MD4 digest string. The terminator is not included. */ +#define RTMD4_DIGEST_LEN 32 + +/** + * MD4 hash algorithm context. + */ +typedef union RTMD4CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[22*4 + 64 + 8]; +#ifdef RT_MD4_PRIVATE_CONTEXT + MD4_CTX Private; +#endif +#ifdef RT_MD4_PRIVATE_ALT_CONTEXT + RTMD4ALTPRIVATECTX AltPrivate; +#endif +} RTMD4CONTEXT; + +/** Pointer to MD4 hash algorithm context. */ +typedef RTMD4CONTEXT *PRTMD4CONTEXT; + + +/** + * Compute the MD4 hash of the data. + * + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + * @param pabDigest Where to store the hash. + * (What's passed is a pointer to the caller's buffer.) + */ +RTDECL(void) RTMd4(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD4_HASH_SIZE]); + +/** + * Initialize MD4 context. + * + * @param pCtx Pointer to the MD4 context to initialize. + */ +RTDECL(void) RTMd4Init(PRTMD4CONTEXT pCtx); + +/** + * Feed data into the MD4 computation. + * + * @param pCtx Pointer to the MD4 context. + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + */ +RTDECL(void) RTMd4Update(PRTMD4CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the MD4 hash of the data. + * + * @param pCtx Pointer to the MD4 context. + * @param pabDigest Where to store the hash. (What's passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTMd4Final(PRTMD4CONTEXT pCtx, uint8_t pabDigest[RTMD4_HASH_SIZE]); + +/** + * Converts a MD4 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabDigest The binary digest returned by RTMd4Final or RTMd4. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTMD4_STRING_LEN + 1 bytes. + */ +RTDECL(int) RTMd4ToString(uint8_t const pabDigest[RTMD4_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a MD4 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabDigest Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTMd4FromString(char const *pszDigest, uint8_t pabDigest[RTMD4_HASH_SIZE]); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_md4_h */ + diff --git a/include/iprt/md5.h b/include/iprt/md5.h new file mode 100644 index 00000000..a89ab8ac --- /dev/null +++ b/include/iprt/md5.h @@ -0,0 +1,148 @@ +/** @file + * IPRT - Message-Digest algorithm 5. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_md5_h +#define IPRT_INCLUDED_md5_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_md5 RTMd5 - Message-Digest algorithm 5 + * @ingroup grp_rt + * @{ + */ + +/** Size of a MD5 hash. */ +#define RTMD5_HASH_SIZE 16 +/** @deprecated Use RTMD5_HASH_SIZE. */ +#define RTMD5HASHSIZE RTMD5_HASH_SIZE +/** The length of a MD5 digest string. The terminator is not included. */ +#define RTMD5_DIGEST_LEN 32 +/** Size of a MD5 hash. + * @deprecated Use RTMD5_DIGEST_LEN */ +#define RTMD5_STRING_LEN RTMD5_DIGEST_LEN + +/** + * MD5 hash algorithm context. + */ +typedef union RTMD5CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[(4 + 6 + 16 + 1) * sizeof(uint32_t)]; + /** Context used by md5-alt.cpp. */ + struct + { + uint32_t in[16]; + uint32_t buf[4]; + uint32_t bits[2]; + } AltPrivate; +#ifdef RT_MD5_OPENSSL_PRIVATE_CONTEXT + /** Context used by md5-openssl.cpp. */ + MD5_CTX OsslPrivate; +#endif +} RTMD5CONTEXT; +/** Pointer to MD5 hash algorithm context. */ +typedef RTMD5CONTEXT *PRTMD5CONTEXT; + +RT_C_DECLS_BEGIN + +/** + * Compute the MD5 hash of the data. + * + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + * @param pabDigest Where to store the hash. + * (What's passed is a pointer to the caller's buffer.) + */ +RTDECL(void) RTMd5(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD5HASHSIZE]); + +/** + * Initialize MD5 context. + * + * @param pCtx Pointer to the MD5 context to initialize. + */ +RTDECL(void) RTMd5Init(PRTMD5CONTEXT pCtx); + +/** + * Feed data into the MD5 computation. + * + * @param pCtx Pointer to the MD5 context. + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + */ +RTDECL(void) RTMd5Update(PRTMD5CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the MD5 hash of the data. + * + * @param pabDigest Where to store the hash. + * (What's passed is a pointer to the caller's buffer.) + * @param pCtx Pointer to the MD5 context. + */ +RTDECL(void) RTMd5Final(uint8_t pabDigest[RTMD5HASHSIZE], PRTMD5CONTEXT pCtx); + +/** + * Converts a MD5 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabDigest The binary digest returned by RTMd5Final or RTMd5. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTMD5_STRING_LEN + 1 bytes. + */ +RTDECL(int) RTMd5ToString(uint8_t const pabDigest[RTMD5_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a MD5 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabDigest Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTMd5FromString(char const *pszDigest, uint8_t pabDigest[RTMD5_HASH_SIZE]); + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_md5_h */ + diff --git a/include/iprt/mem.h b/include/iprt/mem.h new file mode 100644 index 00000000..9cfbbc20 --- /dev/null +++ b/include/iprt/mem.h @@ -0,0 +1,1239 @@ +/** @file + * IPRT - Memory Management and Manipulation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_mem_h +#define IPRT_INCLUDED_mem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#include + +#ifdef IPRT_WITH_GCC_SANITIZER +# include +#endif + +#ifdef IN_RC +# error "There are no RTMem APIs available Guest Context!" +#endif + + +/** @defgroup grp_rt_mem RTMem - Memory Management and Manipulation + * @ingroup grp_rt + * @{ + */ + +RT_C_DECLS_BEGIN + +/** @def RTMEM_ALIGNMENT + * The alignment of the memory blocks returned by RTMemAlloc(), RTMemAllocZ(), + * RTMemRealloc(), RTMemTmpAlloc() and RTMemTmpAllocZ() for allocations greater + * than RTMEM_ALIGNMENT. + * + * @note This alignment is not forced if the electric fence is active! + */ +#if defined(RT_OS_OS2) +# define RTMEM_ALIGNMENT 4 +#else +# define RTMEM_ALIGNMENT 8 +#endif + +/** @def RTMEM_TAG + * The default allocation tag used by the RTMem allocation APIs. + * + * When not defined before the inclusion of iprt/mem.h or iprt/memobj.h, this + * will default to the pointer to the current file name. The memory API will + * make of use of this as pointer to a volatile but read-only string. + * The alternative tag includes the line number for a more-detailed analysis. + */ +#ifndef RTMEM_TAG +# if 0 +# define RTMEM_TAG (__FILE__ ":" RT_XSTR(__LINE__)) +# else +# define RTMEM_TAG (__FILE__) +# endif +#endif + + +/** @name Allocate temporary memory. + * @{ */ +/** + * Allocates temporary memory with default tag. + * + * Temporary memory blocks are used for not too large memory blocks which + * are believed not to stick around for too long. Using this API instead + * of RTMemAlloc() not only gives the heap manager room for optimization + * but makes the code easier to read. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + */ +#define RTMemTmpAlloc(cb) RTMemTmpAllocTag((cb), RTMEM_TAG) + +/** + * Allocates temporary memory with custom tag. + * + * Temporary memory blocks are used for not too large memory blocks which + * are believed not to stick around for too long. Using this API instead + * of RTMemAlloc() not only gives the heap manager room for optimization + * but makes the code easier to read. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocates zero'd temporary memory with default tag. + * + * Same as RTMemTmpAlloc() but the memory will be zero'd. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + */ +#define RTMemTmpAllocZ(cb) RTMemTmpAllocZTag((cb), RTMEM_TAG) + +/** + * Allocates zero'd temporary memory with custom tag. + * + * Same as RTMemTmpAlloc() but the memory will be zero'd. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemTmpAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Free temporary memory. + * + * @param pv Pointer to memory block. + */ +RTDECL(void) RTMemTmpFree(void *pv) RT_NO_THROW_PROTO; + +/** + * Clear and free temporary memory. + * + * This is strongly recommended when the memory being freed holds untrusted data + * to help counter heap spraying. + * + * @param pv Pointer to memory block. + * @param cb Size of the memory block. + * + * @note The memory isn't always filled with zeros, it can be set to a + * different value in some configurations. + */ +RTDECL(void) RTMemTmpFreeZ(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** @} */ + + +/** + * Allocates memory with default tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + */ +#define RTMemAlloc(cb) RTMemAllocTag((cb), RTMEM_TAG) + +/** + * Allocates memory with custom tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocates zero'd memory with default tag. + * + * Instead of memset(pv, 0, sizeof()) use this when you want zero'd + * memory. This keeps the code smaller and the heap can skip the memset + * in about 0.42% of calls :-). + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocated. + */ +#define RTMemAllocZ(cb) RTMemAllocZTag((cb), RTMEM_TAG) + +/** + * Allocates zero'd memory with custom tag. + * + * Instead of memset(pv, 0, sizeof()) use this when you want zero'd + * memory. This keeps the code smaller and the heap can skip the memset + * in about 0.42% of calls :-). + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocated. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Wrapper around RTMemAlloc for automatically aligning variable sized + * allocations so that the various electric fence heaps works correctly. + * + * @returns See RTMemAlloc. + * @param cbUnaligned The unaligned size. + */ +#define RTMemAllocVar(cbUnaligned) RTMemAllocVarTag((cbUnaligned), RTMEM_TAG) + +/** + * Wrapper around RTMemAllocTag for automatically aligning variable sized + * allocations so that the various electric fence heaps works correctly. + * + * @returns See RTMemAlloc. + * @param cbUnaligned The unaligned size. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemAllocVarTag(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Wrapper around RTMemAllocZ for automatically aligning variable sized + * allocations so that the various electric fence heaps works correctly. + * + * @returns See RTMemAllocZ. + * @param cbUnaligned The unaligned size. + */ +#define RTMemAllocZVar(cbUnaligned) RTMemAllocZVarTag((cbUnaligned), RTMEM_TAG) + +/** + * Wrapper around RTMemAllocZTag for automatically aligning variable sized + * allocations so that the various electric fence heaps works correctly. + * + * @returns See RTMemAllocZ. + * @param cbUnaligned The unaligned size. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemAllocZVarTag(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Duplicates a chunk of memory into a new heap block (default tag). + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cb The amount of memory to duplicate. + */ +#define RTMemDup(pvSrc, cb) RTMemDupTag((pvSrc), (cb), RTMEM_TAG) + +/** + * Duplicates a chunk of memory into a new heap block (custom tag). + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cb The amount of memory to duplicate. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemDupTag(const void *pvSrc, size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Duplicates a chunk of memory into a new heap block with some additional + * zeroed memory (default tag). + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cbSrc The amount of memory to duplicate. + * @param cbExtra The amount of extra memory to allocate and zero. + */ +#define RTMemDupEx(pvSrc, cbSrc, cbExtra) RTMemDupExTag((pvSrc), (cbSrc), (cbExtra), RTMEM_TAG) + +/** + * Duplicates a chunk of memory into a new heap block with some additional + * zeroed memory (default tag). + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cbSrc The amount of memory to duplicate. + * @param cbExtra The amount of extra memory to allocate and zero. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemDupExTag(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Reallocates memory with default tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbNew The new block size (in bytes). + */ +#define RTMemRealloc(pvOld, cbNew) RTMemReallocTag((pvOld), (cbNew), RTMEM_TAG) + +/** + * Reallocates memory with custom tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbNew The new block size (in bytes). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemReallocTag(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Reallocates memory with default tag, initializing any new space to zero. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbOld The old block size (in bytes). + * @param cbNew The new block size (in bytes). + */ +#define RTMemReallocZ(pvOld, cbOld, cbNew) RTMemReallocZTag((pvOld), (cbOld), (cbNew), RTMEM_TAG) + +/** + * Reallocates memory with custom tag, initializing any new space to zero. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbOld The old block size (in bytes). + * @param cbNew The new block size (in bytes). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemReallocZTag(void *pvOld, size_t cbOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Frees memory. + * + * @param pv Pointer to memory block. + */ +RTDECL(void) RTMemFree(void *pv) RT_NO_THROW_PROTO; + +/** + * Clears and frees memory. + * + * This is strongly recommended when the memory being freed holds untrusted data + * to help counter heap spraying. + * + * @param pv Pointer to memory block. + * @param cb The size of the allocation. + * + * @note The memory isn't always filled with zeros, it can be set to a + * different value in some configurations. + */ +RTDECL(void) RTMemFreeZ(void *pv, size_t cb) RT_NO_THROW_PROTO; + + + +/** @name RTR0MemAllocEx and RTR0MemAllocExTag flags. + * @{ */ +/** The returned memory should be zeroed. */ +#define RTMEMALLOCEX_FLAGS_ZEROED RT_BIT(0) +/** Allocate memory that can be executed. + * @note Only supported in ring-3 for now, use RTR0MemObjAllocPage w/ @a + * fExecutable = @c true for ring-0. */ +#define RTMEMALLOCEX_FLAGS_EXEC RT_BIT(1) +/** Allocation from any context. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC RT_BIT(2) +/** Allocate the memory such that it can be freed from any context. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_ANY_CTX_FREE RT_BIT(3) +/** Allocate and free from any context. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_ANY_CTX (RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC | RTMEMALLOCEX_FLAGS_ANY_CTX_FREE) +/** Reachable by 16-bit address. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_16BIT_REACH RT_BIT(4) +/** Reachable by 32-bit address. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_32BIT_REACH RT_BIT(5) +/** Mask of valid flags. */ +#define RTMEMALLOCEX_FLAGS_VALID_MASK UINT32_C(0x0000003f) +/** Mask of valid flags for ring-0. */ +#define RTMEMALLOCEX_FLAGS_VALID_MASK_R0 UINT32_C(0x0000000f) +/** @} */ + +/** + * Extended heap allocation API, default tag. + * + * @returns IPRT status code. + * @retval VERR_NO_MEMORY if we're out of memory. + * @retval VERR_NO_EXEC_MEMORY if we're out of executable memory. + * @retval VERR_NOT_SUPPORTED if any of the specified flags are unsupported. + * + * @param cb The amount of memory to allocate. + * @param cbAlignment The alignment requirements. Use 0 to indicate + * default alignment. + * @param fFlags A combination of the RTMEMALLOCEX_FLAGS_XXX + * defines. + * @param ppv Where to return the memory. + */ +#define RTMemAllocEx(cb, cbAlignment, fFlags, ppv) RTMemAllocExTag((cb), (cbAlignment), (fFlags), RTMEM_TAG, (ppv)) + +/** + * Extended heap allocation API, custom tag. + * + * Depending on the implementation, using this function may add extra overhead, + * so use the simpler APIs where ever possible. + * + * @returns IPRT status code. + * @retval VERR_NO_MEMORY if we're out of memory. + * @retval VERR_NO_EXEC_MEMORY if we're out of executable memory. + * @retval VERR_NOT_SUPPORTED if any of the specified flags are unsupported. + * + * @param cb The amount of memory to allocate. + * @param cbAlignment The alignment requirements. Use 0 to indicate + * default alignment. + * @param fFlags A combination of the RTMEMALLOCEX_FLAGS_XXX + * defines. + * @param pszTag The tag. + * @param ppv Where to return the memory. + */ +RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv) RT_NO_THROW_PROTO; + +/** + * For freeing memory allocated by RTMemAllocEx or RTMemAllocExTag. + * + * @param pv What to free, NULL is fine. + * @param cb The amount of allocated memory. + */ +RTDECL(void) RTMemFreeEx(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Allocate page aligned memory with default tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + */ +#define RTMemPageAlloc(cb) RTMemPageAllocTag((cb), RTMEM_TAG) + +/** + * Allocate page aligned memory with custom tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemPageAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocate zero'd page aligned memory with default tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + */ +#define RTMemPageAllocZ(cb) RTMemPageAllocZTag((cb), RTMEM_TAG) + +/** + * Allocate zero'd page aligned memory with custom tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemPageAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocate page aligned memory with default tag, extended version. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + * @param fFlags RTMEMPAGEALLOC_F_XXX. + */ +#define RTMemPageAllocEx(cb, fFlags) RTMemPageAllocExTag((cb), (fFlags), RTMEM_TAG) + +/** + * Allocate page aligned memory with custom tag, extended version. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + * @param fFlags RTMEMPAGEALLOC_F_XXX. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemPageAllocExTag(size_t cb, uint32_t fFlags, const char *pszTag) RT_NO_THROW_PROTO; + +/** @name RTMEMPAGEALLOC_F_XXX - flags for RTMemPageAllocEx() and RTMemPageAllocExTag() + * @{ */ +/** Zero the allocation. */ +#define RTMEMPAGEALLOC_F_ZERO RT_BIT_32(0) +/** Try lock the allocation (failure ignored). */ +#define RTMEMPAGEALLOC_F_ADVISE_LOCKED RT_BIT_32(1) +/** Try prevent the memory from ending up in a dump/core. */ +#define RTMEMPAGEALLOC_F_ADVISE_NO_DUMP RT_BIT_32(2) +/** Valid bit mask. */ +#define RTMEMPAGEALLOC_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Free a memory block allocated with RTMemPageAlloc() or RTMemPageAllocZ(). + * + * @param pv Pointer to the block as it was returned by the allocation function. + * NULL will be ignored. + * @param cb The allocation size. Will be rounded up to page size. + * Ignored if @a pv is NULL. + */ +RTDECL(void) RTMemPageFree(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** Page level protection flags for RTMemProtect(). + * @{ + */ +/** No access at all. */ +#define RTMEM_PROT_NONE 0 +/** Read access. */ +#define RTMEM_PROT_READ 1 +/** Write access. */ +#define RTMEM_PROT_WRITE 2 +/** Execute access. */ +#define RTMEM_PROT_EXEC 4 +/** @} */ + +/** + * Change the page level protection of a memory region. + * + * @returns iprt status code. + * @param pv Start of the region. Will be rounded down to nearest page boundary. + * @param cb Size of the region. Will be rounded up to the nearest page boundary. + * @param fProtect The new protection, a combination of the RTMEM_PROT_* defines. + */ +RTDECL(int) RTMemProtect(void *pv, size_t cb, unsigned fProtect) RT_NO_THROW_PROTO; + +/** + * Goes thru some pains to make sure the specified memory block is thoroughly + * scrambled. + * + * @param pv The start of the memory block. + * @param cb The size of the memory block. + * @param cMinPasses The minimum number of passes to make. + */ +RTDECL(void) RTMemWipeThoroughly(void *pv, size_t cb, size_t cMinPasses) RT_NO_THROW_PROTO; + + +/** @def RTMEM_WILL_LEAK + * Macro for hinting that a memory allocation @a a_pv will leak. + * + * @note This shall only be used in code that doesn't allocate the object. + * Code allocating memory knowing it will leak shall start the allocation + * tag string with 'will-leak:'. + */ +/** @def RTMEM_MAY_LEAK + * Macro for hinting that a memory allocation @a a_pv may leak. + * + * @note This shall only be used in code that doesn't allocate the object. + * Code allocating memory knowing it may leak shall start the allocation + * tag string with 'may-leak:'. + */ +#ifdef IPRT_WITH_GCC_SANITIZER +# define RTMEM_WILL_LEAK(a_pv) __lsan_ignore_object(a_pv) +# define RTMEM_MAY_LEAK(a_pv) __lsan_ignore_object(a_pv) +#else +# define RTMEM_WILL_LEAK(a_pv) do { } while (0) +# define RTMEM_MAY_LEAK(a_pv) do { } while (0) +#endif + + +/** @def RTMEM_IMPLEMENT_NEW_AND_DELETE + * Provides a new and delete implementation to a class using IPRT's RTMem + * allocator. + */ +#if !defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) || defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF) +# ifdef RT_EXCEPTIONS_ENABLED +# define RTMEM_IMPLEMENT_NEW_AND_DELETE() \ + void *operator new(size_t cb) RT_THROW(std::bad_alloc) \ + { \ + void *pv = RTMemAlloc(cb); \ + if (RT_LIKELY(pv)) \ + return pv; \ + throw std::bad_alloc(); \ + } \ + void *operator new(size_t cb, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + return RTMemAlloc(cb); \ + } \ + void *operator new(size_t cb, void *pvBuf) RT_NO_THROW_DEF \ + { \ + NOREF(cb); \ + return pvBuf; \ + } \ + void *operator new[](size_t cb) RT_THROW(std::bad_alloc) \ + { \ + void *pv = RTMemAlloc(cb); \ + if (RT_LIKELY(pv)) \ + return pv; \ + throw std::bad_alloc(); \ + } \ + void *operator new[](size_t cb, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + return RTMemAlloc(cb); \ + } \ + \ + void operator delete(void *pv) RT_NO_THROW_DEF \ + { \ + RTMemFree(pv); \ + } \ + void operator delete(void *pv, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + RTMemFree(pv); \ + } \ + void operator delete[](void *pv) RT_NO_THROW_DEF \ + { \ + RTMemFree(pv); \ + } \ + void operator delete[](void *pv, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + RTMemFree(pv); \ + } \ + \ + typedef int UsingIprtNewAndDeleteOperators +# else /* !RT_EXCEPTIONS_ENABLED */ +# define RTMEM_IMPLEMENT_NEW_AND_DELETE() \ + void *operator new(size_t cb) \ + { \ + return RTMemAlloc(cb); \ + } \ + void *operator new(size_t cb, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + return RTMemAlloc(cb); \ + } \ + void *operator new(size_t cb, void *pvBuf) RT_NO_THROW_DEF \ + { \ + NOREF(cb); \ + return pvBuf; \ + } \ + void *operator new[](size_t cb) \ + { \ + return RTMemAlloc(cb); \ + } \ + void *operator new[](size_t cb, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + return RTMemAlloc(cb); \ + } \ + \ + void operator delete(void *pv) \ + { \ + RTMemFree(pv); \ + } \ + void operator delete(void *pv, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + RTMemFree(pv); \ + } \ + void operator delete[](void *pv) \ + { \ + RTMemFree(pv); \ + } \ + void operator delete[](void *pv, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + RTMemFree(pv); \ + } \ + \ + typedef int UsingIprtNewAndDeleteOperators +# endif /* !RT_EXCEPTIONS_ENABLED */ +#else /* defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) && !defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF) */ +# define RTMEM_IMPLEMENT_NEW_AND_DELETE() RTMEMEF_NEW_AND_DELETE_OPERATORS() +#endif /* defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) && !defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF) */ + + +#ifdef IN_RING0 + +/** + * Allocates physical contiguous memory (below 4GB). + * The allocation is page aligned and the content is undefined. + * + * @returns Pointer to the memory block. This is page aligned. + * @param pPhys Where to store the physical address. + * @param cb The allocation size in bytes. This is always + * rounded up to PAGE_SIZE. + */ +RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb) RT_NO_THROW_PROTO; + +/** + * Frees memory allocated ysing RTMemContAlloc(). + * + * @param pv Pointer to return from RTMemContAlloc(). + * @param cb The cb parameter passed to RTMemContAlloc(). + */ +RTR0DECL(void) RTMemContFree(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Copy memory from an user mode buffer into a kernel buffer. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED on error. + * + * @param pvDst The kernel mode destination address. + * @param R3PtrSrc The user mode source address. + * @param cb The number of bytes to copy. + */ +RTR0DECL(int) RTR0MemUserCopyFrom(void *pvDst, RTR3PTR R3PtrSrc, size_t cb); + +/** + * Copy memory from a kernel buffer into a user mode one. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED on error. + * + * @param R3PtrDst The user mode destination address. + * @param pvSrc The kernel mode source address. + * @param cb The number of bytes to copy. + */ +RTR0DECL(int) RTR0MemUserCopyTo(RTR3PTR R3PtrDst, void const *pvSrc, size_t cb); + +/** + * Tests if the specified address is in the user addressable range. + * + * This function does not check whether the memory at that address is accessible + * or anything of that sort, only if the address it self is in the user mode + * range. + * + * @returns true if it's in the user addressable range. false if not. + * @param R3Ptr The user mode pointer to test. + * + * @remarks Some systems may have overlapping kernel and user address ranges. + * One prominent example of this is the x86 version of Mac OS X. Use + * RTR0MemAreKrnlAndUsrDifferent() to check. + */ +RTR0DECL(bool) RTR0MemUserIsValidAddr(RTR3PTR R3Ptr); + +/** + * Tests if the specified address is in the kernel mode range. + * + * This function does not check whether the memory at that address is accessible + * or anything of that sort, only if the address it self is in the kernel mode + * range. + * + * @returns true if it's in the kernel range. false if not. + * @param pv The alleged kernel mode pointer. + * + * @remarks Some systems may have overlapping kernel and user address ranges. + * One prominent example of this is the x86 version of Mac OS X. Use + * RTR0MemAreKrnlAndUsrDifferent() to check. + */ +RTR0DECL(bool) RTR0MemKernelIsValidAddr(void *pv); + +/** + * Are user mode and kernel mode address ranges distinctly different. + * + * This determines whether RTR0MemKernelIsValidAddr and RTR0MemUserIsValidAddr + * can be used for deciding whether some arbitrary address is a user mode or a + * kernel mode one. + * + * @returns true if they are, false if not. + */ +RTR0DECL(bool) RTR0MemAreKrnlAndUsrDifferent(void); + +/** + * Copy memory from an potentially unsafe kernel mode location and into a safe + * (kernel) buffer. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED on error. + * @retval VERR_NOT_SUPPORTED if not (yet) supported. + * + * @param pvDst The destination address (safe). + * @param pvSrc The source address (potentially unsafe). + * @param cb The number of bytes to copy. + */ +RTR0DECL(int) RTR0MemKernelCopyFrom(void *pvDst, void const *pvSrc, size_t cb); + +/** + * Copy from a safe (kernel) buffer and to a potentially unsafe kenrel mode + * location. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED on error. + * @retval VERR_NOT_SUPPORTED if not (yet) supported. + * + * @param pvDst The destination address (potentially unsafe). + * @param pvSrc The source address (safe). + * @param cb The number of bytes to copy. + */ +RTR0DECL(int) RTR0MemKernelCopyTo(void *pvDst, void const *pvSrc, size_t cb); + +#endif /* IN_RING0 */ + + +/** @name Electrical Fence Version of some APIs. + * @{ + */ + +/** + * Same as RTMemTmpAllocTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfTmpAlloc(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemTmpAllocZTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfTmpAllocZ(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemTmpFree() except that it's for fenced memory. + * + * @param pv Pointer to memory block. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void) RTMemEfTmpFree(void *pv, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemTmpFreeZ() except that it's for fenced memory. + * + * @param pv Pointer to memory block. + * @param cb Size of the memory block. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void) RTMemEfTmpFreeZ(void *pv, size_t cb, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemAllocTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. Free with RTMemEfFree(). + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfAlloc(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemAllocZTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfAllocZ(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemAllocVarTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. Free with RTMemEfFree(). + * @returns NULL on failure. + * @param cbUnaligned Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfAllocVar(size_t cbUnaligned, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemAllocZVarTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cbUnaligned Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfAllocZVar(size_t cbUnaligned, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemReallocTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbNew The new block size (in bytes). + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfRealloc(void *pvOld, size_t cbNew, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemReallocZTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbOld The old block size (in bytes). + * @param cbNew The new block size (in bytes). + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfReallocZ(void *pvOld, size_t cbOld, size_t cbNew, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Free memory allocated by any of the RTMemEf* allocators. + * + * @param pv Pointer to memory block. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void) RTMemEfFree(void *pv, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Clear and free memory allocated by any of the RTMemEf* allocators. + * + * @param pv Pointer to memory block. + * @param cb Size of the allocation. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void) RTMemEfFreeZ(void *pv, size_t cb, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemDupTag() except that it's fenced. + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cb The amount of memory to duplicate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfDup(const void *pvSrc, size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemEfDupExTag except that it's fenced. + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cbSrc The amount of memory to duplicate. + * @param cbExtra The amount of extra memory to allocate and zero. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfDupEx(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** @def RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF + * Define RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF to enable electric fence new and + * delete operators for classes which uses the RTMEMEF_NEW_AND_DELETE_OPERATORS + * macro. + */ +/** @def RTMEMEF_NEW_AND_DELETE_OPERATORS + * Defines the electric fence new and delete operators for a class when + * RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF is define. + */ +/** @def RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT + * Defines the electric fence new and delete operators for an IOKit class when + * RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF is define. + * + * This differs from RTMEMEF_NEW_AND_DELETE_OPERATORS in that the memory we + * allocate is initialized to zero. It is also assuming we don't have nothrow + * variants and exceptions, so fewer variations. + */ +#if defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) && !defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF) +# if defined(RT_EXCEPTIONS_ENABLED) +# define RTMEMEF_NEW_AND_DELETE_OPERATORS() \ + void *operator new(size_t cb) RT_THROW(std::bad_alloc) \ + { \ + void *pv = RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + if (RT_LIKELY(pv)) \ + return pv; \ + throw std::bad_alloc(); \ + } \ + void *operator new(size_t cb, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new(size_t cb, void *pvBuf) RT_NO_THROW_DEF \ + { \ + NOREF(cb); \ + return pvBuf; \ + } \ + void *operator new[](size_t cb) RT_THROW(std::bad_alloc) \ + { \ + void *pv = RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + if (RT_LIKELY(pv)) \ + return pv; \ + throw std::bad_alloc(); \ + } \ + void *operator new[](size_t cb, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + \ + void operator delete(void *pv) RT_NO_THROW_DEF \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete(void *pv, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv) RT_NO_THROW_DEF \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + \ + typedef int UsingElectricNewAndDeleteOperators +# else +# define RTMEMEF_NEW_AND_DELETE_OPERATORS() \ + void *operator new(size_t cb) \ + { \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new(size_t cb, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new(size_t cb, void *pvBuf) RT_NO_THROW_DEF \ + { \ + NOREF(cb); \ + return pvBuf; \ + } \ + void *operator new[](size_t cb) \ + { \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new[](size_t cb, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + \ + void operator delete(void *pv) \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete(void *pv, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv) \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + \ + typedef int UsingElectricNewAndDeleteOperators +# endif +# define RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT() \ + void *operator new(size_t cb) \ + { \ + return RTMemEfAllocZ(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new[](size_t cb) \ + { \ + return RTMemEfAllocZ(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + \ + void operator delete(void *pv) \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv) \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + \ + typedef int UsingElectricNewAndDeleteOperators +#else +# define RTMEMEF_NEW_AND_DELETE_OPERATORS() \ + typedef int UsingDefaultNewAndDeleteOperators +# define RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT() \ + typedef int UsingDefaultNewAndDeleteOperators +#endif +#ifdef DOXYGEN_RUNNING +# define RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF +#endif + +/** @def RTMEM_WRAP_TO_EF_APIS + * Define RTMEM_WRAP_TO_EF_APIS to wrap RTMem APIs to RTMemEf APIs. + */ +#if defined(RTMEM_WRAP_TO_EF_APIS) && !defined(RTMEM_NO_WRAP_TO_EF_APIS) \ + && ( defined(IN_RING3) || ( defined(IN_RING0) && !defined(IN_RING0_AGNOSTIC) && (defined(RT_OS_DARWIN) || 0) ) ) +# define RTMemTmpAllocTag(cb, pszTag) RTMemEfTmpAlloc((cb), (pszTag), RT_SRC_POS) +# define RTMemTmpAllocZTag(cb, pszTag) RTMemEfTmpAllocZ((cb), (pszTag), RT_SRC_POS) +# define RTMemTmpFree(pv) RTMemEfTmpFree((pv), RT_SRC_POS) +# define RTMemTmpFreeZ(pv, cb) RTMemEfTmpFreeZ((pv), (cb), RT_SRC_POS) +# define RTMemAllocTag(cb, pszTag) RTMemEfAlloc((cb), (pszTag), RT_SRC_POS) +# define RTMemAllocZTag(cb, pszTag) RTMemEfAllocZ((cb), (pszTag), RT_SRC_POS) +# define RTMemAllocVarTag(cbUnaligned, pszTag) RTMemEfAllocVar((cbUnaligned), (pszTag), RT_SRC_POS) +# define RTMemAllocZVarTag(cbUnaligned, pszTag) RTMemEfAllocZVar((cbUnaligned), (pszTag), RT_SRC_POS) +# define RTMemReallocTag(pvOld, cbNew, pszTag) RTMemEfRealloc((pvOld), (cbNew), (pszTag), RT_SRC_POS) +# define RTMemReallocZTag(pvOld, cbOld, cbNew, pszTag) RTMemEfReallocZ((pvOld), (cbOld), (cbNew), (pszTag), RT_SRC_POS) +# define RTMemFree(pv) RTMemEfFree((pv), RT_SRC_POS) +# define RTMemFreeZ(pv, cb) RTMemEfFreeZ((pv), (cb), RT_SRC_POS) +# define RTMemDupTag(pvSrc, cb, pszTag) RTMemEfDup((pvSrc), (cb), (pszTag), RT_SRC_POS) +# define RTMemDupExTag(pvSrc, cbSrc, cbExtra, pszTag) RTMemEfDupEx((pvSrc), (cbSrc), (cbExtra), (pszTag), RT_SRC_POS) +#endif +#ifdef DOXYGEN_RUNNING +# define RTMEM_WRAP_TO_EF_APIS +#endif + +/** + * Fenced drop-in replacement for RTMemTmpAllocTag. + * @copydoc RTMemTmpAllocTag + */ +RTDECL(void *) RTMemEfTmpAllocNP(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemTmpAllocZTag. + * @copydoc RTMemTmpAllocZTag + */ +RTDECL(void *) RTMemEfTmpAllocZNP(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemTmpFree. + * @copydoc RTMemTmpFree + */ +RTDECL(void) RTMemEfTmpFreeNP(void *pv) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemTmpFreeZ. + * @copydoc RTMemTmpFreeZ + */ +RTDECL(void) RTMemEfTmpFreeZNP(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemAllocTag. + * @copydoc RTMemAllocTag + */ +RTDECL(void *) RTMemEfAllocNP(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemAllocZTag. + * @copydoc RTMemAllocZTag + */ +RTDECL(void *) RTMemEfAllocZNP(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemAllocVarTag + * @copydoc RTMemAllocVarTag + */ +RTDECL(void *) RTMemEfAllocVarNP(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemAllocZVarTag. + * @copydoc RTMemAllocZVarTag + */ +RTDECL(void *) RTMemEfAllocZVarNP(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemReallocTag. + * @copydoc RTMemReallocTag + */ +RTDECL(void *) RTMemEfReallocNP(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemReallocZTag. + * @copydoc RTMemReallocZTag + */ +RTDECL(void *) RTMemEfReallocZNP(void *pvOld, size_t cbOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemFree. + * @copydoc RTMemFree + */ +RTDECL(void) RTMemEfFreeNP(void *pv) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemFreeZ. + * @copydoc RTMemFreeZ + */ +RTDECL(void) RTMemEfFreeZNP(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemDupExTag. + * @copydoc RTMemDupTag + */ +RTDECL(void *) RTMemEfDupNP(const void *pvSrc, size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemDupExTag. + * @copydoc RTMemDupExTag + */ +RTDECL(void *) RTMemEfDupExNP(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag) RT_NO_THROW_PROTO; + +/** @} */ + +RT_C_DECLS_END + +/** @} */ + + +#endif /* !IPRT_INCLUDED_mem_h */ + diff --git a/include/iprt/memcache.h b/include/iprt/memcache.h new file mode 100644 index 00000000..365ff61e --- /dev/null +++ b/include/iprt/memcache.h @@ -0,0 +1,170 @@ +/** @file + * IPRT - Memory Object Allocation Cache. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_memcache_h +#define IPRT_INCLUDED_memcache_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_rt_memcache RTMemCache - Memory Object Allocation Cache + * @ingroup grp_rt + * + * Optimized allocation, initialization, freeing and destruction of memory + * objects of the same kind and size. Objects are constructed once, then + * allocated and freed one or more times, until finally destructed together with + * the cache (RTMemCacheDestroy). It's expected behavior, even when pfnCtor is + * NULL, that the user will be store information that should be persistent + * across RTMemCacheFree calls. + * + * The objects are zeroed prior to calling pfnCtor. For obvious reasons, the + * objects are not touched by the cache after that, so that RTMemCacheAlloc will + * return the object in the same state as when it as handed to RTMemCacheFree. + * + * @todo A callback for the reuse (at alloc time) might be of interest. + * + * @{ + */ + +/** A memory cache handle. */ +typedef R3R0PTRTYPE(struct RTMEMCACHEINT *) RTMEMCACHE; +/** Pointer to a memory cache handle. */ +typedef RTMEMCACHE *PRTMEMCACHE; +/** Nil memory cache handle. */ +#define NIL_RTMEMCACHE ((RTMEMCACHE)0) + + +/** + * Object constructor. + * + * This is called for when an element is allocated for the first time. + * + * @returns IPRT status code. + * @param hMemCache The cache handle. + * @param pvObj The memory object that should be initialized. + * @param pvUser The user argument. + * + * @remarks No serialization is performed. + */ +typedef DECLCALLBACKTYPE(int, FNMEMCACHECTOR,(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)); +/** Pointer to an object constructor for the memory cache. */ +typedef FNMEMCACHECTOR *PFNMEMCACHECTOR; + +/** + * Object destructor. + * + * This is called when we're shrinking or destroying the cache. + * + * @param hMemCache The cache handle. + * @param pvObj The memory object that should be initialized. + * @param pvUser The user argument. + * + * @remarks No serialization is performed. + */ +typedef DECLCALLBACKTYPE(void, FNMEMCACHEDTOR,(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)); +/** Pointer to an object destructor for the memory cache. */ +typedef FNMEMCACHEDTOR *PFNMEMCACHEDTOR; + + +/** + * Create an allocation cache for fixed size memory objects. + * + * @returns IPRT status code. + * @param phMemCache Where to return the cache handle. + * @param cbObject The size of one memory object. + * @param cbAlignment The object alignment. This must be a power of + * two. The higest alignment is 64. If set to 0, + * a sensible alignment value will be derived from + * the object size. + * @param cMaxObjects The maximum cache size. Pass UINT32_MAX if unsure. + * @param pfnCtor Object constructor callback. Optional. + * @param pfnDtor Object destructor callback. Optional. + * @param pvUser User argument for the two callbacks. + * @param fFlags Flags reserved for future use. Must be zero. + */ +RTDECL(int) RTMemCacheCreate(PRTMEMCACHE phMemCache, size_t cbObject, size_t cbAlignment, uint32_t cMaxObjects, + PFNMEMCACHECTOR pfnCtor, PFNMEMCACHEDTOR pfnDtor, void *pvUser, uint32_t fFlags); + +/** + * Destroy a cache destroying and freeing allocated memory. + * + * @returns IPRT status code. + * @param hMemCache The cache handle. NIL is quietly (VINF_SUCCESS) + * ignored. + */ +RTDECL(int) RTMemCacheDestroy(RTMEMCACHE hMemCache); + +/** + * Allocate an object. + * + * @returns Pointer to the allocated cache object. + * @param hMemCache The cache handle. + */ +RTDECL(void *) RTMemCacheAlloc(RTMEMCACHE hMemCache); + +/** + * Allocate an object and return a proper status code. + * + * @returns IPRT status code. + * @retval VERR_MEM_CACHE_MAX_SIZE if we've reached maximum size (see + * RTMemCacheCreate). + * @retval VERR_NO_MEMORY if we failed to allocate more memory for the cache. + * + * @param hMemCache The cache handle. + * @param ppvObj Where to return the object. + */ +RTDECL(int) RTMemCacheAllocEx(RTMEMCACHE hMemCache, void **ppvObj); + +/** + * Free an object previously returned by RTMemCacheAlloc or RTMemCacheAllocEx. + * + * @param hMemCache The cache handle. + * @param pvObj The object to free. NULL is fine. + */ +RTDECL(void) RTMemCacheFree(RTMEMCACHE hMemCache, void *pvObj); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_memcache_h */ + diff --git a/include/iprt/memobj.h b/include/iprt/memobj.h new file mode 100644 index 00000000..e68ea046 --- /dev/null +++ b/include/iprt/memobj.h @@ -0,0 +1,795 @@ +/** @file + * IPRT - Memory Objects (Ring-0). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_memobj_h +#define IPRT_INCLUDED_memobj_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_memobj RTMemObj - Memory Object Manipulation (Ring-0) + * @ingroup grp_rt + * @{ + */ + +/** @def RTMEM_TAG + * The default allocation tag used by the RTMem allocation APIs. + * + * When not defined before the inclusion of iprt/memobj.h or iprt/mem.h, this + * will default to the pointer to the current file name. The memory API will + * make of use of this as pointer to a volatile but read-only string. + */ +#ifndef RTMEM_TAG +# define RTMEM_TAG (__FILE__) +#endif + +#ifdef IN_RING0 + +/** + * Checks if this is mapping or not. + * + * @returns true if it's a mapping, otherwise false. + * @param MemObj The ring-0 memory object handle. + */ +RTR0DECL(bool) RTR0MemObjIsMapping(RTR0MEMOBJ MemObj); + +/** + * Gets the address of a ring-0 memory object. + * + * @returns The address of the memory object. + * @returns NULL if the handle is invalid (asserts in strict builds) or if there isn't any mapping. + * @param MemObj The ring-0 memory object handle. + */ +RTR0DECL(void *) RTR0MemObjAddress(RTR0MEMOBJ MemObj); + +/** + * Gets the ring-3 address of a ring-0 memory object. + * + * This only applies to ring-0 memory object with ring-3 mappings of some kind, i.e. + * locked user memory, reserved user address space and user mappings. This API should + * not be used on any other objects. + * + * @returns The address of the memory object. + * @returns NIL_RTR3PTR if the handle is invalid or if it's not an object with a ring-3 mapping. + * Strict builds will assert in both cases. + * @param MemObj The ring-0 memory object handle. + */ +RTR0DECL(RTR3PTR) RTR0MemObjAddressR3(RTR0MEMOBJ MemObj); + +/** + * Gets the size of a ring-0 memory object. + * + * The returned value may differ from the one specified to the API creating the + * object because of alignment adjustments. The minimal alignment currently + * employed by any API is PAGE_SIZE, so the result can safely be shifted by + * PAGE_SHIFT to calculate a page count. + * + * @returns The object size. + * @returns 0 if the handle is invalid (asserts in strict builds) or if there isn't any mapping. + * @param MemObj The ring-0 memory object handle. + */ +RTR0DECL(size_t) RTR0MemObjSize(RTR0MEMOBJ MemObj); + +/** + * Get the physical address of an page in the memory object. + * + * @returns The physical address. + * @returns NIL_RTHCPHYS if the object doesn't contain fixed physical pages. + * @returns NIL_RTHCPHYS if the iPage is out of range. + * @returns NIL_RTHCPHYS if the object handle isn't valid. + * @param MemObj The ring-0 memory object handle. + * @param iPage The page number within the object. + */ +RTR0DECL(RTHCPHYS) RTR0MemObjGetPagePhysAddr(RTR0MEMOBJ MemObj, size_t iPage); + +/** + * Checks whether the allocation was zero initialized or not. + * + * This only works on allocations. It is not meaningful for mappings, reserved + * memory and entered physical address, and will return false for these. + * + * @returns true if the allocation was initialized to zero at allocation time, + * false if not or query not meaningful to the object type. + * @param hMemObj The ring-0 memory object to be freed. + * + * @remarks It can be expected that memory allocated in the same fashion will + * have the same initialization state. So, if this returns true for + * one allocation it will return true for all other similarly made + * allocations. + */ +RTR0DECL(bool) RTR0MemObjWasZeroInitialized(RTR0MEMOBJ hMemObj); + +/** + * Frees a ring-0 memory object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if + * @param MemObj The ring-0 memory object to be freed. NULL is accepted. + * @param fFreeMappings Whether or not to free mappings of the object. + */ +RTR0DECL(int) RTR0MemObjFree(RTR0MEMOBJ MemObj, bool fFreeMappings); + +/** + * Allocates page aligned virtual kernel memory (default tag). + * + * The memory is taken from a non paged (= fixed physical memory backing) pool. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + */ +#define RTR0MemObjAllocPage(pMemObj, cb, fExecutable) \ + RTR0MemObjAllocPageTag((pMemObj), (cb), (fExecutable), RTMEM_TAG) + +/** + * Allocates page aligned virtual kernel memory (custom tag). + * + * The memory is taken from a non paged (= fixed physical memory backing) pool. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocPageTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag); + +/** + * Allocates large page aligned virtual kernel memory (default tag). + * + * Each large page in the allocation is backed by a contiguous chunk of physical + * memory aligned to the page size. The memory is taken from a non paged (= + * fixed physical memory backing) pool. + * + * On some hosts we only support allocating a single large page at a time, they + * will return VERR_NOT_SUPPORTED if @a cb is larger than @a cbLargePage. + * + * @returns IPRT status code. + * @retval VERR_TRY_AGAIN instead of VERR_NO_MEMORY when + * RTMEMOBJ_ALLOC_LARGE_F_FAST is set and supported. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to + * nearest large page. + * @param cbLargePage The large page size. The allowed values varies from + * architecture to architecture and the paging mode + * used by the OS. + * @param fFlags Flags, RTMEMOBJ_ALLOC_LARGE_F_XXX. + * + * @note The implicit kernel mapping of this allocation does not necessarily + * have to be aligned on a @a cbLargePage boundrary. + */ +#define RTR0MemObjAllocLarge(pMemObj, cb, cbLargePage, fFlags) \ + RTR0MemObjAllocLargeTag((pMemObj), (cb), (cbLargePage), (fFlags), RTMEM_TAG) + +/** + * Allocates large page aligned virtual kernel memory (custom tag). + * + * Each large page in the allocation is backed by a contiguous chunk of physical + * memory aligned to the page size. The memory is taken from a non paged (= + * fixed physical memory backing) pool. + * + * On some hosts we only support allocating a single large page at a time, they + * will return VERR_NOT_SUPPORTED if @a cb is larger than @a cbLargePage. + * + * @returns IPRT status code. + * @retval VERR_TRY_AGAIN instead of VERR_NO_MEMORY when + * RTMEMOBJ_ALLOC_LARGE_F_FAST is set and supported. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to + * nearest large page. + * @param cbLargePage The large page size. The allowed values varies from + * architecture to architecture and the paging mode + * used by the OS. + * @param fFlags Flags, RTMEMOBJ_ALLOC_LARGE_F_XXX. + * @param pszTag Allocation tag used for statistics and such. + * + * @note The implicit kernel mapping of this allocation does not necessarily + * have to be aligned on a @a cbLargePage boundrary. + */ +RTR0DECL(int) RTR0MemObjAllocLargeTag(PRTR0MEMOBJ pMemObj, size_t cb, size_t cbLargePage, uint32_t fFlags, const char *pszTag); + +/** @name RTMEMOBJ_ALLOC_LARGE_F_XXX + * @{ */ +/** Indicates that it is okay to fail if there aren't enough large pages handy, + * cancelling any expensive search and reshuffling of memory (when supported). + * @note This flag can't be realized on all OSes. (Those who do support it + * will return VERR_TRY_AGAIN instead of VERR_NO_MEMORY if they + * cannot satisfy the request.) */ +#define RTMEMOBJ_ALLOC_LARGE_F_FAST RT_BIT_32(0) +/** Mask with valid bits. */ +#define RTMEMOBJ_ALLOC_LARGE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Allocates page aligned virtual kernel memory with physical backing below 4GB + * (default tag). + * + * The physical memory backing the allocation is fixed. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + */ +#define RTR0MemObjAllocLow(pMemObj, cb, fExecutable) \ + RTR0MemObjAllocLowTag((pMemObj), (cb), (fExecutable), RTMEM_TAG) + +/** + * Allocates page aligned virtual kernel memory with physical backing below 4GB + * (custom tag). + * + * The physical memory backing the allocation is fixed. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocLowTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag); + +/** + * Allocates page aligned virtual kernel memory with contiguous physical backing + * below 4GB (default tag). + * + * The physical memory backing the allocation is fixed. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + */ +#define RTR0MemObjAllocCont(pMemObj, cb, fExecutable) \ + RTR0MemObjAllocContTag((pMemObj), (cb), (fExecutable), RTMEM_TAG) + +/** + * Allocates page aligned virtual kernel memory with contiguous physical backing + * below 4GB (custom tag). + * + * The physical memory backing the allocation is fixed. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocContTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag); + +/** + * Locks a range of user virtual memory (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param R3Ptr User virtual address. This is rounded down to a page + * boundary. + * @param cb Number of bytes to lock. This is rounded up to + * nearest page boundary. + * @param fAccess The desired access, a combination of RTMEM_PROT_READ + * and RTMEM_PROT_WRITE. + * @param R0Process The process to lock pages in. NIL_RTR0PROCESS is an + * alias for the current one. + * + * @remarks RTR0MemGetAddressR3() and RTR0MemGetAddress() will return therounded + * down address. + * + * @remarks Linux: This API requires that the memory begin locked is in a memory + * mapping that is not required in any forked off child process. This + * is not intented as permanent restriction, feel free to help out + * lifting it. + */ +#define RTR0MemObjLockUser(pMemObj, R3Ptr, cb, fAccess, R0Process) \ + RTR0MemObjLockUserTag((pMemObj), (R3Ptr), (cb), (fAccess), (R0Process), RTMEM_TAG) + +/** + * Locks a range of user virtual memory (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param R3Ptr User virtual address. This is rounded down to a page + * boundary. + * @param cb Number of bytes to lock. This is rounded up to + * nearest page boundary. + * @param fAccess The desired access, a combination of RTMEM_PROT_READ + * and RTMEM_PROT_WRITE. + * @param R0Process The process to lock pages in. NIL_RTR0PROCESS is an + * alias for the current one. + * @param pszTag Allocation tag used for statistics and such. + * + * @remarks RTR0MemGetAddressR3() and RTR0MemGetAddress() will return therounded + * down address. + * + * @remarks Linux: This API requires that the memory begin locked is in a memory + * mapping that is not required in any forked off child process. This + * is not intented as permanent restriction, feel free to help out + * lifting it. + */ +RTR0DECL(int) RTR0MemObjLockUserTag(PRTR0MEMOBJ pMemObj, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess, + RTR0PROCESS R0Process, const char *pszTag); + +/** + * Locks a range of kernel virtual memory (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param pv Kernel virtual address. This is rounded down to a page boundary. + * @param cb Number of bytes to lock. This is rounded up to nearest page boundary. + * @param fAccess The desired access, a combination of RTMEM_PROT_READ + * and RTMEM_PROT_WRITE. + * + * @remark RTR0MemGetAddress() will return the rounded down address. + */ +#define RTR0MemObjLockKernel(pMemObj, pv, cb, fAccess) \ + RTR0MemObjLockKernelTag((pMemObj), (pv), (cb), (fAccess), RTMEM_TAG) + +/** + * Locks a range of kernel virtual memory (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param pv Kernel virtual address. This is rounded down to a page boundary. + * @param cb Number of bytes to lock. This is rounded up to nearest page boundary. + * @param fAccess The desired access, a combination of RTMEM_PROT_READ + * and RTMEM_PROT_WRITE. + * @param pszTag Allocation tag used for statistics and such. + * + * @remark RTR0MemGetAddress() will return the rounded down address. + */ +RTR0DECL(int) RTR0MemObjLockKernelTag(PRTR0MEMOBJ pMemObj, void *pv, size_t cb, uint32_t fAccess, const char *pszTag); + +/** + * Allocates contiguous page aligned physical memory without (necessarily) any + * kernel mapping (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + */ +#define RTR0MemObjAllocPhys(pMemObj, cb, PhysHighest) \ + RTR0MemObjAllocPhysTag((pMemObj), (cb), (PhysHighest), RTMEM_TAG) + +/** + * Allocates contiguous page aligned physical memory without (necessarily) any + * kernel mapping (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocPhysTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag); + +/** + * Allocates contiguous physical memory without (necessarily) any kernel mapping + * (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M, _4M and _1G. + */ +#define RTR0MemObjAllocPhysEx(pMemObj, cb, PhysHighest, uAlignment) \ + RTR0MemObjAllocPhysExTag((pMemObj), (cb), (PhysHighest), (uAlignment), RTMEM_TAG) + +/** + * Allocates contiguous physical memory without (necessarily) any kernel mapping + * (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M, _4M and _1G. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocPhysExTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment, const char *pszTag); + +/** + * Allocates non-contiguous page aligned physical memory without (necessarily) + * any kernel mapping (default tag). + * + * This API is for allocating huge amounts of pages and will return + * VERR_NOT_SUPPORTED if this cannot be implemented in a satisfactory + * manner. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it's not possible to allocated unmapped + * physical memory on this platform. The caller should expect + * this error and have a fallback strategy for it. + * + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + */ +#define RTR0MemObjAllocPhysNC(pMemObj, cb, PhysHighest) \ + RTR0MemObjAllocPhysNCTag((pMemObj), (cb), (PhysHighest), RTMEM_TAG) + +/** + * Allocates non-contiguous page aligned physical memory without (necessarily) + * any kernel mapping (custom tag). + * + * This API is for allocating huge amounts of pages and will return + * VERR_NOT_SUPPORTED if this cannot be implemented in a satisfactory + * manner. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it's not possible to allocated unmapped + * physical memory on this platform. The caller should expect + * this error and have a fallback strategy for it. + * + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocPhysNCTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag); + +/** Memory cache policy for RTR0MemObjEnterPhys. + * @{ + */ +/** Default caching policy -- don't care. */ +#define RTMEM_CACHE_POLICY_DONT_CARE UINT32_C(0) +/** MMIO caching policy -- uncachable. */ +#define RTMEM_CACHE_POLICY_MMIO UINT32_C(1) +/** @} */ + +/** + * Creates a page aligned, contiguous, physical memory object (default tag). + * + * No physical memory is allocated, we trust you do know what you're doing. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param Phys The physical address to start at. This is rounded down to the + * nearest page boundary. + * @param cb The size of the object in bytes. This is rounded up to nearest page boundary. + * @param uCachePolicy One of the RTMEM_CACHE_XXX modes. + */ +#define RTR0MemObjEnterPhys(pMemObj, Phys, cb, uCachePolicy) \ + RTR0MemObjEnterPhysTag((pMemObj), (Phys), (cb), (uCachePolicy), RTMEM_TAG) + +/** + * Creates a page aligned, contiguous, physical memory object (custom tag). + * + * No physical memory is allocated, we trust you do know what you're doing. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param Phys The physical address to start at. This is rounded down to the + * nearest page boundary. + * @param cb The size of the object in bytes. This is rounded up to nearest page boundary. + * @param uCachePolicy One of the RTMEM_CACHE_XXX modes. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjEnterPhysTag(PRTR0MEMOBJ pMemObj, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy, const char *pszTag); + +/** + * Reserves kernel virtual address space (default tag). + * + * If this function fails with VERR_NOT_SUPPORTED, the idea is that you + * can use RTR0MemObjEnterPhys() + RTR0MemObjMapKernel() as a fallback if + * you have a safe physical address range to make use of... + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param cb The number of bytes to reserve. This is rounded up to nearest page. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + */ +#define RTR0MemObjReserveKernel(pMemObj, pvFixed, cb, uAlignment) \ + RTR0MemObjReserveKernelTag((pMemObj), (pvFixed), (cb), (uAlignment), RTMEM_TAG) + +/** + * Reserves kernel virtual address space (custom tag). + * + * If this function fails with VERR_NOT_SUPPORTED, the idea is that you + * can use RTR0MemObjEnterPhys() + RTR0MemObjMapKernel() as a fallback if + * you have a safe physical address range to make use of... + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param cb The number of bytes to reserve. This is rounded up to nearest page. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjReserveKernelTag(PRTR0MEMOBJ pMemObj, void *pvFixed, size_t cb, size_t uAlignment, const char *pszTag); + +/** + * Reserves user virtual address space in the current process (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param cb The number of bytes to reserve. This is rounded up to nearest PAGE_SIZE. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param R0Process The process to reserve the memory in. + * NIL_RTR0PROCESS is an alias for the current one. + */ +#define RTR0MemObjReserveUser(pMemObj, R3PtrFixed, cb, uAlignment, R0Process) \ + RTR0MemObjReserveUserTag((pMemObj), (R3PtrFixed), (cb), (uAlignment), (R0Process), RTMEM_TAG) + +/** + * Reserves user virtual address space in the current process (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param cb The number of bytes to reserve. This is rounded up to nearest PAGE_SIZE. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param R0Process The process to reserve the memory in. + * NIL_RTR0PROCESS is an alias for the current one. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjReserveUserTag(PRTR0MEMOBJ pMemObj, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, + RTR0PROCESS R0Process, const char *pszTag); + +/** + * Maps a memory object into kernel virtual address space (default tag). + * + * This is the same as calling RTR0MemObjMapKernelEx with cbSub and offSub set + * to zero. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + */ +#define RTR0MemObjMapKernel(pMemObj, MemObjToMap, pvFixed, uAlignment, fProt) \ + RTR0MemObjMapKernelTag((pMemObj), (MemObjToMap), (pvFixed), (uAlignment), (fProt), RTMEM_TAG) + +/** + * Maps a memory object into kernel virtual address space (custom tag). + * + * This is the same as calling RTR0MemObjMapKernelEx with cbSub and offSub set + * to zero. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjMapKernelTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, + size_t uAlignment, unsigned fProt, const char *pszTag); + +/** + * Maps a memory object into kernel virtual address space (default tag). + * + * The ability to map subsections of the object into kernel space is currently + * not implemented on all platforms. All/Most of platforms supports mapping the + * whole object into kernel space. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it's not possible to map a subsection of a + * memory object on this platform. When you hit this, try implement it. + * + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param offSub Where in the object to start mapping. If non-zero + * the value must be page aligned and cbSub must be + * non-zero as well. + * @param cbSub The size of the part of the object to be mapped. If + * zero the entire object is mapped. The value must be + * page aligned. + */ +#define RTR0MemObjMapKernelEx(pMemObj, MemObjToMap, pvFixed, uAlignment, fProt, offSub, cbSub) \ + RTR0MemObjMapKernelExTag((pMemObj), (MemObjToMap), (pvFixed), (uAlignment), (fProt), (offSub), (cbSub), RTMEM_TAG) + +/** + * Maps a memory object into kernel virtual address space (custom tag). + * + * The ability to map subsections of the object into kernel space is currently + * not implemented on all platforms. All/Most of platforms supports mapping the + * whole object into kernel space. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it's not possible to map a subsection of a + * memory object on this platform. When you hit this, try implement it. + * + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param offSub Where in the object to start mapping. If non-zero + * the value must be page aligned and cbSub must be + * non-zero as well. + * @param cbSub The size of the part of the object to be mapped. If + * zero the entire object is mapped. The value must be + * page aligned. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjMapKernelExTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment, + unsigned fProt, size_t offSub, size_t cbSub, const char *pszTag); + +/** + * Maps a memory object into user virtual address space in the current process + * (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param R0Process The process to map the memory into. NIL_RTR0PROCESS + * is an alias for the current one. + */ +#define RTR0MemObjMapUser(pMemObj, MemObjToMap, R3PtrFixed, uAlignment, fProt, R0Process) \ + RTR0MemObjMapUserTag((pMemObj), (MemObjToMap), (R3PtrFixed), (uAlignment), (fProt), (R0Process), RTMEM_TAG) + +/** + * Maps a memory object into user virtual address space in the current process + * (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param R0Process The process to map the memory into. NIL_RTR0PROCESS + * is an alias for the current one. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjMapUserTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, RTR3PTR R3PtrFixed, + size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process, const char *pszTag); + +/** + * Maps a memory object into user virtual address space in the current process + * (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param R0Process The process to map the memory into. NIL_RTR0PROCESS + * is an alias for the current one. + * @param offSub Where in the object to start mapping. If non-zero + * the value must be page aligned and cbSub must be + * non-zero as well. + * @param cbSub The size of the part of the object to be mapped. If + * zero the entire object is mapped. The value must be + * page aligned. + */ +#define RTR0MemObjMapUserEx(pMemObj, MemObjToMap, R3PtrFixed, uAlignment, fProt, R0Process, offSub, cbSub) \ + RTR0MemObjMapUserExTag((pMemObj), (MemObjToMap), (R3PtrFixed), (uAlignment), (fProt), (R0Process), \ + (offSub), (cbSub), RTMEM_TAG) + +/** + * Maps a memory object into user virtual address space in the current process + * (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param R0Process The process to map the memory into. NIL_RTR0PROCESS + * is an alias for the current one. + * @param offSub Where in the object to start mapping. If non-zero + * the value must be page aligned and cbSub must be + * non-zero as well. + * @param cbSub The size of the part of the object to be mapped. If + * zero the entire object is mapped. The value must be + * page aligned. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjMapUserExTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, RTR3PTR R3PtrFixed, size_t uAlignment, + unsigned fProt, RTR0PROCESS R0Process, size_t offSub, size_t cbSub, const char *pszTag); + +/** + * Change the page level protection of one or more pages in a memory object. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the OS doesn't provide any way to manipulate + * page level protection. The caller must handle this status code + * gracefully. (Note that it may also occur if the implementation is + * missing, in which case just go ahead and implement it.) + * + * @param hMemObj Memory object handle. + * @param offSub Offset into the memory object. Must be page aligned. + * @param cbSub Number of bytes to change the protection of. Must be + * page aligned. + * @param fProt Combination of RTMEM_PROT_* flags. + */ +RTR0DECL(int) RTR0MemObjProtect(RTR0MEMOBJ hMemObj, size_t offSub, size_t cbSub, uint32_t fProt); + +#endif /* IN_RING0 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_memobj_h */ + diff --git a/include/iprt/mempool.h b/include/iprt/mempool.h new file mode 100644 index 00000000..2073a6dd --- /dev/null +++ b/include/iprt/mempool.h @@ -0,0 +1,178 @@ +/** @file + * IPRT - Memory Allocation Pool. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_mempool_h +#define IPRT_INCLUDED_mempool_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** + * Creates a new memory pool. + * + * @returns IPRT status code. + * + * @param phMemPool Where to return the handle to the new memory + * pool. + * @param pszName The name of the pool (for debug purposes). + */ +RTDECL(int) RTMemPoolCreate(PRTMEMPOOL phMemPool, const char *pszName); + +/** + * Destroys the specified pool, freeing all the memory it contains. + * + * @returns IPRT status code. + * + * @param hMemPool The handle to the pool. The nil handle and + * RTMEMPOOL_DEFAULT are quietly ignored (retval + * VINF_SUCCESS). + */ +RTDECL(int) RTMemPoolDestroy(RTMEMPOOL hMemPool); + +/** + * Allocates memory. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * + * @param hMemPool Handle to the pool to allocate the memory from. + * @param cb Size in bytes of the memory block to allocated. + */ +RTDECL(void *) RTMemPoolAlloc(RTMEMPOOL hMemPool, size_t cb) RT_NO_THROW_PROTO; + +/** + * Allocates zero'd memory. + * + * Instead of memset(pv, 0, sizeof()) use this when you want zero'd + * memory. This keeps the code smaller and the heap can skip the memset + * in about 0.42% of calls :-). + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * + * @param hMemPool Handle to the pool to allocate the memory from. + * @param cb Size in bytes of the memory block to allocated. + */ +RTDECL(void *) RTMemPoolAllocZ(RTMEMPOOL hMemPool, size_t cb) RT_NO_THROW_PROTO; + +/** + * Duplicates a chunk of memory into a new heap block. + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * + * @param hMemPool Handle to the pool to allocate the memory from. + * @param pvSrc The memory to duplicate. + * @param cb The amount of memory to duplicate. + */ +RTDECL(void *) RTMemPoolDup(RTMEMPOOL hMemPool, const void *pvSrc, size_t cb) RT_NO_THROW_PROTO; + +/** + * Duplicates a chunk of memory into a new heap block with some + * additional zeroed memory. + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * + * @param hMemPool Handle to the pool to allocate the memory from. + * @param pvSrc The memory to duplicate. + * @param cbSrc The amount of memory to duplicate. + * @param cbExtra The amount of extra memory to allocate and zero. + */ +RTDECL(void *) RTMemPoolDupEx(RTMEMPOOL hMemPool, const void *pvSrc, size_t cbSrc, size_t cbExtra) RT_NO_THROW_PROTO; + +/** + * Reallocates memory. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * + * @param hMemPool Handle to the pool containing the old memory. + * @param pvOld The memory block to reallocate. + * @param cbNew The new block size (in bytes). + */ +RTDECL(void *) RTMemPoolRealloc(RTMEMPOOL hMemPool, void *pvOld, size_t cbNew) RT_NO_THROW_PROTO; + +/** + * Frees memory allocated from a pool. + * + * @param hMemPool Handle to the pool containing the memory. Passing + * NIL here is fine, but it may come at a slight + * performance cost. + * @param pv Pointer to memory block. + * + * @remarks This is the same a RTMemPoolRelease but included here as a separate + * function to simplify code migration. + */ +RTDECL(void) RTMemPoolFree(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW_PROTO; + +/** + * Retains a reference to a memory block in a pool. + * + * @returns New reference count, UINT32_MAX on error (asserted). + * + * @param pv Pointer to memory block. + */ +RTDECL(uint32_t) RTMemPoolRetain(void *pv) RT_NO_THROW_PROTO; + +/** + * Releases a reference to a memory block in a pool. + * + * @returns New reference count, UINT32_MAX on error (asserted). + * + * @param hMemPool Handle to the pool containing the memory. Passing + * NIL here is fine, but it may come at a slight + * performance cost. + * @param pv Pointer to memory block. + */ +RTDECL(uint32_t) RTMemPoolRelease(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW_PROTO; + +/** + * Get the current reference count. + * + * @returns The reference count, UINT32_MAX on error (asserted). + * @param pv Pointer to memory block. + */ +RTDECL(uint32_t) RTMemPoolRefCount(void *pv) RT_NO_THROW_PROTO; + + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_mempool_h */ + diff --git a/include/iprt/memsafer.h b/include/iprt/memsafer.h new file mode 100644 index 00000000..cc9545bf --- /dev/null +++ b/include/iprt/memsafer.h @@ -0,0 +1,270 @@ +/** @file + * IPRT - Memory Allocate for Sensitive Data. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_memsafer_h +#define IPRT_INCLUDED_memsafer_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include /* RTMEM_TAG */ + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_rt_memsafer RTMemSafer - Memory Allocator for Sensitive Data + * @ingroup grp_rt + * + * This API doesn't provide 100% secure storage, it only provider more secure + * and safer storage. Thus the API isn't called RTMemSafe because you cannot + * assume the data is safe against all kinds of extraction methods. + * + * The API guarantee that the memory won't be returned to the system containing + * any of the information you put there. It will be repeatedly wiped after use. + * + * The API tries to isolate your data from other information stored in the + * process/system. How well this is done depends on the implementation. The + * more complicated implementations will provide protection against heartbleed + * like bugs where pieces of the heap is copied onto the wire. + * + * The more hardened implementations of the API will also do their best to + * prevent the memory from ending up in process dumps or being readable by + * debuggers. + * + * Finally, two functions are provided for scrambling the sensitive memory while + * it's not in use. + * + * @{ + */ + +/** @name RTMEMSAFER_F_XXX + * @{ */ +/** Require the memory to not hit the page file. + * @remarks Makes not guarantees with regards to hibernation / + * suspend-to-disk. */ +#define RTMEMSAFER_F_REQUIRE_NOT_PAGABLE RT_BIT_32(0) +/** Mask of valid bits. */ +#define RTMEMSAFER_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Scrambles memory allocated by RTMemSaferAllocZEx and associates after use. + * + * Call this when the sensitive data isn't actively being used. It will at a + * minimum make sure the data is slightly scrambled, how hard it is to unbutton + * is dependent on which implementation is used and available host support. + * + * The user must synchronize calls to RTMemSaferScramble and + * RTMemSaferUnscramble, this memory allocator provides no help and keeps no + * state information around. + * + * @returns IPRT status code. + * @param pv The pointer returned by the allocation function. + * @param cb The exact size given to the allocation function. + */ +RTDECL(int) RTMemSaferScramble(void *pv, size_t cb); + +/** + * Unscrambles memory allocated by RTMemSaferAllocZEx and associates before use. + * + * This undoes the effect of RTMemSaferScramble. + * + * @returns IPRT status code. + * @param pv The pointer returned by the allocation function. + * @param cb The exact size given to the allocation function. + */ +RTDECL(int) RTMemSaferUnscramble(void *pv, size_t cb); + +/** + * Allocates memory for sensitive data. + * + * Some effort will be taken to isolate the data from other memory allocation. + * Memory is always zeroed. + * + * @returns IPRT status code. + * @param ppvNew Where to return the pointer to the memory. + * @param cb Number of bytes to allocate. + * @param fFlags Flags for controlling the allocation, see + * RTMEMSAFER_F_XXX. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTMemSaferAllocZExTag(void **ppvNew, size_t cb, uint32_t fFlags, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocates memory for sensitive data. + * + * Some effort will be taken to isolate the data from other memory allocation. + * Memory is always zeroed. + * + * @returns IPRT status code. + * @param a_ppvNew Where to return the pointer to the memory. + * @param a_cb Number of bytes to allocate. + * @param a_fFlags Flags for controlling the allocation, see + * RTMEMSAFER_F_XXX. + */ +#define RTMemSaferAllocZEx(a_ppvNew, a_cb, a_fFlags) RTMemSaferAllocZExTag(a_ppvNew, a_cb, a_fFlags, RTMEM_TAG) + +/** + * Allocates memory for sensitive data. + * + * Some effort will be taken to isolate the data from other memory allocation. + * Memory is always zeroed. + * + * @returns Pointer to the allocated memory. + * @param cb Number of bytes to allocate. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemSaferAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocates memory for sensitive data. + * + * Some effort will be taken to isolate the data from other memory allocation. + * Memory is always zeroed. + * + * @returns Pointer to the allocated memory. + * @param a_cb Number of bytes to allocate. + */ +#define RTMemSaferAllocZ(a_cb) RTMemSaferAllocZTag(a_cb, RTMEM_TAG) + + +/** + * Reallocates memory allocated by RTMemSaferAllocZEx, RTMemSaferAllocZ, + * RTMemSaferAllocZExTag, or RTMemSaferAllocZTag. + * + * When extending the allocation, the new memory will be zeroed. When shrinking + * the allocation the left over memory will be wiped clean using + * RTMemWipeThorougly. + * + * The function follows the standard realloc behavior. + * + * @returns IPRT status code. + * @param cbOld The current allocation size. + * @param pvOld The current allocation. + * @param cbNew The size of the new allocation. + * @param ppvNew Where to return the pointer to the new memory. + * @param fFlags Flags for controlling the allocation, see + * RTMEMSAFER_F_XXX. It is not permitted to drop saftely + * requirments after the initial allocation. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTMemSaferReallocZExTag(size_t cbOld, void *pvOld, size_t cbNew, void **ppvNew, uint32_t fFlags, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Reallocates memory allocated by RTMemSaferAllocZEx, RTMemSaferAllocZ, + * RTMemSaferAllocZExTag, or RTMemSaferAllocZTag. + * + * When extending the allocation, the new memory will be zeroed. When shrinking + * the allocation the left over memory will be wiped clean using + * RTMemWipeThorougly. + * + * The function follows the standard realloc behavior. + * + * @returns IPRT status code. + * @param a_cbOld The current allocation size. + * @param a_pvOld The current allocation. + * @param a_cbNew The size of the new allocation. + * @param a_ppvNew Where to return the pointer to the new memory. + * @param a_fFlags Flags for controlling the allocation. See RTMEMSAFER_ALLOC_EX_FLAGS_* defines, + * this takes only effect when allocating completely new memory, for extending or + * shrinking existing allocations the flags of the allocation take precedence. + */ +#define RTMemSaferReallocZEx(a_cbOld, a_pvOld, a_cbNew, a_ppvNew, a_fFlags) \ + RTMemSaferReallocZExTag(a_cbOld, a_pvOld, a_cbNew, a_ppvNew, a_fFlags, RTMEM_TAG) + +/** + * Reallocates memory allocated by RTMemSaferAllocZ or RTMemSaferAllocZTag. + * + * When extending the allocation, the new memory will be zeroed. When shrinking + * the allocation the left over memory will be wiped clean using + * RTMemWipeThorougly. + * + * The function follows the standard realloc behavior. + * + * @returns Pointer to the allocated memory. + * @param cbOld The current allocation size. + * @param pvOld The current allocation. + * @param cbNew The size of the new allocation. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemSaferReallocZTag(size_t cbOld, void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Reallocates memory allocated by RTMemSaferAllocZ or RTMemSaferAllocZTag. + * + * When extending the allocation, the new memory will be zeroed. When shrinking + * the allocation the left over memory will be wiped clean using + * RTMemWipeThorougly. + * + * The function follows the standard realloc behavior. + * + * @returns Pointer to the allocated memory. + * @param a_cbOld The current allocation size. + * @param a_pvOld The current allocation. + * @param a_cbNew The size of the new allocation. + */ +#define RTMemSaferReallocZ(a_cbOld, a_pvOld, a_cbNew) RTMemSaferReallocZTag(a_cbOld, a_pvOld, a_cbNew, RTMEM_TAG) + + +/** + * Frees memory allocated by RTMemSaferAllocZ* or RTMemSaferReallocZ*. + * + * Before freeing the allocated memory, it will be wiped clean using + * RTMemWipeThorougly. + * + * @returns Pointer to the allocated memory. + * @param pv The allocation. + * @param cb The allocation size. + */ +RTDECL(void) RTMemSaferFree(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Gets the amount of memory allocated at @a pv. + * + * This can be used to check if the allocation was made using an RTMemSafer API. + * + * @returns Allocation size in bytes, 0 if not a RTMemSafer allocation. + * @param pv The alleged RTMemSafer allocation. + * + * @note Not supported in all contexts and implementations of the API. + */ +RTDECL(size_t) RTMemSaferGetSize(void *pv) RT_NO_THROW_PROTO; + + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_memsafer_h */ + diff --git a/include/iprt/memtracker.h b/include/iprt/memtracker.h new file mode 100644 index 00000000..cd3eff0b --- /dev/null +++ b/include/iprt/memtracker.h @@ -0,0 +1,257 @@ +/** @file + * IPRT - Memory Tracker. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_memtracker_h +#define IPRT_INCLUDED_memtracker_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_memtracker RTMemTracker - Memory Allocation Tracker. + * @ingroup grp_rt + * @{ + */ + +/** + * The allocation/free method. + */ +typedef enum RTMEMTRACKERMETHOD +{ + RTMEMTRACKERMETHOD_INVALID = 0, + RTMEMTRACKERMETHOD_ALLOC, + RTMEMTRACKERMETHOD_ALLOCZ, + RTMEMTRACKERMETHOD_REALLOC_PREP, /**< Internal, don't use. */ + RTMEMTRACKERMETHOD_REALLOC_DONE, /**< Internal, don't use. */ + RTMEMTRACKERMETHOD_REALLOC_FAILED, /**< Internal, don't use. */ + RTMEMTRACKERMETHOD_FREE, + + RTMEMTRACKERMETHOD_NEW, + RTMEMTRACKERMETHOD_NEW_ARRAY, + RTMEMTRACKERMETHOD_DELETE, + RTMEMTRACKERMETHOD_DELETE_ARRAY, + RTMEMTRACKERMETHOD_END, + RTMEMTRACKERMETHOD_32BIT_HACK = 0x7fffffff +} RTMEMTRACKERMETHOD; + +/** Pointer to a tag structure. */ +typedef struct RTMEMTRACKERTAG *PRTMEMTRACKERTAG; + +/** Pointer to a user structure. */ +typedef struct RTMEMTRACKERUSER *PRTMEMTRACKERUSER; + +/** + * Memory Tracking Header for use with RTMemTrackerHdrAlloc, + * RTMemTrackerHdrReallocPrep, RTMemTrackerHdrReallocDone and + * RTMemTrackerHdrFree. + */ +typedef struct RTMEMTRACKERHDR +{ + /** Magic value / eye catcher (RTMEMTRACKERHDR_MAGIC). */ + size_t uMagic; + /** The allocation size, user data only. */ + size_t cbUser; + /** The list entry. */ + RTLISTNODE ListEntry; + /** Pointer to the user structure where this header is linked. */ + PRTMEMTRACKERUSER pUser; + /** Pointer to the per-tag structure. */ + PRTMEMTRACKERTAG pTag; + /** The tag string. */ + const char *pszTag; + /** The caller address. */ + void *pvCaller; + /** Pointer to the user data we're tracking. */ + void *pvUser; + /** Alignment padding. */ + size_t uReserved; +} RTMEMTRACKERHDR; +/** Pointer to a memory tracker header. */ +typedef RTMEMTRACKERHDR *PRTMEMTRACKERHDR; +/** Pointer to a const memory tracker header. */ +typedef RTMEMTRACKERHDR *PPRTMEMTRACKERHDR; + +/** Magic value for RTMEMTRACKERHDR::uMagic (Kelly Link). */ +#if ARCH_BITS == 64 +# define RTMEMTRACKERHDR_MAGIC UINT64_C(0x1907691919690719) +#else +# define RTMEMTRACKERHDR_MAGIC UINT32_C(0x19690719) +#endif +/** Magic number used when reallocated. */ +#if ARCH_BITS == 64 +# define RTMEMTRACKERHDR_MAGIC_REALLOC UINT64_C(0x0000691919690000) +#else +# define RTMEMTRACKERHDR_MAGIC_REALLOC UINT32_C(0x19690000) +#endif +/** Magic number used when freed. */ +#define RTMEMTRACKERHDR_MAGIC_FREE (~RTMEMTRACKERHDR_MAGIC) + + +/** + * Initializes the allocation header and links it to the relevant tag. + * + * @returns Pointer to the user data part. + * @param pv The header + user data block. This must be at + * least @a cb + sizeof(RTMEMTRACKERHDR). + * @param cbUser The user data size (bytes). + * @param pszTag The tag string. + * @param pvCaller The return address. + * @param enmMethod The method that the user called. + */ +RTDECL(void *) RTMemTrackerHdrAlloc(void *pv, size_t cbUser, const char *pszTag, void *pvCaller, RTMEMTRACKERMETHOD enmMethod); + +/** + * Prepares for a realloc, i.e. invalidates the header. + * + * @returns Pointer to the user data part. + * @param pvOldUser Pointer to the old user data. + * @param cbOldUser The size of the old user data, 0 if not + * known. + * @param pszTag The tag string. + * @param pvCaller The return address. + */ +RTDECL(void *) RTMemTrackerHdrReallocPrep(void *pvOldUser, size_t cbOldUser, const char *pszTag, void *pvCaller); + +/** + * Initializes the allocation header and links it to the relevant tag. + * + * @returns Pointer to the user data part. + * @param pvNew The new header + user data block. This must be + * at least @a cb + sizeof(RTMEMTRACKERHDR). If + * this is NULL, we assume the realloc() call + * failed. + * @param cbNewUser The user data size (bytes). + * @param pvOldUser Pointer to the old user data. This is only + * valid on failure of course and used to bail out + * in that case. Should not be NULL. + * @param pszTag The tag string. + * @param pvCaller The return address. + */ +RTDECL(void *) RTMemTrackerHdrReallocDone(void *pvNew, size_t cbNewUser, void *pvOldUser, const char *pszTag, void *pvCaller); + + +/** + * Do the accounting on free. + * + * @returns @a pv. + * @param pvUser Pointer to the user data. + * @param cbUser The size of the user data, 0 if not known. + * @param pszTag The tag string. + * @param pvCaller The return address. + * @param enmMethod The method that the user called. + */ +RTDECL(void *) RTMemTrackerHdrFree(void *pvUser, size_t cbUser, const char *pszTag, void *pvCaller, RTMEMTRACKERMETHOD enmMethod); + + +/** + * Dumps all the allocations and tag statistics to the log. + */ +RTDECL(void) RTMemTrackerDumpAllToLog(void); + +/** + * Dumps all the allocations and tag statistics to the release log. + */ +RTDECL(void) RTMemTrackerDumpAllToLogRel(void); + +/** + * Dumps all the allocations and tag statistics to standard out. + */ +RTDECL(void) RTMemTrackerDumpAllToStdOut(void); + +/** + * Dumps all the allocations and tag statistics to standard err. + */ +RTDECL(void) RTMemTrackerDumpAllToStdErr(void); + +/** + * Dumps all the allocations and tag statistics to the specified filename. + */ +RTDECL(void) RTMemTrackerDumpAllToFile(const char *pszFilename); + + +/** + * Dumps all the tag statistics to the log. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + */ +RTDECL(void) RTMemTrackerDumpStatsToLog(bool fVerbose); + +/** + * Dumps all the tag statistics to the release log. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + */ +RTDECL(void) RTMemTrackerDumpStatsToLogRel(bool fVerbose); + +/** + * Dumps all the tag statistics to standard out. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + */ +RTDECL(void) RTMemTrackerDumpStatsToStdOut(bool fVerbose); + +/** + * Dumps all the tag statistics to standard err. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + */ +RTDECL(void) RTMemTrackerDumpStatsToStdErr(bool fVerbose); + +/** + * Dumps all the tag statistics to the specified filename. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + * @param pszFilename The name of the file to dump to. + */ +RTDECL(void) RTMemTrackerDumpStatsToFile(bool fVerbose, const char *pszFilename); + + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_memtracker_h */ + diff --git a/include/iprt/message.h b/include/iprt/message.h new file mode 100644 index 00000000..b5a912c7 --- /dev/null +++ b/include/iprt/message.h @@ -0,0 +1,394 @@ +/** @file + * IPRT - Message Formatting. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_message_h +#define IPRT_INCLUDED_message_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_msg RTMsg - Message Formatting + * @ingroup grp_rt + * @{ + */ + +/** + * Sets the program name to use. + * + * @returns IPRT status code. + * @param pszFormat The program name format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgSetProgName(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Print error message to standard error. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "error: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgError(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Print error message to standard error. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "error: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(int) RTMsgErrorV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Same as RTMsgError() except for the return value. + * + * @returns @a enmExitCode + * @param enmExitCode What to exit code to return. This is mainly for + * saving some vertical space in the source file. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgErrorExit(RTEXITCODE enmExitCode, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Same as RTMsgErrorV() except for the return value. + * + * @returns @a enmExitCode + * @param enmExitCode What to exit code to return. This is mainly for + * saving some vertical space in the source file. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgErrorExitV(RTEXITCODE enmExitCode, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Same as RTMsgError() except for always returning RTEXITCODE_FAILURE. + * + * @returns RTEXITCODE_FAILURE + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgErrorExitFailure(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Same as RTMsgErrorV() except for always returning RTEXITCODE_FAILURE. + * + * @returns RTEXITCODE_FAILURE + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgErrorExitFailureV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Same as RTMsgError() except for the return value. + * + * @returns @a rcRet + * @param rcRet What IPRT status to return. This is mainly for + * saving some vertical space in the source file. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgErrorRc(int rcRet, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Same as RTMsgErrorV() except for the return value. + * + * @returns @a rcRet + * @param rcRet What IPRT status to return. This is mainly for + * saving some vertical space in the source file. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(int) RTMsgErrorRcV(int rcRet, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * For reporting syntax errors. + * + * @returns RTEXITCODE_SYNTAX + * @param pszFormat The message format string. Newline not needed. + * @param ... Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgSyntax(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * For reporting syntax errors. + * + * @returns RTEXITCODE_SYNTAX + * @param pszFormat The message format string. Newline not needed. + * @param va Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgSyntaxV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Print an error message for a RTR3Init failure and suggest an exit code. + * + * @code + * + * int rc = RTR3Init(); + * if (RT_FAILURE(rc)) + * return RTMsgInitFailure(rc); + * + * @endcode + * + * @returns Appropriate exit code. + * @param rcRTR3Init The status code returned by RTR3Init. + */ +RTDECL(RTEXITCODE) RTMsgInitFailure(int rcRTR3Init); + +/** + * Print informational message to standard error. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "warning: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgWarning(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Print informational message to standard error. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "warning: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(int) RTMsgWarningV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Print informational message to standard output. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "info: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgInfo(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Print informational message to standard output. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "info: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(int) RTMsgInfoV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + + +/** @defgroup grp_rt_msg_refentry Help generated from refentry/manpage. + * + * The refentry/manpage docbook source in doc/manual/en_US/man_* is processed by + * doc/manual/docbook-refentry-to-C-help.xsl and turned a set of the structures + * defined here. + * + * @{ + */ + +/** The non-breaking space character. + * @remarks We could've used U+00A0, but it is easier both to encode and to + * search and replace a single ASCII character. */ +#define RTMSGREFENTRY_NBSP '\b' + +/** @name REFENTRYSTR_SCOPE_XXX - Common string scoping and flags. + * @{ */ +/** Same scope as previous string table entry, flags are reset and can be + * ORed in. */ +#define RTMSGREFENTRYSTR_SCOPE_SAME UINT64_C(0) +/** Global scope. */ +#define RTMSGREFENTRYSTR_SCOPE_GLOBAL UINT64_C(0x0fffffffffffffff) +/** Scope mask. */ +#define RTMSGREFENTRYSTR_SCOPE_MASK UINT64_C(0x0fffffffffffffff) +/** Flags mask. */ +#define RTMSGREFENTRYSTR_FLAGS_MASK UINT64_C(0xf000000000000000) +/** Command synopsis, special hanging indent rules applies. */ +#define RTMSGREFENTRYSTR_FLAGS_SYNOPSIS RT_BIT_64(63) +/** @} */ + +/** String table entry for a refentry. */ +typedef struct RTMSGREFENTRYSTR +{ + /** The scope of the string. There are two predefined scopes, + * REFENTRYSTR_SCOPE_SAME and REFENTRYSTR_SCOPE_GLOBAL. The rest are + * reference entry specific. */ + uint64_t fScope; + /** The string. Non-breaking space is represented by the char + * REFENTRY_NBSP defines, just in case the string needs wrapping. There is + * no trailing newline, that's implicit. */ + const char *psz; +} RTMSGREFENTRYSTR; +/** Pointer to a read-only string table entry. */ +typedef const RTMSGREFENTRYSTR *PCRTMSGREFENTRYSTR; + +/** Refentry string table. */ +typedef struct RTMSGREFENTRYSTRTAB +{ + /** Number of strings. */ + uint16_t cStrings; + /** Reserved for future use. */ + uint16_t fReserved; + /** Pointer to the string table. */ + PCRTMSGREFENTRYSTR paStrings; +} RTMSGREFENTRYSTRTAB; +/** Pointer to a read-only string table. */ +typedef RTMSGREFENTRYSTRTAB const *PCRTMSGREFENTRYSTRTAB; + +/** + * Help extracted from a docbook refentry document. + */ +typedef struct RTMSGREFENTRY +{ + /** Internal reference entry identifier. */ + int64_t idInternal; + /** Usage synopsis. */ + RTMSGREFENTRYSTRTAB Synopsis; + /** Full help. */ + RTMSGREFENTRYSTRTAB Help; + /** Brief command description. */ + const char *pszBrief; +} RTMSGREFENTRY; +/** Pointer to a read-only refentry help extract structure. */ +typedef RTMSGREFENTRY const *PCRTMSGREFENTRY; + + +#ifndef IPRT_INCLUDED_stream_h +typedef struct RTSTREAM *PRTSTREAM; +#endif + + +/** + * Print the synopsis to the given stream. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pEntry The refentry to print the help for. + */ +RTDECL(int) RTMsgRefEntrySynopsis(PRTSTREAM pStrm, PCRTMSGREFENTRY pEntry); + + +/** + * Print the synopsis to the given stream. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pEntry The refentry to print the help for. + * @param fScope The scope inclusion mask. + * @param fFlags RTMSGREFENTRY_SYNOPSIS_F_XXX. + */ +RTDECL(int) RTMsgRefEntrySynopsisEx(PRTSTREAM pStrm, PCRTMSGREFENTRY pEntry, uint64_t fScope, uint32_t fFlags); +/** @name RTMSGREFENTRY_SYNOPSIS_F_XXX - Flags for RTMsgRefEntrySynopsisEx. + * @{ */ +/** Prefix the output with 'Usage:'. */ +#define RTMSGREFENTRY_SYNOPSIS_F_USAGE RT_BIT_32(0) +/** @} */ + + +/** + * Print the help text to the given stream. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pEntry The refentry to print the help for. + */ +RTDECL(int) RTMsgRefEntryHelp(PRTSTREAM pStrm, PCRTMSGREFENTRY pEntry); + +/** + * Print the help text to the given stream, extended version. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pEntry The refentry to print the help for. + * @param fScope The scope inclusion mask. + * @param fFlags Reserved, MBZ. + */ +RTDECL(int) RTMsgRefEntryHelpEx(PRTSTREAM pStrm, PCRTMSGREFENTRY pEntry, uint64_t fScope, uint32_t fFlags); + +/** + * Prints a string table. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pStrTab The string table. + * @param fScope The selection scope. + * @param pcPendingBlankLines In: Pending blank lines from previous string + * table. Out: Pending blank lines. + * @param pcLinesWritten Pointer to variable that should be incremented + * by the number of lines written. Optional. + */ +RTDECL(int) RTMsgRefEntryPrintStringTable(PRTSTREAM pStrm, PCRTMSGREFENTRYSTRTAB pStrTab, uint64_t fScope, + uint32_t *pcPendingBlankLines, uint32_t *pcLinesWritten); + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_message_h */ + diff --git a/include/iprt/mp.h b/include/iprt/mp.h new file mode 100644 index 00000000..e418bceb --- /dev/null +++ b/include/iprt/mp.h @@ -0,0 +1,521 @@ +/** @file + * IPRT - Multiprocessor. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_mp_h +#define IPRT_INCLUDED_mp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_mp RTMp - Multiprocessor + * @ingroup grp_rt + * @{ + */ + +/** + * Gets the identifier of the CPU executing the call. + * + * When called from a system mode where scheduling is active, like ring-3 or + * kernel mode with interrupts enabled on some systems, no assumptions should + * be made about the current CPU when the call returns. + * + * @returns CPU Id. + */ +RTDECL(RTCPUID) RTMpCpuId(void); + +/** + * Get the CPU set index of the CPU executing the call. + * + * Same scheduling warnings as for RTMpCpuId(). + * + * @returns CPU set index. + */ +RTDECL(int) RTMpCurSetIndex(void); + +/** + * Get the CPU set index and identifier of the CPU executing the call. + * + * Same scheduling warnings as for RTMpCpuId(). + * + * @returns CPU set index. + * @param pidCpu Where to return the CPU identifier. (not optional) + */ +RTDECL(int) RTMpCurSetIndexAndId(PRTCPUID pidCpu); + +/** + * Converts a CPU identifier to a CPU set index. + * + * This may or may not validate the presence of the CPU. + * + * @returns The CPU set index on success, -1 on failure. + * @param idCpu The identifier of the CPU. + */ +RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu); + +/** + * Converts a CPU set index to a a CPU identifier. + * + * This may or may not validate the presence of the CPU, so, use + * RTMpIsCpuPossible for that. + * + * @returns The corresponding CPU identifier, NIL_RTCPUID on failure. + * @param iCpu The CPU set index. + */ +RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu); + +/** + * Translates an NT process group member to a CPU set index. + * + * @returns CPU set index, -1 if not valid. + * @param idxGroup The CPU group. + * @param idxMember The CPU group member number. + * + * @remarks Only available on Windows. + */ +RTDECL(int) RTMpSetIndexFromCpuGroupMember(uint32_t idxGroup, uint32_t idxMember); + +/** + * Gets the member numbers for a CPU group. + * + * @returns Maximum number of group members. + * @param idxGroup The CPU group. + * @param pcActive Where to return the number of active members. + * + * @remarks Only available on Windows. + */ +RTDECL(uint32_t) RTMpGetCpuGroupCounts(uint32_t idxGroup, uint32_t *pcActive); + +/** + * Get the maximum number of CPU groups. + * + * @returns Maximum number of CPU groups. + * + * @remarks Only available on Windows. + */ +RTDECL(uint32_t) RTMpGetMaxCpuGroupCount(void); + +/** + * Gets the max CPU identifier (inclusive). + * + * Intended for brute force enumerations, but use with + * care as it may be expensive. + * + * @returns The current higest CPU identifier value. + */ +RTDECL(RTCPUID) RTMpGetMaxCpuId(void); + +/** + * Gets the size of a CPU array that is indexed by CPU set index. + * + * This takes both online, offline and hot-plugged cpus into account. + * + * @returns Number of elements. + * + * @remarks Use RTMpCpuIdToSetIndex to convert a RTCPUID into an array index. + */ +RTDECL(uint32_t) RTMpGetArraySize(void); + +/** + * Checks if a CPU exists in the system or may possibly be hotplugged later. + * + * @returns true/false accordingly. + * @param idCpu The identifier of the CPU. + */ +RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu); + +/** + * Gets set of the CPUs present in the system plus any that may + * possibly be hotplugged later. + * + * @returns pSet. + * @param pSet Where to put the set. + */ +RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet); + +/** + * Get the count of CPUs present in the system plus any that may + * possibly be hotplugged later. + * + * @returns The count. + * @remarks Don't use this for CPU array sizing, use RTMpGetArraySize instead. + */ +RTDECL(RTCPUID) RTMpGetCount(void); + +/** + * Get the count of physical CPU cores present in the system plus any that may + * possibly be hotplugged later. + * + * @returns The number of cores. + */ +RTDECL(RTCPUID) RTMpGetCoreCount(void); + +/** + * Gets set of the CPUs present that are currently online. + * + * @returns pSet. + * @param pSet Where to put the set. + */ +RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet); + +/** + * Get the count of CPUs that are currently online. + * + * @return The count. + */ +RTDECL(RTCPUID) RTMpGetOnlineCount(void); + +/** + * Get the count of physical CPU cores in the system with one or more online + * threads. + * + * @returns The number of online cores. + */ +RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void); + +/** + * Checks if a CPU is online or not. + * + * @returns true/false accordingly. + * @param idCpu The identifier of the CPU. + */ +RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu); + + +/** + * Gets set of the CPUs present in the system. + * + * @returns pSet. + * @param pSet Where to put the set. + */ +RTDECL(PRTCPUSET) RTMpGetPresentSet(PRTCPUSET pSet); + +/** + * Get the count of CPUs that are present in the system. + * + * @return The count. + */ +RTDECL(RTCPUID) RTMpGetPresentCount(void); + +/** + * Get the count of physical CPU cores present in the system. + * + * @returns The number of cores. + */ +RTDECL(RTCPUID) RTMpGetPresentCoreCount(void); + +/** + * Checks if a CPU is present in the system. + * + * @returns true/false accordingly. + * @param idCpu The identifier of the CPU. + */ +RTDECL(bool) RTMpIsCpuPresent(RTCPUID idCpu); + + +/** + * Get the current frequency of a CPU. + * + * The CPU must be online. + * + * @returns The frequency as MHz. 0 if the CPU is offline + * or the information is not available. + * @param idCpu The identifier of the CPU. + */ +RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu); + +/** + * Get the maximum frequency of a CPU. + * + * The CPU must be online. + * + * @returns The frequency as MHz. 0 if the CPU is offline + * or the information is not available. + * @param idCpu The identifier of the CPU. + */ +RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu); + +/** + * Get the CPU description string. + * + * The CPU must be online. + * + * @returns IPRT status code. + * @param idCpu The identifier of the CPU. NIL_RTCPUID can be used to + * indicate the current CPU. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + */ +RTDECL(int) RTMpGetDescription(RTCPUID idCpu, char *pszBuf, size_t cbBuf); + + +#ifdef IN_RING0 + +/** + * Check if there's work (DPCs on Windows) pending on the current CPU. + * + * @return true if there's pending work on the current CPU, false otherwise. + */ +RTDECL(bool) RTMpIsCpuWorkPending(void); + + +/** + * Worker function passed to RTMpOnAll, RTMpOnOthers and RTMpOnSpecific that + * is to be called on the target cpus. + * + * @param idCpu The identifier for the CPU the function is called on. + * @param pvUser1 The 1st user argument. + * @param pvUser2 The 2nd user argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTMPWORKER,(RTCPUID idCpu, void *pvUser1, void *pvUser2)); +/** Pointer to a FNRTMPWORKER. */ +typedef FNRTMPWORKER *PFNRTMPWORKER; + +/** @name RTMPON_F_XXX - RTMpOn flags. + * @{ */ +/** Caller doesn't care if pfnWorker is executed at the same time on the + * specified CPUs or not, as long as it gets executed. */ +#define RTMPON_F_WHATEVER_EXEC 0 +/** The caller insists on pfnWorker being executed more or less concurrently + * on the specified CPUs. */ +#define RTMPON_F_CONCURRENT_EXEC RT_BIT_32(1) +/** Mask of valid bits. */ +#define RTMPON_F_VALID_MASK UINT32_C(0x00000001) +/** @}*/ + +/** + * Checks if the RTMpOnAll() is safe with regards to all threads executing + * concurrently. + * + * If for instance, the RTMpOnAll() is implemented in a way where the threads + * might cause a classic deadlock, it is considered -not- concurrent safe. + * Windows currently is one such platform where it isn't safe. + * + * @returns true if RTMpOnAll() is concurrent safe, false otherwise. + */ +RTDECL(bool) RTMpOnAllIsConcurrentSafe(void); + +/** + * Executes a function on each (online) CPU in the system. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the system. + * + * @param pfnWorker The worker function. + * @param pvUser1 The first user argument for the worker. + * @param pvUser2 The second user argument for the worker. + * + * @remarks The execution isn't in any way guaranteed to be simultaneous, + * it might even be serial (cpu by cpu). + */ +RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); + +/** + * Executes a function on all other (online) CPUs in the system. + * + * The caller must disable preemption prior to calling this API if the outcome + * is to make any sense. But do *not* disable interrupts. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the system. + * + * @param pfnWorker The worker function. + * @param pvUser1 The first user argument for the worker. + * @param pvUser2 The second user argument for the worker. + * + * @remarks The execution isn't in any way guaranteed to be simultaneous, + * it might even be serial (cpu by cpu). + */ +RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); + +/** + * Executes a function on a specific CPU in the system. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the system. + * @retval VERR_CPU_OFFLINE if the CPU is offline. + * @retval VERR_CPU_NOT_FOUND if the CPU wasn't found. + * + * @param idCpu The id of the CPU. + * @param pfnWorker The worker function. + * @param pvUser1 The first user argument for the worker. + * @param pvUser2 The second user argument for the worker. + */ +RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); + +/** + * Executes a function on two specific CPUs in the system. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the + * system or if the specified modifier flag isn't supported. + * @retval VERR_CPU_OFFLINE if one or more of the CPUs are offline (see + * remarks). + * @retval VERR_CPU_NOT_FOUND if on or both of the CPUs weren't found. + * @retval VERR_NOT_ALL_CPUS_SHOWED if one of the CPUs didn't show. + * + * @param idCpu1 The id of the first CPU. + * @param idCpu2 The id of the second CPU. + * @param fFlags Combination of RTMPON_F_XXX flags. + * @param pfnWorker The worker function. + * @param pvUser1 The first user argument for the worker. + * @param pvUser2 The second user argument for the worker. + * + * @remarks There is a possible race between one (or both) of the CPUs going + * offline while setting up the call. The worker function must take + * this into account. + */ +RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, uint32_t fFlags, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); + +/** + * Indicates whether RTMpOnPair supports running the pfnWorker concurrently on + * both CPUs using RTMPON_F_CONCURRENT_EXEC. + * + * @returns true if supported, false if not. + */ +RTDECL(bool) RTMpOnPairIsConcurrentExecSupported(void); + + +/** + * Pokes the specified CPU. + * + * This should cause the execution on the CPU to be interrupted and forcing it + * to enter kernel context. It is optimized version of a RTMpOnSpecific call + * with a worker which returns immediately. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the + * system. The caller must not automatically assume that this API works + * when any of the RTMpOn* APIs works. This is because not all systems + * supports unicast MP events and this API will not be implemented as a + * broadcast. + * @retval VERR_CPU_OFFLINE if the CPU is offline. + * @retval VERR_CPU_NOT_FOUND if the CPU wasn't found. + * + * @param idCpu The id of the CPU to poke. + */ +RTDECL(int) RTMpPokeCpu(RTCPUID idCpu); + + +/** + * MP event, see FNRTMPNOTIFICATION. + */ +typedef enum RTMPEVENT +{ + /** The CPU goes online. */ + RTMPEVENT_ONLINE = 1, + /** The CPU goes offline. */ + RTMPEVENT_OFFLINE +} RTMPEVENT; + +/** + * Notification callback. + * + * The context this is called in differs a bit from platform to platform, so be + * careful while in here. + * + * On Windows we're running with IRQL=PASSIVE_LEVEL (reschedulable) according to + * the KeRegisterProcessorChangeCallback documentation - unrestricted API + * access. Probably not being called on the onlined/offlined CPU... + * + * On Solaris we're holding the cpu_lock, IPL/SPL/PIL is not yet known, however + * we will most likely -not- be firing on the CPU going offline/online. + * + * On Linux it looks like we're called with preemption enabled on any CPU and + * not necessarily on the CPU going offline/online. + * + * There is no callbacks for darwin at the moment, due to lack of suitable KPI. + * + * @param idCpu The CPU this applies to. + * @param enmEvent The event. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTMPNOTIFICATION,(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser)); +/** Pointer to a FNRTMPNOTIFICATION(). */ +typedef FNRTMPNOTIFICATION *PFNRTMPNOTIFICATION; + +/** + * Registers a notification callback for cpu events. + * + * On platforms which doesn't do cpu offline/online events this API + * will just be a no-op that pretends to work. + * + * @todo We'll be adding a flag to this soon to indicate whether the callback should be called on all + * CPUs that are currently online while it's being registered. This is to help avoid some race + * conditions (we'll hopefully be able to implement this on linux, solaris/win is no issue). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NO_MEMORY if a registration record cannot be allocated. + * @retval VERR_ALREADY_EXISTS if the pfnCallback and pvUser already exist + * in the callback list. + * + * @param pfnCallback The callback. + * @param pvUser The user argument to the callback function. + */ +RTDECL(int) RTMpNotificationRegister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser); + +/** + * This deregisters a notification callback registered via RTMpNotificationRegister(). + * + * The pfnCallback and pvUser arguments must be identical to the registration call + * of we won't find the right entry. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if no matching entry was found. + * + * @param pfnCallback The callback. + * @param pvUser The user argument to the callback function. + */ +RTDECL(int) RTMpNotificationDeregister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser); + +#endif /* IN_RING0 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_mp_h */ + diff --git a/include/iprt/net.h b/include/iprt/net.h new file mode 100644 index 00000000..647c15c3 --- /dev/null +++ b/include/iprt/net.h @@ -0,0 +1,1064 @@ +/** @file + * IPRT - Network Protocols. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_net_h +#define IPRT_INCLUDED_net_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_net RTNet - Network Protocols + * @ingroup grp_rt + * @{ + */ + +/** + * Converts an stringified Ethernet MAC address into the RTMAC representation. + * + * @todo This should be move to some generic part of the runtime. + * + * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on + * failure. + * + * @param pszAddr The address string to convert. + * @param pMacAddr Where to store the result. + */ +RTDECL(int) RTNetStrToMacAddr(const char *pszAddr, PRTMAC pMacAddr); + +/** + * IPv4 address. + */ +typedef RTUINT32U RTNETADDRIPV4; +AssertCompileSize(RTNETADDRIPV4, 4); +/** Pointer to a IPv4 address. */ +typedef RTNETADDRIPV4 *PRTNETADDRIPV4; +/** Pointer to a const IPv4 address. */ +typedef RTNETADDRIPV4 const *PCRTNETADDRIPV4; + +/** + * Tests if the given string is an IPv4 address. + * + * @returns boolean. + * @param pcszAddr String which may be an IPv4 address. + */ +RTDECL(bool) RTNetIsIPv4AddrStr(const char *pcszAddr); + +/** + * Tests if the given string is a wildcard IPv4 address. + * + * @returns boolean. + * @param pcszAddr String which may be an IPv4 address. + */ +RTDECL(bool) RTNetStrIsIPv4AddrAny(const char *pcszAddr); + +/** + * Parses dotted-decimal IPv4 address into RTNETADDRIPV4 representation. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param ppszNext Where to store the pointer to the first char + * following the address. (Optional) + * @param pAddr Where to store the result. + */ +RTDECL(int) RTNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr, char **ppszNext); + +/** + * Parses dotted-decimal IPv4 address into RTNETADDRIPV4 representation. + * Leading and trailing whitespace is ignored. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param pAddr Where to store the result. + */ +RTDECL(int) RTNetStrToIPv4Addr(const char *pcszAddr, PRTNETADDRIPV4 pAddr); + +/** + * Parses dotted-decimal IPv4 CIDR notation into RTNETADDRIPV4 + * representation and prefix length. Missing prefix specification is + * treated as exact address specification (prefix length 32). Leading + * and trailing whitespace is ignored. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param pAddr Where to store the address. + * @param piPrefix Where to store the prefix length; + */ +RTDECL(int) RTNetStrToIPv4Cidr(const char *pcszAddr, PRTNETADDRIPV4 pAddr, int *piPrefix); + +/** + * Verifies that RTNETADDRIPV4 is a valid contiguous netmask and + * computes its prefix length. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pMask The netmask to verify and convert. + * @param piPrefix Where to store the prefix length. (Optional) + */ +RTDECL(int) RTNetMaskToPrefixIPv4(PCRTNETADDRIPV4 pMask, int *piPrefix); + +/** + * Computes netmask corresponding to the prefix length. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param iPrefix The prefix to convert. + * @param pMask Where to store the netmask. + */ +RTDECL(int) RTNetPrefixToMaskIPv4(int iPrefix, PRTNETADDRIPV4 pMask); + + +/** + * IPv6 address. + */ +typedef RTUINT128U RTNETADDRIPV6; +AssertCompileSize(RTNETADDRIPV6, 16); +/** Pointer to a IPv6 address. */ +typedef RTNETADDRIPV6 *PRTNETADDRIPV6; +/** Pointer to a const IPv6 address. */ +typedef RTNETADDRIPV6 const *PCRTNETADDRIPV6; + +/** + * Tests if the given string is a valid IPv6 address. + * + * @returns @c true if it is, @c false if not. + * @param pszAddress String which may be an IPv6 address. + */ +RTDECL(bool) RTNetIsIPv6AddrStr(const char *pszAddress); + +/** + * Tests if the given string is a wildcard IPv6 address. + * + * @returns @c true if it is, @c false if not. + * @param pszAddress String which may be an IPv6 address. + */ +RTDECL(bool) RTNetStrIsIPv6AddrAny(const char *pszAddress); + +/** + * Parses IPv6 address into RTNETADDRIPV6 representation. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param ppszNext Where to store the pointer to the first char + * following the address. (Optional) + * @param pAddr Where to store the result. + */ +RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr, char **ppszNext); + +/** + * Parses IPv6 address into RTNETADDRIPV6 representation. + * Leading and trailing whitespace is ignored. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param ppszZone Where to store the pointer to the first char + * of the zone id. NULL is stored if there is + * no zone id. + * @param pAddr Where to store the result. + */ +RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, char **ppszZone); + +/** + * Verifies that RTNETADDRIPV6 is a valid contiguous netmask and + * computes its prefix length. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pMask The netmask to verify and convert. + * @param piPrefix Where to store the prefix length. (Optional) + */ +RTDECL(int) RTNetMaskToPrefixIPv6(PCRTNETADDRIPV6 pMask, int *piPrefix); + +/** + * Computes netmask corresponding to the prefix length. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param iPrefix The prefix to convert. + * @param pMask Where to store the netmask. + */ +RTDECL(int) RTNetPrefixToMaskIPv6(int iPrefix, PRTNETADDRIPV6 pMask); + +/** + * Parses IPv6 prefix notation into RTNETADDRIPV6 representation and + * prefix length. Missing prefix specification is treated as exact + * address specification (prefix length 128). Leading and trailing + * whitespace is ignored. + * + * "CIDR" in the name is a misnomer as IPv6 doesn't have network + * classes, but is parallel to the IPv4 name (and naming things is + * hard). + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param pAddr Where to store the address. + * @param piPrefix Where to store the prefix length; + */ +RTDECL(int) RTNetStrToIPv6Cidr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, int *piPrefix); + + +/** + * IPX address. + */ +#pragma pack(1) +typedef struct RTNETADDRIPX +{ + /** The network ID. */ + uint32_t Network; + /** The node ID. (Defaults to the MAC address apparently.) */ + RTMAC Node; +} RTNETADDRIPX; +#pragma pack() +AssertCompileSize(RTNETADDRIPX, 4+6); +/** Pointer to an IPX address. */ +typedef RTNETADDRIPX *PRTNETADDRIPX; +/** Pointer to a const IPX address. */ +typedef RTNETADDRIPX const *PCRTNETADDRIPX; + +/** + * Network address union. + * + * @remarks The size of this structure may change in the future. + */ +typedef union RTNETADDRU +{ + /** 64-bit view. */ + uint64_t au64[2]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 8-bit view. */ + uint8_t au8[16]; + /** IPv4 view. */ + RTNETADDRIPV4 IPv4; +#ifndef IPv6 /* Work around X11 and RDP defining IPv6 to 1. */ + /** IPv6 view. */ + RTNETADDRIPV6 IPv6; +#endif + /** IPX view. */ + RTNETADDRIPX Ipx; + /** MAC address view. */ + RTMAC Mac; +} RTNETADDRU; +AssertCompileSize(RTNETADDRU, 16); +/** Pointer to an address union. */ +typedef RTNETADDRU *PRTNETADDRU; +/** Pointer to a const address union. */ +typedef RTNETADDRU const *PCRTNETADDRU; + +/** + * Network address type. + * + * @remarks The value assignments may change in the future. + */ +typedef enum RTNETADDRTYPE +{ + /** The invalid 0 entry. */ + RTNETADDRTYPE_INVALID = 0, + /** IP version 4. */ + RTNETADDRTYPE_IPV4, + /** IP version 6. */ + RTNETADDRTYPE_IPV6, + /** IPX. */ + RTNETADDRTYPE_IPX, + /** MAC address. */ + RTNETADDRTYPE_MAC, + /** The end of the valid values. */ + RTNETADDRTYPE_END, + /** The usual 32-bit hack. */ + RTNETADDRTYPE_32_BIT_HACK = 0x7fffffff +} RTNETADDRTYPE; +/** Pointer to a network address type. */ +typedef RTNETADDRTYPE *PRTNETADDRTYPE; +/** Pointer to a const network address type. */ +typedef RTNETADDRTYPE const *PCRTNETADDRTYPE; + +/** + * Network address. + * + * @remarks The size and type values may change. + */ +typedef struct RTNETADDR +{ + /** The address union. */ + RTNETADDRU uAddr; + /** Indicates which view of @a u that is valid. */ + RTNETADDRTYPE enmType; + /** The port number for IPv4 and IPv6 addresses. This is set to + * RTNETADDR_NA_PORT if not applicable. */ + uint32_t uPort; +} RTNETADDR; +/** Pointer to a network address. */ +typedef RTNETADDR *PRTNETADDR; +/** Pointer to a const network address. */ +typedef RTNETADDR const *PCRTNETADDR; + +/** The not applicable value of RTNETADDR::uPort value use to inid. */ +#define RTNETADDR_PORT_NA UINT32_MAX + +/** + * Ethernet header. + */ +#pragma pack(1) +typedef struct RTNETETHERHDR +{ + RTMAC DstMac; + RTMAC SrcMac; + /** Ethernet frame type or frame size, depending on the kind of ethernet. + * This is big endian on the wire. */ + uint16_t EtherType; +} RTNETETHERHDR; +#pragma pack() +AssertCompileSize(RTNETETHERHDR, 14); +/** Pointer to an ethernet header. */ +typedef RTNETETHERHDR *PRTNETETHERHDR; +/** Pointer to a const ethernet header. */ +typedef RTNETETHERHDR const *PCRTNETETHERHDR; + +/** @name EtherType (RTNETETHERHDR::EtherType) + * @{ */ +#define RTNET_ETHERTYPE_IPV4 UINT16_C(0x0800) +#define RTNET_ETHERTYPE_ARP UINT16_C(0x0806) +#define RTNET_ETHERTYPE_IPV6 UINT16_C(0x86dd) +#define RTNET_ETHERTYPE_VLAN UINT16_C(0x8100) +#define RTNET_ETHERTYPE_IPX_1 UINT16_C(0x8037) +#define RTNET_ETHERTYPE_IPX_2 UINT16_C(0x8137) +#define RTNET_ETHERTYPE_IPX_3 UINT16_C(0x8138) +/** @} */ + + +/** + * IPv4 header. + * All is bigendian on the wire. + */ +#pragma pack(1) +typedef struct RTNETIPV4 +{ +#ifdef RT_BIG_ENDIAN + unsigned int ip_v : 4; + unsigned int ip_hl : 4; + unsigned int ip_tos : 8; + unsigned int ip_len : 16; +#else + /** 00:0 - Header length given as a 32-bit word count. */ + unsigned int ip_hl : 4; + /** 00:4 - Header version. */ + unsigned int ip_v : 4; + /** 01 - Type of service. */ + unsigned int ip_tos : 8; + /** 02 - Total length (header + data). */ + unsigned int ip_len : 16; +#endif + /** 04 - Packet idenficiation. */ + uint16_t ip_id; + /** 06 - Offset if fragmented. */ + uint16_t ip_off; + /** 08 - Time to live. */ + uint8_t ip_ttl; + /** 09 - Protocol. */ + uint8_t ip_p; + /** 0a - Header check sum. */ + uint16_t ip_sum; + /** 0c - Source address. */ + RTNETADDRIPV4 ip_src; + /** 10 - Destination address. */ + RTNETADDRIPV4 ip_dst; + /** 14 - Options (optional). */ + uint32_t ip_options[1]; +} RTNETIPV4; +#pragma pack() +AssertCompileSize(RTNETIPV4, 6 * 4); +/** Pointer to a IPv4 header. */ +typedef RTNETIPV4 *PRTNETIPV4; +/** Pointer to a const IPv4 header. */ +typedef RTNETIPV4 const *PCRTNETIPV4; + +/** The minimum IPv4 header length (in bytes). + * Up to and including RTNETIPV4::ip_dst. */ +#define RTNETIPV4_MIN_LEN (20) + + +/** @name IPv4 Protocol Numbers + * @{ */ +/** IPv4: ICMP */ +#define RTNETIPV4_PROT_ICMP (1) +/** IPv4: TCP */ +#define RTNETIPV4_PROT_TCP (6) +/** IPv4: UDP */ +#define RTNETIPV4_PROT_UDP (17) +/** @} */ + +/** @name Common IPv4 Port Assignments + * @{ + */ +/** Boostrap Protocol / DHCP) Server. */ +#define RTNETIPV4_PORT_BOOTPS (67) +/** Boostrap Protocol / DHCP) Client. */ +#define RTNETIPV4_PORT_BOOTPC (68) +/** @} */ + +/** @name IPv4 Flags + * @{ */ +/** IPv4: Don't fragment */ +#define RTNETIPV4_FLAGS_DF (0x4000) +/** IPv4: More fragments */ +#define RTNETIPV4_FLAGS_MF (0x2000) +/** @} */ + +RTDECL(uint16_t) RTNetIPv4HdrChecksum(PCRTNETIPV4 pIpHdr); +RTDECL(bool) RTNetIPv4IsHdrValid(PCRTNETIPV4 pIpHdr, size_t cbHdrMax, size_t cbPktMax, bool fChecksum); +RTDECL(uint32_t) RTNetIPv4PseudoChecksum(PCRTNETIPV4 pIpHdr); +RTDECL(uint32_t) RTNetIPv4PseudoChecksumBits(RTNETADDRIPV4 SrcAddr, RTNETADDRIPV4 DstAddr, uint8_t bProtocol, uint16_t cbPkt); +RTDECL(uint32_t) RTNetIPv4AddDataChecksum(void const *pvData, size_t cbData, uint32_t u32Sum, bool *pfOdd); +RTDECL(uint16_t) RTNetIPv4FinalizeChecksum(uint32_t u32Sum); + + +/** + * IPv6 header. + * All is bigendian on the wire. + */ +#pragma pack(1) +typedef struct RTNETIPV6 +{ + /** Version (4 bits), Traffic Class (8 bits) and Flow Lable (20 bits). + * @todo this is probably mislabeled - ip6_flow vs. ip6_vfc, fix later. */ + uint32_t ip6_vfc; + /** 04 - Payload length, including extension headers. */ + uint16_t ip6_plen; + /** 06 - Next header type (RTNETIPV4_PROT_XXX). */ + uint8_t ip6_nxt; + /** 07 - Hop limit. */ + uint8_t ip6_hlim; + /** xx - Source address. */ + RTNETADDRIPV6 ip6_src; + /** xx - Destination address. */ + RTNETADDRIPV6 ip6_dst; +} RTNETIPV6; +#pragma pack() +AssertCompileSize(RTNETIPV6, 8 + 16 + 16); +/** Pointer to a IPv6 header. */ +typedef RTNETIPV6 *PRTNETIPV6; +/** Pointer to a const IPv6 header. */ +typedef RTNETIPV6 const *PCRTNETIPV6; + +/** The minimum IPv6 header length (in bytes). + * Up to and including RTNETIPV6::ip6_dst. */ +#define RTNETIPV6_MIN_LEN (40) +#define RTNETIPV6_ICMPV6_ND_WITH_LLA_OPT_MIN_LEN (32) + +RTDECL(uint32_t) RTNetIPv6PseudoChecksum(PCRTNETIPV6 pIpHdr); +RTDECL(uint32_t) RTNetIPv6PseudoChecksumEx(PCRTNETIPV6 pIpHdr, uint8_t bProtocol, uint16_t cbPkt); +RTDECL(uint32_t) RTNetIPv6PseudoChecksumBits(PCRTNETADDRIPV6 pSrcAddr, PCRTNETADDRIPV6 pDstAddr, + uint8_t bProtocol, uint16_t cbPkt); + + +/** + * UDP header. + */ +#pragma pack(1) +typedef struct RTNETUDP +{ + /** The source port. */ + uint16_t uh_sport; + /** The destination port. */ + uint16_t uh_dport; + /** The length of the UDP header and associated data. */ + uint16_t uh_ulen; + /** The checksum of the pseudo header, the UDP header and the data. */ + uint16_t uh_sum; +} RTNETUDP; +#pragma pack() +AssertCompileSize(RTNETUDP, 8); +/** Pointer to an UDP header. */ +typedef RTNETUDP *PRTNETUDP; +/** Pointer to a const UDP header. */ +typedef RTNETUDP const *PCRTNETUDP; + +/** The minimum UDP packet length (in bytes). (RTNETUDP::uh_ulen) */ +#define RTNETUDP_MIN_LEN (8) + +RTDECL(uint16_t) RTNetUDPChecksum(uint32_t u32Sum, PCRTNETUDP pUdpHdr); +RTDECL(uint32_t) RTNetIPv4AddUDPChecksum(PCRTNETUDP pUdpHdr, uint32_t u32Sum); +RTDECL(uint16_t) RTNetIPv4UDPChecksum(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, void const *pvData); +RTDECL(bool) RTNetIPv4IsUDPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, size_t cbPktMax); +RTDECL(bool) RTNetIPv4IsUDPValid(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, void const *pvData, size_t cbPktMax, bool fChecksum); + + +/** + * IPv4 BOOTP / DHCP packet. + */ +#pragma pack(1) +typedef struct RTNETBOOTP +{ + /** 00 - The packet opcode (RTNETBOOTP_OP_*). */ + uint8_t bp_op; + /** 01 - Hardware address type. Same as RTNETARPHDR::ar_htype. */ + uint8_t bp_htype; + /** 02 - Hardware address length. */ + uint8_t bp_hlen; + /** 03 - Gateway hops. */ + uint8_t bp_hops; + /** 04 - Transaction ID. */ + uint32_t bp_xid; + /** 08 - Seconds since boot started. */ + uint16_t bp_secs; + /** 0a - Unused (BOOTP) / Flags (DHCP) (RTNET_DHCP_FLAGS_*). */ + uint16_t bp_flags; + /** 0c - Client IPv4 address. */ + RTNETADDRIPV4 bp_ciaddr; + /** 10 - Your IPv4 address. */ + RTNETADDRIPV4 bp_yiaddr; + /** 14 - Server IPv4 address. */ + RTNETADDRIPV4 bp_siaddr; + /** 18 - Gateway IPv4 address. */ + RTNETADDRIPV4 bp_giaddr; + /** 1c - Client hardware address. */ + union + { + uint8_t au8[16]; + RTMAC Mac; + } bp_chaddr; + /** 2c - Server name. */ + uint8_t bp_sname[64]; + /** 6c - File name / more DHCP options. */ + uint8_t bp_file[128]; + /** ec - Vendor specific area (BOOTP) / Options (DHCP). + * @remark This is really 312 bytes in the DHCP version. */ + union + { + uint8_t au8[128]; + struct DHCP + { + /** ec - The DHCP cookie (RTNET_DHCP_COOKIE). */ + uint32_t dhcp_cookie; + /** f0 - The DHCP options. */ + uint8_t dhcp_opts[124]; + } Dhcp; + } bp_vend; + +} RTNETBOOTP; +#pragma pack() +AssertCompileSize(RTNETBOOTP, 0xec + 128); +/** Pointer to a BOOTP / DHCP packet. */ +typedef RTNETBOOTP *PRTNETBOOTP; +/** Pointer to a const BOOTP / DHCP packet. */ +typedef RTNETBOOTP const *PCRTNETBOOTP; + +/** Minimum BOOTP packet length. For quick validation, no standard thing really. */ +#define RTNETBOOTP_MIN_LEN 0xec +/** Minimum DHCP packet length. For quick validation, no standard thing really. */ +#define RTNETBOOTP_DHCP_MIN_LEN 0xf1 + +/** The normal size of the a DHCP packet (i.e. a RTNETBOOTP). + * Same as RTNET_DHCP_OPT_SIZE, just expressed differently. */ +#define RTNET_DHCP_NORMAL_SIZE (0xec + 4 + RTNET_DHCP_OPT_SIZE) +/** The normal size of RTNETBOOTP::bp_vend::Dhcp::dhcp_opts. */ +#define RTNET_DHCP_OPT_SIZE (312 - 4) + +/** @name BOOTP packet opcode values + * @{ */ +#define RTNETBOOTP_OP_REQUEST 1 +#define RTNETBOOTP_OP_REPLY 2 +/** @} */ + +/** @name DHCP flags (RTNETBOOTP::bp_flags) + * @{ */ +#define RTNET_DHCP_FLAGS_NO_BROADCAST UINT16_C(0x8000) /** @todo check test!!! */ +/** @} */ + +/** The DHCP cookie (network endian). */ +#define RTNET_DHCP_COOKIE UINT32_C(0x63825363) + +/** + * An IPv4 DHCP option header. + */ +typedef struct RTNETDHCPOPT +{ + /** 00 - The DHCP option. */ + uint8_t dhcp_opt; + /** 01 - The data length (excluding this header). */ + uint8_t dhcp_len; + /* 02 - The option data follows here, optional and of variable length. */ +} RTNETDHCPOPT; +AssertCompileSize(RTNETDHCPOPT, 2); +/** Pointer to a DHCP option header. */ +typedef RTNETDHCPOPT *PRTNETDHCPOPT; +/** Pointer to a const DHCP option header. */ +typedef RTNETDHCPOPT const *PCRTNETDHCPOPT; + +/** @name DHCP options + * @{ */ +/** 1 byte padding, this has no dhcp_len field. */ +#define RTNET_DHCP_OPT_PAD 0 + +/** The subnet mask. */ +#define RTNET_DHCP_OPT_SUBNET_MASK 1 +/** The time offset. */ +#define RTNET_DHCP_OPT_TIME_OFFSET 2 +/** The routers for the subnet. */ +#define RTNET_DHCP_OPT_ROUTERS 3 +/** Domain Name Server. */ +#define RTNET_DHCP_OPT_DNS 6 +/** Host name. */ +#define RTNET_DHCP_OPT_HOST_NAME 12 +/** Domain name. */ +#define RTNET_DHCP_OPT_DOMAIN_NAME 15 + +/** The requested address. */ +#define RTNET_DHCP_OPT_REQ_ADDR 50 +/** The lease time in seconds. */ +#define RTNET_DHCP_OPT_LEASE_TIME 51 +/** Option overload. + * Indicates that the bp_file and/or bp_sname holds contains DHCP options. */ +#define RTNET_DHCP_OPT_OPTION_OVERLOAD 52 +/** Have a 8-bit message type value as data, see RTNET_DHCP_MT_*. */ +#define RTNET_DHCP_OPT_MSG_TYPE 53 +/** Server ID. */ +#define RTNET_DHCP_OPT_SERVER_ID 54 +/** Parameter request list. */ +#define RTNET_DHCP_OPT_PARAM_REQ_LIST 55 +/** The maximum DHCP message size a client is willing to accept. */ +#define RTNET_DHCP_OPT_MAX_DHCP_MSG_SIZE 57 +/** Client ID. */ +#define RTNET_DHCP_OPT_CLIENT_ID 61 +/** TFTP server name. */ +#define RTNET_DHCP_OPT_TFTP_SERVER_NAME 66 +/** Bootfile name. */ +#define RTNET_DHCP_OPT_BOOTFILE_NAME 67 + +/** Marks the end of the DHCP options, this has no dhcp_len field. */ +#define RTNET_DHCP_OPT_END 255 +/** @} */ + +/** @name DHCP Option overload flags (option 52) + * @{ */ +#define RTNET_DHCP_OPTION_OVERLOAD_FILE 1 +#define RTNET_DHCP_OPTION_OVERLOAD_SNAME 2 +#define RTNET_DHCP_OPTION_OVERLOAD_MASK 3 +/** @} */ + +/** @name DHCP Message Types (option 53) + * @{ */ +#define RTNET_DHCP_MT_DISCOVER 1 +#define RTNET_DHCP_MT_OFFER 2 +#define RTNET_DHCP_MT_REQUEST 3 +#define RTNET_DHCP_MT_DECLINE 4 +#define RTNET_DHCP_MT_ACK 5 +#define RTNET_DHCP_MT_NAC 6 +#define RTNET_DHCP_MT_RELEASE 7 +#define RTNET_DHCP_MT_INFORM 8 +/** @} */ + +/** @name DHCP Flags + * @{ */ +#define RTNET_DHCP_FLAG_BROADCAST 0x8000 +/** @} */ + +RTDECL(bool) RTNetIPv4IsDHCPValid(PCRTNETUDP pUdpHdr, PCRTNETBOOTP pDhcp, size_t cbDhcp, uint8_t *pMsgType); + + +/** + * IPv4 DHCP packet. + * @deprecated Use RTNETBOOTP. + */ +#pragma pack(1) +typedef struct RTNETDHCP +{ + /** 00 - The packet opcode. */ + uint8_t Op; + /** Hardware address type. */ + uint8_t HType; + /** Hardware address length. */ + uint8_t HLen; + uint8_t Hops; + uint32_t XID; + uint16_t Secs; + uint16_t Flags; + /** Client IPv4 address. */ + RTNETADDRIPV4 CIAddr; + /** Your IPv4 address. */ + RTNETADDRIPV4 YIAddr; + /** Server IPv4 address. */ + RTNETADDRIPV4 SIAddr; + /** Gateway IPv4 address. */ + RTNETADDRIPV4 GIAddr; + /** Client hardware address. */ + uint8_t CHAddr[16]; + /** Server name. */ + uint8_t SName[64]; + uint8_t File[128]; + uint8_t abMagic[4]; + uint8_t DhcpOpt; + uint8_t DhcpLen; /* 1 */ + uint8_t DhcpReq; + uint8_t abOptions[57]; +} RTNETDHCP; +#pragma pack() +/** @todo AssertCompileSize(RTNETDHCP, ); */ +/** Pointer to a DHCP packet. */ +typedef RTNETDHCP *PRTNETDHCP; +/** Pointer to a const DHCP packet. */ +typedef RTNETDHCP const *PCRTNETDHCP; + + +/** + * TCP packet. + */ +#pragma pack(1) +typedef struct RTNETTCP +{ + /** 00 - The source port. */ + uint16_t th_sport; + /** 02 - The destination port. */ + uint16_t th_dport; + /** 04 - The sequence number. */ + uint32_t th_seq; + /** 08 - The acknowledgement number. */ + uint32_t th_ack; +#ifdef RT_BIG_ENDIAN + unsigned int th_win : 16; + unsigned int th_flags : 8; + unsigned int th_off : 4; + unsigned int th_x2 : 4; +#else + /** 0c:0 - Reserved. */ + unsigned int th_x2 : 4; + /** 0c:4 - The data offset given as a dword count from the start of this header. */ + unsigned int th_off : 4; + /** 0d - flags. */ + unsigned int th_flags : 8; + /** 0e - The window. */ + unsigned int th_win : 16; +#endif + /** 10 - The checksum of the pseudo header, the TCP header and the data. */ + uint16_t th_sum; + /** 12 - The urgent pointer. */ + uint16_t th_urp; + /* (options follows here and then the data (aka text).) */ +} RTNETTCP; +#pragma pack() +AssertCompileSize(RTNETTCP, 20); +/** Pointer to a TCP packet. */ +typedef RTNETTCP *PRTNETTCP; +/** Pointer to a const TCP packet. */ +typedef RTNETTCP const *PCRTNETTCP; + +/** The minimum TCP header length (in bytes). (RTNETTCP::th_off * 4) */ +#define RTNETTCP_MIN_LEN (20) + +/** @name TCP flags (RTNETTCP::th_flags) + * @{ */ +#define RTNETTCP_F_FIN 0x01 +#define RTNETTCP_F_SYN 0x02 +#define RTNETTCP_F_RST 0x04 +#define RTNETTCP_F_PSH 0x08 +#define RTNETTCP_F_ACK 0x10 +#define RTNETTCP_F_URG 0x20 +#define RTNETTCP_F_ECE 0x40 +#define RTNETTCP_F_CWR 0x80 +/** @} */ + +RTDECL(uint16_t) RTNetTCPChecksum(uint32_t u32Sum, PCRTNETTCP pTcpHdr, void const *pvData, size_t cbData); +RTDECL(uint32_t) RTNetIPv4AddTCPChecksum(PCRTNETTCP pTcpHdr, uint32_t u32Sum); +RTDECL(uint16_t) RTNetIPv4TCPChecksum(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, void const *pvData); +RTDECL(bool) RTNetIPv4IsTCPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, size_t cbHdrMax, size_t cbPktMax); +RTDECL(bool) RTNetIPv4IsTCPValid(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, size_t cbHdrMax, void const *pvData, + size_t cbPktMax, bool fChecksum); + + +/** + * IPv4 ICMP packet header. + */ +#pragma pack(1) +typedef struct RTNETICMPV4HDR +{ + /** 00 - The ICMP message type. */ + uint8_t icmp_type; + /** 01 - Type specific code that further qualifies the message. */ + uint8_t icmp_code; + /** 02 - Checksum of the ICMP message. */ + uint16_t icmp_cksum; +} RTNETICMPV4HDR; +#pragma pack() +AssertCompileSize(RTNETICMPV4HDR, 4); +/** Pointer to an ICMP packet header. */ +typedef RTNETICMPV4HDR *PRTNETICMPV4HDR; +/** Pointer to a const ICMP packet header. */ +typedef RTNETICMPV4HDR const *PCRTNETICMPV4HDR; + +/** @name ICMP (v4) message types. + * @{ */ +#define RTNETICMPV4_TYPE_ECHO_REPLY 0 +#define RTNETICMPV4_TYPE_ECHO_REQUEST 8 +#define RTNETICMPV4_TYPE_TRACEROUTE 30 +/** @} */ + +/** + * IPv4 ICMP ECHO Reply & Request packet. + */ +#pragma pack(1) +typedef struct RTNETICMPV4ECHO +{ + /** 00 - The ICMP header. */ + RTNETICMPV4HDR Hdr; + /** 04 - The identifier to help the requestor match up the reply. + * Can be 0. Typically fixed value. */ + uint16_t icmp_id; + /** 06 - The sequence number to help the requestor match up the reply. + * Can be 0. Typically incrementing between requests. */ + uint16_t icmp_seq; + /** 08 - Variable length data that is to be returned unmodified in the reply. */ + uint8_t icmp_data[1]; +} RTNETICMPV4ECHO; +#pragma pack() +AssertCompileSize(RTNETICMPV4ECHO, 9); +/** Pointer to an ICMP ECHO packet. */ +typedef RTNETICMPV4ECHO *PRTNETICMPV4ECHO; +/** Pointer to a const ICMP ECHO packet. */ +typedef RTNETICMPV4ECHO const *PCRTNETICMPV4ECHO; + +/** + * IPv4 ICMP TRACEROUTE packet. + * This is an reply to an IP packet with the traceroute option set. + */ +#pragma pack(1) +typedef struct RTNETICMPV4TRACEROUTE +{ + /** 00 - The ICMP header. */ + RTNETICMPV4HDR Hdr; + /** 04 - Identifier copied from the traceroute option's ID number. */ + uint16_t icmp_id; + /** 06 - Unused. (Possibly an icmp_seq?) */ + uint16_t icmp_void; + /** 08 - Outbound hop count. From the IP packet causing this message. */ + uint16_t icmp_ohc; + /** 0a - Return hop count. From the IP packet causing this message. */ + uint16_t icmp_rhc; + /** 0c - Output link speed, 0 if not known. */ + uint32_t icmp_speed; + /** 10 - Output link MTU, 0 if not known. */ + uint32_t icmp_mtu; +} RTNETICMPV4TRACEROUTE; +#pragma pack() +AssertCompileSize(RTNETICMPV4TRACEROUTE, 20); +/** Pointer to an ICMP TRACEROUTE packet. */ +typedef RTNETICMPV4TRACEROUTE *PRTNETICMPV4TRACEROUTE; +/** Pointer to a const ICMP TRACEROUTE packet. */ +typedef RTNETICMPV4TRACEROUTE const *PCRTNETICMPV4TRACEROUTE; + +/** @todo add more ICMPv4 as needed. */ + +/** + * IPv4 ICMP union packet. + */ +typedef union RTNETICMPV4 +{ + RTNETICMPV4HDR Hdr; + RTNETICMPV4ECHO Echo; + RTNETICMPV4TRACEROUTE Traceroute; +} RTNETICMPV4; +/** Pointer to an ICMP union packet. */ +typedef RTNETICMPV4 *PRTNETICMPV4; +/** Pointer to a const ICMP union packet. */ +typedef RTNETICMPV4 const *PCRTNETICMPV4; + + +/** + * IPv6 ICMP packet header. + */ +#pragma pack(1) +typedef struct RTNETICMPV6HDR +{ + /** 00 - The ICMPv6 message type. */ + uint8_t icmp6_type; + /** 01 - Type specific code that further qualifies the message. */ + uint8_t icmp6_code; + /** 02 - Checksum of the ICMPv6 message. */ + uint16_t icmp6_cksum; +} RTNETICMPV6HDR; +#pragma pack() +AssertCompileSize(RTNETICMPV6HDR, 4); +/** Pointer to an ICMPv6 packet header. */ +typedef RTNETICMPV6HDR *PRTNETICMPV6HDR; +/** Pointer to a const ICMP packet header. */ +typedef RTNETICMPV6HDR const *PCRTNETICMPV6HDR; + +#define RTNETIPV6_PROT_ICMPV6 (58) + +/** @name Internet Control Message Protocol version 6 (ICMPv6) message types. + * @{ */ +#define RTNETIPV6_ICMP_TYPE_RS 133 +#define RTNETIPV6_ICMP_TYPE_RA 134 +#define RTNETIPV6_ICMP_TYPE_NS 135 +#define RTNETIPV6_ICMP_TYPE_NA 136 +#define RTNETIPV6_ICMP_TYPE_RDR 137 +/** @} */ + +/** @name Neighbor Discovery option types + * @{ */ +#define RTNETIPV6_ICMP_ND_SLLA_OPT (1) +#define RTNETIPV6_ICMP_ND_TLLA_OPT (2) +/** @} */ + +/** ICMPv6 ND Source/Target Link Layer Address option */ +#pragma pack(1) +typedef struct RTNETNDP_LLA_OPT +{ + uint8_t type; + uint8_t len; + RTMAC lla; +} RTNETNDP_LLA_OPT; +#pragma pack() + +AssertCompileSize(RTNETNDP_LLA_OPT, 1+1+6); + +typedef RTNETNDP_LLA_OPT *PRTNETNDP_LLA_OPT; +typedef RTNETNDP_LLA_OPT const *PCRTNETNDP_LLA_OPT; + +/** ICMPv6 ND Neighbor Sollicitation */ +#pragma pack(1) +typedef struct RTNETNDP +{ + /** 00 - The ICMPv6 header. */ + RTNETICMPV6HDR Hdr; + /** 04 - reserved */ + uint32_t reserved; + /** 08 - target address */ + RTNETADDRIPV6 target_address; +} RTNETNDP; +#pragma pack() +AssertCompileSize(RTNETNDP, 4+4+16); +/** Pointer to a NDP ND packet. */ +typedef RTNETNDP *PRTNETNDP; +/** Pointer to a const NDP NS packet. */ +typedef RTNETNDP const *PCRTNETNDP; + + +/** + * Ethernet ARP header. + */ +#pragma pack(1) +typedef struct RTNETARPHDR +{ + /** The hardware type. */ + uint16_t ar_htype; + /** The protocol type (ethertype). */ + uint16_t ar_ptype; + /** The hardware address length. */ + uint8_t ar_hlen; + /** The protocol address length. */ + uint8_t ar_plen; + /** The operation. */ + uint16_t ar_oper; +} RTNETARPHDR; +#pragma pack() +AssertCompileSize(RTNETARPHDR, 8); +/** Pointer to an ethernet ARP header. */ +typedef RTNETARPHDR *PRTNETARPHDR; +/** Pointer to a const ethernet ARP header. */ +typedef RTNETARPHDR const *PCRTNETARPHDR; + +/** ARP hardware type - ethernet. */ +#define RTNET_ARP_ETHER UINT16_C(1) + +/** @name ARP operations + * @{ */ +#define RTNET_ARPOP_REQUEST UINT16_C(1) /**< Request hardware address given a protocol address (ARP). */ +#define RTNET_ARPOP_REPLY UINT16_C(2) +#define RTNET_ARPOP_REVREQUEST UINT16_C(3) /**< Request protocol address given a hardware address (RARP). */ +#define RTNET_ARPOP_REVREPLY UINT16_C(4) +#define RTNET_ARPOP_INVREQUEST UINT16_C(8) /**< Inverse ARP. */ +#define RTNET_ARPOP_INVREPLY UINT16_C(9) +/** Check if an ARP operation is a request or not. */ +#define RTNET_ARPOP_IS_REQUEST(Op) ((Op) & 1) +/** Check if an ARP operation is a reply or not. */ +#define RTNET_ARPOP_IS_REPLY(Op) (!RTNET_ARPOP_IS_REQUEST(Op)) +/** @} */ + + +/** + * Ethernet IPv4 + 6-byte MAC ARP request packet. + */ +#pragma pack(1) +typedef struct RTNETARPIPV4 +{ + /** ARP header. */ + RTNETARPHDR Hdr; + /** The sender hardware address. */ + RTMAC ar_sha; + /** The sender protocol address. */ + RTNETADDRIPV4 ar_spa; + /** The target hardware address. */ + RTMAC ar_tha; + /** The target protocol address. */ + RTNETADDRIPV4 ar_tpa; +} RTNETARPIPV4; +#pragma pack() +AssertCompileSize(RTNETARPIPV4, 8+6+4+6+4); +/** Pointer to an ethernet IPv4+MAC ARP request packet. */ +typedef RTNETARPIPV4 *PRTNETARPIPV4; +/** Pointer to a const ethernet IPv4+MAC ARP request packet. */ +typedef RTNETARPIPV4 const *PCRTNETARPIPV4; + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_net_h */ + diff --git a/include/iprt/nocrt/Makefile.kup b/include/iprt/nocrt/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/nocrt/algorithm b/include/iprt/nocrt/algorithm new file mode 100644 index 00000000..bf6102f8 --- /dev/null +++ b/include/iprt/nocrt/algorithm @@ -0,0 +1,164 @@ +/** @file + * IPRT / No-CRT - Minimal C++ algorithm header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_algorithm +#define VBOX_INCLUDED_SRC_nocrt_algorithm +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4643) /* warning C4643: Forward declaring 'ios_base' in namespace std is not permitted by the C++ Standard */ +#endif + +namespace std +{ + /** + * Swap the values pointed to by the two references. + */ + template + void swap(a_Type &a_rObj1, a_Type &a_rObj2) + { + a_Type Tmp(a_rObj1); + a_rObj1 = a_rObj2; + a_rObj2 = Tmp; + } + + /** + * Swap the values pointed to by two forward iterators. + */ + template + void iter_swap(a_ForwardIt1 a_It1, a_ForwardIt2 a_It2) + { + swap(*a_It1, *a_It2); + } + + template + void sort(a_RandomIt a_ItBegin, a_RandomIt a_ItEnd) + { + /* Note! Using shell sort here because it's tiny and we've got code for it. */ + /** @todo replace with faster code. */ + + /* Anything worth sorting? */ + std::size_t const cElements = a_ItEnd - a_ItBegin; + if (cElements >= 1) + { + /* Loop on decreasing gap, ending with 1: */ + std::size_t cGap = (cElements + 1) / 2; + while (cGap > 0) + { + /* Iterate from cGap till the end: */ + for (std::size_t i = cGap; i < cElements; i++) + { + /* Find the best suitable location for the item at 'i' comparing + backwards in steps of 'cGap', swapping the item at 'i' with the + one at '-cGap*j' if it's smaller, stopping if it's larger. + + Note! Original algorithm would make a copy of the item, this version + avoids extra copies of sorted items at the cost of extra copies + when dealing with unsorted ones a small cGaps values. */ + a_RandomIt ItCur = a_ItBegin + i; + size_t j = i; + do + { + j -= cGap; + a_RandomIt ItAtGap = a_ItBegin + j; + if (*ItAtGap < *ItCur) + break; + std::iter_swap(ItAtGap, ItCur); + ItCur = ItAtGap; + } while (j >= cGap); + } + + /* This does not generate the most optimal gap sequence, but it has the + advantage of being simple and avoid floating point. */ + cGap /= 2; + } + } + } + + template + void sort(a_RandomIt a_ItBegin, a_RandomIt a_ItEnd, a_FnCompareType a_fnComp) + { + /* Note! Using shell sort here because it's tiny and we've got code for it. */ + /** @todo replace with faster code. */ + + /* Anything worth sorting? */ + std::size_t const cElements = a_ItEnd - a_ItBegin; + if (cElements >= 1) + { + /* Loop on decreasing gap, ending with 1: */ + std::size_t cGap = (cElements + 1) / 2; + while (cGap > 0) + { + /* Iterate from cGap till the end: */ + for (std::size_t i = cGap; i < cElements; i++) + { + /* Find the best suitable location for the item at 'i' comparing + backwards in steps of 'cGap', swapping the item at 'i' with the + one at '-cGap*j' if it's smaller, stopping if it's larger. + + Note! Original algorithm would make a copy of the item, this version + avoids extra copies of sorted items at the cost of extra copies + when dealing with unsorted ones a small cGaps values. */ + a_RandomIt ItCur = a_ItBegin + i; + size_t j = i; + do + { + j -= cGap; + a_RandomIt ItAtGap = a_ItBegin + j; + if (a_fnComp(*ItAtGap, *ItCur)) + break; + std::iter_swap(ItAtGap, ItCur); + ItCur = ItAtGap; + } while (j >= cGap); + } + + /* This does not generate the most optimal gap sequence, but it has the + advantage of being simple and avoid floating point. */ + cGap /= 2; + } + } + } + +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !VBOX_INCLUDED_SRC_nocrt_algorithm */ + diff --git a/include/iprt/nocrt/amd64/Makefile.kup b/include/iprt/nocrt/amd64/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/nocrt/amd64/math.h b/include/iprt/nocrt/amd64/math.h new file mode 100644 index 00000000..19bdea78 --- /dev/null +++ b/include/iprt/nocrt/amd64/math.h @@ -0,0 +1,115 @@ +/** @file + * IPRT / No-CRT - math.h, AMD inlined functions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_amd64_math_h +#define IPRT_INCLUDED_nocrt_amd64_math_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +#if RT_INLINE_ASM_GNU_STYLE && defined(__SSE__) + +DECLINLINE(long double) inline_atan2l(long double lrd1, long double lrd2) +{ + long double lrdResult; + __asm__ __volatile__("fpatan" + : "=t" (lrdResult) + : "u" (lrd1), + "0" (lrd2) + : "st(1)"); + return lrdResult; +} + +DECLINLINE(long double) inline_rintl(long double lrd) +{ + long double lrdResult; + __asm__ __volatile__("frndint" + : "=t" (lrdResult) + : "0" (lrd)); + return lrdResult; +} + +DECLINLINE(float) inline_rintf(float rf) +{ + return (float)inline_rintl(rf); +} + +DECLINLINE(double) inline_rint(double rd) +{ + return (double)inline_rintl(rd); +} + +DECLINLINE(long double) inline_sqrtl(long double lrd) +{ + long double lrdResult; + __asm__ __volatile__("fsqrt" + : "=t" (lrdResult) + : "0" (lrd)); + return lrdResult; +} + +DECLINLINE(float) inline_sqrtf(float rf) +{ + return (float)inline_sqrtl(rf); +} + +DECLINLINE(double) inline_sqrt(double rd) +{ + return (double)inline_sqrtl(rd); +} + + +# undef atan2l +# define atan2l(lrd1, lrd2) inline_atan2l(lrd1, lrd2) +# undef rint +# define rint(rd) inline_rint(rd) +# undef rintf +# define rintf(rf) inline_rintf(rf) +# undef rintl +# define rintl(lrd) inline_rintl(lrd) +# undef sqrt +# define sqrt(rd) inline_sqrt(rd) +# undef sqrtf +# define sqrtf(rf) inline_sqrtf(rf) +# undef sqrtl +# define sqrtl(lrd) inline_sqrtl(lrd) + +#endif /* RT_INLINE_ASM_GNU_STYLE */ + +#endif /* !IPRT_INCLUDED_nocrt_amd64_math_h */ + diff --git a/include/iprt/nocrt/assert.h b/include/iprt/nocrt/assert.h new file mode 100644 index 00000000..987db7df --- /dev/null +++ b/include/iprt/nocrt/assert.h @@ -0,0 +1,57 @@ +/** @file + * IPRT / No-CRT - Our own assert.h header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_assert_h +#define IPRT_INCLUDED_nocrt_assert_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +DECL_FORCE_INLINE(void) rtCrtAssertPanic(void) +{ + RTAssertPanic(); +} + +/* Mesa uses assert() in such a way that we must not have any 'do {} while' + wrappers in the expansion, so we partially cook our own assert here but + using the standard iprt/assert.h building blocks. */ +#define assert(a_Expr) (RT_LIKELY(!!(a_Expr)) ? (void)0 \ + : RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__), \ + rtCrtAssertPanic(), (void)0 ) + +#endif /* !IPRT_INCLUDED_nocrt_assert_h */ + diff --git a/include/iprt/nocrt/cassert b/include/iprt/nocrt/cassert new file mode 100644 index 00000000..3315a4bd --- /dev/null +++ b/include/iprt/nocrt/cassert @@ -0,0 +1,49 @@ +/** @file + * IPRT / No-CRT - Minimal C++ cassert header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_cassert +#define VBOX_INCLUDED_SRC_nocrt_cassert +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +namespace std +{ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_cassert */ + diff --git a/include/iprt/nocrt/compiler/compiler.h b/include/iprt/nocrt/compiler/compiler.h new file mode 100644 index 00000000..c2ca1d80 --- /dev/null +++ b/include/iprt/nocrt/compiler/compiler.h @@ -0,0 +1,52 @@ +/** @file + * IPRT / No-CRT - compiler specifics. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_compiler_compiler_h +#define IPRT_INCLUDED_nocrt_compiler_compiler_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef __GNUC__ +# include +#elif defined(_MSC_VER) +# include +#elif defined(__WATCOMC__) +# include +#else +# error "Unsupported compiler." +#endif + +#endif /* !IPRT_INCLUDED_nocrt_compiler_compiler_h */ diff --git a/include/iprt/nocrt/compiler/gcc.h b/include/iprt/nocrt/compiler/gcc.h new file mode 100644 index 00000000..91c1d5a8 --- /dev/null +++ b/include/iprt/nocrt/compiler/gcc.h @@ -0,0 +1,134 @@ +/** @file + * IPRT / No-CRT - GCC specifics. + * + * A quick hack for freebsd where there are no separate location + * for compiler specific headers like on linux, mingw, os2, ++. + * This file will be cleaned up later... + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_compiler_gcc_h +#define IPRT_INCLUDED_nocrt_compiler_gcc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* stddef.h */ +#ifdef __PTRDIFF_TYPE__ +typedef __PTRDIFF_TYPE__ ptrdiff_t; +#elif ARCH_BITS == 32 +typedef int32_t ptrdiff_t; +#elif ARCH_BITS == 64 +typedef int64_t ptrdiff_t; +#else +# error "ARCH_BITS is undefined or incorrect." +#endif +#define _PTRDIFF_T_DECLARED + +#ifdef __SIZE_TYPE__ +typedef __SIZE_TYPE__ size_t; +#elif ARCH_BITS == 32 +typedef uint32_t size_t; +#elif ARCH_BITS == 64 +typedef uint64_t size_t; +#else +# error "ARCH_BITS is undefined or incorrect." +#endif +#define _SIZE_T_DECLARED + +#ifndef __cplusplus +# ifdef __WCHAR_TYPE__ +typedef __WCHAR_TYPE__ wchar_t; +# elif defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +typedef uint16_t wchar_t; +# else +typedef int wchar_t; +# endif +# define _WCHAR_T_DECLARED +#endif + +#ifdef __WINT_TYPE__ +typedef __WINT_TYPE__ wint_t; +#else +typedef unsigned int wint_t; +#endif +#define _WINT_T_DECLARED + +#ifndef NULL +# ifdef __cplusplus +# define NULL 0 +# else +# define NULL ((void *)0) +# endif +#endif + + +#ifndef offsetof +# if defined(__cplusplus) && defined(__offsetof__) +# define offsetof(type, memb) + (__offsetof__ (reinterpret_cast(&reinterpret_cast(static_cast(0)->memb))) ) +# else +# define offsetof(type, memb) ((size_t)&((type *)0)->memb) +# endif +#endif + + +/* sys/types.h */ +#ifdef __SSIZE_TYPE__ +typedef __SSIZE_TYPE__ ssize_t; +#elif ARCH_BITS == 32 +typedef int32_t ssize_t; +#elif ARCH_BITS == 64 +typedef int64_t ssize_t; +#else +# define ARCH_BITS 123123 +# error "ARCH_BITS is undefined or incorrect." +#endif +#define _SSIZE_T_DECLARED + + +/* stdarg.h */ +typedef __builtin_va_list va_list; +#if __GNUC__ == 3 \ + && __GNUC_MINOR__ == 2 +# define va_start(va, arg) __builtin_stdarg_start(va, arg) +#else +# define va_start(va, arg) __builtin_va_start(va, arg) +#endif +#define va_end(va) __builtin_va_end(va) +#define va_arg(va, type) __builtin_va_arg(va, type) +#define va_copy(dst, src) __builtin_va_copy(dst, src) + + +#endif /* !IPRT_INCLUDED_nocrt_compiler_gcc_h */ diff --git a/include/iprt/nocrt/compiler/msc.h b/include/iprt/nocrt/compiler/msc.h new file mode 100644 index 00000000..be81fffc --- /dev/null +++ b/include/iprt/nocrt/compiler/msc.h @@ -0,0 +1,62 @@ +/** @file + * IPRT / No-CRT - MSC specifics. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_compiler_msc_h +#define IPRT_INCLUDED_nocrt_compiler_msc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* stddef.h */ +#if !defined(_MT) && !defined(_DLL) && _MSC_VER < 1400 +# define errno msvcrt_errno +#endif +#if _MSC_VER >= 1900 +# include +#else +# include <../include/stddef.h> +#endif +#undef errno + +#undef ssize_t +typedef intptr_t ssize_t; + + +/* stdarg.h */ +#include <../include/stdarg.h> + +#endif /* !IPRT_INCLUDED_nocrt_compiler_msc_h */ + diff --git a/include/iprt/nocrt/compiler/watcom.h b/include/iprt/nocrt/compiler/watcom.h new file mode 100644 index 00000000..507b66dc --- /dev/null +++ b/include/iprt/nocrt/compiler/watcom.h @@ -0,0 +1,108 @@ +/** @file + * IPRT / No-CRT - Open Watcom specifics. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_compiler_watcom_h +#define IPRT_INCLUDED_nocrt_compiler_watcom_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* stddef.h for size_t and such */ +#if 0 +# include <../h/stddef.h> + +# ifndef _SSIZE_T_DEFINED_ +# define _SSIZE_T_DEFINED_ +typedef signed int ssize_t; +# endif + +#else + +# define _SIZE_T_DEFINED_ +# define __size_t +typedef unsigned size_t; +typedef size_t _w_size_t; + +# define _SSIZE_T_DEFINED_ +# define __ssize_t +typedef signed int ssize_t; + +# define _RSIZE_T_DEFINED +typedef size_t rsize_t; + +# define _PTRDIFF_T_DEFINED_ +# ifdef __HUGE__ +typedef long ptrdiff_t; +# else +typedef int ptrdiff_t; +# endif + +# ifndef _WCHAR_T_DEFINED /* predefined in C++ mode? */ +# define _WCHAR_T_DEFINED +typedef unsigned short wchar_t; +# endif + +# ifndef NULL +# ifndef __cplusplus +# define NULL ((void *)0) +# elif defined(__SMALL__) || defined(__MEDIUM__) || !defined(_M_I86) +# define NULL (0) +# else +# define NULL (0L) +# endif +# endif + +# define offsetof(a_Type, a_Member) RT_OFFSETOF(a_Type, a_Member) + +# if defined(_M_I86) && (defined(__SMALL__) || defined(__MEDIUM__)) +typedef int intptr_t; +typedef unsigned int uintptr_t; +# elif defined(_M_I86) || (!defined(__COMPACT__) && !defined(__LARGE__)) +typedef long intptr_t; +typedef unsigned long uintptr_t; +# else /* 32-bit compile using far data pointers (16:32) */ +typedef long long intptr_t; +typedef unsigned long long uintptr_t; +# endif + +#endif + +/* stdarg.h */ +#include <../h/stdarg.h> + +#endif /* !IPRT_INCLUDED_nocrt_compiler_watcom_h */ + diff --git a/include/iprt/nocrt/cstddef b/include/iprt/nocrt/cstddef new file mode 100644 index 00000000..2b3c29e9 --- /dev/null +++ b/include/iprt/nocrt/cstddef @@ -0,0 +1,52 @@ +/** @file + * IPRT / No-CRT - Dummy cstddef. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_cstddef +#define VBOX_INCLUDED_SRC_nocrt_cstddef +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +namespace std +{ + using size_t = ::size_t; + using ptrdiff_t = ::ptrdiff_t; +} + + +#endif /* !VBOX_INCLUDED_SRC_nocrt_cstddef */ + diff --git a/include/iprt/nocrt/cstdlib b/include/iprt/nocrt/cstdlib new file mode 100644 index 00000000..2a11d98f --- /dev/null +++ b/include/iprt/nocrt/cstdlib @@ -0,0 +1,47 @@ +/** @file + * IPRT / No-CRT - Dummy cstdlib. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_cstdlib +#define VBOX_INCLUDED_SRC_nocrt_cstdlib +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +#endif /* !VBOX_INCLUDED_SRC_nocrt_cstdlib */ + diff --git a/include/iprt/nocrt/ctype.h b/include/iprt/nocrt/ctype.h new file mode 100644 index 00000000..466a9283 --- /dev/null +++ b/include/iprt/nocrt/ctype.h @@ -0,0 +1,61 @@ +/** @file + * IPRT / No-CRT - Our own minimal ctype.h header (needed by ntdefs.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_ctype_h +#define IPRT_INCLUDED_nocrt_ctype_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#define isspace(a_ch) RT_C_IS_SPACE(a_ch) +#define isblank(a_ch) RT_C_IS_BLANK(a_ch) +#define isdigit(a_ch) RT_C_IS_DIGIT(a_ch) +#define isxdigit(a_ch) RT_C_IS_XDIGIT(a_ch) +#define isalpha(a_ch) RT_C_IS_ALPHA(a_ch) +#define isalnum(a_ch) RT_C_IS_ALNUM(a_ch) +#define iscntrl(a_ch) RT_C_IS_CNTRL(a_ch) +#define isgraph(a_ch) RT_C_IS_GRAPH(a_ch) +#define ispunct(a_ch) RT_C_IS_PUNCT(a_ch) +#define isprint(a_ch) RT_C_IS_PRINT(a_ch) +#define isupper(a_ch) RT_C_IS_UPPER(a_ch) +#define islower(a_ch) RT_C_IS_LOWER(a_ch) + +#define tolower(a_ch) RT_C_TO_LOWER(a_ch) +#define toupper(a_ch) RT_C_TO_UPPER(a_ch) + +#endif /* !IPRT_INCLUDED_nocrt_ctype_h */ + diff --git a/include/iprt/nocrt/direct.h b/include/iprt/nocrt/direct.h new file mode 100644 index 00000000..72f23a17 --- /dev/null +++ b/include/iprt/nocrt/direct.h @@ -0,0 +1,43 @@ +/** @file + * IPRT / No-CRT - Stub direct.h header (for MSC compatibility). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_direct_h +#define IPRT_INCLUDED_nocrt_direct_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#endif /* !IPRT_INCLUDED_nocrt_direct_h */ + diff --git a/include/iprt/nocrt/errno.h b/include/iprt/nocrt/errno.h new file mode 100644 index 00000000..1217a531 --- /dev/null +++ b/include/iprt/nocrt/errno.h @@ -0,0 +1,56 @@ +/** @file + * IPRT / No-CRT - Dummy errno.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_errno_h +#define IPRT_INCLUDED_nocrt_errno_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +# include + +RT_C_DECLS_BEGIN + +RTDECL(int *) rtNoCrtGetErrnoPtr(void); +# define errno (*rtNoCrtGetErrnoPtr()) + +RT_C_DECLS_END + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + +#endif /* !IPRT_INCLUDED_nocrt_errno_h */ + diff --git a/include/iprt/nocrt/exception b/include/iprt/nocrt/exception new file mode 100644 index 00000000..6e6ee777 --- /dev/null +++ b/include/iprt/nocrt/exception @@ -0,0 +1,90 @@ +/** @file + * IPRT / No-CRT - Our own exception header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_exception +#define VBOX_INCLUDED_SRC_nocrt_exception +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +namespace std { + +/** Exception base class. */ +class exception +{ +public: + exception() RT_NOEXCEPT +#ifdef _MSC_VER + : m_pszWhat(NULL) +#endif + { } + + exception(const exception &a_rThat) RT_NOEXCEPT +#ifdef _MSC_VER + : m_pszWhat(a_rThat.m_pszWhat) +#endif + { + RT_NOREF(a_rThat); + } + +#ifdef _MSC_VER + exception(const char *a_pszWhat, int a_iIgnored = 0) RT_NOEXCEPT + : m_pszWhat(a_pszWhat) + { RT_NOREF(a_iIgnored); } +#endif + + virtual ~exception() RT_NOEXCEPT + {} + + virtual const char *what() const RT_NOEXCEPT + { +#ifdef _MSC_VER + if (m_pszWhat) + return m_pszWhat; +#endif + return "unknown exception"; + } +#ifdef _MSC_VER +protected: + const char *m_pszWhat; +#endif +}; + +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_exception */ + diff --git a/include/iprt/nocrt/fcntl.h b/include/iprt/nocrt/fcntl.h new file mode 100644 index 00000000..49cf6f4b --- /dev/null +++ b/include/iprt/nocrt/fcntl.h @@ -0,0 +1,90 @@ +/** @file + * IPRT / No-CRT - fcntl.h + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_fcntl_h +#define IPRT_INCLUDED_nocrt_fcntl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include /* to establish the timespec and timeval types before iprt/file.h includes iprt/time.h */ +#include + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY + +/* Open flags:*/ +AssertCompile(RT_IS_POWER_OF_TWO(RTFILE_O_OPEN_CREATE)); +AssertCompile(RT_IS_POWER_OF_TWO(RTFILE_O_CREATE)); +# define _O_CREAT RTFILE_O_OPEN_CREATE +# define _O_EXCL RTFILE_O_CREATE /**< Will remove RTFILE_O_OPEN_CREATE when processing it. */ +# define _O_TRUNC RTFILE_O_TRUNCATE +# define _O_APPEND RTFILE_O_APPEND +# define _O_RDONLY RTFILE_O_READ +# define _O_WRONLY RTFILE_O_WRITE +# define _O_RDWR (RTFILE_O_READ | RTFILE_O_WRITE) +# define _O_CLOEXEC RTFILE_O_INHERIT /**< Invert meaning when processing it. */ +# define _O_NOINHERIT O_CLOEXEC +# define _O_LARGEFILE 0 +# define _O_BINARY 0 + +# define O_CREAT _O_CREAT +# define O_EXCL _O_EXCL +# define O_TRUNC _O_TRUNC +# define O_APPEND _O_APPEND +# define O_RDONLY _O_RDONLY +# define O_WRONLY _O_WRONLY +# define O_RDWR _O_RDWR +# define O_CLOEXEC _O_CLOEXEC +# define O_NOINHERIT _O_NOINHERIT +# define O_BINARY _O_BINARY + +RT_C_DECLS_BEGIN + +int RT_NOCRT(open)(const char *pszFilename, uint64_t fFlags, ... /*RTFMODE fMode*/); +int RT_NOCRT(_open)(const char *pszFilename, uint64_t fFlags, ... /*RTFMODE fMode*/); + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define open RT_NOCRT(open) +# define _open RT_NOCRT(_open) +# endif + +RT_C_DECLS_END + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + + + +#endif /* !IPRT_INCLUDED_nocrt_fcntl_h */ + diff --git a/include/iprt/nocrt/fenv.h b/include/iprt/nocrt/fenv.h new file mode 100644 index 00000000..7af59d13 --- /dev/null +++ b/include/iprt/nocrt/fenv.h @@ -0,0 +1,49 @@ +/** @file + * IPRT / No-CRT - fenv.h wrapper. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_fenv_h +#define IPRT_INCLUDED_nocrt_fenv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +# include +#else +# error "IPRT: no fenv.h available for this platform, or the platform define is missing!" +#endif + +#endif /* !IPRT_INCLUDED_nocrt_fenv_h */ diff --git a/include/iprt/nocrt/float.h b/include/iprt/nocrt/float.h new file mode 100644 index 00000000..f0e8081d --- /dev/null +++ b/include/iprt/nocrt/float.h @@ -0,0 +1,131 @@ +/** @file + * IPRT / No-CRT - Our minimal float.h. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_float_h +#define IPRT_INCLUDED_nocrt_float_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* + * Common. + */ +#define FLT_RADIX 2 + + +/* + * float + */ +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) + +# define FLT_MAX (3.40282347E+38F) +# define FLT_MIN (1.17549435E-38F) +# define FLT_TRUE_MIN (1.40129846E-45F) +# define FLT_MAX_EXP (128) +# define FLT_MIN_EXP (-125) +# define FLT_MAX_10_EXP (38) +# define FLT_MIN_10_EXP (-37) +# define FLT_EPSILON (1.192092896E-07F) +# define FLT_DIG (6) +# define FLT_DECIMAL_DIG (9) +# define FLT_MANT_DIG (24) +# define FLT_HAS_SUBNORM (1) + +#endif + +/* + * double + */ +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) + +# ifdef _MSC_VER +# define DBL_MAX (1.7976931348623158E+308) +# else +# define DBL_MAX (1.7976931348623157E+308) +# endif +# define DBL_MIN (2.2250738585072014E-308) +# define DBL_TRUE_MIN (4.9406564584124654E-324) +# define DBL_MAX_EXP (1024) +# define DBL_MIN_EXP (-1021) +# define DBL_MAX_10_EXP (308) +# define DBL_MIN_10_EXP (-307) +# define DBL_EPSILON (2.2204460492503131E-16) +# define DBL_DIG (15) +# define DBL_DECIMAL_DIG (17) +# define DBL_MANT_DIG (53) +# define DBL_HAS_SUBNORM (1) + +#endif + +/* + * long double + */ +#if ((defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && defined(RT_OS_WINDOWS)) || defined(RT_ARCH_ARM64) /*?*/ + +# define LDBL_MAX DBL_MAX +# define LDBL_MIN DBL_MIN +# define LDBL_TRUE_MIN DBL_TRUE_MIN +# define LDBL_MAX_EXP DBL_MAX_EXP +# define LDBL_MIN_EXP DBL_MIN_EXP +# define LDBL_MAX_10_EXP DBL_MAX_10_EXP +# define LDBL_MIN_10_EXP DBL_MIN_10_EXP +# define LDBL_EPSILON DBL_EPSILON +# define LDBL_DIG DBL_DIG +# define LDBL_DECIMAL_DIG DBL_DECIMAL_DIG +# define LDBL_MANT_DIG DBL_MANT_DIG +# define LDBL_HAS_SUBNORM DBL_HAS_SUBNORM + +#elif defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) + +# define LDBL_MAX (1.1897314953572317650E+4932L) +# define LDBL_MIN (3.3621031431120935063E-4932L) +# define LDBL_TRUE_MIN (3.6451995318824746025E-4951L) +# define LDBL_MAX_EXP (-16381) +# define LDBL_MIN_EXP (16384) +# define LDBL_MAX_10_EXP (4932) +# define LDBL_MIN_10_EXP (-4931) +# define LDBL_EPSILON (1.0842021724855044340E-19L) +# define LDBL_DIG (18) +# define LDBL_DECIMAL_DIG (21) +# define LDBL_MANT_DIG (64) +# define LDBL_HAS_SUBNORM (1) + +#endif + + +#endif /* !IPRT_INCLUDED_nocrt_float_h */ + diff --git a/include/iprt/nocrt/fstream b/include/iprt/nocrt/fstream new file mode 100644 index 00000000..1abd06eb --- /dev/null +++ b/include/iprt/nocrt/fstream @@ -0,0 +1,206 @@ +/** @file + * IPRT / No-CRT - Minimal C++ fstream header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_fstream +#define VBOX_INCLUDED_SRC_nocrt_fstream +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +namespace std +{ + template*/ > + class basic_filebuf : public basic_streambuf + { + protected: + PRTSTREAM m_pStrm; + bool m_fStdStream; + ios_base::openmode m_fMode; + + public: + basic_filebuf(PRTSTREAM a_pStrm = NULL, bool a_fStdStream = false) + : basic_streambuf() + , m_pStrm(a_pStrm) + , m_fStdStream(a_fStdStream) + , m_fMode(ios_base::openmode(0)) + { + } + + virtual ~basic_filebuf() + { + if (m_pStrm) + { + if (m_fStdStream) + RTStrmClose(m_pStrm); + m_pStrm = NULL; + } + } + + bool is_open() const RT_NOEXCEPT + { + return m_pStrm != NULL; + } + + basic_filebuf *open(const char *a_pszFilename, ios_base::openmode a_fMode) + { + /* + * Sanitize the a_fMode first. + */ + AssertReturn(!is_open(), NULL); + AssertReturn(a_fMode & (ios_base::out | ios_base::in), NULL); /* Neither write nor read mode? */ + AssertStmt((a_fMode & (ios_base::out | ios_base::app)) != ios_base::app, a_fMode &= ~ios_base::app); + AssertReturn((a_fMode & (ios_base::out | ios_base::trunc)) != ios_base::trunc, NULL); + AssertReturn(!(a_fMode & ios_base::trunc) || !(a_fMode & ios_base::app), NULL); + + /* + * Translate a_fMode into a stream mode string and try open the file. + */ + char szMode[8]; + szMode[0] = a_fMode & ios_base::trunc ? 'w' : a_fMode & ios_base::app ? 'a' : 'r'; + size_t offMode = 1; + if ((a_fMode & (ios_base::in | ios_base::out)) == (ios_base::in | ios_base::out)) + szMode[offMode++] = '+'; + if (a_fMode & ios_base::binary) + szMode[offMode++] = 'b'; + szMode[offMode] = '\0'; + + int rc = RTStrmOpen(a_pszFilename, szMode, &m_pStrm); + if (RT_SUCCESS(rc)) + { + /** @todo if (a_fMode & ios_base::ate)? */ + + /* + * Set up the buffer? + */ + if (true) + { + return this; + } + + RTStrmClose(m_pStrm); + m_pStrm = NULL; + } + return NULL; + } + + protected: + bool flushBuffered() + { + /** @todo buffering. */ + return true; + } + + //virtual int_type overflow(int_type a_iChar) RT_OVERRIDE + //{ + // if (a_iChar != traits_type::eof()) + // { + // if (flushBuffered()) + // { + // char_type ch = traits_type::to_char_type(a_iChar); + // int rc = RTStrmWrite(m_pStrm, &ch, sizeof(ch)); + // if (RT_SUCCESS(rc)) + // return a_iChar; + // } + // } + // return traits_type::eof(); + //} + + std::streamsize xsputn(char_type const *a_pchSrc, std::streamsize a_cchSrc) //RT_OVERRIDE + { + if (flushBuffered()) + { + size_t cbWritten = 0; + int rc = RTStrmWriteEx(m_pStrm, &a_pchSrc, sizeof(a_pchSrc[0]) * a_cchSrc, &cbWritten); + if (RT_SUCCESS(rc)) + return cbWritten / sizeof(a_pchSrc[0]); + } + return 0; + } + }; + + + /** + * Basic I/O stream. + */ + template*/ > + class basic_ofstream : public basic_ostream + { + protected: + basic_filebuf m_FileBuf; + + public: + basic_ofstream() + : basic_ostream(&m_FileBuf) /** @todo m_FileBuf isn't initialized yet... */ + , m_FileBuf() + { + } + + explicit basic_ofstream(const char *a_pszFilename, ios_base::openmode a_fMode = ios_base::out) + : basic_ostream(&m_FileBuf) /** @todo m_FileBuf isn't initialized yet... */ + , m_FileBuf() + { + m_FileBuf.open(a_pszFilename, a_fMode); + } + private: + basic_ofstream(basic_ofstream const &a_rSrc); /* no copying */ + basic_ofstream &operator=(basic_ofstream const &a_rSrc); /* no copying */ + + public: + virtual ~basic_ofstream() + { + } + + public: + + bool is_open() const RT_NOEXCEPT + { + return m_FileBuf.is_open(); + } + + basic_filebuf *open(const char *a_pszFilename, ios_base::openmode a_fMode) + { + return m_FileBuf.open(a_pszFilename, a_fMode); + } + + + }; +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_fstream */ + diff --git a/include/iprt/nocrt/inttypes.h b/include/iprt/nocrt/inttypes.h new file mode 100644 index 00000000..cb2265c8 --- /dev/null +++ b/include/iprt/nocrt/inttypes.h @@ -0,0 +1,75 @@ +/** @file + * IPRT / No-CRT - Our minimal inttypes.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_inttypes_h +#define IPRT_INCLUDED_nocrt_inttypes_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#define PRId8 "RI8" +#define PRIi8 "RI8" +#define PRIx8 "RX8" +#define PRIu8 "RU8" +#define PRIo8 huh? anyone using this? great! + +#define PRId16 "RI16" +#define PRIi16 "RI16" +#define PRIx16 "RX16" +#define PRIu16 "RU16" +#define PRIo16 huh? anyone using this? great! + +#define PRId32 "RI32" +#define PRIi32 "RI32" +#define PRIx32 "RX32" +#define PRIu32 "RU32" +#define PRIo32 huh? anyone using this? great! + +#define PRId64 "RI64" +#define PRIi64 "RI64" +#define PRIx64 "RX64" +#define PRIu64 "RU64" +#define PRIo64 huh? anyone using this? great! + +#define PRIdMAX "RI64" +#define PRIiMAX "RI64" +#define PRIxMAX "RX64" +#define PRIuMAX "RU64" +#define PRIoMAX huh? anyone using this? great! + +#endif /* !IPRT_INCLUDED_nocrt_inttypes_h */ + diff --git a/include/iprt/nocrt/io.h b/include/iprt/nocrt/io.h new file mode 100644 index 00000000..f8d42941 --- /dev/null +++ b/include/iprt/nocrt/io.h @@ -0,0 +1,48 @@ +/** @file + * IPRT / No-CRT - io.h (DOS, OS/2, Windows compilers). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_io_h +#define IPRT_INCLUDED_nocrt_io_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +#endif /* !IPRT_INCLUDED_nocrt_io_h */ + diff --git a/include/iprt/nocrt/iomanip b/include/iprt/nocrt/iomanip new file mode 100644 index 00000000..29c651e9 --- /dev/null +++ b/include/iprt/nocrt/iomanip @@ -0,0 +1,166 @@ +/** @file + * IPRT / No-CRT - Minimal C++ iomanip header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_iomanip +#define VBOX_INCLUDED_SRC_nocrt_iomanip +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +namespace std +{ + /** + * Used by all flag manipulators. + */ + struct rtNoCrtIosSetFlagsEx + { + ios_base::fmtflags m_fSet; + ios_base::fmtflags m_fMask; + }; + + template + inline basic_istream &operator>>(basic_istream &a_rSrc, + struct rtNoCrtIosSetFlagsEx a_Change) + { + a_rSrc.setf(a_Change.m_fSet, a_Change.m_fMask); + return a_rSrc; + } + + template + inline basic_ostream &operator<<(basic_ostream &a_rDst, + struct rtNoCrtIosSetFlagsEx a_Change) + { + a_rDst.setf(a_Change.m_fSet, a_Change.m_fMask); + return a_rDst; + } + + + /* + * Flag modification functions. + */ + + inline struct rtNoCrtIosSetFlagsEx setiosflags(ios_base::fmtflags a_fFlags) + { + struct rtNoCrtIosSetFlagsEx Ret = { a_fFlags, a_fFlags }; + return Ret; + } + + inline struct rtNoCrtIosSetFlagsEx resetiosflags(ios_base::fmtflags a_fFlags) + { + struct rtNoCrtIosSetFlagsEx Ret = { ios_base::fmtflags(0), a_fFlags }; + return Ret; + } + + inline struct rtNoCrtIosSetFlagsEx setbase(int a_iBase) + { + struct rtNoCrtIosSetFlagsEx Ret = + { + a_iBase == 10 ? ios_base::dec + : a_iBase == 16 ? ios_base::hex + : a_iBase == 8 ? ios_base::oct + : ios_base::fmtflags(0), + ios_base::basefield + }; + return Ret; + } + + /* + * Modify precision. + */ + struct rtNoCrtIosSetPrecision + { + int m_cchPrecision; + }; + + template + inline basic_istream &operator>>(basic_istream &a_rSrc, + struct rtNoCrtIosSetPrecision a_Change) + { + a_rSrc.precision(a_Change.m_cchPrecision); + return a_rSrc; + } + + template + inline basic_ostream &operator<<(basic_ostream &a_rDst, + struct rtNoCrtIosSetPrecision a_Change) + { + a_rDst.precision(a_Change.m_cchPrecision); + return a_rDst; + } + + inline struct rtNoCrtIosSetPrecision setprecision(int a_cchPrecision) + { + struct rtNoCrtIosSetPrecision Ret = { a_cchPrecision }; + return Ret; + } + + /* + * Modify width. + */ + struct rtNoCrtIosSetWidth + { + int m_cchWidth; + }; + + template + inline basic_istream &operator>>(basic_istream &a_rSrc, + struct rtNoCrtIosSetWidth a_Change) + { + a_rSrc.width(a_Change.m_cchWidth); + return a_rSrc; + } + + template + inline basic_ostream &operator<<(basic_ostream &a_rDst, + struct rtNoCrtIosSetWidth a_Change) + { + a_rDst.width(a_Change.m_cchWidth); + return a_rDst; + } + + inline struct rtNoCrtIosSetWidth setw(int a_cchWidth) + { + struct rtNoCrtIosSetWidth Ret = { a_cchWidth }; + return Ret; + } + + /** @todo setfil, get_money, set_money, get_time, set_time */ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_iomanip */ + diff --git a/include/iprt/nocrt/ios b/include/iprt/nocrt/ios new file mode 100644 index 00000000..9e49eaa9 --- /dev/null +++ b/include/iprt/nocrt/ios @@ -0,0 +1,525 @@ +/** @file + * IPRT / No-CRT - Minimal C++ ios header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_ios +#define VBOX_INCLUDED_SRC_nocrt_ios +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** @todo something for cdecl.h */ +#define RTNOCRT_IOS_ENUM_BIT_OPS(a_EnumType, a_IntType) \ + inline a_EnumType operator~(a_EnumType a_fLeft) RT_NOEXCEPT \ + { return a_EnumType(~static_cast(a_fLeft)); } \ + \ + inline a_EnumType operator&(a_EnumType a_fLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_EnumType(static_cast(a_fLeft) & static_cast(a_fRight)); } \ + inline a_EnumType operator|(a_EnumType a_fLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_EnumType(static_cast(a_fLeft) | static_cast(a_fRight)); } \ + inline a_EnumType operator^(a_EnumType a_fLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_EnumType(static_cast(a_fLeft) ^ static_cast(a_fRight)); } \ + \ + inline const a_EnumType &operator&=(a_EnumType &a_rfLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_rfLeft = a_rfLeft & a_fRight; } \ + inline const a_EnumType &operator|=(a_EnumType &a_rfLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_rfLeft = a_rfLeft | a_fRight; } \ + inline const a_EnumType &operator^=(a_EnumType &a_rfLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_rfLeft = a_rfLeft ^ a_fRight; } \ + +namespace std +{ + typedef ptrdiff_t streamsize; + + /** + * I/O stream format flags. + */ + class rtNoCrtIosEnums + { + public: + enum fmtflags + { + /* int: */ + dec = 0x00000001, + oct = 0x00000002, + hex = 0x00000004, + basefield = 0x00000007, + /* float: */ + scientific = 0x00000010, + fixed = 0x00000020, + floatfield = 0x00000030, + /* int and float output tweaks: */ + showbase = 0x00000100, + showpoint = 0x00000200, + showpos = 0x00000400, + /* bool: */ + boolalpha = 0x00000800, + /* adjustment: */ + left = 0x00001000, + right = 0x00002000, + internal = 0x00004000, + adjustfield = 0x00007000, + /* misc: */ + skipws = 0x00010000, + unitbuf = 0x00020000, + uppercase = 0x00040000, + }; + + enum seekdir + { + beg = 1, + end, + cur, + }; + + enum openmode + { + app = 1, + binary, + in, + out, + trunc, + ate + }; + + enum iostate + { + goodbit = 0, + badbit = 1, + failbit = 2, + eofbit = 4 + }; + }; + RTNOCRT_IOS_ENUM_BIT_OPS(rtNoCrtIosEnums::fmtflags, int) + RTNOCRT_IOS_ENUM_BIT_OPS(rtNoCrtIosEnums::seekdir, int) + RTNOCRT_IOS_ENUM_BIT_OPS(rtNoCrtIosEnums::openmode, int) + RTNOCRT_IOS_ENUM_BIT_OPS(rtNoCrtIosEnums::iostate, int) + + + /** + * I/O stream base class. + */ + class ios_base : public rtNoCrtIosEnums + { + public: + //typedef rtNoCrtIosFmtFlags fmtflags; + //typedef rtNoCrtIosSeekDir seekdir; + //typedef rtNoCrtIosOpenMode openmode; + //typedef rtNoCrtIosState iostate; + + protected: + streamsize m_cWidth; + streamsize m_cPrecision; + fmtflags m_fFlags; + iostate m_fState; + + protected: + ios_base() + : m_cWidth(0) + , m_cPrecision(0) + , m_fFlags(dec | skipws) + , m_fState(goodbit) + { + } + private: + ios_base(const ios_base &); /* not copyable */ + ios_base &operator=(const ios_base &); /* not copyable */ + + public: + virtual ~ios_base() + { + } + + streamsize width() const RT_NOEXCEPT + { + return m_cWidth; + } + + streamsize width(streamsize a_cWidth) RT_NOEXCEPT + { + streamsize cOldWidth = m_cWidth; + m_cWidth = a_cWidth; + return cOldWidth; + } + + streamsize precision() const RT_NOEXCEPT + { + return m_cPrecision; + } + + streamsize precision(streamsize a_cPrecision) RT_NOEXCEPT + { + streamsize cOldPrecision = m_cPrecision; + m_cPrecision = a_cPrecision; + return cOldPrecision; + } + + fmtflags flags() const RT_NOEXCEPT + { + return m_fFlags; + } + + fmtflags flags(fmtflags a_fNew) RT_NOEXCEPT + { + fmtflags const fOld = m_fFlags; + m_fFlags = a_fNew; + return fOld; + } + + fmtflags setf(fmtflags a_fAdd) RT_NOEXCEPT + { + fmtflags const fOld = m_fFlags; + m_fFlags = static_cast(fOld | a_fAdd); + return fOld; + } + + fmtflags setf(fmtflags a_fAdd, fmtflags a_fMask) RT_NOEXCEPT + { + fmtflags const fOld = m_fFlags; + m_fFlags = static_cast((fOld & ~a_fMask) | (a_fAdd & a_fMask)); + return fOld; + } + + void unsetf(fmtflags a_fClear) RT_NOEXCEPT + { + m_fFlags = static_cast(m_fFlags & ~a_fClear); + } + }; + + + /** + * Stream buffer. + */ + template*/ > + class basic_streambuf + { + public: + typedef a_CharType char_type; + typedef a_CharTraits traits_type; + typedef typename a_CharTraits::int_type int_type; + typedef typename a_CharTraits::pos_type pos_type; + typedef typename a_CharTraits::off_type off_type; + + protected: + /** @name Put buffering + * @{ */ + char_type *m_pachPut; /**< The put buffer pointer. */ + std::size_t m_cchPut; /**< Put buffer size. */ + std::size_t m_offPutNext; /**< The current put buffer position (where to write next). */ + std::size_t m_offPutStart; /**< Where the buffered put sequence starts. */ + + void setp(char_type *a_pachNewBuf, char_type *a_pachNewBufEnd) + { + Assert((uintptr_t)a_pachNewBuf <= (uintptr_t)a_pachNewBufEnd); + m_pachPut = a_pachNewBuf; + m_cchPut = static_cast(a_pachNewBufEnd - a_pachNewBuf); + m_offPutNext = 0; + m_offPutStart = 0; + } + + char_type *pbbase() const RT_NOEXCEPT + { + Assert(m_offPutNext >= m_offPutStart); Assert(m_offPutNext <= m_cchPut); Assert(m_offPutStart <= m_cchPut); + return &m_pachPut[m_offPutStart]; + } + + char_type *pptr() const RT_NOEXCEPT + { + Assert(m_offPutNext <= m_cchPut); + return &m_pachPut[m_offPutNext]; + } + + char_type *epptr() const RT_NOEXCEPT + { + return &m_pachBuf[m_cchPut]; + } + + void pbump(int a_cchAdvance) const RT_NOEXCEPT + { + Assert(m_offPutNext <= m_cchPut); + m_offPutNext += a_cchAdvance; + Assert(m_offPutNext <= m_cchPut); + } + /** @} */ + + protected: + basic_streambuf() RT_NOEXCEPT + : m_pachPut(NULL) + , m_cchPut(0) + , m_offPutNext(0) + , m_offPutStart(0) + { + } + + basic_streambuf(const basic_streambuf &a_rSrc) RT_NOEXCEPT + : m_pachPut(a_rSrc.m_pachPut) + , m_cchPut(a_rSrc.m_cchPut) + , m_offPutNext(a_rSrc.m_offPutNext) + , m_offPutStart(a_rSrc.m_offPutStart) + { + } + + public: + virtual ~basic_streambuf() + { + } + + /** @name Positioning + * @{ */ + protected: + virtual basic_streambuf *setbuf(char_type *a_pchBuf, std::streamsize a_cchBuf) + { + RT_NOREF(a_pchBuf, a_cchBuf); + return this; + } + public: + basic_streambuf *pubsetbuf(char_type *a_pchBuf, std::streamsize a_cchBuf) + { + return setbuf(a_pchBuf, a_cchBuf); + } + + protected: + virtual pos_type seekoff(off_type a_off, std::ios_base::seekdir a_enmDir, + std::ios_base::openmode a_enmTarget = ios_base::in | ios_base::out) + { + RT_NOREF(a_off, a_enmDir, a_enmTarget); + return pos_type(off_type(-1)); + } + public: + pos_type pubseekoff(off_type a_off, std::ios_base::seekdir a_enmDir, + std::ios_base::openmode a_enmTarget = ios_base::in | ios_base::out) + { + return seekoff(a_off, a_enmDir, a_enmTarget); + } + + protected: + virtual pos_type seekpos(pos_type a_pos, std::ios_base::openmode a_enmTarget = ios_base::in | ios_base::out) + { + RT_NOREF(a_pos, a_enmTarget); + return pos_type(off_type(-1)); + } + public: + pos_type pubseekpos(pos_type a_pos, std::ios_base::openmode a_enmTarget = ios_base::in | ios_base::out) + { + return seekpos(a_pos, a_enmTarget); + } + + protected: + virtual int sync() + { + return 0; + } + public: + pos_type pubsync() + { + return sync(); + } + /** @} */ + + /** @name Output + * @{ */ + protected: + virtual int_type overflow(int_type a_iChar) + { + RT_NOREF(a_iChar); + return traits_type::eof(); + } + + virtual std::streamsize xsputn(char_type const *a_pchSrc, std::streamsize a_cchSrc) + { + std::streamsize cchWritten = 0; + while (a_cchSrc > 0) + { + std::size_t cchCopied = m_cchPut - m_offPutNext; + if (cchCopied > 0) + { + cchCopied = RT_MIN(cchCopied, static_cast(a_cchSrc)); + traits_type::copy(&m_pachPut[m_offPutNext], a_pchSrc, cchCopied); + m_cchPut += cchCopied; + } + else + { + if (overflow(traits_type::to_int_type(m_pachPut[m_offPutNext])) != traits_type::eof()) + cchCopied = 1; + else + break; + } + a_pchSrc += cchCopied; + a_cchSrc -= cchCopied; + } + return cchWritten; + } + + public: + int_type sputc(char_type a_ch) + { + if (m_offPutNext < m_cchPut) + { + m_pachPut[m_offPutNext++] = a_ch; + return traits_type::to_int_type(a_ch); + } + return overflow(traits_type::to_int_type(a_ch)); + } + + std::streamsize sputn(char_type const *a_pchSrc, std::streamsize a_cchSrc) + { + AssertReturn(a_cchSrc >= 0, 0); + return xsputn(a_pchSrc, a_cchSrc); + } + + /** @} */ + + /** @todo add the remaining members... */ + }; + + + /** + * Basic I/O stream. + */ + template*/ > + class basic_ios : public ios_base + { + public: + typedef a_CharType char_type; + typedef a_CharTraits traits_type; + typedef typename a_CharTraits::int_type int_type; + typedef typename a_CharTraits::pos_type pos_type; + typedef typename a_CharTraits::off_type off_type; + + protected: + basic_streambuf *m_pBuf; + basic_ostream *m_pTiedStream; + + protected: + void init(std::basic_streambuf *a_pBuf) + { + m_pBuf = a_pBuf; + m_cWidth = 0; + m_cPrecision = 6; + m_fFlags = ios_base::dec | ios_base::skipws; + m_fState = ios_base::goodbit; + } + + public: + basic_ios() + : ios_base() + , m_pBuf(NULL) + , m_pTiedStream(NULL) + { + } + + basic_ios(std::basic_streambuf *a_pBuf) + : ios_base() + , m_pBuf(NULL) + , m_pTiedStream(NULL) + { + init(a_pBuf); + } + private: + basic_ios(const basic_ios &a_rSrc); /* not copyable */ + basic_ios &operator=(const basic_ios &a_rSrc); /* not copyable */ + + public: + virtual ~basic_ios() + { + } + + /** @name State methods + * @{ */ + bool good() const RT_NOEXCEPT { return m_fState == ios_base::goodbit; } + bool fail() const RT_NOEXCEPT { return (m_fState & (ios_base::failbit | ios_base::badbit)) != ios_base::goodbit; } + bool bad() const RT_NOEXCEPT { return (m_fState & ios_base::badbit) == ios_base::badbit; } + bool eof() const RT_NOEXCEPT { return (m_fState & ios_base::eofbit) != ios_base::eofbit; } +#if RT_CPLUSPLUS_PREREQ(201100) + operator bool() const RT_NOEXCEPT { return good(); } +#else + operator void*() const RT_NOEXCEPT { return good() ? NULL : this; } +#endif + bool operator!() const RT_NOEXCEPT { return fail(); } + + iostate rdstate() const RT_NOEXCEPT + { + return m_fState; + } + + void clear(iostate a_fNewState = goodbit) + { + m_fState = a_fNewState; + if (!m_pBuf) + m_fState |= badbit; + /** @todo failure exception */ + } + + void setstate(iostate a_fNewState) + { + clear(m_fState | a_fNewState); + } + /** @} */ + + /** @name Misc + * @{ */ + std::basic_streambuf *rdbuf() const RT_NOEXCEPT + { + return m_pBuf; + } + + std::basic_streambuf *rdbuf(std::basic_streambuf *a_pNewbuf) RT_NOEXCEPT + { + std::basic_streambuf *pOldBuf = m_pBuf; + m_pBuf = a_pNewBuf; + return pOldBuf; + } + + std::basic_ostream *tie() const + { + return m_pTiedStream; + } + + std::basic_ostream tie(std::basic_ostream *a_pNew) const RT_NOEXCEPT + { + std::basic_ostream * const pOld = m_pTiedStream; + m_pTiedStream = a_pNew; + return pOld; + } + /** @} */ + + /** @todo implement the rest... */ + }; +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_ios */ + diff --git a/include/iprt/nocrt/iosfwd b/include/iprt/nocrt/iosfwd new file mode 100644 index 00000000..835f4a5e --- /dev/null +++ b/include/iprt/nocrt/iosfwd @@ -0,0 +1,81 @@ +/** @file + * IPRT / No-CRT - Minimal C++ iosfwd header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_iosfwd +#define VBOX_INCLUDED_SRC_nocrt_iosfwd +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4643) /* warning C4643: Forward declaring 'ios_base' in namespace std is not permitted by the C++ Standard */ +#endif + +namespace std +{ + using streamoff = RTFOFF; + + class ios_base; + + template > class basic_ios; + template > class basic_streambuf; + template > class basic_istream; + template > class basic_ostream; + template > class basic_iostream; + template > class basic_ifstream; + template > class basic_ofstream; + template > class basic_fstream; + + + typedef basic_ios ios; + typedef basic_streambuf streambuf; + typedef basic_istream istream; + typedef basic_ostream ostream; + typedef basic_iostream iostream; + typedef basic_ifstream ifstream; + typedef basic_ofstream ofstream; + typedef basic_fstream fstream; +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !VBOX_INCLUDED_SRC_nocrt_iosfwd */ + diff --git a/include/iprt/nocrt/iostream b/include/iprt/nocrt/iostream new file mode 100644 index 00000000..d4997a99 --- /dev/null +++ b/include/iprt/nocrt/iostream @@ -0,0 +1,53 @@ +/** @file + * IPRT / No-CRT - Minimal C++ iostream header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_iostream +#define VBOX_INCLUDED_SRC_nocrt_iostream +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +namespace std +{ + extern istream cin; + extern ostream cout; + extern ostream cerr; + extern ostream clog; /**< buffered cerr */ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_iostream */ + diff --git a/include/iprt/nocrt/limits b/include/iprt/nocrt/limits new file mode 100644 index 00000000..0d414536 --- /dev/null +++ b/include/iprt/nocrt/limits @@ -0,0 +1,494 @@ +/** @file + * IPRT / No-CRT - C++ limits header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_limits +#define VBOX_INCLUDED_SRC_nocrt_limits +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +namespace std +{ + enum float_denorm_style + { + denorm_indeterminate = -1, + denorm_absent, + denorm_present, + }; + + enum float_round_style + { + round_indeterminate = -1, + round_toward_zero, + round_to_nearest, + round_toward_infinity, + round_toward_neg_infinity, + }; + + struct rtNoCrtLimitNumericBase + { + static const bool is_specialized = false; + static const bool is_integer = false; + static const bool is_signed = false; + static const bool is_exact = false; + static const bool is_bounded = false; + + static const bool has_infinity = false; + static const bool has_quiet_NaN = false; + static const bool has_signaling_NaN = false; + static const bool has_denorm_loss = false; + static const bool is_iec559 = false; + static const bool is_modulo = false; + static const bool traps = false; + static const bool tinyness_before = false; + + static const int digits = 0; + static const int digits10 = 0; + static const int max_digits10 = 0; + static const int radix = 0; + static const int min_exponent = 0; + static const int min_exponent10 = 0; + static const int max_exponent = 0; + static const int max_exponent10 = 0; + + static const float_denorm_style has_denorm = denorm_absent; + static const float_round_style round_style = round_toward_zero; + }; + + struct rtNoCrtLimitNumericIntBase : public rtNoCrtLimitNumericBase + { + static const bool is_specialized = true; + static const bool is_integer = true; + static const bool is_exact = true; + static const bool is_bounded = true; + static const int radix = 2; + }; + + struct rtNoCrtLimitNumericFloatBase : public rtNoCrtLimitNumericBase + { + static const bool is_specialized = true; + static const bool is_signed = true; + static const bool is_bounded = true; + static const bool has_infinity = false; + static const bool has_quiet_NaN = false; + static const bool has_signaling_NaN = false; + static const bool is_iec559 = false; + static const int radix = FLT_RADIX; + static const float_denorm_style has_denorm = denorm_present; + static const float_round_style round_style = round_to_nearest; + }; + + /* + * Generic template. + */ + template + struct numeric_limits : public rtNoCrtLimitNumericBase + { + /** @todo need a RT_CONSTEXPR_FN etc */ + static constexpr a_Type(min)() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type(max)() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type lowest() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type epsilon() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type round_error() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type infinity() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type quiet_NaN() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type signaling_NaN() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type denorm_min() RT_NOEXCEPT { return a_Type(); } + }; + + /* const and volatile trickery: */ + template struct numeric_limits : public numeric_limits {}; + template struct numeric_limits : public numeric_limits {}; + template struct numeric_limits : public numeric_limits {}; + + /* + * Integer specializations. + */ + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr bool(min)() RT_NOEXCEPT { return false; } + static constexpr bool(max)() RT_NOEXCEPT { return true; } + static constexpr bool lowest() RT_NOEXCEPT { return false; } + static constexpr bool epsilon() RT_NOEXCEPT { return false; } + static constexpr bool round_error() RT_NOEXCEPT { return false; } + static constexpr bool infinity() RT_NOEXCEPT { return false; } + static constexpr bool quiet_NaN() RT_NOEXCEPT { return false; } + static constexpr bool signaling_NaN() RT_NOEXCEPT { return false; } + static constexpr bool denorm_min() RT_NOEXCEPT { return false; } + static const int digits = 1; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr char(min)() RT_NOEXCEPT { return CHAR_MIN; } + static constexpr char(max)() RT_NOEXCEPT { return CHAR_MAX; } + static constexpr char lowest() RT_NOEXCEPT { return CHAR_MIN; } + static constexpr char epsilon() RT_NOEXCEPT { return 0; } + static constexpr char round_error() RT_NOEXCEPT { return 0; } + static constexpr char infinity() RT_NOEXCEPT { return 0; } + static constexpr char quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr char signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr char denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = (char)(-1) < 0; + static const bool is_modulo = (char)(-1) > 0; + static const int digits = (char)(-1) < 0 ? CHAR_BIT - 1 : CHAR_BIT; + static const int digits10 = 2; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr signed char(min)() RT_NOEXCEPT { return SCHAR_MIN; } + static constexpr signed char(max)() RT_NOEXCEPT { return SCHAR_MAX; } + static constexpr signed char lowest() RT_NOEXCEPT { return SCHAR_MIN; } + static constexpr signed char epsilon() RT_NOEXCEPT { return 0; } + static constexpr signed char round_error() RT_NOEXCEPT { return 0; } + static constexpr signed char infinity() RT_NOEXCEPT { return 0; } + static constexpr signed char quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr signed char signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr signed char denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT - 1; + static const int digits10 = 2; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned char(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned char(max)() RT_NOEXCEPT { return UCHAR_MAX; } + static constexpr unsigned char lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned char epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned char round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned char infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned char quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned char signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned char denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT; + static const int digits10 = 2; + }; + + /** @todo wchar_t, char8_t, char16_t, char32_t */ + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr short(min)() RT_NOEXCEPT { return SHRT_MIN; } + static constexpr short(max)() RT_NOEXCEPT { return SHRT_MAX; } + static constexpr short lowest() RT_NOEXCEPT { return SHRT_MIN; } + static constexpr short epsilon() RT_NOEXCEPT { return 0; } + static constexpr short round_error() RT_NOEXCEPT { return 0; } + static constexpr short infinity() RT_NOEXCEPT { return 0; } + static constexpr short quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr short signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr short denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT * sizeof(short) - 1; + static const int digits10 = 4; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned short(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned short(max)() RT_NOEXCEPT { return USHRT_MAX; } + static constexpr unsigned short lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned short epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned short round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned short infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned short quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned short signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned short denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(unsigned short); + static const int digits10 = 4; + }; + +# if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr wchar_t(min)() RT_NOEXCEPT { return WCHAR_MIN; } + static constexpr wchar_t(max)() RT_NOEXCEPT { return WCHAR_MAX; } + static constexpr wchar_t lowest() RT_NOEXCEPT { return WCHAR_MIN; } + static constexpr wchar_t epsilon() RT_NOEXCEPT { return 0; } + static constexpr wchar_t round_error() RT_NOEXCEPT { return 0; } + static constexpr wchar_t infinity() RT_NOEXCEPT { return 0; } + static constexpr wchar_t quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr wchar_t signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr wchar_t denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(wchar_t); + static const int digits10 = sizeof(wchar_t) == 2 ? 4 : 9; /** @todo ASSUMES wchar_t is either 16 or 32 bits */ + }; +# endif + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr char16_t(min)() RT_NOEXCEPT { return 0; } + static constexpr char16_t(max)() RT_NOEXCEPT { return USHRT_MAX; } + static constexpr char16_t lowest() RT_NOEXCEPT { return 0; } + static constexpr char16_t epsilon() RT_NOEXCEPT { return 0; } + static constexpr char16_t round_error() RT_NOEXCEPT { return 0; } + static constexpr char16_t infinity() RT_NOEXCEPT { return 0; } + static constexpr char16_t quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr char16_t signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr char16_t denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(char16_t); + static const int digits10 = 4; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr int(min)() RT_NOEXCEPT { return INT_MIN; } + static constexpr int(max)() RT_NOEXCEPT { return INT_MAX; } + static constexpr int lowest() RT_NOEXCEPT { return INT_MIN; } + static constexpr int epsilon() RT_NOEXCEPT { return 0; } + static constexpr int round_error() RT_NOEXCEPT { return 0; } + static constexpr int infinity() RT_NOEXCEPT { return 0; } + static constexpr int quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr int signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr int denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT * sizeof(int) - 1; + static const int digits10 = 9; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned int(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned int(max)() RT_NOEXCEPT { return UINT_MAX; } + static constexpr unsigned int lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned int epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned int round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned int infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned int quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned int signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned int denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(unsigned int); + static const int digits10 = 9; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr char32_t(min)() RT_NOEXCEPT { return 0; } + static constexpr char32_t(max)() RT_NOEXCEPT { return UINT_MAX; } + static constexpr char32_t lowest() RT_NOEXCEPT { return 0; } + static constexpr char32_t epsilon() RT_NOEXCEPT { return 0; } + static constexpr char32_t round_error() RT_NOEXCEPT { return 0; } + static constexpr char32_t infinity() RT_NOEXCEPT { return 0; } + static constexpr char32_t quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr char32_t signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr char32_t denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(char32_t); + static const int digits10 = 9; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr long(min)() RT_NOEXCEPT { return LONG_MIN; } + static constexpr long(max)() RT_NOEXCEPT { return LONG_MAX; } + static constexpr long lowest() RT_NOEXCEPT { return LONG_MIN; } + static constexpr long epsilon() RT_NOEXCEPT { return 0; } + static constexpr long round_error() RT_NOEXCEPT { return 0; } + static constexpr long infinity() RT_NOEXCEPT { return 0; } + static constexpr long quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr long signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr long denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT * sizeof(long) - 1; + static const int digits10 = sizeof(long) == sizeof(int) ? 9 : 18; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned long(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned long(max)() RT_NOEXCEPT { return ULONG_MAX; } + static constexpr unsigned long lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned long epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned long round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned long infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned long quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned long signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned long denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(unsigned long); + static const int digits10 = sizeof(unsigned long) == sizeof(unsigned int) ? 9 : 19; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr long long(min)() RT_NOEXCEPT { return LLONG_MIN; } + static constexpr long long(max)() RT_NOEXCEPT { return LLONG_MAX; } + static constexpr long long lowest() RT_NOEXCEPT { return LLONG_MIN; } + static constexpr long long epsilon() RT_NOEXCEPT { return 0; } + static constexpr long long round_error() RT_NOEXCEPT { return 0; } + static constexpr long long infinity() RT_NOEXCEPT { return 0; } + static constexpr long long quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr long long signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr long long denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT * sizeof(long long) - 1; + static const int digits10 = 18; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned long long(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long(max)() RT_NOEXCEPT { return ULLONG_MAX; } + static constexpr unsigned long long lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(unsigned long long); + static const int digits10 = 19; + }; + + + /* + * Floating point. + */ + template<> + struct numeric_limits : public rtNoCrtLimitNumericFloatBase + { + static constexpr float(min)() RT_NOEXCEPT { return FLT_MIN; } + static constexpr float(max)() RT_NOEXCEPT { return FLT_MAX; } + static constexpr float lowest() RT_NOEXCEPT { return -(FLT_MAX); } + static constexpr float epsilon() RT_NOEXCEPT { return FLT_EPSILON; } + static constexpr float round_error() RT_NOEXCEPT { return 0.5F; } + static constexpr float infinity() RT_NOEXCEPT { return __builtin_huge_valf(); } + static constexpr float quiet_NaN() RT_NOEXCEPT { return __builtin_nanf("0"); } + static constexpr float signaling_NaN() RT_NOEXCEPT { return __builtin_nansf("1"); } + static constexpr float denorm_min() RT_NOEXCEPT { return FLT_TRUE_MIN; } + + static const int digits = FLT_MANT_DIG; + static const int digits10 = FLT_DIG; + static const int max_digits10 = FLT_DECIMAL_DIG; + static const int max_exponent = FLT_MAX_EXP; + static const int max_exponent10 = FLT_MAX_10_EXP; + static const int min_exponent = FLT_MIN_EXP; + static const int min_exponent10 = FLT_MIN_10_EXP; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericFloatBase + { + static constexpr double(min)() RT_NOEXCEPT { return DBL_MIN; } + static constexpr double(max)() RT_NOEXCEPT { return DBL_MAX; } + static constexpr double lowest() RT_NOEXCEPT { return -(DBL_MAX); } + static constexpr double epsilon() RT_NOEXCEPT { return DBL_EPSILON; } + static constexpr double round_error() RT_NOEXCEPT { return 0.5; } + static constexpr double infinity() RT_NOEXCEPT { return __builtin_huge_val(); } + static constexpr double quiet_NaN() RT_NOEXCEPT { return __builtin_nan("0"); } + static constexpr double signaling_NaN() RT_NOEXCEPT { return __builtin_nans("1"); } + static constexpr double denorm_min() RT_NOEXCEPT { return DBL_TRUE_MIN; } + + static const int digits = DBL_MANT_DIG; + static const int digits10 = DBL_DIG; + static const int max_digits10 = DBL_DECIMAL_DIG; + static const int max_exponent = DBL_MAX_EXP; + static const int max_exponent10 = DBL_MAX_10_EXP; + static const int min_exponent = DBL_MIN_EXP; + static const int min_exponent10 = DBL_MIN_10_EXP; + }; + + template<> + struct numeric_limits : public rtNoCrtLimitNumericFloatBase + { + static constexpr long double(min)() RT_NOEXCEPT { return LDBL_MIN; } + static constexpr long double(max)() RT_NOEXCEPT { return LDBL_MAX; } + static constexpr long double lowest() RT_NOEXCEPT { return -(LDBL_MAX); } + static constexpr long double epsilon() RT_NOEXCEPT { return LDBL_EPSILON; } + static constexpr long double round_error() RT_NOEXCEPT { return 0.5L; } +#if LDBL_DIG == DBL_DIG + static constexpr long double infinity() RT_NOEXCEPT { return __builtin_huge_val(); } + static constexpr long double quiet_NaN() RT_NOEXCEPT { return __builtin_nan("0"); } + static constexpr long double signaling_NaN() RT_NOEXCEPT { return __builtin_nans("1"); } +#else + static constexpr long double infinity() RT_NOEXCEPT { return __builtin_huge_vall(); } + static constexpr long double quiet_NaN() RT_NOEXCEPT { return __builtin_nanl("0"); } + static constexpr long double signaling_NaN() RT_NOEXCEPT { return __builtin_nansl("1"); } +#endif + static constexpr long double denorm_min() RT_NOEXCEPT { return LDBL_TRUE_MIN; } + + static const int digits = LDBL_MANT_DIG; + static const int digits10 = LDBL_DIG; + static const int max_digits10 = LDBL_DECIMAL_DIG; + static const int max_exponent = LDBL_MAX_EXP; + static const int max_exponent10 = LDBL_MAX_10_EXP; + static const int min_exponent = LDBL_MIN_EXP; + static const int min_exponent10 = LDBL_MIN_10_EXP; + }; + + /** @todo more types */ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_limits */ + diff --git a/include/iprt/nocrt/limits.h b/include/iprt/nocrt/limits.h new file mode 100644 index 00000000..7b2e060b --- /dev/null +++ b/include/iprt/nocrt/limits.h @@ -0,0 +1,109 @@ +/** @file + * IPRT / No-CRT - Our own limits header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_limits_h +#define IPRT_INCLUDED_nocrt_limits_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#define CHAR_BIT 8 +#define SCHAR_MAX 0x7f +#define SCHAR_MIN (-0x7f - 1) +#define UCHAR_MAX 0xff +#if 1 /* ASSUMES: signed char */ +# define CHAR_MAX SCHAR_MAX +# define CHAR_MIN SCHAR_MIN +#else +# define CHAR_MAX UCHAR_MAX +# define CHAR_MIN 0 +#endif + +#define WORD_BIT 16 +#define USHRT_MAX 0xffff +#define SHRT_MAX 0x7fff +#define SHRT_MIN (-0x7fff - 1) + +/* ASSUMES 32-bit int */ +#define UINT_MAX 0xffffffffU +#define INT_MAX 0x7fffffff +#define INT_MIN (-0x7fffffff - 1) + +#if defined(RT_ARCH_X86) || defined(RT_OS_WINDOWS) || defined(RT_ARCH_SPARC) || defined(RT_ARCH_ARM32) +# define LONG_BIT 32 +# define ULONG_MAX 0xffffffffU +# define LONG_MAX 0x7fffffff +# define LONG_MIN (-0x7fffffff - 1) +#elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_SPARC64) || defined(RT_ARCH_ARM64) +# define LONG_BIT 64 +# define ULONG_MAX UINT64_C(0xffffffffffffffff) +# define LONG_MAX INT64_C(0x7fffffffffffffff) +# define LONG_MIN (INT64_C(-0x7fffffffffffffff) - 1) +#else +# error "PORTME" +#endif + +#define LLONG_BIT 64 +#define ULLONG_MAX UINT64_C(0xffffffffffffffff) +#define LLONG_MAX INT64_C(0x7fffffffffffffff) +#define LLONG_MIN (INT64_C(-0x7fffffffffffffff) - 1) + +#undef SIZE_MAX +#undef SIZE_T_MAX +#undef SSIZE_MAX +#undef INTPTR_MAX +#undef UINTPTR_MAX +#if ARCH_BITS == 32 +# define SIZE_T_MAX 0xffffffffU +# define SSIZE_MAX 0x7fffffff +# define INTPTR_MAX 0x7fffffff +# define UINTPTR_MAX 0xffffffffU +#elif ARCH_BITS == 64 +# define SIZE_T_MAX UINT64_C(0xffffffffffffffff) +# define SSIZE_MAX INT64_C(0x7fffffffffffffff) +# define INTPTR_MAX INT64_C(0x7fffffffffffffff) +# define UINTPTR_MAX UINT64_C(0xffffffffffffffff) +#else +# error "huh?" +#endif +#define SIZE_MAX SIZE_T_MAX + +/*#define OFF_MAX __OFF_MAX +#define OFF_MIN __OFF_MIN*/ + +#endif /* !IPRT_INCLUDED_nocrt_limits_h */ + diff --git a/include/iprt/nocrt/malloc.h b/include/iprt/nocrt/malloc.h new file mode 100644 index 00000000..57c5aa4f --- /dev/null +++ b/include/iprt/nocrt/malloc.h @@ -0,0 +1,49 @@ +/** @file + * IPRT / No-CRT - Our own minimal malloc.h header (needed by xmmintrin.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_malloc_h +#define IPRT_INCLUDED_nocrt_malloc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Just map it onto stdlib.h and alloca.h for now. */ +#include +#ifdef IN_RING3 +# include +#endif + +#endif /* !IPRT_INCLUDED_nocrt_malloc_h */ + diff --git a/include/iprt/nocrt/math.h b/include/iprt/nocrt/math.h new file mode 100644 index 00000000..4ae2c48c --- /dev/null +++ b/include/iprt/nocrt/math.h @@ -0,0 +1,859 @@ +/** @file + * IPRT / No-CRT - math.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + * -------------------------------------------------------------------- + * + * This code is based on: + * + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD: src/lib/msun/src/math.h,v 1.61 2005/04/16 21:12:47 das Exp $ + * FreeBSD HEAD 2005-06-xx + * + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef IPRT_INCLUDED_nocrt_math_h +#define IPRT_INCLUDED_nocrt_math_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +/*#include */ + +/* from sys/cdefs.h */ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#define __GNUC_PREREQ__(ma, mi) \ + (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi)) +#else +#define __GNUC_PREREQ__(ma, mi) 0 +#endif +#undef __pure2 /* darwin: avoid conflict with system headers when doing syntax checking of the headers */ +#define __pure2 + + +/* + * ANSI/POSIX + */ +extern const union __infinity_un { + RTFLOAT64U __uu; + double __ud; +} RT_NOCRT(__infinity); + +extern const union __nanf_un { + RTFLOAT32U __uu; + float __uf; +} RT_NOCRT(__nanf); + +#if __GNUC_PREREQ__(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800) +#define __MATH_BUILTIN_CONSTANTS +#endif + +#if __GNUC_PREREQ__(3, 0) && !defined(__INTEL_COMPILER) +#define __MATH_BUILTIN_RELOPS +#endif + +#ifndef IPRT_NOCRT_WITHOUT_CONFLICTING_CONSTANTS + +# if defined(__MATH_BUILTIN_CONSTANTS) \ + || (RT_MSC_PREREQ(RT_MSC_VER_VC140) && defined(__cplusplus)) /** @todo when was this added exactly? 2015, 2017 & 2019 has it for C++. */ +# define HUGE_VAL __builtin_huge_val() +# else +# define HUGE_VAL (RT_NOCRT(__infinity).__ud) +# endif + +/* + * XOPEN/SVID + */ +# if 1/* __BSD_VISIBLE || __XSI_VISIBLE*/ +# define M_E 2.7182818284590452354 /* e */ +# define M_LOG2E 1.4426950408889634074 /* log 2e */ +# define M_LOG10E 0.43429448190325182765 /* log 10e */ +# define M_LN2 0.69314718055994530942 /* log e2 */ +# define M_LN10 2.30258509299404568402 /* log e10 */ +# define M_PI 3.14159265358979323846 /* pi */ +# define M_PI_2 1.57079632679489661923 /* pi/2 */ +# define M_PI_4 0.78539816339744830962 /* pi/4 */ +# define M_1_PI 0.31830988618379067154 /* 1/pi */ +# define M_2_PI 0.63661977236758134308 /* 2/pi */ +# define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +# define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +# define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +# define MAXFLOAT ((float)3.40282346638528860e+38) +extern int RT_NOCRT(signgam); +# endif /* __BSD_VISIBLE || __XSI_VISIBLE */ + +# if 1/* __BSD_VISIBLE*/ +# if 0 +/* Old value from 4.4BSD-Lite math.h; this is probably better. */ +# define HUGE HUGE_VAL +# else +# define HUGE MAXFLOAT +# endif +# endif /* __BSD_VISIBLE */ + +#endif /* !IPRT_NOCRT_WITHOUT_MATH_CONSTANTS */ + +/* + * Most of these functions depend on the rounding mode and have the side + * effect of raising floating-point exceptions, so they are not declared + * as __pure2. In C99, FENV_ACCESS affects the purity of these functions. + */ +RT_C_DECLS_BEGIN +/* + * ANSI/POSIX + */ +int RT_NOCRT(__fpclassifyd)(double) __pure2; +int RT_NOCRT(__fpclassifyf)(float) __pure2; +int RT_NOCRT(__fpclassifyl)(long double) __pure2; +int RT_NOCRT(__isfinitef)(float) __pure2; +int RT_NOCRT(__isfinite)(double) __pure2; +int RT_NOCRT(__isfinitel)(long double) __pure2; +int RT_NOCRT(__isinff)(float) __pure2; +int RT_NOCRT(__isinfl)(long double) __pure2; +int RT_NOCRT(__isnanl)(long double) __pure2; +int RT_NOCRT(__isnormalf)(float) __pure2; +int RT_NOCRT(__isnormal)(double) __pure2; +int RT_NOCRT(__isnormall)(long double) __pure2; +int RT_NOCRT(__signbit)(double) __pure2; +int RT_NOCRT(__signbitf)(float) __pure2; +int RT_NOCRT(__signbitl)(long double) __pure2; + +double RT_NOCRT(acos)(double); +double RT_NOCRT(asin)(double); +double RT_NOCRT(atan)(double); +double RT_NOCRT(atan2)(double, double); +double RT_NOCRT(cos)(double); +double RT_NOCRT(sin)(double); +double RT_NOCRT(tan)(double); + +double RT_NOCRT(cosh)(double); +double RT_NOCRT(sinh)(double); +double RT_NOCRT(tanh)(double); + +double RT_NOCRT(exp)(double); +double RT_NOCRT(frexp)(double, int *); /* fundamentally !__pure2 */ +double RT_NOCRT(ldexp)(double, int); +double RT_NOCRT(log)(double); +double RT_NOCRT(log10)(double); +double RT_NOCRT(modf)(double, double *); /* fundamentally !__pure2 */ + +double RT_NOCRT(pow)(double, double); +double RT_NOCRT(sqrt)(double); + +double RT_NOCRT(ceil)(double); +double RT_NOCRT(fabs)(double) __pure2; +double RT_NOCRT(floor)(double); +double RT_NOCRT(fmod)(double, double); + +/* + * These functions are not in C90. + */ +#if 1 /*__BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE*/ +double RT_NOCRT(acosh)(double); +double RT_NOCRT(asinh)(double); +double RT_NOCRT(atanh)(double); +double RT_NOCRT(cbrt)(double); +double RT_NOCRT(erf)(double); +double RT_NOCRT(erfc)(double); +double RT_NOCRT(exp2)(double); +double RT_NOCRT(expm1)(double); +double RT_NOCRT(fma)(double, double, double); +double RT_NOCRT(hypot)(double, double); +int RT_NOCRT(ilogb)(double) __pure2; +int RT_NOCRT(isinf)(double) __pure2; +int RT_NOCRT(isnan)(double) __pure2; +double RT_NOCRT(lgamma)(double); +long long RT_NOCRT(llrint)(double); +long long RT_NOCRT(llround)(double); +double RT_NOCRT(log1p)(double); +double RT_NOCRT(logb)(double); +long RT_NOCRT(lrint)(double); +long RT_NOCRT(lround)(double); +double RT_NOCRT(nextafter)(double, double); +double RT_NOCRT(remainder)(double, double); +double RT_NOCRT(remquo)(double, double, int *); +double RT_NOCRT(rint)(double); +#endif /* __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE */ + +#if 1/* __BSD_VISIBLE || __XSI_VISIBLE*/ +double RT_NOCRT(j0)(double); +double RT_NOCRT(j1)(double); +double RT_NOCRT(jn)(int, double); +double RT_NOCRT(scalb)(double, double); +double RT_NOCRT(y0)(double); +double RT_NOCRT(y1)(double); +double RT_NOCRT(yn)(int, double); + +#if 1/* __XSI_VISIBLE <= 500 || __BSD_VISIBLE*/ +double RT_NOCRT(gamma)(double); +#endif +#endif /* __BSD_VISIBLE || __XSI_VISIBLE */ + +#if 1/* __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999*/ +double RT_NOCRT(copysign)(double, double) __pure2; +double RT_NOCRT(fdim)(double, double); +double RT_NOCRT(fmax)(double, double) __pure2; +double RT_NOCRT(fmin)(double, double) __pure2; +double RT_NOCRT(nearbyint)(double); +double RT_NOCRT(round)(double); +double RT_NOCRT(scalbln)(double, long); +double RT_NOCRT(scalbn)(double, int); +double RT_NOCRT(tgamma)(double); +double RT_NOCRT(trunc)(double); +#endif + +/* + * BSD math library entry points + */ +#if 1/* __BSD_VISIBLE*/ +double RT_NOCRT(drem)(double, double); +int RT_NOCRT(finite)(double) __pure2; +int RT_NOCRT(isnanf)(float) __pure2; + +/* + * Reentrant version of gamma & lgamma; passes signgam back by reference + * as the second argument; user must allocate space for signgam. + */ +double RT_NOCRT(gamma_r)(double, int *); +double RT_NOCRT(lgamma_r)(double, int *); + +/* + * IEEE Test Vector + */ +double RT_NOCRT(significand)(double); +#endif /* __BSD_VISIBLE */ + +/* float versions of ANSI/POSIX functions */ +#if 1/* __ISO_C_VISIBLE >= 1999*/ +float RT_NOCRT(acosf)(float); +float RT_NOCRT(asinf)(float); +float RT_NOCRT(atanf)(float); +float RT_NOCRT(atan2f)(float, float); +float RT_NOCRT(cosf)(float); +float RT_NOCRT(sinf)(float); +float RT_NOCRT(tanf)(float); + +float RT_NOCRT(coshf)(float); +float RT_NOCRT(sinhf)(float); +float RT_NOCRT(tanhf)(float); + +float RT_NOCRT(exp2f)(float); +float RT_NOCRT(expf)(float); +float RT_NOCRT(expm1f)(float); +float RT_NOCRT(frexpf)(float, int *); /* fundamentally !__pure2 */ +int RT_NOCRT(ilogbf)(float) __pure2; +float RT_NOCRT(ldexpf)(float, int); +float RT_NOCRT(log10f)(float); +float RT_NOCRT(log1pf)(float); +float RT_NOCRT(logf)(float); +float RT_NOCRT(modff)(float, float *); /* fundamentally !__pure2 */ + +float RT_NOCRT(powf)(float, float); +float RT_NOCRT(sqrtf)(float); + +float RT_NOCRT(ceilf)(float); +float RT_NOCRT(fabsf)(float) __pure2; +float RT_NOCRT(floorf)(float); +float RT_NOCRT(fmodf)(float, float); +float RT_NOCRT(roundf)(float); + +float RT_NOCRT(erff)(float); +float RT_NOCRT(erfcf)(float); +float RT_NOCRT(hypotf)(float, float); +float RT_NOCRT(lgammaf)(float); + +float RT_NOCRT(acoshf)(float); +float RT_NOCRT(asinhf)(float); +float RT_NOCRT(atanhf)(float); +float RT_NOCRT(cbrtf)(float); +float RT_NOCRT(logbf)(float); +float RT_NOCRT(copysignf)(float, float) __pure2; +long long RT_NOCRT(llrintf)(float); +long long RT_NOCRT(llroundf)(float); +long RT_NOCRT(lrintf)(float); +long RT_NOCRT(lroundf)(float); +float RT_NOCRT(nearbyintf)(float); +float RT_NOCRT(nextafterf)(float, float); +float RT_NOCRT(remainderf)(float, float); +float RT_NOCRT(remquof)(float, float, int *); +float RT_NOCRT(rintf)(float); +float RT_NOCRT(scalblnf)(float, long); +float RT_NOCRT(scalbnf)(float, int); +float RT_NOCRT(truncf)(float); + +float RT_NOCRT(fdimf)(float, float); +float RT_NOCRT(fmaf)(float, float, float); +float RT_NOCRT(fmaxf)(float, float) __pure2; +float RT_NOCRT(fminf)(float, float) __pure2; +#endif + +/* + * float versions of BSD math library entry points + */ +#if 1/* __BSD_VISIBLE*/ +float RT_NOCRT(dremf)(float, float); +int RT_NOCRT(finitef)(float) __pure2; +float RT_NOCRT(gammaf)(float); +float RT_NOCRT(j0f)(float); +float RT_NOCRT(j1f)(float); +float RT_NOCRT(jnf)(int, float); +float RT_NOCRT(scalbf)(float, float); +float RT_NOCRT(y0f)(float); +float RT_NOCRT(y1f)(float); +float RT_NOCRT(ynf)(int, float); + +/* + * Float versions of reentrant version of gamma & lgamma; passes + * signgam back by reference as the second argument; user must + * allocate space for signgam. + */ +float RT_NOCRT(gammaf_r)(float, int *); +float RT_NOCRT(lgammaf_r)(float, int *); + +/* + * float version of IEEE Test Vector + */ +float RT_NOCRT(significandf)(float); +#endif /* __BSD_VISIBLE */ + +/* + * long double versions of ISO/POSIX math functions + */ +#if 1/* __ISO_C_VISIBLE >= 1999*/ +#if 1 /* bird: we've got these */ +long double RT_NOCRT(acoshl)(long double); +long double RT_NOCRT(acosl)(long double); +long double RT_NOCRT(asinhl)(long double); +long double RT_NOCRT(asinl)(long double); +long double RT_NOCRT(atan2l)(long double, long double); +long double RT_NOCRT(atanhl)(long double); +long double RT_NOCRT(atanl)(long double); +long double RT_NOCRT(cbrtl)(long double); +#endif +long double RT_NOCRT(ceill)(long double); +long double RT_NOCRT(copysignl)(long double, long double) __pure2; +#if 1 /* bird */ +long double RT_NOCRT(coshl)(long double); +long double RT_NOCRT(cosl)(long double); +long double RT_NOCRT(erfcl)(long double); +long double RT_NOCRT(erfl)(long double); +long double RT_NOCRT(exp2l)(long double); +long double RT_NOCRT(expl)(long double); +long double RT_NOCRT(expm1l)(long double); +#endif +long double RT_NOCRT(fabsl)(long double) __pure2; +long double RT_NOCRT(fdiml)(long double, long double); +long double RT_NOCRT(floorl)(long double); +long double RT_NOCRT(fmal)(long double, long double, long double); +long double RT_NOCRT(fmaxl)(long double, long double) __pure2; +long double RT_NOCRT(fminl)(long double, long double) __pure2; +#if 1 /* bird */ +long double RT_NOCRT(fmodl)(long double, long double); +#endif +long double RT_NOCRT(frexpl)(long double value, int *); /* fundamentally !__pure2 */ +#if 1 /* bird */ +long double RT_NOCRT(hypotl)(long double, long double); +#endif +int RT_NOCRT(ilogbl)(long double) __pure2; +long double RT_NOCRT(ldexpl)(long double, int); +#if 1 /* bird */ +long double RT_NOCRT(lgammal)(long double); +long long RT_NOCRT(llrintl)(long double); +#endif +long long RT_NOCRT(llroundl)(long double); +#if 1 /* bird */ +long double RT_NOCRT(log10l)(long double); +long double RT_NOCRT(log1pl)(long double); +long double RT_NOCRT(log2l)(long double); +long double RT_NOCRT(logbl)(long double); +long double RT_NOCRT(logl)(long double); +long RT_NOCRT(lrintl)(long double); +#endif +long RT_NOCRT(lroundl)(long double); +#if 1 /* bird */ +long double RT_NOCRT(modfl)(long double, long double *); /* fundamentally !__pure2 */ +long double RT_NOCRT(nanl)(const char *) __pure2; +long double RT_NOCRT(nearbyintl)(long double); +#endif +long double RT_NOCRT(nextafterl)(long double, long double); +double RT_NOCRT(nexttoward)(double, long double); +float RT_NOCRT(nexttowardf)(float, long double); +long double RT_NOCRT(nexttowardl)(long double, long double); +#if 1 /* bird */ +long double RT_NOCRT(powl)(long double, long double); +long double RT_NOCRT(remainderl)(long double, long double); +long double RT_NOCRT(remquol)(long double, long double, int *); +long double RT_NOCRT(rintl)(long double); +#endif +long double RT_NOCRT(roundl)(long double); +long double RT_NOCRT(scalblnl)(long double, long); +long double RT_NOCRT(scalbnl)(long double, int); +#if 1 /* bird: we 've got most of these. */ +long double RT_NOCRT(sinhl)(long double); +long double RT_NOCRT(sinl)(long double); +long double RT_NOCRT(sqrtl)(long double); +long double RT_NOCRT(tanhl)(long double); +long double RT_NOCRT(tanl)(long double); +long double RT_NOCRT(tgammal)(long double); +#endif +long double RT_NOCRT(truncl)(long double); + +/* bird: these were missing, gcc apparently inlines them. */ +double RT_NOCRT(nan)(const char *); +float RT_NOCRT(nanf)(const char *); + +#endif /* __ISO_C_VISIBLE >= 1999 */ + +#ifndef IPRT_NOCRT_WITHOUT_CONFLICTING_CONSTANTS /*def __USE_GNU*/ +/* + * In GLIBC there are long variants of the XOPEN/SVID constant + * block some pages ago. We need this to get the math tests going. + */ +# define M_El 2.7182818284590452353602874713526625L +# define M_LOG2El 1.4426950408889634073599246810018921L +# define M_LOG10El 0.4342944819032518276511289189166051L +# define M_LN2l 0.6931471805599453094172321214581766L +# define M_LN10l 2.3025850929940456840179914546843642L +# define M_PIl 3.1415926535897932384626433832795029L +# define M_PI_2l 1.5707963267948966192313216916397514L +# define M_PI_4l 0.7853981633974483096156608458198757L +# define M_1_PIl 0.3183098861837906715377675267450287L +# define M_2_PIl 0.6366197723675813430755350534900574L +# define M_2_SQRTPIl 1.1283791670955125738961589031215452L +# define M_SQRT2l 1.4142135623730950488016887242096981L +# define M_SQRT1_2l 0.7071067811865475244008443621048490L +#endif /* !IPRT_NOCRT_WITHOUT_MATH_CONSTANTS */ + +#if 1/*def __USE_GNU*/ + +void RT_NOCRT(sincos)(double, double *, double *); +void RT_NOCRT(sincosf)(float, float *, float *); +void RT_NOCRT(sincosl)(long double, long double *, long double *); +float RT_NOCRT(exp10f)(float); +double RT_NOCRT(exp10)(double); +long double RT_NOCRT(exp10l)(long double); +float RT_NOCRT(log2f)(float); +double RT_NOCRT(log2)(double); +long double RT_NOCRT(log2l)(long double); +float RT_NOCRT(tgammaf)(float); +long double RT_NOCRT(significandl)(long double); +long double RT_NOCRT(j0l)(long double); +long double RT_NOCRT(j1l)(long double); +long double RT_NOCRT(jnl)(int, long double); +long double RT_NOCRT(scalbl)(long double, long double); +long double RT_NOCRT(y0l)(long double); +long double RT_NOCRT(y1l)(long double); +long double RT_NOCRT(ynl)(int, long double); +long double RT_NOCRT(lgammal_r)(long double,int *); +long double RT_NOCRT(gammal)(long double); +#endif + + +RT_C_DECLS_END + + +/** @name fpclassify return values + * @{ */ +#define RT_NOCRT_FP_INFINITE 0x01 +#define RT_NOCRT_FP_NAN 0x02 +#define RT_NOCRT_FP_NORMAL 0x04 +#define RT_NOCRT_FP_SUBNORMAL 0x08 +#define RT_NOCRT_FP_ZERO 0x10 +/** @} */ + +/* bird 2022-08-03: moved this block down so we can prototype isnan & isinf without runnning into the macro forms. */ +#ifndef IPRT_NOCRT_WITHOUT_CONFLICTING_CONSTANTS /* __ISO_C_VISIBLE >= 1999*/ +# define FP_ILOGB0 (-__INT_MAX) +# define FP_ILOGBNAN __INT_MAX + +# ifdef __MATH_BUILTIN_CONSTANTS +# define HUGE_VALF __builtin_huge_valf() +# define HUGE_VALL __builtin_huge_vall() +# define INFINITY __builtin_inf() +# define NAN __builtin_nan("") +# elif RT_MSC_PREREQ(RT_MSC_VER_VC140) && defined(__cplusplus) +/** @todo When were these introduced exactly? 2015, 2017 & 2019 has them. + * However, they only work in C++ even if the c1.dll includes the strings. Oh, well. */ +# define HUGE_VALF __builtin_huge_valf() +# define HUGE_VALL __builtin_huge_val() +# define INFINITY __builtin_huge_val() +# define NAN __builtin_nan("0") /* same as we use in climits */ +# else +# define HUGE_VALF (float)HUGE_VAL +# define HUGE_VALL (long double)HUGE_VAL +# define INFINITY HUGE_VALF +# define NAN (__nanf.__uf) +# endif /* __MATH_BUILTIN_CONSTANTS */ + +# ifndef IPRT_NO_CRT +# define MATH_ERRNO 1 +# endif +# define MATH_ERREXCEPT 2 +# define math_errhandling MATH_ERREXCEPT + +/* XXX We need a . */ +# if defined(__ia64__) || defined(__sparc64__) +# define FP_FAST_FMA +# endif +# ifdef __ia64__ +# define FP_FAST_FMAL +# endif +# define FP_FAST_FMAF + +/* Symbolic constants to classify floating point numbers. */ +# define FP_INFINITE RT_NOCRT_FP_INFINITE +# define FP_NAN RT_NOCRT_FP_NAN +# define FP_NORMAL RT_NOCRT_FP_NORMAL +# define FP_SUBNORMAL RT_NOCRT_FP_SUBNORMAL +# define FP_ZERO RT_NOCRT_FP_ZERO +# define fpclassify(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__fpclassifyf)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(__fpclassifyd)(x) \ + : RT_NOCRT(__fpclassifyl)(x)) + +# define isfinite(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__isfinitef)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(__isfinite)(x) \ + : RT_NOCRT(__isfinitel)(x)) +# define isinf(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__isinff)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(isinf)(x) \ + : RT_NOCRT(__isinfl)(x)) +# define isnan(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(isnanf)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(isnan)(x) \ + : RT_NOCRT(__isnanl)(x)) +# define isnormal(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__isnormalf)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(__isnormal)(x) \ + : RT_NOCRT(__isnormall)(x)) + +# ifdef __MATH_BUILTIN_RELOPS +# define isgreater(x, y) __builtin_isgreater((x), (y)) +# define isgreaterequal(x, y) __builtin_isgreaterequal((x), (y)) +# define isless(x, y) __builtin_isless((x), (y)) +# define islessequal(x, y) __builtin_islessequal((x), (y)) +# define islessgreater(x, y) __builtin_islessgreater((x), (y)) +# define isunordered(x, y) __builtin_isunordered((x), (y)) +# else +# define isgreater(x, y) (!isunordered((x), (y)) && (x) > (y)) +# define isgreaterequal(x, y) (!isunordered((x), (y)) && (x) >= (y)) +# define isless(x, y) (!isunordered((x), (y)) && (x) < (y)) +# define islessequal(x, y) (!isunordered((x), (y)) && (x) <= (y)) +# define islessgreater(x, y) (!isunordered((x), (y)) && \ + ((x) > (y) || (y) > (x))) +# define isunordered(x, y) (isnan(x) || isnan(y)) +# endif /* __MATH_BUILTIN_RELOPS */ + +# define signbit(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__signbitf)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(__signbit)(x) \ + : RT_NOCRT(__signbitl)(x)) + +typedef double double_t; +typedef float float_t; +#endif /* !IPRT_NOCRT_WITHOUT_MATH_CONSTANTS */ /* __ISO_C_VISIBLE >= 1999 */ + + +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +/* sed -e "/#/d" -e "/RT_NOCRT/!d" -e "s/^.*RT_NOCRT(\([a-z0-9_]*\)).*$/# define \1 RT_NOCRT(\1)/" */ +# define __fpclassifyf RT_NOCRT(__fpclassifyf) +# define __fpclassifyd RT_NOCRT(__fpclassifyd) +# define __fpclassifyl RT_NOCRT(__fpclassifyl) +# define __isfinitef RT_NOCRT(__isfinitef) +# define __isfinite RT_NOCRT(__isfinite) +# define __isfinitel RT_NOCRT(__isfinitel) +# define __isinff RT_NOCRT(__isinff) +# define __isinfl RT_NOCRT(__isinfl) +# define __isnanl RT_NOCRT(__isnanl) +# define __isnormalf RT_NOCRT(__isnormalf) +# define __isnormal RT_NOCRT(__isnormal) +# define __isnormall RT_NOCRT(__isnormall) +# define __signbitf RT_NOCRT(__signbitf) +# define __signbit RT_NOCRT(__signbit) +# define __signbitl RT_NOCRT(__signbitl) +# define signgam RT_NOCRT(signgam) +# define __fpclassifyd RT_NOCRT(__fpclassifyd) +# define __fpclassifyf RT_NOCRT(__fpclassifyf) +# define __fpclassifyl RT_NOCRT(__fpclassifyl) +# define __isfinitef RT_NOCRT(__isfinitef) +# define __isfinite RT_NOCRT(__isfinite) +# define __isfinitel RT_NOCRT(__isfinitel) +# define __isinff RT_NOCRT(__isinff) +# define __isinfl RT_NOCRT(__isinfl) +# define __isnanl RT_NOCRT(__isnanl) +# define __isnormalf RT_NOCRT(__isnormalf) +# define __isnormal RT_NOCRT(__isnormal) +# define __isnormall RT_NOCRT(__isnormall) +# define __signbit RT_NOCRT(__signbit) +# define __signbitf RT_NOCRT(__signbitf) +# define __signbitl RT_NOCRT(__signbitl) +# define acos RT_NOCRT(acos) +# define asin RT_NOCRT(asin) +# define atan RT_NOCRT(atan) +# define atan2 RT_NOCRT(atan2) +# define cos RT_NOCRT(cos) +# define sin RT_NOCRT(sin) +# define tan RT_NOCRT(tan) +# define cosh RT_NOCRT(cosh) +# define sinh RT_NOCRT(sinh) +# define tanh RT_NOCRT(tanh) +# define exp RT_NOCRT(exp) +# define frexp RT_NOCRT(frexp) +# define ldexp RT_NOCRT(ldexp) +# define log RT_NOCRT(log) +# define log10 RT_NOCRT(log10) +# define modf RT_NOCRT(modf) +# define pow RT_NOCRT(pow) +# define sqrt RT_NOCRT(sqrt) +# define ceil RT_NOCRT(ceil) +# define fabs RT_NOCRT(fabs) +# define floor RT_NOCRT(floor) +# define fmod RT_NOCRT(fmod) +# define acosh RT_NOCRT(acosh) +# define asinh RT_NOCRT(asinh) +# define atanh RT_NOCRT(atanh) +# define cbrt RT_NOCRT(cbrt) +# define erf RT_NOCRT(erf) +# define erfc RT_NOCRT(erfc) +# define exp2 RT_NOCRT(exp2) +# define expm1 RT_NOCRT(expm1) +# define fma RT_NOCRT(fma) +# define hypot RT_NOCRT(hypot) +# define ilogb RT_NOCRT(ilogb) +# define lgamma RT_NOCRT(lgamma) +# define llrint RT_NOCRT(llrint) +# define llround RT_NOCRT(llround) +# define log1p RT_NOCRT(log1p) +# define logb RT_NOCRT(logb) +# define lrint RT_NOCRT(lrint) +# define lround RT_NOCRT(lround) +# define nextafter RT_NOCRT(nextafter) +# define remainder RT_NOCRT(remainder) +# define remquo RT_NOCRT(remquo) +# define rint RT_NOCRT(rint) +# define j0 RT_NOCRT(j0) +# define j1 RT_NOCRT(j1) +# define jn RT_NOCRT(jn) +# define scalb RT_NOCRT(scalb) +# define y0 RT_NOCRT(y0) +# define y1 RT_NOCRT(y1) +# define yn RT_NOCRT(yn) +# define gamma RT_NOCRT(gamma) +# define copysign RT_NOCRT(copysign) +# define fdim RT_NOCRT(fdim) +# define fmax RT_NOCRT(fmax) +# define fmin RT_NOCRT(fmin) +# define nearbyint RT_NOCRT(nearbyint) +# define round RT_NOCRT(round) +# define scalbln RT_NOCRT(scalbln) +# define scalbn RT_NOCRT(scalbn) +# define tgamma RT_NOCRT(tgamma) +# define trunc RT_NOCRT(trunc) +# define drem RT_NOCRT(drem) +# define finite RT_NOCRT(finite) +/*# define isinf RT_NOCRT(isinf) - already a macro */ +/*# define isnan RT_NOCRT(isnan) - already a macro */ +# define isnanf RT_NOCRT(isnanf) +# define gamma_r RT_NOCRT(gamma_r) +# define lgamma_r RT_NOCRT(lgamma_r) +# define significand RT_NOCRT(significand) +# define acosf RT_NOCRT(acosf) +# define asinf RT_NOCRT(asinf) +# define atanf RT_NOCRT(atanf) +# define atan2f RT_NOCRT(atan2f) +# define cosf RT_NOCRT(cosf) +# define sinf RT_NOCRT(sinf) +# define tanf RT_NOCRT(tanf) +# define coshf RT_NOCRT(coshf) +# define sinhf RT_NOCRT(sinhf) +# define tanhf RT_NOCRT(tanhf) +# define exp2f RT_NOCRT(exp2f) +# define expf RT_NOCRT(expf) +# define expm1f RT_NOCRT(expm1f) +# define frexpf RT_NOCRT(frexpf) +# define ilogbf RT_NOCRT(ilogbf) +# define ldexpf RT_NOCRT(ldexpf) +# define log10f RT_NOCRT(log10f) +# define log1pf RT_NOCRT(log1pf) +# define logf RT_NOCRT(logf) +# define modff RT_NOCRT(modff) +# define powf RT_NOCRT(powf) +# define sqrtf RT_NOCRT(sqrtf) +# define ceilf RT_NOCRT(ceilf) +# define fabsf RT_NOCRT(fabsf) +# define floorf RT_NOCRT(floorf) +# define fmodf RT_NOCRT(fmodf) +# define roundf RT_NOCRT(roundf) +# define erff RT_NOCRT(erff) +# define erfcf RT_NOCRT(erfcf) +# define hypotf RT_NOCRT(hypotf) +# define lgammaf RT_NOCRT(lgammaf) +# define acoshf RT_NOCRT(acoshf) +# define asinhf RT_NOCRT(asinhf) +# define atanhf RT_NOCRT(atanhf) +# define cbrtf RT_NOCRT(cbrtf) +# define logbf RT_NOCRT(logbf) +# define copysignf RT_NOCRT(copysignf) +# define llrintf RT_NOCRT(llrintf) +# define llroundf RT_NOCRT(llroundf) +# define lrintf RT_NOCRT(lrintf) +# define lroundf RT_NOCRT(lroundf) +# define nearbyintf RT_NOCRT(nearbyintf) +# define nextafterf RT_NOCRT(nextafterf) +# define remainderf RT_NOCRT(remainderf) +# define remquof RT_NOCRT(remquof) +# define rintf RT_NOCRT(rintf) +# define scalblnf RT_NOCRT(scalblnf) +# define scalbnf RT_NOCRT(scalbnf) +# define truncf RT_NOCRT(truncf) +# define fdimf RT_NOCRT(fdimf) +# define fmaf RT_NOCRT(fmaf) +# define fmaxf RT_NOCRT(fmaxf) +# define fminf RT_NOCRT(fminf) +# define dremf RT_NOCRT(dremf) +# define finitef RT_NOCRT(finitef) +# define gammaf RT_NOCRT(gammaf) +# define j0f RT_NOCRT(j0f) +# define j1f RT_NOCRT(j1f) +# define jnf RT_NOCRT(jnf) +# define scalbf RT_NOCRT(scalbf) +# define y0f RT_NOCRT(y0f) +# define y1f RT_NOCRT(y1f) +# define ynf RT_NOCRT(ynf) +# define gammaf_r RT_NOCRT(gammaf_r) +# define lgammaf_r RT_NOCRT(lgammaf_r) +# define significandf RT_NOCRT(significandf) +# define acoshl RT_NOCRT(acoshl) +# define acosl RT_NOCRT(acosl) +# define asinhl RT_NOCRT(asinhl) +# define asinl RT_NOCRT(asinl) +# define atan2l RT_NOCRT(atan2l) +# define atanhl RT_NOCRT(atanhl) +# define atanl RT_NOCRT(atanl) +# define cbrtl RT_NOCRT(cbrtl) +# define ceill RT_NOCRT(ceill) +# define copysignl RT_NOCRT(copysignl) +# define coshl RT_NOCRT(coshl) +# define cosl RT_NOCRT(cosl) +# define erfcl RT_NOCRT(erfcl) +# define erfl RT_NOCRT(erfl) +# define exp2l RT_NOCRT(exp2l) +# define expl RT_NOCRT(expl) +# define expm1l RT_NOCRT(expm1l) +# define fabsl RT_NOCRT(fabsl) +# define fdiml RT_NOCRT(fdiml) +# define floorl RT_NOCRT(floorl) +# define fmal RT_NOCRT(fmal) +# define fmaxl RT_NOCRT(fmaxl) +# define fminl RT_NOCRT(fminl) +# define fmodl RT_NOCRT(fmodl) +# define frexpl RT_NOCRT(frexpl) +# define hypotl RT_NOCRT(hypotl) +# define ilogbl RT_NOCRT(ilogbl) +# define ldexpl RT_NOCRT(ldexpl) +# define lgammal RT_NOCRT(lgammal) +# define llrintl RT_NOCRT(llrintl) +# define llroundl RT_NOCRT(llroundl) +# define log10l RT_NOCRT(log10l) +# define log1pl RT_NOCRT(log1pl) +# define log2l RT_NOCRT(log2l) +# define logbl RT_NOCRT(logbl) +# define logl RT_NOCRT(logl) +# define lrintl RT_NOCRT(lrintl) +# define lroundl RT_NOCRT(lroundl) +# define modfl RT_NOCRT(modfl) +# define nanl RT_NOCRT(nanl) +# define nearbyintl RT_NOCRT(nearbyintl) +# define nextafterl RT_NOCRT(nextafterl) +# define nexttoward RT_NOCRT(nexttoward) +# define nexttowardf RT_NOCRT(nexttowardf) +# define nexttowardl RT_NOCRT(nexttowardl) +# define powl RT_NOCRT(powl) +# define remainderl RT_NOCRT(remainderl) +# define remquol RT_NOCRT(remquol) +# define rintl RT_NOCRT(rintl) +# define roundl RT_NOCRT(roundl) +# define scalblnl RT_NOCRT(scalblnl) +# define scalbnl RT_NOCRT(scalbnl) +# define sinhl RT_NOCRT(sinhl) +# define sinl RT_NOCRT(sinl) +# define sqrtl RT_NOCRT(sqrtl) +# define tanhl RT_NOCRT(tanhl) +# define tanl RT_NOCRT(tanl) +# define tgammal RT_NOCRT(tgammal) +# define truncl RT_NOCRT(truncl) +# define nan RT_NOCRT(nan) +# define nanf RT_NOCRT(nanf) +# define sincos RT_NOCRT(sincos) +# define sincosf RT_NOCRT(sincosf) +# define sincosl RT_NOCRT(sincosl) +# define exp10f RT_NOCRT(exp10f) +# define exp10 RT_NOCRT(exp10) +# define exp10l RT_NOCRT(exp10l) +# define log2f RT_NOCRT(log2f) +# define log2 RT_NOCRT(log2) +# define log2l RT_NOCRT(log2l) +# define tgammaf RT_NOCRT(tgammaf) +# define significandl RT_NOCRT(significandl) +# define j0l RT_NOCRT(j0l) +# define j1l RT_NOCRT(j1l) +# define jnl RT_NOCRT(jnl) +# define scalbl RT_NOCRT(scalbl) +# define y0l RT_NOCRT(y0l) +# define y1l RT_NOCRT(y1l) +# define ynl RT_NOCRT(ynl) +# define lgammal_r RT_NOCRT(lgammal_r) +# define gammal RT_NOCRT(gammal) +#endif + +/* + * Include inlined implementations. + */ +#ifdef RT_ARCH_AMD64 +# include +#elif defined(RT_ARCH_X86) +# include +#endif + +#endif /* !IPRT_INCLUDED_nocrt_math_h */ + diff --git a/include/iprt/nocrt/memory b/include/iprt/nocrt/memory new file mode 100644 index 00000000..6399c414 --- /dev/null +++ b/include/iprt/nocrt/memory @@ -0,0 +1,108 @@ +/** @file + * IPRT / No-CRT - Minimal C++ std::memory. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_memory +#define VBOX_INCLUDED_SRC_nocrt_memory +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +namespace std +{ + /** + * Simple allocator - not C++11 compliant. + */ + template class allocator + { + public: + typedef a_Type value_type; + typedef a_Type const &const_reference; + typedef a_Type *pointer; + typedef a_Type const *const_pointer; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + public: + allocator() RT_NOEXCEPT + { } + + allocator(allocator const &a_rThat) RT_NOEXCEPT + { RT_NOREF(a_rThat); } + + ~allocator() + { } + + a_Type *allocate(size_type a_cItems, const void *a_pvHint = NULL) + { + RT_NOREF(a_pvHint); + Assert(a_cItems <= max_size()); /** @todo throw stuff */ + return static_cast(::operator new(sizeof(value_type) * a_cItems)); + } + + void deallocate(a_Type *a_paItems, size_type a_cItems) + { + if (a_paItems && a_cItems > 0) + ::operator delete(a_paItems); + } + + size_type max_size() const + { + /* whatever */ +#if ARCH_BITS >= 64 + return _4G / sizeof(value_type); +#else + return _512M / sizeof(value_type); +#endif + } + + void construct(pointer a_pDst, const_reference a_rSrc) + { + ::new (static_cast(a_pDst)) a_Type(a_rSrc); + } + + void destroy(pointer a_pDst) + { + a_pDst->~value_type(); + } + }; + + /** @todo make_unique and unique */ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_memory */ + diff --git a/include/iprt/nocrt/new b/include/iprt/nocrt/new new file mode 100644 index 00000000..ce8929c4 --- /dev/null +++ b/include/iprt/nocrt/new @@ -0,0 +1,118 @@ +/** @file + * IPRT / No-CRT - Our own new header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_new +#define VBOX_INCLUDED_SRC_nocrt_new +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** MSC declares the operators as cdecl it seems. */ +#ifdef _MSC_VER +# define RT_NEW_DELETE_CDECL __cdecl +#else +# define RT_NEW_DELETE_CDECL +#endif + +/** MSC doesn't use the standard namespace. */ +#ifdef _MSC_VER +# define RT_NEW_DELETE_SIZE_T size_t +#else +# define RT_NEW_DELETE_SIZE_T std::size_t +#endif + +/** The hint that we're throwing std::bad_alloc is not apprecitated by MSC. */ +#ifdef RT_EXCEPTIONS_ENABLED +# ifdef _MSC_VER +# define RT_NEW_DELETE_THROWS_BAD_ALLOC +# define RT_NEW_DELETE_NOTHROW RT_NO_THROW_DEF +# else +# ifdef _GLIBCXX_THROW +# define RT_NEW_DELETE_THROWS_BAD_ALLOC _GLIBCXX_THROW(std::bad_alloc) +# elif defined(__cplusplus) && (__cplusplus + 0) < 201700 +# define RT_NEW_DELETE_THROWS_BAD_ALLOC throw(std::bad_alloc) +# else +# define RT_NEW_DELETE_THROWS_BAD_ALLOC noexcept(false) +# endif +# define RT_NEW_DELETE_NOTHROW throw() +# endif +#else /* !RT_EXCEPTIONS_ENABLED */ +# define RT_NEW_DELETE_THROWS_BAD_ALLOC +# define RT_NEW_DELETE_NOTHROW +#endif /* !RT_EXCEPTIONS_ENABLED */ + + +#ifdef IPRT_NO_CRT + +namespace std +{ + struct nothrow_t + { + explicit nothrow_t() + {} + }; + extern __declspec(selectany) nothrow_t const nothrow; +} + + +void *RT_NEW_DELETE_CDECL operator new(RT_NEW_DELETE_SIZE_T cb) RT_NEW_DELETE_THROWS_BAD_ALLOC; +void *RT_NEW_DELETE_CDECL operator new(RT_NEW_DELETE_SIZE_T cb, const std::nothrow_t &) RT_NEW_DELETE_NOTHROW; +void *RT_NEW_DELETE_CDECL operator new(RT_NEW_DELETE_SIZE_T cb, void *pvPlacement) RT_NEW_DELETE_NOTHROW; +void RT_NEW_DELETE_CDECL operator delete(void *pv) RT_NEW_DELETE_NOTHROW; +#ifdef __cpp_sized_deallocation +void RT_NEW_DELETE_CDECL operator delete(void *pv, RT_NEW_DELETE_SIZE_T cb) RT_NEW_DELETE_NOTHROW; +#endif +void RT_NEW_DELETE_CDECL operator delete(void *pv, const std::nothrow_t &) RT_NEW_DELETE_NOTHROW; + + +void *RT_NEW_DELETE_CDECL operator new[](RT_NEW_DELETE_SIZE_T cb) RT_NEW_DELETE_THROWS_BAD_ALLOC; +void *RT_NEW_DELETE_CDECL operator new[](RT_NEW_DELETE_SIZE_T cb, const std::nothrow_t &) RT_NEW_DELETE_NOTHROW; +void *RT_NEW_DELETE_CDECL operator new[](RT_NEW_DELETE_SIZE_T cb, void *pvPlacement) RT_NEW_DELETE_NOTHROW; +void RT_NEW_DELETE_CDECL operator delete[](void * pv) RT_NEW_DELETE_NOTHROW; +#ifdef __cpp_sized_deallocation +void RT_NEW_DELETE_CDECL operator delete[](void * pv, RT_NEW_DELETE_SIZE_T cb) RT_NEW_DELETE_NOTHROW; +#endif +void RT_NEW_DELETE_CDECL operator delete[](void *pv, const std::nothrow_t &) RT_NEW_DELETE_NOTHROW; + + +#else /* IPRT_NO_CRT */ +# include +#endif /* IPRT_NO_CRT */ + +#endif /* !VBOX_INCLUDED_SRC_nocrt_new */ + diff --git a/include/iprt/nocrt/ostream b/include/iprt/nocrt/ostream new file mode 100644 index 00000000..98820e27 --- /dev/null +++ b/include/iprt/nocrt/ostream @@ -0,0 +1,280 @@ +/** @file + * IPRT / No-CRT - Minimal C++ ostream header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_ostream +#define VBOX_INCLUDED_SRC_nocrt_ostream +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Currently all in the ios header. */ +#include + +namespace std +{ + /** + * Basic output stream. + */ + template*/ > + class basic_ostream : public basic_ios + { + protected: + /** Sentry class that performs pre and post output work. */ + class sentry + { + private: + basic_ostream &m_rParent; + + public: + explicit sentry(basic_ostream &a_rParent) + : m_rParent(a_rParent) + { + if (a_rParent.good()) + { + basic_ostream *pTiedStream = a_rParent.tie(); + if (!pTiedStream) + { /* likely? */ } + else + { + pTiedStream->flush(); + if (!pTiedStream->good()) + a_rParent.setstate(failbit); + } + } + } + + explicit operator bool() const + { + return m_rParent.good(); + } + + ~sentry() + { + if ( (m_rParent.flags() & std::ios_base::unitbuf) + && m_rParent.good()) + m_rParent.rdbuf()->pubsync(); + } + }; + + public: + explicit basic_ostream(std::basic_streambuf *a_pBuf) + : basic_ios(a_pBuf) + { } + + /** For cerr initialization. + * @internal */ + explicit basic_ostream(std::basic_streambuf *a_pBuf, + std::basic_ostream *a_pTiedStream, + bool a_fUnbuffered) + : basic_ios(a_pBuf) + { + m_pTiedStream = a_pTiedStream; + if (!a_fUnbuffered) + setf(std::ios_base::unitbuf); + } + + private: + basic_ostream(basic_ostream const &a_rSrc); /* not copyable */ + basic_ostream &operator=(basic_ostream const &a_rSrc); /* not copyable */ + + public: + virtual ~basic_ostream() + { + } + + public: + basic_ostream &put(char_type a_ch) + { + sentry PrePost(*this); + if (PrePost) + { + if (m_pBuf->sputc(a_ch) == traits_type::eof()) + m_fState |= badbit; + } + return *this; + } + + basic_ostream &write(const char_type *a_pchSrc, std::streamsize a_cchToWrite) + { + sentry PrePost(*this); + if (PrePost) + { + std::streamsize cchWritten = m_pBuf->sputn(a_pchSrc, a_cchToWrite); + if (cchWritten != a_cchToWrite) + m_fState |= badbit; + } + return *this; + } + + basic_ostream &flush() + { + if (m_pBuf) + m_pBuf->pubsync(); + return *this; + } + + pos_type tellp() RT_NOEXCEPT; + basic_ostream &seekp(pos_type a_off) RT_NOEXCEPT; + basic_ostream &seekp(off_type a_off, seekdir enmDir) RT_NOEXCEPT; + + /** @name Internal support methods + * @{ */ + inline basic_ostream &intWrite(const char *a_pchSrc, std::streamsize a_cchToWrite); /**< Internal method outputting char buffers. */ + + /** @returns 8, 10 or 16. */ + inline unsigned intGetIntegerBase() const RT_NOEXCEPT + { + switch (m_fFlags & basefield) + { + default: + case dec: return 10; + case hex: return 16; + case oct: return 8; + } + } + + /** @returns RTSTR_F_XXX . */ + inline unsigned intGetIntegerFlags() const RT_NOEXCEPT + { + unsigned fFlags = 0; + if (m_fFlags & uppercase) + fFlags |= RTSTR_F_CAPITAL; + if (m_fFlags & showbase) + fFlags |= RTSTR_F_SPECIAL; + if (m_fFlags & showpos) + fFlags |= RTSTR_F_PLUS; + return fFlags; + } + + basic_ostream &formatInteger(uint64_t a_uValue, uint32_t a_fFlags, unsigned a_uBase = 0) + { + a_fFlags |= intGetIntegerFlags(); + char szTmp[72]; + int cchTmp = RTStrFormatNumber(szTmp, a_uValue, !a_uBase ? intGetIntegerBase() : a_uBase, 0, 0, a_fFlags); + + /** @todo apply cchWidth and padding. */ + + return intWrite(szTmp, cchTmp); + } + + /** @} */ + }; + + /** @name Character and string output. + * @{ */ + /** @todo not sure if this really works... */ + template > + basic_ostream &operator<<(basic_ostream &a_rDst, char a_ch) + { + return a_rDst.put(a_ch); + } + + template > + basic_ostream &operator<<(basic_ostream &a_rDst, const char *a_psz) + { + return a_rDst.intWrite(a_psz, strlen(a_psz)); + } + /** @} */ + + /** @name Integer formatting. + * @{ */ + template > + basic_ostream &operator<<(basic_ostream &a_rDst, signed char a_iValue) + { + return a_rDst.formatInteger(a_iValue, RTSTR_F_8BIT | RTSTR_F_VALSIGNED); + } + + template > + basic_ostream &operator<<(basic_ostream &a_rDst, unsigned char a_uValue) + { + return a_rDst.formatInteger(a_uValue, RTSTR_F_8BIT); + } + + template > + basic_ostream &operator<<(basic_ostream &a_rDst, short a_iValue) + { + return a_rDst.formatInteger(a_iValue, RTSTR_F_16BIT | RTSTR_F_VALSIGNED); + } + + template > + basic_ostream &operator<<(basic_ostream &a_rDst, unsigned short a_uValue) + { + return a_rDst.formatInteger(a_uValue, RTSTR_F_16BIT); + } + + template > + basic_ostream &operator<<(basic_ostream &a_rDst, int a_iValue) + { + return a_rDst.formatInteger(a_iValue, RTSTR_F_32BIT | RTSTR_F_VALSIGNED); + } + + template > + basic_ostream &operator<<(basic_ostream &a_rDst, unsigned int a_uValue) + { + return a_rDst.formatInteger(a_uValue, RTSTR_F_32BIT | RTSTR_F_VALSIGNED); + } + + template > + basic_ostream &operator<<(basic_ostream &a_rDst, long a_iValue) + { + return a_rDst.formatInteger(a_iValue, (sizeof(a_iValue) > sizeof(int32_t) ? RTSTR_F_64BIT : RTSTR_F_32BIT)); + } + + template > + basic_ostream &operator<<(basic_ostream &a_rDst, unsigned long a_uValue) + { + return a_rDst.formatInteger(a_uValue, + RTSTR_F_VALSIGNED | (sizeof(a_uValue) > sizeof(uint32_t) ? RTSTR_F_64BIT : RTSTR_F_32BIT)); + } + + template > + basic_ostream &operator<<(basic_ostream &a_rDst, void const *a_pvValue) + { + return a_rDst.formatInteger((uintptr_t)a_pvValue, + (sizeof(a_pvValue) > sizeof(uint32_t) ? RTSTR_F_64BIT : RTSTR_F_32BIT), 16); + } + /** @} */ + + template<> + inline basic_ostream &basic_ostream::intWrite(const char *a_pchSrc, std::streamsize a_cchToWrite) + { + return write(a_pchSrc, a_cchToWrite); + } + + +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_ostream */ + diff --git a/include/iprt/nocrt/process.h b/include/iprt/nocrt/process.h new file mode 100644 index 00000000..f965813c --- /dev/null +++ b/include/iprt/nocrt/process.h @@ -0,0 +1,43 @@ +/** @file + * IPRT / No-CRT - Stub process.h header for MSC compatibility. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_process_h +#define IPRT_INCLUDED_nocrt_process_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#endif /* !IPRT_INCLUDED_nocrt_process_h */ + diff --git a/include/iprt/nocrt/setjmp.h b/include/iprt/nocrt/setjmp.h new file mode 100644 index 00000000..6b2e15af --- /dev/null +++ b/include/iprt/nocrt/setjmp.h @@ -0,0 +1,68 @@ +/** @file + * IPRT / No-CRT - Our own setjmp header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_setjmp_h +#define IPRT_INCLUDED_nocrt_setjmp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +#ifdef RT_ARCH_AMD64 +# ifdef RT_OS_WINDOWS /* Also saves rsi, rdi and xmm6-xmm15. */ +typedef uint64_t RT_NOCRT(jmp_buf)[10 + (2*10)]; +# else +typedef uint64_t RT_NOCRT(jmp_buf)[8]; +# endif +#else +typedef uint32_t RT_NOCRT(jmp_buf)[6+2]; +#endif + +extern DECL_RETURNS_TWICE(int) RT_NOCRT(setjmp)(RT_NOCRT(jmp_buf)); +extern DECL_NO_RETURN(int) RT_NOCRT(longjmp)(RT_NOCRT(jmp_buf), int); + +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define jmp_buf RT_NOCRT(jmp_buf) +# define setjmp RT_NOCRT(setjmp) +# define longjmp RT_NOCRT(longjmp) +#endif + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_nocrt_setjmp_h */ + diff --git a/include/iprt/nocrt/signal.h b/include/iprt/nocrt/signal.h new file mode 100644 index 00000000..36ca57b5 --- /dev/null +++ b/include/iprt/nocrt/signal.h @@ -0,0 +1,43 @@ +/** @file + * IPRT / No-CRT - Stub signal.h header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_signal_h +#define IPRT_INCLUDED_nocrt_signal_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#endif /* !IPRT_INCLUDED_nocrt_signal_h */ + diff --git a/include/iprt/nocrt/stdarg.h b/include/iprt/nocrt/stdarg.h new file mode 100644 index 00000000..3a5b039d --- /dev/null +++ b/include/iprt/nocrt/stdarg.h @@ -0,0 +1,45 @@ +/** @file + * IPRT / No-CRT - stdarg.h (-> iprt/stdarg.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdarg_h +#define IPRT_INCLUDED_nocrt_stdarg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#endif /* !IPRT_INCLUDED_nocrt_stdarg_h */ + diff --git a/include/iprt/nocrt/stdbool.h b/include/iprt/nocrt/stdbool.h new file mode 100644 index 00000000..d288ce2c --- /dev/null +++ b/include/iprt/nocrt/stdbool.h @@ -0,0 +1,58 @@ +/** @file + * IPRT / No-CRT - Our own minimal stdbool.h header (needed by softfloat.h). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdbool_h +#define IPRT_INCLUDED_nocrt_stdbool_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* The iprt/types.h header should take care of the basics. */ +#include + +#ifndef __cplusplus +# ifndef bool +# define bool _Bool +# endif +# ifndef true +# define true (1) +# endif +# ifndef false +# define false (0) +# endif +#endif + +#endif /* !IPRT_INCLUDED_nocrt_stdbool_h */ + diff --git a/include/iprt/nocrt/stddef.h b/include/iprt/nocrt/stddef.h new file mode 100644 index 00000000..df56a617 --- /dev/null +++ b/include/iprt/nocrt/stddef.h @@ -0,0 +1,48 @@ +/** @file + * IPRT / No-CRT - stddef.h (-> iprt/types.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stddef_h +#define IPRT_INCLUDED_nocrt_stddef_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#ifndef offsetof +# define offsetof(a_Type, a_Member) RT_OFFSETOF(a_Type, a_Member) +#endif + +#endif /* !IPRT_INCLUDED_nocrt_stddef_h */ diff --git a/include/iprt/nocrt/stdint.h b/include/iprt/nocrt/stdint.h new file mode 100644 index 00000000..2b481159 --- /dev/null +++ b/include/iprt/nocrt/stdint.h @@ -0,0 +1,46 @@ +/** @file + * IPRT / No-CRT - Our own minimal stdint.h header (needed by softfloat.h). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdint_h +#define IPRT_INCLUDED_nocrt_stdint_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* The iprt/stdint.h header should take care of the basics. */ +#include + +#endif /* !IPRT_INCLUDED_nocrt_stdint_h */ + diff --git a/include/iprt/nocrt/stdio.h b/include/iprt/nocrt/stdio.h new file mode 100644 index 00000000..a63b3e49 --- /dev/null +++ b/include/iprt/nocrt/stdio.h @@ -0,0 +1,226 @@ +/** @file + * IPRT / No-CRT - Mostly empty stdio.h. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdio_h +#define IPRT_INCLUDED_nocrt_stdio_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include /* errno_t, off_t */ +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +# include /* file.h includes fs.h which includes time.h */ +# include /* for RTFILE_SEEK_XXX */ +# include +#endif + +typedef RTFOFF fpos_t; + + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +/* + * Only for external libraries and such, but even then it would be best to + * check each printf and fprintf call as IPRT isn't 100% compatible... + */ + +/* These are also in unistd.h: */ +# undef SEEK_SET +# define SEEK_SET RTFILE_SEEK_BEGIN +# undef SEEK_CUR +# define SEEK_CUR RTFILE_SEEK_CURRENT +# undef SEEK_END +# define SEEK_END RTFILE_SEEK_END +AssertCompile(SEEK_SET == 0); AssertCompile(SEEK_CUR == 1); AssertCompile(SEEK_END == 2); /* Also in WDK header mmiscapi.h. */ + +# define RT_NOCRT_BUFSIZ 4096 +# define BUFSIZ RT_NOCRT_BUFSIZ + +RT_C_DECLS_BEGIN + +typedef struct RTSTREAM FILE; +# define stdin g_pStdIn +# define stdout g_pStdOut +# define stderr g_pStdErr + +# define printf RTPrintf +# define vprintf RTPrintfV +# define fprintf RTStrmPrintf +# define vfprintf RTStrmPrintfV +int RT_NOCRT(snprintf)(char *, size_t, const char *, ...); +int RT_NOCRT(vsnprintf)(char *, size_t, const char *, va_list); +int RT_NOCRT(scprintf)(const char *, ...); +int RT_NOCRT(vscprintf)(const char *, va_list); + +FILE *RT_NOCRT(fopen)(const char *pszFilename, const char *pszMode); +FILE *RT_NOCRT(fdopen)(int fd, const char *pszMode); +FILE *RT_NOCRT(tmpfile)(void); +errno_t RT_NOCRT(tmpfile_s)(FILE **ppFile); +int RT_NOCRT(fileno)(FILE *pFile); +int RT_NOCRT(fclose)(FILE *pFile); +int RT_NOCRT(fflush)(FILE *pFile); +int RT_NOCRT(setvbuf)(FILE *pFile, char *pchBuf, int iBufferingType, size_t cbBuf); +int RT_NOCRT(fseek)(FILE *pFile, long, int); +int RT_NOCRT(fseeko)(FILE *pFile, off_t, int); +long RT_NOCRT(ftell)(FILE *pFile); +off_t RT_NOCRT(ftello)(FILE *pFile); +size_t RT_NOCRT(fwrite)(void const *pvBuf, size_t cbItem, size_t cItems, FILE *pFile); +int RT_NOCRT(fputs)(const char *psz, FILE *pFile); +int RT_NOCRT(puts)(const char *psz); +int RT_NOCRT(fputc)(int, FILE *pFile); +int RT_NOCRT(putc)(int, FILE *pFile); +size_t RT_NOCRT(fread)(void *pvBuf, size_t cbItem, size_t cItems, FILE *pFile); +int RT_NOCRT(fgetc)(FILE *pFile); +int RT_NOCRT(getc)(FILE *pFile); +int RT_NOCRT(ferror)(FILE *pFile); +void RT_NOCRT(clearerr)(FILE *pFile); +int RT_NOCRT(remove)(const char *pszFilename); +int RT_NOCRT(sscanf)(const char *pszString, const char *pszFormat, ...); +int RT_NOCRT(vsscanf)(const char *pszString, const char *pszFormat, va_list); + +# ifndef RT_NOCRT_EOF /* also in string */ +# define RT_NOCRT_EOF (-1) +# endif +# define EOF RT_NOCRT_EOF + +/* Underscored variants: */ +# define _printf RTPrintf +# define _vprintf RTPrintfV +# define _fprintf RTStrmPrintf +# define _vfprintf RTStrmPrintfV +int RT_NOCRT(_snprintf)(char *, size_t, const char *, ...); +int RT_NOCRT(_vsnprintf)(char *, size_t, const char *, va_list); +int RT_NOCRT(_scprintf)(const char *, ...); +int RT_NOCRT(_vscprintf)(const char *, va_list); + +FILE *RT_NOCRT(_fopen)(const char *pszFilename, const char *pszMode); +FILE *RT_NOCRT(_fdopen)(int fd, const char *pszMode); +FILE *RT_NOCRT(_tmpfile)(void); +errno_t RT_NOCRT(_tmpfile_s)(FILE **ppFile); +int RT_NOCRT(_fileno)(FILE *pFile); +int RT_NOCRT(_fclose)(FILE *pFile); +int RT_NOCRT(_fflush)(FILE *pFile); +int RT_NOCRT(_setvbuf)(FILE *pFile, char *pchBuf, int iBufferingType, size_t cbBuf); +int RT_NOCRT(_fseek)(FILE *pFile, long, int); +int RT_NOCRT(_fseeko)(FILE *pFile, off_t, int); +long RT_NOCRT(_ftell)(FILE *pFile); +off_t RT_NOCRT(_ftello)(FILE *pFile); +size_t RT_NOCRT(_fwrite)(void const *pvBuf, size_t cbItem, size_t cItems, FILE *pFile); +int RT_NOCRT(_fputs)(const char *psz, FILE *pFile); +int RT_NOCRT(_fputc)(int, FILE *pFile); +size_t RT_NOCRT(_fread)(void *pvBuf, size_t cbItem, size_t cItems, FILE *pFile); +int RT_NOCRT(_fgetc)(FILE *pFile); +int RT_NOCRT(_getc)(FILE *pFile); +int RT_NOCRT(_ferror)(FILE *pFile); +void RT_NOCRT(_clearerr)(FILE *pFile); +int RT_NOCRT(_remove)(const char *pszFilename); +int RT_NOCRT(_sscanf)(const char *pszString, const char *pszFormat, ...); +int RT_NOCRT(_vsscanf)(const char *pszString, const char *pszFormat, va_list); + +# define _IONBF (1) /**< No buffering. */ +# define _IOLBF (2) /**< Line buffered. */ +# define _IOFBF (3) /**< Fully buffered. */ + +/* Aliases: */ +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define snprintf RT_NOCRT(snprintf) +# define vsnprintf RT_NOCRT(vsnprintf) +# define scprintf RT_NOCRT(scprintf) +# define vscprintf RT_NOCRT(vscprintf) + +# define fopen RT_NOCRT(fopen) +# define fdopen RT_NOCRT(fdopen) +# define tmpfile RT_NOCRT(tmpfile) +# define tmpfile_s RT_NOCRT(tmpfile_s) +# define fileno RT_NOCRT(fileno) +# define fclose RT_NOCRT(fclose) +# define fflush RT_NOCRT(fflush) +# define setvbuf RT_NOCRT(setvbuf) +# define fseek RT_NOCRT(fseek) +# define fseeko RT_NOCRT(fseeko) +# define ftell RT_NOCRT(ftell) +# define ftello RT_NOCRT(ftello) +# define fwrite RT_NOCRT(fwrite) +# define fputs RT_NOCRT(fputs) +# define puts RT_NOCRT(puts) +# define fputc RT_NOCRT(fputc) +# define fread RT_NOCRT(fread) +# define fgetc RT_NOCRT(fgetc) +# define getc RT_NOCRT(getc) +# define ferror RT_NOCRT(ferror) +# define clearerr RT_NOCRT(clearerr) +# define remove RT_NOCRT(remove) +# define sscanf RT_NOCRT(sscanf) +# define vsscanf RT_NOCRT(vsscanf) + + +/* Underscored variants: */ +# define _snprintf RT_NOCRT(snprintf) +# define _vsnprintf RT_NOCRT(vsnprintf) +# define _scprintf RT_NOCRT(scprintf) +# define _vscprintf RT_NOCRT(vscprintf) + +# define _fopen RT_NOCRT(fopen) +# define _fdopen RT_NOCRT(fdopen) +# define _tmpfile RT_NOCRT(tmpfile) +# define _tmpfile_s RT_NOCRT(tmpfile_s) +# define _fileno RT_NOCRT(fileno) +# define _fclose RT_NOCRT(fclose) +# define _flush RT_NOCRT(fflush) +# define _setvbuf RT_NOCRT(setvbuf) +# define _fseek RT_NOCRT(fseek) +# define _fseeko RT_NOCRT(fseeko) +# define _ftell RT_NOCRT(ftell) +# define _ftello RT_NOCRT(ftello) +# define _fwrite RT_NOCRT(fwrite) +# define _fputs RT_NOCRT(fputs) +# define _puts RT_NOCRT(puts) +# define _fputc RT_NOCRT(fputc) +# define _fread RT_NOCRT(fread) +# define _fgetc RT_NOCRT(fgetc) +# define _getc RT_NOCRT(getc) +# define _ferror RT_NOCRT(ferror) +# define _clearerr RT_NOCRT(clearerr) +# define _remove RT_NOCRT(remove) +# define _sscanf RT_NOCRT(_sscanf) +# define _vsscanf RT_NOCRT(_vsscanf) +# endif + +RT_C_DECLS_END + +#endif + +#endif /* !IPRT_INCLUDED_nocrt_stdio_h */ + diff --git a/include/iprt/nocrt/stdlib.h b/include/iprt/nocrt/stdlib.h new file mode 100644 index 00000000..49868cbe --- /dev/null +++ b/include/iprt/nocrt/stdlib.h @@ -0,0 +1,227 @@ +/** @file + * IPRT / No-CRT - Our minimal stdlib.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdlib_h +#define IPRT_INCLUDED_nocrt_stdlib_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +#define EXIT_SUCCESS RTEXITCODE_SUCCESS +#define EXIT_FAILURE RTEXITCODE_FAILURE + + +typedef void FNRTNOCRTATEXITCALLBACK(void) /*RT_NOEXCEPT*/; +typedef FNRTNOCRTATEXITCALLBACK *PFNRTNOCRTATEXITCALLBACK; +#if defined(_MSC_VER) && defined(RT_WITHOUT_NOCRT_WRAPPERS) /* Clashes with compiler internal prototype or smth. */ +int nocrt_atexit(PFNRTNOCRTATEXITCALLBACK) RT_NOEXCEPT; +# define atexit nocrt_atexit +#else +int RT_NOCRT(atexit)(PFNRTNOCRTATEXITCALLBACK) RT_NOEXCEPT; +#endif + +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define atexit RT_NOCRT(atexit) +#endif + + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +/* + * Only for external libraries and such. + */ + +DECLINLINE(void *) RT_NOCRT(malloc)(size_t cb) +{ + return RTMemAlloc(cb); +} + +DECLINLINE(void *) RT_NOCRT(calloc)(size_t cItems, size_t cbItem) +{ + return RTMemAllocZ(cItems * cbItem); /* caller responsible for overflow issues. */ +} + +DECLINLINE(void *) RT_NOCRT(realloc)(void *pvOld, size_t cbNew) +{ + return RTMemRealloc(pvOld, cbNew); +} + +DECLINLINE(void) RT_NOCRT(free)(void *pv) +{ + RTMemFree(pv); +} + +DECLINLINE(const char *) RT_NOCRT(getenv)(const char *pszVar) +{ + return RTEnvGet(pszVar); +} + +int RT_NOCRT(abs)(int) RT_NOEXCEPT; +long RT_NOCRT(labs)(long) RT_NOEXCEPT; +long long RT_NOCRT(llabs)(long long) RT_NOEXCEPT; +int RT_NOCRT(rand)(void) RT_NOEXCEPT; +void RT_NOCRT(srand)(unsigned) RT_NOEXCEPT; +long RT_NOCRT(strtol)(const char *psz, char **ppszNext, int iBase) RT_NOEXCEPT; +long long RT_NOCRT(strtoll)(const char *psz, char **ppszNext, int iBase) RT_NOEXCEPT; +unsigned long RT_NOCRT(strtoul)(const char *psz, char **ppszNext, int iBase) RT_NOEXCEPT; +unsigned long long RT_NOCRT(strtoull)(const char *psz, char **ppszNext, int iBase) RT_NOEXCEPT; +int RT_NOCRT(atoi)(const char *psz) RT_NOEXCEPT; +double RT_NOCRT(strtod)(const char *psz, char **ppszNext) RT_NOEXCEPT; +double RT_NOCRT(atof)(const char *psz) RT_NOEXCEPT; +void *RT_NOCRT(bsearch)(const void *pvKey, const void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pvKey, const void *pvEntry)); +void RT_NOCRT(qsort)(void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2)); +void RT_NOCRT(qsort_r)(void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2, void *pvUser), void *pvUser); + +/* Map exit & abort onto fatal assert. */ +DECL_NO_RETURN(DECLINLINE(void)) RT_NOCRT(exit)(int iExitCode) { AssertFatalMsgFailed(("exit: iExitCode=%d\n", iExitCode)); } +DECL_NO_RETURN(DECLINLINE(void)) RT_NOCRT(abort)(void) { AssertFatalMsgFailed(("abort\n")); } + +/* + * Underscored versions: + */ +DECLINLINE(void *) RT_NOCRT(_malloc)(size_t cb) +{ + return RTMemAlloc(cb); +} + +DECLINLINE(void *) RT_NOCRT(_calloc)(size_t cItems, size_t cbItem) +{ + return RTMemAllocZ(cItems * cbItem); /* caller responsible for overflow issues. */ +} + +DECLINLINE(void *) RT_NOCRT(_realloc)(void *pvOld, size_t cbNew) +{ + return RTMemRealloc(pvOld, cbNew); +} + +DECLINLINE(void) RT_NOCRT(_free)(void *pv) +{ + RTMemFree(pv); +} + +DECLINLINE(const char *) RT_NOCRT(_getenv)(const char *pszVar) +{ + return RTEnvGet(pszVar); +} + +int RT_NOCRT(_abs)(int); +long RT_NOCRT(_labs)(long); +long long RT_NOCRT(_llabs)(long long); +int RT_NOCRT(_rand)(void); +void RT_NOCRT(_srand)(unsigned); +long RT_NOCRT(_strtol)(const char *psz, char **ppszNext, int iBase); +long long RT_NOCRT(_strtoll)(const char *psz, char **ppszNext, int iBase); +unsigned long RT_NOCRT(_strtoul)(const char *psz, char **ppszNext, int iBase); +unsigned long long RT_NOCRT(_strtoull)(const char *psz, char **ppszNext, int iBase); +int RT_NOCRT(_atoi)(const char *psz); +double RT_NOCRT(_strtod)(const char *psz, char **ppszNext); +double RT_NOCRT(_atof)(const char *psz); +void *RT_NOCRT(_bsearch)(const void *pvKey, const void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2)); +void RT_NOCRT(_qsort)(void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2)); +void RT_NOCRT(_qsort_r)(void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2, void *pvUser), void *pvUser); + +/* Map exit & abort onto fatal assert. */ +DECL_NO_RETURN(DECLINLINE(void)) RT_NOCRT(_exit)(int iExitCode) { AssertFatalMsgFailed(("_exit: iExitCode=%d\n", iExitCode)); } +DECL_NO_RETURN(DECLINLINE(void)) RT_NOCRT(_abort)(void) { AssertFatalMsgFailed(("_abort\n")); } + +/* Some windows CRT error control functions we totally ignore (only underscored): */ +# define _set_error_mode(a_Mode) (0) +# define _set_abort_behavior(a_fFlags, a_fMask) (0) + +/* + * No-CRT aliases. + */ +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define malloc RT_NOCRT(malloc) +# define calloc RT_NOCRT(calloc) +# define realloc RT_NOCRT(realloc) +# define free RT_NOCRT(free) +# define getenv RT_NOCRT(getenv) +# define bsearch RT_NOCRT(bsearch) +# define exit RT_NOCRT(exit) +# define abort RT_NOCRT(abort) +# define abs RT_NOCRT(abs) +# define labs RT_NOCRT(labs) +# define llabs RT_NOCRT(llabs) +# define rand RT_NOCRT(rand) +# define srand RT_NOCRT(srand) +# define strtol RT_NOCRT(strtol) +# define strtoll RT_NOCRT(strtoll) +# define strtoul RT_NOCRT(strtoul) +# define strtoull RT_NOCRT(strtoull) +# define atoi RT_NOCRT(atoi) +# define strtod RT_NOCRT(strtod) +# define atof RT_NOCRT(atof) + +# define _malloc RT_NOCRT(malloc) +# define _calloc RT_NOCRT(calloc) +# define _realloc RT_NOCRT(realloc) +# define _free RT_NOCRT(free) +# define _getenv RT_NOCRT(getenv) +# define _bsearch RT_NOCRT(bsearch) +# define _exit RT_NOCRT(exit) +# define _abort RT_NOCRT(abort) +# define _abs RT_NOCRT(abs) +# define _labs RT_NOCRT(labs) +# define _llabs RT_NOCRT(llabs) +# define _rand RT_NOCRT(rand) +# define _srand RT_NOCRT(srand) +# define _strtol RT_NOCRT(strtol) +# define _strtoll RT_NOCRT(strtoll) +# define _strtoul RT_NOCRT(strtoul) +# define _strtoull RT_NOCRT(strtoull) +# define _atoi RT_NOCRT(atoi) +# define _strtod RT_NOCRT(strtod) +# define _atof RT_NOCRT(atof) +# endif + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_nocrt_stdlib_h */ diff --git a/include/iprt/nocrt/string b/include/iprt/nocrt/string new file mode 100644 index 00000000..31897dd1 --- /dev/null +++ b/include/iprt/nocrt/string @@ -0,0 +1,322 @@ +/** @file + * IPRT / No-CRT - Minimal C++ string header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_string +#define VBOX_INCLUDED_SRC_nocrt_string +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include /* for std::size_t */ +#include + +#ifndef RT_NOCRT_EOF /* also in stdio.h */ +# define RT_NOCRT_EOF (-1) +#endif + +namespace std +{ + using streamoff = ::RTFOFF; + + /** + * @note This should be in iosfwd, not string. + */ + template + class fpos + { + protected: + std::streamoff m_off; + a_MbStateType m_MbState; + + public: + fpos() + : m_off(0) + , m_MbState() + { } + + fpos(std::streamoff a_off) + : m_off(a_off) + , m_MbState() + { } + + a_MbStateType state() const RT_NOEXCEPT + { + return m_MbState; + } + + void state(a_MbStateType a_NewMbState) const RT_NOEXCEPT + { + m_MbState = a_NewMbState; + } + }; + using mbstate_t = ::RT_NOCRT(mbstate_t); + using streampos = fpos; + + /* Use RTCString as std::string, it should be a reasonable match. */ + typedef ::RTCString string; + + /** + * Character traits. + */ + template + struct char_traits + { + /** @name Types + * @{ */ + typedef a_CharType char_type; + typedef unsigned long int_type; + typedef std::streamoff off_type; + typedef std::streampos pos_type; + typedef std::mbstate_t state_type; + /** @} */ + + static void assign(char_type &a_rchDst, const char_type &a_rchSrc) RT_NOEXCEPT + { + a_rchDst = a_rchSrc; + } + + static bool eq(const char_type &a_rchLeft, const char_type &a_rchRight) RT_NOEXCEPT + { + return a_rchLeft == a_rchRight; + } + + static bool lt(const char_type &a_rchLeft, const char_type &a_rchRight) RT_NOEXCEPT + { + return a_rchLeft < a_rchRight; + } + + static std::size_t length(const char_type *a_psz) RT_NOEXCEPT; + static int compare(const char_type *a_pchLeft, const char_type *a_pchRight, std::size_t a_cch) RT_NOEXCEPT; + static const char_type *find(const char_type *a_pchHaystack, std::size_t a_cchHaystack, const char_type &a_rchNeedle) RT_NOEXCEPT; + static char_type *assign(char_type *a_pchDst, std::size_t a_cchDst, char_type a_chFill) RT_NOEXCEPT; + static char_type *copy(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT; + static char_type *move(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT; + + static char_type to_char_type(const int_type &a_riChar) + { + return static_cast(a_riChar); + } + + static int_type to_int_type(const char_type &a_rch) + { + return static_cast(a_rch); + } + + static bool eq_int_type(const int_type &a_riLeft, const int_type &a_riRight) RT_NOEXCEPT + { + return a_riLeft == a_riRight; + } + + static int_type eof() RT_NOEXCEPT + { + return static_cast(RT_NOCRT_EOF); + } + + static int_type not_eof(const int_type &a_riChar) RT_NOEXCEPT + { + if (!eq_int_type(a_riChar, eof())) + return a_riChar; + return to_int_type(char_type()); + } + }; + + template + /*static*/ std::size_t char_traits::length(const char_type *a_psz) RT_NOEXCEPT + { + const char_type * const pszStart = a_psz; + while (!eq(*a_pszLeft, char_type())) + a_psz++; + return static_cast(a_psz - pszStart); + } + + template + /*static*/ int char_traits::compare(const char_type *a_pchLeft, const char_type *a_pchRight, + std::size_t a_cch) RT_NOEXCEPT + { + for (std::size_t off = 0; off < a_cch; off++) + if (eq(a_pchLeft[off], a_pchRight[off])) + { /* likely? */ } + else + return lt(a_pchLeft[off], a_pchRight[off]) ? -1 : 1; + return 0; + } + + template + /*static*/ const typename char_traits::char_type * + char_traits::find(const char_type *a_pchHaystack, std::size_t a_cchHaystack, + const char_type &a_rchNeedle) RT_NOEXCEPT + { + while (a_cchHaystack-- > 0) + { + if (eq(*a_pchHaystack, a_rchNeedle)) + return a_pchHaystack; + a_pchHaystack++; + } + return NULL; + } + + template + /*static*/ typename char_traits::char_type * + char_traits::assign(char_type *a_pchDst, std::size_t a_cchDst, char_type a_chFill) RT_NOEXCEPT + { + char_type * const pchRet = a_pchDst; + while (a_cchDst-- > 0) + *a_pchDst++ = a_chFill; + return pchRet; + } + + template + /*static*/ typename char_traits::char_type * + char_traits::copy(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT + { + char_type * const pchRet = a_pchDst; + while (a_cch-- > 0) + *a_pchDst++ = *a_pchSrc++; + return pchRet; + } + + template + /*static*/ typename char_traits::char_type * + char_traits::move(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT + { + char_type * const pchRet = a_pchDst; + char_type volatile *pchDstV = static_cast(a_pchDst); + char_type const volatile *pchSrcV = static_cast(a_pchSrc); + if ((uintptr_t)a_pchDst < (uintptr_t)a_pchSrc) + { + /* forward copy */ + while (a_cch-- > 0) + *a_pchDstV++ = *a_pchSrcV++; + } + else + { + /* reverse copy */ + a_pchSrcV += a_cch; + a_pchDstV += a_cch; + while (a_cchDst-- > 0) + *a_pchDstV-- = *a_pchSrcV--; + } + return pchRet; + } + + /* + * Character train specializations. + */ + template <> + struct char_traits + { + typedef char char_type; + typedef int int_type; + typedef std::streamoff off_type; + typedef std::streampos pos_type; + typedef std::mbstate_t state_type; + + static void assign(char_type &a_rchDst, const char_type &a_rchSrc) RT_NOEXCEPT + { + a_rchDst = a_rchSrc; + } + + static bool eq(const char_type &a_rchLeft, const char_type &a_rchRight) RT_NOEXCEPT + { + return a_rchLeft == a_rchRight; + } + + static bool lt(const char_type &a_rchLeft, const char_type &a_rchRight) RT_NOEXCEPT + { + return a_rchLeft < a_rchRight; + } + + static std::size_t length(const char_type *a_psz) RT_NOEXCEPT + { + return ::RT_NOCRT(strlen)(a_psz); + } + + static int compare(const char_type *a_pchLeft, const char_type *a_pchRight, std::size_t a_cch) RT_NOEXCEPT + { + return ::RT_NOCRT(memcmp)(a_pchLeft, a_pchRight, a_cch); + } + + static const char_type *find(const char_type *a_pchHaystack, std::size_t a_cchHaystack, const char_type &a_rchNeedle) RT_NOEXCEPT + { + return static_cast(::RT_NOCRT(memchr)(a_pchHaystack, a_rchNeedle, a_cchHaystack)); + } + + static char_type *assign(char_type *a_pchDst, std::size_t a_cchDst, char_type a_chFill) RT_NOEXCEPT + { + return static_cast(::RT_NOCRT(memset)(a_pchDst, a_chFill, a_cchDst)); + } + + static char_type *copy(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT + { + return static_cast(::RT_NOCRT(memcpy)(a_pchDst, a_pchSrc, a_cch)); + } + + static char_type *move(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT + { + return static_cast(::RT_NOCRT(memmove)(a_pchDst, a_pchSrc, a_cch)); + } + + static char_type to_char_type(const int_type &a_riChar) + { + return static_cast(a_riChar); + } + + static int_type to_int_type(const char_type &a_rch) + { + return static_cast(a_rch); + } + + static bool eq_int_type(const int_type &a_riLeft, const int_type &a_riRight) RT_NOEXCEPT + { + return a_riLeft == a_riRight; + } + + static int_type eof() RT_NOEXCEPT + { + return static_cast(RT_NOCRT_EOF); + } + + static int_type not_eof(const int_type &a_riChar) RT_NOEXCEPT + { + if (!eq_int_type(a_riChar, eof())) + return a_riChar; + return 0; + } + }; +} + + +#endif /* !VBOX_INCLUDED_SRC_nocrt_string */ diff --git a/include/iprt/nocrt/string.h b/include/iprt/nocrt/string.h new file mode 100644 index 00000000..b83d0036 --- /dev/null +++ b/include/iprt/nocrt/string.h @@ -0,0 +1,254 @@ +/** @file + * IPRT / No-CRT - string.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_string_h +#define IPRT_INCLUDED_nocrt_string_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* Dummy for now, fix when/if needed. */ +typedef struct RT_NOCRT(mbstate_t) +{ + unsigned long whatever; +} RT_NOCRT(mbstate_t); + + +RT_C_DECLS_BEGIN + +void *RT_NOCRT(memchr)(const void *pv, int ch, size_t cb); +int RT_NOCRT(memcmp)(const void *pv1, const void *pv2, size_t cb); +void *RT_NOCRT(memcpy)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(mempcpy)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(memrchr)(const void *pv, int ch, size_t cb); +void *RT_NOCRT(memmove)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(memset)(void *pvDst, int ch, size_t cb); + +char *RT_NOCRT(strcat)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(strncat)(char *pszDst, const char *pszSrc, size_t cch); +char *RT_NOCRT(strchr)(const char *psz, int ch); +char *RT_NOCRT(strrchr)(const char *psz, int ch); +int RT_NOCRT(strcmp)(const char *psz1, const char *psz2); +int RT_NOCRT(strncmp)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(stricmp)(const char *psz1, const char *psz2); +int RT_NOCRT(strnicmp)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(strcmpcase)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(strcoll)(const char *psz1, const char *psz2); +char *RT_NOCRT(strcpy)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(strncpy)(char *pszDst, const char *pszSrc, size_t cch); +char *RT_NOCRT(strcat)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(strncat)(char *pszDst, const char *pszSrc, size_t cch); +size_t RT_NOCRT(strlen)(const char *psz); +size_t RT_NOCRT(strnlen)(const char *psz, size_t cch); +size_t RT_NOCRT(strspn)(const char *psz, const char *pszBreakChars); +size_t RT_NOCRT(strcspn)(const char *psz, const char *pszBreakChars); +char *RT_NOCRT(strpbrk)(const char *psz, const char *pszBreakChars); +char *RT_NOCRT(strstr)(const char *psz, const char *pszSub); +char *RT_NOCRT(strtok)(char *psz, const char *pszDelim); +char *RT_NOCRT(strtok_r)(char *psz, const char *pszDelim, char **ppszSave); +#if 0 /* C++11: */ +char *RT_NOCRT(strtok_s)(char *psz, /*rsize_t*/ size_t cchMax, const char *pszDelim, char **ppszSave); +#else /* Microsoft: */ +char *RT_NOCRT(strtok_s)(char *psz, const char *pszDelim, char **ppszSave); +#endif +size_t RT_NOCRT(strxfrm)(char *pszDst, const char *pszSrc, size_t cch); + +size_t RT_NOCRT(wcslen)(const wchar_t *pwsz); +wchar_t *RT_NOCRT(wcscat)(wchar_t *pwszDst, const wchar_t *pwszSrc); +wchar_t *RT_NOCRT(wcschr)(const wchar_t *pwsz, wchar_t wc); +wchar_t *RT_NOCRT(wcscpy)(wchar_t *pwszDst, const wchar_t *pwszSrc); +int RT_NOCRT(wcsicmp)(const wchar_t *pwsz1, const wchar_t *pwsz2); +size_t RT_NOCRT(wcstombs)(char *pszDst, const wchar_t *pszSrc, size_t cbDst); + + +/* Underscored versions for MSC compatibility (mesa #defines regular to _regular + a lot, which is why we really need these prototypes). */ +void *RT_NOCRT(_memchr)(const void *pv, int ch, size_t cb); +int RT_NOCRT(_memcmp)(const void *pv1, const void *pv2, size_t cb); +void *RT_NOCRT(_memcpy)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(_mempcpy)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(_memrchr)(const void *pv, int ch, size_t cb); +void *RT_NOCRT(_memmove)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(_memset)(void *pvDst, int ch, size_t cb); + +char *RT_NOCRT(_strcat)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(_strncat)(char *pszDst, const char *pszSrc, size_t cch); +char *RT_NOCRT(_strchr)(const char *psz, int ch); +char *RT_NOCRT(_strrchr)(const char *psz, int ch); +int RT_NOCRT(_strcmp)(const char *psz1, const char *psz2); +int RT_NOCRT(_strncmp)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(_stricmp)(const char *psz1, const char *psz2); +int RT_NOCRT(_strnicmp)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(_strcmpcase)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(_strcoll)(const char *psz1, const char *psz2); +char *RT_NOCRT(_strcpy)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(_strncpy)(char *pszDst, const char *pszSrc, size_t cch); +char *RT_NOCRT(_strcat)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(_strncat)(char *pszDst, const char *pszSrc, size_t cch); +size_t RT_NOCRT(_strlen)(const char *psz); +size_t RT_NOCRT(_strnlen)(const char *psz, size_t cch); +size_t RT_NOCRT(_strspn)(const char *psz, const char *pszBreakChars); +size_t RT_NOCRT(_strcspn)(const char *psz, const char *pszBreakChars); +char *RT_NOCRT(_strpbrk)(const char *psz, const char *pszBreakChars); +char *RT_NOCRT(_strstr)(const char *psz, const char *pszSub); +char *RT_NOCRT(_strtok)(char *psz, const char *pszDelim); +char *RT_NOCRT(_strtok_r)(char *psz, const char *pszDelim, char **ppszSave); +#if 0 /* C++11: */ +char *RT_NOCRT(_strtok_s)(char *psz, /*rsize_t*/ size_t cchMax, const char *pszDelim, char **ppszSave); +#else /* Microsoft: */ +char *RT_NOCRT(_strtok_s)(char *psz, const char *pszDelim, char **ppszSave); +#endif +size_t RT_NOCRT(_strxfrm)(char *pszDst, const char *pszSrc, size_t cch); + +size_t RT_NOCRT(_wcslen)(const wchar_t *pwsz); +wchar_t *RT_NOCRT(_wcscat)(wchar_t *pwszDst, const wchar_t *pwszSrc); +wchar_t *RT_NOCRT(_wcschr)(const wchar_t *pwsz, wchar_t wc); +wchar_t *RT_NOCRT(_wcscpy)(wchar_t *pwszDst, const wchar_t *pwszSrc); +int RT_NOCRT(_wcsicmp)(const wchar_t *pwsz1, const wchar_t *pwsz2); +size_t RT_NOCRT(_wcstombs)(char *pszDst, const wchar_t *pszSrc, size_t cbDst); + + +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define memchr RT_NOCRT(memchr) +# define memcmp RT_NOCRT(memcmp) +# define memcpy RT_NOCRT(memcpy) +# define mempcpy RT_NOCRT(mempcpy) +# define memrchr RT_NOCRT(memrchr) +# define memmove RT_NOCRT(memmove) +# define memset RT_NOCRT(memset) + +# define strcat RT_NOCRT(strcat) +# define strncat RT_NOCRT(strncat) +# define strchr RT_NOCRT(strchr) +# define strrchr RT_NOCRT(strrchr) +# define strcmp RT_NOCRT(strcmp) +# define strncmp RT_NOCRT(strncmp) +# define stricmp RT_NOCRT(stricmp) +# define strnicmp RT_NOCRT(strnicmp) +# define strcmpcase RT_NOCRT(strcmpcase) +# define strcoll RT_NOCRT(strcoll) +# define strcpy RT_NOCRT(strcpy) +# define strncpy RT_NOCRT(strncpy) +# define strcat RT_NOCRT(strcat) +# define strncat RT_NOCRT(strncat) +# define strlen RT_NOCRT(strlen) +# define strnlen RT_NOCRT(strnlen) +# define strspn RT_NOCRT(strspn) +# define strcspn RT_NOCRT(strcspn) +# define strpbrk RT_NOCRT(strpbrk) +# define strstr RT_NOCRT(strstr) +# define strtok RT_NOCRT(strtok) +# define strtok_r RT_NOCRT(strtok_r) +# define strtok_s RT_NOCRT(strtok_s) +# define strxfrm RT_NOCRT(strxfrm) + +# define wcslen RT_NOCRT(wcslen) +# define wcscat RT_NOCRT(wcscat) +# define wcschr RT_NOCRT(wcschr) +# define wcscpy RT_NOCRT(wcscpy) +# define wcsicmp RT_NOCRT(wcsicmp) +# define wcstombs RT_NOCRT(wcstombs) + +/* Underscored: */ +# define _memchr RT_NOCRT(memchr) +# define _memcmp RT_NOCRT(memcmp) +# define _memcpy RT_NOCRT(memcpy) +# define _mempcpy RT_NOCRT(mempcpy) +# define _memrchr RT_NOCRT(memrchr) +# define _memmove RT_NOCRT(memmove) +# define _memset RT_NOCRT(memset) + +# define _strcat RT_NOCRT(strcat) +# define _strncat RT_NOCRT(strncat) +# define _strchr RT_NOCRT(strchr) +# define _strrchr RT_NOCRT(strrchr) +# define _strcmp RT_NOCRT(strcmp) +# define _strncmp RT_NOCRT(strncmp) +# define _stricmp RT_NOCRT(stricmp) +# define _strnicmp RT_NOCRT(strnicmp) +# define _strcmpcase RT_NOCRT(strcmpcase) +# define _strcoll RT_NOCRT(strcoll) +# define _strcpy RT_NOCRT(strcpy) +# define _strncpy RT_NOCRT(strncpy) +# define _strcat RT_NOCRT(strcat) +# define _strncat RT_NOCRT(strncat) +# define _strlen RT_NOCRT(strlen) +# define _strnlen RT_NOCRT(strnlen) +# define _strspn RT_NOCRT(strspn) +# define _strcspn RT_NOCRT(strcspn) +# define _strpbrk RT_NOCRT(strpbrk) +# define _strstr RT_NOCRT(strstr) +# define _strtok RT_NOCRT(strtok) +# define _strtok_r RT_NOCRT(strtok_r) +# define _strtok_s RT_NOCRT(strtok_s) +# define _strxfrm RT_NOCRT(strxfrm) + +# define _wcslen RT_NOCRT(wcslen) +# define _wcscat RT_NOCRT(wcscat) +# define _wcschr RT_NOCRT(wcschr) +# define _wcscpy RT_NOCRT(wcscpy) +# define _wcsicmp RT_NOCRT(wcsicmp) +# define _wcstombs RT_NOCRT(wcstombs) +#endif + + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +/* + * Only for external libraries and such. + */ + +const char *RT_NOCRT(strerror)(int iErrNo); +char *RT_NOCRT(strdup)(const char *pszSrc); + +/* Underscored: */ +const char *RT_NOCRT(_strerror)(int iErrNo); +char *RT_NOCRT(_strdup)(const char *pszSrc); + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define strerror RT_NOCRT(strerror) +# define strdup RT_NOCRT(strdup) + +/* Underscored: */ +# define _strerror RT_NOCRT(strerror) +# define _strdup RT_NOCRT(strdup) +# endif + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_nocrt_string_h */ diff --git a/include/iprt/nocrt/sys/stat.h b/include/iprt/nocrt/sys/stat.h new file mode 100644 index 00000000..0ed81c59 --- /dev/null +++ b/include/iprt/nocrt/sys/stat.h @@ -0,0 +1,138 @@ +/** @file + * IPRT / No-CRT - sys/stat.h + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_sys_stat_h +#define IPRT_INCLUDED_nocrt_sys_stat_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include /* Establish timespec and timeval before iprt/fs.h includes iprt/time.h. */ +#include +#include +#include + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY + +struct RT_NOCRT(stat) +{ + RTINODE st_ino; + RTDEV st_dev; + RTDEV st_rdev; + RTFMODE st_mode; + uint32_t st_link; + RTUID st_uid; + RTGID st_gid; + RTFOFF st_size; + RTFOFF st_blocks; + uint32_t st_blksize; /**< Not related to st_blocks! */ + time_t st_birthtime; + time_t st_ctime; + time_t st_mtime; + time_t st_atime; +}; + +# define _S_IFIFO RTFS_TYPE_FIFO +# define _S_IFCHR RTFS_TYPE_DEV_CHAR +# define _S_IFDIR RTFS_TYPE_DIRECTORY +# define _S_IFBLK RTFS_TYPE_DEV_BLOCK +# define _S_IFREG RTFS_TYPE_FILE +# define _S_IFLNK RTFS_TYPE_SYMLINK +# define _S_IFSOCK RTFS_TYPE_SOCKET +# define _S_IFWHT RTFS_TYPE_WHITEOUT +# define _S_IFMT RTFS_TYPE_MASK + +# define S_IFIFO _S_IFIFO +# define S_IFCHR _S_IFCHR +# define S_IFDIR _S_IFDIR +# define S_IFBLK _S_IFBLK +# define S_IFREG _S_IFREG +# define S_IFLNK _S_IFLNK +# define S_IFSOCK _S_IFSOCK +# define S_IFWHT _S_IFWHT +# define S_IFMT _S_IFMT + +# define S_ISFIFO(a_fMode) RTFS_IS_FIFO(a_fMode) +# define S_ISCHR(a_fMode) RTFS_IS_DEV_CHAR(a_fMode) +# define S_ISDIR(a_fMode) RTFS_IS_DIRECTORY(a_fMode) +# define S_ISBLK(a_fMode) RTFS_IS_DEV_BLOCK(a_fMode) +# define S_ISREG(a_fMode) RTFS_IS_FILE(a_fMode) +# define S_ISLNK(a_fMode) RTFS_IS_SYMLINK(a_fMode) +# define S_ISSOCK(a_fMode) RTFS_IS_SOCKET(a_fMode) +# define S_ISWHT(a_fMode) RTFS_IS_WHITEOUT(a_fMode) + + +RT_C_DECLS_BEGIN + +int RT_NOCRT(chmod)(const char *pszPath, RTFMODE fMode); +int RT_NOCRT(fchmod)(int fd, RTFMODE fMode); +int RT_NOCRT(fstat)(int fd, struct RT_NOCRT(stat) *pStat); +int RT_NOCRT(lstat)(const char *pszPath, struct RT_NOCRT(stat) *pStat); +int RT_NOCRT(stat)(const char *pszPath, struct RT_NOCRT(stat) *pStat); +RTFMODE RT_NOCRT(umask)(RTFMODE fMode); +int RT_NOCRT(mkdir)(const char *, RTFMODE fMode); + +int RT_NOCRT(_chmod)(const char *pszPath, RTFMODE fMode); +int RT_NOCRT(_fchmod)(int fd, RTFMODE fMode); +int RT_NOCRT(_fstat)(int fd, struct RT_NOCRT(stat) *pStat); +int RT_NOCRT(_lstat)(const char *pszPath, struct RT_NOCRT(stat) *pStat); +int RT_NOCRT(_stat)(const char *pszPath, struct RT_NOCRT(stat) *pStat); +RTFMODE RT_NOCRT(_umask)(RTFMODE fMode); +int RT_NOCRT(_mkdir)(const char *, RTFMODE fMode); + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define chmod RT_NOCRT(chmod) +# define fchmod RT_NOCRT(fchmod) +# define fstat RT_NOCRT(fstat) +# define lstat RT_NOCRT(lstat) +# define stat RT_NOCRT(stat) +# define umask RT_NOCRT(umask) +# define mkdir RT_NOCRT(mkdir) + +# define _chmod RT_NOCRT(chmod) +# define _fchmod RT_NOCRT(fchmod) +# define _fstat RT_NOCRT(fstat) +# define _lstat RT_NOCRT(lstat) +# define _stat RT_NOCRT(stat) +# define _umask RT_NOCRT(umask) +# define _mkdir RT_NOCRT(mkdir) +# endif + +RT_C_DECLS_END + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + +#endif /* !IPRT_INCLUDED_nocrt_sys_stat_h */ + diff --git a/include/iprt/nocrt/sys/types.h b/include/iprt/nocrt/sys/types.h new file mode 100644 index 00000000..3320200a --- /dev/null +++ b/include/iprt/nocrt/sys/types.h @@ -0,0 +1,66 @@ +/** @file + * IPRT / No-CRT - Our own sys/types header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_sys_types_h +#define IPRT_INCLUDED_nocrt_sys_types_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if defined(IPRT_INCLUDED_types_h) && !defined(IPRT_COMPLETED_types_h) +# error "Can't include nocrt/sys/types.h from iprt/types.h" +#endif + +#include + +/* #if !defined(MSC-define) && !defined(GNU/LINUX-define) */ +#if !defined(_DEV_T_DEFINED) && !defined(__dev_t_defined) +typedef RTDEV dev_t; +#endif +#if !defined(_UCRT_RESTORE_CLANG_WARNINGS) /* MSC specific type */ +typedef int errno_t; +#endif +#if !defined(_INO_T_DEFINED) && !defined(__ino_t_defined) +typedef RTINODE ino_t; +#endif +#if !defined(_OFF_T_DEFINED) && !defined(__off_t_defined) +typedef RTFOFF off_t; +#endif +#if !defined(_PID_T_DEFINED) && !defined(__pid_t_defined) +typedef RTPROCESS pid_t; +#endif + +#endif /* !IPRT_INCLUDED_nocrt_sys_types_h */ + diff --git a/include/iprt/nocrt/time.h b/include/iprt/nocrt/time.h new file mode 100644 index 00000000..ab2a8649 --- /dev/null +++ b/include/iprt/nocrt/time.h @@ -0,0 +1,107 @@ +/** @file + * IPRT / No-CRT - Our minimal time.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_time_h +#define IPRT_INCLUDED_nocrt_time_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define RTTIME_INCL_TIMESPEC +/*#define RTTIME_INCL_TIMEVAL*/ +#include +#include + +/* #if !defined(MSC-define) && !defined(GNU/LINUX-define) */ +#if !defined(_TIME_T_DEFINED) && !defined(__time_t_defined) +# if defined(RT_OS_WINDOWS) && defined(_USE_32BIT_TIME_T) && ARCH_BITS == 32 +typedef long time_t; +# else +typedef int64_t time_t; +# endif +# ifdef _MSC_VER +typedef int64_t __time64_t; +# endif +#endif /* !_TIME_T_DEFINED */ + +#if !defined(_INC_TIME) /* MSC/UCRT guard */ + +# if !defined(_STRUCT_TIMESPEC) && !defined(__struct_timespec_defined) && !defined(_TIMESPEC_DEFINED) && !defined(__timespec_defined) /* << linux variations, new to old. */ +struct timespec +{ + time_t tv_sec; + long tv_nsec; +}; +# endif + +#if !defined(__struct_tm_defined) +struct tm +{ + int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year; + int tm_wday, tm_yday, tm_isdst, tm_gmtoff; + const char *tm_zone; +}; +# endif + +#endif /* !_INC_TIME */ + +RT_C_DECLS_BEGIN + +time_t RT_NOCRT(time)(time_t *); +errno_t RT_NOCRT(localtime_s)(struct tm *, const time_t *); /* The Microsoft version, not the C11 one. */ +struct tm *RT_NOCRT(localtime_r)(const time_t *, struct tm *); + +time_t RT_NOCRT(_time)(time_t *); +errno_t RT_NOCRT(_localtime_s)(struct tm *, const time_t *); +struct tm *RT_NOCRT(_localtime_r)(const time_t *, struct tm *); + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define time RT_NOCRT(time) +# define localtime_s RT_NOCRT(localtime_s) +# define localtime_r RT_NOCRT(localtime_r) + +# define _time RT_NOCRT(time) +# define _localtime_s RT_NOCRT(localtime_s) +# define _localtime_r RT_NOCRT(localtime_r) +# endif + +RT_C_DECLS_END + +#ifdef IPRT_INCLUDED_time_h +# error nocrt/time.h after time.h +#endif + +#endif /* !IPRT_INCLUDED_nocrt_time_h */ + diff --git a/include/iprt/nocrt/type_traits b/include/iprt/nocrt/type_traits new file mode 100644 index 00000000..c8c35b2f --- /dev/null +++ b/include/iprt/nocrt/type_traits @@ -0,0 +1,88 @@ +/** @file + * IPRT / No-CRT - Minimal type_traits C++ header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_type_traits +#define VBOX_INCLUDED_SRC_nocrt_type_traits +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +namespace std +{ + /* + * std::integral_constant + */ + template + struct integral_constant + { + static constexpr a_Type value = a_Value; + typedef a_Type value_type; + typedef integral_constant type; + constexpr operator value_type() const RT_NOEXCEPT { return value; } + /** @todo operator()() for 2014+ */ + }; + template constexpr a_Type integral_constant::value; + + /* Helper: */ + template using bool_constant = integral_constant; + + /* Specializations: */ + typedef integral_constant true_type; + typedef integral_constant false_type; + + + /* + * std::is_enum + */ + template struct is_enum + : integral_constant + { }; + + /* + * std::underlying_type + */ + template struct underlying_type + { + using type = __underlying_type(a_Type); /* compiler (clan, gcc, msc) builtin */ + }; + + template using underlying_type_t = typename underlying_type::type; + +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_type_traits */ + diff --git a/include/iprt/nocrt/unistd.h b/include/iprt/nocrt/unistd.h new file mode 100644 index 00000000..270a0739 --- /dev/null +++ b/include/iprt/nocrt/unistd.h @@ -0,0 +1,125 @@ +/** @file + * IPRT / No-CRT - Minimal unistd.h header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_unistd_h +#define IPRT_INCLUDED_nocrt_unistd_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +# include /* file.h includes fs.h which includes time.h */ +# include /* for RTFILE_SEEK_XXX */ +# include +#endif + + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY + +/* Flags for access: */ +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 + +/* These are also in stdio.h: */ +# undef SEEK_SET +# define SEEK_SET RTFILE_SEEK_BEGIN +# undef SEEK_CUR +# define SEEK_CUR RTFILE_SEEK_CURRENT +# undef SEEK_END +# define SEEK_END RTFILE_SEEK_END +AssertCompile(SEEK_SET == 0); AssertCompile(SEEK_CUR == 1); AssertCompile(SEEK_END == 2); /* Also in WDK header mmiscapi.h. */ + +RT_C_DECLS_BEGIN + +int RT_NOCRT(access)(const char *, int) RT_NOEXCEPT; +int RT_NOCRT(dup)(int) RT_NOEXCEPT; +int RT_NOCRT(dup2)(int, int) RT_NOEXCEPT; +ssize_t RT_NOCRT(read)(int, void *, size_t) RT_NOEXCEPT; +ssize_t RT_NOCRT(write)(int, const void *, size_t) RT_NOEXCEPT; +int RT_NOCRT(close)(int) RT_NOEXCEPT; +int RT_NOCRT(isatty)(int) RT_NOEXCEPT; +char *RT_NOCRT(getcwd)(char *, size_t) RT_NOEXCEPT; +RTPROCESS RT_NOCRT(getpid)(void) RT_NOEXCEPT; +RTPROCESS RT_NOCRT(getppid)(void) RT_NOEXCEPT; +int RT_NOCRT(unlink)(const char *) RT_NOEXCEPT; + +int RT_NOCRT(_access)(const char *, int) RT_NOEXCEPT; +int RT_NOCRT(_dup)(int) RT_NOEXCEPT; +int RT_NOCRT(_dup2)(int, int) RT_NOEXCEPT; +ssize_t RT_NOCRT(_read)(int, void *, size_t) RT_NOEXCEPT; +ssize_t RT_NOCRT(_write)(int, const void *, size_t) RT_NOEXCEPT; +int RT_NOCRT(_close)(int) RT_NOEXCEPT; +int RT_NOCRT(_isatty)(int) RT_NOEXCEPT; +char *RT_NOCRT(_getcwd)(char *, size_t) RT_NOEXCEPT; +RTPROCESS RT_NOCRT(_getpid)(void) RT_NOEXCEPT; +RTPROCESS RT_NOCRT(_getppid)(void) RT_NOEXCEPT; +int RT_NOCRT(_unlink)(const char *) RT_NOEXCEPT; + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define access RT_NOCRT(access) +# define dup RT_NOCRT(dup) +# define dup2 RT_NOCRT(dup2) +# define read RT_NOCRT(read) +# define write RT_NOCRT(write) +# define close RT_NOCRT(close) +# define isatty RT_NOCRT(isatty) +# define getcwd RT_NOCRT(getcwd) +# define getpid RT_NOCRT(getpid) +# define getppid RT_NOCRT(getppid) +# define unlink RT_NOCRT(unlink) + +# define _access RT_NOCRT(access) +# define _dup RT_NOCRT(dup) +# define _dup2 RT_NOCRT(dup2) +# define _read RT_NOCRT(read) +# define _write RT_NOCRT(write) +# define _close RT_NOCRT(close) +# define _isatty RT_NOCRT(isatty) +# define _getcwd RT_NOCRT(getcwd) +# define _getpid RT_NOCRT(getpid) +# define _getppid RT_NOCRT(getppid) +# define _unlink RT_NOCRT(unlink) +# endif + +RT_C_DECLS_END + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + + +#endif /* !IPRT_INCLUDED_nocrt_unistd_h */ + diff --git a/include/iprt/nocrt/vector b/include/iprt/nocrt/vector new file mode 100644 index 00000000..bee4b734 --- /dev/null +++ b/include/iprt/nocrt/vector @@ -0,0 +1,398 @@ +/** @file + * IPRT / No-CRT - Minimal C++ std::vector. + */ + +/* + * Copyright (C) 2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_vector +#define VBOX_INCLUDED_SRC_nocrt_vector +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +namespace std +{ + template + class RTCNoCrtVectorIterator + { + public: + typedef a_Type &reference; + typedef a_Type *pointer; + typedef typename a_Container::difference_type difference_type; + + protected: + a_Type *m_pItem; + + public: + RTCNoCrtVectorIterator() RT_NOEXCEPT + : m_pItem(NULL) + { } + + RTCNoCrtVectorIterator(a_Type *a_pItem) RT_NOEXCEPT + : m_pItem(a_pItem) + { } + + ~RTCNoCrtVectorIterator() + { + m_pItem = NULL; + } + + /** @name Moving the iterator. + * @{ */ + + RTCNoCrtVectorIterator &operator++() RT_NOEXCEPT + { + ++m_pItem; + return *this; + } + + RTCNoCrtVectorIterator &operator--() RT_NOEXCEPT + { + --m_pItem; + return *this; + } + + RTCNoCrtVectorIterator operator++(int) RT_NOEXCEPT + { + return RTCNoCrtVectorIterator(m_pItem++); + } + + RTCNoCrtVectorIterator operator--(int) RT_NOEXCEPT + { + return RTCNoCrtVectorIterator(m_pItem--); + } + + RTCNoCrtVectorIterator &operator+=(difference_type cItems) RT_NOEXCEPT + { + m_pItem += cItems; + return *this; + } + + RTCNoCrtVectorIterator &operator-=(difference_type cItems) RT_NOEXCEPT + { + m_pItem -= cItems; + return *this; + } + + RTCNoCrtVectorIterator operator+(difference_type cItems) const RT_NOEXCEPT + { + return RTCNoCrtVectorIterator(m_pItem + cItems); + } + + RTCNoCrtVectorIterator operator-(difference_type cItems) const RT_NOEXCEPT + { + return RTCNoCrtVectorIterator(m_pItem - cItems); + } + + /** @} */ + + /** @name Item access + * @{ */ + reference operator*() const RT_NOEXCEPT + { + return *m_pItem; + } + + pointer operator->() const RT_NOEXCEPT + { + return m_pItem; + } + + reference operator[](difference_type iItem) const RT_NOEXCEPT + { + return m_pItem[iItem]; + } + + /** @} */ + + /** Helper for const/non-const iterator comparisons: */ + inline typename a_Container::const_pointer getConst() const RT_NOEXCEPT + { + return m_pItem; + } + }; + + template + inline bool operator==(const RTCNoCrtVectorIterator &a_rLeft, + const RTCNoCrtVectorIterator &a_rRight) RT_NOEXCEPT + { + return a_rLeft.getConst() == a_rRight.getConst(); + } + + template + inline bool operator!=(const RTCNoCrtVectorIterator &a_rLeft, + const RTCNoCrtVectorIterator &a_rRight) RT_NOEXCEPT + { + return a_rLeft.getConst() != a_rRight.getConst(); + } + + template + inline bool operator<(const RTCNoCrtVectorIterator &a_rLeft, + const RTCNoCrtVectorIterator &a_rRight) RT_NOEXCEPT + { + return (uintptr_t)a_rLeft.getConst() < (uintptr_t)a_rRight.getConst(); + } + + template + inline bool operator<=(const RTCNoCrtVectorIterator &a_rLeft, + const RTCNoCrtVectorIterator &a_rRight) RT_NOEXCEPT + { + return (uintptr_t)a_rLeft.getConst() <= (uintptr_t)a_rRight.getConst(); + } + + template + inline bool operator>(const RTCNoCrtVectorIterator &a_rLeft, + const RTCNoCrtVectorIterator &a_rRight) RT_NOEXCEPT + { + return (uintptr_t)a_rLeft.getConst() > (uintptr_t)a_rRight.getConst(); + } + + template + inline bool operator>=(const RTCNoCrtVectorIterator &a_rLeft, + const RTCNoCrtVectorIterator &a_rRight) RT_NOEXCEPT + { + return (uintptr_t)a_rLeft.getConst() >= (uintptr_t)a_rRight.getConst(); + } + + + + template > + class vector + { + public: + typedef a_Type value_type; + typedef a_Type &reference; + typedef a_Type const &const_reference; + typedef a_Allocator allocator_type; + typedef typename a_Allocator::size_type size_type; + typedef typename a_Allocator::difference_type difference_type; + typedef typename a_Allocator::pointer pointer; + typedef typename a_Allocator::const_pointer const_pointer; + + typedef RTCNoCrtVectorIterator iterator; + typedef RTCNoCrtVectorIterator const_iterator; + + protected: + pointer m_paItems; + size_t m_cItems; + size_t m_cAllocated; + allocator_type m_Allocator; + + public: + vector() RT_NOEXCEPT + : m_paItems(NULL) + , m_cItems(0) + , m_cAllocated(0) + { } + + vector(size_type a_cAllocate) + : m_paItems(NULL) + , m_cItems(0) + , m_cAllocated(0) + { + m_paItems = m_Allocator.allocate(a_cAllocate); + if (m_paItems) + m_cAllocated = a_cAllocate; + } + + ~vector() + { + clear(); + } + + /** @name Iterators + * @{ */ + iterator begin() RT_NOEXCEPT + { + return iterator(m_paItems); + } + + const_iterator begin() const RT_NOEXCEPT + { + return const_iterator(m_paItems); + } + + const_iterator cbegin() const RT_NOEXCEPT + { + return const_iterator(m_paItems); + } + + iterator end() RT_NOEXCEPT + { + return iterator(m_paItems + m_cItems); + } + + const_iterator end() const RT_NOEXCEPT + { + return const_iterator(m_paItems + m_cItems); + } + + const_iterator cend() const RT_NOEXCEPT + { + return const_iterator(m_paItems + m_cItems); + } + /** @} */ + + /** @name Element access + * @{ */ + reference operator[](size_type iItem) RT_NOEXCEPT + { + Assert(iItem < m_cAllocated); + return m_paItems[iItem]; + } + + const_reference operator[](size_type iItem) const RT_NOEXCEPT + { + Assert(iItem < m_cAllocated); + return m_paItems[iItem]; + } + + reference front() RT_NOEXCEPT + { + return m_paItems[0]; + } + + const_reference front() const RT_NOEXCEPT + { + return m_paItems[0]; + } + + reference back() RT_NOEXCEPT + { + return m_paItems[m_cItems - 1]; + } + + const_reference back() const RT_NOEXCEPT + { + return m_paItems[m_cItems - 1]; + } + + pointer data() RT_NOEXCEPT + { + return m_paItems; + } + + const_pointer data() const RT_NOEXCEPT + { + return m_paItems; + } + + /** @} */ + + /** @name Capacity + * @{ */ + bool empty() const RT_NOEXCEPT + { + return m_cItems == 0; + } + + size_type size() const RT_NOEXCEPT + { + return m_cItems; + } + + size_type max_size() const RT_NOEXCEPT + { + return m_Allocator.max_size(); + } + + void reserve(size_type a_cNewAllocated) + { + Assert(a_cNewAllocated <= max_size()); + + if (a_cNewAllocated > m_cAllocated) + { + vector Temp(a_cNewAllocated); + if (Temp.m_paItems) + { + /* Copy over the data: */ + size_type const cItems = m_cItems; + const_pointer paSrc = m_paItems; + pointer paDst = Temp.m_paItems; + for (size_type i = 0; i < cItems; Temp.m_cItems = ++i) + m_Allocator.construct(&paDst[i], paSrc[i]); + + /* Swap the data. */ + size_type const cOldAllocated = m_cAllocated; + Temp.m_paItems = m_paItems; + m_paItems = paDst; + m_cAllocated = Temp.m_cAllocated; + Temp.m_cAllocated = cOldAllocated; + } + } + } + + /** @} */ + + /** @name Modifiers + * @{ */ + void push_back(const_reference a_rValue) + { + if (m_cItems < m_cAllocated) + { } + else + { + Assert(m_cItems * 2 >= m_cItems); + reserve(m_cItems < 8 ? 8 : m_cItems * 2); /* This might be non-standard. */ + AssertReturnVoid(m_cItems < m_cAllocated); + } + m_paItems[m_cItems] = a_rValue; + m_cItems++; + } + + void pop_back() RT_NOEXCEPT + { + if (m_cItems > 0) + m_cItems -= 1; + } + + void clear() RT_NOEXCEPT + { + size_type i = m_cItems; + while (i-- > 0) + { + m_Allocator.destroy(&m_paItems[i]); + m_cItems = i; + } + m_Allocator.deallocate(m_paItems, m_cAllocated); + m_paItems = NULL; + m_cAllocated = 0; + } + /** @} */ + }; + +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_vector */ + diff --git a/include/iprt/nocrt/x86/Makefile.kup b/include/iprt/nocrt/x86/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/nocrt/x86/fenv-x86-amd64.h b/include/iprt/nocrt/x86/fenv-x86-amd64.h new file mode 100644 index 00000000..55199ab8 --- /dev/null +++ b/include/iprt/nocrt/x86/fenv-x86-amd64.h @@ -0,0 +1,219 @@ +/** @file + * IPRT / No-CRT - x86 & AMD64 fenv.h. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_x86_fenv_x86_amd64_h +#define IPRT_INCLUDED_nocrt_x86_fenv_x86_amd64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +typedef struct RTNOCRTFENV +{ + /** The FPU environment. */ + union + { + uint32_t au32[28/4]; +#ifdef IPRT_INCLUDED_x86_h + X86FSTENV32P Env; +#endif + } fpu; + /** The SSE control & status register. */ + uint32_t fMxCsr; +} RTNOCRTFENV; + +/** Exception flags/mask. */ +typedef uint16_t RTNOCRTFEXCEPT; + +#ifndef IPRT_NOCRT_WITHOUT_CONFLICTING_TYPES +typedef RTNOCRTFENV fenv_t; +typedef RTNOCRTFEXCEPT fexcept_t; +#endif + +/** @name Exception flags (same as X86_FCW_xM, X86_FSW_xE, X86_MXCSR_xE) + * @note The X86_FSW_SF is not covered here as it is more of a sub-type of + * invalid operand exception, and it is not part of MXCSR. + * @{ */ +#define RT_NOCRT_FE_INVALID 0x0001 +#define RT_NOCRT_FE_DENORMAL 0x0002 +#define RT_NOCRT_FE_DIVBYZERO 0x0004 +#define RT_NOCRT_FE_OVERFLOW 0x0008 +#define RT_NOCRT_FE_UNDERFLOW 0x0010 +#define RT_NOCRT_FE_INEXACT 0x0020 +#define RT_NOCRT_FE_ALL_EXCEPT 0x003f +#ifndef IPRT_NOCRT_WITHOUT_MATH_CONSTANTS +# define FE_INVALID RT_NOCRT_FE_INVALID +# define FE_DENORMAL RT_NOCRT_FE_DENORMAL +# define FE_DIVBYZERO RT_NOCRT_FE_DIVBYZERO +# define FE_OVERFLOW RT_NOCRT_FE_OVERFLOW +# define FE_UNDERFLOW RT_NOCRT_FE_UNDERFLOW +# define FE_INEXACT RT_NOCRT_FE_INEXACT +# define FE_ALL_EXCEPT RT_NOCRT_FE_ALL_EXCEPT +#endif +/** @} */ + +/** @name Rounding Modes (same X86_FCW_RC_XXX) + * @{ */ +#define RT_NOCRT_FE_TONEAREST 0x0000 +#define RT_NOCRT_FE_DOWNWARD 0x0400 +#define RT_NOCRT_FE_UPWARD 0x0800 +#define RT_NOCRT_FE_TOWARDZERO 0x0c00 +#define RT_NOCRT_FE_ROUND_MASK 0x0c00 +#ifndef IPRT_NOCRT_WITHOUT_MATH_CONSTANTS +# define FE_TONEAREST RT_NOCRT_FE_TONEAREST +# define FE_DOWNWARD RT_NOCRT_FE_DOWNWARD +# define FE_UPWARD RT_NOCRT_FE_UPWARD +# define FE_TOWARDZERO RT_NOCRT_FE_TOWARDZERO +#endif +/** @} */ + + +/** @name x87 Precision (same X86_FCW_PC_XXX) + * @{ */ +#define RT_NOCRT_PC_FLOAT 0x0000 +#define RT_NOCRT_PC_RSVD 0x0100 +#define RT_NOCRT_PC_DOUBLE 0x0200 +#define RT_NOCRT_PC_EXTENDED 0x0300 +#define RT_NOCRT_PC_MASK 0x0300 +/** @} */ + + +/** @name Special environment pointer values. + * @note Only valid with fesetenv and feupdateenv. + * @note Defined as constants in fesetenv.asm. + * @{ */ +/** The default FPU+SSE environment set, all exceptions disabled (masked). */ +#define RT_NOCRT_FE_DFL_ENV ((RTNOCRTFENV const *)(intptr_t)1) +/** The default FPU+SSE environment set, but all exceptions enabled (unmasked) + * except for RT_NOCRT_FE_DENORMAL. */ +#define RT_NOCRT_FE_NOMASK_ENV ((RTNOCRTFENV const *)(intptr_t)2) +/** The default FPU+SSE environment set, all exceptions disabled (masked), + * double precision (53 bit mantissa). */ +#define RT_NOCRT_FE_PC53_ENV ((RTNOCRTFENV const *)(intptr_t)3) +/** The default FPU+SSE environment set, all exceptions disabled (masked), + * extended double precision (64 bit mantissa). */ +#define RT_NOCRT_FE_PC64_ENV ((RTNOCRTFENV const *)(intptr_t)4) +#ifndef IPRT_NOCRT_WITHOUT_MATH_CONSTANTS +# define FE_DFL_ENV RT_NOCRT_FE_DFL_ENV +# define FE_NOMASK_ENV RT_NOCRT_FE_NOMASK_ENV +# define FE_PC53_ENV RT_NOCRT_FE_PC53_ENV +# define FE_PC64_ENV RT_NOCRT_FE_PC64_ENV +#endif +/** @} */ + +RT_C_DECLS_BEGIN + +int RT_NOCRT(fegetenv)(RTNOCRTFENV *); +int RT_NOCRT(fesetenv)(RTNOCRTFENV const *); +int RT_NOCRT(feholdexcept)(RTNOCRTFENV *); +int RT_NOCRT(feupdateenv)(RTNOCRTFENV const *); + +int RT_NOCRT(fegetround)(void); +int RT_NOCRT(fesetround)(int); + +int RT_NOCRT(fegetexcept)(void); +int RT_NOCRT(feenableexcept)(int); +int RT_NOCRT(fedisableexcept)(int); + +int RT_NOCRT(feclearexcept)(int); +int RT_NOCRT(fetestexcept)(int); +int RT_NOCRT(fegetexceptflag)(RTNOCRTFEXCEPT *, int); +int RT_NOCRT(fesetexceptflag)(RTNOCRTFEXCEPT const *, int); + +int RT_NOCRT(feraiseexcept)(int); + +/* IPRT addition: */ +int RT_NOCRT(fegetx87precision)(void); +int RT_NOCRT(fesetx87precision)(int); + +/* Underscored variants: */ +int RT_NOCRT(_fegetenv)(RTNOCRTFENV *); +int RT_NOCRT(_fesetenv)(RTNOCRTFENV const *); +int RT_NOCRT(_feholdexcept)(RTNOCRTFENV *); +int RT_NOCRT(_feupdateenv)(RTNOCRTFENV const *); + +int RT_NOCRT(_fegetround)(void); +int RT_NOCRT(_fesetround)(int); + +int RT_NOCRT(_fegetexcept)(void); +int RT_NOCRT(_feenableexcept)(int); +int RT_NOCRT(_fedisableexcept)(int); + +int RT_NOCRT(_feclearexcept)(int); +int RT_NOCRT(_fetestexcept)(int); +int RT_NOCRT(_fegetexceptflag)(RTNOCRTFEXCEPT *, int); +int RT_NOCRT(_fesetexceptflag)(RTNOCRTFEXCEPT const *, int); + +int RT_NOCRT(_feraiseexcept)(int); + +/* Aliases: */ +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define fegetenv RT_NOCRT(fegetenv) +# define fesetenv RT_NOCRT(fesetenv) +# define feholdexcept RT_NOCRT(feholdexcept) +# define feupdateenv RT_NOCRT(feupdateenv) +# define fegetround RT_NOCRT(fegetround) +# define fesetround RT_NOCRT(fesetround) +# define fegetexcept RT_NOCRT(fegetexcept) +# define feenableexcept RT_NOCRT(feenableexcept) +# define fedisableexcept RT_NOCRT(fedisableexcept) +# define feclearexcept RT_NOCRT(feclearexcept) +# define fetestexcept RT_NOCRT(fetestexcept) +# define fegetexceptflag RT_NOCRT(fegetexceptflag) +# define fesetexceptflag RT_NOCRT(fesetexceptflag) +# define feraiseexcept RT_NOCRT(feraiseexcept) + +/* Underscored variants: */ +# define _fegetenv RT_NOCRT(fegetenv) +# define _fesetenv RT_NOCRT(fesetenv) +# define _feholdexcept RT_NOCRT(feholdexcept) +# define _feupdateenv RT_NOCRT(feupdateenv) +# define _fegetround RT_NOCRT(fegetround) +# define _fesetround RT_NOCRT(fesetround) +# define _fegetexcept RT_NOCRT(fegetexcept) +# define _feenableexcept RT_NOCRT(feenableexcept) +# define _fedisableexcept RT_NOCRT(fedisableexcept) +# define _feclearexcept RT_NOCRT(feclearexcept) +# define _fetestexcept RT_NOCRT(fetestexcept) +# define _fegetexceptflag RT_NOCRT(fegetexceptflag) +# define _fesetexceptflag RT_NOCRT(fesetexceptflag) +# define _feraiseexcept RT_NOCRT(feraiseexcept) +#endif + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_nocrt_x86_fenv_x86_amd64_h */ + diff --git a/include/iprt/nocrt/x86/math.h b/include/iprt/nocrt/x86/math.h new file mode 100644 index 00000000..1aa223a3 --- /dev/null +++ b/include/iprt/nocrt/x86/math.h @@ -0,0 +1,114 @@ +/** @file + * IPRT / No-CRT - math.h, x86 inlined functions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_x86_math_h +#define IPRT_INCLUDED_nocrt_x86_math_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#if RT_INLINE_ASM_GNU_STYLE + +DECLINLINE(long double) inline_atan2l(long double lrd1, long double lrd2) +{ + long double lrdResult; + __asm__ __volatile__("fpatan" + : "=t" (lrdResult) + : "u" (lrd1), + "0" (lrd2) + : "st(1)"); + return lrdResult; +} + +DECLINLINE(long double) inline_rintl(long double lrd) +{ + long double lrdResult; + __asm__ __volatile__("frndint" + : "=t" (lrdResult) + : "0" (lrd)); + return lrdResult; +} + +DECLINLINE(float) inline_rintf(float rf) +{ + return (float)inline_rintl(rf); +} + +DECLINLINE(double) inline_rint(double rd) +{ + return (double)inline_rintl(rd); +} + +DECLINLINE(long double) inline_sqrtl(long double lrd) +{ + long double lrdResult; + __asm__ __volatile__("fsqrt" + : "=t" (lrdResult) + : "0" (lrd)); + return lrdResult; +} + +DECLINLINE(float) inline_sqrtf(float rf) +{ + return (float)inline_sqrtl(rf); +} + +DECLINLINE(double) inline_sqrt(double rd) +{ + return (double)inline_sqrtl(rd); +} + + +# undef atan2l +# define atan2l(lrd1, lrd2) inline_atan2l(lrd1, lrd2) +# undef rint +# define rint(rd) inline_rint(rd) +# undef rintf +# define rintf(rf) inline_rintf(rf) +# undef rintl +# define rintl(lrd) inline_rintl(lrd) +# undef sqrt +# define sqrt(rd) inline_sqrt(rd) +# undef sqrtf +# define sqrtf(rf) inline_sqrtf(rf) +# undef sqrtl +# define sqrtl(lrd) inline_sqrtl(lrd) + +#endif /* RT_INLINE_ASM_GNU_STYLE */ + +#endif /* !IPRT_INCLUDED_nocrt_x86_math_h */ + diff --git a/include/iprt/nt/Makefile.kup b/include/iprt/nt/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/nt/dispmprt.h b/include/iprt/nt/dispmprt.h new file mode 100644 index 00000000..055648d9 --- /dev/null +++ b/include/iprt/nt/dispmprt.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include dispmprt.h (DDK). + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_dispmprt_h +#define IPRT_INCLUDED_nt_dispmprt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'DBG' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# ifndef __cplusplus +# pragma warning(disable:4255) /* video.h(1776) : warning C4255: 'VideoPortGetCurrentIrql' : no function prototype given: converting '()' to '(void)' */ +# endif +#endif + +RT_C_DECLS_BEGIN +#include +RT_C_DECLS_END + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_dispmprt_h */ + diff --git a/include/iprt/nt/hyperv.h b/include/iprt/nt/hyperv.h new file mode 100644 index 00000000..aa461a35 --- /dev/null +++ b/include/iprt/nt/hyperv.h @@ -0,0 +1,1768 @@ +/** @file + * Hyper-V related types and definitions. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_hyperv_h +#define IPRT_INCLUDED_nt_hyperv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#ifndef IN_IDA_PRO +# include +# include +#else +# define RT_FLEXIBLE_ARRAY +# define RT_FLEXIBLE_ARRAY_EXTENSION +# define AssertCompile(expr) +# define AssertCompileSize(type, size) +# define AssertCompileMemberOffset(type, member, off) +typedef unsigned char uint8_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#endif + + +/** Hyper-V partition ID. */ +typedef uint64_t HV_PARTITION_ID; +/** Invalid Hyper-V partition ID. */ +#define HV_PARTITION_ID_INVALID UINT64_C(0) +/** Hyper-V virtual processor index (== VMCPUID). */ +typedef uint32_t HV_VP_INDEX; +/** Guest physical address (== RTGCPHYS). */ +typedef uint64_t HV_GPA; +/** Guest physical page number. */ +typedef uint64_t HV_GPA_PAGE_NUMBER; +/** System(/parent) physical page number. */ +typedef uint64_t HV_SPA_PAGE_NUMBER; +/** Hyper-V unsigned 128-bit integer type. */ +typedef struct { uint64_t Low64, High64; } HV_UINT128; +/** Hyper-V port ID. */ +typedef union +{ + uint32_t AsUINT32; + struct + { + uint32_t Id : 24; + uint32_t Reserved : 8; + }; +} HV_PORT_ID; +/** Pointer to a Hyper-V port ID. */ +typedef HV_PORT_ID *PHV_PORT_ID; + + +/** + * Hypercall IDs. + */ +typedef enum +{ + HvCallReserved0000 = 0, + + HvCallSwitchVirtualAddressSpace, + HvCallFlushVirtualAddressSpace, + HvCallFlushVirtualAddressList, + HvCallGetLogicalProcessorRunTime, + /* 5, 6 & 7 are deprecated / reserved. */ + HvCallNotifyLongSpinWait = 8, + HvCallParkLogicalProcessors, /**< @since v2 */ + HvCallInvokeHypervisorDebugger, /**< @since v2 - not mentioned in TLFS v5.0b */ + HvCallSendSyntheticClusterIpi, /**< @since v? */ + HvCallModifyVtlProtectionMask, /**< @since v? */ + HvCallEnablePartitionVtl, /**< @since v? */ + HvCallDisablePartitionVtl, /**< @since v? */ + HvCallEnableVpVtl, /**< @since v? */ + HvCallDisableVpVtl, /**< @since v? */ + HvCallVtlCall, /**< @since v? */ + HvCallVtlReturn, /**< @since v? */ + HvCallFlushVirtualAddressSpaceEx, /**< @since v? */ + HvCallFlushVirtualAddressListEx, /**< @since v? */ + HvCallSendSyntheticClusterIpiEx, /**< @since v? */ + /* Reserved: 0x16..0x3f */ + + HvCallCreatePartition = 0x40, + HvCallInitializePartition, + HvCallFinalizePartition, + HvCallDeletePartition, + HvCallGetPartitionProperty, + HvCallSetPartitionProperty, + HvCallGetPartitionId, + HvCallGetNextChildPartition, + HvCallDepositMemory, /**< 0x48 - Repeat call. */ + HvCallWithdrawMemory, /**< 0x49 - Repeat call. */ + HvCallGetMemoryBalance, + HvCallMapGpaPages, /**< 0X4b - Repeat call. */ + HvCallUnmapGpaPages, /**< 0X4c - Repeat call. */ + HvCallInstallIntercept, + HvCallCreateVp, + HvCallDeleteVp, /**< 0x4f - Fast call. */ + HvCallGetVpRegisters, /**< 0x50 - Repeat call. */ + HvCallSetVpRegisters, /**< 0x51 - Repeat call. */ + HvCallTranslateVirtualAddress, + HvCallReadGpa, + HvCallWriteGpa, + HvCallAssertVirtualInterruptV1, + HvCallClearVirtualInterrupt, /**< 0x56 - Fast call. */ + HvCallCreatePortV1, + HvCallDeletePort, /**< 0x58 - Fast call. */ + HvCallConnectPortV1, + HvCallGetPortProperty, + HvCallDisconnectPort, + HvCallPostMessage, + HvCallSignalEvent, + HvCallSavePartitionState, + HvCallRestorePartitionState, + HvCallInitializeEventLogBufferGroup, + HvCallFinalizeEventLogBufferGroup, + HvCallCreateEventLogBuffer, + HvCallDeleteEventLogBuffer, + HvCallMapEventLogBuffer, + HvCallUnmapEventLogBuffer, + HvCallSetEventLogGroupSources, + HvCallReleaseEventLogBuffer, + HvCallFlushEventLogBuffer, + HvCallPostDebugData, + HvCallRetrieveDebugData, + HvCallResetDebugSession, + HvCallMapStatsPage, + HvCallUnmapStatsPage, + HvCallMapSparseGpaPages, /**< @since v2 */ + HvCallSetSystemProperty, /**< @since v2 */ + HvCallSetPortProperty, /**< @since v2 */ + /* 0x71..0x75 reserved/deprecated (was v2 test IDs). */ + HvCallAddLogicalProcessor = 0x76, + HvCallRemoveLogicalProcessor, + HvCallQueryNumaDistance, + HvCallSetLogicalProcessorProperty, + HvCallGetLogicalProcessorProperty, + HvCallGetSystemProperty, + HvCallMapDeviceInterrupt, + HvCallUnmapDeviceInterrupt, + HvCallRetargetDeviceInterrupt, + /* 0x7f is reserved. */ + HvCallMapDevicePages = 0x80, + HvCallUnmapDevicePages, + HvCallAttachDevice, + HvCallDetachDevice, + HvCallNotifyStandbyTransition, + HvCallPrepareForSleep, + HvCallPrepareForHibernate, + HvCallNotifyPartitionEvent, + HvCallGetLogicalProcessorRegisters, + HvCallSetLogicalProcessorRegisters, + HvCallQueryAssociatedLpsforMca, + HvCallNotifyRingEmpty, + HvCallInjectSyntheticMachineCheck, + HvCallScrubPartition, + HvCallCollectLivedump, + HvCallDisableHypervisor, + HvCallModifySparseGpaPages, + HvCallRegisterInterceptResult, + HvCallUnregisterInterceptResult, + /* 0x93 is reserved/undocumented. */ + HvCallAssertVirtualInterrupt = 0x94, + HvCallCreatePort, + HvCallConnectPort, + HvCallGetSpaPageList, + /* 0x98 is reserved. */ + HvCallStartVirtualProcessor = 0x99, + HvCallGetVpIndexFromApicId, + /* 0x9b..0xae are reserved/undocumented. + 0xad: New version of HvCallGetVpRegisters? Perhaps on logical CPU or smth. */ + HvCallFlushGuestPhysicalAddressSpace = 0xaf, + HvCallFlushGuestPhysicalAddressList, + /* 0xb1..0xb4 are unknown */ + HvCallCreateCpuGroup = 0xb5, + HvCallDeleteCpuGroup, + HvCallGetCpuGroupProperty, + HvCallSetCpuGroupProperty, + HvCallGetCpuGroupAffinit, + HvCallGetNextCpuGroup = 0xba, + HvCallGetNextCpuGroupPartition, + HvCallPrecommitGpaPages = 0xbe, + HvCallUncommitGpaPages, /**< Happens when VidDestroyGpaRangeCheckSecure/WHvUnmapGpaRange is called. */ + /* 0xc0 is unknown */ + HvCallVpRunloopRelated = 0xc2, /**< Fast */ + /* 0xc3..0xcb are unknown */ + HvCallQueryVtlProtectionMaskRange = 0xcc, + HvCallModifyVtlProtectionMaskRange, + /* 0xce..0xd1 are unknown */ + HvCallAcquireSparseGpaPageHostAccess = 0xd2, + HvCallReleaseSparseGpaPageHostAccess, + HvCallCheckSparseGpaPageVtlAccess, + HvCallAcquireSparseSpaPageHostAccess = 0xd7, + HvCallReleaseSparseSpaPageHostAccess, + HvCallAcceptGpaPages, /**< 0x18 byte input, zero rep, no output. */ + /* 0xda..0xe0 are unknown (not dug out yet) */ + HvCallMapVpRegisterPage = 0xe1, /**< Takes partition id + VP index (16 bytes). Returns a physical address (8 bytes). */ + HvCallUnmapVpRegisterPage, /**< Takes partition id + VP index. */ + HvCallUnknownE3, + HvCallUnknownE4, + HvCallUnknownE5, + HvCallUnknownE6, + /** Number of defined hypercalls (varies with version). */ + HvCallCount +} HV_CALL_CODE; +AssertCompile(HvCallSendSyntheticClusterIpiEx == 0x15); +AssertCompile(HvCallMapGpaPages == 0x4b); +AssertCompile(HvCallSetPortProperty == 0x70); +AssertCompile(HvCallRetargetDeviceInterrupt == 0x7e); +AssertCompile(HvCallUnregisterInterceptResult == 0x92); +AssertCompile(HvCallGetSpaPageList == 0x97); +AssertCompile(HvCallFlushGuestPhysicalAddressList == 0xb0); +AssertCompile(HvCallUncommitGpaPages == 0xbf); +AssertCompile(HvCallCount == 0xe7); + +/** Makes the first parameter to a hypercall (rcx). */ +#define HV_MAKE_CALL_INFO(a_enmCallCode, a_cReps) ( (uint64_t)(a_enmCallCode) | ((uint64_t)(a_cReps) << 32) ) +/** Makes the return value (success) for a rep hypercall. */ +#define HV_MAKE_CALL_REP_RET(a_cReps) ((uint64_t)(a_cReps) << 32) + +/** Hypercall status code. */ +typedef uint16_t HV_STATUS; + +/** @name Hyper-V Hypercall status codes + * @{ */ +#define HV_STATUS_SUCCESS (0x0000) +#define HV_STATUS_RESERVED_1 (0x0001) +#define HV_STATUS_INVALID_HYPERCALL_CODE (0x0002) +#define HV_STATUS_INVALID_HYPERCALL_INPUT (0x0003) +#define HV_STATUS_INVALID_ALIGNMENT (0x0004) +#define HV_STATUS_INVALID_PARAMETER (0x0005) +#define HV_STATUS_ACCESS_DENIED (0x0006) +#define HV_STATUS_INVALID_PARTITION_STATE (0x0007) +#define HV_STATUS_OPERATION_DENIED (0x0008) +#define HV_STATUS_UNKNOWN_PROPERTY (0x0009) +#define HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE (0x000a) +#define HV_STATUS_INSUFFICIENT_MEMORY (0x000b) +#define HV_STATUS_PARTITION_TOO_DEEP (0x000c) +#define HV_STATUS_INVALID_PARTITION_ID (0x000d) +#define HV_STATUS_INVALID_VP_INDEX (0x000e) +#define HV_STATUS_RESERVED_F (0x000f) +#define HV_STATUS_NOT_FOUND (0x0010) +#define HV_STATUS_INVALID_PORT_ID (0x0011) +#define HV_STATUS_INVALID_CONNECTION_ID (0x0012) +#define HV_STATUS_INSUFFICIENT_BUFFERS (0x0013) +#define HV_STATUS_NOT_ACKNOWLEDGED (0x0014) +#define HV_STATUS_INVALID_VP_STATE (0x0015) +#define HV_STATUS_ACKNOWLEDGED (0x0016) +#define HV_STATUS_INVALID_SAVE_RESTORE_STATE (0x0017) +#define HV_STATUS_INVALID_SYNIC_STATE (0x0018) +#define HV_STATUS_OBJECT_IN_USE (0x0019) +#define HV_STATUS_INVALID_PROXIMITY_DOMAIN_INFO (0x001a) +#define HV_STATUS_NO_DATA (0x001b) +#define HV_STATUS_INACTIVE (0x001c) +#define HV_STATUS_NO_RESOURCES (0x001d) +#define HV_STATUS_FEATURE_UNAVAILABLE (0x001e) +#define HV_STATUS_PARTIAL_PACKET (0x001f) +#define HV_STATUS_PROCESSOR_FEATURE_SSE3_NOT_SUPPORTED (0x0020) +#define HV_STATUS_PROCESSOR_FEATURE_LAHFSAHF_NOT_SUPPORTED (0x0021) +#define HV_STATUS_PROCESSOR_FEATURE_SSSE3_NOT_SUPPORTED (0x0022) +#define HV_STATUS_PROCESSOR_FEATURE_SSE4_1_NOT_SUPPORTED (0x0023) +#define HV_STATUS_PROCESSOR_FEATURE_SSE4_2_NOT_SUPPORTED (0x0024) +#define HV_STATUS_PROCESSOR_FEATURE_SSE4A_NOT_SUPPORTED (0x0025) +#define HV_STATUS_PROCESSOR_FEATURE_XOP_NOT_SUPPORTED (0x0026) +#define HV_STATUS_PROCESSOR_FEATURE_POPCNT_NOT_SUPPORTED (0x0027) +#define HV_STATUS_PROCESSOR_FEATURE_CMPXCHG16B_NOT_SUPPORTED (0x0028) +#define HV_STATUS_PROCESSOR_FEATURE_ALTMOVCR8_NOT_SUPPORTED (0x0029) +#define HV_STATUS_PROCESSOR_FEATURE_LZCNT_NOT_SUPPORTED (0x002a) +#define HV_STATUS_PROCESSOR_FEATURE_MISALIGNED_SSE_NOT_SUPPORTED (0x002b) +#define HV_STATUS_PROCESSOR_FEATURE_MMX_EXT_NOT_SUPPORTED (0x002c) +#define HV_STATUS_PROCESSOR_FEATURE_3DNOW_NOT_SUPPORTED (0x002d) +#define HV_STATUS_PROCESSOR_FEATURE_EXTENDED_3DNOW_NOT_SUPPORTED (0x002e) +#define HV_STATUS_PROCESSOR_FEATURE_PAGE_1GB_NOT_SUPPORTED (0x002f) +#define HV_STATUS_PROCESSOR_CACHE_LINE_FLUSH_SIZE_INCOMPATIBLE (0x0030) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_NOT_SUPPORTED (0x0031) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVEOPT_NOT_SUPPORTED (0x0032) +#define HV_STATUS_INSUFFICIENT_BUFFER (0x0033) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_AVX_NOT_SUPPORTED (0x0034) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_ FEATURE_NOT_SUPPORTED (0x0035) +#define HV_STATUS_PROCESSOR_XSAVE_SAVE_AREA_INCOMPATIBLE (0x0036) +#define HV_STATUS_INCOMPATIBLE_PROCESSOR (0x0037) +#define HV_STATUS_INSUFFICIENT_DEVICE_DOMAINS (0x0038) +#define HV_STATUS_PROCESSOR_FEATURE_AES_NOT_SUPPORTED (0x0039) +#define HV_STATUS_PROCESSOR_FEATURE_PCLMULQDQ_NOT_SUPPORTED (0x003a) +#define HV_STATUS_PROCESSOR_FEATURE_INCOMPATIBLE_XSAVE_FEATURES (0x003b) +#define HV_STATUS_CPUID_FEATURE_VALIDATION_ERROR (0x003c) +#define HV_STATUS_CPUID_XSAVE_FEATURE_VALIDATION_ERROR (0x003d) +#define HV_STATUS_PROCESSOR_STARTUP_TIMEOUT (0x003e) +#define HV_STATUS_SMX_ENABLED (0x003f) +#define HV_STATUS_PROCESSOR_FEATURE_PCID_NOT_SUPPORTED (0x0040) +#define HV_STATUS_INVALID_LP_INDEX (0x0041) +#define HV_STATUS_FEATURE_FMA4_NOT_SUPPORTED (0x0042) +#define HV_STATUS_FEATURE_F16C_NOT_SUPPORTED (0x0043) +#define HV_STATUS_PROCESSOR_FEATURE_RDRAND_NOT_SUPPORTED (0x0044) +#define HV_STATUS_PROCESSOR_FEATURE_RDWRFSGS_NOT_SUPPORTED (0x0045) +#define HV_STATUS_PROCESSOR_FEATURE_SMEP_NOT_SUPPORTED (0x0046) +#define HV_STATUS_PROCESSOR_FEATURE_ENHANCED_FAST_STRING_NOT_SUPPORTED (0x0047) +#define HV_STATUS_PROCESSOR_FEATURE_MOVBE_NOT_SUPPORTED (0x0048) +#define HV_STATUS_PROCESSOR_FEATURE_BMI1_NOT_SUPPORTED (0x0049) +#define HV_STATUS_PROCESSOR_FEATURE_BMI2_NOT_SUPPORTED (0x004a) +#define HV_STATUS_PROCESSOR_FEATURE_HLE_NOT_SUPPORTED (0x004b) +#define HV_STATUS_PROCESSOR_FEATURE_RTM_NOT_SUPPORTED (0x004c) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_FMA_NOT_SUPPORTED (0x004d) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_AVX2_NOT_SUPPORTED (0x004e) +#define HV_STATUS_PROCESSOR_FEATURE_NPIEP1_NOT_SUPPORTED (0x004f) +#define HV_STATUS_INVALID_REGISTER_VALUE (0x0050) +#define HV_STATUS_PROCESSOR_FEATURE_RDSEED_NOT_SUPPORTED (0x0052) +#define HV_STATUS_PROCESSOR_FEATURE_ADX_NOT_SUPPORTED (0x0053) +#define HV_STATUS_PROCESSOR_FEATURE_SMAP_NOT_SUPPORTED (0x0054) +#define HV_STATUS_NX_NOT_DETECTED (0x0055) +#define HV_STATUS_PROCESSOR_FEATURE_INTEL_PREFETCH_NOT_SUPPORTED (0x0056) +#define HV_STATUS_INVALID_DEVICE_ID (0x0057) +#define HV_STATUS_INVALID_DEVICE_STATE (0x0058) +#define HV_STATUS_PENDING_PAGE_REQUESTS (0x0059) +#define HV_STATUS_PAGE_REQUEST_INVALID (0x0060) +#define HV_STATUS_OPERATION_FAILED (0x0071) +#define HV_STATUS_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE (0x0072) +/** @} */ + + +/** Hyper-V partition property value. */ +typedef uint64_t HV_PARTITION_PROPERTY; +/** Pointer to a partition property value. */ +typedef HV_PARTITION_PROPERTY *PHV_PARTITION_PROPERTY; +/** + * Hyper-V partition property code. + * This is documented in TLFS, except version 5.x. + */ +typedef enum +{ + HvPartitionPropertyPrivilegeFlags = 0x00010000, + HvPartitionPropertySyntheticProcessorFeaturesBanks, /**< Read by WHvApi::Capabilities::GetSyntheticProcessorFeaturesBanks (build 22000) */ + + HvPartitionPropertyCpuReserve = 0x00020001, + HvPartitionPropertyCpuCap, + HvPartitionPropertyCpuWeight, + HvPartitionPropertyUnknown20004, /**< On exo partition (build 17134), initial value zero. */ + + HvPartitionPropertyEmulatedTimerPeriod = 0x00030000, /**< @note Fails on exo partition (build 17134). */ + HvPartitionPropertyEmulatedTimerControl, /**< @note Fails on exo partition (build 17134). */ + HvPartitionPropertyPmTimerAssist, /**< @note Fails on exo partition (build 17134). */ + HvPartitionPropertyUnknown30003, /**< @note WHvSetupPartition writes this (build 22000). */ + HvPartitionPropertyUnknown30004, /**< ? */ + HvPartitionPropertyUnknown30005, /**< WHvPartitionPropertyCodeReferenceTime maps to this (build 22000) */ + + HvPartitionPropertyDebugChannelId = 0x00040000, /**< @note Hangs system on exo partition hangs (build 17134). */ + + HvPartitionPropertyVirtualTlbPageCount = 0x00050000, + HvPartitionPropertyUnknown50001, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown50002, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown50003, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown50004, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown50005, /**< On exo partition (build 17134), initial value one. */ + HvPartitionPropertyUnknown50006, /**< On exo partition (build 17134), initial value zero. + * @note build 22000/w11-ga fends this off in VID.SYS. */ + HvPartitionPropertyUnknown50007, + HvPartitionPropertyUnknown50008, + HvPartitionPropertyUnknown50009, + HvPartitionPropertyUnknown5000a, + HvPartitionPropertyUnknown5000b, + HvPartitionPropertyUnknown5000c, + HvPartitionPropertyUnknown5000d, + HvPartitionPropertyUnknown5000e, + HvPartitionPropertyUnknown5000f, + HvPartitionPropertyUnknown50010, + HvPartitionPropertyUnknown50012, + HvPartitionPropertyUnknown50013, /**< Set by WHvSetupPartition (build 22000) */ + HvPartitionPropertyUnknown50014, + HvPartitionPropertyUnknown50015, + HvPartitionPropertyUnknown50016, + HvPartitionPropertyUnknown50017, /**< Set by WHvSetupPartition (build 22000) */ + + HvPartitionPropertyProcessorVendor = 0x00060000, + HvPartitionPropertyProcessorFeatures, /**< On exo/17134/threadripper: 0x6cb26f39fbf */ + HvPartitionPropertyProcessorXsaveFeatures, + HvPartitionPropertyProcessorCLFlushSize, /**< On exo/17134/threadripper: 8 */ + HvPartitionPropertyUnknown60004, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown60005, /**< On exo partition (build 17134), initial value 0x603. */ + HvPartitionPropertyUnknown60006, /**< On exo partition (build 17134), initial value 0x2c. */ + HvPartitionPropertyUnknown60007, /**< WHvSetupPartition reads this (build 22000). */ + HvPartitionPropertyUnknown60008, /**< WHvSetupPartition reads this (build 22000). */ + HvPartitionPropertyProcessorClockFrequency, /**< Read by WHvApi::Capabilities::GetProcessorClockFrequency (build 22000). */ + HvPartitionPropertyProcessorFeaturesBank0, /**< Read by WHvApi::Capabilities::GetProcessorFeaturesBanks (build 22000). */ + HvPartitionPropertyProcessorFeaturesBank1, /**< Read by WHvApi::Capabilities::GetProcessorFeaturesBanks (build 22000). */ + + HvPartitionPropertyGuestOsId = 0x00070000, /**< @since v4 */ + + HvPartitionPropertyUnknown800000 = 0x00080000 /**< On exo partition (build 17134), initial value zero. */ +} HV_PARTITION_PROPERTY_CODE; +AssertCompileSize(HV_PARTITION_PROPERTY_CODE, 4); +/** Pointer to a partition property code. */ +typedef HV_PARTITION_PROPERTY_CODE *PHV_PARTITION_PROPERTY_CODE; + + +/** Input for HvCallGetPartitionProperty. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_PARTITION_PROPERTY_CODE PropertyCode; + uint32_t uPadding; +} HV_INPUT_GET_PARTITION_PROPERTY; +AssertCompileSize(HV_INPUT_GET_PARTITION_PROPERTY, 16); +/** Pointer to input for HvCallGetPartitionProperty. */ +typedef HV_INPUT_GET_PARTITION_PROPERTY *PHV_INPUT_GET_PARTITION_PROPERTY; + +/** Output for HvCallGetPartitionProperty. */ +typedef struct +{ + HV_PARTITION_PROPERTY PropertyValue; +} HV_OUTPUT_GET_PARTITION_PROPERTY; +/** Pointer to output for HvCallGetPartitionProperty. */ +typedef HV_OUTPUT_GET_PARTITION_PROPERTY *PHV_OUTPUT_GET_PARTITION_PROPERTY; + + +/** Input for HvCallSetPartitionProperty. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_PARTITION_PROPERTY_CODE PropertyCode; + uint32_t uPadding; + HV_PARTITION_PROPERTY PropertyValue; +} HV_INPUT_SET_PARTITION_PROPERTY; +AssertCompileSize(HV_INPUT_SET_PARTITION_PROPERTY, 24); +/** Pointer to input for HvCallSetPartitionProperty. */ +typedef HV_INPUT_SET_PARTITION_PROPERTY *PHV_INPUT_SET_PARTITION_PROPERTY; + + +/** Hyper-V NUMA node ID. + * On systems without NUMA, i.e. a single node, it uses 0 as identifier. */ +typedef uint32_t HV_PROXIMITY_DOMAIN_ID; +/** Pointer to NUMA node ID. */ +typedef HV_PROXIMITY_DOMAIN_ID *PHV_PROXIMITY_DOMAIN_ID; + +/** Hyper-V NUMA flags. */ +typedef struct +{ + uint32_t ProximityPreferred : 1; /**< When set, allocations may come from other NUMA nodes. */ + uint32_t Reserved : 30; /**< Reserved for future (as of circa v2). */ + uint32_t ProxyimityInfoValid : 1; /**< Set if the NUMA information is valid. */ +} HV_PROXIMITY_DOMAIN_FLAGS; +/** Pointer to Hyper-V NUMA flags. */ +typedef HV_PROXIMITY_DOMAIN_FLAGS *PHV_PROXIMITY_DOMAIN_FLAGS; + +/** Hyper-V NUMA information. */ +typedef struct +{ + HV_PROXIMITY_DOMAIN_ID Id; /**< NUMA node identifier. */ + HV_PROXIMITY_DOMAIN_FLAGS Flags; /**< NUMA flags. */ +} HV_PROXIMITY_DOMAIN_INFO; +/** Pointer to Hyper-V NUMA information. */ +typedef HV_PROXIMITY_DOMAIN_INFO *PHV_PROXIMITY_DOMAIN_INFO; + +/** Input for HvCallGetMemoryBalance. */ +typedef struct +{ + HV_PARTITION_ID TargetPartitionId; + HV_PROXIMITY_DOMAIN_INFO ProximityDomainInfo; +} HV_INPUT_GET_MEMORY_BALANCE; +AssertCompileSize(HV_INPUT_GET_MEMORY_BALANCE, 16); +/** Pointer to the input for HvCallGetMemoryBalance. */ +typedef HV_INPUT_GET_MEMORY_BALANCE *PHV_INPUT_GET_MEMORY_BALANCE; + +/** Output for HvCallGetMemoryBalance. */ +typedef struct +{ + uint64_t PagesAvailable; + uint64_t PagesInUse; +} HV_OUTPUT_GET_MEMORY_BALANCE; +/** Pointer to the output for HvCallGetMemoryBalance. */ +typedef HV_OUTPUT_GET_MEMORY_BALANCE *PHV_OUTPUT_GET_MEMORY_BALANCE; + + +/** @name Flags used with HvCallMapGpaPages and HvCallMapSparseGpaPages. + * @note There seems to be a more flags defined after v2. + * @{ */ +typedef uint32_t HV_MAP_GPA_FLAGS; +#define HV_MAP_GPA_READABLE UINT32_C(0x0001) +#define HV_MAP_GPA_WRITABLE UINT32_C(0x0002) +#define HV_MAP_GPA_EXECUTABLE UINT32_C(0x0004) +/** Seems this have to be set when HV_MAP_GPA_EXECUTABLE is (17101). */ +#define HV_MAP_GPA_EXECUTABLE_AGAIN UINT32_C(0x0008) +/** Dunno what this is yet, but it requires HV_MAP_GPA_DUNNO_1000. + * The readable bit gets put here when both HV_MAP_GPA_DUNNO_1000 and + * HV_MAP_GPA_DUNNO_MASK_0700 are clear. */ +#define HV_MAP_GPA_DUNNO_ACCESS UINT32_C(0x0010) +/** Guess work. */ +#define HV_MAP_GPA_MAYBE_ACCESS_MASK UINT32_C(0x001f) +/** Some kind of mask. */ +#define HV_MAP_GPA_DUNNO_MASK_0700 UINT32_C(0x0700) +/** Dunno what this is, but required for HV_MAP_GPA_DUNNO_ACCESS. */ +#define HV_MAP_GPA_DUNNO_1000 UINT32_C(0x1000) +/** Working with large 2MB pages. */ +#define HV_MAP_GPA_LARGE UINT32_C(0x2000) +/** Valid mask as per build 17101. */ +#define HV_MAP_GPA_VALID_MASK UINT32_C(0x7f1f) +/** @} */ + +/** Input for HvCallMapGpaPages. */ +typedef struct +{ + HV_PARTITION_ID TargetPartitionId; + HV_GPA_PAGE_NUMBER TargetGpaBase; + HV_MAP_GPA_FLAGS MapFlags; + uint32_t u32ExplicitPadding; + /* The repeating part: */ + RT_FLEXIBLE_ARRAY_EXTENSION + HV_SPA_PAGE_NUMBER PageList[RT_FLEXIBLE_ARRAY]; +} HV_INPUT_MAP_GPA_PAGES; +AssertCompileMemberOffset(HV_INPUT_MAP_GPA_PAGES, PageList, 24); +/** Pointer to the input for HvCallMapGpaPages. */ +typedef HV_INPUT_MAP_GPA_PAGES *PHV_INPUT_MAP_GPA_PAGES; + + +/** A parent to guest mapping pair for HvCallMapSparseGpaPages. */ +typedef struct +{ + HV_GPA_PAGE_NUMBER TargetGpaPageNumber; + HV_SPA_PAGE_NUMBER SourceSpaPageNumber; +} HV_GPA_MAPPING; +/** Pointer to a parent->guest mapping pair for HvCallMapSparseGpaPages. */ +typedef HV_GPA_MAPPING *PHV_GPA_MAPPING; + +/** Input for HvCallMapSparseGpaPages. */ +typedef struct +{ + HV_PARTITION_ID TargetPartitionId; + HV_MAP_GPA_FLAGS MapFlags; + uint32_t u32ExplicitPadding; + /* The repeating part: */ + RT_FLEXIBLE_ARRAY_EXTENSION + HV_GPA_MAPPING PageList[RT_FLEXIBLE_ARRAY]; +} HV_INPUT_MAP_SPARSE_GPA_PAGES; +AssertCompileMemberOffset(HV_INPUT_MAP_SPARSE_GPA_PAGES, PageList, 16); +/** Pointer to the input for HvCallMapSparseGpaPages. */ +typedef HV_INPUT_MAP_SPARSE_GPA_PAGES *PHV_INPUT_MAP_SPARSE_GPA_PAGES; + + +/** Input for HvCallUnmapGpaPages. */ +typedef struct +{ + HV_PARTITION_ID TargetPartitionId; + HV_GPA_PAGE_NUMBER TargetGpaBase; + /** This field is either an omission in the 7600 WDK or a later additions. + * Anyway, not quite sure what it does. Bit 2 seems to indicate 2MB pages. */ + uint64_t fFlags; +} HV_INPUT_UNMAP_GPA_PAGES; +AssertCompileSize(HV_INPUT_UNMAP_GPA_PAGES, 24); +/** Pointer to the input for HvCallUnmapGpaPages. */ +typedef HV_INPUT_UNMAP_GPA_PAGES *PHV_INPUT_UNMAP_GPA_PAGES; + + + +/** Cache types used by HvCallReadGpa and HvCallWriteGpa. */ +typedef enum +{ + HvCacheTypeX64Uncached = 0, + HvCacheTypeX64WriteCombining, + /* 2 & 3 are undefined. */ + HvCacheTypeX64WriteThrough = 4, + HvCacheTypeX64WriteProtected, + HvCacheTypeX64WriteBack +} HV_CACHE_TYPE; + +/** Control flags for HvCallReadGpa and HvCallWriteGpa. */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t CacheType : 8; /**< HV_CACHE_TYPE */ +#ifndef IN_IDA_PRO + uint64_t Reserved : 56; +#endif + }; +} HV_ACCESS_GPA_CONTROL_FLAGS; + +/** Results codes for HvCallReadGpa and HvCallWriteGpa. */ +typedef enum +{ + HvAccessGpaSuccess = 0, + HvAccessGpaUnmapped, + HvAccessGpaReadIntercept, + HvAccessGpaWriteIntercept, + HvAccessGpaIllegalOverlayAccess +} HV_ACCESS_GPA_RESULT_CODE; + +/** The result of HvCallReadGpa and HvCallWriteGpa. */ +typedef union +{ + uint64_t AsUINT64; + struct + { + HV_ACCESS_GPA_RESULT_CODE ResultCode; + uint32_t Reserved; + }; +} HV_ACCESS_GPA_RESULT; + + +/** Input for HvCallReadGpa. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_VP_INDEX VpIndex; + uint32_t ByteCount; + HV_GPA BaseGpa; + HV_ACCESS_GPA_CONTROL_FLAGS ControlFlags; +} HV_INPUT_READ_GPA; +AssertCompileSize(HV_INPUT_READ_GPA, 32); +/** Pointer to the input for HvCallReadGpa. */ +typedef HV_INPUT_READ_GPA *PHV_INPUT_READ_GPA; + +/** Output for HvCallReadGpa. */ +typedef struct +{ + HV_ACCESS_GPA_RESULT AccessResult; + uint8_t Data[16]; +} HV_OUTPUT_READ_GPA; +AssertCompileSize(HV_OUTPUT_READ_GPA, 24); +/** Pointer to the output for HvCallReadGpa. */ +typedef HV_OUTPUT_READ_GPA *PHV_OUTPUT_READ_GPA; + + +/** Input for HvCallWriteGpa. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_VP_INDEX VpIndex; + uint32_t ByteCount; + HV_GPA BaseGpa; + HV_ACCESS_GPA_CONTROL_FLAGS ControlFlags; + uint8_t Data[16]; +} HV_INPUT_WRITE_GPA; +AssertCompileSize(HV_INPUT_READ_GPA, 32); +/** Pointer to the input for HvCallWriteGpa. */ +typedef HV_INPUT_READ_GPA *PHV_INPUT_READ_GPA; + +/** Output for HvCallWriteGpa. */ +typedef struct +{ + HV_ACCESS_GPA_RESULT AccessResult; +} HV_OUTPUT_WRITE_GPA; +AssertCompileSize(HV_OUTPUT_WRITE_GPA, 8); +/** Pointer to the output for HvCallWriteGpa. */ +typedef HV_OUTPUT_WRITE_GPA *PHV_OUTPUT_WRITE_GPA; + + +/** + * Register names used by HvCallGetVpRegisters and HvCallSetVpRegisters. + */ +typedef enum _HV_REGISTER_NAME +{ + HvRegisterExplicitSuspend = 0x00000000, + HvRegisterInterceptSuspend, + HvRegisterUnknown02, /**< Reads as 0 initially on exo part. */ + HvRegisterUnknown03, /**< Reads as 0 initially on exo part. */ + HvRegisterInternalActivityState, /**< @since about build 17758 */ + + HvRegisterHypervisorVersion = 0x00000100, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterPrivilegesAndFeaturesInfo = 0x00000200, /**< @since v5 @note Not readable on exo part. */ + HvRegisterFeaturesInfo, /**< @since v5 @note Not readable on exo part. */ + HvRegisterImplementationLimitsInfo, /**< @since v5 @note Not readable on exo part. */ + HvRegisterHardwareFeaturesInfo, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterGuestCrashP0 = 0x00000210, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashP1, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashP2, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashP3, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashP4, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashCtl, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterPowerStateConfigC1 = 0x00000220, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateTriggerC1, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateConfigC2, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateTriggerC2, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateConfigC3, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateTriggerC3, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterSystemReset = 0x00000230, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterProcessorClockFrequency = 0x00000240, /**< @since v5 @note Not readable on exo part. */ + HvRegisterInterruptClockFrequency, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterGuestIdle = 0x00000250, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterDebugDeviceOptions = 0x00000260, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterPendingInterruption = 0x00010002, + HvRegisterInterruptState, + HvRegisterPendingEvent0, /**< @since v5 */ + HvRegisterPendingEvent1, /**< @since v5 */ + HvX64RegisterDeliverabilityNotifications, /**< @since v5c? Late 2017? */ + + HvX64RegisterRax = 0x00020000, + HvX64RegisterRcx, + HvX64RegisterRdx, + HvX64RegisterRbx, + HvX64RegisterRsp, + HvX64RegisterRbp, + HvX64RegisterRsi, + HvX64RegisterRdi, + HvX64RegisterR8, + HvX64RegisterR9, + HvX64RegisterR10, + HvX64RegisterR11, + HvX64RegisterR12, + HvX64RegisterR13, + HvX64RegisterR14, + HvX64RegisterR15, + HvX64RegisterRip, + HvX64RegisterRflags, + + HvX64RegisterXmm0 = 0x00030000, + HvX64RegisterXmm1, + HvX64RegisterXmm2, + HvX64RegisterXmm3, + HvX64RegisterXmm4, + HvX64RegisterXmm5, + HvX64RegisterXmm6, + HvX64RegisterXmm7, + HvX64RegisterXmm8, + HvX64RegisterXmm9, + HvX64RegisterXmm10, + HvX64RegisterXmm11, + HvX64RegisterXmm12, + HvX64RegisterXmm13, + HvX64RegisterXmm14, + HvX64RegisterXmm15, + HvX64RegisterFpMmx0, + HvX64RegisterFpMmx1, + HvX64RegisterFpMmx2, + HvX64RegisterFpMmx3, + HvX64RegisterFpMmx4, + HvX64RegisterFpMmx5, + HvX64RegisterFpMmx6, + HvX64RegisterFpMmx7, + HvX64RegisterFpControlStatus, + HvX64RegisterXmmControlStatus, + + HvX64RegisterCr0 = 0x00040000, + HvX64RegisterCr2, + HvX64RegisterCr3, + HvX64RegisterCr4, + HvX64RegisterCr8, + HvX64RegisterXfem, + + HvX64RegisterIntermediateCr0 = 0x00041000, /**< @since v5 */ + HvX64RegisterIntermediateCr4 = 0x00041003, /**< @since v5 */ + HvX64RegisterIntermediateCr8, /**< @since v5 */ + + HvX64RegisterDr0 = 0x00050000, + HvX64RegisterDr1, + HvX64RegisterDr2, + HvX64RegisterDr3, + HvX64RegisterDr6, + HvX64RegisterDr7, + + HvX64RegisterEs = 0x00060000, + HvX64RegisterCs, + HvX64RegisterSs, + HvX64RegisterDs, + HvX64RegisterFs, + HvX64RegisterGs, + HvX64RegisterLdtr, + HvX64RegisterTr, + + HvX64RegisterIdtr = 0x00070000, + HvX64RegisterGdtr, + + HvX64RegisterTsc = 0x00080000, + HvX64RegisterEfer, + HvX64RegisterKernelGsBase, + HvX64RegisterApicBase, + HvX64RegisterPat, + HvX64RegisterSysenterCs, + HvX64RegisterSysenterEip, + HvX64RegisterSysenterEsp, + HvX64RegisterStar, + HvX64RegisterLstar, + HvX64RegisterCstar, + HvX64RegisterSfmask, + HvX64RegisterInitialApicId, + + HvX64RegisterMtrrCap, /**< Not readable in exo partitions? */ + HvX64RegisterMtrrDefType, + + HvX64RegisterMtrrPhysBase0 = 0x00080010, + HvX64RegisterMtrrPhysBase1, + HvX64RegisterMtrrPhysBase2, + HvX64RegisterMtrrPhysBase3, + HvX64RegisterMtrrPhysBase4, + HvX64RegisterMtrrPhysBase5, + HvX64RegisterMtrrPhysBase6, + HvX64RegisterMtrrPhysBase7, + HvX64RegisterMtrrPhysBase8, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBase9, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseA, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseB, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseC, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseD, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseE, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseF, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + + HvX64RegisterMtrrPhysMask0 = 0x00080040, + HvX64RegisterMtrrPhysMask1, + HvX64RegisterMtrrPhysMask2, + HvX64RegisterMtrrPhysMask3, + HvX64RegisterMtrrPhysMask4, + HvX64RegisterMtrrPhysMask5, + HvX64RegisterMtrrPhysMask6, + HvX64RegisterMtrrPhysMask7, + HvX64RegisterMtrrPhysMask8, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMask9, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskA, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskB, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskC, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskD, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskE, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskF, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + + HvX64RegisterMtrrFix64k00000 = 0x00080070, + HvX64RegisterMtrrFix16k80000, + HvX64RegisterMtrrFix16kA0000, + HvX64RegisterMtrrFix4kC0000, + HvX64RegisterMtrrFix4kC8000, + HvX64RegisterMtrrFix4kD0000, + HvX64RegisterMtrrFix4kD8000, + HvX64RegisterMtrrFix4kE0000, + HvX64RegisterMtrrFix4kE8000, + HvX64RegisterMtrrFix4kF0000, + HvX64RegisterMtrrFix4kF8000, + HvX64RegisterTscAux, /**< @since v5c? late 2017? */ + + HvX64RegisterUnknown8007d = 0x0008007d, /**< Readable on exo partition (17134), initial value is zero. */ + + HvX64RegisterSpecCtrl = 0x00080084, /**< @since build about 17758 */ + HvX64RegisterPredCmd, /**< @since build about 17758 */ + + HvX64RegisterIa32MiscEnable = 0x000800a0, /**< @since v5 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterIa32FeatureControl, /**< @since v5 @note Appears not to be readable on exo partition (Threadripper). */ + + HvX64RegisterApicId = 0x00084802, /**< @since build 17758 */ + HvX64RegisterApicVersion, /**< @since build 17758 */ + + /** Uptime counter or some such thing. Unit is different than HvRegisterTimeRefCount or the accounting is different. */ + HvX64RegisterVpRuntime = 0x00090000, + HvX64RegisterHypercall, + HvRegisterGuestOsId, + HvRegisterVpIndex, + HvRegisterTimeRefCount, /**< Time counter since partition creation, 100ns units. */ + + HvRegisterCpuManagementVersion = 0x00090007, /**< @since v5 @note Appears not to be readable on exo partition. */ + + HvX64RegisterEoi = 0x00090010, /**< @note Appears not to be readable on exo partition. */ + HvX64RegisterIcr, /**< @note Appears not to be readable on exo partition. */ + HvX64RegisterTpr, /**< @note Appears not to be readable on exo partition. */ + HvRegisterVpAssistPage, + /** Readable on exo partition (17134). Some kind of counter. */ + HvRegisterUnknown90014, + + HvRegisterStatsPartitionRetail = 0x00090020, + HvRegisterStatsPartitionInternal, + HvRegisterStatsVpRetail, + HvRegisterStatsVpInternal, + + HvRegisterSint0 = 0x000a0000, + HvRegisterSint1, + HvRegisterSint2, + HvRegisterSint3, + HvRegisterSint4, + HvRegisterSint5, + HvRegisterSint6, + HvRegisterSint7, + HvRegisterSint8, + HvRegisterSint9, + HvRegisterSint10, + HvRegisterSint11, + HvRegisterSint12, + HvRegisterSint13, + HvRegisterSint14, + HvRegisterSint15, + HvRegisterScontrol, + HvRegisterSversion, + HvRegisterSifp, + HvRegisterSipp, + HvRegisterEom, + HvRegisterSirbp, /**< @since v4 */ + + HvRegisterStimer0Config = 0x000b0000, + HvRegisterStimer0Count, + HvRegisterStimer1Config, + HvRegisterStimer1Count, + HvRegisterStimer2Config, + HvRegisterStimer2Count, + HvRegisterStimer3Config, + HvRegisterStimer3Count, + + HvRegisterUnknown0b0100 = 0x000b0100, /**< Readable on exo partition (17134), initial value is zero. */ + HvRegisterUnknown0b0101, /**< Readable on exo partition (17134), initial value is zero. */ + + HvX64RegisterYmm0Low = 0x000c0000, /**< @note Not readable on exo partition. Need something enabled? */ + HvX64RegisterYmm1Low, + HvX64RegisterYmm2Low, + HvX64RegisterYmm3Low, + HvX64RegisterYmm4Low, + HvX64RegisterYmm5Low, + HvX64RegisterYmm6Low, + HvX64RegisterYmm7Low, + HvX64RegisterYmm8Low, + HvX64RegisterYmm9Low, + HvX64RegisterYmm10Low, + HvX64RegisterYmm11Low, + HvX64RegisterYmm12Low, + HvX64RegisterYmm13Low, + HvX64RegisterYmm14Low, + HvX64RegisterYmm15Low, + HvX64RegisterYmm0High, + HvX64RegisterYmm1High, + HvX64RegisterYmm2High, + HvX64RegisterYmm3High, + HvX64RegisterYmm4High, + HvX64RegisterYmm5High, + HvX64RegisterYmm6High, + HvX64RegisterYmm7High, + HvX64RegisterYmm8High, + HvX64RegisterYmm9High, + HvX64RegisterYmm10High, + HvX64RegisterYmm11High, + HvX64RegisterYmm12High, + HvX64RegisterYmm13High, + HvX64RegisterYmm14High, + HvX64RegisterYmm15High, + + HvRegisterVsmVpVtlControl = 0x000d0000, /**< @note Not readable on exo partition. */ + + HvRegisterVsmCodePageOffsets = 0x000d0002, + HvRegisterVsmVpStatus, + HvRegisterVsmPartitionStatus, + HvRegisterVsmVina, /**< @note Not readable on exo partition. */ + HvRegisterVsmCapabilities, + HvRegisterVsmPartitionConfig, /**< @note Not readable on exo partition. */ + + HvRegisterVsmVpSecureConfigVtl0 = 0x000d0010, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl1, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl2, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl3, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl4, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl5, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl6, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl7, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl8, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl9, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl10, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl11, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl12, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl13, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl14, /**< @since v5 */ + + HvRegisterUnknown0e0000 = 0x000e0000, /**< Readable on exo partition (17134), initial value zero. */ + HvRegisterUnknown0e0001, /**< Readable on exo partition (17134), initial value zero. */ + HvRegisterUnknown0e0002, /**< Readable on exo partition (17134), initial value zero. */ + HvRegisterUnknown0e0003 /**< Readable on exo partition (17134), initial value zero. */ +} HV_REGISTER_NAME; +AssertCompile(HvRegisterInterceptSuspend == 0x00000001); +AssertCompile(HvRegisterPendingEvent1 == 0x00010005); +AssertCompile(HvX64RegisterDeliverabilityNotifications == 0x00010006); +AssertCompile(HvX64RegisterRflags == 0x00020011); +AssertCompile(HvX64RegisterXmmControlStatus == 0x00030019); +AssertCompile(HvX64RegisterXfem == 0x00040005); +AssertCompile(HvX64RegisterIntermediateCr0 == 0x00041000); +AssertCompile(HvX64RegisterIntermediateCr4 == 0x00041003); +AssertCompile(HvX64RegisterDr7 == 0x00050005); +AssertCompile(HvX64RegisterTr == 0x00060007); +AssertCompile(HvX64RegisterGdtr == 0x00070001); +AssertCompile(HvX64RegisterInitialApicId == 0x0008000c); +AssertCompile(HvX64RegisterMtrrCap == 0x0008000d); +AssertCompile(HvX64RegisterMtrrDefType == 0x0008000e); +AssertCompile(HvX64RegisterMtrrPhysBaseF == 0x0008001f); +AssertCompile(HvX64RegisterMtrrPhysMaskF == 0x0008004f); +AssertCompile(HvX64RegisterMtrrFix4kF8000 == 0x0008007a); +AssertCompile(HvRegisterTimeRefCount == 0x00090004); +AssertCompile(HvRegisterCpuManagementVersion == 0x00090007); +AssertCompile(HvRegisterVpAssistPage == 0x00090013); +AssertCompile(HvRegisterStatsVpInternal == 0x00090023); +AssertCompile(HvRegisterSirbp == 0x000a0015); +AssertCompile(HvRegisterStimer3Count == 0x000b0007); +AssertCompile(HvX64RegisterYmm15High == 0x000c001f); +AssertCompile(HvRegisterVsmVpSecureConfigVtl14 == 0x000d001e); +AssertCompileSize(HV_REGISTER_NAME, 4); + + +/** Value format for HvRegisterExplicitSuspend. */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t Suspended : 1; +#ifndef IN_IDA_PRO + uint64_t Reserved : 63; +#endif + }; +} HV_EXPLICIT_SUSPEND_REGISTER; +/** Pointer to a value of HvRegisterExplicitSuspend. */ +typedef HV_EXPLICIT_SUSPEND_REGISTER *PHV_EXPLICIT_SUSPEND_REGISTER; + +/** Value format for HvRegisterInterceptSuspend. */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t Suspended : 1; + uint64_t TlbLocked : 1; +#ifndef IN_IDA_PRO + uint64_t Reserved : 62; +#endif + }; +} HV_INTERCEPT_SUSPEND_REGISTER; +/** Pointer to a value of HvRegisterInterceptSuspend. */ +typedef HV_INTERCEPT_SUSPEND_REGISTER *PHV_INTERCEPT_SUSPEND_REGISTER; + +/** Value format for HvRegisterInterruptState. + * @sa WHV_X64_INTERRUPT_STATE_REGISTER */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t InterruptShadow : 1; + uint64_t NmiMasked : 1; +#ifndef IN_IDA_PRO + uint64_t Reserved : 62; +#endif + }; +} HV_X64_INTERRUPT_STATE_REGISTER; +/** Pointer to a value of HvRegisterInterruptState. */ +typedef HV_X64_INTERRUPT_STATE_REGISTER *PHV_X64_INTERRUPT_STATE_REGISTER; + +/** Pending exception type for HvRegisterPendingInterruption. + * @sa WHV_X64_PENDING_INTERRUPTION_TYPE */ +typedef enum +{ + HvX64PendingInterrupt = 0, + /* what is/was 1? */ + HvX64PendingNmi = 2, + HvX64PendingException + /* any more? */ +} HV_X64_PENDING_INTERRUPTION_TYPE; + +/** Value format for HvRegisterPendingInterruption. + * @sa WHV_X64_PENDING_INTERRUPTION_REGISTER */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint32_t InterruptionPending : 1; + uint32_t InterruptionType : 3; /**< HV_X64_PENDING_INTERRUPTION_TYPE */ + uint32_t DeliverErrorCode : 1; + uint32_t InstructionLength : 4; /**< @since v5? Wasn't in 7600 WDK */ + uint32_t NestedEvent : 1; /**< @since v5? Wasn't in 7600 WDK */ + uint32_t Reserved : 6; + uint32_t InterruptionVector : 16; + uint32_t ErrorCode; + }; +} HV_X64_PENDING_INTERRUPTION_REGISTER; +/** Pointer to a value of HvRegisterPendingInterruption. */ +typedef HV_X64_PENDING_INTERRUPTION_REGISTER *PHV_X64_PENDING_INTERRUPTION_REGISTER; + +/** Value format for HvX64RegisterDeliverabilityNotifications. + * Value format for HvRegisterPendingEvent0/1. + * @sa WHV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t NmiNotification : 1; + uint64_t InterruptNotification : 1; + uint64_t InterruptPriority : 4; +#ifndef IN_IDA_PRO + uint64_t Reserved : 58; +#endif + }; +} HV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER; +/** Pointer to a value of HvRegisterPendingEvent0/1. */ +typedef HV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER *PHV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER; + + +/** Value format for HvX64RegisterEs..Tr. + * @sa WHV_X64_SEGMENT_REGISTER */ +typedef struct _HV_X64_SEGMENT_REGISTER +{ + uint64_t Base; + uint32_t Limit; + uint16_t Selector; + union + { + struct + { + uint16_t SegmentType : 4; + uint16_t NonSystemSegment : 1; + uint16_t DescriptorPrivilegeLevel : 2; + uint16_t Present : 1; + uint16_t Reserved : 4; + uint16_t Available : 1; + uint16_t Long : 1; + uint16_t Default : 1; + uint16_t Granularity : 1; + }; + uint16_t Attributes; + }; +} HV_X64_SEGMENT_REGISTER; +AssertCompileSize(HV_X64_SEGMENT_REGISTER, 16); +/** Pointer to a value of HvX64RegisterEs..Tr. */ +typedef HV_X64_SEGMENT_REGISTER *PHV_X64_SEGMENT_REGISTER; + +/** Value format for HvX64RegisterIdtr/Gdtr. + * @sa WHV_X64_TABLE_REGISTER */ +typedef struct +{ + uint16_t Pad[3]; + uint16_t Limit; + uint64_t Base; +} HV_X64_TABLE_REGISTER; +AssertCompileSize(HV_X64_TABLE_REGISTER, 16); +/** Pointer to a value of HvX64RegisterIdtr/Gdtrr. */ +typedef HV_X64_TABLE_REGISTER *PHV_X64_TABLE_REGISTER; + +/** Value format for HvX64RegisterFpMmx0..7 in floating pointer mode. + * @sa WHV_X64_FP_REGISTER, RTFLOAT80U2 */ +typedef union +{ + HV_UINT128 AsUINT128; + struct + { + uint64_t Mantissa; + uint64_t BiasedExponent : 15; + uint64_t Sign : 1; +#ifndef IN_IDA_PRO + uint64_t Reserved : 48; +#endif + }; +} HV_X64_FP_REGISTER; +/** Pointer to a value of HvX64RegisterFpMmx0..7 in floating point mode. */ +typedef HV_X64_FP_REGISTER *PHV_X64_FP_REGISTER; + +/** Value union for HvX64RegisterFpMmx0..7. */ +typedef union +{ + HV_UINT128 AsUINT128; + HV_X64_FP_REGISTER Fp; + uint64_t Mmx; +} HV_X64_FP_MMX_REGISTER; +/** Pointer to a value of HvX64RegisterFpMmx0..7. */ +typedef HV_X64_FP_MMX_REGISTER *PHV_X64_FP_MMX_REGISTER; + +/** Value format for HvX64RegisterFpControlStatus. + * @sa WHV_X64_FP_CONTROL_STATUS_REGISTER */ +typedef union +{ + HV_UINT128 AsUINT128; + struct + { + uint16_t FpControl; + uint16_t FpStatus; + uint8_t FpTag; + uint8_t IgnNe : 1; + uint8_t Reserved : 7; + uint16_t LastFpOp; + union + { + uint64_t LastFpRip; + struct + { + uint32_t LastFpEip; + uint16_t LastFpCs; + }; + }; + }; +} HV_X64_FP_CONTROL_STATUS_REGISTER; +/** Pointer to a value of HvX64RegisterFpControlStatus. */ +typedef HV_X64_FP_CONTROL_STATUS_REGISTER *PHV_X64_FP_CONTROL_STATUS_REGISTER; + +/** Value format for HvX64RegisterXmmControlStatus. + * @sa WHV_X64_XMM_CONTROL_STATUS_REGISTER */ +typedef union +{ + HV_UINT128 AsUINT128; + struct + { + union + { + uint64_t LastFpRdp; + struct + { + uint32_t LastFpDp; + uint16_t LastFpDs; + }; + }; + uint32_t XmmStatusControl; + uint32_t XmmStatusControlMask; + }; +} HV_X64_XMM_CONTROL_STATUS_REGISTER; +/** Pointer to a value of HvX64RegisterXmmControlStatus. */ +typedef HV_X64_XMM_CONTROL_STATUS_REGISTER *PHV_X64_XMM_CONTROL_STATUS_REGISTER; + +/** Register value union. + * @sa WHV_REGISTER_VALUE */ +typedef union +{ + HV_UINT128 Reg128; + uint64_t Reg64; + uint32_t Reg32; + uint16_t Reg16; + uint8_t Reg8; + HV_EXPLICIT_SUSPEND_REGISTER ExplicitSuspend; + HV_INTERCEPT_SUSPEND_REGISTER InterceptSuspend; + HV_X64_INTERRUPT_STATE_REGISTER InterruptState; + HV_X64_PENDING_INTERRUPTION_REGISTER PendingInterruption; + HV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER DeliverabilityNotifications; + HV_X64_TABLE_REGISTER Table; + HV_X64_SEGMENT_REGISTER Segment; + HV_X64_FP_REGISTER Fp; + HV_X64_FP_CONTROL_STATUS_REGISTER FpControlStatus; + HV_X64_XMM_CONTROL_STATUS_REGISTER XmmControlStatus; +} HV_REGISTER_VALUE; +AssertCompileSize(HV_REGISTER_VALUE, 16); +/** Pointer to a Hyper-V register value union. */ +typedef HV_REGISTER_VALUE *PHV_REGISTER_VALUE; +/** Pointer to a const Hyper-V register value union. */ +typedef HV_REGISTER_VALUE const *PCHV_REGISTER_VALUE; + + +/** Input for HvCallGetVpRegisters. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_VP_INDEX VpIndex; + /** Was this introduced after v2? Dunno what it it really is. */ + uint32_t fFlags; + /* The repeating part: */ + RT_FLEXIBLE_ARRAY_EXTENSION + HV_REGISTER_NAME Names[RT_FLEXIBLE_ARRAY]; +} HV_INPUT_GET_VP_REGISTERS; +AssertCompileMemberOffset(HV_INPUT_GET_VP_REGISTERS, Names, 16); +/** Pointer to input for HvCallGetVpRegisters. */ +typedef HV_INPUT_GET_VP_REGISTERS *PHV_INPUT_GET_VP_REGISTERS; +/* Output for HvCallGetVpRegisters is an array of HV_REGISTER_VALUE parallel to HV_INPUT_GET_VP_REGISTERS::Names. */ + + +/** Register and value pair for HvCallSetVpRegisters. */ +typedef struct +{ + HV_REGISTER_NAME Name; + uint32_t Pad0; + uint64_t Pad1; + HV_REGISTER_VALUE Value; +} HV_REGISTER_ASSOC; +AssertCompileSize(HV_REGISTER_ASSOC, 32); +AssertCompileMemberOffset(HV_REGISTER_ASSOC, Value, 16); +/** Pointer to a register and value pair for HvCallSetVpRegisters. */ +typedef HV_REGISTER_ASSOC *PHV_REGISTER_ASSOC; +/** Helper for clearing the alignment padding members. */ +#define HV_REGISTER_ASSOC_ZERO_PADDING(a_pRegAssoc) do { (a_pRegAssoc)->Pad0 = 0; (a_pRegAssoc)->Pad1 = 0; } while (0) +/** Helper for clearing the alignment padding members and the high 64-bit + * part of the value. */ +#define HV_REGISTER_ASSOC_ZERO_PADDING_AND_HI64(a_pRegAssoc) \ + do { (a_pRegAssoc)->Pad0 = 0; (a_pRegAssoc)->Pad1 = 0; (a_pRegAssoc)->Value.Reg128.High64 = 0; } while (0) + +/** Input for HvCallSetVpRegisters. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_VP_INDEX VpIndex; + uint32_t RsvdZ; + /* The repeating part: */ + RT_FLEXIBLE_ARRAY_EXTENSION + HV_REGISTER_ASSOC Elements[RT_FLEXIBLE_ARRAY]; +} HV_INPUT_SET_VP_REGISTERS; +AssertCompileMemberOffset(HV_INPUT_SET_VP_REGISTERS, Elements, 16); +/** Pointer to input for HvCallSetVpRegisters. */ +typedef HV_INPUT_SET_VP_REGISTERS *PHV_INPUT_SET_VP_REGISTERS; + + + +/** + * Hyper-V SyncIC message types. + */ +typedef enum +{ + HvMessageTypeNone = 0x00000000, + + HvMessageTypeUnmappedGpa = 0x80000000, + HvMessageTypeGpaIntercept, + + HvMessageTimerExpired = 0x80000010, + + HvMessageTypeInvalidVpRegisterValue = 0x80000020, + HvMessageTypeUnrecoverableException, + HvMessageTypeUnsupportedFeature, + HvMessageTypeTlbPageSizeMismatch, /**< @since v5 */ + + /** @note Same as HvMessageTypeX64ApicEoi? Gone in 5.0. Missing from 7600 WDK + * headers even if it's in the 2.0 docs. */ + HvMessageTypeApicEoi = 0x80000030, + /** @note Same as HvMessageTypeX64LegacyFpError? Gone in 5.0, whereas 4.0b + * calls it HvMessageTypeX64LegacyFpError. Missing from 7600 WDK + * headers even if it's in the 2.0 docs. */ + HvMessageTypeFerrAsserted, + + HvMessageTypeEventLogBufferComplete = 0x80000040, + + HvMessageTypeX64IoPortIntercept = 0x80010000, + HvMessageTypeX64MsrIntercept, + HvMessageTypeX64CpuidIntercept, + HvMessageTypeX64ExceptionIntercept, + /** @note Appeared in 5.0 docs, but were here in 7600 WDK headers already. */ + HvMessageTypeX64ApicEoi, + /** @note Appeared in 5.0 docs, but were here in 7600 WDK headers already. */ + HvMessageTypeX64LegacyFpError, + /** @since v5 */ + HvMessageTypeX64RegisterIntercept, + /** @since WinHvPlatform? */ + HvMessageTypeX64Halt, + /** @since WinHvPlatform? */ + HvMessageTypeX64InterruptWindow + +} HV_MESSAGE_TYPE; +AssertCompileSize(HV_MESSAGE_TYPE, 4); +AssertCompile(HvMessageTypeX64RegisterIntercept == 0x80010006); +AssertCompile(HvMessageTypeX64Halt == 0x80010007); +AssertCompile(HvMessageTypeX64InterruptWindow == 0x80010008); +/** Pointer to a Hyper-V SyncIC message type. */ +typedef HV_MESSAGE_TYPE *PHV_MESSAGE_TYPE; + +/** Flag set for hypervisor messages, guest cannot send messages with this + * flag set. */ +#define HV_MESSAGE_TYPE_HYPERVISOR_MASK UINT32_C(0x80000000) + +/** Hyper-V SynIC message size (they are fixed sized). */ +#define HV_MESSAGE_SIZE 256 +/** Maximum Hyper-V SynIC message payload size in bytes. */ +#define HV_MESSAGE_MAX_PAYLOAD_BYTE_COUNT (HV_MESSAGE_SIZE - 16) +/** Maximum Hyper-V SynIC message payload size in QWORDs (uint64_t). */ +#define HV_MESSAGE_MAX_PAYLOAD_QWORD_COUNT (HV_MESSAGE_MAX_PAYLOAD_BYTE_COUNT / 8) + +/** SynIC message flags. */ +typedef union +{ + uint8_t AsUINT8; + struct + { + /** Messages are pending in the queue. */ + uint8_t MessagePending : 1; + uint8_t Reserved : 7; + }; +} HV_MESSAGE_FLAGS; +AssertCompileSize(HV_MESSAGE_FLAGS, 1); + +/** SynIC message header. */ +typedef struct +{ + HV_MESSAGE_TYPE MessageType; + /** The 2.0-5.0b docs all have this incorrectly switched with 'Reserved', WDK 7600 got it right. */ + uint8_t PayloadSize; + HV_MESSAGE_FLAGS MessageFlags; + uint16_t Reserved; + union + { + uint64_t OriginationId; + HV_PARTITION_ID Sender; + HV_PORT_ID Port; + }; +} HV_MESSAGE_HEADER; +AssertCompileSize(HV_MESSAGE_HEADER, 16); +/** Pointer to a Hyper-V message header. */ +typedef HV_MESSAGE_HEADER *PHV_MESSAGE_HEADER; +/** Pointer to a const Hyper-V message header. */ +typedef HV_MESSAGE_HEADER const *PCHV_MESSAGE_HEADER; + + + +/** @name Intercept access type. + * @{ */ +typedef uint8_t HV_INTERCEPT_ACCESS_TYPE; +#define HV_INTERCEPT_ACCESS_READ 0 +#define HV_INTERCEPT_ACCESS_WRITE 1 +#define HV_INTERCEPT_ACCESS_EXECUTE 2 +/** @} */ + +/** @name Intercept access type mask. + * @{ */ +typedef uint32_t HV_INTERCEPT_ACCESS_TYPE_MASK; +#define HV_INTERCEPT_ACCESS_MASK_NONE 0 +#define HV_INTERCEPT_ACCESS_MASK_READ 1 +#define HV_INTERCEPT_ACCESS_MASK_WRITE 2 +#define HV_INTERCEPT_ACCESS_MASK_EXECUTE 4 +/** @} */ + +/** X64 intercept execution state. + * @sa WHV_X64_VP_EXECUTION_STATE */ +typedef union +{ + uint16_t AsUINT16; + struct + { + uint16_t Cpl : 2; + uint16_t Cr0Pe : 1; + uint16_t Cr0Am : 1; + uint16_t EferLma : 1; + uint16_t DebugActive : 1; + uint16_t InterruptionPending : 1; + uint16_t Reserved0 : 5; + uint16_t InterruptShadow : 1; + uint16_t Reserved1 : 3; + }; +} HV_X64_VP_EXECUTION_STATE; +AssertCompileSize(HV_X64_VP_EXECUTION_STATE, 2); +/** Pointer to X86 intercept execution state. */ +typedef HV_X64_VP_EXECUTION_STATE *PHV_X64_VP_EXECUTION_STATE; +/** Pointer to const X86 intercept execution state. */ +typedef HV_X64_VP_EXECUTION_STATE const *PCHV_X64_VP_EXECUTION_STATE; + +/** X64 intercept message header. */ +typedef struct +{ + HV_VP_INDEX VpIndex; /**< 0x00 */ + uint8_t InstructionLength : 4; /**< 0x04[3:0]: Zero if not available, instruction fetch exit, ... */ + uint8_t Cr8 : 4; /**< 0x04[7:4]: Not sure since when, but after v2. */ + HV_INTERCEPT_ACCESS_TYPE InterceptAccessType; /**< 0x05 */ + HV_X64_VP_EXECUTION_STATE ExecutionState; /**< 0x06 */ + HV_X64_SEGMENT_REGISTER CsSegment; /**< 0x08 */ + uint64_t Rip; /**< 0x18 */ + uint64_t Rflags; /**< 0x20 */ +} HV_X64_INTERCEPT_MESSAGE_HEADER; +AssertCompileSize(HV_X64_INTERCEPT_MESSAGE_HEADER, 40); +/** Pointer to a x86 intercept message header. */ +typedef HV_X64_INTERCEPT_MESSAGE_HEADER *PHV_X64_INTERCEPT_MESSAGE_HEADER; + + +/** X64 memory access flags (HvMessageTypeGpaIntercept, HvMessageTypeUnmappedGpa). + * @sa WHV_MEMORY_ACCESS_INFO */ +typedef union +{ + uint8_t AsUINT8; + struct + { + uint8_t GvaValid : 1; + uint8_t Reserved : 7; + }; +} HV_X64_MEMORY_ACCESS_INFO; +AssertCompileSize(HV_X64_MEMORY_ACCESS_INFO, 1); + +/** The payload format for HvMessageTypeGpaIntercept and HvMessageTypeUnmappedGpa. + * @sa WHV_MEMORY_ACCESS_CONTEXT + * @note max message size. */ +typedef struct +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00 */ + HV_CACHE_TYPE CacheType; /**< 0x28 */ + uint8_t InstructionByteCount; /**< 0x2c */ + HV_X64_MEMORY_ACCESS_INFO MemoryAccessInfo; /**< 0x2d */ + uint16_t Reserved1; /**< 0x2e */ + uint64_t GuestVirtualAddress; /**< 0x30 */ + uint64_t GuestPhysicalAddress; /**< 0x38 */ + uint8_t InstructionBytes[16]; /**< 0x40 */ + /* We don't the following (v5 / WinHvPlatform): */ + HV_X64_SEGMENT_REGISTER DsSegment; /**< 0x50 */ + HV_X64_SEGMENT_REGISTER SsSegment; /**< 0x60 */ + uint64_t Rax; /**< 0x70 */ + uint64_t Rcx; /**< 0x78 */ + uint64_t Rdx; /**< 0x80 */ + uint64_t Rbx; /**< 0x88 */ + uint64_t Rsp; /**< 0x90 */ + uint64_t Rbp; /**< 0x98 */ + uint64_t Rsi; /**< 0xa0 */ + uint64_t Rdi; /**< 0xa8 */ + uint64_t R8; /**< 0xb0 */ + uint64_t R9; /**< 0xb8 */ + uint64_t R10; /**< 0xc0 */ + uint64_t R11; /**< 0xc8 */ + uint64_t R12; /**< 0xd0 */ + uint64_t R13; /**< 0xd8 */ + uint64_t R14; /**< 0xe0 */ + uint64_t R15; /**< 0xe8 */ +} HV_X64_MEMORY_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_MEMORY_INTERCEPT_MESSAGE, 0xf0); +AssertCompileMemberOffset(HV_X64_MEMORY_INTERCEPT_MESSAGE, DsSegment, 0x50); +/** Pointer to a HvMessageTypeGpaIntercept or HvMessageTypeUnmappedGpa payload. */ +typedef HV_X64_MEMORY_INTERCEPT_MESSAGE *PHV_X64_MEMORY_INTERCEPT_MESSAGE; +/** Pointer to a const HvMessageTypeGpaIntercept or HvMessageTypeUnmappedGpa payload. */ +typedef HV_X64_MEMORY_INTERCEPT_MESSAGE const *PCHV_X64_MEMORY_INTERCEPT_MESSAGE; + + +/** The payload format for HvMessageTypeX64MsrIntercept. */ +typedef struct _HV_X64_MSR_INTERCEPT_MESSAGE +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00 */ + uint32_t MsrNumber; /**< 0x28 (ecx) */ + uint32_t Reserved; /**< 0x2c */ + uint64_t Rdx; /**< 0x30 */ + uint64_t Rax; /**< 0x38 */ +} HV_X64_MSR_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_MSR_INTERCEPT_MESSAGE, 0x40); +/** Pointer to a HvMessageTypeX64MsrIntercept payload. */ +typedef HV_X64_MSR_INTERCEPT_MESSAGE *PHV_X64_MSR_INTERCEPT_MESSAGE; +/** Pointer to a const HvMessageTypeX64MsrIntercept payload. */ +typedef HV_X64_MSR_INTERCEPT_MESSAGE const *PCHV_X64_MSR_INTERCEPT_MESSAGE; + +/** Full MSR message. */ +typedef struct +{ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_MSR_INTERCEPT_MESSAGE Payload; +} HV_X64_MSR_INTERCEPT_MESSAGE_FULL; + + +/** X64 I/O port access information (HvMessageTypeX64IoPortIntercept). */ +typedef union HV_X64_IO_PORT_ACCESS_INFO +{ + uint8_t AsUINT8; + struct + { + uint8_t AccessSize : 3; + uint8_t StringOp : 1; + uint8_t RepPrefix : 1; + uint8_t Reserved : 3; + }; +} HV_X64_IO_PORT_ACCESS_INFO; +AssertCompileSize(HV_X64_IO_PORT_ACCESS_INFO, 1); + +/** The payload format for HvMessageTypeX64IoPortIntercept. */ +typedef struct _HV_X64_IO_PORT_INTERCEPT_MESSAGE +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00 */ + uint16_t PortNumber; /**< 0x28 */ + HV_X64_IO_PORT_ACCESS_INFO AccessInfo; /**< 0x2a */ + uint8_t InstructionByteCount; /**< 0x2b */ + uint32_t Reserved; /**< 0x2c */ + uint64_t Rax; /**< 0x30 */ + uint8_t InstructionBytes[16]; /**< 0x38 */ + HV_X64_SEGMENT_REGISTER DsSegment; /**< 0x48 */ + HV_X64_SEGMENT_REGISTER EsSegment; /**< 0x58 */ + uint64_t Rcx; /**< 0x68 */ + uint64_t Rsi; /**< 0x70 */ + uint64_t Rdi; /**< 0x78 */ +} HV_X64_IO_PORT_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_IO_PORT_INTERCEPT_MESSAGE, 128); +/** Pointer to a HvMessageTypeX64IoPortIntercept payload. */ +typedef HV_X64_IO_PORT_INTERCEPT_MESSAGE *PHV_X64_IO_PORT_INTERCEPT_MESSAGE; +/** Pointer to a const HvMessageTypeX64IoPortIntercept payload. */ +typedef HV_X64_IO_PORT_INTERCEPT_MESSAGE const *PCHV_X64_IO_PORT_INTERCEPT_MESSAGE; + +/** Full I/O port message. */ +typedef struct +{ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_IO_PORT_INTERCEPT_MESSAGE Payload; +} HV_X64_IO_PORT_INTERCEPT_MESSAGE_FULL; + + +/** + * The payload format for HvMessageTypeX64CpuidIntercept, + * + * @note This message does not include HV_X64_INTERCEPT_MESSAGE_HEADER! + */ +typedef struct +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00: The usual intercept header. */ + uint64_t Rax; /**< 0x28: Input RAX. */ + uint64_t Rcx; /**< 0x30: Input RCX. */ + uint64_t Rdx; /**< 0x38: Input RDX. */ + uint64_t Rbx; /**< 0x40: Input RBX. */ + uint64_t DefaultResultRax; /**< 0x48: Default result RAX. */ + uint64_t DefaultResultRcx; /**< 0x50: Default result RCX. */ + uint64_t DefaultResultRdx; /**< 0x58: Default result RDX. */ + uint64_t DefaultResultRbx; /**< 0x60: Default result RBX. */ +} HV_X64_CPUID_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_CPUID_INTERCEPT_MESSAGE, 0x68); +/** Pointer to a HvMessageTypeX64CpuidIntercept payload. */ +typedef HV_X64_CPUID_INTERCEPT_MESSAGE *PHV_X64_CPUID_INTERCEPT_MESSAGE; +/** Pointer to a const HvMessageTypeX64CpuidIntercept payload. */ +typedef HV_X64_CPUID_INTERCEPT_MESSAGE const *PCHV_X64_CPUID_INTERCEPT_MESSAGE; + +/** Full HvMessageTypeX64CpuidIntercept message. */ +typedef struct +{ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_CPUID_INTERCEPT_MESSAGE Payload; +} HV_X64_CPUID_INTERCEPT_MESSAGE_FULL; + + +/** X64 exception information (HvMessageTypeX64ExceptionIntercept). + * @sa WHV_VP_EXCEPTION_INFO */ +typedef union +{ + uint8_t AsUINT8; + struct + { + uint8_t ErrorCodeValid : 1; + /** @todo WHV_VP_EXCEPTION_INFO::SoftwareException */ + uint8_t Reserved : 7; + }; +} HV_X64_EXCEPTION_INFO; +AssertCompileSize(HV_X64_EXCEPTION_INFO, 1); + +/** The payload format for HvMessageTypeX64ExceptionIntercept. + * @sa WHV_VP_EXCEPTION_CONTEXT + * @note max message size. */ +typedef struct +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00 */ + uint16_t ExceptionVector; /**< 0x28 */ + HV_X64_EXCEPTION_INFO ExceptionInfo; /**< 0x2a */ + uint8_t InstructionByteCount; /**< 0x2b */ + uint32_t ErrorCode; /**< 0x2c */ + uint64_t ExceptionParameter; /**< 0x30 */ + uint64_t Reserved; /**< 0x38 */ + uint8_t InstructionBytes[16]; /**< 0x40 */ + HV_X64_SEGMENT_REGISTER DsSegment; /**< 0x50 */ + HV_X64_SEGMENT_REGISTER SsSegment; /**< 0x60 */ + uint64_t Rax; /**< 0x70 */ + uint64_t Rcx; /**< 0x78 */ + uint64_t Rdx; /**< 0x80 */ + uint64_t Rbx; /**< 0x88 */ + uint64_t Rsp; /**< 0x90 */ + uint64_t Rbp; /**< 0x98 */ + uint64_t Rsi; /**< 0xa0 */ + uint64_t Rdi; /**< 0xa8 */ + uint64_t R8; /**< 0xb0 */ + uint64_t R9; /**< 0xb8 */ + uint64_t R10; /**< 0xc0 */ + uint64_t R11; /**< 0xc8 */ + uint64_t R12; /**< 0xd0 */ + uint64_t R13; /**< 0xd8 */ + uint64_t R14; /**< 0xe0 */ + uint64_t R15; /**< 0xe8 */ +} HV_X64_EXCEPTION_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_EXCEPTION_INTERCEPT_MESSAGE, 0xf0); +/** Pointer to a HvMessageTypeX64ExceptionIntercept payload. */ +typedef HV_X64_EXCEPTION_INTERCEPT_MESSAGE *PHV_X64_EXCEPTION_INTERCEPT_MESSAGE; +/** Pointer to a ocnst HvMessageTypeX64ExceptionIntercept payload. */ +typedef HV_X64_EXCEPTION_INTERCEPT_MESSAGE const *PCHV_X64_EXCEPTION_INTERCEPT_MESSAGE; + + +/** + * The payload format for HvMessageTypeX64Halt, + * + * @note This message does not include HV_X64_INTERCEPT_MESSAGE_HEADER! + */ +typedef struct +{ + /** Seems to be a zero 64-bit field here. */ + uint64_t u64Reserved; +} HV_X64_HALT_MESSAGE; +/** Pointer to a HvMessageTypeX64Halt payload. */ +typedef HV_X64_HALT_MESSAGE *PHV_X64_HALT_MESSAGE; +/** Pointer to a const HvMessageTypeX64Halt payload. */ +typedef HV_X64_HALT_MESSAGE const *PCHV_X64_HALT_MESSAGE; + +/** Full HvMessageTypeX64Halt message. */ +typedef struct +{ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_HALT_MESSAGE Payload; +} HV_X64_HALT_MESSAGE_FULL; + + +/** + * The payload format for HvMessageTypeX64InterruptWindow, + * + * @note This message does not include HV_X64_INTERCEPT_MESSAGE_HEADER! + */ +typedef struct +{ + /** 0x00: The usual intercept header. */ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; + /** 0x28: What's pending. */ + HV_X64_PENDING_INTERRUPTION_TYPE Type; + /** 0x2c: Explicit structure alignment padding. */ + uint32_t u32ExplicitPadding; +} HV_X64_INTERRUPT_WINDOW_MESSAGE; +AssertCompileSize(HV_X64_INTERRUPT_WINDOW_MESSAGE, 0x30); +/** Pointer to a HvMessageTypeX64InterruptWindow payload. */ +typedef HV_X64_INTERRUPT_WINDOW_MESSAGE *PHV_X64_INTERRUPT_WINDOW_MESSAGE; +/** Pointer to a const HvMessageTypeX64InterruptWindow payload. */ +typedef HV_X64_INTERRUPT_WINDOW_MESSAGE const *PCHV_X64_INTERRUPT_WINDOW_MESSAGE; + +/** Full HvMessageTypeX64InterruptWindow message. */ +typedef struct +{ + /** Payload size is 0x30. */ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_INTERRUPT_WINDOW_MESSAGE Payload; +} HV_X64_INTERRUPT_WINDOW_MESSAGE_FULL; + + + +/** Hyper-V SynIC message. */ +typedef struct +{ + HV_MESSAGE_HEADER Header; + /** 0x10 */ + union + { + uint64_t Payload[HV_MESSAGE_MAX_PAYLOAD_QWORD_COUNT]; + + /** Common header for X64 intercept messages. + * The HvMessageTypeUnrecoverableException message only has this. */ + HV_X64_INTERCEPT_MESSAGE_HEADER X64InterceptHeader; + /** HvMessageTypeGpaIntercept, HvMessageTypeUnmappedGpa. */ + HV_X64_MEMORY_INTERCEPT_MESSAGE X64MemoryIntercept; + /** HvMessageTypeX64IoPortIntercept */ + HV_X64_IO_PORT_INTERCEPT_MESSAGE X64IoPortIntercept; + /** HvMessageTypeX64MsrIntercept */ + HV_X64_MSR_INTERCEPT_MESSAGE X64MsrIntercept; + /** HvMessageTypeX64CpuidIntercept */ + HV_X64_CPUID_INTERCEPT_MESSAGE X64CpuIdIntercept; + /** HvMessageTypeX64ExceptionIntercept */ + HV_X64_EXCEPTION_INTERCEPT_MESSAGE X64ExceptionIntercept; + /** HvMessageTypeX64Halt. + * @note No intercept header? */ + HV_X64_HALT_MESSAGE X64Halt; + /** HvMessageTypeX64InterruptWindow. */ + HV_X64_INTERRUPT_WINDOW_MESSAGE X64InterruptWindow; + }; +} HV_MESSAGE; +AssertCompileSize(HV_MESSAGE, HV_MESSAGE_SIZE); +/** Pointer to a Hyper-V SynIC message. */ +typedef HV_MESSAGE *PHV_MESSAGE; +/** Pointer to const a Hyper-V SynIC message. */ +typedef HV_MESSAGE const *PCHV_MESSAGE; + +#endif /* !IPRT_INCLUDED_nt_hyperv_h */ + diff --git a/include/iprt/nt/miniport.h b/include/iprt/nt/miniport.h new file mode 100644 index 00000000..0525e306 --- /dev/null +++ b/include/iprt/nt/miniport.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include miniport.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_miniport_h +#define IPRT_INCLUDED_nt_miniport_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* basetsd.h(114) : warning C4668: '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +RT_C_DECLS_BEGIN +#include +RT_C_DECLS_END + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_miniport_h */ + diff --git a/include/iprt/nt/ndis.h b/include/iprt/nt/ndis.h new file mode 100644 index 00000000..e8263edb --- /dev/null +++ b/include/iprt/nt/ndis.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include ndis.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_ndis_h +#define IPRT_INCLUDED_nt_ndis_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'NDIS_WRAPPER' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +RT_C_DECLS_BEGIN +#include +RT_C_DECLS_END + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_ndis_h */ + diff --git a/include/iprt/nt/nt-and-windows.h b/include/iprt/nt/nt-and-windows.h new file mode 100644 index 00000000..e5bbbaff --- /dev/null +++ b/include/iprt/nt/nt-and-windows.h @@ -0,0 +1,68 @@ +/* $Id: nt-and-windows.h $ */ +/** @file + * IPRT - Header for code using both NT native and Windows APIs. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_nt_and_windows_h +#define IPRT_INCLUDED_nt_nt_and_windows_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define _PEB IncompleteWindows__PEB +#define PEB IncompleteWindows_PEB +#define PPEB IncompleteWindows_PPEB + +#define _TEB IncompleteWindows__TEB +#define TEB IncompleteWindows_TEB +#define PTEB IncompleteWindows_PTEB + +#define IPRT_NT_USE_WINTERNL +#define IPRT_NT_HAVE_CURRENT_TEB_MACRO +#define WIN32_NO_STATUS +#include +#undef WIN32_NO_STATUS + +#undef _PEB +#undef PEB +#undef PPEB + +#undef _TEB +#undef TEB +#undef PTEB + +#include + +#endif /* !IPRT_INCLUDED_nt_nt_and_windows_h */ + diff --git a/include/iprt/nt/nt-structures.h b/include/iprt/nt/nt-structures.h new file mode 100644 index 00000000..fbf83f0a --- /dev/null +++ b/include/iprt/nt/nt-structures.h @@ -0,0 +1,146 @@ +/* $Id: nt-structures.h $ */ +/** @file + * IPRT - Header for NT structures. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_nt_structures_h +#define IPRT_INCLUDED_nt_nt_structures_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include + + +/** @name NT Kernel Structures + * @{ */ +typedef struct KTRAP_FRAME_AMD64 +{ + uint64_t P1Home; /**< 0x00 */ + uint64_t P2Home; /**< 0x08 */ + uint64_t P3Home; /**< 0x10 */ + uint64_t P4Home; /**< 0x18 */ + uint64_t P5; /**< 0x20 */ + uint8_t PreviousMode; /**< 0x28: KPROCESSOR_MODE / MODE - unused? */ + uint8_t PreviousIrql; /**< 0x29: KIRQL - Interrupts? */ + uint8_t FaultIndicator; /**< 0x2a: Holds (ErrCd >> 1) & 9) for \#PF. */ + uint8_t ExceptionActive; /**< 0x2b: 0 if interrupt, 1 if exception, 2 if service call, */ + uint32_t MxCsr; /**< 0x2c */ + /** @name Volatile general register state. Only saved on interrupts and exceptions. + * @{ */ + uint64_t Rax; /**< 0x30 */ + uint64_t Rcx; /**< 0x38 */ + uint64_t Rdx; /**< 0x40 */ + uint64_t R8; /**< 0x48 */ + uint64_t R9; /**< 0x50 */ + uint64_t R10; /**< 0x58 */ + uint64_t R11; /**< 0x60 */ + /** @} */ + uint64_t GsBaseOrSwap; /**< 0x68: GsBase if previous mode is kernel, GsSwap if pervious mode was user. */ + /** @name Volatile SSE state. Only saved on interrupts and exceptions. + * @{ */ + RTUINT128U Xmm0; /**< 0x70 */ + RTUINT128U Xmm1; /**< 0x80: RBP points here. */ + RTUINT128U Xmm2; /**< 0x90 */ + RTUINT128U Xmm3; /**< 0xa0 */ + RTUINT128U Xmm4; /**< 0xb0 */ + RTUINT128U Xmm5; /**< 0xc0 */ + /** @} */ + uint64_t FaultAddrOrCtxRecOrTS; /**< 0xd0: Used to save CR2 in \#PF and NMI handlers. */ + /** @name Usermode debug state. + * @{ */ + uint64_t Dr0; /**< 0xd8: Only if DR7 indicates active. */ + uint64_t Dr1; /**< 0xe0: Only if DR7 indicates active. */ + uint64_t Dr2; /**< 0xe8: Only if DR7 indicates active. */ + uint64_t Dr3; /**< 0xf0: Only if DR7 indicates active. */ + uint64_t Dr6; /**< 0xf8: Only if DR7 indicates active. */ + uint64_t Dr7; /**< 0x100: Considered active any of these bits are set: + X86_DR7_LE_ALL | X86_DR7_LE | X86_DR7_GE. */ + union + { + struct + { + uint64_t LastBranchControl; /**< 0x108 */ + uint32_t LastBranchMSR; /**< 0x110 */ + } amd; + struct + { + uint64_t DebugControl; /**< 0x108 */ + uint64_t LastBranchToRip; /**< 0x110 */ + uint64_t LastBranchFromRip; /**< 0x118 */ + uint64_t LastExceptionToRip; /**< 0x120 */ + uint64_t LastExceptionFromRip; /**< 0x128 */ + } intel; + } u; + /** @} */ + /** @name Segment registers. Not sure when these would actually be used. + * @{ */ + uint16_t SegDs; /**< 0x130 */ + uint16_t SegEs; /**< 0x132 */ + uint16_t SegFs; /**< 0x134 */ + uint16_t SegGs; /**< 0x136 */ + /** @} */ + uint64_t TrapFrame; /**< 0x138 */ + /** @name Some non-volatile registers only saved in service calls. + * @{ */ + uint64_t Rbx; /**< 0x140 */ + uint64_t Rdi; /**< 0x148 */ + uint64_t Rsi; /**< 0x150 */ + /** @} */ + uint64_t Rbp; /**< 0x158: Typically restored by: MOV RBP, [RBP + 0xd8] */ + uint64_t ErrCdOrXcptFrameOrS; /**< 0x160 */ + uint64_t Rip; /**< 0x168 - IRET RIP */ + uint16_t SegCs; /**< 0x170 - IRET CS */ + uint8_t Fill0; /**< 0x172 */ + uint8_t Logging; /**< 0x173 */ + uint16_t Fill1[2]; /**< 0x174 */ + uint32_t EFlags; /**< 0x178 - IRET EFLAGS - Uninitialized for stack switching/growth code path. */ + uint32_t Fill2; /**< 0x17c */ + uint64_t Rsp; /**< 0x180 - IRET RSP */ + uint16_t SegSs; /**< 0x188 - IRET SS */ + uint16_t Fill3; /**< 0x18a */ + uint32_t Fill4; /**< 0x18c */ +} KTRAP_FRAME_AMD64; +AssertCompileSize(KTRAP_FRAME_AMD64, 0x190); +/** Pointer to an AMD64 NT trap frame. */ +typedef KTRAP_FRAME_AMD64 *PKTRAP_FRAME_AMD64; +/** Pointer to a const AMD64 NT trap frame. */ +typedef KTRAP_FRAME_AMD64 const *PCKTRAP_FRAME_AMD64; + +/** @} */ + + +#endif /* !IPRT_INCLUDED_nt_nt_structures_h */ + diff --git a/include/iprt/nt/nt.h b/include/iprt/nt/nt.h new file mode 100644 index 00000000..c23cd9f0 --- /dev/null +++ b/include/iprt/nt/nt.h @@ -0,0 +1,3824 @@ +/* $Id: nt.h $ */ +/** @file + * IPRT - Header for code using the Native NT API. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_nt_h +#define IPRT_INCLUDED_nt_nt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** @def IPRT_NT_MAP_TO_ZW + * Map Nt calls to Zw calls. In ring-0 the Zw calls let you pass kernel memory + * to the APIs (takes care of the previous context checks). + */ +#ifdef DOXYGEN_RUNNING +# define IPRT_NT_MAP_TO_ZW +#endif + +#ifdef IPRT_NT_MAP_TO_ZW +# define NtQueryDirectoryFile ZwQueryDirectoryFile +# define NtQueryInformationFile ZwQueryInformationFile +# define NtQueryInformationProcess ZwQueryInformationProcess +# define NtQueryInformationThread ZwQueryInformationThread +# define NtQueryFullAttributesFile ZwQueryFullAttributesFile +# define NtQuerySystemInformation ZwQuerySystemInformation +# define NtQuerySecurityObject ZwQuerySecurityObject +# define NtSetInformationFile ZwSetInformationFile +# define NtClose ZwClose +# define NtCreateFile ZwCreateFile +# define NtReadFile ZwReadFile +# define NtWriteFile ZwWriteFile +# define NtFlushBuffersFile ZwFlushBuffersFile +/** @todo this is very incomplete! */ +#endif + +#include + +/* + * Hacks common to both base header sets. + */ +#define RtlFreeUnicodeString WrongLinkage_RtlFreeUnicodeString +#define NtQueryObject Incomplete_NtQueryObject +#define ZwQueryObject Incomplete_ZwQueryObject +#define NtSetInformationObject Incomplete_NtSetInformationObject +#define _OBJECT_INFORMATION_CLASS Incomplete_OBJECT_INFORMATION_CLASS +#define OBJECT_INFORMATION_CLASS Incomplete_OBJECT_INFORMATION_CLASS +#define ObjectBasicInformation Incomplete_ObjectBasicInformation +#define ObjectTypeInformation Incomplete_ObjectTypeInformation +#define _PEB Incomplete__PEB +#define PEB Incomplete_PEB +#define PPEB Incomplete_PPEB +#define _TEB Incomplete__TEB +#define TEB Incomplete_TEB +#define PTEB Incomplete_PTEB +#define _PEB_LDR_DATA Incomplete__PEB_LDR_DATA +#define PEB_LDR_DATA Incomplete_PEB_LDR_DATA +#define PPEB_LDR_DATA Incomplete_PPEB_LDR_DATA +#define _KUSER_SHARED_DATA Incomplete__KUSER_SHARED_DATA +#define KUSER_SHARED_DATA Incomplete_KUSER_SHARED_DATA +#define PKUSER_SHARED_DATA Incomplete_PKUSER_SHARED_DATA + + + +#ifdef IPRT_NT_USE_WINTERNL +/* + * Use Winternl.h. + */ +# define _FILE_INFORMATION_CLASS IncompleteWinternl_FILE_INFORMATION_CLASS +# define FILE_INFORMATION_CLASS IncompleteWinternl_FILE_INFORMATION_CLASS +# define FileDirectoryInformation IncompleteWinternl_FileDirectoryInformation + +# define NtQueryInformationProcess IncompleteWinternl_NtQueryInformationProcess +# define NtSetInformationProcess IncompleteWinternl_NtSetInformationProcess +# define PROCESSINFOCLASS IncompleteWinternl_PROCESSINFOCLASS +# define _PROCESSINFOCLASS IncompleteWinternl_PROCESSINFOCLASS +# define PROCESS_BASIC_INFORMATION IncompleteWinternl_PROCESS_BASIC_INFORMATION +# define PPROCESS_BASIC_INFORMATION IncompleteWinternl_PPROCESS_BASIC_INFORMATION +# define _PROCESS_BASIC_INFORMATION IncompleteWinternl_PROCESS_BASIC_INFORMATION +# define ProcessBasicInformation IncompleteWinternl_ProcessBasicInformation +# define ProcessDebugPort IncompleteWinternl_ProcessDebugPort +# define ProcessWow64Information IncompleteWinternl_ProcessWow64Information +# define ProcessImageFileName IncompleteWinternl_ProcessImageFileName +# define ProcessBreakOnTermination IncompleteWinternl_ProcessBreakOnTermination + +# define RTL_USER_PROCESS_PARAMETERS IncompleteWinternl_RTL_USER_PROCESS_PARAMETERS +# define PRTL_USER_PROCESS_PARAMETERS IncompleteWinternl_PRTL_USER_PROCESS_PARAMETERS +# define _RTL_USER_PROCESS_PARAMETERS IncompleteWinternl__RTL_USER_PROCESS_PARAMETERS + +# define NtQueryInformationThread IncompleteWinternl_NtQueryInformationThread +# define NtSetInformationThread IncompleteWinternl_NtSetInformationThread +# define THREADINFOCLASS IncompleteWinternl_THREADINFOCLASS +# define _THREADINFOCLASS IncompleteWinternl_THREADINFOCLASS +# define ThreadIsIoPending IncompleteWinternl_ThreadIsIoPending + +# define NtQuerySystemInformation IncompleteWinternl_NtQuerySystemInformation +# define NtSetSystemInformation IncompleteWinternl_NtSetSystemInformation +# define NtQueryTimerResolution AddedRecentlyUseOwnPrototype_NtQueryTimerResolution +# define SYSTEM_INFORMATION_CLASS IncompleteWinternl_SYSTEM_INFORMATION_CLASS +# define _SYSTEM_INFORMATION_CLASS IncompleteWinternl_SYSTEM_INFORMATION_CLASS +# define SystemBasicInformation IncompleteWinternl_SystemBasicInformation +# define SystemPerformanceInformation IncompleteWinternl_SystemPerformanceInformation +# define SystemTimeOfDayInformation IncompleteWinternl_SystemTimeOfDayInformation +# define SystemProcessInformation IncompleteWinternl_SystemProcessInformation +# define SystemProcessorPerformanceInformation IncompleteWinternl_SystemProcessorPerformanceInformation +# define SystemInterruptInformation IncompleteWinternl_SystemInterruptInformation +# define SystemExceptionInformation IncompleteWinternl_SystemExceptionInformation +# define SystemRegistryQuotaInformation IncompleteWinternl_SystemRegistryQuotaInformation +# define SystemLookasideInformation IncompleteWinternl_SystemLookasideInformation +# define SystemPolicyInformation IncompleteWinternl_SystemPolicyInformation + + +# pragma warning(push) +# pragma warning(disable: 4668) +# define WIN32_NO_STATUS +# include +# include +# include +# undef WIN32_NO_STATUS +# include +# pragma warning(pop) + +# ifndef OBJ_DONT_REPARSE +# define RTNT_NEED_CLIENT_ID +# endif + +# undef _FILE_INFORMATION_CLASS +# undef FILE_INFORMATION_CLASS +# undef FileDirectoryInformation + +# undef NtQueryInformationProcess +# undef NtSetInformationProcess +# undef PROCESSINFOCLASS +# undef _PROCESSINFOCLASS +# undef PROCESS_BASIC_INFORMATION +# undef PPROCESS_BASIC_INFORMATION +# undef _PROCESS_BASIC_INFORMATION +# undef ProcessBasicInformation +# undef ProcessDebugPort +# undef ProcessWow64Information +# undef ProcessImageFileName +# undef ProcessBreakOnTermination + +# undef RTL_USER_PROCESS_PARAMETERS +# undef PRTL_USER_PROCESS_PARAMETERS +# undef _RTL_USER_PROCESS_PARAMETERS + +# undef NtQueryInformationThread +# undef NtSetInformationThread +# undef THREADINFOCLASS +# undef _THREADINFOCLASS +# undef ThreadIsIoPending + +# undef NtQuerySystemInformation +# undef NtSetSystemInformation +# undef NtQueryTimerResolution +# undef SYSTEM_INFORMATION_CLASS +# undef _SYSTEM_INFORMATION_CLASS +# undef SystemBasicInformation +# undef SystemPerformanceInformation +# undef SystemTimeOfDayInformation +# undef SystemProcessInformation +# undef SystemProcessorPerformanceInformation +# undef SystemInterruptInformation +# undef SystemExceptionInformation +# undef SystemRegistryQuotaInformation +# undef SystemLookasideInformation +# undef SystemPolicyInformation + +# define RTNT_NEED_NT_GET_PRODUCT_TYPE + +#else +/* + * Use ntifs.h and wdm.h. + */ +# if _MSC_VER >= 1200 /* Fix/workaround for KeInitializeSpinLock visibility issue on AMD64. */ +# define FORCEINLINE static __forceinline +# else +# define FORCEINLINE static __inline +# endif + +# define _FSINFOCLASS OutdatedWdm_FSINFOCLASS +# define FS_INFORMATION_CLASS OutdatedWdm_FS_INFORMATION_CLASS +# define PFS_INFORMATION_CLASS OutdatedWdm_PFS_INFORMATION_CLASS +# define FileFsVolumeInformation OutdatedWdm_FileFsVolumeInformation +# define FileFsLabelInformation OutdatedWdm_FileFsLabelInformation +# define FileFsSizeInformation OutdatedWdm_FileFsSizeInformation +# define FileFsDeviceInformation OutdatedWdm_FileFsDeviceInformation +# define FileFsAttributeInformation OutdatedWdm_FileFsAttributeInformation +# define FileFsControlInformation OutdatedWdm_FileFsControlInformation +# define FileFsFullSizeInformation OutdatedWdm_FileFsFullSizeInformation +# define FileFsObjectIdInformation OutdatedWdm_FileFsObjectIdInformation +# define FileFsDriverPathInformation OutdatedWdm_FileFsDriverPathInformation +# define FileFsVolumeFlagsInformation OutdatedWdm_FileFsVolumeFlagsInformation +# define FileFsSectorSizeInformation OutdatedWdm_FileFsSectorSizeInformation +# define FileFsDataCopyInformation OutdatedWdm_FileFsDataCopyInformation +# define FileFsMetadataSizeInformation OutdatedWdm_FileFsMetadataSizeInformation +# define FileFsFullSizeInformationEx OutdatedWdm_FileFsFullSizeInformationEx +# define FileFsMaximumInformation OutdatedWdm_FileFsMaximumInformation +# define NtQueryVolumeInformationFile OutdatedWdm_NtQueryVolumeInformationFile +# define NtSetVolumeInformationFile OutdatedWdm_NtSetVolumeInformationFile +# define _MEMORY_INFORMATION_CLASS OutdatedWdm__MEMORY_INFORMATION_CLASS +# define MEMORY_INFORMATION_CLASS OutdatedWdm_MEMORY_INFORMATION_CLASS +# define MemoryBasicInformation OutdatedWdm_MemoryBasicInformation +# define NtQueryVirtualMemory OutdatedWdm_NtQueryVirtualMemory + +# pragma warning(push) +# ifdef RT_ARCH_X86 +# define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap +# pragma warning(disable: 4163) +# endif +# pragma warning(disable: 4668) +# pragma warning(disable: 4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4471) /* wdm.h(11057) : warning C4471: '_POOL_TYPE' : a forward declaration of an unscoped enumeration must have an underlying type (int assumed) */ +# endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* warning C5039: 'KeInitializeDpc': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif + +# include +# include + +# ifdef RT_ARCH_X86 +# undef _InterlockedAddLargeStatistic +# endif +# pragma warning(pop) + +# undef _FSINFOCLASS +# undef FS_INFORMATION_CLASS +# undef PFS_INFORMATION_CLASS +# undef FileFsVolumeInformation +# undef FileFsLabelInformation +# undef FileFsSizeInformation +# undef FileFsDeviceInformation +# undef FileFsAttributeInformation +# undef FileFsControlInformation +# undef FileFsFullSizeInformation +# undef FileFsObjectIdInformation +# undef FileFsDriverPathInformation +# undef FileFsVolumeFlagsInformation +# undef FileFsSectorSizeInformation +# undef FileFsDataCopyInformation +# undef FileFsMetadataSizeInformation +# undef FileFsFullSizeInformationEx +# undef FileFsMaximumInformation +# undef NtQueryVolumeInformationFile +# undef NtSetVolumeInformationFile +# undef _MEMORY_INFORMATION_CLASS +# undef MEMORY_INFORMATION_CLASS +# undef MemoryBasicInformation +# undef NtQueryVirtualMemory + +# define IPRT_NT_NEED_API_GROUP_NTIFS +# ifndef NTDDI_WIN10_RS1 +# define RTNT_NEED_NT_GET_PRODUCT_TYPE +# elif NTDDI_VERSION < NTDDI_WIN10_RS1 +# define RTNT_NEED_NT_GET_PRODUCT_TYPE +# endif + +#endif + +#undef RtlFreeUnicodeString +#undef NtQueryObject +#undef ZwQueryObject +#undef NtSetInformationObject +#undef _OBJECT_INFORMATION_CLASS +#undef OBJECT_INFORMATION_CLASS +#undef ObjectBasicInformation +#undef ObjectTypeInformation +#undef _PEB +#undef PEB +#undef PPEB +#undef _TEB +#undef TEB +#undef PTEB +#undef _PEB_LDR_DATA +#undef PEB_LDR_DATA +#undef PPEB_LDR_DATA +#undef _KUSER_SHARED_DATA +#undef KUSER_SHARED_DATA +#undef PKUSER_SHARED_DATA + + +#include +#include + + +/** @name Useful macros + * @{ */ +/** Indicates that we're targeting native NT in the current source. */ +#define RTNT_USE_NATIVE_NT 1 +/** Initializes a IO_STATUS_BLOCK. */ +#define RTNT_IO_STATUS_BLOCK_INITIALIZER { STATUS_FAILED_DRIVER_ENTRY, ~(uintptr_t)42 } +/** Reinitializes a IO_STATUS_BLOCK. */ +#define RTNT_IO_STATUS_BLOCK_REINIT(a_pIos) \ + do { (a_pIos)->Status = STATUS_FAILED_DRIVER_ENTRY; (a_pIos)->Information = ~(uintptr_t)42; } while (0) +/** Similar to INVALID_HANDLE_VALUE in the Windows environment. */ +#define RTNT_INVALID_HANDLE_VALUE ( (HANDLE)~(uintptr_t)0 ) +/** Constant UNICODE_STRING initializer. */ +#define RTNT_CONSTANT_UNISTR(a_String) { sizeof(a_String) - sizeof(WCHAR), sizeof(a_String), (WCHAR *)a_String } +/** Null UNICODE_STRING initializer. */ +#define RTNT_NULL_UNISTR() { 0, 0, NULL } + +/** Declaration wrapper for NT apis. + * Adds nothrow. Don't use with callbacks. */ +#define RT_DECL_NTAPI(type) DECL_NOTHROW(NTSYSAPI type NTAPI) +/** @} */ + + +/** @name IPRT helper functions for NT + * @{ */ +RT_C_DECLS_BEGIN + +RTDECL(int) RTNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, + ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + PHANDLE phHandle, PULONG_PTR puDisposition); +RTDECL(int) RTNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions, + ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir); +RTDECL(int) RTNtPathOpenDirEx(HANDLE hRootDir, struct _UNICODE_STRING *pNtName, ACCESS_MASK fDesiredAccess, + ULONG fShareAccess, ULONG fCreateOptions, ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir); +RTDECL(int) RTNtPathClose(HANDLE hHandle); + +/** + * Converts a windows-style path to NT format and encoding. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT name. Free using + * RTNtPathFree. + * @param phRootDir Where to return the root handle, if applicable. + * @param pszPath The UTF-8 path. + */ +RTDECL(int) RTNtPathFromWinUtf8(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath); + +/** + * Converts a UTF-16 windows-style path to NT format. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT name. Free using + * RTNtPathFree. + * @param phRootDir Where to return the root handle, if applicable. + * @param pwszPath The UTF-16 windows-style path. + * @param cwcPath The max length of the windows-style path in + * RTUTF16 units. Use RTSTR_MAX if unknown and @a + * pwszPath is correctly terminated. + */ +RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszPath, size_t cwcPath); + +/** + * How to handle ascent ('..' relative to a root handle). + */ +typedef enum RTNTPATHRELATIVEASCENT +{ + kRTNtPathRelativeAscent_Invalid = 0, + kRTNtPathRelativeAscent_Allow, + kRTNtPathRelativeAscent_Fail, + kRTNtPathRelativeAscent_Ignore, + kRTNtPathRelativeAscent_End, + kRTNtPathRelativeAscent_32BitHack = 0x7fffffff +} RTNTPATHRELATIVEASCENT; + +/** + * Converts a relative windows-style path to relative NT format and encoding. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT name. Free using + * rtTNtPathToNative with phRootDir set to NULL. + * @param phRootDir On input, the handle to the directory the path + * is relative to. On output, the handle to + * specify as root directory in the object + * attributes when accessing the path. If + * enmAscent is kRTNtPathRelativeAscent_Allow, it + * may have been set to NULL. + * @param pszPath The relative UTF-8 path. + * @param enmAscent How to handle ascent. + * @param fMustReturnAbsolute Must convert to an absolute path. This + * is necessary if the root dir is a NT directory + * object (e.g. /Devices) since they cannot parse + * relative paths it seems. + */ +RTDECL(int) RTNtPathRelativeFromUtf8(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath, + RTNTPATHRELATIVEASCENT enmAscent, bool fMustReturnAbsolute); + +/** + * Ensures that the NT string has sufficient storage to hold @a cwcMin RTUTF16 + * chars plus a terminator. + * + * The NT string must have been returned by RTNtPathFromWinUtf8 or + * RTNtPathFromWinUtf16Ex. + * + * @returns IPRT status code. + * @param pNtName The NT path string. + * @param cwcMin The minimum number of RTUTF16 chars. Max 32767. + * @sa RTNtPathFree + */ +RTDECL(int) RTNtPathEnsureSpace(struct _UNICODE_STRING *pNtName, size_t cwcMin); + +/** + * Gets the NT path to the object represented by the given handle. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT path. Free using + * RTNtPathFree. + * @param hHandle The handle. + * @param cwcExtra How much extra space is needed. + */ +RTDECL(int) RTNtPathFromHandle(struct _UNICODE_STRING *pNtName, HANDLE hHandle, size_t cwcExtra); + +/** + * Frees the native path and root handle. + * + * @param pNtName The NT path after a successful rtNtPathToNative + * call or RTNtPathRelativeFromUtf8. + * @param phRootDir The root handle variable from rtNtPathToNative, + */ +RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir); + + +/** + * Checks whether the path could be containing alternative 8.3 names generated + * by NTFS, FAT, or other similar file systems. + * + * @returns Pointer to the first component that might be an 8.3 name, NULL if + * not 8.3 path. + * @param pwszPath The path to check. + * + * @remarks This is making bad ASSUMPTION wrt to the naming scheme of 8.3 names, + * however, non-tilde 8.3 aliases are probably rare enough to not be + * worth all the extra code necessary to open each path component and + * check if we've got the short name or not. + */ +RTDECL(PRTUTF16) RTNtPathFindPossible8dot3Name(PCRTUTF16 pwszPath); + +/** + * Fixes up a path possibly containing one or more alternative 8-dot-3 style + * components. + * + * The path is fixed up in place. Errors are ignored. + * + * @returns VINF_SUCCESS if it all went smoothly, informational status codes + * indicating the nature of last problem we ran into. + * + * @param pUniStr The path to fix up. MaximumLength is the max buffer + * length. + * @param fPathOnly Whether to only process the path and leave the filename + * as passed in. + */ +RTDECL(int) RTNtPathExpand8dot3Path(struct _UNICODE_STRING *pUniStr, bool fPathOnly); + +/** + * Wrapper around RTNtPathExpand8dot3Path that allocates a buffer instead of + * working on the input buffer. + * + * @returns IPRT status code, see RTNtPathExpand8dot3Path(). + * @param pUniStrSrc The path to fix up. MaximumLength is the max buffer + * length. + * @param fPathOnly Whether to only process the path and leave the filename + * as passed in. + * @param pUniStrDst Output string. On success, the caller must use + * RTUtf16Free to free what the Buffer member points to. + * This is all zeros and NULL on failure. + */ +RTDECL(int) RTNtPathExpand8dot3PathA(struct _UNICODE_STRING const *pUniStrSrc, bool fPathOnly, struct _UNICODE_STRING *pUniStrDst); + + +RT_C_DECLS_END +/** @} */ + + +/** @name NT API delcarations. + * @{ */ +RT_C_DECLS_BEGIN + +/** @name Process access rights missing in ntddk headers + * @{ */ +#ifndef PROCESS_TERMINATE +# define PROCESS_TERMINATE UINT32_C(0x00000001) +#endif +#ifndef PROCESS_CREATE_THREAD +# define PROCESS_CREATE_THREAD UINT32_C(0x00000002) +#endif +#ifndef PROCESS_SET_SESSIONID +# define PROCESS_SET_SESSIONID UINT32_C(0x00000004) +#endif +#ifndef PROCESS_VM_OPERATION +# define PROCESS_VM_OPERATION UINT32_C(0x00000008) +#endif +#ifndef PROCESS_VM_READ +# define PROCESS_VM_READ UINT32_C(0x00000010) +#endif +#ifndef PROCESS_VM_WRITE +# define PROCESS_VM_WRITE UINT32_C(0x00000020) +#endif +#ifndef PROCESS_DUP_HANDLE +# define PROCESS_DUP_HANDLE UINT32_C(0x00000040) +#endif +#ifndef PROCESS_CREATE_PROCESS +# define PROCESS_CREATE_PROCESS UINT32_C(0x00000080) +#endif +#ifndef PROCESS_SET_QUOTA +# define PROCESS_SET_QUOTA UINT32_C(0x00000100) +#endif +#ifndef PROCESS_SET_INFORMATION +# define PROCESS_SET_INFORMATION UINT32_C(0x00000200) +#endif +#ifndef PROCESS_QUERY_INFORMATION +# define PROCESS_QUERY_INFORMATION UINT32_C(0x00000400) +#endif +#ifndef PROCESS_SUSPEND_RESUME +# define PROCESS_SUSPEND_RESUME UINT32_C(0x00000800) +#endif +#ifndef PROCESS_QUERY_LIMITED_INFORMATION +# define PROCESS_QUERY_LIMITED_INFORMATION UINT32_C(0x00001000) +#endif +#ifndef PROCESS_SET_LIMITED_INFORMATION +# define PROCESS_SET_LIMITED_INFORMATION UINT32_C(0x00002000) +#endif +#define PROCESS_UNKNOWN_4000 UINT32_C(0x00004000) +#define PROCESS_UNKNOWN_6000 UINT32_C(0x00008000) +#ifndef PROCESS_ALL_ACCESS +# define PROCESS_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | UINT32_C(0x0000ffff) ) +#endif +/** @} */ + +/** @name Thread access rights missing in ntddk headers + * @{ */ +#ifndef THREAD_QUERY_INFORMATION +# define THREAD_QUERY_INFORMATION UINT32_C(0x00000040) +#endif +#ifndef THREAD_SET_THREAD_TOKEN +# define THREAD_SET_THREAD_TOKEN UINT32_C(0x00000080) +#endif +#ifndef THREAD_IMPERSONATE +# define THREAD_IMPERSONATE UINT32_C(0x00000100) +#endif +#ifndef THREAD_DIRECT_IMPERSONATION +# define THREAD_DIRECT_IMPERSONATION UINT32_C(0x00000200) +#endif +#ifndef THREAD_RESUME +# define THREAD_RESUME UINT32_C(0x00001000) +#endif +#define THREAD_UNKNOWN_2000 UINT32_C(0x00002000) +#define THREAD_UNKNOWN_4000 UINT32_C(0x00004000) +#define THREAD_UNKNOWN_8000 UINT32_C(0x00008000) +/** @} */ + +/** @name Special handle values. + * @{ */ +#ifndef NtCurrentProcess +# define NtCurrentProcess() ( (HANDLE)-(intptr_t)1 ) +#endif +#ifndef NtCurrentThread +# define NtCurrentThread() ( (HANDLE)-(intptr_t)2 ) +#endif +#ifndef ZwCurrentProcess +# define ZwCurrentProcess() NtCurrentProcess() +#endif +#ifndef ZwCurrentThread +# define ZwCurrentThread() NtCurrentThread() +#endif +/** @} */ + + +/** @name Directory object access rights. + * @{ */ +#ifndef DIRECTORY_QUERY +# define DIRECTORY_QUERY UINT32_C(0x00000001) +#endif +#ifndef DIRECTORY_TRAVERSE +# define DIRECTORY_TRAVERSE UINT32_C(0x00000002) +#endif +#ifndef DIRECTORY_CREATE_OBJECT +# define DIRECTORY_CREATE_OBJECT UINT32_C(0x00000004) +#endif +#ifndef DIRECTORY_CREATE_SUBDIRECTORY +# define DIRECTORY_CREATE_SUBDIRECTORY UINT32_C(0x00000008) +#endif +#ifndef DIRECTORY_ALL_ACCESS +# define DIRECTORY_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | UINT32_C(0x0000000f) ) +#endif +/** @} */ + + + +#ifdef RTNT_NEED_CLIENT_ID +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID; +#endif +#ifdef IPRT_NT_USE_WINTERNL +typedef CLIENT_ID *PCLIENT_ID; +#endif + +/** Extended affinity type, introduced in Windows 7 (?). */ +typedef struct _KAFFINITY_EX +{ + /** Count of valid bitmap entries. */ + uint16_t Count; + /** Count of allocated bitmap entries. */ + uint16_t Size; + /** Reserved / aligmment padding. */ + uint32_t Reserved; + /** Bitmap where one bit corresponds to a CPU. + * @note Started at 20 entries. W10 20H2 increased it to 32. Must be + * probed by passing a big buffer to KeInitializeAffinityEx and check + * the Size afterwards. */ + uintptr_t Bitmap[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} KAFFINITY_EX; +typedef KAFFINITY_EX *PKAFFINITY_EX; +typedef KAFFINITY_EX const *PCKAFFINITY_EX; + +/** @name User Shared Data + * @{ */ + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _KSYSTEM_TIME +{ + ULONG LowPart; + LONG High1Time; + LONG High2Time; +} KSYSTEM_TIME; +typedef KSYSTEM_TIME *PKSYSTEM_TIME; + +typedef enum _NT_PRODUCT_TYPE +{ + NtProductWinNt = 1, + NtProductLanManNt, + NtProductServer +} NT_PRODUCT_TYPE; + +#define PROCESSOR_FEATURE_MAX 64 + +typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE +{ + StandardDesign = 0, + NEC98x86, + EndAlternatives +} ALTERNATIVE_ARCHITECTURE_TYPE; + +# if 0 +typedef struct _XSTATE_FEATURE +{ + ULONG Offset; + ULONG Size; +} XSTATE_FEATURE; +typedef XSTATE_FEATURE *PXSTATE_FEATURE; + +#define MAXIMUM_XSTATE_FEATURES 64 + +typedef struct _XSTATE_CONFIGURATION +{ + ULONG64 EnabledFeatures; + ULONG Size; + ULONG OptimizedSave : 1; + XSTATE_FEATURE Features[MAXIMUM_XSTATE_FEATURES]; +} XSTATE_CONFIGURATION; +typedef XSTATE_CONFIGURATION *PXSTATE_CONFIGURATION; +# endif +#endif /* IPRT_NT_USE_WINTERNL */ + +typedef struct _KUSER_SHARED_DATA +{ + ULONG TickCountLowDeprecated; /**< 0x000 */ + ULONG TickCountMultiplier; /**< 0x004 */ + KSYSTEM_TIME volatile InterruptTime; /**< 0x008 */ + KSYSTEM_TIME volatile SystemTime; /**< 0x014 */ + KSYSTEM_TIME volatile TimeZoneBias; /**< 0x020 */ + USHORT ImageNumberLow; /**< 0x02c */ + USHORT ImageNumberHigh; /**< 0x02e */ + WCHAR NtSystemRoot[260]; /**< 0x030 - Seems to be last member in NT 3.51. */ + ULONG MaxStackTraceDepth; /**< 0x238 */ + ULONG CryptoExponent; /**< 0x23c */ + ULONG TimeZoneId; /**< 0x240 */ + ULONG LargePageMinimum; /**< 0x244 */ + ULONG AitSamplingValue; /**< 0x248 */ + ULONG AppCompatFlag; /**< 0x24c */ + ULONGLONG RNGSeedVersion; /**< 0x250 */ + ULONG GlobalValidationRunlevel; /**< 0x258 */ + LONG volatile TimeZoneBiasStamp; /**< 0x25c*/ + ULONG Reserved2; /**< 0x260 */ + NT_PRODUCT_TYPE NtProductType; /**< 0x264 */ + BOOLEAN ProductTypeIsValid; /**< 0x268 */ + BOOLEAN Reserved0[1]; /**< 0x269 */ + USHORT NativeProcessorArchitecture; /**< 0x26a */ + ULONG NtMajorVersion; /**< 0x26c */ + ULONG NtMinorVersion; /**< 0x270 */ + BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX]; /**< 0x274 */ + ULONG Reserved1; /**< 0x2b4 */ + ULONG Reserved3; /**< 0x2b8 */ + ULONG volatile TimeSlip; /**< 0x2bc */ + ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; /**< 0x2c0 */ + ULONG AltArchitecturePad[1]; /**< 0x2c4 */ + LARGE_INTEGER SystemExpirationDate; /**< 0x2c8 */ + ULONG SuiteMask; /**< 0x2d0 */ + BOOLEAN KdDebuggerEnabled; /**< 0x2d4 */ + union /**< 0x2d5 */ + { + UCHAR MitigationPolicies; /**< 0x2d5 */ + struct + { + UCHAR NXSupportPolicy : 2; + UCHAR SEHValidationPolicy : 2; + UCHAR CurDirDevicesSkippedForDlls : 2; + UCHAR Reserved : 2; + }; + }; + UCHAR Reserved6[2]; /**< 0x2d6 */ + ULONG volatile ActiveConsoleId; /**< 0x2d8 */ + ULONG volatile DismountCount; /**< 0x2dc */ + ULONG ComPlusPackage; /**< 0x2e0 */ + ULONG LastSystemRITEventTickCount; /**< 0x2e4 */ + ULONG NumberOfPhysicalPages; /**< 0x2e8 */ + BOOLEAN SafeBootMode; /**< 0x2ec */ + UCHAR Reserved12[3]; /**< 0x2ed */ + union /**< 0x2f0 */ + { + ULONG SharedDataFlags; /**< 0x2f0 */ + struct + { + ULONG DbgErrorPortPresent : 1; + ULONG DbgElevationEnabled : 1; + ULONG DbgVirtEnabled : 1; + ULONG DbgInstallerDetectEnabled : 1; + ULONG DbgLkgEnabled : 1; + ULONG DbgDynProcessorEnabled : 1; + ULONG DbgConsoleBrokerEnabled : 1; + ULONG DbgSecureBootEnabled : 1; + ULONG SpareBits : 24; + }; + }; + ULONG DataFlagsPad[1]; /**< 0x2f4 */ + ULONGLONG TestRetInstruction; /**< 0x2f8 */ + LONGLONG QpcFrequency; /**< 0x300 */ + ULONGLONG SystemCallPad[3]; /**< 0x308 */ + union /**< 0x320 */ + { + ULONG64 volatile TickCountQuad; /**< 0x320 */ + KSYSTEM_TIME volatile TickCount; /**< 0x320 */ + struct /**< 0x320 */ + { + ULONG ReservedTickCountOverlay[3]; /**< 0x320 */ + ULONG TickCountPad[1]; /**< 0x32c */ + }; + }; + ULONG Cookie; /**< 0x330 */ + ULONG CookiePad[1]; /**< 0x334 */ + LONGLONG ConsoleSessionForegroundProcessId; /**< 0x338 */ + ULONGLONG TimeUpdateLock; /**< 0x340 */ + ULONGLONG BaselineSystemTimeQpc; /**< 0x348 */ + ULONGLONG BaselineInterruptTimeQpc; /**< 0x350 */ + ULONGLONG QpcSystemTimeIncrement; /**< 0x358 */ + ULONGLONG QpcInterruptTimeIncrement; /**< 0x360 */ + ULONG QpcSystemTimeIncrement32; /**< 0x368 */ + ULONG QpcInterruptTimeIncrement32; /**< 0x36c */ + UCHAR QpcSystemTimeIncrementShift; /**< 0x370 */ + UCHAR QpcInterruptTimeIncrementShift; /**< 0x371 */ + UCHAR Reserved8[14]; /**< 0x372 */ + USHORT UserModeGlobalLogger[16]; /**< 0x380 */ + ULONG ImageFileExecutionOptions; /**< 0x3a0 */ + ULONG LangGenerationCount; /**< 0x3a4 */ + ULONGLONG Reserved4; /**< 0x3a8 */ + ULONGLONG volatile InterruptTimeBias; /**< 0x3b0 - What QueryUnbiasedInterruptTimePrecise + * subtracts from interrupt time. */ + ULONGLONG volatile QpcBias; /**< 0x3b8 */ + ULONG volatile ActiveProcessorCount; /**< 0x3c0 */ + UCHAR volatile ActiveGroupCount; /**< 0x3c4 */ + UCHAR Reserved9; /**< 0x3c5 */ + union /**< 0x3c6 */ + { + USHORT QpcData; /**< 0x3c6 */ + struct /**< 0x3c6 */ + { + BOOLEAN volatile QpcBypassEnabled; /**< 0x3c6 */ + UCHAR QpcShift; /**< 0x3c7 */ + }; + }; + LARGE_INTEGER TimeZoneBiasEffectiveStart; /**< 0x3c8 */ + LARGE_INTEGER TimeZoneBiasEffectiveEnd; /**< 0x3d0 */ + XSTATE_CONFIGURATION XState; /**< 0x3d8 */ +} KUSER_SHARED_DATA; +typedef KUSER_SHARED_DATA *PKUSER_SHARED_DATA; +AssertCompileMemberOffset(KUSER_SHARED_DATA, InterruptTime, 0x008); +AssertCompileMemberOffset(KUSER_SHARED_DATA, SystemTime, 0x014); +AssertCompileMemberOffset(KUSER_SHARED_DATA, NtSystemRoot, 0x030); +AssertCompileMemberOffset(KUSER_SHARED_DATA, LargePageMinimum, 0x244); +AssertCompileMemberOffset(KUSER_SHARED_DATA, Reserved1, 0x2b4); +AssertCompileMemberOffset(KUSER_SHARED_DATA, TestRetInstruction, 0x2f8); +AssertCompileMemberOffset(KUSER_SHARED_DATA, Cookie, 0x330); +AssertCompileMemberOffset(KUSER_SHARED_DATA, ImageFileExecutionOptions, 0x3a0); +AssertCompileMemberOffset(KUSER_SHARED_DATA, XState, 0x3d8); +/** @def MM_SHARED_USER_DATA_VA + * Read only userland mapping of KUSER_SHARED_DATA. */ +#ifndef MM_SHARED_USER_DATA_VA +# if ARCH_BITS == 32 +# define MM_SHARED_USER_DATA_VA UINT32_C(0x7ffe0000) +# elif ARCH_BITS == 64 +# define MM_SHARED_USER_DATA_VA UINT64_C(0x7ffe0000) +# else +# error "Unsupported/undefined ARCH_BITS value." +# endif +#endif +/** @def KI_USER_SHARED_DATA + * Read write kernel mapping of KUSER_SHARED_DATA. */ +#ifndef KI_USER_SHARED_DATA +# ifdef RT_ARCH_X86 +# define KI_USER_SHARED_DATA UINT32_C(0xffdf0000) +# elif defined(RT_ARCH_AMD64) +# define KI_USER_SHARED_DATA UINT64_C(0xfffff78000000000) +# else +# error "PORT ME - KI_USER_SHARED_DATA" +# endif +#endif +/** @} */ + + +/** @name Process And Thread Environment Blocks + * @{ */ + +typedef struct _PEB_LDR_DATA +{ + uint32_t Length; + BOOLEAN Initialized; + BOOLEAN Padding[3]; + HANDLE SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + /* End NT4 */ + LIST_ENTRY *EntryInProgress; + BOOLEAN ShutdownInProgress; + HANDLE ShutdownThreadId; +} PEB_LDR_DATA; +typedef PEB_LDR_DATA *PPEB_LDR_DATA; + +typedef struct _PEB_COMMON +{ + BOOLEAN InheritedAddressSpace; /**< 0x000 / 0x000 */ + BOOLEAN ReadImageFileExecOptions; /**< 0x001 / 0x001 */ + BOOLEAN BeingDebugged; /**< 0x002 / 0x002 */ + union + { + uint8_t BitField; /**< 0x003 / 0x003 */ + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + } Common; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t IsProtectedProcess : 1; /**< 0x003 / 0x003 : Pos 1, 1 Bit */ + uint8_t IsImageDynamicallyRelocated : 1; /**< 0x003 / 0x003 : Pos 2, 1 Bit - Differs from W80 */ + uint8_t SkipPatchingUser32Forwarders : 1; /**< 0x003 / 0x003 : Pos 3, 1 Bit - Differs from W80 */ + uint8_t IsPackagedProcess : 1; /**< 0x003 / 0x003 : Pos 4, 1 Bit - Differs from W80 */ + uint8_t IsAppContainer : 1; /**< 0x003 / 0x003 : Pos 5, 1 Bit - Differs from W80 */ + uint8_t IsProtectedProcessLight : 1; /**< 0x003 / 0x003 : Pos 6, 1 Bit - Differs from W80 */ + uint8_t SpareBits : 1; /**< 0x003 / 0x003 : Pos 7, 1 Bit */ + } W81; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t IsProtectedProcess : 1; /**< 0x003 / 0x003 : Pos 1, 1 Bit */ + uint8_t IsLegacyProcess : 1; /**< 0x003 / 0x003 : Pos 2, 1 Bit - Differs from W81 */ + uint8_t IsImageDynamicallyRelocated : 1; /**< 0x003 / 0x003 : Pos 3, 1 Bit - Differs from W81 */ + uint8_t SkipPatchingUser32Forwarders : 1; /**< 0x003 / 0x003 : Pos 4, 1 Bit - Differs from W81 */ + uint8_t IsPackagedProcess : 1; /**< 0x003 / 0x003 : Pos 5, 1 Bit - Differs from W81 */ + uint8_t IsAppContainer : 1; /**< 0x003 / 0x003 : Pos 6, 1 Bit - Differs from W81 */ + uint8_t SpareBits : 1; /**< 0x003 / 0x003 : Pos 7, 1 Bit */ + } W80; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t IsProtectedProcess : 1; /**< 0x003 / 0x003 : Pos 1, 1 Bit */ + uint8_t IsLegacyProcess : 1; /**< 0x003 / 0x003 : Pos 2, 1 Bit - Differs from W81, same as W80 & W6. */ + uint8_t IsImageDynamicallyRelocated : 1; /**< 0x003 / 0x003 : Pos 3, 1 Bit - Differs from W81, same as W80 & W6. */ + uint8_t SkipPatchingUser32Forwarders : 1; /**< 0x003 / 0x003 : Pos 4, 1 Bit - Added in W7; Differs from W81, same as W80. */ + uint8_t SpareBits : 3; /**< 0x003 / 0x003 : Pos 5, 3 Bit - Differs from W81 & W80, more spare bits. */ + } W7; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t IsProtectedProcess : 1; /**< 0x003 / 0x003 : Pos 1, 1 Bit */ + uint8_t IsLegacyProcess : 1; /**< 0x003 / 0x003 : Pos 2, 1 Bit - Differs from W81, same as W80 & W7. */ + uint8_t IsImageDynamicallyRelocated : 1; /**< 0x003 / 0x003 : Pos 3, 1 Bit - Differs from W81, same as W80 & W7. */ + uint8_t SpareBits : 4; /**< 0x003 / 0x003 : Pos 4, 4 Bit - Differs from W81, W80, & W7, more spare bits. */ + } W6; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t SpareBits : 7; /**< 0x003 / 0x003 : Pos 1, 7 Bit - Differs from W81, W80, & W7, more spare bits. */ + } W52; + struct + { + BOOLEAN SpareBool; + } W51; + } Diff0; +#if ARCH_BITS == 64 + uint32_t Padding0; /**< 0x004 / NA */ +#endif + HANDLE Mutant; /**< 0x008 / 0x004 */ + PVOID ImageBaseAddress; /**< 0x010 / 0x008 */ + PPEB_LDR_DATA Ldr; /**< 0x018 / 0x00c */ + struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters; /**< 0x020 / 0x010 */ + PVOID SubSystemData; /**< 0x028 / 0x014 */ + HANDLE ProcessHeap; /**< 0x030 / 0x018 */ + struct _RTL_CRITICAL_SECTION *FastPebLock; /**< 0x038 / 0x01c */ + union + { + struct + { + PVOID AtlThunkSListPtr; /**< 0x040 / 0x020 */ + PVOID IFEOKey; /**< 0x048 / 0x024 */ + union + { + ULONG CrossProcessFlags; /**< 0x050 / 0x028 */ + struct + { + uint32_t ProcessInJob : 1; /**< 0x050 / 0x028: Pos 0, 1 Bit */ + uint32_t ProcessInitializing : 1; /**< 0x050 / 0x028: Pos 1, 1 Bit */ + uint32_t ProcessUsingVEH : 1; /**< 0x050 / 0x028: Pos 2, 1 Bit */ + uint32_t ProcessUsingVCH : 1; /**< 0x050 / 0x028: Pos 3, 1 Bit */ + uint32_t ProcessUsingFTH : 1; /**< 0x050 / 0x028: Pos 4, 1 Bit */ + uint32_t ReservedBits0 : 1; /**< 0x050 / 0x028: Pos 5, 27 Bits */ + } W7, W8, W80, W81; + struct + { + uint32_t ProcessInJob : 1; /**< 0x050 / 0x028: Pos 0, 1 Bit */ + uint32_t ProcessInitializing : 1; /**< 0x050 / 0x028: Pos 1, 1 Bit */ + uint32_t ReservedBits0 : 30; /**< 0x050 / 0x028: Pos 2, 30 Bits */ + } W6; + }; +#if ARCH_BITS == 64 + uint32_t Padding1; /**< 0x054 / */ +#endif + } W6, W7, W8, W80, W81; + struct + { + PVOID AtlThunkSListPtr; /**< 0x040 / 0x020 */ + PVOID SparePtr2; /**< 0x048 / 0x024 */ + uint32_t EnvironmentUpdateCount; /**< 0x050 / 0x028 */ +#if ARCH_BITS == 64 + uint32_t Padding1; /**< 0x054 / */ +#endif + } W52; + struct + { + PVOID FastPebLockRoutine; /**< NA / 0x020 */ + PVOID FastPebUnlockRoutine; /**< NA / 0x024 */ + uint32_t EnvironmentUpdateCount; /**< NA / 0x028 */ + } W51; + } Diff1; + union + { + PVOID KernelCallbackTable; /**< 0x058 / 0x02c */ + PVOID UserSharedInfoPtr; /**< 0x058 / 0x02c - Alternative use in W6.*/ + }; + uint32_t SystemReserved; /**< 0x060 / 0x030 */ + union + { + struct + { + uint32_t AtlThunkSListPtr32; /**< 0x064 / 0x034 */ + } W7, W8, W80, W81; + struct + { + uint32_t SpareUlong; /**< 0x064 / 0x034 */ + } W52, W6; + struct + { + uint32_t ExecuteOptions : 2; /**< NA / 0x034: Pos 0, 2 Bits */ + uint32_t SpareBits : 30; /**< NA / 0x034: Pos 2, 30 Bits */ + } W51; + } Diff2; + union + { + struct + { + PVOID ApiSetMap; /**< 0x068 / 0x038 */ + } W7, W8, W80, W81; + struct + { + struct _PEB_FREE_BLOCK *FreeList; /**< 0x068 / 0x038 */ + } W52, W6; + struct + { + struct _PEB_FREE_BLOCK *FreeList; /**< NA / 0x038 */ + } W51; + } Diff3; + uint32_t TlsExpansionCounter; /**< 0x070 / 0x03c */ +#if ARCH_BITS == 64 + uint32_t Padding2; /**< 0x074 / NA */ +#endif + struct _RTL_BITMAP *TlsBitmap; /**< 0x078 / 0x040 */ + uint32_t TlsBitmapBits[2]; /**< 0x080 / 0x044 */ + PVOID ReadOnlySharedMemoryBase; /**< 0x088 / 0x04c */ + union + { + struct + { + PVOID SparePvoid0; /**< 0x090 / 0x050 - HotpatchInformation before W81. */ + } W81; + struct + { + PVOID HotpatchInformation; /**< 0x090 / 0x050 - Retired in W81. */ + } W6, W7, W80; + struct + { + PVOID ReadOnlySharedMemoryHeap; + } W52; + } Diff4; + PVOID *ReadOnlyStaticServerData; /**< 0x098 / 0x054 */ + PVOID AnsiCodePageData; /**< 0x0a0 / 0x058 */ + PVOID OemCodePageData; /**< 0x0a8 / 0x05c */ + PVOID UnicodeCaseTableData; /**< 0x0b0 / 0x060 */ + uint32_t NumberOfProcessors; /**< 0x0b8 / 0x064 */ + uint32_t NtGlobalFlag; /**< 0x0bc / 0x068 */ +#if ARCH_BITS == 32 + uint32_t Padding2b; +#endif + LARGE_INTEGER CriticalSectionTimeout; /**< 0x0c0 / 0x070 */ + SIZE_T HeapSegmentReserve; /**< 0x0c8 / 0x078 */ + SIZE_T HeapSegmentCommit; /**< 0x0d0 / 0x07c */ + SIZE_T HeapDeCommitTotalFreeThreshold; /**< 0x0d8 / 0x080 */ + SIZE_T HeapDeCommitFreeBlockThreshold; /**< 0x0e0 / 0x084 */ + uint32_t NumberOfHeaps; /**< 0x0e8 / 0x088 */ + uint32_t MaximumNumberOfHeaps; /**< 0x0ec / 0x08c */ + PVOID *ProcessHeaps; /**< 0x0f0 / 0x090 - Last NT 3.51 member. */ + PVOID GdiSharedHandleTable; /**< 0x0f8 / 0x094 */ + PVOID ProcessStarterHelper; /**< 0x100 / 0x098 */ + uint32_t GdiDCAttributeList; /**< 0x108 / 0x09c */ +#if ARCH_BITS == 64 + uint32_t Padding3; /**< 0x10c / NA */ +#endif + struct _RTL_CRITICAL_SECTION *LoaderLock; /**< 0x110 / 0x0a0 */ + uint32_t OSMajorVersion; /**< 0x118 / 0x0a4 */ + uint32_t OSMinorVersion; /**< 0x11c / 0x0a8 */ + uint16_t OSBuildNumber; /**< 0x120 / 0x0ac */ + uint16_t OSCSDVersion; /**< 0x122 / 0x0ae */ + uint32_t OSPlatformId; /**< 0x124 / 0x0b0 */ + uint32_t ImageSubsystem; /**< 0x128 / 0x0b4 */ + uint32_t ImageSubsystemMajorVersion; /**< 0x12c / 0x0b8 */ + uint32_t ImageSubsystemMinorVersion; /**< 0x130 / 0x0bc */ +#if ARCH_BITS == 64 + uint32_t Padding4; /**< 0x134 / NA */ +#endif + union + { + struct + { + SIZE_T ActiveProcessAffinityMask; /**< 0x138 / 0x0c0 */ + } W7, W8, W80, W81; + struct + { + SIZE_T ImageProcessAffinityMask; /**< 0x138 / 0x0c0 */ + } W52, W6; + } Diff5; + uint32_t GdiHandleBuffer[ARCH_BITS == 64 ? 60 : 34]; /**< 0x140 / 0x0c4 */ + PVOID PostProcessInitRoutine; /**< 0x230 / 0x14c */ + PVOID TlsExpansionBitmap; /**< 0x238 / 0x150 */ + uint32_t TlsExpansionBitmapBits[32]; /**< 0x240 / 0x154 */ + uint32_t SessionId; /**< 0x2c0 / 0x1d4 */ +#if ARCH_BITS == 64 + uint32_t Padding5; /**< 0x2c4 / NA */ +#endif + ULARGE_INTEGER AppCompatFlags; /**< 0x2c8 / 0x1d8 */ + ULARGE_INTEGER AppCompatFlagsUser; /**< 0x2d0 / 0x1e0 */ + PVOID pShimData; /**< 0x2d8 / 0x1e8 */ + PVOID AppCompatInfo; /**< 0x2e0 / 0x1ec */ + UNICODE_STRING CSDVersion; /**< 0x2e8 / 0x1f0 */ + struct _ACTIVATION_CONTEXT_DATA *ActivationContextData; /**< 0x2f8 / 0x1f8 */ + struct _ASSEMBLY_STORAGE_MAP *ProcessAssemblyStorageMap; /**< 0x300 / 0x1fc */ + struct _ACTIVATION_CONTEXT_DATA *SystemDefaultActivationContextData; /**< 0x308 / 0x200 */ + struct _ASSEMBLY_STORAGE_MAP *SystemAssemblyStorageMap; /**< 0x310 / 0x204 */ + SIZE_T MinimumStackCommit; /**< 0x318 / 0x208 */ + /* End of PEB in W52 (Windows XP (RTM))! */ + struct _FLS_CALLBACK_INFO *FlsCallback; /**< 0x320 / 0x20c */ + LIST_ENTRY FlsListHead; /**< 0x328 / 0x210 */ + PVOID FlsBitmap; /**< 0x338 / 0x218 */ + uint32_t FlsBitmapBits[4]; /**< 0x340 / 0x21c */ + uint32_t FlsHighIndex; /**< 0x350 / 0x22c */ + /* End of PEB in W52 (Windows Server 2003)! */ + PVOID WerRegistrationData; /**< 0x358 / 0x230 */ + PVOID WerShipAssertPtr; /**< 0x360 / 0x234 */ + /* End of PEB in W6 (windows Vista)! */ + union + { + struct + { + PVOID pUnused; /**< 0x368 / 0x238 - Was pContextData in W7. */ + } W8, W80, W81; + struct + { + PVOID pContextData; /**< 0x368 / 0x238 - Retired in W80. */ + } W7; + } Diff6; + PVOID pImageHeaderHash; /**< 0x370 / 0x23c */ + union + { + uint32_t TracingFlags; /**< 0x378 / 0x240 */ + struct + { + uint32_t HeapTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 0, 1 Bit */ + uint32_t CritSecTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 1, 1 Bit */ + uint32_t LibLoaderTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 2, 1 Bit */ + uint32_t SpareTracingBits : 29; /**< 0x378 / 0x240 : Pos 3, 29 Bits */ + } W8, W80, W81; + struct + { + uint32_t HeapTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 0, 1 Bit */ + uint32_t CritSecTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 1, 1 Bit */ + uint32_t SpareTracingBits : 30; /**< 0x378 / 0x240 : Pos 3, 30 Bits - One bit more than W80 */ + } W7; + } Diff7; +#if ARCH_BITS == 64 + uint32_t Padding6; /**< 0x37c / NA */ +#endif + uint64_t CsrServerReadOnlySharedMemoryBase; /**< 0x380 / 0x248 */ + /* End of PEB in W8, W81. */ + uintptr_t TppWorkerpListLock; /**< 0x388 / 0x250 */ + LIST_ENTRY TppWorkerpList; /**< 0x390 / 0x254 */ + PVOID WaitOnAddressHashTable[128]; /**< 0x3a0 / 0x25c */ +#if ARCH_BITS == 32 + uint32_t ExplicitPadding7; /**< NA NA / 0x45c */ +#endif +} PEB_COMMON; +typedef PEB_COMMON *PPEB_COMMON; + +AssertCompileMemberOffset(PEB_COMMON, ProcessHeap, ARCH_BITS == 64 ? 0x30 : 0x18); +AssertCompileMemberOffset(PEB_COMMON, SystemReserved, ARCH_BITS == 64 ? 0x60 : 0x30); +AssertCompileMemberOffset(PEB_COMMON, TlsExpansionCounter, ARCH_BITS == 64 ? 0x70 : 0x3c); +AssertCompileMemberOffset(PEB_COMMON, NtGlobalFlag, ARCH_BITS == 64 ? 0xbc : 0x68); +AssertCompileMemberOffset(PEB_COMMON, LoaderLock, ARCH_BITS == 64 ? 0x110 : 0xa0); +AssertCompileMemberOffset(PEB_COMMON, Diff5.W52.ImageProcessAffinityMask, ARCH_BITS == 64 ? 0x138 : 0xc0); +AssertCompileMemberOffset(PEB_COMMON, PostProcessInitRoutine, ARCH_BITS == 64 ? 0x230 : 0x14c); +AssertCompileMemberOffset(PEB_COMMON, AppCompatFlags, ARCH_BITS == 64 ? 0x2c8 : 0x1d8); +AssertCompileSize(PEB_COMMON, ARCH_BITS == 64 ? 0x7a0 : 0x460); + +/** The size of the windows 10 (build 14393) PEB structure. */ +#define PEB_SIZE_W10 sizeof(PEB_COMMON) +/** The size of the windows 8.1 PEB structure. */ +#define PEB_SIZE_W81 RT_UOFFSETOF(PEB_COMMON, TppWorkerpListLock) +/** The size of the windows 8.0 PEB structure. */ +#define PEB_SIZE_W80 RT_UOFFSETOF(PEB_COMMON, TppWorkerpListLock) +/** The size of the windows 7 PEB structure. */ +#define PEB_SIZE_W7 RT_UOFFSETOF(PEB_COMMON, CsrServerReadOnlySharedMemoryBase) +/** The size of the windows vista PEB structure. */ +#define PEB_SIZE_W6 RT_UOFFSETOF(PEB_COMMON, Diff3) +/** The size of the windows server 2003 PEB structure. */ +#define PEB_SIZE_W52 RT_UOFFSETOF(PEB_COMMON, WerRegistrationData) +/** The size of the windows XP PEB structure. */ +#define PEB_SIZE_W51 RT_UOFFSETOF(PEB_COMMON, FlsCallback) + +#if 0 +typedef struct _NT_TIB +{ + struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; + PVOID StackBase; + PVOID StackLimit; + PVOID SubSystemTib; + union + { + PVOID FiberData; + ULONG Version; + }; + PVOID ArbitraryUserPointer; + struct _NT_TIB *Self; +} NT_TIB; +typedef NT_TIB *PNT_TIB; +#endif + +typedef struct _ACTIVATION_CONTEXT_STACK +{ + uint32_t Flags; + uint32_t NextCookieSequenceNumber; + PVOID ActiveFrame; + LIST_ENTRY FrameListCache; +} ACTIVATION_CONTEXT_STACK; + +/* Common TEB. */ +typedef struct _TEB_COMMON +{ + NT_TIB NtTib; /**< 0x000 / 0x000 */ + PVOID EnvironmentPointer; /**< 0x038 / 0x01c */ + CLIENT_ID ClientId; /**< 0x040 / 0x020 */ + PVOID ActiveRpcHandle; /**< 0x050 / 0x028 */ + PVOID ThreadLocalStoragePointer; /**< 0x058 / 0x02c */ + PPEB_COMMON ProcessEnvironmentBlock; /**< 0x060 / 0x030 */ + uint32_t LastErrorValue; /**< 0x068 / 0x034 */ + uint32_t CountOfOwnedCriticalSections; /**< 0x06c / 0x038 */ + PVOID CsrClientThread; /**< 0x070 / 0x03c */ + PVOID Win32ThreadInfo; /**< 0x078 / 0x040 */ + uint32_t User32Reserved[26]; /**< 0x080 / 0x044 */ + uint32_t UserReserved[5]; /**< 0x0e8 / 0x0ac */ + PVOID WOW32Reserved; /**< 0x100 / 0x0c0 */ + uint32_t CurrentLocale; /**< 0x108 / 0x0c4 */ + uint32_t FpSoftwareStatusRegister; /**< 0x10c / 0x0c8 */ + PVOID SystemReserved1[54]; /**< 0x110 / 0x0cc */ + uint32_t ExceptionCode; /**< 0x2c0 / 0x1a4 */ +#if ARCH_BITS == 64 + uint32_t Padding0; /**< 0x2c4 / NA */ +#endif + union + { + struct + { + struct _ACTIVATION_CONTEXT_STACK *ActivationContextStackPointer;/**< 0x2c8 / 0x1a8 */ + uint8_t SpareBytes[ARCH_BITS == 64 ? 24 : 36]; /**< 0x2d0 / 0x1ac */ + } W52, W6, W7, W8, W80, W81; +#if ARCH_BITS == 32 + struct + { + ACTIVATION_CONTEXT_STACK ActivationContextStack; /**< NA / 0x1a8 */ + uint8_t SpareBytes[20]; /**< NA / 0x1bc */ + } W51; +#endif + } Diff0; + union + { + struct + { + uint32_t TxFsContext; /**< 0x2e8 / 0x1d0 */ + } W6, W7, W8, W80, W81; + struct + { + uint32_t SpareBytesContinues; /**< 0x2e8 / 0x1d0 */ + } W52; + } Diff1; +#if ARCH_BITS == 64 + uint32_t Padding1; /**< 0x2ec / NA */ +#endif + /*_GDI_TEB_BATCH*/ uint8_t GdiTebBatch[ARCH_BITS == 64 ? 0x4e8 :0x4e0]; /**< 0x2f0 / 0x1d4 */ + CLIENT_ID RealClientId; /**< 0x7d8 / 0x6b4 */ + HANDLE GdiCachedProcessHandle; /**< 0x7e8 / 0x6bc */ + uint32_t GdiClientPID; /**< 0x7f0 / 0x6c0 */ + uint32_t GdiClientTID; /**< 0x7f4 / 0x6c4 */ + PVOID GdiThreadLocalInfo; /**< 0x7f8 / 0x6c8 */ + SIZE_T Win32ClientInfo[62]; /**< 0x800 / 0x6cc */ + PVOID glDispatchTable[233]; /**< 0x9f0 / 0x7c4 */ + SIZE_T glReserved1[29]; /**< 0x1138 / 0xb68 */ + PVOID glReserved2; /**< 0x1220 / 0xbdc */ + PVOID glSectionInfo; /**< 0x1228 / 0xbe0 */ + PVOID glSection; /**< 0x1230 / 0xbe4 */ + PVOID glTable; /**< 0x1238 / 0xbe8 */ + PVOID glCurrentRC; /**< 0x1240 / 0xbec */ + PVOID glContext; /**< 0x1248 / 0xbf0 */ + NTSTATUS LastStatusValue; /**< 0x1250 / 0xbf4 */ +#if ARCH_BITS == 64 + uint32_t Padding2; /**< 0x1254 / NA */ +#endif + UNICODE_STRING StaticUnicodeString; /**< 0x1258 / 0xbf8 */ + WCHAR StaticUnicodeBuffer[261]; /**< 0x1268 / 0xc00 */ +#if ARCH_BITS == 64 + WCHAR Padding3[3]; /**< 0x1472 / NA */ +#endif + PVOID DeallocationStack; /**< 0x1478 / 0xe0c */ + PVOID TlsSlots[64]; /**< 0x1480 / 0xe10 */ + LIST_ENTRY TlsLinks; /**< 0x1680 / 0xf10 */ + PVOID Vdm; /**< 0x1690 / 0xf18 */ + PVOID ReservedForNtRpc; /**< 0x1698 / 0xf1c */ + PVOID DbgSsReserved[2]; /**< 0x16a0 / 0xf20 */ + uint32_t HardErrorMode; /**< 0x16b0 / 0xf28 - Called HardErrorsAreDisabled in W51. */ +#if ARCH_BITS == 64 + uint32_t Padding4; /**< 0x16b4 / NA */ +#endif + PVOID Instrumentation[ARCH_BITS == 64 ? 11 : 9]; /**< 0x16b8 / 0xf2c */ + union + { + struct + { + GUID ActivityId; /**< 0x1710 / 0xf50 */ + PVOID SubProcessTag; /**< 0x1720 / 0xf60 */ + } W6, W7, W8, W80, W81; + struct + { + PVOID InstrumentationContinues[ARCH_BITS == 64 ? 3 : 5]; /**< 0x1710 / 0xf50 */ + } W52; + } Diff2; + union /**< 0x1728 / 0xf64 */ + { + struct + { + PVOID PerflibData; /**< 0x1728 / 0xf64 */ + } W8, W80, W81; + struct + { + PVOID EtwLocalData; /**< 0x1728 / 0xf64 */ + } W7, W6; + struct + { + PVOID SubProcessTag; /**< 0x1728 / 0xf64 */ + } W52; + struct + { + PVOID InstrumentationContinues[1]; /**< 0x1728 / 0xf64 */ + } W51; + } Diff3; + union + { + struct + { + PVOID EtwTraceData; /**< 0x1730 / 0xf68 */ + } W52, W6, W7, W8, W80, W81; + struct + { + PVOID InstrumentationContinues[1]; /**< 0x1730 / 0xf68 */ + } W51; + } Diff4; + PVOID WinSockData; /**< 0x1738 / 0xf6c */ + uint32_t GdiBatchCount; /**< 0x1740 / 0xf70 */ + union + { + union + { + PROCESSOR_NUMBER CurrentIdealProcessor; /**< 0x1744 / 0xf74 - W7+ */ + uint32_t IdealProcessorValue; /**< 0x1744 / 0xf74 - W7+ */ + struct + { + uint8_t ReservedPad1; /**< 0x1744 / 0xf74 - Called SpareBool0 in W6 */ + uint8_t ReservedPad2; /**< 0x1745 / 0xf75 - Called SpareBool0 in W6 */ + uint8_t ReservedPad3; /**< 0x1746 / 0xf76 - Called SpareBool0 in W6 */ + uint8_t IdealProcessor; /**< 0x1747 / 0xf77 */ + }; + } W6, W7, W8, W80, W81; + struct + { + BOOLEAN InDbgPrint; /**< 0x1744 / 0xf74 */ + BOOLEAN FreeStackOnTermination; /**< 0x1745 / 0xf75 */ + BOOLEAN HasFiberData; /**< 0x1746 / 0xf76 */ + uint8_t IdealProcessor; /**< 0x1747 / 0xf77 */ + } W51, W52; + } Diff5; + uint32_t GuaranteedStackBytes; /**< 0x1748 / 0xf78 */ +#if ARCH_BITS == 64 + uint32_t Padding5; /**< 0x174c / NA */ +#endif + PVOID ReservedForPerf; /**< 0x1750 / 0xf7c */ + PVOID ReservedForOle; /**< 0x1758 / 0xf80 */ + uint32_t WaitingOnLoaderLock; /**< 0x1760 / 0xf84 */ +#if ARCH_BITS == 64 + uint32_t Padding6; /**< 0x1764 / NA */ +#endif + union /**< 0x1770 / 0xf8c */ + { + struct + { + PVOID SavedPriorityState; /**< 0x1768 / 0xf88 */ + SIZE_T ReservedForCodeCoverage; /**< 0x1770 / 0xf8c */ + PVOID ThreadPoolData; /**< 0x1778 / 0xf90 */ + } W8, W80, W81; + struct + { + PVOID SavedPriorityState; /**< 0x1768 / 0xf88 */ + SIZE_T SoftPatchPtr1; /**< 0x1770 / 0xf8c */ + PVOID ThreadPoolData; /**< 0x1778 / 0xf90 */ + } W6, W7; + struct + { + PVOID SparePointer1; /**< 0x1768 / 0xf88 */ + SIZE_T SoftPatchPtr1; /**< 0x1770 / 0xf8c */ + PVOID SoftPatchPtr2; /**< 0x1778 / 0xf90 */ + } W52; +#if ARCH_BITS == 32 + struct _Wx86ThreadState + { + PVOID CallBx86Eip; /**< NA / 0xf88 */ + PVOID DeallocationCpu; /**< NA / 0xf8c */ + BOOLEAN UseKnownWx86Dll; /**< NA / 0xf90 */ + int8_t OleStubInvoked; /**< NA / 0xf91 */ + } W51; +#endif + } Diff6; + PVOID TlsExpansionSlots; /**< 0x1780 / 0xf94 */ +#if ARCH_BITS == 64 + PVOID DallocationBStore; /**< 0x1788 / NA */ + PVOID BStoreLimit; /**< 0x1790 / NA */ +#endif + union + { + struct + { + uint32_t MuiGeneration; /**< 0x1798 / 0xf98 */ + } W7, W8, W80, W81; + struct + { + uint32_t ImpersonationLocale; + } W6; + } Diff7; + uint32_t IsImpersonating; /**< 0x179c / 0xf9c */ + PVOID NlsCache; /**< 0x17a0 / 0xfa0 */ + PVOID pShimData; /**< 0x17a8 / 0xfa4 */ + union /**< 0x17b0 / 0xfa8 */ + { + struct + { + uint16_t HeapVirtualAffinity; /**< 0x17b0 / 0xfa8 */ + uint16_t LowFragHeapDataSlot; /**< 0x17b2 / 0xfaa */ + } W8, W80, W81; + struct + { + uint32_t HeapVirtualAffinity; /**< 0x17b0 / 0xfa8 */ + } W7; + } Diff8; +#if ARCH_BITS == 64 + uint32_t Padding7; /**< 0x17b4 / NA */ +#endif + HANDLE CurrentTransactionHandle; /**< 0x17b8 / 0xfac */ + struct _TEB_ACTIVE_FRAME *ActiveFrame; /**< 0x17c0 / 0xfb0 */ + /* End of TEB in W51 (Windows XP)! */ + PVOID FlsData; /**< 0x17c8 / 0xfb4 */ + union + { + struct + { + PVOID PreferredLanguages; /**< 0x17d0 / 0xfb8 */ + } W6, W7, W8, W80, W81; + struct + { + BOOLEAN SafeThunkCall; /**< 0x17d0 / 0xfb8 */ + uint8_t BooleanSpare[3]; /**< 0x17d1 / 0xfb9 */ + /* End of TEB in W52 (Windows server 2003)! */ + } W52; + } Diff9; + PVOID UserPrefLanguages; /**< 0x17d8 / 0xfbc */ + PVOID MergedPrefLanguages; /**< 0x17e0 / 0xfc0 */ + uint32_t MuiImpersonation; /**< 0x17e8 / 0xfc4 */ + union + { + uint16_t CrossTebFlags; /**< 0x17ec / 0xfc8 */ + struct + { + uint16_t SpareCrossTebBits : 16; /**< 0x17ec / 0xfc8 : Pos 0, 16 Bits */ + }; + }; + union + { + uint16_t SameTebFlags; /**< 0x17ee / 0xfca */ + struct + { + uint16_t SafeThunkCall : 1; /**< 0x17ee / 0xfca : Pos 0, 1 Bit */ + uint16_t InDebugPrint : 1; /**< 0x17ee / 0xfca : Pos 1, 1 Bit */ + uint16_t HasFiberData : 1; /**< 0x17ee / 0xfca : Pos 2, 1 Bit */ + uint16_t SkipThreadAttach : 1; /**< 0x17ee / 0xfca : Pos 3, 1 Bit */ + uint16_t WerInShipAssertCode : 1; /**< 0x17ee / 0xfca : Pos 4, 1 Bit */ + uint16_t RanProcessInit : 1; /**< 0x17ee / 0xfca : Pos 5, 1 Bit */ + uint16_t ClonedThread : 1; /**< 0x17ee / 0xfca : Pos 6, 1 Bit */ + uint16_t SuppressDebugMsg : 1; /**< 0x17ee / 0xfca : Pos 7, 1 Bit */ + } Common; + struct + { + uint16_t SafeThunkCall : 1; /**< 0x17ee / 0xfca : Pos 0, 1 Bit */ + uint16_t InDebugPrint : 1; /**< 0x17ee / 0xfca : Pos 1, 1 Bit */ + uint16_t HasFiberData : 1; /**< 0x17ee / 0xfca : Pos 2, 1 Bit */ + uint16_t SkipThreadAttach : 1; /**< 0x17ee / 0xfca : Pos 3, 1 Bit */ + uint16_t WerInShipAssertCode : 1; /**< 0x17ee / 0xfca : Pos 4, 1 Bit */ + uint16_t RanProcessInit : 1; /**< 0x17ee / 0xfca : Pos 5, 1 Bit */ + uint16_t ClonedThread : 1; /**< 0x17ee / 0xfca : Pos 6, 1 Bit */ + uint16_t SuppressDebugMsg : 1; /**< 0x17ee / 0xfca : Pos 7, 1 Bit */ + uint16_t DisableUserStackWalk : 1; /**< 0x17ee / 0xfca : Pos 8, 1 Bit */ + uint16_t RtlExceptionAttached : 1; /**< 0x17ee / 0xfca : Pos 9, 1 Bit */ + uint16_t InitialThread : 1; /**< 0x17ee / 0xfca : Pos 10, 1 Bit */ + uint16_t SessionAware : 1; /**< 0x17ee / 0xfca : Pos 11, 1 Bit - New Since W7. */ + uint16_t SpareSameTebBits : 4; /**< 0x17ee / 0xfca : Pos 12, 4 Bits */ + } W8, W80, W81; + struct + { + uint16_t SafeThunkCall : 1; /**< 0x17ee / 0xfca : Pos 0, 1 Bit */ + uint16_t InDebugPrint : 1; /**< 0x17ee / 0xfca : Pos 1, 1 Bit */ + uint16_t HasFiberData : 1; /**< 0x17ee / 0xfca : Pos 2, 1 Bit */ + uint16_t SkipThreadAttach : 1; /**< 0x17ee / 0xfca : Pos 3, 1 Bit */ + uint16_t WerInShipAssertCode : 1; /**< 0x17ee / 0xfca : Pos 4, 1 Bit */ + uint16_t RanProcessInit : 1; /**< 0x17ee / 0xfca : Pos 5, 1 Bit */ + uint16_t ClonedThread : 1; /**< 0x17ee / 0xfca : Pos 6, 1 Bit */ + uint16_t SuppressDebugMsg : 1; /**< 0x17ee / 0xfca : Pos 7, 1 Bit */ + uint16_t DisableUserStackWalk : 1; /**< 0x17ee / 0xfca : Pos 8, 1 Bit */ + uint16_t RtlExceptionAttached : 1; /**< 0x17ee / 0xfca : Pos 9, 1 Bit */ + uint16_t InitialThread : 1; /**< 0x17ee / 0xfca : Pos 10, 1 Bit */ + uint16_t SpareSameTebBits : 5; /**< 0x17ee / 0xfca : Pos 12, 4 Bits */ + } W7; + struct + { + uint16_t DbgSafeThunkCall : 1; /**< 0x17ee / 0xfca : Pos 0, 1 Bit */ + uint16_t DbgInDebugPrint : 1; /**< 0x17ee / 0xfca : Pos 1, 1 Bit */ + uint16_t DbgHasFiberData : 1; /**< 0x17ee / 0xfca : Pos 2, 1 Bit */ + uint16_t DbgSkipThreadAttach : 1; /**< 0x17ee / 0xfca : Pos 3, 1 Bit */ + uint16_t DbgWerInShipAssertCode : 1; /**< 0x17ee / 0xfca : Pos 4, 1 Bit */ + uint16_t DbgRanProcessInit : 1; /**< 0x17ee / 0xfca : Pos 5, 1 Bit */ + uint16_t DbgClonedThread : 1; /**< 0x17ee / 0xfca : Pos 6, 1 Bit */ + uint16_t DbgSuppressDebugMsg : 1; /**< 0x17ee / 0xfca : Pos 7, 1 Bit */ + uint16_t SpareSameTebBits : 8; /**< 0x17ee / 0xfca : Pos 8, 8 Bits */ + } W6; + } Diff10; + PVOID TxnScopeEnterCallback; /**< 0x17f0 / 0xfcc */ + PVOID TxnScopeExitCallback; /**< 0x17f8 / 0xfd0 */ + PVOID TxnScopeContext; /**< 0x1800 / 0xfd4 */ + uint32_t LockCount; /**< 0x1808 / 0xfd8 */ + union + { + struct + { + uint32_t SpareUlong0; /**< 0x180c / 0xfdc */ + } W7, W8, W80, W81; + struct + { + uint32_t ProcessRundown; + } W6; + } Diff11; + union + { + struct + { + PVOID ResourceRetValue; /**< 0x1810 / 0xfe0 */ + /* End of TEB in W7 (windows 7)! */ + PVOID ReservedForWdf; /**< 0x1818 / 0xfe4 - New Since W7. */ + /* End of TEB in W8 (windows 8.0 & 8.1)! */ + PVOID ReservedForCrt; /**< 0x1820 / 0xfe8 - New Since W10. */ + RTUUID EffectiveContainerId; /**< 0x1828 / 0xfec - New Since W10. */ + /* End of TEB in W10 14393! */ + } W8, W80, W81, W10; + struct + { + PVOID ResourceRetValue; /**< 0x1810 / 0xfe0 */ + } W7; + struct + { + uint64_t LastSwitchTime; /**< 0x1810 / 0xfe0 */ + uint64_t TotalSwitchOutTime; /**< 0x1818 / 0xfe8 */ + LARGE_INTEGER WaitReasonBitMap; /**< 0x1820 / 0xff0 */ + /* End of TEB in W6 (windows Vista)! */ + } W6; + } Diff12; +} TEB_COMMON; +typedef TEB_COMMON *PTEB_COMMON; +AssertCompileMemberOffset(TEB_COMMON, ExceptionCode, ARCH_BITS == 64 ? 0x2c0 : 0x1a4); +AssertCompileMemberOffset(TEB_COMMON, LastStatusValue, ARCH_BITS == 64 ? 0x1250 : 0xbf4); +AssertCompileMemberOffset(TEB_COMMON, DeallocationStack, ARCH_BITS == 64 ? 0x1478 : 0xe0c); +AssertCompileMemberOffset(TEB_COMMON, ReservedForNtRpc, ARCH_BITS == 64 ? 0x1698 : 0xf1c); +AssertCompileMemberOffset(TEB_COMMON, Instrumentation, ARCH_BITS == 64 ? 0x16b8 : 0xf2c); +AssertCompileMemberOffset(TEB_COMMON, Diff2, ARCH_BITS == 64 ? 0x1710 : 0xf50); +AssertCompileMemberOffset(TEB_COMMON, Diff3, ARCH_BITS == 64 ? 0x1728 : 0xf64); +AssertCompileMemberOffset(TEB_COMMON, Diff4, ARCH_BITS == 64 ? 0x1730 : 0xf68); +AssertCompileMemberOffset(TEB_COMMON, WinSockData, ARCH_BITS == 64 ? 0x1738 : 0xf6c); +AssertCompileMemberOffset(TEB_COMMON, GuaranteedStackBytes, ARCH_BITS == 64 ? 0x1748 : 0xf78); +AssertCompileMemberOffset(TEB_COMMON, MuiImpersonation, ARCH_BITS == 64 ? 0x17e8 : 0xfc4); +AssertCompileMemberOffset(TEB_COMMON, LockCount, ARCH_BITS == 64 ? 0x1808 : 0xfd8); +AssertCompileSize(TEB_COMMON, ARCH_BITS == 64 ? 0x1838 : 0x1000); + + +/** The size of the windows 8.1 PEB structure. */ +#define TEB_SIZE_W10 ( RT_UOFFSETOF(TEB_COMMON, Diff12.W10.EffectiveContainerId) + sizeof(RTUUID) ) +/** The size of the windows 8.1 PEB structure. */ +#define TEB_SIZE_W81 ( RT_UOFFSETOF(TEB_COMMON, Diff12.W8.ReservedForWdf) + sizeof(PVOID) ) +/** The size of the windows 8.0 PEB structure. */ +#define TEB_SIZE_W80 ( RT_UOFFSETOF(TEB_COMMON, Diff12.W8.ReservedForWdf) + sizeof(PVOID) ) +/** The size of the windows 7 PEB structure. */ +#define TEB_SIZE_W7 RT_UOFFSETOF(TEB_COMMON, Diff12.W8.ReservedForWdf) +/** The size of the windows vista PEB structure. */ +#define TEB_SIZE_W6 ( RT_UOFFSETOF(TEB_COMMON, Diff12.W6.WaitReasonBitMap) + sizeof(LARGE_INTEGER) ) +/** The size of the windows server 2003 PEB structure. */ +#define TEB_SIZE_W52 RT_ALIGN_Z(RT_UOFFSETOF(TEB_COMMON, Diff9.W52.BooleanSpare), sizeof(PVOID)) +/** The size of the windows XP PEB structure. */ +#define TEB_SIZE_W51 RT_UOFFSETOF(TEB_COMMON, FlsData) + + + +#define _PEB _PEB_COMMON +typedef PEB_COMMON PEB; +typedef PPEB_COMMON PPEB; + +#define _TEB _TEB_COMMON +typedef TEB_COMMON TEB; +typedef PTEB_COMMON PTEB; + +#if !defined(NtCurrentTeb) && !defined(IPRT_NT_HAVE_CURRENT_TEB_MACRO) +# ifdef RT_ARCH_X86 +DECL_FORCE_INLINE(PTEB) RTNtCurrentTeb(void) { return (PTEB)__readfsdword(RT_UOFFSETOF(TEB_COMMON, NtTib.Self)); } +DECL_FORCE_INLINE(PPEB) RTNtCurrentPeb(void) { return (PPEB)__readfsdword(RT_UOFFSETOF(TEB_COMMON, ProcessEnvironmentBlock)); } +DECL_FORCE_INLINE(uint32_t) RTNtCurrentThreadId(void) { return __readfsdword(RT_UOFFSETOF(TEB_COMMON, ClientId.UniqueThread)); } +DECL_FORCE_INLINE(NTSTATUS) RTNtLastStatusValue(void) { return (NTSTATUS)__readfsdword(RT_UOFFSETOF(TEB_COMMON, LastStatusValue)); } +DECL_FORCE_INLINE(uint32_t) RTNtLastErrorValue(void) { return __readfsdword(RT_UOFFSETOF(TEB_COMMON, LastErrorValue)); } +# elif defined(RT_ARCH_AMD64) +DECL_FORCE_INLINE(PTEB) RTNtCurrentTeb(void) { return (PTEB)__readgsqword(RT_UOFFSETOF(TEB_COMMON, NtTib.Self)); } +DECL_FORCE_INLINE(PPEB) RTNtCurrentPeb(void) { return (PPEB)__readgsqword(RT_UOFFSETOF(TEB_COMMON, ProcessEnvironmentBlock)); } +DECL_FORCE_INLINE(uint32_t) RTNtCurrentThreadId(void) { return __readgsdword(RT_UOFFSETOF(TEB_COMMON, ClientId.UniqueThread)); } +DECL_FORCE_INLINE(NTSTATUS) RTNtLastStatusValue(void) { return (NTSTATUS)__readgsdword(RT_UOFFSETOF(TEB_COMMON, LastStatusValue)); } +DECL_FORCE_INLINE(uint32_t) RTNtLastErrorValue(void) { return __readgsdword(RT_UOFFSETOF(TEB_COMMON, LastErrorValue)); } +# else +# error "Port me" +# endif +#else +# define RTNtCurrentTeb() ((PTEB)NtCurrentTeb()) +# define RTNtCurrentPeb() (RTNtCurrentTeb()->ProcessEnvironmentBlock) +# define RTNtCurrentThreadId() ((uint32_t)(uintptr_t)RTNtCurrentTeb()->ClientId.UniqueThread) +# define RTNtLastStatusValue() (RTNtCurrentTeb()->LastStatusValue) +# define RTNtLastErrorValue() (RTNtCurrentTeb()->LastErrorValue) +#endif +#define NtCurrentPeb() RTNtCurrentPeb() + +#ifdef IN_RING3 +RT_DECL_NTAPI(void) RtlAcquirePebLock(void); +RT_DECL_NTAPI(void) RtlReleasePebLock(void); +#endif + +/** @} */ + + +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtCreateSection(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PLARGE_INTEGER, ULONG, ULONG, HANDLE); +typedef enum _SECTION_INHERIT +{ + ViewShare = 1, + ViewUnmap +} SECTION_INHERIT; +#endif +RT_DECL_NTAPI(NTSTATUS) NtMapViewOfSection(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, PLARGE_INTEGER, PSIZE_T, SECTION_INHERIT, + ULONG, ULONG); +RT_DECL_NTAPI(NTSTATUS) NtFlushVirtualMemory(HANDLE, PVOID *, PSIZE_T, PIO_STATUS_BLOCK); +RT_DECL_NTAPI(NTSTATUS) NtUnmapViewOfSection(HANDLE, PVOID); + +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtOpenProcess(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID); +RT_DECL_NTAPI(NTSTATUS) ZwOpenProcess(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID); +#endif +RT_DECL_NTAPI(NTSTATUS) NtOpenThread(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID); +RT_DECL_NTAPI(NTSTATUS) ZwOpenThread(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID); +RT_DECL_NTAPI(NTSTATUS) NtAlertThread(HANDLE hThread); +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) ZwAlertThread(HANDLE hThread); +#endif +RT_DECL_NTAPI(NTSTATUS) NtTestAlert(void); + +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtOpenProcessToken(HANDLE, ACCESS_MASK, PHANDLE); +RT_DECL_NTAPI(NTSTATUS) NtOpenThreadToken(HANDLE, ACCESS_MASK, BOOLEAN, PHANDLE); +#endif +RT_DECL_NTAPI(NTSTATUS) ZwOpenProcessToken(HANDLE, ACCESS_MASK, PHANDLE); +RT_DECL_NTAPI(NTSTATUS) ZwOpenThreadToken(HANDLE, ACCESS_MASK, BOOLEAN, PHANDLE); + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _FILE_FS_VOLUME_INFORMATION +{ + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[1]; +} FILE_FS_VOLUME_INFORMATION; +typedef FILE_FS_VOLUME_INFORMATION *PFILE_FS_VOLUME_INFORMATION; +typedef struct _FILE_FS_LABEL_INFORMATION +{ + ULONG VolumeLabelLength; + WCHAR VolumeLabel[1]; +} FILE_FS_LABEL_INFORMATION; +typedef FILE_FS_LABEL_INFORMATION *PFILE_FS_LABEL_INFORMATION; +typedef struct _FILE_FS_SIZE_INFORMATION +{ + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER AvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_SIZE_INFORMATION; +typedef FILE_FS_SIZE_INFORMATION *PFILE_FS_SIZE_INFORMATION; +typedef struct _FILE_FS_DEVICE_INFORMATION +{ + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION; +typedef FILE_FS_DEVICE_INFORMATION *PFILE_FS_DEVICE_INFORMATION; +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION +{ + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION; +typedef FILE_FS_ATTRIBUTE_INFORMATION *PFILE_FS_ATTRIBUTE_INFORMATION; +typedef struct _FILE_FS_CONTROL_INFORMATION +{ + LARGE_INTEGER FreeSpaceStartFiltering; + LARGE_INTEGER FreeSpaceThreshold; + LARGE_INTEGER FreeSpaceStopFiltering; + LARGE_INTEGER DefaultQuotaThreshold; + LARGE_INTEGER DefaultQuotaLimit; + ULONG FileSystemControlFlags; +} FILE_FS_CONTROL_INFORMATION; +typedef FILE_FS_CONTROL_INFORMATION *PFILE_FS_CONTROL_INFORMATION; +typedef struct _FILE_FS_FULL_SIZE_INFORMATION +{ + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER CallerAvailableAllocationUnits; + LARGE_INTEGER ActualAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION; +typedef FILE_FS_FULL_SIZE_INFORMATION *PFILE_FS_FULL_SIZE_INFORMATION; +typedef struct _FILE_FS_OBJECTID_INFORMATION +{ + UCHAR ObjectId[16]; + UCHAR ExtendedInfo[48]; +} FILE_FS_OBJECTID_INFORMATION; +typedef FILE_FS_OBJECTID_INFORMATION *PFILE_FS_OBJECTID_INFORMATION; +typedef struct _FILE_FS_DRIVER_PATH_INFORMATION +{ + BOOLEAN DriverInPath; + ULONG DriverNameLength; + WCHAR DriverName[1]; +} FILE_FS_DRIVER_PATH_INFORMATION; +typedef FILE_FS_DRIVER_PATH_INFORMATION *PFILE_FS_DRIVER_PATH_INFORMATION; +typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION +{ + ULONG Flags; +} FILE_FS_VOLUME_FLAGS_INFORMATION; +typedef FILE_FS_VOLUME_FLAGS_INFORMATION *PFILE_FS_VOLUME_FLAGS_INFORMATION; +#endif +#if !defined(SSINFO_OFFSET_UNKNOWN) || defined(IPRT_NT_USE_WINTERNL) +typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION +{ + ULONG LogicalBytesPerSector; + ULONG PhysicalBytesPerSectorForAtomicity; + ULONG PhysicalBytesPerSectorForPerformance; + ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity; + ULONG Flags; + ULONG ByteOffsetForSectorAlignment; + ULONG ByteOffsetForPartitionAlignment; +} FILE_FS_SECTOR_SIZE_INFORMATION; +typedef FILE_FS_SECTOR_SIZE_INFORMATION *PFILE_FS_SECTOR_SIZE_INFORMATION; +# ifndef SSINFO_OFFSET_UNKNOWN +# define SSINFO_OFFSET_UNKNOWN 0xffffffffUL +# define SSINFO_FLAGS_ALIGNED_DEVICE 1UL +# define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 2UL +# define SSINFO_FLAGS_NO_SEEK_PENALTY 4UL +# define SSINFO_FLAGS_TRIM_ENABLED 8UL +# define SSINFO_FLAGS_BYTE_ADDRESSABLE 16UL +# endif +#endif +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _FILE_FS_DATA_COPY_INFORMATION +{ + ULONG NumberOfCopies; +} FILE_FS_DATA_COPY_INFORMATION; +typedef FILE_FS_DATA_COPY_INFORMATION *PFILE_FS_DATA_COPY_INFORMATION; +typedef struct _FILE_FS_METADATA_SIZE_INFORMATION +{ + LARGE_INTEGER TotalMetadataAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_METADATA_SIZE_INFORMATION; +typedef FILE_FS_METADATA_SIZE_INFORMATION *PFILE_FS_METADATA_SIZE_INFORMATION; +typedef struct _FILE_FS_FULL_SIZE_INFORMATION_EX +{ + ULONGLONG ActualTotalAllocationUnits; + ULONGLONG ActualAvailableAllocationUnits; + ULONGLONG ActualPoolUnavailableAllocationUnits; + ULONGLONG CallerTotalAllocationUnits; + ULONGLONG CallerAvailableAllocationUnits; + ULONGLONG CallerPoolUnavailableAllocationUnits; + ULONGLONG UsedAllocationUnits; + ULONGLONG TotalReservedAllocationUnits; + ULONGLONG VolumeStorageReserveAllocationUnits; + ULONGLONG AvailableCommittedAllocationUnits; + ULONGLONG PoolAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION_EX; +typedef FILE_FS_FULL_SIZE_INFORMATION_EX *PFILE_FS_FULL_SIZE_INFORMATION_EX; +#endif /* IPRT_NT_USE_WINTERNL */ + +typedef enum _FSINFOCLASS +{ + FileFsVolumeInformation = 1, + FileFsLabelInformation, + FileFsSizeInformation, /**< FILE_FS_SIZE_INFORMATION */ + FileFsDeviceInformation, + FileFsAttributeInformation, + FileFsControlInformation, + FileFsFullSizeInformation, + FileFsObjectIdInformation, + FileFsDriverPathInformation, + FileFsVolumeFlagsInformation, + FileFsSectorSizeInformation, + FileFsDataCopyInformation, + FileFsMetadataSizeInformation, + FileFsFullSizeInformationEx, + FileFsMaximumInformation +} FS_INFORMATION_CLASS; +typedef FS_INFORMATION_CLASS *PFS_INFORMATION_CLASS; +RT_DECL_NTAPI(NTSTATUS) NtQueryVolumeInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS); +RT_DECL_NTAPI(NTSTATUS) NtSetVolumeInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS); + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _FILE_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION; +typedef FILE_DIRECTORY_INFORMATION *PFILE_DIRECTORY_INFORMATION; +typedef struct _FILE_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; +} FILE_FULL_DIR_INFORMATION; +typedef FILE_FULL_DIR_INFORMATION *PFILE_FULL_DIR_INFORMATION; +typedef struct _FILE_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; /**< 0x00: */ + ULONG FileIndex; /**< 0x04: */ + LARGE_INTEGER CreationTime; /**< 0x08: */ + LARGE_INTEGER LastAccessTime; /**< 0x10: */ + LARGE_INTEGER LastWriteTime; /**< 0x18: */ + LARGE_INTEGER ChangeTime; /**< 0x20: */ + LARGE_INTEGER EndOfFile; /**< 0x28: */ + LARGE_INTEGER AllocationSize; /**< 0x30: */ + ULONG FileAttributes; /**< 0x38: */ + ULONG FileNameLength; /**< 0x3c: */ + ULONG EaSize; /**< 0x40: */ + CCHAR ShortNameLength; /**< 0x44: */ + WCHAR ShortName[12]; /**< 0x46: */ + WCHAR FileName[1]; /**< 0x5e: */ +} FILE_BOTH_DIR_INFORMATION; +typedef FILE_BOTH_DIR_INFORMATION *PFILE_BOTH_DIR_INFORMATION; +typedef struct _FILE_BASIC_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION; +typedef FILE_BASIC_INFORMATION *PFILE_BASIC_INFORMATION; +typedef struct _FILE_STANDARD_INFORMATION +{ + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION; +typedef FILE_STANDARD_INFORMATION *PFILE_STANDARD_INFORMATION; +typedef struct _FILE_NAME_INFORMATION +{ + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION; +typedef FILE_NAME_INFORMATION *PFILE_NAME_INFORMATION; +typedef FILE_NAME_INFORMATION FILE_NETWORK_PHYSICAL_NAME_INFORMATION; +typedef FILE_NETWORK_PHYSICAL_NAME_INFORMATION *PFILE_NETWORK_PHYSICAL_NAME_INFORMATION; +typedef struct _FILE_INTERNAL_INFORMATION +{ + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION; +typedef FILE_INTERNAL_INFORMATION *PFILE_INTERNAL_INFORMATION; +typedef struct _FILE_EA_INFORMATION +{ + ULONG EaSize; +} FILE_EA_INFORMATION; +typedef FILE_EA_INFORMATION *PFILE_EA_INFORMATION; +typedef struct _FILE_ACCESS_INFORMATION +{ + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION; +typedef FILE_ACCESS_INFORMATION *PFILE_ACCESS_INFORMATION; +typedef struct _FILE_RENAME_INFORMATION +{ + union + { + BOOLEAN ReplaceIfExists; + ULONG Flags; + }; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_RENAME_INFORMATION; +typedef FILE_RENAME_INFORMATION *PFILE_RENAME_INFORMATION; +typedef struct _FILE_LINK_INFORMATION +{ + union + { + BOOLEAN ReplaceIfExists; + ULONG Flags; + }; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_INFORMATION; +typedef FILE_LINK_INFORMATION *PFILE_LINK_INFORMATION; +typedef struct _FILE_NAMES_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAMES_INFORMATION; +typedef FILE_NAMES_INFORMATION *PFILE_NAMES_INFORMATION; +typedef struct _FILE_DISPOSITION_INFORMATION +{ + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION; +typedef FILE_DISPOSITION_INFORMATION *PFILE_DISPOSITION_INFORMATION; +typedef struct _FILE_POSITION_INFORMATION +{ + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION; +typedef FILE_POSITION_INFORMATION *PFILE_POSITION_INFORMATION; +typedef struct _FILE_FULL_EA_INFORMATION +{ + ULONG NextEntryOffset; + UCHAR Flags; + UCHAR EaNameLength; + USHORT EaValueLength; + CHAR EaName[1]; +} FILE_FULL_EA_INFORMATION; +typedef FILE_FULL_EA_INFORMATION *PFILE_FULL_EA_INFORMATION; +typedef struct _FILE_MODE_INFORMATION +{ + ULONG Mode; +} FILE_MODE_INFORMATION; +typedef FILE_MODE_INFORMATION *PFILE_MODE_INFORMATION; +typedef struct _FILE_ALIGNMENT_INFORMATION +{ + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION; +typedef FILE_ALIGNMENT_INFORMATION *PFILE_ALIGNMENT_INFORMATION; +typedef struct _FILE_ALL_INFORMATION +{ + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION; +typedef FILE_ALL_INFORMATION *PFILE_ALL_INFORMATION; +typedef struct _FILE_ALLOCATION_INFORMATION +{ + LARGE_INTEGER AllocationSize; +} FILE_ALLOCATION_INFORMATION; +typedef FILE_ALLOCATION_INFORMATION *PFILE_ALLOCATION_INFORMATION; +typedef struct _FILE_END_OF_FILE_INFORMATION +{ + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION; +typedef FILE_END_OF_FILE_INFORMATION *PFILE_END_OF_FILE_INFORMATION; +typedef struct _FILE_STREAM_INFORMATION +{ + ULONG NextEntryOffset; + ULONG StreamNameLength; + LARGE_INTEGER StreamSize; + LARGE_INTEGER StreamAllocationSize; + WCHAR StreamName[1]; +} FILE_STREAM_INFORMATION; +typedef FILE_STREAM_INFORMATION *PFILE_STREAM_INFORMATION; + +typedef struct _FILE_PIPE_INFORMATION +{ + ULONG ReadMode; + ULONG CompletionMode; +} FILE_PIPE_INFORMATION; +typedef FILE_PIPE_INFORMATION *PFILE_PIPE_INFORMATION; + +typedef struct _FILE_PIPE_LOCAL_INFORMATION +{ + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION; +typedef FILE_PIPE_LOCAL_INFORMATION *PFILE_PIPE_LOCAL_INFORMATION; + +/** @name Pipe state (FILE_PIPE_LOCAL_INFORMATION::NamedPipeState) + * @{ */ +#if !defined(FILE_PIPE_DISCONNECTED_STATE) || defined(DOXYGEN_RUNNING) +# define FILE_PIPE_DISCONNECTED_STATE 0x00000001U +# define FILE_PIPE_LISTENING_STATE 0x00000002U +# define FILE_PIPE_CONNECTED_STATE 0x00000003U +# define FILE_PIPE_CLOSING_STATE 0x00000004U +#endif +/** @} */ + +/** @name Pipe config (FILE_PIPE_LOCAL_INFORMATION::NamedPipeConfiguration) + * @{ */ +#if !defined(FILE_PIPE_INBOUND) || defined(DOXYGEN_RUNNING) +# define FILE_PIPE_INBOUND 0x00000000U +# define FILE_PIPE_OUTBOUND 0x00000001U +# define FILE_PIPE_FULL_DUPLEX 0x00000002U +#endif +/** @} */ + +/** @name Pipe end (FILE_PIPE_LOCAL_INFORMATION::NamedPipeEnd) + * @{ */ +#if !defined(FILE_PIPE_CLIENT_END) || defined(DOXYGEN_RUNNING) +# define FILE_PIPE_CLIENT_END 0x00000000U +# define FILE_PIPE_SERVER_END 0x00000001U +#endif +/** @} */ + +typedef struct _FILE_PIPE_REMOTE_INFORMATION +{ + LARGE_INTEGER CollectDataTime; + ULONG MaximumCollectionCount; +} FILE_PIPE_REMOTE_INFORMATION; +typedef FILE_PIPE_REMOTE_INFORMATION *PFILE_PIPE_REMOTE_INFORMATION; +typedef struct _FILE_MAILSLOT_QUERY_INFORMATION +{ + ULONG MaximumMessageSize; + ULONG MailslotQuota; + ULONG NextMessageSize; + ULONG MessagesAvailable; + LARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_QUERY_INFORMATION; +typedef FILE_MAILSLOT_QUERY_INFORMATION *PFILE_MAILSLOT_QUERY_INFORMATION; +typedef struct _FILE_MAILSLOT_SET_INFORMATION +{ + PLARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_SET_INFORMATION; +typedef FILE_MAILSLOT_SET_INFORMATION *PFILE_MAILSLOT_SET_INFORMATION; +typedef struct _FILE_COMPRESSION_INFORMATION +{ + LARGE_INTEGER CompressedFileSize; + USHORT CompressionFormat; + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved[3]; +} FILE_COMPRESSION_INFORMATION; +typedef FILE_COMPRESSION_INFORMATION *PFILE_COMPRESSION_INFORMATION; +typedef struct _FILE_OBJECTID_INFORMATION +{ + LONGLONG FileReference; + UCHAR ObjectId[16]; + union + { + struct + { + UCHAR BirthVolumeId[16]; + UCHAR BirthObjectId[16]; + UCHAR DomainId[16]; + }; + UCHAR ExtendedInfo[48]; + }; +} FILE_OBJECTID_INFORMATION; +typedef FILE_OBJECTID_INFORMATION *PFILE_OBJECTID_INFORMATION; +typedef struct _FILE_COMPLETION_INFORMATION +{ + HANDLE Port; + PVOID Key; +} FILE_COMPLETION_INFORMATION; +typedef FILE_COMPLETION_INFORMATION *PFILE_COMPLETION_INFORMATION; +typedef struct _FILE_MOVE_CLUSTER_INFORMATION +{ + ULONG ClusterCount; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_MOVE_CLUSTER_INFORMATION; +typedef FILE_MOVE_CLUSTER_INFORMATION *PFILE_MOVE_CLUSTER_INFORMATION; +typedef struct _FILE_QUOTA_INFORMATION +{ + ULONG NextEntryOffset; + ULONG SidLength; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER QuotaUsed; + LARGE_INTEGER QuotaThreshold; + LARGE_INTEGER QuotaLimit; + SID Sid; +} FILE_QUOTA_INFORMATION; +typedef FILE_QUOTA_INFORMATION *PFILE_QUOTA_INFORMATION; +typedef struct _FILE_REPARSE_POINT_INFORMATION +{ + LONGLONG FileReference; + ULONG Tag; +} FILE_REPARSE_POINT_INFORMATION; +typedef FILE_REPARSE_POINT_INFORMATION *PFILE_REPARSE_POINT_INFORMATION; +typedef struct _FILE_NETWORK_OPEN_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION; +typedef FILE_NETWORK_OPEN_INFORMATION *PFILE_NETWORK_OPEN_INFORMATION; +typedef struct _FILE_ATTRIBUTE_TAG_INFORMATION +{ + ULONG FileAttributes; + ULONG ReparseTag; +} FILE_ATTRIBUTE_TAG_INFORMATION; +typedef FILE_ATTRIBUTE_TAG_INFORMATION *PFILE_ATTRIBUTE_TAG_INFORMATION; +typedef struct _FILE_TRACKING_INFORMATION +{ + HANDLE DestinationFile; + ULONG ObjectInformationLength; + CHAR ObjectInformation[1]; +} FILE_TRACKING_INFORMATION; +typedef FILE_TRACKING_INFORMATION *PFILE_TRACKING_INFORMATION; +typedef struct _FILE_ID_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_BOTH_DIR_INFORMATION; +typedef FILE_ID_BOTH_DIR_INFORMATION *PFILE_ID_BOTH_DIR_INFORMATION; +typedef struct _FILE_ID_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_FULL_DIR_INFORMATION; +typedef FILE_ID_FULL_DIR_INFORMATION *PFILE_ID_FULL_DIR_INFORMATION; +typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION +{ + LARGE_INTEGER ValidDataLength; +} FILE_VALID_DATA_LENGTH_INFORMATION; +typedef FILE_VALID_DATA_LENGTH_INFORMATION *PFILE_VALID_DATA_LENGTH_INFORMATION; +typedef struct _FILE_IO_COMPLETION_NOTIFICATION_INFORMATION +{ + ULONG Flags; +} FILE_IO_COMPLETION_NOTIFICATION_INFORMATION; +typedef FILE_IO_COMPLETION_NOTIFICATION_INFORMATION *PFILE_IO_COMPLETION_NOTIFICATION_INFORMATION; +typedef enum _IO_PRIORITY_HINT +{ + IoPriorityVeryLow = 0, + IoPriorityLow, + IoPriorityNormal, + IoPriorityHigh, + IoPriorityCritical, + MaxIoPriorityTypes +} IO_PRIORITY_HINT; +AssertCompileSize(IO_PRIORITY_HINT, sizeof(int)); +typedef struct _FILE_IO_PRIORITY_HINT_INFORMATION +{ + IO_PRIORITY_HINT PriorityHint; +} FILE_IO_PRIORITY_HINT_INFORMATION; +typedef FILE_IO_PRIORITY_HINT_INFORMATION *PFILE_IO_PRIORITY_HINT_INFORMATION; +typedef struct _FILE_SFIO_RESERVE_INFORMATION +{ + ULONG RequestsPerPeriod; + ULONG Period; + BOOLEAN RetryFailures; + BOOLEAN Discardable; + ULONG RequestSize; + ULONG NumOutstandingRequests; +} FILE_SFIO_RESERVE_INFORMATION; +typedef FILE_SFIO_RESERVE_INFORMATION *PFILE_SFIO_RESERVE_INFORMATION; +typedef struct _FILE_SFIO_VOLUME_INFORMATION +{ + ULONG MaximumRequestsPerPeriod; + ULONG MinimumPeriod; + ULONG MinimumTransferSize; +} FILE_SFIO_VOLUME_INFORMATION; +typedef FILE_SFIO_VOLUME_INFORMATION *PFILE_SFIO_VOLUME_INFORMATION; +typedef struct _FILE_LINK_ENTRY_INFORMATION +{ + ULONG NextEntryOffset; + LONGLONG ParentFileId; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_ENTRY_INFORMATION; +typedef FILE_LINK_ENTRY_INFORMATION *PFILE_LINK_ENTRY_INFORMATION; +typedef struct _FILE_LINKS_INFORMATION +{ + ULONG BytesNeeded; + ULONG EntriesReturned; + FILE_LINK_ENTRY_INFORMATION Entry; +} FILE_LINKS_INFORMATION; +typedef FILE_LINKS_INFORMATION *PFILE_LINKS_INFORMATION; +typedef struct _FILE_PROCESS_IDS_USING_FILE_INFORMATION +{ + ULONG NumberOfProcessIdsInList; + ULONG_PTR ProcessIdList[1]; +} FILE_PROCESS_IDS_USING_FILE_INFORMATION; +typedef FILE_PROCESS_IDS_USING_FILE_INFORMATION *PFILE_PROCESS_IDS_USING_FILE_INFORMATION; +typedef struct _FILE_ID_GLOBAL_TX_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + LARGE_INTEGER FileId; + GUID LockingTransactionId; + ULONG TxInfoFlags; + WCHAR FileName[1]; +} FILE_ID_GLOBAL_TX_DIR_INFORMATION; +typedef FILE_ID_GLOBAL_TX_DIR_INFORMATION *PFILE_ID_GLOBAL_TX_DIR_INFORMATION; +typedef struct _FILE_IS_REMOTE_DEVICE_INFORMATION +{ + BOOLEAN IsRemote; +} FILE_IS_REMOTE_DEVICE_INFORMATION; +typedef FILE_IS_REMOTE_DEVICE_INFORMATION *PFILE_IS_REMOTE_DEVICE_INFORMATION; +typedef struct _FILE_NUMA_NODE_INFORMATION +{ + USHORT NodeNumber; +} FILE_NUMA_NODE_INFORMATION; +typedef FILE_NUMA_NODE_INFORMATION *PFILE_NUMA_NODE_INFORMATION; +typedef struct _FILE_STANDARD_LINK_INFORMATION +{ + ULONG NumberOfAccessibleLinks; + ULONG TotalNumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_LINK_INFORMATION; +typedef FILE_STANDARD_LINK_INFORMATION *PFILE_STANDARD_LINK_INFORMATION; +typedef struct _FILE_REMOTE_PROTOCOL_INFORMATION +{ + USHORT StructureVersion; + USHORT StructureSize; + ULONG Protocol; + USHORT ProtocolMajorVersion; + USHORT ProtocolMinorVersion; + USHORT ProtocolRevision; + USHORT Reserved; + ULONG Flags; + struct + { + ULONG Reserved[8]; + } GenericReserved; + struct + { + ULONG Reserved[16]; + } ProtocolSpecificReserved; +} FILE_REMOTE_PROTOCOL_INFORMATION; +typedef FILE_REMOTE_PROTOCOL_INFORMATION *PFILE_REMOTE_PROTOCOL_INFORMATION; +typedef struct _FILE_VOLUME_NAME_INFORMATION +{ + ULONG DeviceNameLength; + WCHAR DeviceName[1]; +} FILE_VOLUME_NAME_INFORMATION; +typedef FILE_VOLUME_NAME_INFORMATION *PFILE_VOLUME_NAME_INFORMATION; +# ifndef FILE_INVALID_FILE_ID +typedef struct _FILE_ID_128 +{ + BYTE Identifier[16]; +} FILE_ID_128; +typedef FILE_ID_128 *PFILE_ID_128; +# endif +typedef struct _FILE_ID_EXTD_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + WCHAR FileName[1]; +} FILE_ID_EXTD_DIR_INFORMATION; +typedef FILE_ID_EXTD_DIR_INFORMATION *PFILE_ID_EXTD_DIR_INFORMATION; +typedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_ID_EXTD_BOTH_DIR_INFORMATION; +typedef FILE_ID_EXTD_BOTH_DIR_INFORMATION *PFILE_ID_EXTD_BOTH_DIR_INFORMATION; +typedef struct _FILE_ID_INFORMATION +{ + ULONGLONG VolumeSerialNumber; + FILE_ID_128 FileId; +} FILE_ID_INFORMATION; +typedef FILE_ID_INFORMATION *PFILE_ID_INFORMATION; +typedef struct _FILE_LINK_ENTRY_FULL_ID_INFORMATION +{ + ULONG NextEntryOffset; + FILE_ID_128 ParentFileId; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_ENTRY_FULL_ID_INFORMATION; +typedef FILE_LINK_ENTRY_FULL_ID_INFORMATION *PFILE_LINK_ENTRY_FULL_ID_INFORMATION; +typedef struct _FILE_LINKS_FULL_ID_INFORMATION { + ULONG BytesNeeded; + ULONG EntriesReturned; + FILE_LINK_ENTRY_FULL_ID_INFORMATION Entry; +} FILE_LINKS_FULL_ID_INFORMATION; +typedef FILE_LINKS_FULL_ID_INFORMATION *PFILE_LINKS_FULL_ID_INFORMATION; +typedef struct _FILE_DISPOSITION_INFORMATION_EX +{ + ULONG Flags; +} FILE_DISPOSITION_INFORMATION_EX; +typedef FILE_DISPOSITION_INFORMATION_EX *PFILE_DISPOSITION_INFORMATION_EX; +# ifndef QUERY_STORAGE_CLASSES_FLAGS_MEASURE_WRITE +typedef struct _FILE_DESIRED_STORAGE_CLASS_INFORMATION +{ + /*FILE_STORAGE_TIER_CLASS*/ ULONG Class; + ULONG Flags; +} FILE_DESIRED_STORAGE_CLASS_INFORMATION; +typedef FILE_DESIRED_STORAGE_CLASS_INFORMATION *PFILE_DESIRED_STORAGE_CLASS_INFORMATION; +# endif +typedef struct _FILE_STAT_INFORMATION +{ + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ACCESS_MASK EffectiveAccess; +} FILE_STAT_INFORMATION; +typedef FILE_STAT_INFORMATION *PFILE_STAT_INFORMATION; +typedef struct _FILE_STAT_LX_INFORMATION +{ + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ACCESS_MASK EffectiveAccess; + ULONG LxFlags; + ULONG LxUid; + ULONG LxGid; + ULONG LxMode; + ULONG LxDeviceIdMajor; + ULONG LxDeviceIdMinor; +} FILE_STAT_LX_INFORMATION; +typedef FILE_STAT_LX_INFORMATION *PFILE_STAT_LX_INFORMATION; +typedef struct _FILE_CASE_SENSITIVE_INFORMATION +{ + ULONG Flags; +} FILE_CASE_SENSITIVE_INFORMATION; +typedef FILE_CASE_SENSITIVE_INFORMATION *PFILE_CASE_SENSITIVE_INFORMATION; + +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation, + FileIoCompletionNotificationInformation, + FileIoStatusBlockRangeInformation, + FileIoPriorityHintInformation, + FileSfioReserveInformation, + FileSfioVolumeInformation, + FileHardLinkInformation, + FileProcessIdsUsingFileInformation, + FileNormalizedNameInformation, + FileNetworkPhysicalNameInformation, + FileIdGlobalTxDirectoryInformation, + FileIsRemoteDeviceInformation, + FileUnusedInformation, + FileNumaNodeInformation, + FileStandardLinkInformation, + FileRemoteProtocolInformation, + /* Defined with Windows 10: */ + FileRenameInformationBypassAccessCheck, + FileLinkInformationBypassAccessCheck, + FileVolumeNameInformation, + FileIdInformation, + FileIdExtdDirectoryInformation, + FileReplaceCompletionInformation, + FileHardLinkFullIdInformation, + FileIdExtdBothDirectoryInformation, + FileDispositionInformationEx, + FileRenameInformationEx, + FileRenameInformationExBypassAccessCheck, + FileDesiredStorageClassInformation, + FileStatInformation, + FileMemoryPartitionInformation, + FileStatLxInformation, + FileCaseSensitiveInformation, + FileLinkInformationEx, + FileLinkInformationExBypassAccessCheck, + FileStorageReserveIdInformation, + FileCaseSensitiveInformationForceAccessCheck, + FileMaximumInformation +} FILE_INFORMATION_CLASS; +typedef FILE_INFORMATION_CLASS *PFILE_INFORMATION_CLASS; +RT_DECL_NTAPI(NTSTATUS) NtQueryInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS); +RT_DECL_NTAPI(NTSTATUS) NtQueryDirectoryFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, + FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN); +RT_DECL_NTAPI(NTSTATUS) NtSetInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS); +#endif /* IPRT_NT_USE_WINTERNL */ +RT_DECL_NTAPI(NTSTATUS) NtQueryAttributesFile(POBJECT_ATTRIBUTES, PFILE_BASIC_INFORMATION); +RT_DECL_NTAPI(NTSTATUS) NtQueryFullAttributesFile(POBJECT_ATTRIBUTES, PFILE_NETWORK_OPEN_INFORMATION); + + +/** @name SE_GROUP_XXX - Attributes returned with TokenGroup and others. + * @{ */ +#ifndef SE_GROUP_MANDATORY +# define SE_GROUP_MANDATORY UINT32_C(0x01) +#endif +#ifndef SE_GROUP_ENABLED_BY_DEFAULT +# define SE_GROUP_ENABLED_BY_DEFAULT UINT32_C(0x02) +#endif +#ifndef SE_GROUP_ENABLED +# define SE_GROUP_ENABLED UINT32_C(0x04) +#endif +#ifndef SE_GROUP_OWNER +# define SE_GROUP_OWNER UINT32_C(0x08) +#endif +#ifndef SE_GROUP_USE_FOR_DENY_ONLY +# define SE_GROUP_USE_FOR_DENY_ONLY UINT32_C(0x10) +#endif +#ifndef SE_GROUP_INTEGRITY +# define SE_GROUP_INTEGRITY UINT32_C(0x20) +#endif +#ifndef SE_GROUP_INTEGRITY_ENABLED +# define SE_GROUP_INTEGRITY_ENABLED UINT32_C(0x40) +#endif +#ifndef SE_GROUP_RESOURCE +# define SE_GROUP_RESOURCE UINT32_C(0x20000000) +#endif +#ifndef SE_GROUP_LOGON_ID +# define SE_GROUP_LOGON_ID UINT32_C(0xc0000000) +#endif +/** @} */ + + +#ifdef IPRT_NT_USE_WINTERNL + +/** For use with KeyBasicInformation. */ +typedef struct _KEY_BASIC_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG NameLength; + WCHAR Name[1]; +} KEY_BASIC_INFORMATION; +typedef KEY_BASIC_INFORMATION *PKEY_BASIC_INFORMATION; + +/** For use with KeyNodeInformation. */ +typedef struct _KEY_NODE_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; /**< Offset from the start of the structure. */ + ULONG ClassLength; + ULONG NameLength; + WCHAR Name[1]; +} KEY_NODE_INFORMATION; +typedef KEY_NODE_INFORMATION *PKEY_NODE_INFORMATION; + +/** For use with KeyFullInformation. */ +typedef struct _KEY_FULL_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; /**< Offset of the Class member. */ + ULONG ClassLength; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG MaxClassLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + WCHAR Class[1]; +} KEY_FULL_INFORMATION; +typedef KEY_FULL_INFORMATION *PKEY_FULL_INFORMATION; + +/** For use with KeyNameInformation. */ +typedef struct _KEY_NAME_INFORMATION +{ + ULONG NameLength; + WCHAR Name[1]; +} KEY_NAME_INFORMATION; +typedef KEY_NAME_INFORMATION *PKEY_NAME_INFORMATION; + +/** For use with KeyCachedInformation. */ +typedef struct _KEY_CACHED_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + ULONG NameLength; +} KEY_CACHED_INFORMATION; +typedef KEY_CACHED_INFORMATION *PKEY_CACHED_INFORMATION; + +/** For use with KeyVirtualizationInformation. */ +typedef struct _KEY_VIRTUALIZATION_INFORMATION +{ + ULONG VirtualizationCandidate : 1; + ULONG VirtualizationEnabled : 1; + ULONG VirtualTarget : 1; + ULONG VirtualStore : 1; + ULONG VirtualSource : 1; + ULONG Reserved : 27; +} KEY_VIRTUALIZATION_INFORMATION; +typedef KEY_VIRTUALIZATION_INFORMATION *PKEY_VIRTUALIZATION_INFORMATION; + +typedef enum _KEY_INFORMATION_CLASS +{ + KeyBasicInformation = 0, + KeyNodeInformation, + KeyFullInformation, + KeyNameInformation, + KeyCachedInformation, + KeyFlagsInformation, + KeyVirtualizationInformation, + KeyHandleTagsInformation, + MaxKeyInfoClass +} KEY_INFORMATION_CLASS; +RT_DECL_NTAPI(NTSTATUS) NtQueryKey(HANDLE, KEY_INFORMATION_CLASS, PVOID, ULONG, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtEnumerateKey(HANDLE, ULONG, KEY_INFORMATION_CLASS, PVOID, ULONG, PULONG); + +typedef struct _MEMORY_SECTION_NAME +{ + UNICODE_STRING SectionFileName; + WCHAR NameBuffer[1]; +} MEMORY_SECTION_NAME; + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _PROCESS_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PPEB PebBaseAddress; + ULONG_PTR AffinityMask; + int32_t BasePriority; + ULONG_PTR UniqueProcessId; + ULONG_PTR InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION; +typedef PROCESS_BASIC_INFORMATION *PPROCESS_BASIC_INFORMATION; +#endif + +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation = 0, /**< 0 / 0x00 */ + ProcessQuotaLimits, /**< 1 / 0x01 */ + ProcessIoCounters, /**< 2 / 0x02 */ + ProcessVmCounters, /**< 3 / 0x03 */ + ProcessTimes, /**< 4 / 0x04 */ + ProcessBasePriority, /**< 5 / 0x05 */ + ProcessRaisePriority, /**< 6 / 0x06 */ + ProcessDebugPort, /**< 7 / 0x07 */ + ProcessExceptionPort, /**< 8 / 0x08 */ + ProcessAccessToken, /**< 9 / 0x09 */ + ProcessLdtInformation, /**< 10 / 0x0a */ + ProcessLdtSize, /**< 11 / 0x0b */ + ProcessDefaultHardErrorMode, /**< 12 / 0x0c */ + ProcessIoPortHandlers, /**< 13 / 0x0d */ + ProcessPooledUsageAndLimits, /**< 14 / 0x0e */ + ProcessWorkingSetWatch, /**< 15 / 0x0f */ + ProcessUserModeIOPL, /**< 16 / 0x10 */ + ProcessEnableAlignmentFaultFixup, /**< 17 / 0x11 */ + ProcessPriorityClass, /**< 18 / 0x12 */ + ProcessWx86Information, /**< 19 / 0x13 */ + ProcessHandleCount, /**< 20 / 0x14 */ + ProcessAffinityMask, /**< 21 / 0x15 */ + ProcessPriorityBoost, /**< 22 / 0x16 */ + ProcessDeviceMap, /**< 23 / 0x17 */ + ProcessSessionInformation, /**< 24 / 0x18 */ + ProcessForegroundInformation, /**< 25 / 0x19 */ + ProcessWow64Information, /**< 26 / 0x1a */ + ProcessImageFileName, /**< 27 / 0x1b */ + ProcessLUIDDeviceMapsEnabled, /**< 28 / 0x1c */ + ProcessBreakOnTermination, /**< 29 / 0x1d */ + ProcessDebugObjectHandle, /**< 30 / 0x1e */ + ProcessDebugFlags, /**< 31 / 0x1f */ + ProcessHandleTracing, /**< 32 / 0x20 */ + ProcessIoPriority, /**< 33 / 0x21 */ + ProcessExecuteFlags, /**< 34 / 0x22 */ + ProcessTlsInformation, /**< 35 / 0x23 */ + ProcessCookie, /**< 36 / 0x24 */ + ProcessImageInformation, /**< 37 / 0x25 */ + ProcessCycleTime, /**< 38 / 0x26 */ + ProcessPagePriority, /**< 39 / 0x27 */ + ProcessInstrumentationCallbak, /**< 40 / 0x28 */ + ProcessThreadStackAllocation, /**< 41 / 0x29 */ + ProcessWorkingSetWatchEx, /**< 42 / 0x2a */ + ProcessImageFileNameWin32, /**< 43 / 0x2b */ + ProcessImageFileMapping, /**< 44 / 0x2c */ + ProcessAffinityUpdateMode, /**< 45 / 0x2d */ + ProcessMemoryAllocationMode, /**< 46 / 0x2e */ + ProcessGroupInformation, /**< 47 / 0x2f */ + ProcessTokenVirtualizationEnabled, /**< 48 / 0x30 */ + ProcessOwnerInformation, /**< 49 / 0x31 */ + ProcessWindowInformation, /**< 50 / 0x32 */ + ProcessHandleInformation, /**< 51 / 0x33 */ + ProcessMitigationPolicy, /**< 52 / 0x34 */ + ProcessDynamicFunctionTableInformation, /**< 53 / 0x35 */ + ProcessHandleCheckingMode, /**< 54 / 0x36 */ + ProcessKeepAliveCount, /**< 55 / 0x37 */ + ProcessRevokeFileHandles, /**< 56 / 0x38 */ + ProcessWorkingSetControl, /**< 57 / 0x39 */ + ProcessHandleTable, /**< 58 / 0x3a */ + ProcessCheckStackExtentsMode, /**< 59 / 0x3b */ + ProcessCommandLineInformation, /**< 60 / 0x3c */ + ProcessProtectionInformation, /**< 61 / 0x3d */ + ProcessMemoryExhaustion, /**< 62 / 0x3e */ + ProcessFaultInformation, /**< 63 / 0x3f */ + ProcessTelemetryIdInformation, /**< 64 / 0x40 */ + ProcessCommitReleaseInformation, /**< 65 / 0x41 */ + ProcessDefaultCpuSetsInformation, /**< 66 / 0x42 - aka ProcessReserved1Information */ + ProcessAllowedCpuSetsInformation, /**< 67 / 0x43 - aka ProcessReserved2Information; PROCESS_SET_LIMITED_INFORMATION & audiog.exe; W10 */ + ProcessSubsystemProcess, /**< 68 / 0x44 */ + ProcessJobMemoryInformation, /**< 69 / 0x45 */ + ProcessInPrivate, /**< 70 / 0x46 */ + ProcessRaiseUMExceptionOnInvalidHandleClose,/**< 71 / 0x47 */ + ProcessIumChallengeResponse, /**< 72 / 0x48 */ + ProcessChildProcessInformation, /**< 73 / 0x49 */ + ProcessHighGraphicsPriorityInformation, /**< 74 / 0x4a */ + ProcessSubsystemInformation, /**< 75 / 0x4b */ + ProcessEnergyValues, /**< 76 / 0x4c */ + ProcessPowerThrottlingState, /**< 77 / 0x4d */ + ProcessReserved3Information, /**< 78 / 0x4e */ + ProcessWin32kSyscallFilterInformation, /**< 79 / 0x4f */ + ProcessDisableSystemAllowedCpuSets, /**< 80 / 0x50 */ + ProcessWakeInformation, /**< 81 / 0x51 */ + ProcessEnergyTrackingState, /**< 82 / 0x52 */ + ProcessManageWritesToExecutableMemory, /**< 83 / 0x53 */ + ProcessCaptureTrustletLiveDump, /**< 84 / 0x54 */ + ProcessTelemetryCoverage, /**< 85 / 0x55 */ + ProcessEnclaveInformation, /**< 86 / 0x56 */ + ProcessEnableReadWriteVmLogging, /**< 87 / 0x57 */ + ProcessUptimeInformation, /**< 88 / 0x58 */ + ProcessImageSection, /**< 89 / 0x59 */ + ProcessDebugAuthInformation, /**< 90 / 0x5a */ + ProcessSystemResourceManagement, /**< 92 / 0x5b */ + ProcessSequenceNumber, /**< 93 / 0x5c */ + MaxProcessInfoClass +} PROCESSINFOCLASS; +AssertCompile(ProcessSequenceNumber == 0x5c); +#endif +#if defined(IPRT_NT_USE_WINTERNL) || defined(WDK_NTDDI_VERSION) /* Present in ntddk.h from 7600.16385.1, but not in W10. */ +RT_DECL_NTAPI(NTSTATUS) NtQueryInformationProcess(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); +#endif +#ifdef IPRT_NT_USE_WINTERNL +#if ARCH_BITS == 32 +/** 64-bit API pass thru to WOW64 processes. */ +RT_DECL_NTAPI(NTSTATUS) NtWow64QueryInformationProcess64(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); +#endif + +typedef enum _THREADINFOCLASS +{ + ThreadBasicInformation = 0, + ThreadTimes, + ThreadPriority, + ThreadBasePriority, + ThreadAffinityMask, + ThreadImpersonationToken, + ThreadDescriptorTableEntry, + ThreadEnableAlignmentFaultFixup, + ThreadEventPair_Reusable, + ThreadQuerySetWin32StartAddress, + ThreadZeroTlsCell, + ThreadPerformanceCount, + ThreadAmILastThread, + ThreadIdealProcessor, + ThreadPriorityBoost, + ThreadSetTlsArrayAddress, + ThreadIsIoPending, + ThreadHideFromDebugger, + ThreadBreakOnTermination, + ThreadSwitchLegacyState, + ThreadIsTerminated, + ThreadLastSystemCall, + ThreadIoPriority, + ThreadCycleTime, + ThreadPagePriority, + ThreadActualBasePriority, + ThreadTebInformation, + ThreadCSwitchMon, + ThreadCSwitchPmu, + ThreadWow64Context, + ThreadGroupInformation, + ThreadUmsInformation, + ThreadCounterProfiling, + ThreadIdealProcessorEx, + ThreadCpuAccountingInformation, + MaxThreadInfoClass +} THREADINFOCLASS; +RT_DECL_NTAPI(NTSTATUS) NtSetInformationThread(HANDLE, THREADINFOCLASS, LPCVOID, ULONG); + +RT_DECL_NTAPI(NTSTATUS) NtQueryInformationToken(HANDLE, TOKEN_INFORMATION_CLASS, PVOID, ULONG, PULONG); +RT_DECL_NTAPI(NTSTATUS) ZwQueryInformationToken(HANDLE, TOKEN_INFORMATION_CLASS, PVOID, ULONG, PULONG); + +RT_DECL_NTAPI(NTSTATUS) NtReadFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, PLARGE_INTEGER, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtWriteFile(HANDLE, HANDLE, PIO_APC_ROUTINE, void const *, PIO_STATUS_BLOCK, PVOID, ULONG, PLARGE_INTEGER, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtFlushBuffersFile(HANDLE, PIO_STATUS_BLOCK); +RT_DECL_NTAPI(NTSTATUS) NtCancelIoFile(HANDLE, PIO_STATUS_BLOCK); + +RT_DECL_NTAPI(NTSTATUS) NtReadVirtualMemory(HANDLE, PVOID, PVOID, SIZE_T, PSIZE_T); +RT_DECL_NTAPI(NTSTATUS) NtWriteVirtualMemory(HANDLE, PVOID, void const *, SIZE_T, PSIZE_T); + +RT_DECL_NTAPI(NTSTATUS) RtlAddAccessAllowedAce(PACL, ULONG, ULONG, PSID); +RT_DECL_NTAPI(NTSTATUS) RtlCopySid(ULONG, PSID, PSID); +RT_DECL_NTAPI(NTSTATUS) RtlCreateAcl(PACL, ULONG, ULONG); +RT_DECL_NTAPI(NTSTATUS) RtlCreateSecurityDescriptor(PSECURITY_DESCRIPTOR, ULONG); +RT_DECL_NTAPI(BOOLEAN) RtlEqualSid(PSID, PSID); +RT_DECL_NTAPI(NTSTATUS) RtlGetVersion(PRTL_OSVERSIONINFOW); +RT_DECL_NTAPI(NTSTATUS) RtlInitializeSid(PSID, PSID_IDENTIFIER_AUTHORITY, UCHAR); +RT_DECL_NTAPI(NTSTATUS) RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR, BOOLEAN, PACL, BOOLEAN); +RT_DECL_NTAPI(PULONG) RtlSubAuthoritySid(PSID, ULONG); + +#endif /* IPRT_NT_USE_WINTERNL */ + +#ifdef RTNT_NEED_NT_GET_PRODUCT_TYPE +RT_DECL_NTAPI(BOOLEAN) RtlGetNtProductType(enum _NT_PRODUCT_TYPE *); /**< @since NT 3.1 */ +#endif + +/** For use with ObjectBasicInformation. + * A watered down version of this struct appears under the name + * PUBLIC_OBJECT_BASIC_INFORMATION in ntifs.h. It only defines + * the first four members, so don't trust the rest. */ +typedef struct _OBJECT_BASIC_INFORMATION +{ + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + /* Not in ntifs.h: */ + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG Reserved[3]; + ULONG NameInfoSize; + ULONG TypeInfoSize; + ULONG SecurityDescriptorSize; + LARGE_INTEGER CreationTime; +} OBJECT_BASIC_INFORMATION; +typedef OBJECT_BASIC_INFORMATION *POBJECT_BASIC_INFORMATION; + +/** For use with ObjectHandleFlagInformation. */ +typedef struct _OBJECT_HANDLE_FLAG_INFORMATION +{ + BOOLEAN Inherit; + BOOLEAN ProtectFromClose; +} OBJECT_HANDLE_FLAG_INFORMATION; +typedef OBJECT_HANDLE_FLAG_INFORMATION *POBJECT_HANDLE_FLAG_INFORMATION; + +/** + * Returned via ObjectTypesInformation, see also OBJECT_TYPES_INFORMATION. + * The next structure address is calculate: + * (uintptr_t)Name.Buffer + RT_ALIGN_32(Name.MaximumLength, sizeof(uintptr_t)) + */ +typedef struct _OBJECT_TYPE_INFORMATION +{ /* 64-bit offset */ + UNICODE_STRING TypeName; /**< 0x00 */ + ULONG TotalNumberOfObjects; /**< 0x10 */ + ULONG TotalNumberOfHandles; /**< 0x14 */ + ULONG TotalPagedPoolUsage; /**< 0x18 - not set by W10 19044 */ + ULONG TotalNonPagedPoolUsage; /**< 0x1c - not set by W10 19044 */ + ULONG TotalNamePoolUsage; /**< 0x20 - not set by W10 19044 */ + ULONG TotalHandleTableUsage; /**< 0x24 - not set by W10 19044 */ + ULONG HighWaterNumberOfObjects; /**< 0x28 */ + ULONG HighWaterNumberOfHandles; /**< 0x2c */ + ULONG HighWaterPagedPoolUsage; /**< 0x30 - not set by W10 19044 */ + ULONG HighWaterNonPagedPoolUsage; /**< 0x34 - not set by W10 19044 */ + ULONG HighWaterNamePoolUsage; /**< 0x38 - not set by W10 19044 */ + ULONG HighWaterHandleTableUsage; /**< 0x3c - not set by W10 19044 */ + ULONG InvalidAttributes; /**< 0x40 */ + GENERIC_MAPPING GenericMapping; /**< 0x44 */ + ULONG ValidAccessMask; /**< 0x54 */ + BOOLEAN SecurityRequired; /**< 0x58 */ + BOOLEAN MaintainHandleCount; /**< 0x59 */ + UCHAR TypeIndex; /**< 0x5a */ + UCHAR ReservedZero; /**< 0x5b */ + ULONG PoolType; /**< 0x5c */ + ULONG DefaultPagedPoolCharge; /**< 0x60 - not set by W10 19044 */ + ULONG DefaultNonPagedPoolCharge; /**< 0x64 - not set by W10 19044 */ + /* The name string follows after the structure. */ +} OBJECT_TYPE_INFORMATION; +AssertCompileSize(OBJECT_TYPE_INFORMATION, sizeof(UNICODE_STRING) + 0x58); +typedef OBJECT_TYPE_INFORMATION *POBJECT_TYPE_INFORMATION; + +/** Returned via ObjectTypesInformation. */ +typedef struct _OBJECT_TYPES_INFORMATION +{ + ULONG NumberOfTypes; + OBJECT_TYPE_INFORMATION FirstType; +} OBJECT_TYPES_INFORMATION; +typedef OBJECT_TYPES_INFORMATION *POBJECT_TYPES_INFORMATION; + +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInformation = 0, + ObjectNameInformation, + ObjectTypeInformation, + ObjectTypesInformation, + ObjectHandleFlagInformation, + ObjectSessionInformation, + MaxObjectInfoClass +} OBJECT_INFORMATION_CLASS; +typedef OBJECT_INFORMATION_CLASS *POBJECT_INFORMATION_CLASS; +#ifdef IN_RING0 +# define NtQueryObject ZwQueryObject +#endif +RT_DECL_NTAPI(NTSTATUS) NtQueryObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtSetInformationObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG); +RT_DECL_NTAPI(NTSTATUS) NtDuplicateObject(HANDLE, HANDLE, HANDLE, PHANDLE, ACCESS_MASK, ULONG, ULONG); + +RT_DECL_NTAPI(NTSTATUS) NtOpenDirectoryObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); + +typedef struct _OBJECT_DIRECTORY_INFORMATION +{ + UNICODE_STRING Name; + UNICODE_STRING TypeName; +} OBJECT_DIRECTORY_INFORMATION; +typedef OBJECT_DIRECTORY_INFORMATION *POBJECT_DIRECTORY_INFORMATION; +RT_DECL_NTAPI(NTSTATUS) NtQueryDirectoryObject(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG); + +RT_DECL_NTAPI(NTSTATUS) NtSuspendProcess(HANDLE); +RT_DECL_NTAPI(NTSTATUS) NtResumeProcess(HANDLE); +/** @name ProcessDefaultHardErrorMode bit definitions. + * @{ */ +#define PROCESS_HARDERR_CRITICAL_ERROR UINT32_C(0x00000001) /**< Inverted from the win32 define. */ +#define PROCESS_HARDERR_NO_GP_FAULT_ERROR UINT32_C(0x00000002) +#define PROCESS_HARDERR_NO_ALIGNMENT_FAULT_ERROR UINT32_C(0x00000004) +#define PROCESS_HARDERR_NO_OPEN_FILE_ERROR UINT32_C(0x00008000) +/** @} */ +RT_DECL_NTAPI(NTSTATUS) NtSetInformationProcess(HANDLE, PROCESSINFOCLASS, PVOID, ULONG); +RT_DECL_NTAPI(NTSTATUS) NtTerminateProcess(HANDLE, LONG); + +/** Returned by NtQUerySection with SectionBasicInformation. */ +typedef struct _SECTION_BASIC_INFORMATION +{ + PVOID BaseAddress; + ULONG AllocationAttributes; + LARGE_INTEGER MaximumSize; +} SECTION_BASIC_INFORMATION; +typedef SECTION_BASIC_INFORMATION *PSECTION_BASIC_INFORMATION; + +/** Retured by ProcessImageInformation as well as NtQuerySection. */ +typedef struct _SECTION_IMAGE_INFORMATION +{ + PVOID TransferAddress; + ULONG ZeroBits; + SIZE_T MaximumStackSize; + SIZE_T CommittedStackSize; + ULONG SubSystemType; + union + { + struct + { + USHORT SubSystemMinorVersion; + USHORT SubSystemMajorVersion; + }; + ULONG SubSystemVersion; + }; + ULONG GpValue; + USHORT ImageCharacteristics; + USHORT DllCharacteristics; + USHORT Machine; + BOOLEAN ImageContainsCode; + union /**< Since Vista, used to be a spare BOOLEAN. */ + { + struct + { + UCHAR ComPlusNativeRead : 1; + UCHAR ComPlusILOnly : 1; + UCHAR ImageDynamicallyRelocated : 1; + UCHAR ImageMAppedFlat : 1; + UCHAR Reserved : 4; + }; + UCHAR ImageFlags; + }; + ULONG LoaderFlags; + ULONG ImageFileSize; /**< Since XP? */ + ULONG CheckSum; /**< Since Vista, Used to be a reserved/spare ULONG. */ +} SECTION_IMAGE_INFORMATION; +typedef SECTION_IMAGE_INFORMATION *PSECTION_IMAGE_INFORMATION; + +typedef enum _SECTION_INFORMATION_CLASS +{ + SectionBasicInformation = 0, + SectionImageInformation, + MaxSectionInfoClass +} SECTION_INFORMATION_CLASS; +RT_DECL_NTAPI(NTSTATUS) NtQuerySection(HANDLE, SECTION_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); + +RT_DECL_NTAPI(NTSTATUS) NtCreateSymbolicLinkObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PUNICODE_STRING pTarget); +RT_DECL_NTAPI(NTSTATUS) NtOpenSymbolicLinkObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); +RT_DECL_NTAPI(NTSTATUS) NtQuerySymbolicLinkObject(HANDLE, PUNICODE_STRING, PULONG); +#ifndef SYMBOLIC_LINK_QUERY +# define SYMBOLIC_LINK_QUERY UINT32_C(0x00000001) +#endif +#ifndef SYMBOLIC_LINK_ALL_ACCESS +# define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYMBOLIC_LINK_QUERY) +#endif + +RT_DECL_NTAPI(NTSTATUS) NtQueryInformationThread(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtResumeThread(HANDLE, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtSuspendThread(HANDLE, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtTerminateThread(HANDLE, LONG); +RT_DECL_NTAPI(NTSTATUS) NtGetContextThread(HANDLE, PCONTEXT); +RT_DECL_NTAPI(NTSTATUS) NtSetContextThread(HANDLE, PCONTEXT); +RT_DECL_NTAPI(NTSTATUS) ZwYieldExecution(void); + + +#ifndef SEC_FILE +# define SEC_FILE UINT32_C(0x00800000) +#endif +#ifndef SEC_IMAGE +# define SEC_IMAGE UINT32_C(0x01000000) +#endif +#ifndef SEC_PROTECTED_IMAGE +# define SEC_PROTECTED_IMAGE UINT32_C(0x02000000) +#endif +#ifndef SEC_NOCACHE +# define SEC_NOCACHE UINT32_C(0x10000000) +#endif +#ifndef MEM_ROTATE +# define MEM_ROTATE UINT32_C(0x00800000) +#endif +typedef enum _MEMORY_INFORMATION_CLASS +{ + MemoryBasicInformation = 0, + MemoryWorkingSetList, + MemorySectionName, + MemoryBasicVlmInformation +} MEMORY_INFORMATION_CLASS; +#ifndef IPRT_NT_USE_WINTERNL +# ifndef WDK_NTDDI_VERSION /* W10 ntifs.h has it, 7600.16385.1 didn't. */ +typedef struct _MEMORY_BASIC_INFORMATION +{ + PVOID BaseAddress; + PVOID AllocationBase; + ULONG AllocationProtect; +# if ARCH_BITS == 64 + USHORT PartitionId; +# endif + SIZE_T RegionSize; + ULONG State; + ULONG Protect; + ULONG Type; +} MEMORY_BASIC_INFORMATION; +typedef MEMORY_BASIC_INFORMATION *PMEMORY_BASIC_INFORMATION; +# endif +# define NtQueryVirtualMemory ZwQueryVirtualMemory +#endif +#if defined(IPRT_NT_USE_WINTERNL) || !defined(WDK_NTDDI_VERSION) /* W10 ntifs.h has it, 7600.16385.1 didn't. */ +RT_DECL_NTAPI(NTSTATUS) NtQueryVirtualMemory(HANDLE, void const *, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); +#endif +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtAllocateVirtualMemory(HANDLE, PVOID *, ULONG, PSIZE_T, ULONG, ULONG); +RT_DECL_NTAPI(NTSTATUS) NtFreeVirtualMemory(HANDLE, PVOID *, PSIZE_T, ULONG); +#endif +RT_DECL_NTAPI(NTSTATUS) NtProtectVirtualMemory(HANDLE, PVOID *, PSIZE_T, ULONG, PULONG); + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation = 0, + SystemCpuInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemInformation_Unknown_4, + SystemProcessInformation, + SystemInformation_Unknown_6, + SystemInformation_Unknown_7, + SystemProcessorPerformanceInformation, + SystemInformation_Unknown_9, + SystemInformation_Unknown_10, + SystemModuleInformation, + SystemInformation_Unknown_12, + SystemInformation_Unknown_13, + SystemInformation_Unknown_14, + SystemInformation_Unknown_15, + SystemHandleInformation, + SystemInformation_Unknown_17, + SystemPageFileInformation, + SystemInformation_Unknown_19, + SystemInformation_Unknown_20, + SystemCacheInformation, + SystemInformation_Unknown_22, + SystemInterruptInformation, + SystemDpcBehaviourInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, /* 26 */ + SystemUnloadGdiDriverInformation, /* 27 */ + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemInformation_Unknown_30, + SystemInformation_Unknown_31, + SystemInformation_Unknown_32, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemInformation_Unknown_38, + SystemInformation_Unknown_39, + SystemInformation_Unknown_40, + SystemInformation_Unknown_41, + SystemInformation_Unknown_42, + SystemInformation_Unknown_43, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation, + SystemSetTimeSlipEvent, + SystemCreateSession, + SystemDeleteSession, + SystemInformation_Unknown_49, + SystemRangeStartInformation, + SystemVerifierInformation, + SystemInformation_Unknown_52, + SystemSessionProcessInformation, + SystemLoadGdiDriverInSystemSpaceInformation, /* 54 */ + SystemInformation_Unknown_55, + SystemInformation_Unknown_56, + SystemExtendedProcessInformation, + SystemInformation_Unknown_58, + SystemInformation_Unknown_59, + SystemInformation_Unknown_60, + SystemInformation_Unknown_61, + SystemInformation_Unknown_62, + SystemInformation_Unknown_63, + SystemExtendedHandleInformation, /* 64 */ + SystemInformation_Unknown_65, + SystemInformation_Unknown_66, + SystemInformation_Unknown_67, /**< See https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/codeintegrity.htm */ + SystemInformation_Unknown_68, + SystemInformation_HotPatchInfo, /* 69 */ + SystemInformation_Unknown_70, + SystemInformation_Unknown_71, + SystemInformation_Unknown_72, + SystemInformation_Unknown_73, + SystemInformation_Unknown_74, + SystemInformation_Unknown_75, + SystemInformation_Unknown_76, + SystemInformation_Unknown_77, + SystemInformation_Unknown_78, + SystemInformation_Unknown_79, + SystemInformation_Unknown_80, + SystemInformation_Unknown_81, + SystemInformation_Unknown_82, + SystemInformation_Unknown_83, + SystemInformation_Unknown_84, + SystemInformation_Unknown_85, + SystemInformation_Unknown_86, + SystemInformation_Unknown_87, + SystemInformation_Unknown_88, + SystemInformation_Unknown_89, + SystemInformation_Unknown_90, + SystemInformation_Unknown_91, + SystemInformation_Unknown_92, + SystemInformation_Unknown_93, + SystemInformation_Unknown_94, + SystemInformation_Unknown_95, + SystemInformation_KiOpPrefetchPatchCount, /* 96 */ + SystemInformation_Unknown_97, + SystemInformation_Unknown_98, + SystemInformation_Unknown_99, + SystemInformation_Unknown_100, + SystemInformation_Unknown_101, + SystemInformation_Unknown_102, + SystemInformation_Unknown_103, + SystemInformation_Unknown_104, + SystemInformation_Unknown_105, + SystemInformation_Unknown_107, + SystemInformation_GetLogicalProcessorInformationEx, /* 107 */ + + /** @todo fill gap. they've added a whole bunch of things */ + SystemPolicyInformation = 134, + SystemInformationClassMax +} SYSTEM_INFORMATION_CLASS; + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _VM_COUNTERS +{ + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; +} VM_COUNTERS; +typedef VM_COUNTERS *PVM_COUNTERS; +#endif + +#if 0 +typedef struct _IO_COUNTERS +{ + ULONGLONG ReadOperationCount; + ULONGLONG WriteOperationCount; + ULONGLONG OtherOperationCount; + ULONGLONG ReadTransferCount; + ULONGLONG WriteTransferCount; + ULONGLONG OtherTransferCount; +} IO_COUNTERS; +typedef IO_COUNTERS *PIO_COUNTERS; +#endif + +typedef struct _RTNT_SYSTEM_PROCESS_INFORMATION +{ + ULONG NextEntryOffset; /**< 0x00 / 0x00 */ + ULONG NumberOfThreads; /**< 0x04 / 0x04 */ + LARGE_INTEGER Reserved1[3]; /**< 0x08 / 0x08 */ + LARGE_INTEGER CreationTime; /**< 0x20 / 0x20 */ + LARGE_INTEGER UserTime; /**< 0x28 / 0x28 */ + LARGE_INTEGER KernelTime; /**< 0x30 / 0x30 */ + UNICODE_STRING ProcessName; /**< 0x38 / 0x38 Clean unicode encoding? */ + int32_t BasePriority; /**< 0x40 / 0x48 */ + HANDLE UniqueProcessId; /**< 0x44 / 0x50 */ + HANDLE ParentProcessId; /**< 0x48 / 0x58 */ + ULONG HandleCount; /**< 0x4c / 0x60 */ + ULONG Reserved2; /**< 0x50 / 0x64 Session ID? */ + ULONG_PTR Reserved3; /**< 0x54 / 0x68 */ + VM_COUNTERS VmCounters; /**< 0x58 / 0x70 */ + IO_COUNTERS IoCounters; /**< 0x88 / 0xd0 Might not be present in earlier windows versions. */ + /* After this follows the threads, then the ProcessName.Buffer. */ +} RTNT_SYSTEM_PROCESS_INFORMATION; +typedef RTNT_SYSTEM_PROCESS_INFORMATION *PRTNT_SYSTEM_PROCESS_INFORMATION; +#ifndef IPRT_NT_USE_WINTERNL +typedef RTNT_SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION; +typedef SYSTEM_PROCESS_INFORMATION *PSYSTEM_PROCESS_INFORMATION; +#endif + +typedef struct _SYSTEM_HANDLE_ENTRY_INFO +{ + USHORT UniqueProcessId; + USHORT CreatorBackTraceIndex; + UCHAR ObjectTypeIndex; + UCHAR HandleAttributes; + USHORT HandleValue; + PVOID Object; + ULONG GrantedAccess; +} SYSTEM_HANDLE_ENTRY_INFO; +typedef SYSTEM_HANDLE_ENTRY_INFO *PSYSTEM_HANDLE_ENTRY_INFO; + +/** Returned by SystemHandleInformation */ +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG NumberOfHandles; + SYSTEM_HANDLE_ENTRY_INFO Handles[1]; +} SYSTEM_HANDLE_INFORMATION; +typedef SYSTEM_HANDLE_INFORMATION *PSYSTEM_HANDLE_INFORMATION; + +/** Extended handle information entry. + * @remarks 3 x PVOID + 4 x ULONG = 28 bytes on 32-bit / 40 bytes on 64-bit */ +typedef struct _SYSTEM_HANDLE_ENTRY_INFO_EX +{ + PVOID Object; + HANDLE UniqueProcessId; + HANDLE HandleValue; + ACCESS_MASK GrantedAccess; + USHORT CreatorBackTraceIndex; + USHORT ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} SYSTEM_HANDLE_ENTRY_INFO_EX; +typedef SYSTEM_HANDLE_ENTRY_INFO_EX *PSYSTEM_HANDLE_ENTRY_INFO_EX; + +/** Returned by SystemExtendedHandleInformation. */ +typedef struct _SYSTEM_HANDLE_INFORMATION_EX +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + SYSTEM_HANDLE_ENTRY_INFO_EX Handles[1]; +} SYSTEM_HANDLE_INFORMATION_EX; +typedef SYSTEM_HANDLE_INFORMATION_EX *PSYSTEM_HANDLE_INFORMATION_EX; + +/** Returned by SystemSessionProcessInformation. */ +typedef struct _SYSTEM_SESSION_PROCESS_INFORMATION +{ + ULONG SessionId; + ULONG BufferLength; + /** Return buffer, SYSTEM_PROCESS_INFORMATION entries. */ + PVOID Buffer; +} SYSTEM_SESSION_PROCESS_INFORMATION; +typedef SYSTEM_SESSION_PROCESS_INFORMATION *PSYSTEM_SESSION_PROCESS_INFORMATION; + +typedef struct _RTL_PROCESS_MODULE_INFORMATION +{ + HANDLE Section; /**< 0x00 / 0x00 */ + PVOID MappedBase; /**< 0x04 / 0x08 */ + PVOID ImageBase; /**< 0x08 / 0x10 */ + ULONG ImageSize; /**< 0x0c / 0x18 */ + ULONG Flags; /**< 0x10 / 0x1c */ + USHORT LoadOrderIndex; /**< 0x14 / 0x20 */ + USHORT InitOrderIndex; /**< 0x16 / 0x22 */ + USHORT LoadCount; /**< 0x18 / 0x24 */ + USHORT OffsetToFileName; /**< 0x1a / 0x26 */ + UCHAR FullPathName[256]; /**< 0x1c / 0x28 */ +} RTL_PROCESS_MODULE_INFORMATION; +typedef RTL_PROCESS_MODULE_INFORMATION *PRTL_PROCESS_MODULE_INFORMATION; + +/** Returned by SystemModuleInformation. */ +typedef struct _RTL_PROCESS_MODULES +{ + ULONG NumberOfModules; + RTL_PROCESS_MODULE_INFORMATION Modules[1]; /**< 0x04 / 0x08 */ +} RTL_PROCESS_MODULES; +typedef RTL_PROCESS_MODULES *PRTL_PROCESS_MODULES; + +RT_DECL_NTAPI(NTSTATUS) NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +#ifndef IPRT_NT_MAP_TO_ZW +RT_DECL_NTAPI(NTSTATUS) ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +#endif + +RT_DECL_NTAPI(NTSTATUS) NtSetTimerResolution(ULONG cNtTicksWanted, BOOLEAN fSetResolution, PULONG pcNtTicksCur); +RT_DECL_NTAPI(NTSTATUS) NtQueryTimerResolution(PULONG pcNtTicksMin, PULONG pcNtTicksMax, PULONG pcNtTicksCur); + +RT_DECL_NTAPI(NTSTATUS) NtDelayExecution(BOOLEAN, PLARGE_INTEGER); +RT_DECL_NTAPI(NTSTATUS) NtYieldExecution(void); +#ifndef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtWaitForSingleObject(HANDLE, BOOLEAN, PLARGE_INTEGER); +#endif +typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTWAITFORSINGLEOBJECT)(HANDLE, BOOLEAN, PLARGE_INTEGER); +typedef enum _OBJECT_WAIT_TYPE { WaitAllObjects = 0, WaitAnyObject = 1, ObjectWaitTypeHack = 0x7fffffff } OBJECT_WAIT_TYPE; +RT_DECL_NTAPI(NTSTATUS) NtWaitForMultipleObjects(ULONG, PHANDLE, OBJECT_WAIT_TYPE, BOOLEAN, PLARGE_INTEGER); + +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtQuerySecurityObject(HANDLE, ULONG, PSECURITY_DESCRIPTOR, ULONG, PULONG); +#endif + +#ifdef IPRT_NT_USE_WINTERNL +typedef enum _EVENT_TYPE +{ + /* Manual reset event. */ + NotificationEvent = 0, + /* Automaitc reset event. */ + SynchronizationEvent +} EVENT_TYPE; +#endif +RT_DECL_NTAPI(NTSTATUS) NtCreateEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN); +RT_DECL_NTAPI(NTSTATUS) NtOpenEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); +typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTCLEAREVENT)(HANDLE); +RT_DECL_NTAPI(NTSTATUS) NtClearEvent(HANDLE); +RT_DECL_NTAPI(NTSTATUS) NtResetEvent(HANDLE, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtSetEvent(HANDLE, PULONG); +typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTSETEVENT)(HANDLE, PULONG); +typedef enum _EVENT_INFORMATION_CLASS +{ + EventBasicInformation = 0 +} EVENT_INFORMATION_CLASS; +/** Data returned by NtQueryEvent + EventBasicInformation. */ +typedef struct EVENT_BASIC_INFORMATION +{ + EVENT_TYPE EventType; + ULONG EventState; +} EVENT_BASIC_INFORMATION; +typedef EVENT_BASIC_INFORMATION *PEVENT_BASIC_INFORMATION; +RT_DECL_NTAPI(NTSTATUS) NtQueryEvent(HANDLE, EVENT_INFORMATION_CLASS, PVOID, ULONG, PULONG); + +#ifdef IPRT_NT_USE_WINTERNL +/** For NtQueryValueKey. */ +typedef enum _KEY_VALUE_INFORMATION_CLASS +{ + KeyValueBasicInformation = 0, + KeyValueFullInformation, + KeyValuePartialInformation, + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64 +} KEY_VALUE_INFORMATION_CLASS; + +/** KeyValuePartialInformation and KeyValuePartialInformationAlign64 struct. */ +typedef struct _KEY_VALUE_PARTIAL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; +} KEY_VALUE_PARTIAL_INFORMATION; +typedef KEY_VALUE_PARTIAL_INFORMATION *PKEY_VALUE_PARTIAL_INFORMATION; +#endif +RT_DECL_NTAPI(NTSTATUS) NtOpenKey(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); +RT_DECL_NTAPI(NTSTATUS) NtQueryValueKey(HANDLE, PUNICODE_STRING, KEY_VALUE_INFORMATION_CLASS, PVOID, ULONG, PULONG); + + +RT_DECL_NTAPI(NTSTATUS) RtlAddAccessDeniedAce(PACL, ULONG, ULONG, PSID); + + +typedef struct _CURDIR +{ + UNICODE_STRING DosPath; + HANDLE Handle; /**< 0x10 / 0x08 */ +} CURDIR; +AssertCompileSize(CURDIR, ARCH_BITS == 32 ? 0x0c : 0x18); +typedef CURDIR *PCURDIR; + +typedef struct _RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + STRING DosPath; /**< Yeah, it's STRING according to dt ntdll!_RTL_DRIVE_LETTER_CURDIR. */ +} RTL_DRIVE_LETTER_CURDIR; +typedef RTL_DRIVE_LETTER_CURDIR *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct _RTL_USER_PROCESS_PARAMETERS +{ + ULONG MaximumLength; /**< 0x000 / 0x000 */ + ULONG Length; /**< 0x004 / 0x004 */ + ULONG Flags; /**< 0x008 / 0x008 */ + ULONG DebugFlags; /**< 0x00c / 0x00c */ + HANDLE ConsoleHandle; /**< 0x010 / 0x010 */ + ULONG ConsoleFlags; /**< 0x018 / 0x014 */ + HANDLE StandardInput; /**< 0x020 / 0x018 */ + HANDLE StandardOutput; /**< 0x028 / 0x01c */ + HANDLE StandardError; /**< 0x030 / 0x020 */ + CURDIR CurrentDirectory; /**< 0x038 / 0x024 */ + UNICODE_STRING DllPath; /**< 0x050 / 0x030 */ + UNICODE_STRING ImagePathName; /**< 0x060 / 0x038 */ + UNICODE_STRING CommandLine; /**< 0x070 / 0x040 */ + PWSTR Environment; /**< 0x080 / 0x048 */ + ULONG StartingX; /**< 0x088 / 0x04c */ + ULONG StartingY; /**< 0x090 / 0x050 */ + ULONG CountX; /**< 0x094 / 0x054 */ + ULONG CountY; /**< 0x098 / 0x058 */ + ULONG CountCharsX; /**< 0x09c / 0x05c */ + ULONG CountCharsY; /**< 0x0a0 / 0x060 */ + ULONG FillAttribute; /**< 0x0a4 / 0x064 */ + ULONG WindowFlags; /**< 0x0a8 / 0x068 */ + ULONG ShowWindowFlags; /**< 0x0ac / 0x06c */ + UNICODE_STRING WindowTitle; /**< 0x0b0 / 0x070 */ + UNICODE_STRING DesktopInfo; /**< 0x0c0 / 0x078 */ + UNICODE_STRING ShellInfo; /**< 0x0d0 / 0x080 */ + UNICODE_STRING RuntimeInfo; /**< 0x0e0 / 0x088 */ + RTL_DRIVE_LETTER_CURDIR CurrentDirectories[0x20]; /**< 0x0f0 / 0x090 */ + SIZE_T EnvironmentSize; /**< 0x3f0 / 0x - Added in Vista */ + SIZE_T EnvironmentVersion; /**< 0x3f8 / 0x - Added in Windows 7. */ + PVOID PackageDependencyData; /**< 0x400 / 0x - Added Windows 8? */ + ULONG ProcessGroupId; /**< 0x408 / 0x - Added Windows 8? */ + ULONG LoaderThreads; /**< 0x40c / 0x - Added Windows 10? */ +} RTL_USER_PROCESS_PARAMETERS; +typedef RTL_USER_PROCESS_PARAMETERS *PRTL_USER_PROCESS_PARAMETERS; +#define RTL_USER_PROCESS_PARAMS_FLAG_NORMALIZED 1 + +typedef struct _RTL_USER_PROCESS_INFORMATION +{ + ULONG Size; + HANDLE ProcessHandle; + HANDLE ThreadHandle; + CLIENT_ID ClientId; + SECTION_IMAGE_INFORMATION ImageInformation; +} RTL_USER_PROCESS_INFORMATION; +typedef RTL_USER_PROCESS_INFORMATION *PRTL_USER_PROCESS_INFORMATION; + + +RT_DECL_NTAPI(NTSTATUS) RtlCreateUserProcess(PUNICODE_STRING, ULONG, PRTL_USER_PROCESS_PARAMETERS, PSECURITY_DESCRIPTOR, + PSECURITY_DESCRIPTOR, HANDLE, BOOLEAN, HANDLE, HANDLE, PRTL_USER_PROCESS_INFORMATION); +RT_DECL_NTAPI(NTSTATUS) RtlCreateProcessParameters(PRTL_USER_PROCESS_PARAMETERS *, PUNICODE_STRING ImagePathName, + PUNICODE_STRING DllPath, PUNICODE_STRING CurrentDirectory, + PUNICODE_STRING CommandLine, PUNICODE_STRING Environment, + PUNICODE_STRING WindowTitle, PUNICODE_STRING DesktopInfo, + PUNICODE_STRING ShellInfo, PUNICODE_STRING RuntimeInfo); +RT_DECL_NTAPI(VOID) RtlDestroyProcessParameters(PRTL_USER_PROCESS_PARAMETERS); +RT_DECL_NTAPI(NTSTATUS) RtlCreateUserThread(HANDLE, PSECURITY_DESCRIPTOR, BOOLEAN, ULONG, SIZE_T, SIZE_T, + PFNRT, PVOID, PHANDLE, PCLIENT_ID); + +#ifndef RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO +typedef struct _RTL_CRITICAL_SECTION +{ + struct _RTL_CRITICAL_SECTION_DEBUG *DebugInfo; + LONG LockCount; + LONG Recursioncount; + HANDLE OwningThread; + HANDLE LockSemaphore; + ULONG_PTR SpinCount; +} RTL_CRITICAL_SECTION; +typedef RTL_CRITICAL_SECTION *PRTL_CRITICAL_SECTION; +#endif + +/*RT_DECL_NTAPI(ULONG) RtlNtStatusToDosError(NTSTATUS rcNt);*/ + +/** @def RTL_QUERY_REGISTRY_TYPECHECK + * WDK 8.1+, backported in updates, ignored in older. */ +#if !defined(RTL_QUERY_REGISTRY_TYPECHECK) || defined(DOXYGEN_RUNNING) +# define RTL_QUERY_REGISTRY_TYPECHECK UINT32_C(0x00000100) +#endif +/** @def RTL_QUERY_REGISTRY_TYPECHECK_SHIFT + * WDK 8.1+, backported in updates, ignored in older. */ +#if !defined(RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) || defined(DOXYGEN_RUNNING) +# define RTL_QUERY_REGISTRY_TYPECHECK_SHIFT 24 +#endif + +RT_DECL_NTAPI(VOID) RtlFreeUnicodeString(PUNICODE_STRING); + +RT_C_DECLS_END +/** @} */ + + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @name NT Kernel APIs + * @{ */ +RT_C_DECLS_BEGIN + +typedef ULONG KEPROCESSORINDEX; /**< Bitmap indexes != process numbers, apparently. */ + +RT_DECL_NTAPI(VOID) KeInitializeAffinityEx(PKAFFINITY_EX pAffinity); +typedef VOID (NTAPI *PFNKEINITIALIZEAFFINITYEX)(PKAFFINITY_EX pAffinity); +RT_DECL_NTAPI(VOID) KeAddProcessorAffinityEx(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef VOID (NTAPI *PFNKEADDPROCESSORAFFINITYEX)(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(VOID) KeRemoveProcessorAffinityEx(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef VOID (NTAPI *PFNKEREMOVEPROCESSORAFFINITYEX)(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(BOOLEAN) KeInterlockedSetProcessorAffinityEx(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef BOOLEAN (NTAPI *PFNKEINTERLOCKEDSETPROCESSORAFFINITYEX)(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(BOOLEAN) KeInterlockedClearProcessorAffinityEx(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef BOOLEAN (NTAPI *PFNKEINTERLOCKEDCLEARPROCESSORAFFINITYEX)(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(BOOLEAN) KeCheckProcessorAffinityEx(PCKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef BOOLEAN (NTAPI *PFNKECHECKPROCESSORAFFINITYEX)(PCKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(VOID) KeCopyAffinityEx(PKAFFINITY_EX pDst, PCKAFFINITY_EX pSrc); +typedef VOID (NTAPI *PFNKECOPYAFFINITYEX)(PKAFFINITY_EX pDst, PCKAFFINITY_EX pSrc); +RT_DECL_NTAPI(VOID) KeComplementAffinityEx(PKAFFINITY_EX pResult, PCKAFFINITY_EX pIn); +typedef VOID (NTAPI *PFNKECOMPLEMENTAFFINITYEX)(PKAFFINITY_EX pResult, PCKAFFINITY_EX pIn); +RT_DECL_NTAPI(BOOLEAN) KeAndAffinityEx(PCKAFFINITY_EX pIn1, PCKAFFINITY_EX pIn2, PKAFFINITY_EX pResult OPTIONAL); +typedef BOOLEAN (NTAPI *PFNKEANDAFFINITYEX)(PCKAFFINITY_EX pIn1, PCKAFFINITY_EX pIn2, PKAFFINITY_EX pResult OPTIONAL); +RT_DECL_NTAPI(BOOLEAN) KeOrAffinityEx(PCKAFFINITY_EX pIn1, PCKAFFINITY_EX pIn2, PKAFFINITY_EX pResult OPTIONAL); +typedef BOOLEAN (NTAPI *PFNKEORAFFINITYEX)(PCKAFFINITY_EX pIn1, PCKAFFINITY_EX pIn2, PKAFFINITY_EX pResult OPTIONAL); +/** Works like anding the complemented subtrahend with the minuend. */ +RT_DECL_NTAPI(BOOLEAN) KeSubtractAffinityEx(PCKAFFINITY_EX pMinuend, PCKAFFINITY_EX pSubtrahend, PKAFFINITY_EX pResult OPTIONAL); +typedef BOOLEAN (NTAPI *PFNKESUBTRACTAFFINITYEX)(PCKAFFINITY_EX pMinuend, PCKAFFINITY_EX pSubtrahend, PKAFFINITY_EX pResult OPTIONAL); +RT_DECL_NTAPI(BOOLEAN) KeIsEqualAffinityEx(PCKAFFINITY_EX pLeft, PCKAFFINITY_EX pRight); +typedef BOOLEAN (NTAPI *PFNKEISEQUALAFFINITYEX)(PCKAFFINITY_EX pLeft, PCKAFFINITY_EX pRight); +RT_DECL_NTAPI(BOOLEAN) KeIsEmptyAffinityEx(PCKAFFINITY_EX pAffinity); +typedef BOOLEAN (NTAPI *PFNKEISEMPTYAFFINITYEX)(PCKAFFINITY_EX pAffinity); +RT_DECL_NTAPI(BOOLEAN) KeIsSubsetAffinityEx(PCKAFFINITY_EX pSubset, PCKAFFINITY_EX pSuperSet); +typedef BOOLEAN (NTAPI *PFNKEISSUBSETAFFINITYEX)(PCKAFFINITY_EX pSubset, PCKAFFINITY_EX pSuperSet); +RT_DECL_NTAPI(ULONG) KeCountSetBitsAffinityEx(PCKAFFINITY_EX pAffinity); +typedef ULONG (NTAPI *PFNKECOUNTSETAFFINITYEX)(PCKAFFINITY_EX pAffinity); +RT_DECL_NTAPI(KEPROCESSORINDEX) KeFindFirstSetLeftAffinityEx(PCKAFFINITY_EX pAffinity); +typedef KEPROCESSORINDEX (NTAPI *PFNKEFINDFIRSTSETLEFTAFFINITYEX)(PCKAFFINITY_EX pAffinity); +typedef NTSTATUS (NTAPI *PFNKEGETPROCESSORNUMBERFROMINDEX)(KEPROCESSORINDEX idxProcessor, PPROCESSOR_NUMBER pProcNumber); +typedef KEPROCESSORINDEX (NTAPI *PFNKEGETPROCESSORINDEXFROMNUMBER)(const PROCESSOR_NUMBER *pProcNumber); +typedef NTSTATUS (NTAPI *PFNKEGETPROCESSORNUMBERFROMINDEX)(KEPROCESSORINDEX ProcIndex, PROCESSOR_NUMBER *pProcNumber); +typedef KEPROCESSORINDEX (NTAPI *PFNKEGETCURRENTPROCESSORNUMBEREX)(const PROCESSOR_NUMBER *pProcNumber); +typedef KAFFINITY (NTAPI *PFNKEQUERYACTIVEPROCESSORS)(VOID); +typedef ULONG (NTAPI *PFNKEQUERYMAXIMUMPROCESSORCOUNT)(VOID); +typedef ULONG (NTAPI *PFNKEQUERYMAXIMUMPROCESSORCOUNTEX)(USHORT GroupNumber); +typedef USHORT (NTAPI *PFNKEQUERYMAXIMUMGROUPCOUNT)(VOID); +typedef ULONG (NTAPI *PFNKEQUERYACTIVEPROCESSORCOUNT)(KAFFINITY *pfActiveProcessors); +typedef ULONG (NTAPI *PFNKEQUERYACTIVEPROCESSORCOUNTEX)(USHORT GroupNumber); +typedef NTSTATUS (NTAPI *PFNKEQUERYLOGICALPROCESSORRELATIONSHIP)(PROCESSOR_NUMBER *pProcNumber, + LOGICAL_PROCESSOR_RELATIONSHIP RelationShipType, + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pInfo, PULONG pcbInfo); +typedef PVOID (NTAPI *PFNKEREGISTERPROCESSORCHANGECALLBACK)(PPROCESSOR_CALLBACK_FUNCTION pfnCallback, void *pvUser, ULONG fFlags); +typedef VOID (NTAPI *PFNKEDEREGISTERPROCESSORCHANGECALLBACK)(PVOID pvCallback); +typedef NTSTATUS (NTAPI *PFNKESETTARGETPROCESSORDPCEX)(KDPC *pDpc, PROCESSOR_NUMBER *pProcNumber); +typedef LOGICAL (NTAPI *PFNKESHOULDYIELDPROCESSOR)(void); + +RT_DECL_NTAPI(BOOLEAN) ObFindHandleForObject(PEPROCESS pProcess, PVOID pvObject, POBJECT_TYPE pObjectType, + PVOID pvOptionalConditions, PHANDLE phFound); +RT_DECL_NTAPI(NTSTATUS) ObReferenceObjectByName(PUNICODE_STRING pObjectPath, ULONG fAttributes, PACCESS_STATE pAccessState, + ACCESS_MASK fDesiredAccess, POBJECT_TYPE pObjectType, + KPROCESSOR_MODE enmAccessMode, PVOID pvParseContext, PVOID *ppvObject); +RT_DECL_NTAPI(HANDLE) PsGetProcessInheritedFromUniqueProcessId(PEPROCESS); +RT_DECL_NTAPI(UCHAR *) PsGetProcessImageFileName(PEPROCESS); +RT_DECL_NTAPI(BOOLEAN) PsIsProcessBeingDebugged(PEPROCESS); +RT_DECL_NTAPI(ULONG) PsGetProcessSessionId(PEPROCESS); +extern DECLIMPORT(POBJECT_TYPE *) LpcPortObjectType; /**< In vista+ this is the ALPC port object type. */ +extern DECLIMPORT(POBJECT_TYPE *) LpcWaitablePortObjectType; /**< In vista+ this is the ALPC port object type. */ + +typedef VOID (NTAPI *PFNHALREQUESTIPI_PRE_W7)(KAFFINITY TargetSet); +typedef VOID (NTAPI *PFNHALREQUESTIPI_W7PLUS)(ULONG uUsuallyZero, PCKAFFINITY_EX pTargetSet); + +RT_C_DECLS_END +/** @ */ +#endif /* IN_RING0 */ + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @name NT Userland APIs + * @{ */ +RT_C_DECLS_BEGIN + +#if 0 /** @todo figure this out some time... */ +typedef struct CSR_MSG_DATA_CREATED_PROCESS +{ + HANDLE hProcess; + HANDLE hThread; + CLIENT_ID + DWORD idProcess; + DWORD idThread; + DWORD fCreate; + +} CSR_MSG_DATA_CREATED_PROCESS; + +#define CSR_MSG_NO_CREATED_PROCESS UINT32_C(0x10000) +#define CSR_MSG_NO_CREATED_THREAD UINT32_C(0x10001) +RT_DECL_NTAPI(NTSTATUS) CsrClientCallServer(PVOID, PVOID, ULONG, SIZE_T); +#endif + +RT_DECL_NTAPI(VOID) LdrInitializeThunk(PVOID, PVOID, PVOID); + +typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA +{ + ULONG Flags; + PCUNICODE_STRING FullDllName; + PCUNICODE_STRING BaseDllName; + PVOID DllBase; + ULONG SizeOfImage; +} LDR_DLL_LOADED_NOTIFICATION_DATA, LDR_DLL_UNLOADED_NOTIFICATION_DATA; +typedef LDR_DLL_LOADED_NOTIFICATION_DATA *PLDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA; +typedef LDR_DLL_LOADED_NOTIFICATION_DATA const *PCLDR_DLL_LOADED_NOTIFICATION_DATA, *PCLDR_DLL_UNLOADED_NOTIFICATION_DATA; + +typedef union _LDR_DLL_NOTIFICATION_DATA +{ + LDR_DLL_LOADED_NOTIFICATION_DATA Loaded; + LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded; +} LDR_DLL_NOTIFICATION_DATA; +typedef LDR_DLL_NOTIFICATION_DATA *PLDR_DLL_NOTIFICATION_DATA; +typedef LDR_DLL_NOTIFICATION_DATA const *PCLDR_DLL_NOTIFICATION_DATA; + +typedef VOID (NTAPI *PLDR_DLL_NOTIFICATION_FUNCTION)(ULONG ulReason, PCLDR_DLL_NOTIFICATION_DATA pData, PVOID pvUser); + +#define LDR_DLL_NOTIFICATION_REASON_LOADED UINT32_C(1) +#define LDR_DLL_NOTIFICATION_REASON_UNLOADED UINT32_C(2) +RT_DECL_NTAPI(NTSTATUS) LdrRegisterDllNotification(ULONG fFlags, PLDR_DLL_NOTIFICATION_FUNCTION pfnCallback, PVOID pvUser, + PVOID *pvCookie); +typedef NTSTATUS (NTAPI *PFNLDRREGISTERDLLNOTIFICATION)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, PVOID, PVOID *); +RT_DECL_NTAPI(NTSTATUS) LdrUnregisterDllNotification(PVOID pvCookie); +typedef NTSTATUS (NTAPI *PFNLDRUNREGISTERDLLNOTIFICATION)(PVOID); + +RT_DECL_NTAPI(NTSTATUS) LdrLoadDll(IN PWSTR pwszSearchPathOrFlags OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phMod); +typedef NTSTATUS (NTAPI *PFNLDRLOADDLL)(IN PWSTR pwszSearchPathOrFlags OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phMod); +RT_DECL_NTAPI(NTSTATUS) LdrUnloadDll(IN HANDLE hMod); +typedef NTSTATUS (NTAPI *PFNLDRUNLOADDLL)(IN HANDLE hMod); +RT_DECL_NTAPI(NTSTATUS) LdrGetDllHandle(IN PCWSTR pwszDllPath OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phDll); +typedef NTSTATUS (NTAPI *PFNLDRGETDLLHANDLE)(IN PCWSTR pwszDllPath OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phDll); +#define LDRGETDLLHANDLEEX_F_UNCHANGED_REFCOUNT RT_BIT_32(0) +#define LDRGETDLLHANDLEEX_F_PIN RT_BIT_32(1) +/** @since Windows XP. */ +RT_DECL_NTAPI(NTSTATUS) LdrGetDllHandleEx(IN ULONG fFlags, IN PCWSTR pwszDllPath OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phDll); +/** @since Windows XP. */ +typedef NTSTATUS (NTAPI *PFNLDRGETDLLHANDLEEX)(IN ULONG fFlags, IN PCWSTR pwszDllPath OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phDll); +/** @since Windows 7. */ +RT_DECL_NTAPI(NTSTATUS) LdrGetDllHandleByMapping(IN PVOID pvBase, OUT PHANDLE phDll); +/** @since Windows 7. */ +typedef NTSTATUS (NTAPI *PFNLDRGETDLLHANDLEBYMAPPING)(IN PVOID pvBase, OUT PHANDLE phDll); +/** @since Windows 7. */ +RT_DECL_NTAPI(NTSTATUS) LdrGetDllHandleByName(IN PCUNICODE_STRING pName OPTIONAL, IN PCUNICODE_STRING pFullName OPTIONAL, + OUT PHANDLE phDll); +/** @since Windows 7. */ +typedef NTSTATUS (NTAPI *PFNLDRGETDLLHANDLEBYNAME)(IN PCUNICODE_STRING pName OPTIONAL, IN PCUNICODE_STRING pFullName OPTIONAL, + OUT PHANDLE phDll); +#define LDRADDREFDLL_F_PIN RT_BIT_32(0) +RT_DECL_NTAPI(NTSTATUS) LdrAddRefDll(IN ULONG fFlags, IN HANDLE hDll); +typedef NTSTATUS (NTAPI *PFNLDRADDREFDLL)(IN ULONG fFlags, IN HANDLE hDll); +RT_DECL_NTAPI(NTSTATUS) LdrGetProcedureAddress(IN HANDLE hDll, IN ANSI_STRING const *pSymbol OPTIONAL, + IN ULONG uOrdinal OPTIONAL, OUT PVOID *ppvSymbol); +typedef NTSTATUS (NTAPI *PFNLDRGETPROCEDUREADDRESS)(IN HANDLE hDll, IN PCANSI_STRING pSymbol OPTIONAL, + IN ULONG uOrdinal OPTIONAL, OUT PVOID *ppvSymbol); +#define LDRGETPROCEDUREADDRESSEX_F_DONT_RECORD_FORWARDER RT_BIT_32(0) +/** @since Windows Vista. */ +RT_DECL_NTAPI(NTSTATUS) LdrGetProcedureAddressEx(IN HANDLE hDll, IN ANSI_STRING const *pSymbol OPTIONAL, + IN ULONG uOrdinal OPTIONAL, OUT PVOID *ppvSymbol, ULONG fFlags); +/** @since Windows Vista. */ +typedef NTSTATUS (NTAPI *PFNLDRGETPROCEDUREADDRESSEX)(IN HANDLE hDll, IN ANSI_STRING const *pSymbol OPTIONAL, + IN ULONG uOrdinal OPTIONAL, OUT PVOID *ppvSymbol, ULONG fFlags); +#define LDRLOCKLOADERLOCK_F_RAISE_ERRORS RT_BIT_32(0) +#define LDRLOCKLOADERLOCK_F_NO_WAIT RT_BIT_32(1) +#define LDRLOCKLOADERLOCK_DISP_INVALID UINT32_C(0) +#define LDRLOCKLOADERLOCK_DISP_ACQUIRED UINT32_C(1) +#define LDRLOCKLOADERLOCK_DISP_NOT_ACQUIRED UINT32_C(2) +/** @since Windows XP. */ +RT_DECL_NTAPI(NTSTATUS) LdrLockLoaderLock(IN ULONG fFlags, OUT PULONG puDisposition OPTIONAL, OUT PVOID *ppvCookie); +/** @since Windows XP. */ +typedef NTSTATUS (NTAPI *PFNLDRLOCKLOADERLOCK)(IN ULONG fFlags, OUT PULONG puDisposition OPTIONAL, OUT PVOID *ppvCookie); +#define LDRUNLOCKLOADERLOCK_F_RAISE_ERRORS RT_BIT_32(0) +/** @since Windows XP. */ +RT_DECL_NTAPI(NTSTATUS) LdrUnlockLoaderLock(IN ULONG fFlags, OUT PVOID pvCookie); +/** @since Windows XP. */ +typedef NTSTATUS (NTAPI *PFNLDRUNLOCKLOADERLOCK)(IN ULONG fFlags, OUT PVOID pvCookie); + +RT_DECL_NTAPI(NTSTATUS) RtlExpandEnvironmentStrings_U(PVOID, PUNICODE_STRING, PUNICODE_STRING, PULONG); +RT_DECL_NTAPI(VOID) RtlExitUserProcess(NTSTATUS rcExitCode); /**< Vista and later. */ +RT_DECL_NTAPI(VOID) RtlExitUserThread(NTSTATUS rcExitCode); +RT_DECL_NTAPI(NTSTATUS) RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG fFlags, + IN PCUNICODE_STRING pOrgName, + IN PUNICODE_STRING pDefaultSuffix, + IN OUT PUNICODE_STRING pStaticString, + IN OUT PUNICODE_STRING pDynamicString, + IN OUT PUNICODE_STRING *ppResultString, + IN PULONG pfNewFlags OPTIONAL, + IN PSIZE_T pcbFilename OPTIONAL, + IN PSIZE_T pcbNeeded OPTIONAL); +/** @since Windows 8. + * @note Status code is always zero in windows 10 build 14393. */ +RT_DECL_NTAPI(NTSTATUS) ApiSetQueryApiSetPresence(IN PCUNICODE_STRING pAllegedApiSetDll, OUT PBOOLEAN pfPresent); +/** @copydoc ApiSetQueryApiSetPresence */ +typedef NTSTATUS (NTAPI *PFNAPISETQUERYAPISETPRESENCE)(IN PCUNICODE_STRING pAllegedApiSetDll, OUT PBOOLEAN pfPresent); + + +# ifdef IPRT_NT_USE_WINTERNL +typedef NTSTATUS NTAPI RTL_HEAP_COMMIT_ROUTINE(PVOID, PVOID *, PSIZE_T); +typedef RTL_HEAP_COMMIT_ROUTINE *PRTL_HEAP_COMMIT_ROUTINE; +typedef struct _RTL_HEAP_PARAMETERS +{ + ULONG Length; + SIZE_T SegmentReserve; + SIZE_T SegmentCommit; + SIZE_T DeCommitFreeBlockThreshold; + SIZE_T DeCommitTotalFreeThreshold; + SIZE_T MaximumAllocationSize; + SIZE_T VirtualMemoryThreshold; + SIZE_T InitialCommit; + SIZE_T InitialReserve; + PRTL_HEAP_COMMIT_ROUTINE CommitRoutine; + SIZE_T Reserved[2]; +} RTL_HEAP_PARAMETERS; +typedef RTL_HEAP_PARAMETERS *PRTL_HEAP_PARAMETERS; +RT_DECL_NTAPI(PVOID) RtlCreateHeap(ULONG fFlags, PVOID pvHeapBase, SIZE_T cbReserve, SIZE_T cbCommit, PVOID pvLock, + PRTL_HEAP_PARAMETERS pParameters); +/** @name Heap flags (for RtlCreateHeap). + * @{ */ +/*# define HEAP_NO_SERIALIZE UINT32_C(0x00000001) +# define HEAP_GROWABLE UINT32_C(0x00000002) +# define HEAP_GENERATE_EXCEPTIONS UINT32_C(0x00000004) +# define HEAP_ZERO_MEMORY UINT32_C(0x00000008) +# define HEAP_REALLOC_IN_PLACE_ONLY UINT32_C(0x00000010) +# define HEAP_TAIL_CHECKING_ENABLED UINT32_C(0x00000020) +# define HEAP_FREE_CHECKING_ENABLED UINT32_C(0x00000040) +# define HEAP_DISABLE_COALESCE_ON_FREE UINT32_C(0x00000080)*/ +# define HEAP_SETTABLE_USER_VALUE UINT32_C(0x00000100) +# define HEAP_SETTABLE_USER_FLAG1 UINT32_C(0x00000200) +# define HEAP_SETTABLE_USER_FLAG2 UINT32_C(0x00000400) +# define HEAP_SETTABLE_USER_FLAG3 UINT32_C(0x00000800) +# define HEAP_SETTABLE_USER_FLAGS UINT32_C(0x00000e00) +# define HEAP_CLASS_0 UINT32_C(0x00000000) +# define HEAP_CLASS_1 UINT32_C(0x00001000) +# define HEAP_CLASS_2 UINT32_C(0x00002000) +# define HEAP_CLASS_3 UINT32_C(0x00003000) +# define HEAP_CLASS_4 UINT32_C(0x00004000) +# define HEAP_CLASS_5 UINT32_C(0x00005000) +# define HEAP_CLASS_6 UINT32_C(0x00006000) +# define HEAP_CLASS_7 UINT32_C(0x00007000) +# define HEAP_CLASS_8 UINT32_C(0x00008000) +# define HEAP_CLASS_MASK UINT32_C(0x0000f000) +# endif +# define HEAP_CLASS_PROCESS HEAP_CLASS_0 +# define HEAP_CLASS_PRIVATE HEAP_CLASS_1 +# define HEAP_CLASS_KERNEL HEAP_CLASS_2 +# define HEAP_CLASS_GDI HEAP_CLASS_3 +# define HEAP_CLASS_USER HEAP_CLASS_4 +# define HEAP_CLASS_CONSOLE HEAP_CLASS_5 +# define HEAP_CLASS_USER_DESKTOP HEAP_CLASS_6 +# define HEAP_CLASS_CSRSS_SHARED HEAP_CLASS_7 +# define HEAP_CLASS_CSRSS_PORT HEAP_CLASS_8 +# ifdef IPRT_NT_USE_WINTERNL +/*# define HEAP_CREATE_ALIGN_16 UINT32_C(0x00010000) +# define HEAP_CREATE_ENABLE_TRACING UINT32_C(0x00020000) +# define HEAP_CREATE_ENABLE_EXECUTE UINT32_C(0x00040000)*/ +# define HEAP_CREATE_VALID_MASK UINT32_C(0x0007f0ff) +# endif /* IPRT_NT_USE_WINTERNL */ +/** @} */ +# ifdef IPRT_NT_USE_WINTERNL +/** @name Heap tagging constants + * @{ */ +# define HEAP_GLOBAL_TAG UINT32_C(0x00000800) +/*# define HEAP_MAXIMUM_TAG UINT32_C(0x00000fff) +# define HEAP_PSEUDO_TAG_FLAG UINT32_C(0x00008000) +# define HEAP_TAG_SHIFT 18 */ +# define HEAP_TAG_MASK (HEAP_MAXIMUM_TAG << HEAP_TAG_SHIFT) +/** @} */ +RT_DECL_NTAPI(PVOID) RtlAllocateHeap(HANDLE hHeap, ULONG fFlags, SIZE_T cb); +RT_DECL_NTAPI(PVOID) RtlReAllocateHeap(HANDLE hHeap, ULONG fFlags, PVOID pvOld, SIZE_T cbNew); +RT_DECL_NTAPI(BOOLEAN) RtlFreeHeap(HANDLE hHeap, ULONG fFlags, PVOID pvMem); +# endif /* IPRT_NT_USE_WINTERNL */ +RT_DECL_NTAPI(SIZE_T) RtlCompactHeap(HANDLE hHeap, ULONG fFlags); +RT_DECL_NTAPI(SIZE_T) RtlSizeHeap(HANDLE hHeap, ULONG fFlags, PVOID pvMem); +RT_DECL_NTAPI(NTSTATUS) RtlGetLastNtStatus(VOID); +RT_DECL_NTAPI(ULONG) RtlGetLastWin32Error(VOID); +RT_DECL_NTAPI(VOID) RtlSetLastWin32Error(ULONG uError); +RT_DECL_NTAPI(VOID) RtlSetLastWin32ErrorAndNtStatusFromNtStatus(NTSTATUS rcNt); +RT_DECL_NTAPI(VOID) RtlRestoreLastWin32Error(ULONG uError); +RT_DECL_NTAPI(BOOLEAN) RtlQueryPerformanceCounter(PLARGE_INTEGER); +RT_DECL_NTAPI(uint64_t) RtlGetSystemTimePrecise(VOID); +typedef uint64_t (NTAPI * PFNRTLGETSYSTEMTIMEPRECISE)(VOID); +RT_DECL_NTAPI(uint64_t) RtlGetInterruptTimePrecise(uint64_t *puPerfTime); +typedef uint64_t (NTAPI * PFNRTLGETINTERRUPTTIMEPRECISE)(uint64_t *); +RT_DECL_NTAPI(BOOLEAN) RtlQueryUnbiasedInterruptTime(uint64_t *puInterruptTime); +typedef BOOLEAN (NTAPI * PFNRTLQUERYUNBIASEDINTERRUPTTIME)(uint64_t *); + +RT_C_DECLS_END +/** @} */ +#endif /* IN_RING3 */ + +#endif /* !IPRT_INCLUDED_nt_nt_h */ + diff --git a/include/iprt/nt/ntddk.h b/include/iprt/nt/ntddk.h new file mode 100644 index 00000000..51313368 --- /dev/null +++ b/include/iprt/nt/ntddk.h @@ -0,0 +1,83 @@ +/** @file + * Safe way to include ntddk.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_ntddk_h +#define IPRT_INCLUDED_nt_ntddk_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure we get the right prototypes. */ +#include + +#define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap +#define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap +#define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap +#define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap +#define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap +#define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap +#define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap +#define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap + +#pragma warning(push) +#pragma warning(disable:4163) +#pragma warning(disable:4668) /* warning C4668: 'WHEA_DOWNLEVEL_TYPE_NAMES' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable:4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +#if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4471) /* wdm.h(11057) : warning C4471: '_POOL_TYPE' : a forward declaration of an unscoped enumeration must have an underlying type (int assumed) */ +#endif + +/* Include the sdk/ddk version header so _WIN32_VER and the rest gets defined before ntdef.h is included, + otherwise we'll miss out on DECLARE_GLOBAL_CONST_UNICODE_STRING and friends in the W10 SDKs. */ +#define DECLSPEC_DEPRECATED_DDK +#include + +/*RT_C_DECLS_BEGIN - no longer necessary it seems */ +#include +/*RT_C_DECLS_END - no longer necessary it seems */ +#pragma warning(pop) + +#undef _InterlockedExchange +#undef _InterlockedExchangeAdd +#undef _InterlockedCompareExchange +#undef _InterlockedAddLargeStatistic +#undef _interlockedbittestandset +#undef _interlockedbittestandreset +#undef _interlockedbittestandset64 +#undef _interlockedbittestandreset64 + +#endif /* !IPRT_INCLUDED_nt_ntddk_h */ + diff --git a/include/iprt/nt/rx.h b/include/iprt/nt/rx.h new file mode 100644 index 00000000..99c40d4a --- /dev/null +++ b/include/iprt/nt/rx.h @@ -0,0 +1,65 @@ +/** @file + * Safe way to include rx.h (DDK/IFS). + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_rx_h +#define IPRT_INCLUDED_nt_rx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4668) /* rxovride.h(38) : warning C4668: 'DBG' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# pragma warning(disable: 4100) /* Fcb.h(1558) : warning C4100: 'SrvOpen' : unreferenced formal parameter */ +# pragma warning(disable: 4115) /* rxce.h(106) : warning C4115: '_ADAPTER_STATUS' : named type definition in parentheses */ +# ifndef __cplusplus +# pragma warning(disable: 4255) /* rxworkq.h(235) : warning C4255: 'RxInitializeDispatcher' : no function prototype given: converting '()' to '(void)' */ +# endif +#endif + +RT_C_DECLS_BEGIN + +#include + +RT_C_DECLS_END + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_rx_h */ + diff --git a/include/iprt/nt/tdikrnl.h b/include/iprt/nt/tdikrnl.h new file mode 100644 index 00000000..94446f72 --- /dev/null +++ b/include/iprt/nt/tdikrnl.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include tdikrnl.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_tdikrnl_h +#define IPRT_INCLUDED_nt_tdikrnl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* warning C4668: 'NTDDI_WINS03' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +RT_C_DECLS_BEGIN +#include +RT_C_DECLS_END +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_nt_tdikrnl_h */ + diff --git a/include/iprt/nt/vid.h b/include/iprt/nt/vid.h new file mode 100644 index 00000000..a319af67 --- /dev/null +++ b/include/iprt/nt/vid.h @@ -0,0 +1,313 @@ +/** @file + * Virtualization Infrastructure Driver (VID) API. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_vid_h +#define IPRT_INCLUDED_nt_vid_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "hyperv.h" + + +/** + * Output from VidMessageSlotMap. + */ +typedef struct VID_MAPPED_MESSAGE_SLOT +{ + /** The message block mapping. */ + struct _HV_MESSAGE *pMsgBlock; + /** Copy of input iCpu. */ + uint32_t iCpu; + /** Explicit padding. */ + uint32_t uParentAdvisory; +} VID_MAPPED_MESSAGE_SLOT; +/** Pointer to VidMessageSlotMap output structure. */ +typedef VID_MAPPED_MESSAGE_SLOT *PVID_MAPPED_MESSAGE_SLOT; + + +/** @name VID_MESSAGE_MAPPING_HEADER::enmVidMsgType values (wild guess). + * @{ */ +/** Type mask, strips flags. */ +#define VID_MESSAGE_TYPE_MASK UINT32_C(0x00ffffff) +/** No return message necessary. */ +#define VID_MESSAGE_TYPE_FLAG_NO_RETURN UINT32_C(0x01000000) +/** Observed message values. */ +typedef enum +{ + /** Invalid zero value. */ + VidMessageInvalid = 0, + /** Guessing this means a message from the hypervisor. */ + VidMessageHypervisorMessage = 0x00000c | VID_MESSAGE_TYPE_FLAG_NO_RETURN, + /** Guessing this means stop request completed. Message length is 1 byte. */ + VidMessageStopRequestComplete = 0x00000d | VID_MESSAGE_TYPE_FLAG_NO_RETURN, +} VID_MESSAGE_TYPE; +AssertCompileSize(VID_MESSAGE_TYPE, 4); +/** @} */ + +/** + * Header of the message mapping returned by VidMessageSlotMap. + */ +typedef struct VID_MESSAGE_MAPPING_HEADER +{ + /** Current guess is that this is VID_MESSAGE_TYPE. */ + VID_MESSAGE_TYPE enmVidMsgType; + /** The message size or so it seems (0x100). */ + uint32_t cbMessage; + /** So far these have been zero. */ + uint32_t aZeroPPadding[2+4]; +} VID_MESSAGE_MAPPING_HEADER; +AssertCompileSize(VID_MESSAGE_MAPPING_HEADER, 32); + +/** + * VID processor status (VidGetVirtualProcessorRunningStatus). + * + * @note This is used internally in VID.SYS, in 17101 it's at offset 8 in their + * 'pVCpu' structure. + */ +typedef enum +{ + VidProcessorStatusStopped = 0, + VidProcessorStatusRunning, + VidProcessorStatusSuspended, + VidProcessorStatusUndefined = 0xffff +} VID_PROCESSOR_STATUS; +AssertCompileSize(VID_PROCESSOR_STATUS, 4); + + +/** I/O control input for VidMessageSlotHandleAndGetNext. */ +typedef struct VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT +{ + HV_VP_INDEX iCpu; + uint32_t fFlags; /**< VID_MSHAGN_F_GET_XXX*/ + uint32_t cMillies; /**< Not present in build 17758 as the API changed to always to infinite waits. */ +} VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT; +/** Pointer to input for VidMessageSlotHandleAndGetNext. */ +typedef VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT *PVID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT; +/** Pointer to const input for VidMessageSlotHandleAndGetNext. */ +typedef VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT const *PCVID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT; + +/** @name VID_MSHAGN_F_GET_XXX - Flags for VidMessageSlotHandleAndGetNext + * @{ */ +/** This will try get the next message, waiting if necessary. + * It is subject to NtAlertThread processing when it starts waiting. */ +#define VID_MSHAGN_F_GET_NEXT_MESSAGE RT_BIT_32(0) +/** ACK the message as handled and resume execution/whatever. + * This is executed before VID_MSHAGN_F_GET_NEXT_MESSAGE and should not be + * subject to NtAlertThread side effects. */ +#define VID_MSHAGN_F_HANDLE_MESSAGE RT_BIT_32(1) +/** Cancel VP execution (no other bit set). + * @since about build 17758. */ +#define VID_MSHAGN_F_CANCEL RT_BIT_32(2) +/** @} */ + +/** A 64-bit version of HV_PARTITION_PROPERTY_CODE. */ +typedef int64_t VID_PARTITION_PROPERTY_CODE; + + +#ifdef IN_RING3 +RT_C_DECLS_BEGIN + +/** Calling convention. */ +#ifndef WINAPI +# define VIDAPI __stdcall +#else +# define VIDAPI WINAPI +#endif + +/** Partition handle. */ +#ifndef WINAPI +typedef void *VID_PARTITION_HANDLE; +#else +typedef HANDLE VID_PARTITION_HANDLE; +#endif + +/** + * Gets the partition ID. + * + * The partition ID is the numeric identifier used when making hypercalls to the + * hypervisor. + * + * @note Starting with Windows 11 (or possibly earlier), this does not work on + * Exo partition as created by WHvCreatePartition. It returns a + * STATUS_NOT_IMPLEMENTED as the I/O control code is not allowed through. + * All partitions has an ID though, so just pure annoying blockheadedness + * sprung upon us w/o any chance of doing a memory managment rewrite in + * time. + */ +DECLIMPORT(BOOL) VIDAPI VidGetHvPartitionId(VID_PARTITION_HANDLE hPartition, HV_PARTITION_ID *pidPartition); + +/** + * Get a partition property. + * + * @returns Success indicator (details in LastErrorValue). + * @param hPartition The partition handle. + * @param enmProperty The property to get. Is a HV_PARTITION_PROPERTY_CODE + * type, but seems to be passed around as a 64-bit integer + * for some reason. + * @param puValue Where to return the property value. + */ +DECLIMPORT(BOOL) VIDAPI VidGetPartitionProperty(VID_PARTITION_HANDLE hPartition, VID_PARTITION_PROPERTY_CODE enmProperty, + PHV_PARTITION_PROPERTY puValue); + +/** + * @copydoc VidGetPartitionProperty + * @note Currently (Windows 11 GA) identical to VidGetPartitionProperty. + */ +DECLIMPORT(BOOL) VIDAPI VidGetExoPartitionProperty(VID_PARTITION_HANDLE hPartition, VID_PARTITION_PROPERTY_CODE enmProperty, + PHV_PARTITION_PROPERTY puValue); + +/** + * Starts asynchronous execution of a virtual CPU. + */ +DECLIMPORT(BOOL) VIDAPI VidStartVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu); + +/** + * Stops the asynchronous execution of a virtual CPU. + * + * @retval ERROR_VID_STOP_PENDING if busy with intercept, check messages. + */ +DECLIMPORT(BOOL) VIDAPI VidStopVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu); + +/** + * WHvCreateVirtualProcessor boils down to a call to VidMessageSlotMap and + * some internal WinHvPlatform state fiddling. + * + * Looks like it maps memory and returns the pointer to it. + * VidMessageSlotHandleAndGetNext is later used to wait for the next message and + * put (??) it into that memory mapping. + * + * @returns Success indicator (details in LastErrorValue). + * + * @param hPartition The partition handle. + * @param pOutput Where to return the pointer to the message memory + * mapping. The CPU index is also returned here. + * @param iCpu The CPU to wait-and-get messages for. + */ +DECLIMPORT(BOOL) VIDAPI VidMessageSlotMap(VID_PARTITION_HANDLE hPartition, PVID_MAPPED_MESSAGE_SLOT pOutput, HV_VP_INDEX iCpu); + +/** + * This is used by WHvRunVirtualProcessor to wait for the next exit msg. + * + * The message appears in the memory mapping returned by VidMessageSlotMap. + * + * @returns Success indicator (details only in LastErrorValue - LastStatusValue + * is not set). + * @retval STATUS_TIMEOUT for STATUS_TIMEOUT as well as STATUS_USER_APC and + * STATUS_ALERTED. + * + * @param hPartition The partition handle. + * @param iCpu The CPU to wait-and-get messages for. + * @param fFlags Flags, VID_MSHAGN_F_XXX. + * + * When starting or resuming execution, at least one of + * VID_MSHAGN_F_GET_NEXT_MESSAGE (bit 0) and + * VID_MSHAGN_F_HANDLE_MESSAGE (bit 1) must be set. + * + * When cancelling execution only VID_MSHAGN_F_CANCEL (big 2) + * must be set. + * + * @param cMillies The timeout, presumably in milliseconds. This parameter + * was dropped about build 17758. + * + * @todo Would be awfully nice if someone at Microsoft could hit at the + * flags here. + */ +DECLIMPORT(BOOL) VIDAPI VidMessageSlotHandleAndGetNext(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu, + uint32_t fFlags, uint32_t cMillies); +/** + * Gets the processor running status. + * + * This is probably only available in special builds, as one of the early I/O + * control dispatching routines will not let it thru. Lower down routines does + * implement it, so it's possible to patch it into working. This works for + * build 17101: eb vid+12180 0f 84 98 00 00 00 + * + * @retval ERROR_NOT_IMPLEMENTED + * + * @remarks VidExoFastIoControlPartition probably disapproves of this too. It + * could be very handy for debugging upon occation. + */ +DECLIMPORT(BOOL) VIDAPI VidGetVirtualProcessorRunningStatus(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu, + VID_PROCESSOR_STATUS *penmStatus); + +/** + * For query virtual processor registers and other state information. + * + * @returns Success indicator (details in LastErrorValue). + */ +DECLIMPORT(BOOL) VIDAPI VidGetVirtualProcessorState(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu, + HV_REGISTER_NAME const *paRegNames, uint32_t cRegisters, + HV_REGISTER_VALUE *paRegValues); + +/** + * For setting virtual processor registers and other state information. + * + * @returns Success indicator (details in LastErrorValue). + */ +DECLIMPORT(BOOL) VIDAPI VidSetVirtualProcessorState(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu, + HV_REGISTER_NAME const *paRegNames, uint32_t cRegisters, + HV_REGISTER_VALUE const *paRegValues); + +/** + * Wrapper around the HvCallGetMemoryBalance hypercall. + * + * When VID.SYS processes the request, it will also query + * HvPartitionPropertyVirtualTlbPageCount, so we're passing a 3rd return + * parameter in case the API is ever extended to match the I/O control. + * + * @returns Success indicator (details in LastErrorValue). + * @retval ERROR_NOT_IMPLEMENTED for exo partitions. + * + * @param hPartition The partition handle. + * @param pcPagesAvailable Where to return the number of unused pages + * still available to the partition. + * @param pcPagesInUse Where to return the number of pages currently + * in use by the partition. + * @param pReserved Pointer to dummy value, just in case they + * modify the API to include the nested TLB size. + * + * @note Not available for exo partitions, unfortunately. The + * VidExoFastIoControlPartition function deflects it, failing it with + * STATUS_NOT_IMPLEMENTED / ERROR_NOT_IMPLEMENTED. + */ +DECLIMPORT(BOOL) VIDAPI VidGetHvMemoryBalance(VID_PARTITION_HANDLE hPartition, uint64_t *pcPagesAvailable, + uint64_t *pcPagesInUse, uint64_t *pReserved); + +RT_C_DECLS_END +#endif /* IN_RING3 */ + +#endif /* !IPRT_INCLUDED_nt_vid_h */ + diff --git a/include/iprt/nt/video.h b/include/iprt/nt/video.h new file mode 100644 index 00000000..f48ab5ab --- /dev/null +++ b/include/iprt/nt/video.h @@ -0,0 +1,59 @@ +/** @file + * Safe way to include video.h (DDK). + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_video_h +#define IPRT_INCLUDED_nt_video_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'DBG' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# ifndef __cplusplus +# pragma warning(disable:4255) /* warning C4255: 'VideoPortGetCurrentIrql' : no function prototype given: converting '()' to '(void)'*/ +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_video_h */ + diff --git a/include/iprt/nt/wdm.h b/include/iprt/nt/wdm.h new file mode 100644 index 00000000..06560e90 --- /dev/null +++ b/include/iprt/nt/wdm.h @@ -0,0 +1,81 @@ +/** @file + * Safe way to include wdm.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_wdm_h +#define IPRT_INCLUDED_nt_wdm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure we get the right prototypes. */ +#include + +#define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap +#define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap +#define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap +#define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap +#define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap +#define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap +#define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap +#define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap + +#pragma warning(push) +#pragma warning(disable:4163) +#pragma warning(disable:4668) /* warning C4668: 'WHEA_DOWNLEVEL_TYPE_NAMES' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable:4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +#pragma warning(disable:4005) /* wdm.h(29) : warning C4005: 'NO_INTERLOCKED_INTRINSICS' : macro redefinition */ +#if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4471) /* wdm.h(11057) : warning C4471: '_POOL_TYPE' : a forward declaration of an unscoped enumeration must have an underlying type (int assumed) */ +#endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* warning C5039: 'KeInitializeDpc': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#include +#pragma warning(pop) + +#undef _InterlockedExchange +#undef _InterlockedExchangeAdd +#undef _InterlockedCompareExchange +#undef _InterlockedAddLargeStatistic +#undef _interlockedbittestandset +#undef _interlockedbittestandreset +#undef _interlockedbittestandset64 +#undef _interlockedbittestandreset64 + +#endif /* !IPRT_INCLUDED_nt_wdm_h */ + diff --git a/include/iprt/once.h b/include/iprt/once.h new file mode 100644 index 00000000..eb734e79 --- /dev/null +++ b/include/iprt/once.h @@ -0,0 +1,231 @@ +/** @file + * IPRT - Execute Once. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_once_h +#define IPRT_INCLUDED_once_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_once RTOnce - Execute Once + * @ingroup grp_rt + * @{ + */ + +/** + * Callback that gets executed once. + * + * @returns IPRT style status code, RTOnce returns this. + * + * @param pvUser The user parameter. + */ +typedef DECLCALLBACKTYPE(int32_t, FNRTONCE,(void *pvUser)); +/** Pointer to a FNRTONCE. */ +typedef FNRTONCE *PFNRTONCE; + +/** + * Callback that gets executed on IPRT/process termination. + * + * @param pvUser The user parameter. + * @param fLazyCleanUpOk Indicates whether lazy clean-up is OK (see + * initterm.h). + */ +typedef DECLCALLBACKTYPE(void, FNRTONCECLEANUP,(void *pvUser, bool fLazyCleanUpOk)); +/** Pointer to a FNRTONCE. */ +typedef FNRTONCECLEANUP *PFNRTONCECLEANUP; + +/** + * Execute once structure. + * + * This is typically a global variable that is statically initialized + * by RTONCE_INITIALIZER. + */ +typedef struct RTONCE +{ + /** Event semaphore that the other guys are blocking on. */ + RTSEMEVENTMULTI volatile hEventMulti; + /** Reference counter for hEventMulti. */ + int32_t volatile cEventRefs; + /** See RTONCESTATE. */ + int32_t volatile iState; + /** The return code of pfnOnce. */ + int32_t volatile rc; + + /** Pointer to the clean-up function. */ + PFNRTONCECLEANUP pfnCleanUp; + /** Argument to hand to the clean-up function. */ + void *pvUser; + /** Clean-up list entry. */ + RTLISTNODE CleanUpNode; +} RTONCE; +/** Pointer to a execute once struct. */ +typedef RTONCE *PRTONCE; + +/** + * The execute once statemachine. + */ +typedef enum RTONCESTATE +{ + /** RTOnce() has not been called. + * Next: NO_SEM */ + RTONCESTATE_UNINITIALIZED = 1, + /** RTOnce() is busy, no race. + * Next: CREATING_SEM, DONE */ + RTONCESTATE_BUSY_NO_SEM, + /** More than one RTOnce() caller is busy. + * Next: BUSY_HAVE_SEM, BUSY_SPIN, DONE_CREATING_SEM, DONE */ + RTONCESTATE_BUSY_CREATING_SEM, + /** More than one RTOnce() caller, the first is busy, the others are + * waiting. + * Next: DONE */ + RTONCESTATE_BUSY_HAVE_SEM, + /** More than one RTOnce() caller, the first is busy, the others failed to + * create a semaphore and are spinning. + * Next: DONE */ + RTONCESTATE_BUSY_SPIN, + /** More than one RTOnce() caller, the first has completed, the others + * are busy creating the semaphore. + * Next: DONE_HAVE_SEM */ + RTONCESTATE_DONE_CREATING_SEM, + /** More than one RTOnce() caller, the first is busy grabbing the + * semaphore, while the others are waiting. + * Next: DONE */ + RTONCESTATE_DONE_HAVE_SEM, + /** The execute once stuff has completed. */ + RTONCESTATE_DONE = 16 +} RTONCESTATE; + +/** Static initializer for RTONCE variables. */ +#define RTONCE_INITIALIZER \ + { NIL_RTSEMEVENTMULTI, 0, RTONCESTATE_UNINITIALIZED, VERR_INTERNAL_ERROR, NULL, NULL, { NULL, NULL } } + + +/** + * Serializes execution of the pfnOnce function, making sure it's + * executed exactly once and that nobody returns from RTOnce before + * it has executed successfully. + * + * @returns IPRT like status code returned by pfnOnce. + * + * @param pOnce Pointer to the execute once variable. + * @param pfnOnce The function to executed once. + * @param pfnCleanUp The function that will be doing the cleaning up. + * Optional. + * @param pvUser The user parameter for pfnOnce. + */ +RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, FNRTONCECLEANUP pfnCleanUp, void *pvUser); + +/** + * Serializes execution of the pfnOnce function, making sure it's + * executed exactly once and that nobody returns from RTOnce before + * it has executed successfully. + * + * @returns IPRT like status code returned by pfnOnce. + * + * @param pOnce Pointer to the execute once variable. + * @param pfnOnce The function to executed once. + * @param pvUser The user parameter for pfnOnce. + */ +DECLINLINE(int) RTOnce(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser) +{ + int32_t iState = ASMAtomicUoReadS32(&pOnce->iState); + if (RT_LIKELY( iState == RTONCESTATE_DONE + || iState == RTONCESTATE_DONE_CREATING_SEM + || iState == RTONCESTATE_DONE_HAVE_SEM )) + return ASMAtomicUoReadS32(&pOnce->rc); + return RTOnceSlow(pOnce, pfnOnce, NULL, pvUser); +} + +/** + * Execute pfnOnce once and register a termination clean-up callback. + * + * Serializes execution of the pfnOnce function, making sure it's + * executed exactly once and that nobody returns from RTOnce before + * it has executed successfully. + * + * @returns IPRT like status code returned by pfnOnce. + * + * @param pOnce Pointer to the execute once variable. + * @param pfnOnce The function to executed once. + * @param pfnCleanUp The function that will be doing the cleaning up. + * @param pvUser The user parameter for pfnOnce. + */ +DECLINLINE(int) RTOnceEx(PRTONCE pOnce, PFNRTONCE pfnOnce, PFNRTONCECLEANUP pfnCleanUp, void *pvUser) +{ + int32_t iState = ASMAtomicUoReadS32(&pOnce->iState); + if (RT_LIKELY( iState == RTONCESTATE_DONE + || iState == RTONCESTATE_DONE_CREATING_SEM + || iState == RTONCESTATE_DONE_HAVE_SEM )) + return ASMAtomicUoReadS32(&pOnce->rc); + return RTOnceSlow(pOnce, pfnOnce, pfnCleanUp, pvUser); +} + +/** + * Resets an execute once variable. + * + * The caller is responsible for making sure there are no concurrent accesses to + * the execute once variable. + * + * @param pOnce Pointer to the execute once variable. + */ +RTDECL(void) RTOnceReset(PRTONCE pOnce); + +/** + * Check whether the execute once variable was successfullly initialized. + */ +DECLINLINE(bool) RTOnceWasInitialized(PRTONCE pOnce) +{ + int32_t const iState = ASMAtomicUoReadS32(&pOnce->iState); + int32_t const rc = ASMAtomicUoReadS32(&pOnce->rc); + return RT_SUCCESS(rc) + && ( iState == RTONCESTATE_DONE + || iState == RTONCESTATE_DONE_CREATING_SEM + || iState == RTONCESTATE_DONE_HAVE_SEM); +} + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_once_h */ + diff --git a/include/iprt/param.h b/include/iprt/param.h new file mode 100644 index 00000000..224064b6 --- /dev/null +++ b/include/iprt/param.h @@ -0,0 +1,137 @@ +/** @file + * IPRT - Parameter Definitions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_param_h +#define IPRT_INCLUDED_param_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @todo Much of the PAGE_* stuff here is obsolete and highly risky to have around. + * As for component configs (MM_*), either we gather all in here or we move those bits away! */ + +/** @defgroup grp_rt_param System Parameter Definitions + * @ingroup grp_rt_cdefs + * @{ + */ + +/* Undefine PAGE_SIZE and PAGE_SHIFT to avoid unnecessary noice when clashing + * with system headers. Include system headers before / after iprt depending + * on which you wish to take precedence. */ +#undef PAGE_SIZE +#undef PAGE_SHIFT + +/* Undefine PAGE_OFFSET_MASK to avoid the conflict with the-linux-kernel.h */ +#undef PAGE_OFFSET_MASK + +/** + * i386 Page size. + */ +#if defined(RT_ARCH_SPARC64) +# define PAGE_SIZE 8192 +#elif defined(RT_ARCH_ARM64) +# define PAGE_SIZE 16384 +#else +# define PAGE_SIZE 4096 +#endif + +/** + * i386 Page shift. + * This is used to convert between size (in bytes) and page count. + */ +#if defined(RT_ARCH_SPARC64) +# define PAGE_SHIFT 13 +#elif defined(RT_ARCH_ARM64) +# define PAGE_SHIFT 14 +#else +# define PAGE_SHIFT 12 +#endif + +/** + * i386 Page offset mask. + * + * @note If you do one-complement this, always insert a target type case after + * the operator! Otherwise you may end up with weird results. + */ +#if defined(RT_ARCH_SPARC64) +# define PAGE_OFFSET_MASK 0x1fff +#elif defined(RT_ARCH_ARM64) +# define PAGE_OFFSET_MASK 0x3fff +#else +# define PAGE_OFFSET_MASK 0xfff +#endif + +/** + * Page address mask for the uintptr_t sized pointers. + * + * Be careful when using this since it may be a size too big! + * @remark Physical addresses are always masked using X86_PTE_PAE_PG_MASK! + */ +#define PAGE_BASE_MASK (~(uintptr_t)PAGE_OFFSET_MASK) + +/** + * Get the page aligned address of a POINTER in the CURRENT context. + * + * @returns Page aligned address (it's an uintptr_t). + * @param pv The virtual address to align. + * + * @remarks Physical addresses are always masked using X86_PTE_PAE_PG_MASK! + * @remarks This only works with POINTERS in the current context. + * Do NOT use on guest address or physical address! + */ +#define PAGE_ADDRESS(pv) ((uintptr_t)(pv) & ~(uintptr_t)PAGE_OFFSET_MASK) + +/** + * Get the page aligned address of a physical address + * + * @returns Page aligned address (it's an RTHCPHYS or RTGCPHYS). + * @param Phys The physical address to align. + */ +#define PHYS_PAGE_ADDRESS(Phys) ((Phys) & X86_PTE_PAE_PG_MASK) + +/** + * Host max path (the reasonable value). + * @remarks defined both by iprt/param.h and iprt/path.h. + */ +#if !defined(IPRT_INCLUDED_path_h) || defined(DOXYGEN_RUNNING) +# define RTPATH_MAX (4096 + 4) /* (PATH_MAX + 1) on linux w/ some alignment */ +#endif + +/** @} */ + +#endif /* !IPRT_INCLUDED_param_h */ + diff --git a/include/iprt/path.h b/include/iprt/path.h new file mode 100644 index 00000000..285d9f19 --- /dev/null +++ b/include/iprt/path.h @@ -0,0 +1,1674 @@ +/** @file + * IPRT - Path Manipulation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_path_h +#define IPRT_INCLUDED_path_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#ifdef IN_RING3 +# include +#endif + + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_path RTPath - Path Manipulation + * @ingroup grp_rt + * @{ + */ + +/** + * Host max path (the reasonable value). + * @remarks defined both by iprt/param.h and iprt/path.h. + */ +#if !defined(IPRT_INCLUDED_param_h) || defined(DOXYGEN_RUNNING) +# define RTPATH_MAX (4096 + 4) /* (PATH_MAX + 1) on linux w/ some alignment */ +#endif + +/** + * The absolute max host path length we are willing to support. + * @note Not really suitable for stack buffers. + */ +#define RTPATH_BIG_MAX (_64K) + +/** @def RTPATH_TAG + * The default allocation tag used by the RTPath allocation APIs. + * + * When not defined before the inclusion of iprt/string.h, this will default to + * the pointer to the current file name. The string API will make of use of + * this as pointer to a volatile but read-only string. + */ +#ifndef RTPATH_TAG +# define RTPATH_TAG (__FILE__) +#endif + + +/** @name RTPATH_F_XXX - Generic flags for APIs working on the file system. + * @{ */ +/** Last component: Work on the link. */ +#define RTPATH_F_ON_LINK RT_BIT_32(0) +/** Last component: Follow if link. */ +#define RTPATH_F_FOLLOW_LINK RT_BIT_32(1) +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTPATH_F_NO_SYMLINKS RT_BIT_32(2) +/** Current RTPATH_F_XXX flag mask. */ +#define RTPATH_F_MASK UINT32_C(0x00000007) +/** @} */ + +/** Validates a flags parameter containing RTPATH_F_*. + * @remarks The parameters will be referenced multiple times. */ +#define RTPATH_F_IS_VALID(a_fFlags, a_fIgnore) \ + ( ((a_fFlags) & ~(uint32_t)((a_fIgnore) | RTPATH_F_NO_SYMLINKS)) == RTPATH_F_ON_LINK \ + || ((a_fFlags) & ~(uint32_t)((a_fIgnore) | RTPATH_F_NO_SYMLINKS)) == RTPATH_F_FOLLOW_LINK ) + + +/** @name RTPATH_STR_F_XXX - Generic flags for APIs working with path strings. + * @{ + */ +/** Host OS path style (default 0 value). */ +#define RTPATH_STR_F_STYLE_HOST UINT32_C(0x00000000) +/** DOS, OS/2 and Windows path style. */ +#define RTPATH_STR_F_STYLE_DOS UINT32_C(0x00000001) +/** Unix path style. */ +#define RTPATH_STR_F_STYLE_UNIX UINT32_C(0x00000002) +/** Reserved path style. */ +#define RTPATH_STR_F_STYLE_RESERVED UINT32_C(0x00000003) +/** The path style mask. */ +#define RTPATH_STR_F_STYLE_MASK UINT32_C(0x00000003) +/** Partial path - no start. + * This causes the API to skip the root specification parsing. */ +#define RTPATH_STR_F_NO_START UINT32_C(0x00000010) +/** Partial path - no end. + * This causes the API to skip the filename and dir-slash parsing. */ +#define RTPATH_STR_F_NO_END UINT32_C(0x00000020) +/** Partial path - no start and no end. */ +#define RTPATH_STR_F_MIDDLE (RTPATH_STR_F_NO_START | RTPATH_STR_F_NO_END) + +/** Reserved for future use. */ +#define RTPATH_STR_F_RESERVED_MASK UINT32_C(0x0000ffcc) +/** @} */ + +/** Validates a flags parameter containing RTPATH_FSTR_. + * @remarks The parameters will be references multiple times. */ +#define RTPATH_STR_F_IS_VALID(a_fFlags, a_fIgnore) \ + ( ((a_fFlags) & ~((uint32_t)(a_fIgnore) | RTPATH_STR_F_STYLE_MASK | RTPATH_STR_F_MIDDLE)) == 0 \ + && ((a_fFlags) & RTPATH_STR_F_STYLE_MASK) != RTPATH_STR_F_STYLE_RESERVED \ + && ((a_fFlags) & RTPATH_STR_F_RESERVED_MASK) == 0 ) + + +/** @def RTPATH_STYLE + * The host path style. This is set to RTPATH_STR_F_STYLE_DOS, + * RTPATH_STR_F_STYLE_UNIX, or other future styles. */ +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# define RTPATH_STYLE RTPATH_STR_F_STYLE_DOS +#else +# define RTPATH_STYLE RTPATH_STR_F_STYLE_UNIX +#endif + + +/** @def RTPATH_SLASH + * The preferred slash character. + * + * @remark IPRT will always accept unix slashes. So, normally you would + * never have to use this define. + */ +#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS +# define RTPATH_SLASH '\\' +#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX +# define RTPATH_SLASH '/' +#else +# error "Unsupported RTPATH_STYLE value." +#endif + +/** @deprecated Use '/'! */ +#define RTPATH_DELIMITER RTPATH_SLASH + + +/** @def RTPATH_SLASH_STR + * The preferred slash character as a string, handy for concatenations + * with other strings. + * + * @remark IPRT will always accept unix slashes. So, normally you would + * never have to use this define. + */ +#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS +# define RTPATH_SLASH_STR "\\" +#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX +# define RTPATH_SLASH_STR "/" +#else +# error "Unsupported RTPATH_STYLE value." +#endif + + +/** @def RTPATH_IS_SLASH + * Checks if a character is a slash. + * + * @returns true if it's a slash and false if not. + * @returns @param a_ch Char to check. + */ +#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS +# define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '\\' || (a_ch) == '/' ) +#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX +# define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '/' ) +#else +# error "Unsupported RTPATH_STYLE value." +#endif + + +/** @def RTPATH_IS_VOLSEP + * Checks if a character marks the end of the volume specification. + * + * @remark This is sufficient for the drive letter concept on PC. + * However it might be insufficient on other platforms + * and even on PC a UNC volume spec won't be detected this way. + * Use the RTPath@() instead. + * + * @returns true if it is and false if it isn't. + * @returns @param a_ch Char to check. + */ +#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS +# define RTPATH_IS_VOLSEP(a_ch) ( (a_ch) == ':' ) +#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX +# define RTPATH_IS_VOLSEP(a_ch) (false) +#else +# error "Unsupported RTPATH_STYLE value." +#endif + + +/** @def RTPATH_IS_SEP + * Checks if a character is path component separator + * + * @returns true if it is and false if it isn't. + * @returns @param a_ch Char to check. + * @ + */ +#define RTPATH_IS_SEP(a_ch) ( RTPATH_IS_SLASH(a_ch) || RTPATH_IS_VOLSEP(a_ch) ) + +#if defined(RT_OS_WINDOWS) || defined(DOXYGEN_RUNNING) +/** @def RTPATH_NT_PASSTHRU_PREFIX + * Prefix used to access the NT namespace directly. + * This forms an invalid UNC name. */ +# define RTPATH_NT_PASSTHRU_PREFIX "\\\\:iprtnt:\\" +#endif + +/** + * Checks if the path exists. + * + * Symbolic links will all be attempted resolved and broken links means false. + * + * @returns true if it exists and false if it doesn't. + * @param pszPath The path to check. + */ +RTDECL(bool) RTPathExists(const char *pszPath); + +/** + * Checks if the path exists. + * + * @returns true if it exists and false if it doesn't. + * @param pszPath The path to check. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + */ +RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags); + +/** + * Sets the current working directory of the process. + * + * @returns IPRT status code. + * @param pszPath The path to the new working directory. + */ +RTDECL(int) RTPathSetCurrent(const char *pszPath); + +/** + * Gets the current working directory of the process. + * + * @returns IPRT status code. + * @param pszPath Where to store the path. + * @param cchPath The size of the buffer pszPath points to. + */ +RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cchPath); + +/** + * Gets the current working directory on the specified drive. + * + * On systems without drive letters, the root slash will be returned. + * + * @returns IPRT status code. + * @param chDrive The drive we're querying the driver letter on. + * @param pszPath Where to store the working directroy path. + * @param cbPath The size of the buffer pszPath points to. + */ +RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath); + +/** + * Gets the current working drive of the process. + * + * Normally drive letter and colon will be returned, never trailing a root + * slash. If the current directory is on a UNC share, the root of the share + * will be returned. On systems without drive letters, an empty string is + * returned for consistency. + * + * @returns IPRT status code. + * @param pszPath Where to store the working drive or UNC root. + * @param cbPath The size of the buffer pszPath points to. + */ +RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath); + +/** + * Get the real path (no symlinks, no . or .. components), must exist. + * + * @returns iprt status code. + * @param pszPath The path to resolve. + * @param pszRealPath Where to store the real path. + * @param cchRealPath Size of the buffer. + */ +RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath); + +/** + * Same as RTPathReal only the result is RTStrDup()'ed. + * + * @returns Pointer to real path. Use RTStrFree() to free this string. + * @returns NULL if RTPathReal() or RTStrDup() fails. + * @param pszPath The path to resolve. + */ +RTDECL(char *) RTPathRealDup(const char *pszPath); + +/** + * Get the absolute path (starts from root, no . or .. components), doesn't have + * to exist. + * + * Note that this method is designed to never perform actual file system access, + * therefore symlinks are not resolved. + * + * @returns iprt status code. + * @param pszPath The path to resolve. + * @param pszAbsPath Where to store the absolute path. + * @param cbAbsPath Size of the buffer. + * + * @note Current implementation is buggy and will remove trailing slashes + * that would normally specify a directory. Don't depend on this. + */ +RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cbAbsPath); + +/** + * Same as RTPathAbs only the result is RTStrDup()'ed. + * + * @returns Pointer to the absolute path. Use RTStrFree() to free this string. + * @returns NULL if RTPathAbs() or RTStrDup() fails. + * @param pszPath The path to resolve. + * + * @note Current implementation is buggy and will remove trailing slashes + * that would normally specify a directory. Don't depend on this. + */ +RTDECL(char *) RTPathAbsDup(const char *pszPath); + +/** + * Get the absolute path (no symlinks, no . or .. components), assuming the + * given base path as the current directory. + * + * The resulting path doesn't have to exist. + * + * @returns iprt status code. + * @param pszBase The base path to act like a current directory. + * When NULL, the actual cwd is used (i.e. the call + * is equivalent to RTPathAbs(pszPath, ...). + * @param pszPath The path to resolve. + * @param fFlags One of the RTPATH_STR_F_STYLE_XXX flags combined + * with any of the RTPATHABS_F_XXX ones. Most + * users will pass RTPATH_STR_F_STYLE_HOST (0). + * @param pszAbsPath Where to store the absolute path. + * @param pcbAbsPath Hold the size of the buffer when called. The return + * value is the string length on success, and the + * required (or slightly more in some case) buffer + * size, including terminator, on VERR_BUFFER_OVERFLOW + * failures. + */ +RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath); + +/** @name RTPATHABS_F_XXX - Flags for RTPathAbsEx. + * @note The RTPATH_F_STR_XXX style flags also applies. + * @{ */ +/** Treat specified base directory as a root that cannot be ascended beyond. */ +#define RTPATHABS_F_STOP_AT_BASE RT_BIT_32(16) +/** Treat CWD as a root that cannot be ascended beyond. */ +#define RTPATHABS_F_STOP_AT_CWD RT_BIT_32(17) +/** Ensure trailing slash in the result. */ +#define RTPATHABS_F_ENSURE_TRAILING_SLASH RT_BIT_32(18) +/** @} */ + +/** + * Same as RTPathAbsEx only the result is RTStrDup()'ed. + * + * @returns Pointer to the absolute path. Use RTStrFree() to free this string. + * @retval NULL if RTPathAbsEx() or RTStrDup() fails. + * + * @param pszBase The base path to act like a current directory. + * When NULL, the actual cwd is used (i.e. the call + * is equivalent to RTPathAbs(pszPath, ...). + * @param pszPath The path to resolve. + * @param fFlags One of the RTPATH_STR_F_STYLE_XXX flags combined + * with any of the RTPATHABS_F_XXX ones. Most + * users will pass RTPATH_STR_F_STYLE_HOST (0). + */ +RTDECL(char *) RTPathAbsExDup(const char *pszBase, const char *pszPath, uint32_t fFlags); + +/** + * Strips the filename from a path. Truncates the given string in-place by overwriting the + * last path separator character with a null byte in a platform-neutral way. + * + * @param pszPath Path from which filename should be extracted, will be truncated. + * If the string contains no path separator, it will be changed to a "." string. + */ +RTDECL(void) RTPathStripFilename(char *pszPath); + +/** + * Strips the last suffix from a path. + * + * @param pszPath Path which suffix should be stripped. + */ +RTDECL(void) RTPathStripSuffix(char *pszPath); + +/** + * Strips the trailing slashes of a path name. + * + * Won't strip root slashes. + * + * @returns The new length of pszPath. + * @param pszPath Path to strip. + */ +RTDECL(size_t) RTPathStripTrailingSlash(char *pszPath); + +/** + * Skips the root specification, if present. + * + * @return Pointer to the first char after the root specification. This can be + * pointing to the terminator, if the path is only a root + * specification. + * @param pszPath The path to skip ahead in. + */ +RTDECL(char *) RTPathSkipRootSpec(const char *pszPath); + +/** + * Ensures that the path has a trailing path separator such that file names can + * be appended without further work. + * + * This can be helpful when preparing for efficiently combining a directory path + * with the filenames returned by RTDirRead. The return value gives you the + * position at which you copy the RTDIRENTRY::szName to construct a valid path + * to it. + * + * @returns The length of the path, 0 on buffer overflow. + * @param pszPath The path. + * @param cbPath The length of the path buffer @a pszPath points to. + */ +RTDECL(size_t) RTPathEnsureTrailingSeparator(char *pszPath, size_t cbPath); + +/** + * Same as RTPathEnsureTrailingSeparator but with selectable path style. + * + * @returns The length of the path, 0 on buffer overflow. + * @param pszPath The path. + * @param cbPath The length of the path buffer @a pszPath points to. + * @param fFlags The path style, RTPATH_STR_F_STYLE_XXX. + * @sa RTPathEnsureTrailingSeparator + */ +RTDECL(size_t) RTPathEnsureTrailingSeparatorEx(char *pszPath, size_t cbPath, uint32_t fFlags); + +/** + * Changes all the slashes in the specified path to DOS style. + * + * Unless @a fForce is set, nothing will be done when on a UNIX flavored system + * since paths wont work with DOS style slashes there. + * + * @returns @a pszPath. + * @param pszPath The path to modify. + * @param fForce Whether to force the conversion on non-DOS OSes. + */ +RTDECL(char *) RTPathChangeToDosSlashes(char *pszPath, bool fForce); + +/** + * Changes all the slashes in the specified path to unix style. + * + * Unless @a fForce is set, nothing will be done when on a UNIX flavored system + * since paths wont work with DOS style slashes there. + * + * @returns @a pszPath. + * @param pszPath The path to modify. + * @param fForce Whether to force the conversion on non-DOS OSes. + */ +RTDECL(char *) RTPathChangeToUnixSlashes(char *pszPath, bool fForce); + +/** + * Purges a string so it can be used as a file according to fFlags. + * + * Illegal filename characters are replaced by '_'. + * + * @returns pszString + * @param pszString The string to purge. + * @param fFlags One of the RTPATH_STR_F_STYLE_XXX flags. Most users + * will pass RTPATH_STR_F_STYLE_HOST (0). + */ +RTDECL(char *) RTPathPurgeFilename(char *pszString, uint32_t fFlags); + +/** + * Simple parsing of the a path. + * + * It figures the length of the directory component, the offset of + * the file name and the location of the suffix dot. + * + * @returns The path length. + * + * @param pszPath Path to find filename in. + * @param pcchDir Where to put the length of the directory component. If + * no directory, this will be 0. Optional. + * @param poffName Where to store the filename offset. + * If empty string or if it's ending with a slash this + * will be set to -1. Optional. + * @param poffSuff Where to store the suffix offset (the last dot). + * If empty string or if it's ending with a slash this + * will be set to -1. Optional. + */ +RTDECL(size_t) RTPathParseSimple(const char *pszPath, size_t *pcchDir, ssize_t *poffName, ssize_t *poffSuff); + +/** + * Finds the filename in a path. + * + * @returns Pointer to filename within pszPath. + * @returns NULL if no filename (i.e. empty string or ends with a slash). + * @param pszPath Path to find filename in. + */ +RTDECL(char *) RTPathFilename(const char *pszPath); +RTDECL(PRTUTF16) RTPathFilenameUtf16(PCRTUTF16 pwszPath); + +/** + * Finds the filename in a path, extended version. + * + * @returns Pointer to filename within pszPath. + * @returns NULL if no filename (i.e. empty string or ends with a slash). + * @param pszPath Path to find filename in. + * @param fFlags RTPATH_STR_F_STYLE_XXX. Other RTPATH_STR_F_XXX flags + * will be ignored. + */ +RTDECL(char *) RTPathFilenameEx(const char *pszPath, uint32_t fFlags); +RTDECL(PRTUTF16) RTPathFilenameExUtf16(PCRTUTF16 pwszPath, uint32_t fFlags); + +/** + * Finds the common path in a given set of paths. + * + * The paths are not made absolute or real, they are taken as given. + * + * @returns The common path length as represented by \a papszPaths[0], 0 if not + * found or invalid input. + * @param cPaths Number of paths in \a papszPaths. + * @param papszPaths Array of paths to find common path for. The paths must + * not contains ".." sequences, as that's too complicated + * to handle. + */ +RTDECL(size_t) RTPathFindCommon(size_t cPaths, const char * const *papszPaths); + +/** + * Finds the common path in a given set of paths, extended version. + * + * The paths are not made absolute or real, they are taken as given. + * + * @returns The common path length as represented by \a papszPaths[0], 0 if not + * found or invalid input. + * @param cPaths Number of paths in \a papszPaths. + * @param papszPaths Array of paths to find common path for. The paths must + * not contains ".." sequences, as that's too complicated + * to handle. + * @param fFlags RTPATH_STR_F_STYLE_XXX, RTPATH_STR_F_NO_START, and + * RTPATHFINDCOMMON_F_IGNORE_DOTDOT as desired. Other + * RTPATH_STR_F_XXX flags will be ignored. + */ +RTDECL(size_t) RTPathFindCommonEx(size_t cPaths, const char * const *papszPaths, uint32_t fFlags); + +/** @name RTPATHFINDCOMMON_F_XXX - Flags for RTPathFindCommonEx. + * @{ */ +/** Ignore the dangers of '..' components. */ +#define RTPATHFINDCOMMON_F_IGNORE_DOTDOT RT_BIT_32(16) +/** @} */ + +/** + * Finds the suffix part of in a path (last dot and onwards). + * + * @returns Pointer to suffix within pszPath. + * @returns NULL if no suffix + * @param pszPath Path to find suffix in. + * + * @remarks IPRT terminology: A suffix includes the dot, the extension starts + * after the dot. For instance suffix '.txt' and extension 'txt'. + */ +RTDECL(char *) RTPathSuffix(const char *pszPath); + +/** + * Checks if a path has an extension / suffix. + * + * @returns true if extension / suffix present. + * @returns false if no extension / suffix. + * @param pszPath Path to check. + */ +RTDECL(bool) RTPathHasSuffix(const char *pszPath); +/** Same thing, different name. */ +#define RTPathHasExt RTPathHasSuffix + +/** + * Checks if a path includes more than a filename. + * + * @returns true if path present. + * @returns false if no path. + * @param pszPath Path to check. + */ +RTDECL(bool) RTPathHasPath(const char *pszPath); +/** Misspelled, don't use. */ +#define RTPathHavePath RTPathHasPath + +/** + * Checks if the path starts with a root specifier or not. + * + * @returns @c true if it starts with root, @c false if not. + * + * @param pszPath Path to check. + */ +RTDECL(bool) RTPathStartsWithRoot(const char *pszPath); + +/** + * Determins the length of the parent part of the given path. + * + * @returns The length of the parent section of the path, including the final + * path separator. Returns 0 if only filename or empty path. + * @param pszPath The path to evaluate. + * + * @note Will stop at the server for UNC paths, so given "//server/share/" + * the parent length will be 9. + */ +RTDECL(size_t) RTPathParentLength(const char *pszPath); + +/** + * Determins the length of the parent part of the given path, extended variant. + * + * @returns The length of the parent section of the path, including the final + * path separator. Returns 0 if only filename or empty path. + * @param pszPath The path to evaluate. + * @param fFlags RTPATH_STR_F_STYLE_XXX and RTPATH_STR_F_NO_START. + * Asserts and ignores RTPATH_STR_F_NO_END. + * + * @note Will stop at the server for UNC paths, so given "//server/share/" + * the parent length will be 9. + */ +RTDECL(size_t) RTPathParentLengthEx(const char *pszPath, uint32_t fFlags); + +/** + * Counts the components in the specified path. + * + * An empty string has zero components. A lone root slash is considered have + * one. The paths "/init" and "/bin/" are considered having two components. An + * UNC share specifier like "\\myserver\share" will be considered as one single + * component. + * + * @returns The number of path components. + * @param pszPath The path to parse. + */ +RTDECL(size_t) RTPathCountComponents(const char *pszPath); + +/** + * Copies the specified number of path components from @a pszSrc and into @a + * pszDst. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. In the latter case the buffer + * is not touched. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer. + * @param pszSrc The source path. + * @param cComponents The number of components to copy from @a pszSrc. + */ +RTDECL(int) RTPathCopyComponents(char *pszDst, size_t cbDst, const char *pszSrc, size_t cComponents); + +/** @name Path properties returned by RTPathParse and RTPathSplit. + * @{ */ + +/** Indicates that there is a filename. + * If not set, either a lone root spec was given (RTPATH_PROP_UNC, + * RTPATH_PROP_ROOT_SLASH, or RTPATH_PROP_VOLUME) or the final component had a + * trailing slash (RTPATH_PROP_DIR_SLASH). */ +#define RTPATH_PROP_FILENAME UINT16_C(0x0001) +/** Indicates that a directory was specified using a trailing slash. + * @note This is not set for lone root specifications (RTPATH_PROP_UNC, + * RTPATH_PROP_ROOT_SLASH, or RTPATH_PROP_VOLUME). + * @note The slash is not counted into the last component. However, it is + * counted into cchPath. */ +#define RTPATH_PROP_DIR_SLASH UINT16_C(0x0002) + +/** The filename has a suffix (extension). */ +#define RTPATH_PROP_SUFFIX UINT16_C(0x0004) +/** Indicates that this is an UNC path (Windows and OS/2 only). + * + * UNC = Universal Naming Convention. It is on the form '//Computer/', + * '//Namespace/', '//ComputerName/Resource' and '//Namespace/Resource'. + * RTPathParse, RTPathSplit and friends does not consider the 'Resource' as + * part of the UNC root specifier. Thus the root specs for the above examples + * would be '//ComputerName/' or '//Namespace/'. + * + * Please note that '//something' is not a UNC path, there must be a slash + * following the computer or namespace. + */ +#define RTPATH_PROP_UNC UINT16_C(0x0010) +/** A root slash was specified (unix style root). + * (While the path must relative if not set, this being set doesn't make it + * absolute.) + * + * This will be set in the following examples: '/', '/bin', 'C:/', 'C:/Windows', + * '//./', '//./PhysicalDisk0', '//example.org/', and '//example.org/share'. + * + * It will not be set for the following examples: '.', 'bin/ls', 'C:', and + * 'C:Windows'. + */ +#define RTPATH_PROP_ROOT_SLASH UINT16_C(0x0020) +/** A volume is specified (Windows, DOS and OS/2). + * For examples: 'C:', 'C:/', and 'A:/AutoExec.bat'. */ +#define RTPATH_PROP_VOLUME UINT16_C(0x0040) +/** The path is absolute, i.e. has a root specifier (root-slash, + * volume or UNC) and contains no winding '..' bits, though it may contain + * unnecessary slashes (RTPATH_PROP_EXTRA_SLASHES) and '.' components + * (RTPATH_PROP_DOT_REFS). + * + * On systems without volumes and UNC (unix style) it will be set for '/', + * '/bin/ls', and '/bin//./ls', but not for 'bin/ls', /bin/../usr/bin/env', + * '/./bin/ls' or '/.'. + * + * On systems with volumes, it will be set for 'C:/', C:/Windows', and + * 'C:/./Windows//', but not for 'C:', 'C:Windows', or 'C:/Windows/../boot.ini'. + * + * On systems with UNC paths, it will be set for '//localhost/', + * '//localhost/C$', '//localhost/C$/Windows/System32', '//localhost/.', and + * '//localhost/C$//./AutoExec.bat', but not for + * '//localhost/C$/Windows/../AutoExec.bat'. + * + * @note For the RTPathAbs definition, this flag needs to be set while both + * RTPATH_PROP_EXTRA_SLASHES and RTPATH_PROP_DOT_REFS must be cleared. + */ +#define RTPATH_PROP_ABSOLUTE UINT16_C(0x0100) +/** Relative path. Inverse of RTPATH_PROP_ABSOLUTE. */ +#define RTPATH_PROP_RELATIVE UINT16_C(0x0200) +/** The path contains unnecessary slashes. Meaning, that if */ +#define RTPATH_PROP_EXTRA_SLASHES UINT16_C(0x0400) +/** The path contains references to the special '.' (dot) directory link. */ +#define RTPATH_PROP_DOT_REFS UINT16_C(0x0800) +/** The path contains references to the special '..' (dot) directory link. + * RTPATH_PROP_RELATIVE will always be set together with this. */ +#define RTPATH_PROP_DOTDOT_REFS UINT16_C(0x1000) +/** Special UNC root. + * The share name is not sacred when this is set. */ +#define RTPATH_PROP_SPECIAL_UNC UINT16_C(0x2000) + + +/** Macro to determin whether to insert a slash after the first component when + * joining it with something else. + * (All other components in a split or parsed path requies slashes added.) */ +#define RTPATH_PROP_FIRST_NEEDS_NO_SLASH(a_fProps) \ + RT_BOOL( (a_fProps) & (RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_VOLUME | RTPATH_PROP_UNC) ) + +/** Macro to determin whether there is a root specification of any kind + * (unix, volumes, unc). */ +#define RTPATH_PROP_HAS_ROOT_SPEC(a_fProps) \ + RT_BOOL( (a_fProps) & (RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_VOLUME | RTPATH_PROP_UNC) ) + +/** @} */ + + +/** + * Parsed path. + * + * The first component is the root, volume or UNC specifier, if present. Use + * RTPATH_PROP_HAS_ROOT_SPEC() on RTPATHPARSED::fProps to determine its + * presence. + * + * Other than the root component, no component will include directory separators + * (slashes). + */ +typedef struct RTPATHPARSED +{ + /** Number of path components. + * This will always be set on VERR_BUFFER_OVERFLOW returns from RTPathParsed + * so the caller can calculate the required buffer size. */ + uint16_t cComps; + /** Path property flags, RTPATH_PROP_XXX */ + uint16_t fProps; + /** On success this is the length of the described path, i.e. sum of all + * component lengths and necessary separators. + * Do NOT use this to index in the source path in case it contains + * unnecessary slashes that RTPathParsed has ignored here. */ + uint16_t cchPath; + /** Reserved for future use. */ + uint16_t u16Reserved; + /** The offset of the filename suffix, offset of the NUL char if none. */ + uint16_t offSuffix; + /** The length of the suffix. */ + uint16_t cchSuffix; + /** Array of component descriptors (variable size). + * @note Don't try figure the end of the input path by adding up off and cch + * of the last component. If RTPATH_PROP_DIR_SLASH is set, there may + * be one or more trailing slashes that are unaccounted for! */ + RT_FLEXIBLE_ARRAY_EXTENSION + struct + { + /** The offset of the component. */ + uint16_t off; + /** The length of the component. */ + uint16_t cch; + } aComps[RT_FLEXIBLE_ARRAY]; +} RTPATHPARSED; +/** Pointer to to a parsed path result. */ +typedef RTPATHPARSED *PRTPATHPARSED; +/** Pointer to to a const parsed path result. */ +typedef RTPATHPARSED *PCRTPATHPARSED; + +/** Stupid hack for MSC and flexible arrays. */ +#define RTPATHPARSED_MIN_SIZE (sizeof(uint16_t) * (6 + 4)) + + +/** + * Parses the path. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer. + * @retval VERR_INVALID_PARAMETER if cbOutput is less than the RTPATHPARSED + * strucuture. No output. (asserted) + * @retval VERR_BUFFER_OVERFLOW there are more components in the path than + * there is space in aComps. The required amount of space can be + * determined from the pParsed->cComps: + * @code + * RT_OFFSETOF(RTPATHPARSED, aComps[pParsed->cComps]) + * @endcode + * @retval VERR_PATH_ZERO_LENGTH if the path is empty. + * + * @param pszPath The path to parse. + * @param pParsed Where to store the details of the parsed path. + * @param cbParsed The size of the buffer. Must be at least the + * size of RTPATHPARSED. + * @param fFlags Combination of RTPATH_STR_F_XXX flags. + * Most users will pass 0. + * @sa RTPathSplit, RTPathSplitA. + */ +RTDECL(int) RTPathParse(const char *pszPath, PRTPATHPARSED pParsed, size_t cbParsed, uint32_t fFlags); + +/** + * Reassembles a path parsed by RTPathParse. + * + * This will be more useful as more APIs manipulating the RTPATHPARSED output + * are added. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. + * The necessary length is @a pParsed->cchPath + 1 (updated). + * + * @param pszSrcPath The source path. + * @param pParsed The parser output for @a pszSrcPath. Caller may + * eliminate elements by setting their length to + * zero. The cchPath member is updated. + * @param fFlags Combination of RTPATH_STR_F_STYLE_XXX. + * Most users will pass 0. + * @param pszDstPath Pointer to the buffer where the path is to be + * reassembled. + * @param cbDstPath The size of the output buffer. + */ +RTDECL(int) RTPathParsedReassemble(const char *pszSrcPath, PRTPATHPARSED pParsed, uint32_t fFlags, + char *pszDstPath, size_t cbDstPath); + + +/** + * Output buffer for RTPathSplit and RTPathSplitA. + */ +typedef struct RTPATHSPLIT +{ + /** Number of path components. + * This will always be set on VERR_BUFFER_OVERFLOW returns from RTPathParsed + * so the caller can calculate the required buffer size. */ + uint16_t cComps; + /** Path property flags, RTPATH_PROP_XXX */ + uint16_t fProps; + /** On success this is the length of the described path, i.e. sum of all + * component lengths and necessary separators. + * Do NOT use this to index in the source path in case it contains + * unnecessary slashes that RTPathSplit has ignored here. */ + uint16_t cchPath; + /** Reserved (internal use). */ + uint16_t u16Reserved; + /** The amount of memory used (on success) or required (on + * VERR_BUFFER_OVERFLOW) of this structure and it's strings. */ + uint32_t cbNeeded; + /** Pointer to the filename suffix (the dot), if any. Points to the NUL + * character of the last component if none or if RTPATH_PROP_DIR_SLASH is + * present. */ + const char *pszSuffix; + /** Array of component strings (variable size). */ + RT_FLEXIBLE_ARRAY_EXTENSION + char *apszComps[RT_FLEXIBLE_ARRAY]; +} RTPATHSPLIT; +/** Pointer to a split path buffer. */ +typedef RTPATHSPLIT *PRTPATHSPLIT; +/** Pointer to a const split path buffer. */ +typedef RTPATHSPLIT const *PCRTPATHSPLIT; + +/** + * Splits the path into individual component strings, carved from user supplied + * the given buffer block. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer. + * @retval VERR_INVALID_PARAMETER if cbOutput is less than the RTPATHSPLIT + * strucuture. No output. (asserted) + * @retval VERR_BUFFER_OVERFLOW there are more components in the path than + * there is space in aComps. The required amount of space can be + * determined from the pParsed->cComps: + * @code + * RT_OFFSETOF(RTPATHPARSED, aComps[pParsed->cComps]) + * @endcode + * @retval VERR_PATH_ZERO_LENGTH if the path is empty. + * @retval VERR_FILENAME_TOO_LONG if the filename is too long (close to 64 KB). + * + * @param pszPath The path to parse. + * @param pSplit Where to store the details of the parsed path. + * @param cbSplit The size of the buffer pointed to by @a pSplit + * (variable sized array at the end). Must be at + * least the size of RTPATHSPLIT. + * @param fFlags Combination of RTPATH_STR_F_XXX flags. + * Most users will pass 0. + * + * @sa RTPathSplitA, RTPathParse. + */ +RTDECL(int) RTPathSplit(const char *pszPath, PRTPATHSPLIT pSplit, size_t cbSplit, uint32_t fFlags); + +/** + * Splits the path into individual component strings, allocating the buffer on + * the default thread heap. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer. + * @retval VERR_PATH_ZERO_LENGTH if the path is empty. + * + * @param pszPath The path to parse. + * @param ppSplit Where to return the pointer to the output on + * success. This must be freed by calling + * RTPathSplitFree(). + * @param fFlags Combination of RTPATH_STR_F_XXX flags. + * Most users will pass 0. + * @sa RTPathSplitFree, RTPathSplit, RTPathParse. + */ +#define RTPathSplitA(pszPath, ppSplit, fFlags) RTPathSplitATag(pszPath, ppSplit, fFlags, RTPATH_TAG) + +/** + * Splits the path into individual component strings, allocating the buffer on + * the default thread heap. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer. + * @retval VERR_PATH_ZERO_LENGTH if the path is empty. + * + * @param pszPath The path to parse. + * @param ppSplit Where to return the pointer to the output on + * success. This must be freed by calling + * RTPathSplitFree(). + * @param fFlags Combination of RTPATH_STR_F_XXX flags. + * Most users will pass 0. + * @param pszTag Allocation tag used for statistics and such. + * @sa RTPathSplitFree, RTPathSplit, RTPathParse. + */ +RTDECL(int) RTPathSplitATag(const char *pszPath, PRTPATHSPLIT *ppSplit, uint32_t fFlags, const char *pszTag); + +/** + * Frees buffer returned by RTPathSplitA. + * + * @param pSplit What RTPathSplitA returned. + * @sa RTPathSplitA + */ +RTDECL(void) RTPathSplitFree(PRTPATHSPLIT pSplit); + +/** + * Reassembles a path parsed by RTPathSplit. + * + * This will be more useful as more APIs manipulating the RTPATHSPLIT output are + * added. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if @a cbDstPath is less than or equal to + * RTPATHSPLIT::cchPath. + * + * @param pSplit A split path (see RTPathSplit, RTPathSplitA). + * @param fFlags Combination of RTPATH_STR_F_STYLE_XXX. + * Most users will pass 0. + * @param pszDstPath Pointer to the buffer where the path is to be + * reassembled. + * @param cbDstPath The size of the output buffer. + */ +RTDECL(int) RTPathSplitReassemble(PRTPATHSPLIT pSplit, uint32_t fFlags, char *pszDstPath, size_t cbDstPath); + +/** + * Checks if the two paths leads to the file system object. + * + * If the objects exist, we'll query attributes for them. If that's not + * conclusive (some OSes) or one of them doesn't exist, we'll use a combination + * of RTPathAbs and RTPathCompare to determine the result. + * + * @returns true, false, or VERR_FILENAME_TOO_LONG. + * @param pszPath1 The first path. + * @param pszPath2 The seoncd path. + */ +RTDECL(int) RTPathIsSame(const char *pszPath1, const char *pszPath2); + + +/** + * Compares two paths. + * + * The comparison takes platform-dependent details into account, + * such as: + *
    + *
  • On DOS-like platforms, both separator chars (|\| and |/|) are considered + * to be equal. + *
  • On platforms with case-insensitive file systems, mismatching characters + * are uppercased and compared again. + *
+ * + * @returns @< 0 if the first path less than the second path. + * @returns 0 if the first path identical to the second path. + * @returns @> 0 if the first path greater than the second path. + * + * @param pszPath1 Path to compare (must be an absolute path). + * @param pszPath2 Path to compare (must be an absolute path). + * + * @remarks File system details are currently ignored. This means that you won't + * get case-insensitive compares on unix systems when a path goes into a + * case-insensitive filesystem like FAT, HPFS, HFS, NTFS, JFS, or + * similar. For NT, OS/2 and similar you'll won't get case-sensitive + * compares on a case-sensitive file system. + */ +RTDECL(int) RTPathCompare(const char *pszPath1, const char *pszPath2); + +/** + * Checks if a path starts with the given parent path. + * + * This means that either the path and the parent path matches completely, or + * that the path is to some file or directory residing in the tree given by the + * parent directory. + * + * The path comparison takes platform-dependent details into account, + * see RTPathCompare() for details. + * + * @returns |true| when \a pszPath starts with \a pszParentPath (or when they + * are identical), or |false| otherwise. + * + * @param pszPath Path to check, must be an absolute path. + * @param pszParentPath Parent path, must be an absolute path. + * No trailing directory slash! + * + * @remarks This API doesn't currently handle root directory compares in a + * manner consistent with the other APIs. RTPathStartsWith(pszSomePath, + * "/") will not work if pszSomePath isn't "/". + */ +RTDECL(bool) RTPathStartsWith(const char *pszPath, const char *pszParentPath); + +/** + * Appends one partial path to another. + * + * The main purpose of this function is to deal correctly with the slashes when + * concatenating the two partial paths. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. No changes has been made. + * @retval VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer + * than cbPathDst-1 bytes (failed to find terminator). Asserted. + * + * @param pszPath The path to append pszAppend to. This serves as both + * input and output. This can be empty, in which case + * pszAppend is just copied over. + * @param cbPathDst The size of the buffer pszPath points to, terminator + * included. This should NOT be strlen(pszPath). + * @param pszAppend The partial path to append to pszPath. This can be + * NULL, in which case nothing is done. + * + * @remarks See the RTPathAppendEx remarks. + */ +RTDECL(int) RTPathAppend(char *pszPath, size_t cbPathDst, const char *pszAppend); + +/** + * Appends one partial path to another. + * + * The main purpose of this function is to deal correctly with the slashes when + * concatenating the two partial paths. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. No changes has been made. + * @retval VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer + * than cbPathDst-1 bytes (failed to find terminator). Asserted. + * + * @param pszPath The path to append pszAppend to. This serves as both + * input and output. This can be empty, in which case + * pszAppend is just copied over. + * @param cbPathDst The size of the buffer pszPath points to, terminator + * included. This should NOT be strlen(pszPath). + * @param pszAppend The partial path to append to pszPath. This can be + * NULL, in which case nothing is done. + * @param cchAppendMax The maximum number or characters to take from @a + * pszAppend. RTSTR_MAX is fine. + * @param fFlags Combination of RTPATH_STR_F_STYLE_XXX. + * Most users will pass 0 / RTPATH_STR_F_STYLE_HOST. + * + * @remarks On OS/2, Window and similar systems, concatenating a drive letter + * specifier with a slash prefixed path will result in an absolute + * path. Meaning, RTPathAppend(strcpy(szBuf, "C:"), sizeof(szBuf), + * "/bar") will result in "C:/bar". (This follows directly from the + * behavior when pszPath is empty.) + * + * On the other hand, when joining a drive letter specifier with a + * partial path that does not start with a slash, the result is not an + * absolute path. Meaning, RTPathAppend(strcpy(szBuf, "C:"), + * sizeof(szBuf), "bar") will result in "C:bar". + */ +RTDECL(int) RTPathAppendEx(char *pszPath, size_t cbPathDst, const char *pszAppend, size_t cchAppendMax, uint32_t fFlags); + +/** + * Like RTPathAppend, but with the base path as a separate argument instead of + * in the path buffer. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. + * @retval VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer + * than cbPathDst-1 bytes (failed to find terminator). Asserted. + * + * @param pszPathDst Where to store the resulting path. + * @param cbPathDst The size of the buffer pszPathDst points to, + * terminator included. + * @param pszPathSrc The base path to copy into @a pszPathDst before + * appending @a pszAppend. + * @param pszAppend The partial path to append to pszPathSrc. This can + * be NULL, in which case nothing is done. + * + */ +RTDECL(int) RTPathJoin(char *pszPathDst, size_t cbPathDst, const char *pszPathSrc, + const char *pszAppend); + +/** + * Same as RTPathJoin, except that the output buffer is allocated. + * + * @returns Buffer containing the joined up path, call RTStrFree to free. NULL + * on allocation failure. + * @param pszPathSrc The base path to copy into @a pszPathDst before + * appending @a pszAppend. + * @param pszAppend The partial path to append to pszPathSrc. This can + * be NULL, in which case nothing is done. + * + */ +RTDECL(char *) RTPathJoinA(const char *pszPathSrc, const char *pszAppend); + +/** + * Extended version of RTPathJoin, both inputs can be specified as substrings. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. + * @retval VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer + * than cbPathDst-1 bytes (failed to find terminator). Asserted. + * + * @param pszPathDst Where to store the resulting path. + * @param cbPathDst The size of the buffer pszPathDst points to, + * terminator included. + * @param pszPathSrc The base path to copy into @a pszPathDst before + * appending @a pszAppend. + * @param cchPathSrcMax The maximum number of bytes to copy from @a + * pszPathSrc. RTSTR_MAX is find. + * @param pszAppend The partial path to append to pszPathSrc. This can + * be NULL, in which case nothing is done. + * @param cchAppendMax The maximum number of bytes to copy from @a + * pszAppend. RTSTR_MAX is find. + * @param fFlags Combination of RTPATH_STR_F_STYLE_XXX. + * Most users will pass 0 / RTPATH_STR_F_STYLE_HOST. + * + */ +RTDECL(int) RTPathJoinEx(char *pszPathDst, size_t cbPathDst, + const char *pszPathSrc, size_t cchPathSrcMax, + const char *pszAppend, size_t cchAppendMax, uint32_t fFlags); + +/** + * Callback for RTPathTraverseList that's called for each element. + * + * @returns IPRT style status code. Return VERR_TRY_AGAIN to continue, any other + * value will abort the traversing and be returned to the caller. + * + * @param pchPath Pointer to the start of the current path. This is + * not null terminated. + * @param cchPath The length of the path. + * @param pvUser1 The first user parameter. + * @param pvUser2 The second user parameter. + */ +typedef DECLCALLBACKTYPE(int, FNRTPATHTRAVERSER,(char const *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)); +/** Pointer to a FNRTPATHTRAVERSER. */ +typedef FNRTPATHTRAVERSER *PFNRTPATHTRAVERSER; + +/** + * Traverses a string that can contain multiple paths separated by a special + * character. + * + * @returns IPRT style status code from the callback or VERR_END_OF_STRING if + * the callback returned VERR_TRY_AGAIN for all paths in the string. + * + * @param pszPathList The string to traverse. + * @param chSep The separator character. Using the null terminator + * is fine, but the result will simply be that there + * will only be one callback for the entire string + * (save any leading white space). + * @param pfnCallback The callback. + * @param pvUser1 First user argument for the callback. + * @param pvUser2 Second user argument for the callback. + */ +RTDECL(int) RTPathTraverseList(const char *pszPathList, char chSep, PFNRTPATHTRAVERSER pfnCallback, void *pvUser1, void *pvUser2); + + +/** + * Calculate a relative path between the two given paths. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. + * @retval VERR_NOT_SUPPORTED if both paths start with different volume specifiers. + * @param pszPathDst Where to store the resulting path. + * @param cbPathDst The size of the buffer pszPathDst points to, + * terminator included. + * @param pszPathFrom The path to start from creating the relative path. + * @param fFromFile Whether @a pszPathFrom is a file and we should work + * relative to it's parent directory (@c true), or if + * we should assume @a pszPathFrom is a directory and + * work relative to it. + * @param pszPathTo The path to reach with the created relative path. + */ +RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst, const char *pszPathFrom, bool fFromFile, const char *pszPathTo); + +#ifdef IN_RING3 + +/** + * Gets the path to the directory containing the executable. + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathExecDir(char *pszPath, size_t cchPath); + +/** + * Gets the user home directory. + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathUserHome(char *pszPath, size_t cchPath); + +/** + * Gets the user documents directory. + * + * The returned path isn't guaranteed to exist. + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath); + +/** + * Gets the directory of shared libraries. + * + * This is not the same as RTPathAppPrivateArch() as Linux depends all shared + * libraries in a common global directory where ld.so can find them. + * + * Linux: /usr/lib + * Solaris: /opt/@/@@ or something + * Windows: @/@ + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathSharedLibs(char *pszPath, size_t cchPath); + +/** + * Gets the directory for architecture-independent application data, for + * example NLS files, module sources, ... + * + * Linux: /usr/shared/@ + * Solaris: /opt/@ + * Windows: @/@ + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathAppPrivateNoArch(char *pszPath, size_t cchPath); + +/** + * Gets the directory for architecture-dependent application data, for + * example modules which can be loaded at runtime. + * + * Linux: /usr/lib/@ + * Solaris: /opt/@/@@ or something + * Windows: @/@ + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathAppPrivateArch(char *pszPath, size_t cchPath); + +/** + * Gets the toplevel directory for architecture-dependent application data. + * + * This differs from RTPathAppPrivateArch on Solaris only where it will work + * around the /opt/@/amd64 and /opt/@/i386 multi + * architecture installation style. + * + * Linux: /usr/lib/@ + * Solaris: /opt/@ + * Windows: @/@ + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathAppPrivateArchTop(char *pszPath, size_t cchPath); + +/** + * Gets the directory for documentation. + * + * Linux: /usr/share/doc/@ + * Solaris: /opt/@ + * Windows: @/@ + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathAppDocs(char *pszPath, size_t cchPath); + +/** + * Gets the temporary directory path. + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathTemp(char *pszPath, size_t cchPath); + + +/** + * RTPathGlobl result entry. + */ +typedef struct RTPATHGLOBENTRY +{ + /** List entry. */ + struct RTPATHGLOBENTRY *pNext; + /** RTDIRENTRYTYPE value. */ + uint8_t uType; + /** Unused explicit padding. */ + uint8_t bUnused; + /** The length of the path. */ + uint16_t cchPath; + /** The path to the file (variable length). */ + char szPath[1]; +} RTPATHGLOBENTRY; +/** Pointer to a GLOB result entry. */ +typedef RTPATHGLOBENTRY *PRTPATHGLOBENTRY; +/** Pointer to a const GLOB result entry. */ +typedef RTPATHGLOBENTRY const *PCRTPATHGLOBENTRY; +/** Pointer to a GLOB result entry pointer. */ +typedef PCRTPATHGLOBENTRY *PPCRTPATHGLOBENTRY; + +/** + * Performs wildcard expansion on a path pattern. + * + * @returns IPRT status code. + * + * @param pszPattern The pattern to expand. + * @param fFlags RTPATHGLOB_F_XXX. + * @param ppHead Where to return the head of the result list. This + * is always set to NULL on failure. + * @param pcResults Where to return the number of the result. Optional. + */ +RTDECL(int) RTPathGlob(const char *pszPattern, uint32_t fFlags, PPCRTPATHGLOBENTRY ppHead, uint32_t *pcResults); + +/** @name RTPATHGLOB_F_XXX - RTPathGlob flags + * @{ */ +/** Case insensitive. */ +#define RTPATHGLOB_F_IGNORE_CASE RT_BIT_32(0) +/** Do not expand \${EnvOrSpecialVariable} in the pattern. */ +#define RTPATHGLOB_F_NO_VARIABLES RT_BIT_32(1) +/** Do not interpret a leading tilde as a home directory reference. */ +#define RTPATHGLOB_F_NO_TILDE RT_BIT_32(2) +/** Only return the first match. */ +#define RTPATHGLOB_F_FIRST_ONLY RT_BIT_32(3) +/** Only match directories (implied if pattern ends with slash). */ +#define RTPATHGLOB_F_ONLY_DIRS RT_BIT_32(4) +/** Do not match directories. (Can't be used with RTPATHGLOB_F_ONLY_DIRS or + * patterns containing a trailing slash.) */ +#define RTPATHGLOB_F_NO_DIRS RT_BIT_32(5) +/** Disables the '**' wildcard pattern for matching zero or more subdirs. */ +#define RTPATHGLOB_F_NO_STARSTAR RT_BIT_32(6) +/** Mask of valid flags. */ +#define RTPATHGLOB_F_MASK UINT32_C(0x0000007f) +/** @} */ + +/** + * Frees the results produced by RTPathGlob. + * + * @param pHead What RTPathGlob returned. NULL ignored. + */ +RTDECL(void) RTPathGlobFree(PCRTPATHGLOBENTRY pHead); + + +/** + * Query information about a file system object. + * + * This API will resolve NOT symbolic links in the last component (just like + * unix lstat()). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the object exists, information returned. + * @retval VERR_PATH_NOT_FOUND if any but the last component in the specified + * path was not found or was not a directory. + * @retval VERR_FILE_NOT_FOUND if the object does not exist (but path to the + * parent directory exists). + * + * @param pszPath Path to the file system object. + * @param pObjInfo Object information structure to be filled on successful + * return. + * @param enmAdditionalAttribs + * Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + */ +RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs); + +/** + * Query information about a file system object. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the object exists, information returned. + * @retval VERR_PATH_NOT_FOUND if any but the last component in the specified + * path was not found or was not a directory. + * @retval VERR_FILE_NOT_FOUND if the object does not exist (but path to the + * parent directory exists). + * + * @param pszPath Path to the file system object. + * @param pObjInfo Object information structure to be filled on successful return. + * @param enmAdditionalAttribs + * Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + */ +RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags); + +/** + * Changes the mode flags of a file system object. + * + * The API requires at least one of the mode flag sets (Unix/Dos) to + * be set. The type is ignored. + * + * This API will resolve symbolic links in the last component since + * mode isn't important for symbolic links. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param fMode The new file mode, see @ref grp_rt_fs for details. + */ +RTR3DECL(int) RTPathSetMode(const char *pszPath, RTFMODE fMode); + +/** + * Gets the mode flags of a file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pfMode Where to store the file mode, see @ref grp_rt_fs for details. + * + * @remark This is wrapper around RTPathQueryInfoEx(RTPATH_F_FOLLOW_LINK) and + * exists to complement RTPathSetMode(). + */ +RTR3DECL(int) RTPathGetMode(const char *pszPath, PRTFMODE pfMode); + +/** + * Changes one or more of the timestamps associated of file system object. + * + * This API will not resolve symbolic links in the last component (just + * like unix lutimes()). + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pAccessTime Pointer to the new access time. + * @param pModificationTime Pointer to the new modification time. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + */ +RTR3DECL(int) RTPathSetTimes(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + +/** + * Changes one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pAccessTime Pointer to the new access time. + * @param pModificationTime Pointer to the new modification time. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + */ +RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags); + +/** + * Gets one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pAccessTime Where to store the access time. NULL is ok. + * @param pModificationTime Where to store the modification time. NULL is ok. + * @param pChangeTime Where to store the change time. NULL is ok. + * @param pBirthTime Where to store the creation time. NULL is ok. + * + * @remark This is wrapper around RTPathQueryInfo() and exists to complement + * RTPathSetTimes(). If the last component is a symbolic link, it will + * not be resolved. + */ +RTR3DECL(int) RTPathGetTimes(const char *pszPath, PRTTIMESPEC pAccessTime, PRTTIMESPEC pModificationTime, + PRTTIMESPEC pChangeTime, PRTTIMESPEC pBirthTime); + +/** + * Changes the owner and/or group of a file system object. + * + * This API will not resolve symbolic links in the last component (just + * like unix lchown()). + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param uid The new file owner user id. Pass NIL_RTUID to leave + * this unchanged. + * @param gid The new group id. Pass NIL_RTGUID to leave this + * unchanged. + */ +RTR3DECL(int) RTPathSetOwner(const char *pszPath, uint32_t uid, uint32_t gid); + +/** + * Changes the owner and/or group of a file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param uid The new file owner user id. Pass NIL_RTUID to leave + * this unchanged. + * @param gid The new group id. Pass NIL_RTGID to leave this + * unchanged. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + */ +RTR3DECL(int) RTPathSetOwnerEx(const char *pszPath, uint32_t uid, uint32_t gid, uint32_t fFlags); + +/** + * Gets the owner and/or group of a file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pUid Where to store the owner user id. NULL is ok. + * @param pGid Where to store the group id. NULL is ok. + * + * @remark This is wrapper around RTPathQueryInfo() and exists to complement + * RTPathGetOwner(). If the last component is a symbolic link, it will + * not be resolved. + */ +RTR3DECL(int) RTPathGetOwner(const char *pszPath, uint32_t *pUid, uint32_t *pGid); + + +/** @name RTPathRename, RTDirRename & RTFileRename flags. + * @{ */ +/** Do not replace anything. */ +#define RTPATHRENAME_FLAGS_NO_REPLACE UINT32_C(0) +/** This will replace attempt any target which isn't a directory. */ +#define RTPATHRENAME_FLAGS_REPLACE RT_BIT(0) +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTPATHRENAME_FLAGS_NO_SYMLINKS RT_BIT(1) +/** @} */ + +/** + * Renames a path within a filesystem. + * + * This will rename symbolic links. If RTPATHRENAME_FLAGS_REPLACE is used and + * pszDst is a symbolic link, it will be replaced and not its target. + * + * @returns IPRT status code. + * @param pszSrc The source path. + * @param pszDst The destination path. + * @param fRename Rename flags, RTPATHRENAME_FLAGS_*. + */ +RTR3DECL(int) RTPathRename(const char *pszSrc, const char *pszDst, unsigned fRename); + +/** @name RTPathUnlink flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTPATHUNLINK_FLAGS_NO_SYMLINKS RT_BIT(0) +/** @} */ + +/** + * Removes the last component of the path. + * + * @returns IPRT status code. + * @param pszPath The path. + * @param fUnlink Unlink flags, RTPATHUNLINK_FLAGS_*. + */ +RTR3DECL(int) RTPathUnlink(const char *pszPath, uint32_t fUnlink); + +/** + * A /bin/rm tool. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTDECL(RTEXITCODE) RTPathRmCmd(unsigned cArgs, char **papszArgs); + +# ifdef RT_OS_WINDOWS + +/** + * Converts the given UTF-8 path into a native windows path. + * + * @returns IPRT status code. + * @param ppwszPath Where to return the path. This will always be + * set to NULL on failure. Use RTPathWinFree to + * free it when done. + * @param pszPath The UTF-8 path to convert. + * @param fFlags MBZ, reserved for future hacks. + * @sa RTPathWinFree, RTNtPathFromWinUtf8, RTNtPathRelativeFromUtf8. + */ +RTDECL(int) RTPathWinFromUtf8(PRTUTF16 *ppwszPath, const char *pszPath, uint32_t fFlags); + +/** + * Frees a native windows path returned by RTPathWinFromUtf8 + * + * @param pwszPath The path to free. NULL is ignored. + */ +RTDECL(void) RTPathWinFree(PRTUTF16 pwszPath); + +# endif /* RT_OS_WINDOWS */ + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_path_h */ + diff --git a/include/iprt/pipe.h b/include/iprt/pipe.h new file mode 100644 index 00000000..a47f2d58 --- /dev/null +++ b/include/iprt/pipe.h @@ -0,0 +1,293 @@ +/** @file + * IPRT - Anonymous Pipes. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_pipe_h +#define IPRT_INCLUDED_pipe_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_pipe RTPipe - Anonymous Pipes + * @ingroup grp_rt + * + * @note The current Windows implementation has some peculiarities, + * especially with respect to the write side where the it is possible + * to write one extra pipe buffer sized block of data when the pipe + * buffer is full. + * + * @{ + */ + +/** + * Create an anonymous pipe. + * + * @returns IPRT status code. + * @param phPipeRead Where to return the read end of the pipe. + * @param phPipeWrite Where to return the write end of the pipe. + * @param fFlags A combination of RTPIPE_C_XXX defines. + */ +RTDECL(int) RTPipeCreate(PRTPIPE phPipeRead, PRTPIPE phPipeWrite, uint32_t fFlags); + +/** @name RTPipeCreate flags. + * @{ */ +/** Mark the read end as inheritable. */ +#define RTPIPE_C_INHERIT_READ RT_BIT(0) +/** Mark the write end as inheritable. */ +#define RTPIPE_C_INHERIT_WRITE RT_BIT(1) +/** Mask of valid flags. */ +#define RTPIPE_C_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Closes one end of a pipe created by RTPipeCreate. + * + * @returns IPRT status code. + * @param hPipe The pipe end to close. + */ +RTDECL(int) RTPipeClose(RTPIPE hPipe); + +/** + * Closes one end of a pipe created by RTPipeCreate, extended version. + * + * @returns IPRT status code. + * @param hPipe The pipe end to close. + * @param fLeaveOpen Wheter to leave the underlying native handle open + * (for RTPipeClose() this is @c false). + */ +RTDECL(int) RTPipeCloseEx(RTPIPE hPipe, bool fLeaveOpen); + +/** + * Creates an IPRT pipe handle from a native one. + * + * Do NOT use the native handle after passing it to this function, IPRT owns it + * and might even have closed in some cases (in order to gain some query + * information access on Windows). + * + * @returns IPRT status code. + * @param phPipe Where to return the pipe handle. + * @param hNativePipe The native pipe handle. + * @param fFlags Pipe flags, RTPIPE_N_XXX. + */ +RTDECL(int) RTPipeFromNative(PRTPIPE phPipe, RTHCINTPTR hNativePipe, uint32_t fFlags); + +/** @name RTPipeFromNative flags. + * @{ */ +/** The read end. */ +#define RTPIPE_N_READ RT_BIT(0) +/** The write end. */ +#define RTPIPE_N_WRITE RT_BIT(1) +/** Make sure the pipe is inheritable if set and not inheritable when clear. */ +#define RTPIPE_N_INHERIT RT_BIT(2) +/** Mask of valid flags for . */ +#define RTPIPE_N_VALID_MASK UINT32_C(0x00000007) +/** RTPipeFromNative: Leave the native pipe handle open on close. */ +#define RTPIPE_N_LEAVE_OPEN RT_BIT(3) +/** Mask of valid flags for RTPipeFromNative(). */ +#define RTPIPE_N_VALID_MASK_FN UINT32_C(0x0000000f) +/** @} */ + +/** + * Gets the native handle for an IPRT pipe handle. + * + * This is mainly for passing a pipe to a child and then closing the parent + * handle. IPRT also uses it internally to implement RTProcCreatEx and + * RTPollSetAdd on some platforms. Do NOT expect sane API behavior if used + * for any other purpose. + * + * @returns The native handle. -1 on failure. + * @param hPipe The IPRT pipe handle. + */ +RTDECL(RTHCINTPTR) RTPipeToNative(RTPIPE hPipe); + +/** + * Get the creation inheritability of the pipe. + * + * @returns true if inherited by children (when pipe was created), false if not. + * @param hPipe The IPRT pipe handle. + */ +RTDECL(int) RTPipeGetCreationInheritability(RTPIPE hPipe); + +/** + * Read bytes from a pipe, non-blocking. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if racing a call to RTPipeReadBlocking. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected and we've read + * all the buffered data. + * @retval VINF_TRY_AGAIN if no data was available. @a *pcbRead will be set to + * 0. + * @retval VERR_ACCESS_DENIED if it's a write pipe. + * + * @param hPipe The IPRT pipe handle to read from. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. Must be greater than 0. + * @param pcbRead Where to return the number of bytes that has been + * read (mandatory). This is 0 if there is no more + * bytes to read. + * @sa RTPipeReadBlocking. + */ +RTDECL(int) RTPipeRead(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Read bytes from a pipe, blocking. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if racing a call to RTPipeRead. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected and we've read + * all the buffered data. + * @retval VERR_ACCESS_DENIED if it's a write pipe. + * + * @param hPipe The IPRT pipe handle to read from. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. + * @param pcbRead Where to return the number of bytes that has been + * read. Optional. + */ +RTDECL(int) RTPipeReadBlocking(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Write bytes to a pipe, non-blocking. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if racing a call to RTPipeWriteBlocking. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected. Does not + * trigger when @a cbToWrite is 0. + * @retval VINF_TRY_AGAIN if no data was written. @a *pcbWritten will be set + * to 0. + * @retval VERR_ACCESS_DENIED if it's a read pipe. + * + * @param hPipe The IPRT pipe handle to write to. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How many bytes we wrote, mandatory. The return can + * be 0. + */ +RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Write bytes to a pipe, blocking. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if racing a call to RTPipeWrite. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected. Does not + * trigger when @a cbToWrite is 0. + * @retval VERR_ACCESS_DENIED if it's a read pipe. + * + * @param hPipe The IPRT pipe handle to write to. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How many bytes we wrote, optional. If NULL then all + * bytes will be written. + */ +RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Flushes the buffers for the specified pipe and making sure the other party + * reads them. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported by the OS. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected. + * @retval VERR_ACCESS_DENIED if it's a read pipe. + * + * @param hPipe The IPRT pipe handle to flush. + */ +RTDECL(int) RTPipeFlush(RTPIPE hPipe); + +/** + * Checks if the pipe is ready for reading or writing (depending on the pipe + * end). + * + * @returns IPRT status code. + * @retval VERR_TIMEOUT if the timeout was reached before the pipe was ready + * for reading/writing. + * @retval VERR_NOT_SUPPORTED if not supported by the OS? + * + * @param hPipe The IPRT pipe handle to select on. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait for ever. + */ +RTDECL(int) RTPipeSelectOne(RTPIPE hPipe, RTMSINTERVAL cMillies); + +/** + * Queries the number of bytes immediately available for reading. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported by the OS. The caller shall + * handle this case. + * + * @param hPipe The IPRT read pipe handle. + * @param pcbReadable Where to return the number of bytes that is ready + * to be read. + */ +RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable); + +/** + * Query information about a pipe (mainly a VFS I/O stream formality). + * + * The only thing we guarentee to be returned is RTFSOBJINFO::Attr.fMode being + * set to FIFO and will reflect the read/write end in the RTFS_DOS_READONLY, + * RTFS_UNIX_IRUSR and RTFS_UNIX_IWUSR bits. + * + * Some implementations sometimes provide the pipe buffer size via + * RTFSOBJINFO::cbAllocated. + * + * Some implementations sometimes provide the available read data or available + * write space via RTFSOBJINFO::cbObject. + * + * Some implementations sometimes provide valid device and/or inode numbers. + * + * @returns iprt status code. + * + * @param hPipe The IPRT read pipe handle. + * @param pObjInfo Object information structure to be filled on successful + * return. + * @param enmAddAttr Which set of additional attributes to request. Use + * RTFSOBJATTRADD_NOTHING if this doesn't matter. + */ +RTDECL(int) RTPipeQueryInfo(RTPIPE hPipe, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_pipe_h */ + diff --git a/include/iprt/poll.h b/include/iprt/poll.h new file mode 100644 index 00000000..be2b3b6d --- /dev/null +++ b/include/iprt/poll.h @@ -0,0 +1,265 @@ +/** @file + * IPRT - Polling I/O Handles. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_poll_h +#define IPRT_INCLUDED_poll_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_poll RTPoll - Polling I/O Handles + * @ingroup grp_rt + * @{ + */ + +/** @name Poll events + * @{ */ +/** Readable without blocking. */ +#define RTPOLL_EVT_READ RT_BIT_32(0) +/** Writable without blocking. */ +#define RTPOLL_EVT_WRITE RT_BIT_32(1) +/** Error condition, hangup, exception or similar. */ +#define RTPOLL_EVT_ERROR RT_BIT_32(2) +/** Mask of the valid bits. */ +#define RTPOLL_EVT_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Polls on the specified poll set until an event occurs on one of the handles + * or the timeout expires. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if an event occurred on a handle. Note that these + * @retval VERR_INVALID_HANDLE if @a hPollSet is invalid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_TIMEOUT if @a cMillies ellapsed without any events. + * @retval VERR_DEADLOCK if @a cMillies is set to RT_INDEFINITE_WAIT and there + * are no valid handles in the set. + * + * @param hPollSet The set to poll on. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait for ever. + * @param pfEvents Where to return details about the events that + * occurred. Optional. + * @param pid Where to return the ID associated with the + * handle when calling RTPollSetAdd. Optional. + * + * @sa RTPollNoResume + * + * @remarks The caller is responsible for ensuring + */ +RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid); + +/** + * Same as RTPoll except that it will return when interrupted. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if an event occurred on a handle. Note that these + * @retval VERR_INVALID_HANDLE if @a hPollSet is invalid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_TIMEOUT if @a cMillies ellapsed without any events. + * @retval VERR_DEADLOCK if @a cMillies is set to RT_INDEFINITE_WAIT and there + * are no valid handles in the set. + * @retval VERR_INTERRUPTED if a signal or other asynchronous event interrupted + * the polling. + * + * @param hPollSet The set to poll on. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait for ever. + * @param pfEvents Where to return details about the events that + * occurred. Optional. + * @param pid Where to return the ID associated with the + * handle when calling RTPollSetAdd. Optional. + */ +RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid); + +/** + * Creates a poll set with no members. + * + * @returns IPRT status code. + * @param phPollSet Where to return the poll set handle. + */ +RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet); + +/** + * Destroys a poll set. + * + * @returns IPRT status code. + * @param hPollSet The poll set to destroy. NIL_POLLSET is quietly + * ignored (VINF_SUCCESS). + */ +RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet); + +/** + * Adds a generic handle to the poll set. + * + * If a handle is entered more than once, it is recommended to add the one with + * RTPOLL_EVT_ERROR first to ensure that you get the right ID back when an error + * actually occurs. On some hosts it is possible that polling for + * RTPOLL_EVT_READ on a socket may cause it to return error conditions because + * the two cannot so easily be distinguished. + * + * Also note that RTPOLL_EVT_ERROR may be returned by RTPoll even if not asked + * for. + * + * @returns IPRT status code + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_POLL_HANDLE_NOT_POLLABLE if the specified handle is not + * pollable. + * @retval VERR_POLL_HANDLE_ID_EXISTS if the handle ID is already in use in the + * set. + * + * @param hPollSet The poll set to modify. + * @param pHandle The handle to add. NIL handles are quietly + * ignored. + * @param fEvents Which events to poll for. + * @param id The handle ID. + */ +RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id); + +/** + * Removes a generic handle from the poll set. + * + * @returns IPRT status code + * @retval VERR_INVALID_HANDLE if @a hPollSet not valid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_POLL_HANDLE_ID_NOT_FOUND if @a id doesn't resolve to a valid + * handle. + * + * @param hPollSet The poll set to modify. + * @param id The handle ID of the handle that should be + * removed. + */ +RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id); + + +/** + * Query a handle in the poll set by it's ID. + * + * @returns IPRT status code + * @retval VINF_SUCCESS if the handle was found. @a *pHandle is set. + * @retval VERR_INVALID_HANDLE if @a hPollSet is invalid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_POLL_HANDLE_ID_NOT_FOUND if there is no handle with that ID. + * + * @param hPollSet The poll set to query. + * @param id The ID of the handle. + * @param pHandle Where to return the handle details. Optional. + */ +RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle); + +/** + * Gets the number of handles in the set. + * + * @retval The handle count. + * @retval UINT32_MAX if @a hPollSet is invalid or there is concurrent access. + * + * @param hPollSet The poll set. + */ +RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet); + +/** + * Modifies the events to poll for for the given id. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if @a hPollSet not valid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_POLL_HANDLE_ID_NOT_FOUND if @a id doesn't resolve to a valid + * handle. + * + * @param hPollSet The poll set to modify. + * @param id The handle ID to change the events for. + * @param fEvents Which events to poll for. + */ +RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents); + +/** + * Adds a pipe handle to the set. + * + * @returns See RTPollSetAdd. + * + * @param hPollSet The poll set. + * @param hPipe The pipe handle. + * @param fEvents Which events to poll for. + * @param id The handle ID. + * + * @todo Maybe we could figure out what to poll for depending on the kind of + * pipe we're dealing with. + */ +DECLINLINE(int) RTPollSetAddPipe(RTPOLLSET hPollSet, RTPIPE hPipe, uint32_t fEvents, uint32_t id) +{ + RTHANDLE Handle; + Handle.enmType = RTHANDLETYPE_PIPE; + Handle.u.uInt = 0; + Handle.u.hPipe = hPipe; + return RTPollSetAdd(hPollSet, &Handle, fEvents, id); +} + +/** + * Adds a socket handle to the set. + * + * @returns See RTPollSetAdd. + * + * @param hPollSet The poll set. + * @param hSocket The socket handle. + * @param fEvents Which events to poll for. + * @param id The handle ID. + */ +DECLINLINE(int) RTPollSetAddSocket(RTPOLLSET hPollSet, RTSOCKET hSocket, uint32_t fEvents, uint32_t id) +{ + RTHANDLE Handle; + Handle.enmType = RTHANDLETYPE_SOCKET; + Handle.u.uInt = 0; + Handle.u.hSocket = hSocket; + return RTPollSetAdd(hPollSet, &Handle, fEvents, id); +} + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_poll_h */ + diff --git a/include/iprt/power.h b/include/iprt/power.h new file mode 100644 index 00000000..d36e840d --- /dev/null +++ b/include/iprt/power.h @@ -0,0 +1,125 @@ +/** @file + * IPRT - Power management. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_power_h +#define IPRT_INCLUDED_power_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_power RTPower - Power management + * @ingroup grp_rt + * @{ + */ + +#ifdef IN_RING0 + +/** + * MP event, see FNRTPOWERNOTIFICATION. + */ +typedef enum RTPOWEREVENT +{ + /** The system will go into suspend mode. */ + RTPOWEREVENT_SUSPEND = 1, + /** The system has resumed. */ + RTPOWEREVENT_RESUME +} RTPOWEREVENT; + +/** + * Notification callback. + * + * The context this is called in differs a bit from platform to + * platform, so be careful while in here. + * + * @param enmEvent The event. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTPOWERNOTIFICATION,(RTPOWEREVENT enmEvent, void *pvUser)); +/** Pointer to a FNRTPOWERNOTIFICATION(). */ +typedef FNRTPOWERNOTIFICATION *PFNRTPOWERNOTIFICATION; + +/** + * Registers a notification callback for power events. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NO_MEMORY if a registration record cannot be allocated. + * @retval VERR_ALREADY_EXISTS if the pfnCallback and pvUser already exist + * in the callback list. + * + * @param pfnCallback The callback. + * @param pvUser The user argument to the callback function. + */ +RTDECL(int) RTPowerNotificationRegister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser); + +/** + * This deregisters a notification callback registered via RTPowerNotificationRegister(). + * + * The pfnCallback and pvUser arguments must be identical to the registration call + * of we won't find the right entry. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if no matching entry was found. + * + * @param pfnCallback The callback. + * @param pvUser The user argument to the callback function. + */ +RTDECL(int) RTPowerNotificationDeregister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser); + +/** + * This calls all registered power management callback handlers registered via RTPowerNotificationRegister(). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * + * @param enmEvent Power Management event + */ +RTDECL(int) RTPowerSignalEvent(RTPOWEREVENT enmEvent); + +#endif /* IN_RING0 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_power_h */ + diff --git a/include/iprt/process.h b/include/iprt/process.h new file mode 100644 index 00000000..de3590e8 --- /dev/null +++ b/include/iprt/process.h @@ -0,0 +1,479 @@ +/** @file + * IPRT - Process Management. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_process_h +#define IPRT_INCLUDED_process_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_process RTProc - Process Management + * @ingroup grp_rt + * @{ + */ + + +/** + * Process priority. + * + * The process priority is used to select how scheduling properties + * are assigned to the different thread types (see THREADTYPE). + * + * In addition to using the policy assigned to the process at startup (DEFAULT) + * it is possible to change the process priority at runtime. This allows for + * a GUI, resource manager or admin to adjust the general priority of a task + * without upsetting the fine-tuned priority of the threads within. + */ +typedef enum RTPROCPRIORITY +{ + /** Invalid priority. */ + RTPROCPRIORITY_INVALID = 0, + /** Default priority. + * Derive the scheduling policy from the priority of the RTR3Init() + * and RTProcSetPriority() callers and the rights the process have + * to alter its own priority. + */ + RTPROCPRIORITY_DEFAULT, + /** Flat priority. + * Assumes a scheduling policy which puts the process at the default priority + * and with all thread at the same priority. + */ + RTPROCPRIORITY_FLAT, + /** Low priority. + * Assumes a scheduling policy which puts the process mostly below the + * default priority of the host OS. + */ + RTPROCPRIORITY_LOW, + /** Normal priority. + * Assume a scheduling policy which shares the CPU resources fairly with + * other processes running with the default priority of the host OS. + */ + RTPROCPRIORITY_NORMAL, + /** High priority. + * Assumes a scheduling policy which puts the task above the default + * priority of the host OS. This policy might easily cause other tasks + * in the system to starve. + */ + RTPROCPRIORITY_HIGH, + /** Last priority, used for validation. */ + RTPROCPRIORITY_LAST +} RTPROCPRIORITY; + + +/** + * Get the current process identifier. + * + * @returns Process identifier. + */ +RTDECL(RTPROCESS) RTProcSelf(void); + + +#ifdef IN_RING0 +/** + * Get the current process handle. + * + * @returns Ring-0 process handle. + */ +RTR0DECL(RTR0PROCESS) RTR0ProcHandleSelf(void); +#endif + + +/** + * Translate a signal number to a short name on the form SIGXXXX. + * + * If the signal is not known, it will be formatted as a number into one of + * several static buffers. This means that there could be concurrency issues if + * this suddenly happens on multiple threads, though that is unlikely. + * + * @returns Readonly string naming the signal. + * @param iSignal The signal to name. + */ +RTDECL(const char *) RTProcSignalName(int iSignal); + +#ifdef IN_RING3 + +/** + * Attempts to alter the priority of the current process. + * + * @returns iprt status code. + * @param enmPriority The new priority. + */ +RTR3DECL(int) RTProcSetPriority(RTPROCPRIORITY enmPriority); + +/** + * Gets the current priority of this process. + * + * @returns The priority (see RTPROCPRIORITY). + */ +RTR3DECL(RTPROCPRIORITY) RTProcGetPriority(void); + +/** + * Create a child process. + * + * @returns iprt status code. + * @param pszExec Executable image to use to create the child process. + * @param papszArgs Pointer to an array of arguments to the child. The array terminated by an entry containing NULL. + * @param Env Handle to the environment block for the child. + * @param fFlags Flags, one of the RTPROC_FLAGS_* defines. + * @param pProcess Where to store the process identifier on successful return. + * The content is not changed on failure. NULL is allowed. + */ +RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess); + + +/** + * Create a child process. + * + * @returns IPRT status code. + * + * @param pszExec Executable image to use to create the child process. + * @param papszArgs Pointer to an array of arguments to the child. The + * array terminated by an entry containing NULL. + * @param hEnv Handle to the environment block for the child. Pass + * RTENV_DEFAULT to use the environment of the current + * process. + * @param fFlags Flags, one of the RTPROC_FLAGS_* defines. + * @param phStdIn The standard in handle to assign the new process. Pass + * NULL to use the same as the current process. If the + * handle is NIL, we'll close the standard input of the + * guest. + * @param phStdOut The standard out handle to assign the new process. Pass + * NULL to use the same as the current process. If the + * handle is NIL, we'll close the standard output of the + * guest. + * @param phStdErr The standard error handle to assign the new process. Pass + * NULL to use the same as the current process. If the + * handle is NIL, we'll close the standard error of the + * guest. + * @param pszAsUser User to run the process as. Pass NULL to use the same + * user as the current process. + * Windows: Use user\@domain (UPN, User Principal Name) + * format to specify a domain. + * @param pszPassword Password to use to authenticate @a pszAsUser. Must be + * NULL wif pszAsUser is NULL. Whether this is actually + * used or not depends on the platform. + * @param pvExtraData Points to additional data as per @a fFlags: + * - RTPROC_FLAGS_DESIRED_SESSION_ID: Pointing to a + * uint32_t variable with the desired session ID. + * @param phProcess Where to store the process handle on successful return. + * The content is not changed on failure. NULL is allowed. + * + * @remarks The handles does not have to be created as inheritable, but it + * doesn't hurt if they are as it may avoid race conditions on some + * platforms. + * + * @remarks The as-user feature isn't supported/implemented on all platforms and + * will cause a-yet-to-be-determined-error-status on these. + */ +RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags, + PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser, + const char *pszPassword, void *pvExtraData, PRTPROCESS phProcess); + +/** @name RTProcCreate and RTProcCreateEx flags + * @{ */ +/** Detach the child process from the parents process tree and process group, + * session or/and console (depends on the platform what's done applicable). + * + * The new process will not be a direct decendent of the parent and it will not + * be possible to wait for it, i.e. @a phProcess shall be NULL. */ +#define RTPROC_FLAGS_DETACHED RT_BIT(0) +/** Don't show the started process. + * This is a Windows (and maybe OS/2) concept, do not use on other platforms. */ +#define RTPROC_FLAGS_HIDDEN RT_BIT(1) +/** Use special code path for starting child processes from a service (daemon). + * This is a windows concept for dealing with the so called "Session 0" + * isolation which was introduced with Windows Vista. Do not use on other + * platforms. */ +#define RTPROC_FLAGS_SERVICE RT_BIT(2) +/** Suppress changing the process contract id for the child process + * on Solaris. Without this flag the contract id is always changed, as that's + * the more frequently used case. */ +#define RTPROC_FLAGS_SAME_CONTRACT RT_BIT(3) +/** Load user profile data when executing a process. + * This redefines the meaning of RTENV_DEFAULT to the profile environment. See + * also RTPROC_FLAGS_ONLY_BASIC_PROFILE */ +#define RTPROC_FLAGS_PROFILE RT_BIT(4) +/** Create process without a console window. + * This is a Windows (and OS/2) concept, do not use on other platforms. */ +#define RTPROC_FLAGS_NO_WINDOW RT_BIT(5) +/** Search the PATH for the executable. */ +#define RTPROC_FLAGS_SEARCH_PATH RT_BIT(6) +/** Don't quote and escape arguments on Windows and similar platforms where a + * command line is passed to the child process instead of an argument vector, + * just join up argv with a space between each. Ignored on platforms + * passing argument the vector. */ +#define RTPROC_FLAGS_UNQUOTED_ARGS RT_BIT(7) +/** Consider hEnv an environment change record to be applied to RTENV_DEFAULT. + * If hEnv is RTENV_DEFAULT, the flag has no effect. */ +#define RTPROC_FLAGS_ENV_CHANGE_RECORD RT_BIT(8) +/** Create process using the current impersonated thread token. + * Caller should also specify RTPROC_FLAGS_SERVICE and RTPROC_FLAGS_PROFILE. + * Windows only flag, ignored everywhere else. */ +#define RTPROC_FLAGS_AS_IMPERSONATED_TOKEN RT_BIT(9) +/** Hint that we don't expect to ever want to wait on the process. */ +#define RTPROC_FLAGS_NO_WAIT RT_BIT(10) +/** For use with RTPROC_FLAGS_SERVICE to specify a desired session ID + * (Windows only, ignored elsewhere). The @a pvExtraData argument points to + * a uint32_t containing the session ID, UINT32_MAX means any session. + * Can not be set with RTPROC_FLAGS_TOKEN_SUPPLIED */ +#define RTPROC_FLAGS_DESIRED_SESSION_ID RT_BIT(11) +/** This is a modifier to RTPROC_FLAGS_PROFILE on unix systems that makes it + * skip trying to dump the environment of a login shell. */ +#define RTPROC_FLAGS_ONLY_BASIC_PROFILE RT_BIT(12) +/** Don't translate arguments to the (guessed) child process codeset. + * This is ignored on Windows as it is using UTF-16. */ +#define RTPROC_FLAGS_UTF8_ARGV RT_BIT_32(13) +/** Create process using supplied token. The @a pvExtraData argument points to + * a HANDLE containing the token used as user credentials for process creation. + * Can not be set with RTPROC_FLAGS_DESIRED_SESSION_ID. + * Windows only flag, ignored everywhere else. */ +#define RTPROC_FLAGS_TOKEN_SUPPLIED RT_BIT(14) + +/** Valid flag mask. */ +#define RTPROC_FLAGS_VALID_MASK UINT32_C(0x7fff) +/** @} */ + + +/** + * Process exit reason. + */ +typedef enum RTPROCEXITREASON +{ + /** Normal exit. iStatus contains the exit code. */ + RTPROCEXITREASON_NORMAL = 1, + /** Any abnormal exit. iStatus is undefined. */ + RTPROCEXITREASON_ABEND, + /** Killed by a signal. The iStatus field contains the signal number. */ + RTPROCEXITREASON_SIGNAL +} RTPROCEXITREASON; + +/** + * Process exit status. + */ +typedef struct RTPROCSTATUS +{ + /** The process exit status if the exit was a normal one. */ + int iStatus; + /** The reason the process terminated. */ + RTPROCEXITREASON enmReason; +} RTPROCSTATUS; +/** Pointer to a process exit status structure. */ +typedef RTPROCSTATUS *PRTPROCSTATUS; +/** Pointer to a const process exit status structure. */ +typedef const RTPROCSTATUS *PCRTPROCSTATUS; + + +/** Flags for RTProcWait(). + * @{ */ +/** Block indefinitly waiting for the process to exit. */ +#define RTPROCWAIT_FLAGS_BLOCK 0 +/** Don't block, just check if the process have exited. */ +#define RTPROCWAIT_FLAGS_NOBLOCK 1 +/** @} */ + +/** + * Waits for a process, resumes on interruption. + * + * @returns VINF_SUCCESS when the status code for the process was collected and + * put in *pProcStatus. + * @returns VERR_PROCESS_NOT_FOUND if the specified process wasn't found. + * @returns VERR_PROCESS_RUNNING when the RTPROCWAIT_FLAGS_NOBLOCK and the + * process haven't exited yet. + * + * @param Process The process to wait for. + * @param fFlags The wait flags, any of the RTPROCWAIT_FLAGS_ \#defines. + * @param pProcStatus Where to store the exit status on success. + * Optional. + */ +RTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus); + +/** + * Waits for a process, returns on interruption. + * + * @returns VINF_SUCCESS when the status code for the process was collected and + * put in *pProcStatus. + * @returns VERR_PROCESS_NOT_FOUND if the specified process wasn't found. + * @returns VERR_PROCESS_RUNNING when the RTPROCWAIT_FLAGS_NOBLOCK and the + * process haven't exited yet. + * @returns VERR_INTERRUPTED when the wait was interrupted by the arrival of a + * signal or other async event. + * + * @param Process The process to wait for. + * @param fFlags The wait flags, any of the RTPROCWAIT_FLAGS_ \#defines. + * @param pProcStatus Where to store the exit status on success. + * Optional. + */ +RTR3DECL(int) RTProcWaitNoResume(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus); + +/** + * Terminates (kills) a running process. + * + * @returns IPRT status code. + * @param Process The process to terminate. + */ +RTR3DECL(int) RTProcTerminate(RTPROCESS Process); + +/** + * Gets the processor affinity mask of the current process. + * + * @returns The affinity mask. + */ +RTR3DECL(uint64_t) RTProcGetAffinityMask(void); + +/** + * Gets the short process name. + * + * @returns Pointer to read-only name string. + * @note IPRT must've been initialized or the string will be empty. + */ +RTR3DECL(const char *) RTProcShortName(void); + +/** + * Gets the path to the executable image of the current process. + * + * @returns Pointer to read-only path string. + * @note IPRT must've been initialized or the string will be empty. + */ +RTR3DECL(const char *) RTProcExecutablePath(void); + +/** + * Gets a copy of the path to the executable image of the current process. + * + * @returns pszExecPath on success. NULL on buffer overflow or other errors. + * + * @param pszExecPath Where to store the path. + * @param cbExecPath The size of the buffer. + * @note IPRT must've been initialized or the string will be empty. + */ +RTR3DECL(char *) RTProcGetExecutablePath(char *pszExecPath, size_t cbExecPath); + +/** + * Daemonize the current process, making it a background process. + * + * The way this work is that it will spawn a detached / backgrounded / + * daemonized / call-it-what-you-want process that isn't a direct child of the + * current process. The spawned will have the same arguments a the caller, + * except that the @a pszDaemonizedOpt is appended to prevent that the new + * process calls this API again. + * + * The new process will have the standard handles directed to/from the + * bitbucket. + * + * @returns IPRT status code. On success it is normal for the caller to exit + * the process by returning from main(). + * + * @param papszArgs The argument vector of the calling process. + * @param pszDaemonizedOpt The daemonized option. This is appended to the + * end of the parameter list of the daemonized process. + */ +RTR3DECL(int) RTProcDaemonize(const char * const *papszArgs, const char *pszDaemonizedOpt); + +/** + * Daemonize the current process, making it a background process. The current + * process will exit if daemonizing is successful. + * + * @returns IPRT status code. On success it will only return in the child + * process, the parent will exit. On failure, it will return in the + * parent process and no child has been spawned. + * + * @param fNoChDir Pass false to change working directory to "/". + * @param fNoClose Pass false to redirect standard file streams to the null device. + * @param pszPidfile Path to a file to write the process id of the daemon + * process to. Daemonizing will fail if this file already + * exists or cannot be written. May be NULL. + */ +RTR3DECL(int) RTProcDaemonizeUsingFork(bool fNoChDir, bool fNoClose, const char *pszPidfile); + +/** + * Check if the given process is running on the system. + * + * This check is case sensitive on most systems, except for Windows, OS/2 and + * Darwin. + * + * @returns true if the process is running & false otherwise. + * @param pszName Process name to search for. If no path is given only the + * filename part of the running process set will be + * matched. If a path is specified, the full path will be + * matched. + */ +RTR3DECL(bool) RTProcIsRunningByName(const char *pszName); + +/** + * Queries the parent process ID. + * + * @returns IPRT status code + * @param hProcess The process to query the parent of. + * @param phParent Where to return the parent process ID. + */ +RTR3DECL(int) RTProcQueryParent(RTPROCESS hProcess, PRTPROCESS phParent); + +/** + * Query the username of the given process. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the given buffer size is to small for the username. + * @param hProcess The process handle to query the username for. + * NIL_PROCESS is an alias for the current process. + * @param pszUser Where to store the user name on success. + * @param cbUser The size of the user name buffer. + * @param pcbUser Where to store the username length on success + * or the required buffer size if VERR_BUFFER_OVERFLOW + * is returned. + */ +RTR3DECL(int) RTProcQueryUsername(RTPROCESS hProcess, char *pszUser, size_t cbUser, size_t *pcbUser); + +/** + * Query the username of the given process allocating the string for the username. + * + * @returns IPRT status code. + * @param hProcess The process handle to query the username for. + * @param ppszUser Where to store the pointer to the string containing + * the username on success. Free with RTStrFree(). + */ +RTR3DECL(int) RTProcQueryUsernameA(RTPROCESS hProcess, char **ppszUser); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_process_h */ + diff --git a/include/iprt/queueatomic.h b/include/iprt/queueatomic.h new file mode 100644 index 00000000..72b188e1 --- /dev/null +++ b/include/iprt/queueatomic.h @@ -0,0 +1,137 @@ +/** @file + * IPRT - Generic Work Queue with concurrent atomic access. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_queueatomic_h +#define IPRT_INCLUDED_queueatomic_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** @defgroup grp_rt_queueatomic RTQueueAtomic - Generic Work Queue + * @ingroup grp_rt + * + * Implementation of a lockless work queue for threaded environments. + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * A work item + */ +typedef struct RTQUEUEATOMICITEM +{ + /** Pointer to the next work item in the list. */ + struct RTQUEUEATOMICITEM * volatile pNext; +} RTQUEUEATOMICITEM; +/** Pointer to a work item. */ +typedef RTQUEUEATOMICITEM *PRTQUEUEATOMICITEM; +/** Pointer to a work item pointer. */ +typedef PRTQUEUEATOMICITEM *PPRTQUEUEATOMICITEM; + +/** + * Work queue. + */ +typedef struct RTQUEUEATOMIC +{ + /* Head of the work queue. */ + volatile PRTQUEUEATOMICITEM pHead; +} RTQUEUEATOMIC; +/** Pointer to a work queue. */ +typedef RTQUEUEATOMIC *PRTQUEUEATOMIC; + +/** + * Initialize a work queue. + * + * @param pWorkQueue Pointer to an unitialised work queue. + */ +DECLINLINE(void) RTQueueAtomicInit(PRTQUEUEATOMIC pWorkQueue) +{ + ASMAtomicWriteNullPtr(&pWorkQueue->pHead); +} + +/** + * Insert a new item into the work queue. + * + * @param pWorkQueue The work queue to insert into. + * @param pItem The item to insert. + */ +DECLINLINE(void) RTQueueAtomicInsert(PRTQUEUEATOMIC pWorkQueue, PRTQUEUEATOMICITEM pItem) +{ + PRTQUEUEATOMICITEM pNext = ASMAtomicUoReadPtrT(&pWorkQueue->pHead, PRTQUEUEATOMICITEM); + PRTQUEUEATOMICITEM pHeadOld; + pItem->pNext = pNext; + while (!ASMAtomicCmpXchgExPtr(&pWorkQueue->pHead, pItem, pNext, &pHeadOld)) + { + pNext = pHeadOld; + Assert(pNext != pItem); + pItem->pNext = pNext; + ASMNopPause(); + } +} + +/** + * Remove all items from the given work queue and return them in the inserted order. + * + * @returns Pointer to the first item. + * @param pWorkQueue The work queue. + */ +DECLINLINE(PRTQUEUEATOMICITEM) RTQueueAtomicRemoveAll(PRTQUEUEATOMIC pWorkQueue) +{ + PRTQUEUEATOMICITEM pHead = ASMAtomicXchgPtrT(&pWorkQueue->pHead, NULL, PRTQUEUEATOMICITEM); + + /* Reverse it. */ + PRTQUEUEATOMICITEM pCur = pHead; + pHead = NULL; + while (pCur) + { + PRTQUEUEATOMICITEM pInsert = pCur; + pCur = pCur->pNext; + pInsert->pNext = pHead; + pHead = pInsert; + } + + return pHead; +} + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_queueatomic_h */ + diff --git a/include/iprt/rand.h b/include/iprt/rand.h new file mode 100644 index 00000000..149e0fb5 --- /dev/null +++ b/include/iprt/rand.h @@ -0,0 +1,330 @@ +/** @file + * IPRT - Random Numbers and Byte Streams. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_rand_h +#define IPRT_INCLUDED_rand_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_rand RTRand - Random Numbers and Byte Streams + * @ingroup grp_rt + * @{ + */ + +/** + * Fills a buffer with random bytes. + * + * @param pv Where to store the random bytes. + * @param cb Number of bytes to generate. + */ +RTDECL(void) RTRandBytes(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit signed random number in the set [i32First..i32Last]. + * + * @returns The random number. + * @param i32First First number in the set. + * @param i32Last Last number in the set. + */ +RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit signed random number. + * + * @returns The random number. + */ +RTDECL(int32_t) RTRandS32(void) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit unsigned random number in the set [u32First..u32Last]. + * + * @returns The random number. + * @param u32First First number in the set. + * @param u32Last Last number in the set. + */ +RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit unsigned random number. + * + * @returns The random number. + */ +RTDECL(uint32_t) RTRandU32(void) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit signed random number in the set [i64First..i64Last]. + * + * @returns The random number. + * @param i64First First number in the set. + * @param i64Last Last number in the set. + */ +RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit signed random number. + * + * @returns The random number. + */ +RTDECL(int64_t) RTRandS64(void) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit unsigned random number in the set [u64First..u64Last]. + * + * @returns The random number. + * @param u64First First number in the set. + * @param u64Last Last number in the set. + */ +RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit unsigned random number. + * + * @returns The random number. + */ +RTDECL(uint64_t) RTRandU64(void) RT_NO_THROW_PROTO; + + +/** + * Create an instance of the default random number generator. + * + * @returns IPRT status code. + * @param phRand Where to return the handle to the new random number + * generator. + */ +RTDECL(int) RTRandAdvCreate(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Create an instance of the default pseudo random number generator. + * + * @returns IPRT status code. + * @param phRand Where to store the handle to the generator. + */ +RTDECL(int) RTRandAdvCreatePseudo(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Create an instance of the Park-Miller pseudo random number generator. + * + * @returns IPRT status code. + * @param phRand Where to store the handle to the generator. + */ +RTDECL(int) RTRandAdvCreateParkMiller(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Create an instance of the faster random number generator for the OS. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED on platforms which doesn't have this feature. + * @retval VERR_FILE_NOT_FOUND on system where the random generator hasn't + * been installed or configured correctly. + * @retval VERR_PATH_NOT_FOUND for the same reasons as VERR_FILE_NOT_FOUND. + * + * @param phRand Where to store the handle to the generator. + * + * @remarks Think /dev/urandom. + */ +RTDECL(int) RTRandAdvCreateSystemFaster(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Create an instance of the truer random number generator for the OS. + * + * Don't use this unless you seriously need good random numbers because most + * systems will have will have problems producing sufficient entropy for this + * and you'll end up blocking while it accumulates. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED on platforms which doesn't have this feature. + * @retval VERR_FILE_NOT_FOUND on system where the random generator hasn't + * been installed or configured correctly. + * @retval VERR_PATH_NOT_FOUND for the same reasons as VERR_FILE_NOT_FOUND. + * + * @param phRand Where to store the handle to the generator. + * + * @remarks Think /dev/random. + */ +RTDECL(int) RTRandAdvCreateSystemTruer(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Destroys a random number generator. + * + * @returns IPRT status code. + * @param hRand Handle to the random number generator. + */ +RTDECL(int) RTRandAdvDestroy(RTRAND hRand) RT_NO_THROW_PROTO; + +/** + * Generic method for seeding of a random number generator. + * + * The different generators may have specialized methods for + * seeding, use one of those if you desire better control + * over the result. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it isn't a pseudo generator. + * + * @param hRand Handle to the random number generator. + * @param u64Seed Seed. + */ +RTDECL(int) RTRandAdvSeed(RTRAND hRand, uint64_t u64Seed) RT_NO_THROW_PROTO; + +/** + * Save the current state of a pseudo generator. + * + * This can be use to save the state so it can later be resumed at the same + * position. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. *pcbState contains the length of the + * returned string and pszState contains the state string. + * @retval VERR_BUFFER_OVERFLOW if the supplied buffer is too small. *pcbState + * will contain the necessary buffer size. + * @retval VERR_NOT_SUPPORTED by non-psuedo generators. + * + * @param hRand Handle to the random number generator. + * @param pszState Where to store the state. The returned string will be + * null terminated and printable. + * @param pcbState The size of the buffer pszState points to on input, the + * size required / used on return (including the + * terminator, thus the 'cb' instead of 'cch'). + */ +RTDECL(int) RTRandAdvSaveState(RTRAND hRand, char *pszState, size_t *pcbState) RT_NO_THROW_PROTO; + +/** + * Restores the state of a pseudo generator. + * + * The state must have been obtained using RTRandAdvGetState. + * + * @returns IPRT status code. + * @retval VERR_PARSE_ERROR if the state string is malformed. + * @retval VERR_NOT_SUPPORTED by non-psuedo generators. + * + * @param hRand Handle to the random number generator. + * @param pszState The state to load. + */ +RTDECL(int) RTRandAdvRestoreState(RTRAND hRand, char const *pszState) RT_NO_THROW_PROTO; + +/** + * Fills a buffer with random bytes. + * + * @param hRand Handle to the random number generator. + * @param pv Where to store the random bytes. + * @param cb Number of bytes to generate. + */ +RTDECL(void) RTRandAdvBytes(RTRAND hRand, void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit signed random number in the set [i32First..i32Last]. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + * @param i32First First number in the set. + * @param i32Last Last number in the set. + */ +RTDECL(int32_t) RTRandAdvS32Ex(RTRAND hRand, int32_t i32First, int32_t i32Last) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit signed random number. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + */ +RTDECL(int32_t) RTRandAdvS32(RTRAND hRand) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit unsigned random number in the set [u32First..u32Last]. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + * @param u32First First number in the set. + * @param u32Last Last number in the set. + */ +RTDECL(uint32_t) RTRandAdvU32Ex(RTRAND hRand, uint32_t u32First, uint32_t u32Last) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit unsigned random number. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + */ +RTDECL(uint32_t) RTRandAdvU32(RTRAND hRand) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit signed random number in the set [i64First..i64Last]. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + * @param i64First First number in the set. + * @param i64Last Last number in the set. + */ +RTDECL(int64_t) RTRandAdvS64Ex(RTRAND hRand, int64_t i64First, int64_t i64Last) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit signed random number. + * + * @returns The random number. + */ +RTDECL(int64_t) RTRandAdvS64(RTRAND hRand) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit unsigned random number in the set [u64First..u64Last]. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + * @param u64First First number in the set. + * @param u64Last Last number in the set. + */ +RTDECL(uint64_t) RTRandAdvU64Ex(RTRAND hRand, uint64_t u64First, uint64_t u64Last) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit unsigned random number. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + */ +RTDECL(uint64_t) RTRandAdvU64(RTRAND hRand) RT_NO_THROW_PROTO; + + +/** @} */ + +RT_C_DECLS_END + + +#endif /* !IPRT_INCLUDED_rand_h */ + diff --git a/include/iprt/req.h b/include/iprt/req.h new file mode 100644 index 00000000..a017e9e1 --- /dev/null +++ b/include/iprt/req.h @@ -0,0 +1,643 @@ +/** @file + * IPRT - Request Queue & Pool. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_req_h +#define IPRT_INCLUDED_req_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_req RTReq - Request Queue & Pool. + * @ingroup grp_rt + * @{ + */ + +/** Request queue handle. */ +typedef struct RTREQQUEUEINT *RTREQQUEUE; +/** Pointer to a request queue handle. */ +typedef RTREQQUEUE *PRTREQQUEUE; +/** NIL request queue handle. */ +#define NIL_RTREQQUEUE ((RTREQQUEUE)0) + +/** Request thread pool handle. */ +typedef struct RTREQPOOLINT *RTREQPOOL; +/** Poiner to a request thread pool handle. */ +typedef RTREQPOOL *PRTREQPOOL; +/** NIL request pool handle. */ +#define NIL_RTREQPOOL ((RTREQPOOL)0) + + +/** + * Request type. + */ +typedef enum RTREQTYPE +{ + /** Invalid request. */ + RTREQTYPE_INVALID = 0, + /** RT: Internal. */ + RTREQTYPE_INTERNAL, + /** Maximum request type (exclusive). Used for validation. */ + RTREQTYPE_MAX +} RTREQTYPE; + +/** + * Request flags. + */ +typedef enum RTREQFLAGS +{ + /** The request returns a IPRT status code. */ + RTREQFLAGS_IPRT_STATUS = 0, + /** The request is a void request and have no status code. */ + RTREQFLAGS_VOID = 1, + /** Return type mask. */ + RTREQFLAGS_RETURN_MASK = 1, + /** Caller does not wait on the packet. */ + RTREQFLAGS_NO_WAIT = 2 +} RTREQFLAGS; + + +/** A request packet. */ +typedef struct RTREQ RTREQ; +/** Pointer to an RT request packet. */ +typedef RTREQ *PRTREQ; +/** Nil request handle. */ +#define NIL_RTREQ ((PRTREQ)0) + + +#ifdef IN_RING3 + +/** + * Create a request packet queue + * + * @returns IPRT status code. + * @param phQueue Where to store the request queue handle. + */ +RTDECL(int) RTReqQueueCreate(PRTREQQUEUE phQueue); + +/** + * Destroy a request packet queue + * + * @returns IPRT status code. + * @param hQueue The request queue. + */ +RTDECL(int) RTReqQueueDestroy(RTREQQUEUE hQueue); + +/** + * Process one or more request packets + * + * @returns IPRT status code. Any non-VINF_SUCCESS returns from request + * processing is immediately propagated to the caller. + * @retval VERR_TIMEOUT if @a cMillies was reached without the packet being + * added. + * @retval VERR_INVALID_HANDLE if @a hQueue not a valid queue handle. + * + * @param hQueue The request queue. + * @param cMillies Max number of milliseconds to wait for a pending + * request. This is not adjusted down before another + * wait, so the function may end up waiting for much + * longer than the given amount if there are requests + * trickling in at a rate slightly higher than the + * timeout. + * + * Use RT_INDEFINITE_WAIT to process requests until a + * non-VINF_SUCCESS return code is encountered. + * + * @remarks The function may repeatedly try wait for @a cMillies on new + * requests if requests arrive before it times out. + */ +RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies); + +/** + * Allocate and queue a call request. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * The returned request packet must be freed using RTReqRelease(). + * + * @returns iprt statuscode. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param hQueue The request queue. + * @param ppReq Where to store the pointer to the request. + * This will be NULL or a valid request pointer no matter what happens. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Function arguments. + * + * @remarks See remarks on RTReqQueueCallV. + */ +RTDECL(int) RTReqQueueCall(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Allocate and queue a call request to a void function. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * The returned request packet must be freed using RTReqRelease(). + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param hQueue The request queue. + * @param ppReq Where to store the pointer to the request. + * This will be NULL or a valid request pointer no matter what happens. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Function arguments. + * + * @remarks See remarks on RTReqQueueCallV. + */ +RTDECL(int) RTReqQueueCallVoid(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Allocate and queue a call request to a void function. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * The returned request packet must be freed using RTReqRelease(). + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param hQueue The request queue. + * @param ppReq Where to store the pointer to the request. Optional + * when RTREQFLAGS_NO_WAIT is used. + * This variable will be set to NIL or a valid request + * handle no matter what happens. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + * @param fFlags A combination of the RTREQFLAGS values. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Function arguments. + * + * @remarks See remarks on RTReqQueueCallV. + */ +RTDECL(int) RTReqQueueCallEx(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Allocate and queue a call request. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * The returned request packet must be freed using RTReqRelease(). + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param hQueue The request queue. + * @param ppReq Where to store the pointer to the request. Optional + * when RTREQFLAGS_NO_WAIT is used. + * This variable will be set to NIL or a valid request + * handle no matter what happens. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + * @param fFlags A combination of the RTREQFLAGS values. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param Args Variable argument vector. + * + * @remarks Caveats: + * - Do not pass anything which is larger than an uintptr_t. + * - 64-bit integers are larger than uintptr_t on 32-bit hosts. + * Pass integers > 32-bit by reference (pointers). + * - Don't use NULL since it should be the integer 0 in C++ and may + * therefore end up with garbage in the bits 63:32 on 64-bit + * hosts because 'int' is 32-bit. + * Use (void *)NULL or (uintptr_t)0 instead of NULL. + */ +RTDECL(int) RTReqQueueCallV(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args); + +/** + * Checks if the queue is busy or not. + * + * The caller is responsible for dealing with any concurrent submitts. + * + * @returns true if busy, false if idle. + * @param hQueue The queue. + */ +RTDECL(bool) RTReqQueueIsBusy(RTREQQUEUE hQueue); + +/** + * Allocates a request packet. + * + * The caller allocates a request packet, fills in the request data + * union and queues the request. + * + * @returns IPRT status code. + * + * @param hQueue The request queue. + * @param enmType Package type. + * @param phReq Where to store the handle to the new request. + */ +RTDECL(int) RTReqQueueAlloc(RTREQQUEUE hQueue, RTREQTYPE enmType, PRTREQ *phReq); + + +/** + * Creates a request thread pool. + * + * The core configuration is given as parameters, finer pool tuning can be + * achieved via RTReqPoolSetCfgVar. + * + * @returns IPRT status code. + * @param cMaxThreads The maximum number of worker threads. + * UINT32_MAX is an alias for the highest + * allowed thread count. + * @param cMsMinIdle The number of milliseconds a worker + * thread needs to be idle before it is + * considered for shutdown. The value + * RT_INDEFINITE_WAIT disables automatic + * idle thread shutdown. + * @param cThreadsPushBackThreshold At which worker thread count the push + * back should kick in. + * @param cMsMaxPushBack The max number of milliseconds to push + * back a submitter. UINT32_MAX is an + * alias for the highest allowed push back. + * @param pszName The pool name. Keep it short as it is + * used for naming worker threads. + * @param phPool Where to return the pool handle. + */ +RTDECL(int) RTReqPoolCreate(uint32_t cMaxThreads, RTMSINTERVAL cMsMinIdle, + uint32_t cThreadsPushBackThreshold, uint32_t cMsMaxPushBack, + const char *pszName, PRTREQPOOL phPool); + +/** + * Retains a reference to a request thread pool. + * + * @returns The new reference count, UINT32_MAX on invalid handle (asserted). + * @param hPool The request thread pool handle. + */ +RTDECL(uint32_t) RTReqPoolRetain(RTREQPOOL hPool); + +/** + * Releases a reference to the request thread pool. + * + * When the reference count reaches zero, the request will be pooled for reuse. + * + * @returns The new reference count, UINT32_MAX on invalid handle (asserted). + * @param hPool The request thread pool handle. + */ +RTDECL(uint32_t) RTReqPoolRelease(RTREQPOOL hPool); + +/** + * Request thread pool configuration variable. + */ +typedef enum RTREQPOOLCFGVAR +{ + /** Invalid zero value. */ + RTREQPOOLCFGVAR_INVALID = 0, + /** The desired RTTHREADTYPE of the worker threads. */ + RTREQPOOLCFGVAR_THREAD_TYPE, + /** The RTTHREADFLAGS mask for the worker threads (not waitable). */ + RTREQPOOLCFGVAR_THREAD_FLAGS, + /** The minimum number of threads to keep handy once spawned. */ + RTREQPOOLCFGVAR_MIN_THREADS, + /** The maximum number of thread to start. */ + RTREQPOOLCFGVAR_MAX_THREADS, + /** The minimum number of milliseconds a worker thread needs to be idle + * before we consider shutting it down. The other shutdown criteria + * being set by RTREQPOOLCFGVAR_MIN_THREADS. The value + * RT_INDEFINITE_WAIT can be used to disable shutting down idle threads. */ + RTREQPOOLCFGVAR_MS_MIN_IDLE, + /** The sleep period, in milliseoncds, to employ when idling. The value + * RT_INDEFINITE_WAIT can be used to disable shutting down idle threads. */ + RTREQPOOLCFGVAR_MS_IDLE_SLEEP, + /** The number of threads at which to start pushing back. The value + * UINT64_MAX is an alias for the current upper thread count limit, i.e. + * disabling push back. The value 0 (zero) is an alias for the current + * lower thread count, a good value to start pushing back at. The value + * must otherwise be within */ + RTREQPOOLCFGVAR_PUSH_BACK_THRESHOLD, + /** The minimum push back time in milliseconds. */ + RTREQPOOLCFGVAR_PUSH_BACK_MIN_MS, + /** The maximum push back time in milliseconds. */ + RTREQPOOLCFGVAR_PUSH_BACK_MAX_MS, + /** The maximum number of free requests to keep handy for recycling. */ + RTREQPOOLCFGVAR_MAX_FREE_REQUESTS, + /** The end of the range of valid config variables. */ + RTREQPOOLCFGVAR_END, + /** Blow the type up to 32-bits. */ + RTREQPOOLCFGVAR_32BIT_HACK = 0x7fffffff +} RTREQPOOLCFGVAR; + + +/** + * Sets a config variable for a request thread pool. + * + * @returns IPRT status code. + * @param hPool The pool handle. + * @param enmVar The variable to set. + * @param uValue The new value. + */ +RTDECL(int) RTReqPoolSetCfgVar(RTREQPOOL hPool, RTREQPOOLCFGVAR enmVar, uint64_t uValue); + +/** + * Gets a config variable for a request thread pool. + * + * @returns The value, UINT64_MAX on invalid parameters. + * @param hPool The pool handle. + * @param enmVar The variable to query. + */ +RTDECL(uint64_t) RTReqPoolGetCfgVar(RTREQPOOL hPool, RTREQPOOLCFGVAR enmVar); + +/** + * Request thread pool statistics value names. + */ +typedef enum RTREQPOOLSTAT +{ + /** The invalid zero value, as per tradition. */ + RTREQPOOLSTAT_INVALID = 0, + /** The current number of worker threads. */ + RTREQPOOLSTAT_THREADS, + /** The number of threads that have been created. */ + RTREQPOOLSTAT_THREADS_CREATED, + /** The total number of requests that have been processed. */ + RTREQPOOLSTAT_REQUESTS_PROCESSED, + /** The total number of requests that have been submitted. */ + RTREQPOOLSTAT_REQUESTS_SUBMITTED, + /** The total number of requests that have been cancelled. */ + RTREQPOOLSTAT_REQUESTS_CANCELLED, + /** the current number of pending (waiting) requests. */ + RTREQPOOLSTAT_REQUESTS_PENDING, + /** The current number of active (executing) requests. */ + RTREQPOOLSTAT_REQUESTS_ACTIVE, + /** The current number of free (recycled) requests. */ + RTREQPOOLSTAT_REQUESTS_FREE, + /** Total time the requests took to process. */ + RTREQPOOLSTAT_NS_TOTAL_REQ_PROCESSING, + /** Total time the requests had to wait in the queue before being + * scheduled. */ + RTREQPOOLSTAT_NS_TOTAL_REQ_QUEUED, + /** Average time the requests took to process. */ + RTREQPOOLSTAT_NS_AVERAGE_REQ_PROCESSING, + /** Average time the requests had to wait in the queue before being + * scheduled. */ + RTREQPOOLSTAT_NS_AVERAGE_REQ_QUEUED, + /** The end of the valid statistics value names. */ + RTREQPOOLSTAT_END, + /** Blow the type up to 32-bit. */ + RTREQPOOLSTAT_32BIT_HACK = 0x7fffffff +} RTREQPOOLSTAT; + +/** + * Reads a statistics value from the request thread pool. + * + * @returns The value, UINT64_MAX if an invalid parameter was given. + * @param hPool The request thread pool handle. + * @param enmStat The statistics value to get. + */ +RTDECL(uint64_t) RTReqPoolGetStat(RTREQPOOL hPool, RTREQPOOLSTAT enmStat); + +/** + * Allocates a request packet. + * + * This is mostly for internal use, please use the convenience methods. + * + * @returns IPRT status code. + * + * @param hPool The request thread pool handle. + * @param enmType Package type. + * @param phReq Where to store the handle to the new request. + */ +RTDECL(int) RTReqPoolAlloc(RTREQPOOL hPool, RTREQTYPE enmType, PRTREQ *phReq); + +/** + * Calls a function on a worker thread. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param cMillies The number of milliseconds to wait for the request + * to be processed. + * @param phReq Where to store the pointer to the request. Optional + * when RTREQFLAGS_NO_WAIT is used. + * This variable will be set to NIL or a valid request + * handle no matter what happens. + * @param fFlags A combination of RTREQFLAGS values. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. + * @param cArgs The number of arguments in the ellipsis. + * @param ... Arguments. + * + * @remarks The function better avoid taking uint64_t and structs as part of the + * arguments (use pointers to these instead). In general anything + * that's larger than an uintptr_t is problematic. + */ +RTDECL(int) RTReqPoolCallEx(RTREQPOOL hPool, RTMSINTERVAL cMillies, PRTREQ *phReq, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...); + + +/** + * Calls a function on a worker thread. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param cMillies The number of milliseconds to wait for the request + * to be processed. + * @param phReq Where to store the pointer to the request. Optional + * when RTREQFLAGS_NO_WAIT is used. + * This variable will be set to NIL or a valid request + * handle no matter what happens. + * @param fFlags A combination of RTREQFLAGS values. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. + * @param cArgs The number of arguments in the variable argument + * list. + * @param va Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallExV(RTREQPOOL hPool, RTMSINTERVAL cMillies, PRTREQ *phReq, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list va); + +/** + * Calls a function on a worker thread, wait for it to return. + * + * @returns IPRT status code returned by @a pfnFunction or request pool error. + * @param hPool The request thread pool handle. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. The + * function must return an int value compatible with + * the IPRT status code convention. + * @param cArgs The number of arguments in the elipsis. + * @param ... Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallWait(RTREQPOOL hPool, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Calls a function on a worker thread, don't wait for it to return. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. The + * function should return an int value compatible with + * the IPRT status code convention, thought it's not + * all that important as it's thrown away. + * @param cArgs The number of arguments in the elipsis. + * @param ... Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallNoWait(RTREQPOOL hPool, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Calls a void function on a worker thread. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. The + * function is taken to return void. + * @param cArgs The number of arguments in the elipsis. + * @param ... Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallVoidWait(RTREQPOOL hPool, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Call a void function on a worker thread, don't wait for it to return. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. The + * function is taken to return void. + * @param cArgs The number of arguments in the elipsis. + * @param ... Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallVoidNoWait(RTREQPOOL hPool, PFNRT pfnFunction, unsigned cArgs, ...); + + +/** + * Retains a reference to a request. + * + * @returns The new reference count, UINT32_MAX on invalid handle (asserted). + * @param hReq The request handle. + */ +RTDECL(uint32_t) RTReqRetain(PRTREQ hReq); + +/** + * Releases a reference to the request. + * + * When the reference count reaches zero, the request will be pooled for reuse. + * + * @returns The new reference count, UINT32_MAX on invalid handle (asserted). + * @param hReq Package to release. + */ +RTDECL(uint32_t) RTReqRelease(PRTREQ hReq); + +/** + * Queues a request. + * + * The request must be allocated using RTReqQueueAlloc() or RTReqPoolAlloc() and + * contain all the required data. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param pReq The request to queue. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + */ +RTDECL(int) RTReqSubmit(PRTREQ pReq, RTMSINTERVAL cMillies); + +/** + * Cancels a pending request. + * + * @returns IPRT status code. + * @retval VERR_RT_REQUEST_STATE if the request is not cancellable. + * + * @param hReq The request to cancel. + */ +RTDECL(int) RTReqCancel(PRTREQ hReq); + +/** + * Waits for a request to be completed. + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param pReq The request to wait for. + * @param cMillies Number of milliseconds to wait. + * Use RT_INDEFINITE_WAIT to only wait till it's completed. + */ +RTDECL(int) RTReqWait(PRTREQ pReq, RTMSINTERVAL cMillies); + +/** + * Gets the status of the request. + * + * @returns IPRT status code. + * + * @param pReq The request to get the status for. + */ +RTDECL(int) RTReqGetStatus(PRTREQ pReq); + +#endif /* IN_RING3 */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_req_h */ + diff --git a/include/iprt/runtime-loader.h b/include/iprt/runtime-loader.h new file mode 100644 index 00000000..3892ffcf --- /dev/null +++ b/include/iprt/runtime-loader.h @@ -0,0 +1,189 @@ +/** @file + * IPRT - Runtime Loader Generation. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include +#ifdef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +# include +# include +# include +#endif + +/** @defgroup grp_rt_runtime_loader Runtime Loader Generation + * @ingroup grp_rt + * + * How to use this loader generator + * + * This loader generator can be used to generate stub code for loading a shared + * library and its functions at runtime, or for generating a header file with + * the declaration of the loader function and optionally declarations for the + * functions loaded. It should be included in a header file or a C source + * file, after defining certain macros which it makes use of. + * + * To generate the C source code for function proxy stubs and the library + * loader function, you should define the following macros in your source file + * before including this header: + * + * RT_RUNTIME_LOADER_LIB_NAME - the file name of the library to load + * RT_RUNTIME_LOADER_FUNCTION - the name of the loader function + * RT_RUNTIME_LOADER_INSERT_SYMBOLS - a macro containing the names of the + * functions to be loaded, defined in the + * following pattern: + * @code + * #define RT_RUNTIME_LOADER_INSERT_SYMBOLS \ + * RT_PROXY_STUB(func_name, ret_type, (long_param_list), (short_param_list)) \ + * RT_PROXY_STUB(func_name2, ret_type2, (long_param_list2), (short_param_list2)) \ + * ... + * @endcode + * + * where long_param_list is a parameter list for declaring the function of the + * form (type1 arg1, type2 arg2, ...) and short_param_list for calling it, of + * the form (arg1, arg2, ...). + * + * To generate the header file, you should define RT_RUNTIME_LOADER_FUNCTION + * and if you wish to generate declarations for the functions you should + * additionally define RT_RUNTIME_LOADER_INSERT_SYMBOLS as above and + * RT_RUNTIME_LOADER_GENERATE_DECLS (without a value) before including this + * file. + * + * @{ + */ +/** @todo this is far too complicated. A script for generating the files would + * probably be preferable. + * + * bird> An alternative is to generate assembly jump wrappers, this only + * requires the symbol names and prefix. I've done this ages ago when we forked + * the EMX/GCC toolchain on OS/2... It's a wee bit more annoying in x86 PIC/PIE + * mode, but nothing that cannot be dealt with. + */ +/** @todo r=bird: The use of RTR3DECL here is an unresolved issue. */ +/** @todo r=bird: The lack of RT_C_DECLS_BEGIN/END is an unresolved issue. Here + * we'll get into trouble if we use the same symbol names as the + * original! */ +/** @todo r=bird: The prefix usage here is very confused: RT_RUNTIME_LOADER_XXX, + * RT_PROXY_STUB, etc. */ + +#ifdef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS + +/* The following are the symbols which we need from the library. */ +# define RT_PROXY_STUB(function, rettype, signature, shortsig) \ + void (*function ## _fn)(void); \ + RTR3DECL(rettype) function signature \ + { return ( (rettype (*) signature) function ## _fn ) shortsig; } + +RT_RUNTIME_LOADER_INSERT_SYMBOLS + +# undef RT_PROXY_STUB + +/* Now comes a table of functions to be loaded from the library. */ +typedef struct +{ + const char *pszName; + void (**ppfn)(void); +} RTLDRSHAREDFUNC; + +# define RT_PROXY_STUB(s, dummy1, dummy2, dummy3 ) { #s , & s ## _fn } , +static RTLDRSHAREDFUNC g_aSharedFuncs[] = +{ + RT_RUNTIME_LOADER_INSERT_SYMBOLS + { NULL, NULL } +}; +# undef RT_PROXY_STUB + +/** + * The function which does the actual work for RT_RUNTIME_LOADER_FUNCTION, + * serialised for thread safety. + */ +static DECLCALLBACK(int) rtldrLoadOnce(void *) +{ + RTLDRMOD hLib; + int rc; + + LogFlowFunc(("\n")); + rc = RTLdrLoadEx(RT_RUNTIME_LOADER_LIB_NAME, &hLib, RTLDRLOAD_FLAGS_LOCAL | RTLDRLOAD_FLAGS_NO_UNLOAD, NULL); + for (unsigned i = 0; RT_SUCCESS(rc) && g_aSharedFuncs[i].pszName != NULL; ++i) + rc = RTLdrGetSymbol(hLib, g_aSharedFuncs[i].pszName, (void **)g_aSharedFuncs[i].ppfn); + LogFlowFunc(("rc = %Rrc\n", rc)); + + return rc; +} + +/** + * Load the shared library RT_RUNTIME_LOADER_LIB_NAME and resolve the symbols + * pointed to by RT_RUNTIME_LOADER_INSERT_SYMBOLS. + * + * May safely be called from multiple threads and will not return until the + * library is loaded or has failed to load. + * + * @returns IPRT status code. + */ +RTR3DECL(int) RT_RUNTIME_LOADER_FUNCTION(void) +{ + static RTONCE s_Once = RTONCE_INITIALIZER; + int rc; + + LogFlowFunc(("\n")); + rc = RTOnce(&s_Once, rtldrLoadOnce, NULL); + LogFlowFunc(("rc = %Rrc\n", rc)); + + return rc; +} + +#elif defined(RT_RUNTIME_LOADER_GENERATE_HEADER) +# ifdef RT_RUNTIME_LOADER_GENERATE_DECLS +/* Declarations of the functions that we need from + * RT_RUNTIME_LOADER_LIB_NAME */ +# define RT_PROXY_STUB(function, rettype, signature, shortsig) \ + RTR3DECL(rettype) function signature ; + +RT_RUNTIME_LOADER_INSERT_SYMBOLS + +# undef RT_PROXY_STUB +# endif /* RT_RUNTIME_LOADER_GENERATE_DECLS */ + +/** + * Try to dynamically load the library. This function should be called before + * attempting to use any of the library functions. It is safe to call this + * function multiple times. + * + * @returns iprt status code + */ +RTR3DECL(int) RT_RUNTIME_LOADER_FUNCTION(void); + +#else +# error "One of RT_RUNTIME_LOADER_GENERATE_HEADER or RT_RUNTIME_LOADER_GENERATE_BODY_STUBS must be defined when including this file" +#endif + +/** @} */ + diff --git a/include/iprt/runtime.h b/include/iprt/runtime.h new file mode 100644 index 00000000..5d2ddc5d --- /dev/null +++ b/include/iprt/runtime.h @@ -0,0 +1,99 @@ +/** @file + * IPRT - Include Everything. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_runtime_h +#define IPRT_INCLUDED_runtime_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +#if !defined(IN_RC) && !defined(IN_RING0_AGNOSTIC) +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#ifndef IN_RC +# include +# include +#endif +#include +#include +#include +#include +#ifndef IN_RC +# include +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#ifndef IN_RC +# include +#endif +#include +#include +#include +#include +#include + +#ifdef IN_RING3 +# include +# include +# include +# include /** @todo iprt/alloca.h should be made available in R0 and GC too! */ +# include /** @todo iprt/process.h should be made available in R0 too (partly). */ +#endif + +#ifdef IN_RING0 +# include +#endif + + +#endif /* !IPRT_INCLUDED_runtime_h */ + diff --git a/include/iprt/s3.h b/include/iprt/s3.h new file mode 100644 index 00000000..93c33454 --- /dev/null +++ b/include/iprt/s3.h @@ -0,0 +1,283 @@ +/* $Id: s3.h $ */ +/** @file + * IPRT - Simple Storage Service (S3) Communication API. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_s3_h +#define IPRT_INCLUDED_s3_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_s3 RTS3 - Simple Storage Service (S3) Communication API + * @ingroup grp_rt + * @{ + */ + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** RTS3 interface handle. */ +typedef R3PTRTYPE(struct RTS3INTERNAL *) RTS3; +/** Pointer to a RTS3 interface handle. */ +typedef RTS3 *PRTS3; +/** Nil RTS3 interface handle. */ +#define NIL_RTS3 ((RTS3)0) + + +/** + * S3 progress callback. + * + * @returns Reserved, must be 0. + * + * @param uPercent The process completion percentage. + * @param pvUser The user parameter given to RTS3SetProgressCallback. + */ +typedef DECLCALLBACKTYPE(int, FNRTS3PROGRESS,(unsigned uPercent, void *pvUser)); +/** Pointer to a S3 progress callback. */ +typedef FNRTS3PROGRESS *PFNRTS3PROGRESS; + + +/** Pointer to an S3 bucket entry. */ +typedef struct RTS3BUCKETENTRY *PRTS3BUCKETENTRY; +/** Pointer to a const S3 bucket entry. */ +typedef struct RTS3BUCKETENTRY const *PCRTS3BUCKETENTRY; +/** + * RTS3 bucket entry. + * + * Represent a bucket of the S3 storage server. Bucket entries are chained as a + * doubly linked list using the pPrev & pNext member. + * + * @todo Consider making the entire list const unless there are plans for + * more APIs using this structure which requires the caller to create + * or modify it. + */ +typedef struct RTS3BUCKETENTRY +{ + /** The previous element. */ + PRTS3BUCKETENTRY pPrev; + /** The next element. */ + PRTS3BUCKETENTRY pNext; + + /** The name of the bucket. */ + char const *pszName; + /** The creation date of the bucket as string. */ + char const *pszCreationDate; +} RTS3BUCKETENTRY; + + +/** Pointer to an S3 key entry. */ +typedef struct RTS3KEYENTRY *PRTS3KEYENTRY; +/** Pointer to a const S3 key entry. */ +typedef struct RTS3KEYENTRY const *PCRTS3KEYENTRY; +/** + * RTS3 key entry. + * + * Represent a key of the S3 storage server. Key entries are chained as a doubly + * linked list using the pPrev & pNext member. + * + * @todo Consider making the entire list const unless there are plans for + * more APIs using this structure which requires the caller to create + * or modify it. + */ +typedef struct RTS3KEYENTRY +{ + /** The previous element. */ + PRTS3KEYENTRY pPrev; + /** The next element. */ + PRTS3KEYENTRY pNext; + + /** The name of the key. */ + char const *pszName; + /** The date this key was last modified as string. */ + char const *pszLastModified; + /** The size of the file behind this key in bytes. */ + uint64_t cbFile; +} RTS3KEYENTRY; + + +/** + * Creates a RTS3 interface handle. + * + * @returns iprt status code. + * + * @param phS3 Where to store the RTS3 handle. + * @param pszAccessKey The access key for the S3 storage server. + * @param pszSecretKey The secret access key for the S3 storage server. + * @param pszBaseUrl The base URL of the S3 storage server. + * @param pszUserAgent An optional user agent string used in the HTTP + * communication. + */ +RTR3DECL(int) RTS3Create(PRTS3 phS3, const char *pszAccessKey, const char *pszSecretKey, const char *pszBaseUrl, const char *pszUserAgent); + +/** + * Destroys a RTS3 interface handle. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + */ +RTR3DECL(void) RTS3Destroy(RTS3 hS3); + +/** + * Sets an optional progress callback. + * + * This callback function will be called when the completion percentage of an S3 + * operation changes. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pfnProgressCB The pointer to the progress function. + * @param pvUser The pvUser arg of FNRTS3PROGRESS. + */ +RTR3DECL(void) RTS3SetProgressCallback(RTS3 hS3, PFNRTS3PROGRESS pfnProgressCB, void *pvUser); + +/** + * Gets a list of all available buckets on the S3 storage server. + * + * You have to delete ppBuckets after usage with RTS3BucketsDestroy. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param ppBuckets Where to store the pointer to the head of the + * returned bucket list. Consider the entire list + * read-only. + */ +RTR3DECL(int) RTS3GetBuckets(RTS3 hS3, PCRTS3BUCKETENTRY *ppBuckets); + +/** + * Destroys the bucket list returned by RTS3GetBuckets. + * + * @returns iprt status code. + * + * @param pBuckets Pointer to the first bucket entry. + */ +RTR3DECL(int) RTS3BucketsDestroy(PCRTS3BUCKETENTRY pBuckets); + +/** + * Creates a new bucket on the S3 storage server. + * + * This name have to be unique over all accounts on the S3 storage server. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the new bucket. + */ +RTR3DECL(int) RTS3CreateBucket(RTS3 hS3, const char *pszBucketName); + +/** + * Deletes a bucket on the S3 storage server. + * + * The bucket must be empty. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket to delete. + */ +RTR3DECL(int) RTS3DeleteBucket(RTS3 hS3, const char *pszBucketName); + +/** + * Gets a list of all available keys in a bucket on the S3 storage server. + * + * You have to delete ppKeys after usage with RTS3KeysDestroy. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket to delete. + * @param ppKeys Where to store the pointer to the head of the + * returned key list. Consider the entire list + * read-only. + */ +RTR3DECL(int) RTS3GetBucketKeys(RTS3 hS3, const char *pszBucketName, PCRTS3KEYENTRY *ppKeys); + +/** + * Delete the key list returned by RTS3GetBucketKeys. + * + * @returns iprt status code. + * + * @param pKeys Pointer to the first key entry. + */ +RTR3DECL(int) RTS3KeysDestroy(PCRTS3KEYENTRY pKeys); + +/** + * Deletes a key in a bucket on the S3 storage server. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket contains pszKeyName. + * @param pszKeyName Name of the key to delete. + */ +RTR3DECL(int) RTS3DeleteKey(RTS3 hS3, const char *pszBucketName, const char *pszKeyName); + +/** + * Downloads a key from a bucket into a file. + * + * The file must not exists. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket that contains pszKeyName. + * @param pszKeyName Name of the key to download. + * @param pszFilename Name of the file to store the downloaded key as. + */ +RTR3DECL(int) RTS3GetKey(RTS3 hS3, const char *pszBucketName, const char *pszKeyName, const char *pszFilename); + +/** + * Uploads the content of a file into a key in the specified bucked. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket where the new key should be + * created. + * @param pszKeyName Name of the new key. + * @param pszFilename Name of the file to upload the content of. + */ +RTR3DECL(int) RTS3PutKey(RTS3 hS3, const char *pszBucketName, const char *pszKeyName, const char *pszFilename); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_s3_h */ + diff --git a/include/iprt/sanitized/intrin.h b/include/iprt/sanitized/intrin.h new file mode 100644 index 00000000..39b5ad32 --- /dev/null +++ b/include/iprt/sanitized/intrin.h @@ -0,0 +1,62 @@ +/** @file + * Safe way to include intrin.h from VC++. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sanitized_intrin_h +#define IPRT_INCLUDED_sanitized_intrin_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* Several incorrect __cplusplus uses. */ +# pragma warning(disable:4255) /* Incorrect __slwpcb prototype. */ +#endif + +/* This is a hack to avoid dragging in malloc.h from UCRT. */ +#if (defined(IPRT_NO_CRT) || defined(RT_OS_AGNOSTIC)) && !defined(_INC_MALLOC) +# define _INC_MALLOC 1 +# include +# undef _INC_MALLOC +#else +# include +#endif + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_sanitized_intrin_h */ + diff --git a/include/iprt/sanitized/iterator b/include/iprt/sanitized/iterator new file mode 100644 index 00000000..b3c78e0c --- /dev/null +++ b/include/iprt/sanitized/iterator @@ -0,0 +1,60 @@ +/** @file + * Safe way to include the 'iterator' header from the C++ library. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sanitized_iterator +#define IPRT_INCLUDED_sanitized_iterator +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the 'iterator' file of VCC141 has trouble with C4091 in -Wall mode (via ios): + * xlocnum(1616): warning C4774: 'sprintf_s' : format string expected in argument 3 is not a string literal + */ +# pragma warning(push) +# if _MSC_VER >= 1910 /*RT_MSC_VER_VC141*/ +# pragma warning(disable:4774) +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_sanitized_iterator */ + diff --git a/include/iprt/sanitized/sstream b/include/iprt/sanitized/sstream new file mode 100644 index 00000000..46da7af5 --- /dev/null +++ b/include/iprt/sanitized/sstream @@ -0,0 +1,62 @@ +/** @file + * Safe way to include the 'sstream' header from the C++ library. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sanitized_sstream +#define IPRT_INCLUDED_sanitized_sstream +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the 'sstream' file of VCC141 has trouble with C4091 in -Wall mode + * because it drags in string.h which causes stuff like: + * xlocnum(1616): warning C4774: 'sprintf_s' : format sstream expected in argument 3 is not a sstream literal + * sstream(530): warning C4774: '_scprintf' : format sstream expected in argument 1 is not a sstream literal + */ +# pragma warning(push) +# if _MSC_VER >= 1910 /*RT_MSC_VER_VC141*/ +# pragma warning(disable:4774) +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_sanitized_sstream */ + diff --git a/include/iprt/sanitized/string b/include/iprt/sanitized/string new file mode 100644 index 00000000..515d2a13 --- /dev/null +++ b/include/iprt/sanitized/string @@ -0,0 +1,61 @@ +/** @file + * Safe way to include the 'string' header from the C++ library. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sanitized_string +#define IPRT_INCLUDED_sanitized_string +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the 'string' file of VCC141 has trouble with C4091 in -Wall mode: + * string(530): warning C4774: '_scprintf' : format string expected in argument 1 is not a string literal + * xlocnum(1616): warning C4774: 'sprintf_s' : format string expected in argument 3 is not a string literal + */ +# pragma warning(push) +# if _MSC_VER >= 1910 /*RT_MSC_VER_VC141*/ +# pragma warning(disable:4774) +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_sanitized_string */ + diff --git a/include/iprt/semaphore.h b/include/iprt/semaphore.h new file mode 100644 index 00000000..6d3e5f6a --- /dev/null +++ b/include/iprt/semaphore.h @@ -0,0 +1,1450 @@ +/** @file + * IPRT - Semaphore. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_semaphore_h +#define IPRT_INCLUDED_semaphore_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) +# include +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_sems RTSem - Semaphores + * + * This module implements all kinds of event and mutex semaphores; in addition + * to these, IPRT implements "critical sections", which are fast recursive + * mutexes (see @ref grp_rt_critsect ). C++ users may find @ref grp_rt_cpp_lock + * interesting. + * + * @ingroup grp_rt + * @{ + */ + + +/** @name Generic Semaphore Wait Flags. + * + * @remarks Exactly one of RTSEMWAIT_FLAGS_RELATIVE and + * RTSEMWAIT_FLAGS_ABSOLUTE must be set, unless + * RTSEMWAIT_FLAGS_INDEFINITE is used. + * + * Exactly one of RTSEMWAIT_FLAGS_NANOSECS and + * RTSEMWAIT_FLAGS_MILLISECS must be set, unless + * RTSEMWAIT_FLAGS_INDEFINITE is used. + * + * Exactly one of RTSEMWAIT_FLAGS_RESUME and RTSEMWAIT_FLAGS_NORESUME + * must be set. + * + * The interruptible vs resume stuff is ring-0 vs ring-3 semantics. + * + * @{ */ +/** The timeout is relative. */ +#define RTSEMWAIT_FLAGS_RELATIVE RT_BIT_32(0) +/** The timeout is absolute. */ +#define RTSEMWAIT_FLAGS_ABSOLUTE RT_BIT_32(1) +/** The timeout is specified in nanoseconds. */ +#define RTSEMWAIT_FLAGS_NANOSECS RT_BIT_32(2) +/** The timeout is specified in milliseconds. */ +#define RTSEMWAIT_FLAGS_MILLISECS RT_BIT_32(3) +/** Indefinite wait. + * The relative/absolute and nano-/millisecond flags are ignored. */ +#define RTSEMWAIT_FLAGS_INDEFINITE RT_BIT_32(4) +/** Mask covering the time related bits. */ +#define RTSEMWAIT_FLAGS_TIME_MASK UINT32_C(0x0000001f) + +/** Interruptible wait. */ +#define RTSEMWAIT_FLAGS_INTERRUPTIBLE RT_BIT_32(5) +/** No automatic resume, same as interruptible. */ +#define RTSEMWAIT_FLAGS_NORESUME RTSEMWAIT_FLAGS_INTERRUPTIBLE +/** Uninterruptible wait. */ +#define RTSEMWAIT_FLAGS_UNINTERRUPTIBLE RT_BIT_32(6) +/** Resume on interrupt, same as uninterruptible. */ +#define RTSEMWAIT_FLAGS_RESUME RTSEMWAIT_FLAGS_UNINTERRUPTIBLE + +/** Macro for validate the flags. */ +#define RTSEMWAIT_FLAGS_ARE_VALID(fFlags) \ + ( !((fFlags) & UINT32_C(0xffffff80)) \ + && ( ((fFlags) & RTSEMWAIT_FLAGS_INDEFINITE) \ + ? ( (((fFlags) & UINT32_C(0x20))) ^ (((fFlags) >> 1) & UINT32_C(0x20)) ) == UINT32_C(0x20) \ + : ( (((fFlags) & UINT32_C(0x25))) ^ (((fFlags) >> 1) & UINT32_C(0x25)) ) == UINT32_C(0x25) )) +/** @} */ + + + +/** @defgroup grp_rt_sems_event RTSemEvent - Single Release Event Semaphores + * + * Event semaphores can be used for inter-thread communication when one thread + * wants to notify another thread that something happened. A thread can block + * ("wait") on an event semaphore until it is signalled by another thread; see + * RTSemEventCreate, RTSemEventSignal and RTSemEventWait. + * + * @{ */ + +/** + * Create an event semaphore. + * + * @returns iprt status code. + * @param phEventSem Where to store the handle to the newly created + * event semaphore. + */ +RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem); + +/** + * Create an event semaphore. + * + * @returns iprt status code. + * @param phEventSem Where to store the handle to the newly created + * event semaphore. + * @param fFlags Flags, any combination of the + * RTSEMEVENT_FLAGS_XXX \#defines. + * @param hClass The class (no reference consumed). Since we + * don't do order checks on event semaphores, the + * use of the class is limited to controlling the + * timeout threshold for deadlock detection. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5); + +/** @name RTSemMutexCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTSEMEVENT_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** Bootstrap hack for use with certain memory allocator locks only! */ +#define RTSEMEVENT_FLAGS_BOOTSTRAP_HACK UINT32_C(0x00000004) +/** @} */ + +/** + * Destroy an event semaphore. + * + * @returns iprt status code. + * @param hEventSem Handle of the event semaphore. NIL_RTSEMEVENT + * is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem); + +/** + * Signal an event semaphore. + * + * The event semaphore will be signaled and automatically reset after exactly + * one thread have successfully returned from RTSemEventWait() after + * waiting/polling on that semaphore. + * + * @returns iprt status code. + * @param hEventSem The event semaphore to signal. + * + * @remarks ring-0: This works when preemption is disabled. However it is + * system specific whether it works in interrupt context or with + * interrupts disabled. + * + * ring-0/Darwin: This works when interrupts are disabled and thereby + * in interrupt context, except it cannot race semaphore destruction as + * the allocator does not work under these circumstances. + */ +RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem); + +/** + * Whether RTSemEventSignal can be safely called w/o risk of preemption. + * + * Checks whether the caller can safely signal a single release semaphore + * without any risk of getting preempted on locks or similar while doing so. + * This also checks whether the context is suitable in general. + * + * @returns true if safe, false if not. + * @remarks Only ring-0. + */ +RTR0DECL(bool) RTSemEventIsSignalSafe(void); + +/** + * Wait for the event semaphore to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hEventSem The event semaphore to wait on. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies); + +/** + * Wait for the event semaphore to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hEventSem The event semaphore to wait on. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies); + +/** + * Extended API for waiting on an event semaphore to be signaled. + * + * @returns IPRT status code. + * @param hEventSem The event semaphore to wait on. + * @param fFlags Combination of RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout); + +/** + * Debug version of RTSemEventWaitEx that tracks the location. + * + * @returns IPRT status code, see RTSemEventWaitEx. + * @param hEventSem The event semaphore to wait on. + * @param fFlags See RTSemEventWaitEx. + * @param uTimeout See RTSemEventWaitEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Gets the best timeout resolution that RTSemEventWaitEx can do. + * + * @returns The resolution in nanoseconds. + */ +RTDECL(uint32_t) RTSemEventGetResolution(void); + +/** + * Sets the signaller thread to one specific thread. + * + * This is only used for validating usage and deadlock detection. When used + * after calls to RTSemEventAddSignaller, the specified thread will be the only + * signalling thread. + * + * @param hEventSem The event semaphore. + * @param hThread The thread that will signal it. Pass + * NIL_RTTHREAD to indicate that there is no + * special signalling thread. + */ +RTDECL(void) RTSemEventSetSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread); + +/** + * To add more signalling threads. + * + * First call RTSemEventSetSignaller then add further threads with this. + * + * @param hEventSem The event semaphore. + * @param hThread The thread that will signal it. NIL_RTTHREAD is + * not accepted. + */ +RTDECL(void) RTSemEventAddSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread); + +/** + * To remove a signalling thread. + * + * Reverts work done by RTSemEventAddSignaller and RTSemEventSetSignaller. + * + * @param hEventSem The event semaphore. + * @param hThread A previously added thread. + */ +RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread); + +/** @} */ + + +/** @defgroup grp_rt_sems_event_multi RTSemEventMulti - Multiple Release Event Semaphores + * + * A variant of @ref grp_rt_sems_event where all threads will be unblocked when + * signalling the semaphore. + * + * @{ */ + +/** + * Creates a multiple release event semaphore. + * + * @returns iprt status code. + * @param phEventMultiSem Where to store the handle to the newly created + * multiple release event semaphore. + */ +RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem); + +/** + * Creates a multiple release event semaphore. + * + * @returns iprt status code. + * @param phEventMultiSem Where to store the handle to the newly created + * multiple release event semaphore. + * @param fFlags Flags, any combination of the + * RTSEMEVENTMULTI_FLAGS_XXX \#defines. + * @param hClass The class (no reference consumed). Since we + * don't do order checks on event semaphores, the + * use of the class is limited to controlling the + * timeout threshold for deadlock detection. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5); + +/** @name RTSemMutexCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** @} */ + +/** + * Destroy an event multi semaphore. + * + * @returns iprt status code. + * @param hEventMultiSem The multiple release event semaphore. NIL is + * quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem); + +/** + * Signal an event multi semaphore. + * + * @returns iprt status code. + * @param hEventMultiSem The multiple release event semaphore. + * + * @remarks ring-0: This works when preemption is disabled. However it is + * system specific whether it works in interrupt context or with + * interrupts disabled. + * + * ring-0/Darwin: This works when interrupts are disabled and thereby + * in interrupt context, except it cannot race semaphore destruction as + * the allocator does not work under these circumstances. + */ +RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem); + +/** + * Whether RTSemEventMultiSignal can be safely called w/o risk of preemption. + * + * Checks whether the caller can safely signal a multiple release semaphore + * without any risk of getting preempted on locks or similar while doing so. + * This also checks whether the context is suitable in general. + * + * @returns true if safe, false if not. + * @remarks Only ring-0. + */ +RTR0DECL(bool) RTSemEventMultiIsSignalSafe(void); + +/** + * Resets an event multi semaphore to non-signaled state. + * + * @returns iprt status code. + * @param hEventMultiSem The multiple release event semaphore. + */ +RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem); + +/** + * Wait for the event multi semaphore to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async + * system event (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hEventMultiSem The multiple release event semaphore. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies); + +/** + * Wait for the event multi semaphore to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hEventMultiSem The multiple release event semaphore. + * @param cMillies Number of milliseconds to wait. + * @todo Rename to RTSemEventMultiWaitIntr since it is mainly for + * ring-0 consumption. + */ +RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies); + +/** + * Extended API for waiting on an event semaphore to be signaled. + * + * @returns IPRT status code. + * @param hEventMultiSem The multiple release event semaphore to wait + * on. + * @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout); + +/** + * Debug version of RTSemEventMultiWaitEx that tracks the location. + + * @returns IPRT status code, see RTSemEventMultiWaitEx. + * @param hEventMultiSem The multiple release event semaphore handle. + * @param fFlags See RTSemEventMultiWaitEx. + * @param uTimeout See RTSemEventMultiWaitEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Gets the best timeout resolution that RTSemEventMultiWaitEx can do. + * + * @returns The resolution in nanoseconds. + */ +RTDECL(uint32_t) RTSemEventMultiGetResolution(void); + +/** + * Sets the signaller thread to one specific thread. + * + * This is only used for validating usage and deadlock detection. When used + * after calls to RTSemEventAddSignaller, the specified thread will be the only + * signalling thread. + * + * @param hEventMultiSem The multiple release event semaphore. + * @param hThread The thread that will signal it. Pass + * NIL_RTTHREAD to indicate that there is no + * special signalling thread. + */ +RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread); + +/** + * To add more signalling threads. + * + * First call RTSemEventSetSignaller then add further threads with this. + * + * @param hEventMultiSem The multiple release event semaphore. + * @param hThread The thread that will signal it. NIL_RTTHREAD is + * not accepted. + */ +RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread); + +/** + * To remove a signalling thread. + * + * Reverts work done by RTSemEventAddSignaller and RTSemEventSetSignaller. + * + * @param hEventMultiSem The multiple release event semaphore. + * @param hThread A previously added thread. + */ +RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread); + +/** @} */ + + +/** @defgroup grp_rt_sems_mutex RTSemMutex - Mutex semaphores. + * + * Mutex semaphores protect a section of code or data to which access must be + * exclusive. Only one thread can hold access to a critical section at one + * time. See RTSemMutexCreate, RTSemMutexRequest and RTSemMutexRelease. + * + * @remarks These are less efficient than "fast mutexes" and "critical + * sections", which IPRT implements as well; see @ref + * grp_rt_sems_fast_mutex and @ref grp_rt_critsect . + * + * @{ */ + +/** + * Create a mutex semaphore. + * + * @returns iprt status code. + * @param phMutexSem Where to store the mutex semaphore handle. + */ +RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem); + +/** + * Creates a read/write semaphore. + * + * @returns iprt status code. + * @param phMutexSem Where to store the handle to the newly created + * mutex semaphore. + * @param fFlags Flags, any combination of the + * RTSEMMUTEX_FLAGS_XXX \#defines. + * @param hClass The class (no reference consumed). If NIL, no + * lock order validation will be performed on this + * lock. + * @param uSubClass The sub-class. This is used to define lock + * order within a class. RTLOCKVAL_SUB_CLASS_NONE + * is the recommended value here. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); + +/** @name RTSemMutexCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTSEMMUTEX_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** @} */ + + +/** + * Destroy a mutex semaphore. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to destroy. NIL is quietly + * ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem); + +/** + * Changes the lock validator sub-class of the mutex semaphore. + * + * It is recommended to try make sure that nobody is using this semaphore while + * changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param hMutexSem The handle to the mutex semaphore. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTSemMutexSetSubClass(RTSEMMUTEX hMutexSem, uint32_t uSubClass); + +/** + * Request ownership of a mutex semaphore, resume on interruption. + * + * This function will resume if the wait is interrupted by an async + * system event (like a unix signal) or similar. + * + * The same thread may request a mutex semaphore multiple times, + * a nested counter is kept to make sure it's released on the right + * RTSemMutexRelease() call. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies); + +/** + * Request ownership of a mutex semaphore, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * The same thread may request a mutex semaphore multiple times, + * a nested counter is kept to make sure it's released on the right + * RTSemMutexRelease() call. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies); + +/** + * Debug version of RTSemMutexRequest that tracks the location. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Debug version of RTSemMutexRequestNoResume that tracks the location. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Request ownership of a mutex semaphore, extended edition. + * + * The same thread may request a mutex semaphore multiple times, + * a nested counter is kept to make sure it's released on the right + * RTSemMutexRelease() call. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemMutexRequestEx(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout); + +/** + * Debug version of RTSemMutexRequestEx that tracks the location. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param fFlags See RTSemMutexRequestEx. + * @param uTimeout See RTSemMutexRequestEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemMutexRequestExDebug(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Release the ownership of a mutex semaphore. + * + * @returns iprt status code. + * @param hMutexSem The mutex to release the ownership of. It goes + * without saying the the calling thread must own + * it. + */ +RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem); + +/** + * Checks if the mutex semaphore is owned or not. + * + * @returns true if owned, false if not. + * @param hMutexSem The mutex semaphore. + */ +RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem); + +/* Strict build: Remap the two request calls to the debug versions. */ +#if defined(RT_STRICT) && !defined(RTSEMMUTEX_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# ifdef IPRT_INCLUDED_asm_h +# define RTSemMutexRequest(hMutexSem, cMillies) RTSemMutexRequestDebug((hMutexSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemMutexRequestNoResume(hMutexSem, cMillies) RTSemMutexRequestNoResumeDebug((hMutexSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemMutexRequestEx(hMutexSem, fFlags, uTimeout) RTSemMutexRequestExDebug((hMutexSem), (fFlags), (uTimeout), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define RTSemMutexRequest(hMutexSem, cMillies) RTSemMutexRequestDebug((hMutexSem), (cMillies), 0, RT_SRC_POS) +# define RTSemMutexRequestNoResume(hMutexSem, cMillies) RTSemMutexRequestNoResumeDebug((hMutexSem), (cMillies), 0, RT_SRC_POS) +# define RTSemMutexRequestEx(hMutexSem, fFlags, uTimeout) RTSemMutexRequestExDebug((hMutexSem), (fFlags), (uTimeout), 0, RT_SRC_POS) +# endif +#endif + +/* Strict lock order: Automatically classify locks by init location. */ +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTSEMMUTEX_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# define RTSemMutexCreate(phMutexSem) \ + RTSemMutexCreateEx((phMutexSem), 0 /*fFlags*/, \ + RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ + RTLOCKVAL_SUB_CLASS_NONE, NULL) +#endif + +/** @} */ + + +/** @defgroup grp_rt_sems_fast_mutex RTSemFastMutex - Fast Mutex Semaphores + * + * Fast mutexes work like regular mutexes in that they allow only a single + * thread access to a critical piece of code or data. As opposed to mutexes, + * they require no syscall if the fast mutex is not held (like critical + * sections). Unlike critical sections however, they are *not* recursive. + * + * @remarks The fast mutexes has sideeffects on IRQL on Windows hosts. So use + * with care and test on windows with the driver verifier enabled. + * + * @{ */ + +/** + * Create a fast mutex semaphore. + * + * @returns iprt status code. + * @param phFastMtx Where to store the handle to the newly created + * fast mutex semaphore. + * + * @remarks Fast mutex semaphores are not recursive. + */ +RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx); + +/** + * Destroy a fast mutex semaphore. + * + * @returns iprt status code. + * @param hFastMtx Handle to the fast mutex semaphore. NIL is + * quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx); + +/** + * Request ownership of a fast mutex semaphore. + * + * @returns iprt status code. + * @param hFastMtx Handle to the fast mutex semaphore. + */ +RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx); + +/** + * Release the ownership of a fast mutex semaphore. + * + * @returns iprt status code. + * @param hFastMtx Handle to the fast mutex semaphore. It goes + * without saying the the calling thread must own + * it. + */ +RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx); + +/** @} */ + + +/** @defgroup grp_rt_sems_spin_mutex RTSemSpinMutex - Spinning Mutex Semaphores + * + * A very adaptive variant of mutex semaphore that is tailored for the ring-0 + * logger. + * + * @{ */ + +/** + * Creates a spinning mutex semaphore. + * + * @returns iprt status code. + * @retval VERR_INVALID_PARAMETER on invalid flags. + * @retval VERR_NO_MEMORY if out of memory for the semaphore structure and + * handle. + * + * @param phSpinMtx Where to return the handle to the create semaphore. + * @param fFlags Flags, see RTSEMSPINMUTEX_FLAGS_XXX. + */ +RTDECL(int) RTSemSpinMutexCreate(PRTSEMSPINMUTEX phSpinMtx, uint32_t fFlags); + +/** @name RTSemSpinMutexCreate flags. + * @{ */ +/** Always take the semaphore in a IRQ safe way. + * (In plain words: always disable interrupts.) */ +#define RTSEMSPINMUTEX_FLAGS_IRQ_SAFE RT_BIT_32(0) +/** Mask of valid flags. */ +#define RTSEMSPINMUTEX_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Destroys a spinning mutex semaphore. + * + * @returns iprt status code. + * @retval VERR_INVALID_HANDLE (or crash) if the handle is invalid. (NIL will + * not cause this status.) + * + * @param hSpinMtx The semaphore handle. NIL_RTSEMSPINMUTEX is ignored + * quietly (VINF_SUCCESS). + */ +RTDECL(int) RTSemSpinMutexDestroy(RTSEMSPINMUTEX hSpinMtx); + +/** + * Request the spinning mutex semaphore. + * + * This may block if the context we're called in allows this. If not it will + * spin. If called in an interrupt context, we will only spin if the current + * owner isn't interrupted. Also, on some systems it is not always possible to + * wake up blocking threads in all contexts, so, which will either be indicated + * by returning VERR_SEM_BAD_CONTEXT or by temporarily switching the semaphore + * into pure spinlock state. + * + * Preemption will be disabled upon return. IRQs may also be disabled. + * + * @returns iprt status code. + * @retval VERR_SEM_BAD_CONTEXT if the context it's called in isn't suitable + * for releasing it if someone is sleeping on it. + * @retval VERR_SEM_DESTROYED if destroyed. + * @retval VERR_SEM_NESTED if held by the caller. Asserted. + * @retval VERR_INVALID_HANDLE if the handle is invalid. Asserted + * + * @param hSpinMtx The semaphore handle. + */ +RTDECL(int) RTSemSpinMutexRequest(RTSEMSPINMUTEX hSpinMtx); + +/** + * Like RTSemSpinMutexRequest but it won't block or spin if the semaphore is + * held by someone else. + * + * @returns iprt status code. + * @retval VERR_SEM_BUSY if held by someone else. + * @retval VERR_SEM_DESTROYED if destroyed. + * @retval VERR_SEM_NESTED if held by the caller. Asserted. + * @retval VERR_INVALID_HANDLE if the handle is invalid. Asserted + * + * @param hSpinMtx The semaphore handle. + */ +RTDECL(int) RTSemSpinMutexTryRequest(RTSEMSPINMUTEX hSpinMtx); + +/** + * Releases the semaphore previously acquired by RTSemSpinMutexRequest or + * RTSemSpinMutexTryRequest. + * + * @returns iprt status code. + * @retval VERR_SEM_DESTROYED if destroyed. + * @retval VERR_NOT_OWNER if not owner. Asserted. + * @retval VERR_INVALID_HANDLE if the handle is invalid. Asserted. + * + * @param hSpinMtx The semaphore handle. + */ +RTDECL(int) RTSemSpinMutexRelease(RTSEMSPINMUTEX hSpinMtx); + +/** @} */ + + +/** @defgroup grp_rt_sem_rw RTSemRW - Read / Write Semaphores + * + * Read/write semaphores are a fancier version of mutexes in that they grant + * read access to the protected data to several threads at the same time but + * allow only one writer at a time. This can make code scale better at the + * expense of slightly more overhead in mutex management. + * + * @{ */ + +/** + * Creates a read/write semaphore. + * + * @returns iprt status code. + * @param phRWSem Where to store the handle to the newly created + * RW semaphore. + */ +RTDECL(int) RTSemRWCreate(PRTSEMRW phRWSem); + +/** + * Creates a read/write semaphore. + * + * @returns iprt status code. + * @param phRWSem Where to store the handle to the newly created + * RW semaphore. + * @param fFlags Flags, any combination of the RTSEMRW_FLAGS_XXX + * \#defines. + * @param hClass The class (no reference consumed). If NIL, no + * lock order validation will be performed on this + * lock. + * @param uSubClass The sub-class. This is used to define lock + * order within a class. RTLOCKVAL_SUB_CLASS_NONE + * is the recommended value here. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTSemRWCreateEx(PRTSEMRW phRWSem, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); + +/** @name RTSemRWCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTSEMRW_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** @} */ + +/** + * Destroys a read/write semaphore. + * + * @returns iprt status code. + * @param hRWSem Handle to the read/write semaphore. NIL is + * quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemRWDestroy(RTSEMRW hRWSem); + +/** + * Changes the lock validator sub-class of the read/write semaphore. + * + * It is recommended to try make sure that nobody is using this semaphore while + * changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param hRWSem Handle to the read/write semaphore. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTSemRWSetSubClass(RTSEMRW hRWSem, uint32_t uSubClass); + +/** + * Request read access to a read/write semaphore, resume on interruption + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemRWRequestRead(RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Request read access to a read/write semaphore, return on interruption + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Debug version of RTSemRWRequestRead that tracks the location. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestReadDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Debug version of RTSemRWRequestWriteNoResume that tracks the location. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestReadNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Request read access to a read/write semaphore, extended edition. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_TIMEOUT if the wait timed out. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemRWRequestReadEx(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout); + + +/** + * Debug version of RTSemRWRequestReadEx that tracks the location. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_TIMEOUT if the wait timed out. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param fFlags See RTSemRWRequestReadEx. + * @param uTimeout See RTSemRWRequestReadEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestReadExDebug(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Release read access to a read/write semaphore. + * + * @returns iprt status code. + * @param hRWSem Handle to the read/write semaphore. It goes + * without saying that caller must own read + * privileges to the semaphore. + */ +RTDECL(int) RTSemRWReleaseRead(RTSEMRW hRWSem); + +/** + * Request write access to a read/write semaphore, resume on interruption. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_DEADLOCK if the caller owned the read lock. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemRWRequestWrite(RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Request write access to a read/write semaphore, return on interruption. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_DEADLOCK if the caller owned the read lock. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Debug version of RTSemRWRequestWrite that tracks the location. + * + * @returns IPRT status code, see RTSemRWRequestWrite. + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Debug version of RTSemRWRequestWriteNoResume that tracks the location. + * + * @returns IPRT status code, see RTSemRWRequestWriteNoResume. + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Request write access to a read/write semaphore, extended edition. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPTED if the wait was interrupted. + * @retval VERR_TIMEOUT if the wait timed out. + * @retval VERR_DEADLOCK if the caller owned the read lock. Do not depend on + * this as it is implementation specific. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemRWRequestWriteEx(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout); + +/** + * Debug version of RTSemRWRequestWriteEx that tracks the location. + * + * @returns IPRT status code, see RTSemRWRequestWriteEx. + * @param hRWSem Handle to the read/write semaphore. + * @param fFlags See RTSemRWRequestWriteEx. + * @param uTimeout See RTSemRWRequestWriteEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestWriteExDebug(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Release write access to a read/write semaphore. + * + * @returns iprt status code. + * @param hRWSem Handle to the read/write semaphore. Goes + * without saying that caller must have write + * access to the semaphore. + */ +RTDECL(int) RTSemRWReleaseWrite(RTSEMRW hRWSem); + +/** + * Checks if the caller is the exclusive semaphore owner. + * + * @returns true / false accoringly. + * @param hRWSem Handle to the read/write semaphore. + */ +RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW hRWSem); + +/** + * Checks if the caller is one of the read owners of the semaphore. + * + * @note !CAUTION! This API doesn't work reliably if lock validation isn't + * enabled. Meaning, the answer is not trustworhty unless + * RT_LOCK_STRICT or RTSEMRW_STRICT was defined at build time. Also, + * make sure you do not use RTSEMRW_FLAGS_NO_LOCK_VAL when creating + * the semaphore. And finally, if you used a locking class, don't + * disable deadlock detection by setting cMsMinDeadlock to + * RT_INDEFINITE_WAIT. + * + * In short, only use this for assertions. + * + * @returns true if reader, false if not. + * @param hRWSem Handle to the read/write semaphore. + * @param fWannaHear What you'd like to hear when lock validation is + * not available. (For avoiding asserting all over + * the place.) + */ +RTDECL(bool) RTSemRWIsReadOwner(RTSEMRW hRWSem, bool fWannaHear); + +/** + * Gets the write recursion count. + * + * @returns The write recursion count (0 if bad semaphore handle). + * @param hRWSem Handle to the read/write semaphore. + */ +RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW hRWSem); + +/** + * Gets the read recursion count of the current writer. + * + * @returns The read recursion count (0 if bad semaphore handle). + * @param hRWSem Handle to the read/write semaphore. + */ +RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW hRWSem); + +/** + * Gets the current number of reads. + * + * This includes all read recursions, so it might be higher than the number of + * read owners. It does not include reads done by the current writer. + * + * @returns The read count (0 if bad semaphore handle). + * @param hRWSem Handle to the read/write semaphore. + */ +RTDECL(uint32_t) RTSemRWGetReadCount(RTSEMRW hRWSem); + +/* Strict build: Remap the four request calls to the debug versions. */ +#if defined(RT_STRICT) && !defined(RTSEMRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# ifdef IPRT_INCLUDED_asm_h +# define RTSemRWRequestRead(hRWSem, cMillies) RTSemRWRequestReadDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemRWRequestReadNoResume(hRWSem, cMillies) RTSemRWRequestReadNoResumeDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemRWRequestWrite(hRWSem, cMillies) RTSemRWRequestWriteDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemRWRequestWriteNoResume(hRWSem, cMillies) RTSemRWRequestWriteNoResumeDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemRWRequestWriteEx(hRWSem, fFlags, uTimeout) RTSemRWRequestWriteExDebug((hRWSem), (fFlags), (uTimeout), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define RTSemRWRequestRead(hRWSem, cMillies) RTSemRWRequestReadDebug((hRWSem), (cMillies), 0, RT_SRC_POS) +# define RTSemRWRequestReadNoResume(hRWSem, cMillies) RTSemRWRequestReadNoResumeDebug((hRWSem), (cMillies), 0, RT_SRC_POS) +# define RTSemRWRequestWrite(hRWSem, cMillies) RTSemRWRequestWriteDebug((hRWSem), (cMillies), 0, RT_SRC_POS) +# define RTSemRWRequestWriteNoResume(hRWSem, cMillies) RTSemRWRequestWriteNoResumeDebug((hRWSem), (cMillies), 0, RT_SRC_POS) +# define RTSemRWRequestWriteEx(hRWSem, fFlags, uTimeout) RTSemRWRequestWriteExDebug((hRWSem), (fFlags), (uTimeout), 0, RT_SRC_POS) +# endif +#endif + +/* Strict lock order: Automatically classify locks by init location. */ +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTSEMRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# define RTSemRWCreate(phSemRW) \ + RTSemRWCreateEx((phSemRW), 0 /*fFlags*/, \ + RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ + RTLOCKVAL_SUB_CLASS_NONE, NULL) +#endif + +/** @} */ + + +/** @defgroup grp_rt_sems_pingpong RTSemPingPong - Ping-Pong Construct + * + * Serialization of a two way communication. + * + * @{ */ + +/** + * Ping-pong speaker + */ +typedef enum RTPINGPONGSPEAKER +{ + /** Not initialized. */ + RTPINGPONGSPEAKER_UNINITIALIZE = 0, + /** Ping is speaking, Pong is waiting. */ + RTPINGPONGSPEAKER_PING, + /** Pong is signaled, Ping is waiting. */ + RTPINGPONGSPEAKER_PONG_SIGNALED, + /** Pong is speaking, Ping is waiting. */ + RTPINGPONGSPEAKER_PONG, + /** Ping is signaled, Pong is waiting. */ + RTPINGPONGSPEAKER_PING_SIGNALED, + /** Hack to ensure that it's at least 32-bits wide. */ + RTPINGPONGSPEAKER_HACK = 0x7fffffff +} RTPINGPONGSPEAKER; + +/** + * Ping-Pong construct. + * + * Two threads, one saying Ping and the other saying Pong. The construct + * makes sure they don't speak out of turn and that they can wait and poll + * on the conversation. + */ +typedef struct RTPINGPONG +{ + /** The semaphore the Ping thread waits on. */ + RTSEMEVENT Ping; + /** The semaphore the Pong thread waits on. */ + RTSEMEVENT Pong; + /** The current speaker. */ + volatile RTPINGPONGSPEAKER enmSpeaker; +#if HC_ARCH_BITS == 64 + /** Padding the structure to become a multiple of sizeof(RTHCPTR). */ + uint32_t u32Padding; +#endif +} RTPINGPONG; +/** Pointer to Ping-Pong construct. */ +typedef RTPINGPONG *PRTPINGPONG; + +/** + * Init a Ping-Pong construct. + * + * @returns iprt status code. + * @param pPP Pointer to the ping-pong structure which needs initialization. + */ +RTDECL(int) RTSemPingPongInit(PRTPINGPONG pPP); + +/** + * Deletes a Ping-Pong construct. + * + * @returns iprt status code. + * @param pPP Pointer to the ping-pong structure which is to be destroyed. + * (I.e. put into uninitialized state.) + */ +RTDECL(int) RTSemPingPongDelete(PRTPINGPONG pPP); + +/** + * Signals the pong thread in a ping-pong construct. (I.e. sends ping.) + * This is called by the ping thread. + * + * @returns iprt status code. + * @param pPP Pointer to the ping-pong structure to ping. + */ +RTDECL(int) RTSemPing(PRTPINGPONG pPP); + +/** + * Signals the ping thread in a ping-pong construct. (I.e. sends pong.) + * This is called by the pong thread. + * + * @returns iprt status code. + * @param pPP Pointer to the ping-pong structure to pong. + */ +RTDECL(int) RTSemPong(PRTPINGPONG pPP); + +/** + * Wait function for the ping thread. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param pPP Pointer to the ping-pong structure to wait on. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemPingWait(PRTPINGPONG pPP, RTMSINTERVAL cMillies); + +/** + * Wait function for the pong thread. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param pPP Pointer to the ping-pong structure to wait on. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemPongWait(PRTPINGPONG pPP, RTMSINTERVAL cMillies); + + +/** + * Checks if the pong thread is speaking. + * + * @returns true / false. + * @param pPP Pointer to the ping-pong structure. + * @remark This is NOT the same as !RTSemPongIsSpeaker(). + */ +DECLINLINE(bool) RTSemPingIsSpeaker(PRTPINGPONG pPP) +{ + RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker; + return enmSpeaker == RTPINGPONGSPEAKER_PING; +} + + +/** + * Checks if the pong thread is speaking. + * + * @returns true / false. + * @param pPP Pointer to the ping-pong structure. + * @remark This is NOT the same as !RTSemPingIsSpeaker(). + */ +DECLINLINE(bool) RTSemPongIsSpeaker(PRTPINGPONG pPP) +{ + RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker; + return enmSpeaker == RTPINGPONGSPEAKER_PONG; +} + + +/** + * Checks whether the ping thread should wait. + * + * @returns true / false. + * @param pPP Pointer to the ping-pong structure. + * @remark This is NOT the same as !RTSemPongShouldWait(). + */ +DECLINLINE(bool) RTSemPingShouldWait(PRTPINGPONG pPP) +{ + RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker; + return enmSpeaker == RTPINGPONGSPEAKER_PONG + || enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED + || enmSpeaker == RTPINGPONGSPEAKER_PING_SIGNALED; +} + + +/** + * Checks whether the pong thread should wait. + * + * @returns true / false. + * @param pPP Pointer to the ping-pong structure. + * @remark This is NOT the same as !RTSemPingShouldWait(). + */ +DECLINLINE(bool) RTSemPongShouldWait(PRTPINGPONG pPP) +{ + RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker; + return enmSpeaker == RTPINGPONGSPEAKER_PING + || enmSpeaker == RTPINGPONGSPEAKER_PING_SIGNALED + || enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED; +} + +/** @} */ + + +/** @defgroup grp_rt_sems_xroads RTSemXRoads - Crossroads + * + * The crossroads semaphore is intended to prevent two classes of incompatible + * events from occurring simultaneously, like south/north bound traffic and + * west/east bound traffic at a 4-way junction. + * + * @remarks In order to simplify the implementation, the current flow is always + * given priority. So, it won't work at all well when busy! + * + * @remarks "XRoads" is used as a name because it is briefer than "crossroads" + * and it slightly stresses that is a 4 way crossing to the users of + * American English. + * @{ + */ + +/** + * Creates a crossroads semaphore. + * + * @returns IPRT status code. + * + * @param phXRoads Where to return the handle to the newly created + * crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsCreate(PRTSEMXROADS phXRoads); + +/** + * Destroys a crossroads semaphore. + * + * @returns IPRT status code. + * + * @param hXRoads Handle to the crossroads semaphore that is to be + * destroyed. NIL_RTSEMXROADS is quitetly ignored + * (VINF_SUCCESS). + */ +RTDECL(int) RTSemXRoadsDestroy(RTSEMXROADS hXRoads); + +/** + * Enter the crossroads from the south or north. + * + * (Coupled with RTSemXRoadsNSLeave.) + * + * @returns IPRT status code. + * @param hXRoads Handle to the crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsNSEnter(RTSEMXROADS hXRoads); + +/** + * Leave the crossroads to the north or south. + * + * (Coupled with RTSemXRoadsNSEnter.) + * + * @returns IPRT status code. + * @param hXRoads Handle to the crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsNSLeave(RTSEMXROADS hXRoads); + +/** + * Leave the crossroads from the east or west. + * + * (Coupled with RTSemXRoadsEWLeave.) + * + * @returns IPRT status code. + * @param hXRoads Handle to the crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsEWEnter(RTSEMXROADS hXRoads); + +/** + * Leave the crossroads to the west or east. + * + * (Coupled with RTSemXRoadsEWEnter.) + * + * @returns IPRT status code. + * @param hXRoads Handle to the crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsEWLeave(RTSEMXROADS hXRoads); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_semaphore_h */ + diff --git a/include/iprt/serialport.h b/include/iprt/serialport.h new file mode 100644 index 00000000..25f5fbe5 --- /dev/null +++ b/include/iprt/serialport.h @@ -0,0 +1,377 @@ +/** @file + * IPRT Serial Port API. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_serialport_h +#define IPRT_INCLUDED_serialport_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_serial IPRT Serial Port API + * @ingroup grp_rt + * + * The IPRT serial port API provides a platform independent API to control a + * serial port of the host. It supports receiving/transmitting data as well as + * controlling and monitoring the status lines of a standard serial port. + * + * The user of the API is currently resposible for serializing calls to it. + * The only exception is RTSerialPortEvtPollInterrupt() which can be called on + * any thread to interrupt another thread waiting in RTSerialPortEvtPoll(). + * + * @{ + */ + +/** Serial Port handle. */ +typedef struct RTSERIALPORTINTERNAL *RTSERIALPORT; +/** Pointer to a Serial Port handle. */ +typedef RTSERIALPORT *PRTSERIALPORT; +/** NIL Serial Port handle value. */ +#define NIL_RTSERIALPORT ((RTSERIALPORT)0) + + +/** + * Supported parity settings. + */ +typedef enum RTSERIALPORTPARITY +{ + /** Invalid parity setting. */ + RTSERIALPORTPARITY_INVALID = 0, + /** No parity used. */ + RTSERIALPORTPARITY_NONE, + /** Even parity used. */ + RTSERIALPORTPARITY_EVEN, + /** Odd parity used. */ + RTSERIALPORTPARITY_ODD, + /** Mark parity (parity bit always 1) used. */ + RTSERIALPORTPARITY_MARK, + /** Space parity (parity bit always 0) used. */ + RTSERIALPORTPARITY_SPACE, + /** 32bit hack. */ + RTSERIALPORTPARITY_32BIT_HACK = 0x7fffffff +} RTSERIALPORTPARITY; + + +/** + * Supported data bit count setting. + */ +typedef enum RTSERIALPORTDATABITS +{ + /** Invalid bitcount setting. */ + RTSERIALPORTDATABITS_INVALID = 0, + /** 5 data bits. */ + RTSERIALPORTDATABITS_5BITS, + /** 6 data bits. */ + RTSERIALPORTDATABITS_6BITS, + /** 7 data bits. */ + RTSERIALPORTDATABITS_7BITS, + /** 8 data bits. */ + RTSERIALPORTDATABITS_8BITS, + /** 32bit hack. */ + RTSERIALPORTDATABITS_32BIT_HACK = 0x7fffffff +} RTSERIALPORTDATABITS; + + +/** + * Supported stop bit setting. + */ +typedef enum RTSERIALPORTSTOPBITS +{ + /** Invalid stop bit setting. */ + RTSERIALPORTSTOPBITS_INVALID = 0, + /** One stop bit is used. */ + RTSERIALPORTSTOPBITS_ONE, + /** 1.5 stop bits are used. */ + RTSERIALPORTSTOPBITS_ONEPOINTFIVE, + /** 2 stop bits are used. */ + RTSERIALPORTSTOPBITS_TWO, + /** 32bit hack. */ + RTSERIALPORTSTOPBITS_32BIT_HACK = 0x7fffffff +} RTSERIALPORTSTOPBITS; + + +/** + * Serial port config structure. + */ +typedef struct RTSERIALPORTCFG +{ + /** Baud rate. */ + uint32_t uBaudRate; + /** Used parity. */ + RTSERIALPORTPARITY enmParity; + /** Number of data bits. */ + RTSERIALPORTDATABITS enmDataBitCount; + /** Number of stop bits. */ + RTSERIALPORTSTOPBITS enmStopBitCount; +} RTSERIALPORTCFG; +/** Pointer to a serial port config. */ +typedef RTSERIALPORTCFG *PRTSERIALPORTCFG; +/** Pointer to a const serial port config. */ +typedef const RTSERIALPORTCFG *PCRTSERIALPORTCFG; + + +/** @name RTSerialPortOpen flags + * @{ */ +/** Open the serial port with the receiver enabled to receive data. */ +#define RTSERIALPORT_OPEN_F_READ RT_BIT(0) +/** Open the serial port with the transmitter enabled to transmit data. */ +#define RTSERIALPORT_OPEN_F_WRITE RT_BIT(1) +/** Open the serial port with status line monitoring enabled to get notified about status line changes. */ +#define RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING RT_BIT(2) +/** Open the serial port with BREAK condition detection enabled (Requires extra work on some hosts). */ +#define RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION RT_BIT(3) +/** Open the serial port with loopback mode enabled. */ +#define RTSERIALPORT_OPEN_F_ENABLE_LOOPBACK RT_BIT(4) +/** Bitmask of valid flags. */ +#define RTSERIALPORT_OPEN_F_VALID_MASK UINT32_C(0x0000001f) +/** @} */ + + +/** @name RTSerialPortChgModemLines flags + * @{ */ +/** Change the RTS (Ready To Send) line signal. */ +#define RTSERIALPORT_CHG_STS_LINES_F_RTS RT_BIT(0) +/** Change the DTR (Data Terminal Ready) line signal. */ +#define RTSERIALPORT_CHG_STS_LINES_F_DTR RT_BIT(1) +/** Bitmask of valid flags. */ +#define RTSERIALPORT_CHG_STS_LINES_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + + +/** @name RTSerialPortQueryStatusLines flags + * @{ */ +/** The DCD (Data Carrier Detect) signal is active. */ +#define RTSERIALPORT_STS_LINE_DCD RT_BIT(0) +/** The RI (Ring Indicator) signal is active. */ +#define RTSERIALPORT_STS_LINE_RI RT_BIT(1) +/** The DSR (Data Set Ready) signal is active. */ +#define RTSERIALPORT_STS_LINE_DSR RT_BIT(2) +/** The CTS (Clear To Send) signal is active. */ +#define RTSERIALPORT_STS_LINE_CTS RT_BIT(3) +/** @} */ + + +/** @name RTSerialPortEvtPoll flags + * @{ */ +/** Data was received and can be read. */ +#define RTSERIALPORT_EVT_F_DATA_RX RT_BIT(0) +/** All data was transmitted and there is room again in the transmit buffer. */ +#define RTSERIALPORT_EVT_F_DATA_TX RT_BIT(1) +/** A BREAK condition was detected on the communication channel. + * Only available when BREAK condition detection was enabled when opening the serial port .*/ +#define RTSERIALPORT_EVT_F_BREAK_DETECTED RT_BIT(2) +/** One of the monitored status lines changed, check with RTSerialPortQueryStatusLines(). + * Only available if status line monitoring was enabled when opening the serial port. */ +#define RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED RT_BIT(3) +/** Status line monitor failed with an error and status line monitoring is disabled, + * this cannot be given in the event mask but will be set if status line + * monitoring is enabled and the monitor failed. */ +#define RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED RT_BIT(4) +/** Bitmask of valid flags. */ +#define RTSERIALPORT_EVT_F_VALID_MASK UINT32_C(0x0000001f) +/** @} */ + + +/** + * Opens a serial port with the specified flags. + * + * @returns IPRT status code. + * @param phSerialPort Where to store the IPRT serial port handle on success. + * @param pszPortAddress The address of the serial port (host dependent). + * @param fFlags Flags to open the serial port with, see RTSERIALPORT_OPEN_F_*. + */ +RTDECL(int) RTSerialPortOpen(PRTSERIALPORT phSerialPort, const char *pszPortAddress, uint32_t fFlags); + + +/** + * Closes the given serial port handle. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + */ +RTDECL(int) RTSerialPortClose(RTSERIALPORT hSerialPort); + + +/** + * Gets the native handle for an IPRT serial port handle. + * + * @returns The native handle. -1 on failure. + * @param hSerialPort The IPRT serial port handle. + */ +RTDECL(RTHCINTPTR) RTSerialPortToNative(RTSERIALPORT hSerialPort); + + +/** + * Tries to read the given number of bytes from the serial port, blocking version. + * + * @returns IPRT status code. + * @retval VERR_SERIALPORT_BREAK_DETECTED if a break was detected before the requested number of bytes was received. + * @param hSerialPort The IPRT serial port handle. + * @param pvBuf Where to store the read data. + * @param cbToRead How much to read from the serial port. + * @param pcbRead Where to store the number of bytes received until an error condition occurred, optional. + */ +RTDECL(int) RTSerialPortRead(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead); + + +/** + * Tries to read the given number of bytes from the serial port, non-blocking version. + * + * @returns IPRT status code. + * @retval VERR_SERIALPORT_BREAK_DETECTED if a break was detected before anything could be received. + * @retval VINF_TRY_AGAIN if nothing could be read. + * @param hSerialPort The IPRT serial port handle. + * @param pvBuf Where to store the read data. + * @param cbToRead How much to read from the serial port. + * @param pcbRead Where to store the number of bytes received. + */ +RTDECL(int) RTSerialPortReadNB(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead); + + +/** + * Writes the given data to the serial port, blocking version. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param pvBuf The data to write. + * @param cbToWrite How much to write. + * @param pcbWritten Where to store the number of bytes written until an error condition occurred, optional. + */ +RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + + +/** + * Writes the given data to the serial port, non-blocking version. + * + * @returns IPRT status code. + * @retval VINF_TRY_AGAIN if nothing could be written. + * @param hSerialPort The IPRT serial port handle. + * @param pvBuf The data to write. + * @param cbToWrite How much to write. + * @param pcbWritten Where to store the number of bytes written. + */ +RTDECL(int) RTSerialPortWriteNB(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + + +/** + * Queries the current active serial port config. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param pCfg Where to store the current active config. + */ +RTDECL(int) RTSerialPortCfgQueryCurrent(RTSERIALPORT hSerialPort, PRTSERIALPORTCFG pCfg); + + +/** + * Change the serial port to the given config. + * + * @returns IPRT status code. + * @retval VERR_SERIALPORT_INVALID_BAUDRATE if the baud rate is not supported on the serial port. + * @param hSerialPort The IPRT serial port handle. + * @param pCfg The config to write. + * @param pErrInfo Where to store additional information on error, optional. + */ +RTDECL(int) RTSerialPortCfgSet(RTSERIALPORT hSerialPort, PCRTSERIALPORTCFG pCfg, PRTERRINFO pErrInfo); + + +/** + * Poll for an event on the given serial port. + * + * @returns IPRT status code. + * @retval VERR_TIMEOUT if the timeout was reached before an event happened. + * @retval VERR_INTERRUPTED if another thread interrupted the polling through RTSerialPortEvtPollInterrupt(). + * @param hSerialPort The IPRT serial port handle. + * @param fEvtMask The mask of events to receive, see RTSERIALPORT_EVT_F_* + * @param pfEvtsRecv Where to store the bitmask of events received. + * @param msTimeout Number of milliseconds to wait for an event. + */ +RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, uint32_t fEvtMask, uint32_t *pfEvtsRecv, + RTMSINTERVAL msTimeout); + + +/** + * Interrupt another thread currently polling for an event. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * + * @note Any thread. + */ +RTDECL(int) RTSerialPortEvtPollInterrupt(RTSERIALPORT hSerialPort); + + +/** + * Sets or clears a BREAK condition on the given serial port. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param fSet Flag whether to set the BREAK condition or clear it. + */ +RTDECL(int) RTSerialPortChgBreakCondition(RTSERIALPORT hSerialPort, bool fSet); + + +/** + * Modify the status lines of the given serial port. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param fClear Combination of status lines to clear, see RTSERIALPORT_CHG_STS_LINES_F_*. + * @param fSet Combination of status lines to set, see RTSERIALPORT_CHG_STS_LINES_F_*. + * + * @note fClear takes precedence over fSet in case the same status line bit is set in both arguments. + */ +RTDECL(int) RTSerialPortChgStatusLines(RTSERIALPORT hSerialPort, uint32_t fClear, uint32_t fSet); + + +/** + * Query the status of the status lines on the given serial port. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param pfStsLines Where to store the bitmask of active status lines on success, + * see RTSERIALPORT_STS_LINE_*. + */ +RTDECL(int) RTSerialPortQueryStatusLines(RTSERIALPORT hSerialPort, uint32_t *pfStsLines); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_serialport_h */ + diff --git a/include/iprt/setjmp-without-sigmask.h b/include/iprt/setjmp-without-sigmask.h new file mode 100644 index 00000000..b73bce4c --- /dev/null +++ b/include/iprt/setjmp-without-sigmask.h @@ -0,0 +1,64 @@ +/** @file + * IPRT - setjmp/long without signal mask saving and restoring. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_setjmp_without_sigmask_h +#define IPRT_INCLUDED_setjmp_without_sigmask_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#include + +/* + * System V and ANSI-C setups does not by default map setjmp/longjmp to the + * signal mask saving/restoring variants (Linux included). This is mainly + * an issue on BSD derivatives. + */ +#if defined(IN_RING3) \ + && ( defined(RT_OS_DARWIN) \ + || defined(RT_OS_DRAGONFLY) \ + || defined(RT_OS_FREEBSD) \ + || defined(RT_OS_NETBSD) \ + || defined(RT_OS_OPENBSD) ) +# undef setjmp /* /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/setjmp.h defines it on macOS. */ +# define setjmp _setjmp +# define longjmp _longjmp +#endif + + +#endif /* !IPRT_INCLUDED_setjmp_without_sigmask_h */ + diff --git a/include/iprt/sg.h b/include/iprt/sg.h new file mode 100644 index 00000000..b0831d95 --- /dev/null +++ b/include/iprt/sg.h @@ -0,0 +1,460 @@ +/** @file + * IPRT - S/G buffer handling. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sg_h +#define IPRT_INCLUDED_sg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_sgbuf RTSgBuf - Scatter / Gather Buffers + * @ingroup grp_rt + * @{ + */ + +/** Pointer to a const S/G entry. */ +typedef const struct RTSGBUF *PCRTSGBUF; + +/** + * Callback for RTSgBufCopyToFn() called on every segment of the given S/G buffer. + * + * @returns Number of bytes copied for this segment, a value smaller than cbSrc will stop the copy operation. + * @param pSgBuf The S/G buffer for reference. + * @param pvSrc Where to copy from. + * @param cbSrc The number of bytes in the source buffer. + * @param pvUser Opaque user data passed in RTSgBufCopyToFn(). + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSGBUFCOPYTO, (PCRTSGBUF pSgBuf, const void *pvSrc, size_t cbSrc, void *pvUser)); +/** Pointer to a FNRTSGBUFCOPYTO. */ +typedef FNRTSGBUFCOPYTO *PFNRTSGBUFCOPYTO; + +/** + * Callback for RTSgBufCopyFromFn() called on every segment of the given S/G buffer. + * + * @returns Number of bytes copied for this segment, a value smaller than cbDst will stop the copy operation. + * @param pSgBuf The S/G buffer for reference. + * @param pvDst Where to copy to. + * @param cbDst The number of bytes in the destination buffer. + * @param pvUser Opaque user data passed in RTSgBufCopyFromFn(). + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSGBUFCOPYFROM, (PCRTSGBUF pSgBuf, void *pvDst, size_t cbDst, void *pvUser)); +/** Pointer to a FNRTSGBUFCOPYFROM. */ +typedef FNRTSGBUFCOPYFROM *PFNRTSGBUFCOPYFROM; + +/** + * A S/G entry. + */ +typedef struct RTSGSEG +{ + /** Pointer to the segment buffer. */ + void *pvSeg; + /** Size of the segment buffer. */ + size_t cbSeg; +} RTSGSEG; +/** Pointer to a S/G entry. */ +typedef RTSGSEG *PRTSGSEG; +/** Pointer to a const S/G entry. */ +typedef const RTSGSEG *PCRTSGSEG; +/** Pointer to a S/G entry pointer. */ +typedef PRTSGSEG *PPRTSGSEG; + +/** + * A S/G buffer. + * + * The members should be treated as private. + * + * @warning There is a lot of code, especially in the VFS area of IPRT, that + * totally ignores the idxSeg, pvSegCur and cbSegLeft members! So, + * it is not recommended to pass buffers that aren't fully reset or + * where cbSegLeft is shorter than what paSegs describes. + */ +typedef struct RTSGBUF +{ + /** Pointer to the scatter/gather array. */ + PCRTSGSEG paSegs; + /** Number of segments. */ + unsigned cSegs; + + /** Current segment we are in. */ + unsigned idxSeg; + /** Pointer to current byte within the current segment. */ + void *pvSegCur; + /** Number of bytes left in the current segment. */ + size_t cbSegLeft; +} RTSGBUF; +/** Pointer to a S/G entry. */ +typedef RTSGBUF *PRTSGBUF; +/** Pointer to a S/G entry pointer. */ +typedef PRTSGBUF *PPRTSGBUF; + + +/** + * Sums up the length of all the segments. + * + * @returns The complete segment length. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(size_t) RTSgBufCalcTotalLength(PCRTSGBUF pSgBuf) +{ + size_t cb = 0; + unsigned i = pSgBuf->cSegs; + while (i-- > 0) + cb += pSgBuf->paSegs[i].cbSeg; + return cb; +} + +/** + * Sums up the number of bytes left from the current position. + * + * @returns Number of bytes left. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(size_t) RTSgBufCalcLengthLeft(PCRTSGBUF pSgBuf) +{ + size_t cb = pSgBuf->cbSegLeft; + unsigned i = pSgBuf->cSegs; + while (i-- > pSgBuf->idxSeg + 1) + cb += pSgBuf->paSegs[i].cbSeg; + return cb; +} + +/** + * Checks if the current buffer position is at the start of the first segment. + * + * @returns true / false. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(bool) RTSgBufIsAtStart(PCRTSGBUF pSgBuf) +{ + return pSgBuf->idxSeg == 0 + && ( pSgBuf->cSegs == 0 + || pSgBuf->pvSegCur == pSgBuf->paSegs[0].pvSeg); +} + +/** + * Checks if the current buffer position is at the end of all the segments. + * + * @returns true / false. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(bool) RTSgBufIsAtEnd(PCRTSGBUF pSgBuf) +{ + return pSgBuf->idxSeg > pSgBuf->cSegs + || ( pSgBuf->idxSeg == pSgBuf->cSegs + && pSgBuf->cbSegLeft == 0); +} + +/** + * Checks if the current buffer position is at the start of the current segment. + * + * @returns true / false. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(bool) RTSgBufIsAtStartOfSegment(PCRTSGBUF pSgBuf) +{ + return pSgBuf->idxSeg < pSgBuf->cSegs + && pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg == pSgBuf->pvSegCur; +} + +/** + * Initialize a S/G buffer structure. + * + * @returns nothing. + * @param pSgBuf Pointer to the S/G buffer to initialize. + * @param paSegs Pointer to the start of the segment array. + * @param cSegs Number of segments in the array. + * + * @note paSegs and cSegs can be NULL and 0 respectively to indicate an empty + * S/G buffer. Operations on the S/G buffer will not do anything in this + * case. + */ +RTDECL(void) RTSgBufInit(PRTSGBUF pSgBuf, PCRTSGSEG paSegs, size_t cSegs); + +/** + * Resets the internal buffer position of the S/G buffer to the beginning. + * + * @returns nothing. + * @param pSgBuf The S/G buffer to reset. + */ +RTDECL(void) RTSgBufReset(PRTSGBUF pSgBuf); + +/** + * Clones a given S/G buffer. + * + * @returns nothing. + * @param pSgBufNew The new S/G buffer to clone to. + * @param pSgBufOld The source S/G buffer to clone from. + * + * @note This is only a shallow copy. Both S/G buffers will point to the + * same segment array. + */ +RTDECL(void) RTSgBufClone(PRTSGBUF pSgBufNew, PCRTSGBUF pSgBufOld); + +/** + * Returns the next segment in the S/G buffer or NULL if no segments left. + * + * @returns Pointer to the next segment in the S/G buffer. + * @param pSgBuf The S/G buffer. + * @param cbDesired The max number of bytes to get. + * @param pcbSeg Where to store the size of the returned segment, this is + * equal or smaller than @a cbDesired. + * + * @note Use RTSgBufAdvance() to advance after read/writing into the buffer. + */ +DECLINLINE(void *) RTSgBufGetCurrentSegment(PRTSGBUF pSgBuf, size_t cbDesired, size_t *pcbSeg) +{ + if (!RTSgBufIsAtEnd(pSgBuf)) + { + *pcbSeg = RT_MIN(cbDesired, pSgBuf->cbSegLeft); + return pSgBuf->pvSegCur; + } + *pcbSeg = 0; + return NULL; +} + +/** + * Returns the next segment in the S/G buffer or NULL if no segment is left. + * + * @returns Pointer to the next segment in the S/G buffer. + * @param pSgBuf The S/G buffer. + * @param pcbSeg Where to store the size of the returned segment. + * Holds the number of bytes requested initially or 0 to + * indicate that the size doesn't matter. + * This may contain fewer bytes on success if the current segment + * is smaller than the amount of bytes requested. + * + * @note This operation advances the internal buffer pointer of both S/G buffers. + */ +RTDECL(void *) RTSgBufGetNextSegment(PRTSGBUF pSgBuf, size_t *pcbSeg); + +/** + * Copy data between two S/G buffers. + * + * @returns The number of bytes copied. + * @param pSgBufDst The destination S/G buffer. + * @param pSgBufSrc The source S/G buffer. + * @param cbCopy Number of bytes to copy. + * + * @note This operation advances the internal buffer pointer of both S/G buffers. + */ +RTDECL(size_t) RTSgBufCopy(PRTSGBUF pSgBufDst, PRTSGBUF pSgBufSrc, size_t cbCopy); + +/** + * Compares the content of two S/G buffers. + * + * @returns Whatever memcmp returns. + * @param pSgBuf1 First S/G buffer. + * @param pSgBuf2 Second S/G buffer. + * @param cbCmp How many bytes to compare. + * + * @note This operation doesn't change the internal position of the S/G buffers. + */ +RTDECL(int) RTSgBufCmp(PCRTSGBUF pSgBuf1, PCRTSGBUF pSgBuf2, size_t cbCmp); + +/** + * Compares the content of two S/G buffers - advanced version. + * + * @returns Whatever memcmp returns. + * @param pSgBuf1 First S/G buffer. + * @param pSgBuf2 Second S/G buffer. + * @param cbCmp How many bytes to compare. + * @param poffDiff Where to store the offset of the first different byte + * in the buffer starting from the position of the S/G + * buffer before this call. + * @param fAdvance Flag whether the internal buffer position should be advanced. + * + */ +RTDECL(int) RTSgBufCmpEx(PRTSGBUF pSgBuf1, PRTSGBUF pSgBuf2, size_t cbCmp, size_t *poffDiff, bool fAdvance); + +/** + * Fills an S/G buf with a constant byte. + * + * @returns The number of actually filled bytes. + * Can be less than than cbSet if the end of the S/G buffer was reached. + * @param pSgBuf The S/G buffer. + * @param ubFill The byte to fill the buffer with. + * @param cbSet How many bytes to set. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufSet(PRTSGBUF pSgBuf, uint8_t ubFill, size_t cbSet); + +/** + * Copies data from an S/G buffer into a given non scattered buffer. + * + * @returns Number of bytes copied. + * @param pSgBuf The S/G buffer to copy from. + * @param pvBuf Buffer to copy the data into. + * @param cbCopy How many bytes to copy. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy); + +/** + * Copies data from a non scattered buffer into an S/G buffer. + * + * @returns Number of bytes copied. + * @param pSgBuf The S/G buffer to copy to. + * @param pvBuf Buffer to copy the data from. + * @param cbCopy How many bytes to copy. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy); + +/** + * Copies data from the given S/G buffer to a destination handled by the given callback. + * + * @returns Number of bytes copied. + * @param pSgBuf The S/G buffer to copy from. + * @param cbCopy How many bytes to copy. + * @param pfnCopyTo The callback to call on every S/G buffer segment until the operation finished. + * @param pvUser Opaque user data to pass in the given callback. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufCopyToFn(PRTSGBUF pSgBuf, size_t cbCopy, PFNRTSGBUFCOPYTO pfnCopyTo, void *pvUser); + +/** + * Copies data to the given S/G buffer from a destination handled by the given callback. + * + * @returns Number of bytes copied. + * @param pSgBuf The S/G buffer to copy to. + * @param cbCopy How many bytes to copy. + * @param pfnCopyFrom The callback to call on every S/G buffer segment until the operation finished. + * @param pvUser Opaque user data to pass in the given callback. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufCopyFromFn(PRTSGBUF pSgBuf, size_t cbCopy, PFNRTSGBUFCOPYFROM pfnCopyFrom, void *pvUser); + +/** + * Advances the internal buffer pointer. + * + * @returns Number of bytes the pointer was moved forward. + * @param pSgBuf The S/G buffer. + * @param cbAdvance Number of bytes to move forward. + */ +RTDECL(size_t) RTSgBufAdvance(PRTSGBUF pSgBuf, size_t cbAdvance); + +/** + * Constructs a new segment array starting from the current position + * and describing the given number of bytes. + * + * @returns Number of bytes the array describes. + * @param pSgBuf The S/G buffer. + * @param paSeg The uninitialized segment array. + * If NULL pcSeg will contain the number of segments needed + * to describe the requested amount of data. + * @param pcSeg The number of segments the given array has. + * This will hold the actual number of entries needed upon return. + * @param cbData Number of bytes the new array should describe. + * + * @note This operation advances the internal buffer pointer of the S/G buffer if paSeg is not NULL. + */ +RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned *pcSeg, size_t cbData); + +/** + * Returns whether the given S/G buffer is zeroed out from the current position + * upto the number of bytes to check. + * + * @returns true if the buffer has only zeros + * false otherwise. + * @param pSgBuf The S/G buffer. + * @param cbCheck Number of bytes to check. + */ +RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck); + +/** + * Maps the given S/G buffer to a segment array of another type (for example to + * iovec on POSIX or WSABUF on Windows). + * + * @param paMapped Where to store the pointer to the start of the native + * array or NULL. The memory needs to be freed with + * RTMemTmpFree(). + * @param pSgBuf The S/G buffer to map. + * @param Struct Struct used as the destination. + * @param pvBufField Name of the field holding the pointer to a buffer. + * @param TypeBufPtr Type of the buffer pointer. + * @param cbBufField Name of the field holding the size of the buffer. + * @param TypeBufSize Type of the field for the buffer size. + * @param cSegsMapped Where to store the number of segments the native array + * has. + * + * @note This operation maps the whole S/G buffer starting at the current + * internal position. The internal buffer position is unchanged by + * this operation. + * + * @remark Usage is a bit ugly but saves a few lines of duplicated code + * somewhere else and makes it possible to keep the S/G buffer members + * private without going through RTSgBufSegArrayCreate() first. + */ +#define RTSgBufMapToNative(paMapped, pSgBuf, Struct, pvBufField, TypeBufPtr, cbBufField, TypeBufSize, cSegsMapped) \ + do \ + { \ + AssertCompileMemberSize(Struct, pvBufField, RT_SIZEOFMEMB(RTSGSEG, pvSeg)); \ + /*AssertCompile(RT_SIZEOFMEMB(Struct, cbBufField) >= RT_SIZEOFMEMB(RTSGSEG, cbSeg));*/ \ + (cSegsMapped) = (pSgBuf)->cSegs - (pSgBuf)->idxSeg; \ + \ + /* We need room for at least one segment. */ \ + if ((pSgBuf)->cSegs == (pSgBuf)->idxSeg) \ + (cSegsMapped)++; \ + \ + (paMapped) = (Struct *)RTMemTmpAllocZ((cSegsMapped) * sizeof(Struct)); \ + if ((paMapped)) \ + { \ + /* The first buffer is special because we could be in the middle of a segment. */ \ + (paMapped)[0].pvBufField = (TypeBufPtr)(pSgBuf)->pvSegCur; \ + (paMapped)[0].cbBufField = (TypeBufSize)(pSgBuf)->cbSegLeft; \ + \ + for (unsigned i = 1; i < (cSegsMapped); i++) \ + { \ + (paMapped)[i].pvBufField = (TypeBufPtr)(pSgBuf)->paSegs[(pSgBuf)->idxSeg + i].pvSeg; \ + (paMapped)[i].cbBufField = (TypeBufSize)(pSgBuf)->paSegs[(pSgBuf)->idxSeg + i].cbSeg; \ + } \ + } \ + } while (0) + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_sg_h */ + diff --git a/include/iprt/sha.h b/include/iprt/sha.h new file mode 100644 index 00000000..d39e0ca7 --- /dev/null +++ b/include/iprt/sha.h @@ -0,0 +1,593 @@ +/** @file + * IPRT - SHA1 digest creation + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sha_h +#define IPRT_INCLUDED_sha_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_sha RTSha - SHA Family of Hash Functions + * @ingroup grp_rt + * @{ + */ + +/** The size of a SHA-1 hash. */ +#define RTSHA1_HASH_SIZE 20 +/** The length of a SHA-1 digest string. The terminator is not included. */ +#define RTSHA1_DIGEST_LEN 40 + +/** + * SHA-1 context. + */ +typedef union RTSHA1CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[8 + (5 + 80) * 4 + 4]; +#ifdef RT_SHA1_PRIVATE_CONTEXT + SHA_CTX Private; +#endif +#ifdef RT_SHA1_PRIVATE_ALT_CONTEXT + RTSHA1ALTPRIVATECTX AltPrivate; +#endif +} RTSHA1CONTEXT; +/** Pointer to an SHA-1 context. */ +typedef RTSHA1CONTEXT *PRTSHA1CONTEXT; + +/** + * Compute the SHA-1 hash of the data. + * + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha1(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RTSHA1_HASH_SIZE]); + +/** + * Computes the SHA-1 hash for the given data comparing it with the one given. + * + * @returns true on match, false on mismatch. + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash The hash to verify. (What is passed is a pointer to the + * caller's buffer.) + */ +RTDECL(bool) RTSha1Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA1_HASH_SIZE]); + +/** + * Initializes the SHA-1 context. + * + * @param pCtx Pointer to the SHA-1 context. + */ +RTDECL(void) RTSha1Init(PRTSHA1CONTEXT pCtx); + +/** + * Feed data into the SHA-1 computation. + * + * @param pCtx Pointer to the SHA-1 context. + * @param pvBuf Pointer to the data. + * @param cbBuf The length of the data (in bytes). + */ +RTDECL(void) RTSha1Update(PRTSHA1CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the SHA-1 hash of the data. + * + * @param pCtx Pointer to the SHA-1 context. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha1Final(PRTSHA1CONTEXT pCtx, uint8_t pabHash[RTSHA1_HASH_SIZE]); + +/** + * Converts a SHA-1 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabHash The binary digest returned by RTSha1Final or RTSha1. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTSHA1_DIGEST_LEN + 1 bytes. + */ +RTDECL(int) RTSha1ToString(uint8_t const pabHash[RTSHA1_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a SHA-1 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTSha1FromString(char const *pszDigest, uint8_t pabHash[RTSHA1_HASH_SIZE]); + +/** + * Creates a SHA1 digest for the given memory buffer. + * + * @returns iprt status code. + * + * @param pvBuf Memory buffer to create a SHA1 digest for. + * @param cbBuf The amount of data (in bytes). + * @param ppszDigest On success the SHA1 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha1Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Creates a SHA1 digest for the given file. + * + * @returns iprt status code. + * + * @param pszFile Filename to create a SHA1 digest for. + * @param ppszDigest On success the SHA1 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha1DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + + + +/** The size of a SHA-256 hash. */ +#define RTSHA256_HASH_SIZE 32 +/** The length of a SHA-256 digest string. The terminator is not included. */ +#define RTSHA256_DIGEST_LEN 64 + +/** + * SHA-256 context. + */ +typedef union RTSHA256CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[8 + (8 + 80) * 4]; +#ifdef RT_SHA256_PRIVATE_CONTEXT + SHA256_CTX Private; +#endif +#ifdef RT_SHA256_PRIVATE_ALT_CONTEXT + RTSHA256ALTPRIVATECTX AltPrivate; +#endif +} RTSHA256CONTEXT; +/** Pointer to an SHA-256 context. */ +typedef RTSHA256CONTEXT *PRTSHA256CONTEXT; + +/** + * Compute the SHA-256 hash of the data. + * + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha256(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RTSHA256_HASH_SIZE]); + +/** + * Computes the SHA-256 hash for the given data comparing it with the one given. + * + * @returns true on match, false on mismatch. + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash The hash to verify. (What is passed is a pointer to the + * caller's buffer.) + */ +RTDECL(bool) RTSha256Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA256_HASH_SIZE]); + +/** + * Initializes the SHA-256 context. + * + * @param pCtx Pointer to the SHA-256 context. + */ +RTDECL(void) RTSha256Init(PRTSHA256CONTEXT pCtx); + +/** + * Feed data into the SHA-256 computation. + * + * @param pCtx Pointer to the SHA-256 context. + * @param pvBuf Pointer to the data. + * @param cbBuf The length of the data (in bytes). + */ +RTDECL(void) RTSha256Update(PRTSHA256CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the SHA-256 hash of the data. + * + * @param pCtx Pointer to the SHA-256 context. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha256Final(PRTSHA256CONTEXT pCtx, uint8_t pabHash[RTSHA256_HASH_SIZE]); + +/** + * Converts a SHA-256 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabHash The binary digest returned by RTSha256Final or RTSha256. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTSHA256_DIGEST_LEN + 1 bytes. + */ +RTDECL(int) RTSha256ToString(uint8_t const pabHash[RTSHA256_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a SHA-256 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTSha256FromString(char const *pszDigest, uint8_t pabHash[RTSHA256_HASH_SIZE]); + +/** + * Creates a SHA256 digest for the given memory buffer. + * + * @returns iprt status code. + * + * @param pvBuf Memory buffer to create a + * SHA256 digest for. + * @param cbBuf The amount of data (in bytes). + * @param ppszDigest On success the SHA256 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha256Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Creates a SHA256 digest for the given file. + * + * @returns iprt status code. + * + * @param pszFile Filename to create a SHA256 + * digest for. + * @param ppszDigest On success the SHA256 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha256DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + + + +/** The size of a SHA-224 hash. */ +#define RTSHA224_HASH_SIZE 28 +/** The length of a SHA-224 digest string. The terminator is not included. */ +#define RTSHA224_DIGEST_LEN 56 + +/** SHA-224 context (same as for SHA-256). */ +typedef RTSHA256CONTEXT RTSHA224CONTEXT; +/** Pointer to an SHA-224 context. */ +typedef RTSHA256CONTEXT *PRTSHA224CONTEXT; + +/** + * Compute the SHA-224 hash of the data. + * + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha224(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RTSHA224_HASH_SIZE]); + +/** + * Computes the SHA-224 hash for the given data comparing it with the one given. + * + * @returns true on match, false on mismatch. + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash The hash to verify. (What is passed is a pointer to the + * caller's buffer.) + */ +RTDECL(bool) RTSha224Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA224_HASH_SIZE]); + +/** + * Initializes the SHA-224 context. + * + * @param pCtx Pointer to the SHA-224 context. + */ +RTDECL(void) RTSha224Init(PRTSHA224CONTEXT pCtx); + +/** + * Feed data into the SHA-224 computation. + * + * @param pCtx Pointer to the SHA-224 context. + * @param pvBuf Pointer to the data. + * @param cbBuf The length of the data (in bytes). + */ +RTDECL(void) RTSha224Update(PRTSHA224CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the SHA-224 hash of the data. + * + * @param pCtx Pointer to the SHA-224 context. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha224Final(PRTSHA224CONTEXT pCtx, uint8_t pabHash[RTSHA224_HASH_SIZE]); + +/** + * Converts a SHA-224 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabHash The binary digest returned by RTSha224Final or RTSha224. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTSHA224_DIGEST_LEN + 1 bytes. + */ +RTDECL(int) RTSha224ToString(uint8_t const pabHash[RTSHA224_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a SHA-224 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTSha224FromString(char const *pszDigest, uint8_t pabHash[RTSHA224_HASH_SIZE]); + +/** + * Creates a SHA224 digest for the given memory buffer. + * + * @returns iprt status code. + * + * @param pvBuf Memory buffer to create a SHA224 digest for. + * @param cbBuf The amount of data (in bytes). + * @param ppszDigest On success the SHA224 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha224Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Creates a SHA224 digest for the given file. + * + * @returns iprt status code. + * + * @param pszFile Filename to create a SHA224 digest for. + * @param ppszDigest On success the SHA224 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha224DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + + + +/** The size of a SHA-512 hash. */ +#define RTSHA512_HASH_SIZE 64 +/** The length of a SHA-512 digest string. The terminator is not included. */ +#define RTSHA512_DIGEST_LEN 128 + +/** + * SHA-512 context. + */ +typedef union RTSHA512CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[16 + (80 + 8) * 8]; +#ifdef RT_SHA512_PRIVATE_CONTEXT + SHA512_CTX Private; +#endif +#ifdef RT_SHA512_PRIVATE_ALT_CONTEXT + RTSHA512ALTPRIVATECTX AltPrivate; +#endif +} RTSHA512CONTEXT; +/** Pointer to an SHA-512 context. */ +typedef RTSHA512CONTEXT *PRTSHA512CONTEXT; + +/** + * Compute the SHA-512 hash of the data. + * + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha512(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RTSHA512_HASH_SIZE]); + +/** + * Computes the SHA-512 hash for the given data comparing it with the one given. + * + * @returns true on match, false on mismatch. + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash The hash to verify. (What is passed is a pointer to the + * caller's buffer.) + */ +RTDECL(bool) RTSha512Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA512_HASH_SIZE]); + +/** + * Initializes the SHA-512 context. + * + * @param pCtx Pointer to the SHA-512 context. + */ +RTDECL(void) RTSha512Init(PRTSHA512CONTEXT pCtx); + +/** + * Feed data into the SHA-512 computation. + * + * @param pCtx Pointer to the SHA-512 context. + * @param pvBuf Pointer to the data. + * @param cbBuf The length of the data (in bytes). + */ +RTDECL(void) RTSha512Update(PRTSHA512CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the SHA-512 hash of the data. + * + * @param pCtx Pointer to the SHA-512 context. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha512Final(PRTSHA512CONTEXT pCtx, uint8_t pabHash[RTSHA512_HASH_SIZE]); + +/** + * Converts a SHA-512 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabHash The binary digest returned by RTSha512Final or RTSha512. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTSHA512_DIGEST_LEN + 1 bytes. + */ +RTDECL(int) RTSha512ToString(uint8_t const pabHash[RTSHA512_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a SHA-512 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTSha512FromString(char const *pszDigest, uint8_t pabHash[RTSHA512_HASH_SIZE]); + + +/** Macro for declaring the interface for a SHA-512 variation. + * @internal */ +#define RTSHA512_DECLARE_VARIANT(a_Name, a_UName) \ + typedef RTSHA512CONTEXT RT_CONCAT3(RTSHA,a_UName,CONTEXT); \ + typedef RTSHA512CONTEXT *RT_CONCAT3(PRTSHA,a_UName,CONTEXT); \ + RTDECL(void) RT_CONCAT(RTSha,a_Name)(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]); \ + RTDECL(bool) RT_CONCAT3(RTSha,a_Name,Check)(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]); \ + RTDECL(void) RT_CONCAT3(RTSha,a_Name,Init)(RT_CONCAT3(PRTSHA,a_UName,CONTEXT) pCtx); \ + RTDECL(void) RT_CONCAT3(RTSha,a_Name,Update)(RT_CONCAT3(PRTSHA,a_UName,CONTEXT) pCtx, const void *pvBuf, size_t cbBuf); \ + RTDECL(void) RT_CONCAT3(RTSha,a_Name,Final)(RT_CONCAT3(PRTSHA,a_UName,CONTEXT) pCtx, uint8_t pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]); \ + RTDECL(int) RT_CONCAT3(RTSha,a_Name,ToString)(uint8_t const pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)], char *pszDigest, size_t cchDigest); \ + RTDECL(int) RT_CONCAT3(RTSha,a_Name,FromString)(char const *pszDigest, uint8_t pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]) + + +/** The size of a SHA-384 hash. */ +#define RTSHA384_HASH_SIZE 48 +/** The length of a SHA-384 digest string. The terminator is not included. */ +#define RTSHA384_DIGEST_LEN 96 +RTSHA512_DECLARE_VARIANT(384,384); + +/** The size of a SHA-512/224 hash. */ +#define RTSHA512T224_HASH_SIZE 28 +/** The length of a SHA-512/224 digest string. The terminator is not + * included. */ +#define RTSHA512T224_DIGEST_LEN 56 +RTSHA512_DECLARE_VARIANT(512t224,512T224); + +/** The size of a SHA-512/256 hash. */ +#define RTSHA512T256_HASH_SIZE 32 +/** The length of a SHA-512/256 digest string. The terminator is not + * included. */ +#define RTSHA512T256_DIGEST_LEN 64 +RTSHA512_DECLARE_VARIANT(512t256,512T256); + + +/** + * SHA3 context. + */ +typedef union RTSHA3CONTEXT +{ + uint64_t a64Padding[26]; + uint8_t abPadding[208]; +#ifdef RT_SHA3_PRIVATE_CONTEXT + RTSHA3PRIVATECTX Private; +#endif +#ifdef RT_SHA3_PRIVATE_ALT_CONTEXT + RTSHA3ALTPRIVATECTX AltPrivate; +#endif +} RTSHA3CONTEXT; +/** Pointer to an SHA3 context. */ +typedef RTSHA3CONTEXT *PRTSHA3CONTEXT; + +/** Macro for declaring the interface for a SHA3 variation. + * + * @note The interface differes slightly from the older checksums: + * - Must call Final and/or Cleanup method. + * - Must use Clone instead of memcpy'ing the context. + * - Status codes are returned, Init may really fail. + * + * @internal */ +#define RTSHA3_DECLARE_VARIANT(a_Bits) \ + typedef struct RT_CONCAT3(RTSHA3T,a_Bits,CONTEXT) { RTSHA3CONTEXT Sha3; } RT_CONCAT3(RTSHA3T,a_Bits,CONTEXT); \ + typedef RT_CONCAT3(RTSHA3T,a_Bits,CONTEXT) *RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT); \ + RTDECL(int) RT_CONCAT(RTSha3t,a_Bits)(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)]); \ + RTDECL(bool) RT_CONCAT3(RTSha3t,a_Bits,Check)(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)]); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Init)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Update)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx, const void *pvBuf, size_t cbBuf); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Final)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)]); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Cleanup)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Clone)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx, RT_CONCAT3(RTSHA3T,a_Bits,CONTEXT) const *pCtxSrc); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,ToString)(uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)], char *pszDigest, size_t cchDigest); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,FromString)(char const *pszDigest, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)]) + +/** The size of a SHA-224 hash. */ +#define RTSHA3_224_HASH_SIZE 28 +/** The length of a SHA-224 digest string. The terminator is not included. */ +#define RTSHA3_224_DIGEST_LEN 56 +RTSHA3_DECLARE_VARIANT(224); + +/** The size of a SHA-256 hash. */ +#define RTSHA3_256_HASH_SIZE 32 +/** The length of a SHA-256 digest string. The terminator is not included. */ +#define RTSHA3_256_DIGEST_LEN 64 +RTSHA3_DECLARE_VARIANT(256); + +/** The size of a SHA-384 hash. */ +#define RTSHA3_384_HASH_SIZE 48 +/** The length of a SHA-384 digest string. The terminator is not included. */ +#define RTSHA3_384_DIGEST_LEN 96 +RTSHA3_DECLARE_VARIANT(384); + +/** The size of a SHA-512 hash. */ +#define RTSHA3_512_HASH_SIZE 64 +/** The length of a SHA-512 digest string. The terminator is not included. */ +#define RTSHA3_512_DIGEST_LEN 128 +RTSHA3_DECLARE_VARIANT(512); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_sha_h */ + diff --git a/include/iprt/shmem.h b/include/iprt/shmem.h new file mode 100644 index 00000000..7ea65f17 --- /dev/null +++ b/include/iprt/shmem.h @@ -0,0 +1,180 @@ +/** @file + * IPRT - Named shared memory. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_shmem_h +#define IPRT_INCLUDED_shmem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_shmem RTShMem - Shared memory. + * @ingroup grp_rt + * @{ + */ + +/** @name Open flags for RTShMemOpen(). + * @{ + */ +/** Creates a new shared memory object or opens an already existing one. */ +#define RTSHMEM_O_F_CREATE RT_BIT_32(0) +/** Creates a new shared memory object failing if one with the same name exists already. */ +#define RTSHMEM_O_F_CREATE_EXCL (RTSHMEM_O_F_CREATE | RT_BIT_32(1)) +/** Opens the shared memory object for read access. */ +#define RTSHMEM_O_F_READ RT_BIT_32(2) +/** Opens the shared memory object for write access. */ +#define RTSHMEM_O_F_WRITE RT_BIT_32(3) +/** Opens the shared memory object for read and write access. */ +#define RTSHMEM_O_F_READWRITE (RTSHMEM_O_F_READ | RTSHMEM_O_F_WRITE) +/** Truncates the shared memory object to 0 bytes on open. */ +#define RTSHMEM_O_F_TRUNCATE RT_BIT_32(4) +/** Mappings may be created with executable access right (required to be known on Windows beforehand). */ +#define RTSHMEM_O_F_MAYBE_EXEC RT_BIT_32(5) +/** Mask of all valid flags. */ +#define RTSHMEM_O_F_VALID_MASK UINT32_C(0x0000003f) +/** @} */ + +/** + * Creates or opens a new shared memory object with the given name. + * + * @returns IPRT status code. + * @retval VERR_OUT_OF_RANGE if the mapping hint count is too big. + * @param phShMem Where to store the handle to the shared memory object on success. + * @param pszName Name of the shared memory object to open or create. + * @param fFlags Combination of RTSHMEM_O_F_* flags. + * @param cbMax Maximum number of bytes to reserve for the shared memory object. + * On some platforms this can be 0 and set to another value using RTShMemSetSize() afterwards. + * Giving 0 on Windows results in an error as shared memory objects there do not support + * changing the size afterwards. + * @param cMappingsHint Hint about the possible number of mappings created later on, set to 0 for a default value. + */ +RTDECL(int) RTShMemOpen(PRTSHMEM phShMem, const char *pszName, uint32_t fFlags, size_t cbMax, uint32_t cMappingsHint); + +/** + * Closes the given shared memory object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_STATE if there is still a mapping active for the given shared memory object. + * @param hShMem The shared memory object handle. + * + * @note The shared memory object will be deleted if the creator closes it. + */ +RTDECL(int) RTShMemClose(RTSHMEM hShMem); + +/** + * Tries to delete a shared memory object with the given name. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the platform does not support deleting the shared memory object by name. + * @param pszName Name of the shared memory object to delete. + */ +RTDECL(int) RTShMemDelete(const char *pszName); + +/** + * Returns the number of references (i.e. mappings) held for the given shared memory object. + * + * @returns Reference count or 0 on invalid handle. + * @param hShMem The shared memory object handle. + */ +RTDECL(uint32_t) RTShMemRefCount(RTSHMEM hShMem); + +/** + * Sets the size of the given shared memory object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_STATE if there are mappings active for the given shared memory object. + * @retval VERR_NOT_SUPPORTED on some hosts which do not support changing the size after creation. + * @param hShMem The shared memory object handle. + * @param cbMem Size of the memory object handle in bytes. + */ +RTDECL(int) RTShMemSetSize(RTSHMEM hShMem, size_t cbMem); + +/** + * Queries the current size of the shared memory object. + * + * @returns IPRT status code. + * @param hShMem The shared memory object handle. + * @param pcbMem Where to store the size of the shared memory object on success. + */ +RTDECL(int) RTShMemQuerySize(RTSHMEM hShMem, size_t *pcbMem); + +/** @name Region mapping flags for RTShMemMapRegion(). + * @{ + */ +/** Read access. */ +#define RTSHMEM_MAP_F_READ RT_BIT_32(0) +/** Write access. */ +#define RTSHMEM_MAP_F_WRITE RT_BIT_32(1) +/** Execute access. */ +#define RTSHMEM_MAP_F_EXEC RT_BIT_32(2) +/** Copy on write, any write creates a new page private to the callers address space and changes + * in that area are not shared with other processes using the hsared memory object. */ +#define RTSHMEM_MAP_F_COW RT_BIT_32(3) +/** Mask of all valid flags. */ +#define RTSHMEM_MAP_F_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Maps a region of the given shared memory object into the callers address space. + * + * @returns IPRT status code. + * @retval VERR_SHMEM_MAXIMUM_MAPPINGS_REACHED if the maximum number of mappings was reached (host dependent). + * @retval VERR_ACCESS_DENIED if the requested memory access rights do not line up with the flags given when opening + * the memory object (requesting write access for a readonly shared memory object for example). + * @param hShMem The shared memory object handle. + * @param offRegion Offset into the shared memory object to start mapping at. + * @param cbRegion Size of the region to map. + * @param fFlags Desired properties of the mapped region, combination of RTSHMEM_MAP_F_* defines. + * @param ppv Where to store the start address of the mapped region on success. + */ +RTDECL(int) RTShMemMapRegion(RTSHMEM hShMem, size_t offRegion, size_t cbRegion, uint32_t fFlags, void **ppv); + +/** + * Unmaps the given region of the shared memory object. + * + * @returns IPRT status code. + * @param hShMem The shared memory object handle. + * @param pv Pointer to the mapped region obtained with RTShMemMapRegion() earlier on. + */ +RTDECL(int) RTShMemUnmapRegion(RTSHMEM hShMem, void *pv); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_shmem_h */ + diff --git a/include/iprt/socket.h b/include/iprt/socket.h new file mode 100644 index 00000000..c7a572e7 --- /dev/null +++ b/include/iprt/socket.h @@ -0,0 +1,430 @@ +/** @file + * IPRT - Network Sockets. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_socket_h +#define IPRT_INCLUDED_socket_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + +#ifdef IN_RING0 +# error "There are no RTSocket APIs available Ring-0 Host Context!" +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_socket RTSocket - Network Sockets + * @ingroup grp_rt + * @{ + */ + +/** Use the system default timeout for the connet attempt. */ +#define RT_SOCKETCONNECT_DEFAULT_WAIT (RT_INDEFINITE_WAIT - 1) + +/** + * Retains a reference to the socket handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSocket The socket handle. + */ +RTDECL(uint32_t) RTSocketRetain(RTSOCKET hSocket); + +/** + * Release a reference to the socket handle. + * + * When the reference count reaches zero, the socket handle is shut down and + * destroyed. This will not be graceful shutdown, use the protocol specific + * close method if this is desired. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSocket The socket handle. The NIL handle is quietly + * ignored and 0 is returned. + */ +RTDECL(uint32_t) RTSocketRelease(RTSOCKET hSocket); + +/** + * Shuts down the socket, close it and then release one handle reference. + * + * This is slightly different from RTSocketRelease which will first do the + * shutting down and closing when the reference count reaches zero. + * + * @returns IPRT status code. + * @param hSocket The socket handle. NIL is ignored. + * + * @remarks This will not perform a graceful shutdown of the socket, it will + * just destroy it. Use the protocol specific close method if this is + * desired. + */ +RTDECL(int) RTSocketClose(RTSOCKET hSocket); + +/** + * Creates an IPRT socket handle from a native one. + * + * Do NOT use the native handle after passing it to this function, IPRT owns it + * and might even have closed upon a successful return. + * + * @returns IPRT status code. + * @param phSocket Where to store the IPRT socket handle. + * @param uNative The native handle. + */ +RTDECL(int) RTSocketFromNative(PRTSOCKET phSocket, RTHCINTPTR uNative); + +/** + * Gets the native socket handle. + * + * @returns The native socket handle or RTHCUINTPTR_MAX if not invalid. + * @param hSocket The socket handle. + */ +RTDECL(RTHCUINTPTR) RTSocketToNative(RTSOCKET hSocket); + +/** + * Helper that ensures the correct inheritability of a socket. + * + * We're currently ignoring failures. + * + * @returns IPRT status code + * @param hSocket The socket handle. + * @param fInheritable The desired inheritability state. + */ +RTDECL(int) RTSocketSetInheritance(RTSOCKET hSocket, bool fInheritable); + +/** + * Parse Internet style addresses, getting a generic IPRT network address. + * + * @returns IPRT status code + * @param pszAddress Name or IP address. NULL or empty string (no + * spaces) is taken to mean INADDR_ANY, which is + * meaningful when binding a server socket for + * instance. + * @param uPort Port number (host byte order). + * @param pAddr Where to return the generic IPRT network address. + */ +RTDECL(int) RTSocketParseInetAddress(const char *pszAddress, unsigned uPort, PRTNETADDR pAddr); + +/** + * Try resolve a host name, returning the first matching address. + * + * @returns IPRT status code. + * @param pszHost Name or IP address to look up. + * @param pszAddress Where to return the stringified address. + * @param pcbAddress Input: The size of the @a pszResult buffer. + * Output: size of the returned string. This is set on + * VERR_BUFFER_OVERFLOW and most other error statuses. + * @param penmAddrType Input: Which kind of address to return. Valid values + * are: + * - RTNETADDRTYPE_IPV4 -> lookup AF_INET. + * - RTNETADDRTYPE_IPV6 -> lookup AF_INET6. + * - RTNETADDRTYPE_INVALID/NULL -> lookup anything. + * Output: The type of address that is being returned. + * Not modified on failure. + */ +RTDECL(int) RTSocketQueryAddressStr(const char *pszHost, char *pszAddress, size_t *pcbAddress, PRTNETADDRTYPE penmAddrType); + +/** + * Receive data from a socket. + * + * @returns IPRT status code. + * @param hSocket The socket handle. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. If NULL the entire buffer + * will be filled upon successful return. If not NULL a + * partial read can be done successfully. + */ +RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead); + +/** + * Receive data from a socket, including sender address. Mainly useful + * for datagram sockets. + * + * @returns IPRT status code. + * @param hSocket The socket handle. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. Must be non-NULL. + * @param pSrcAddr Pointer to sender address buffer. May be NULL. + */ +RTDECL(int) RTSocketReadFrom(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr); + +/** + * Send data to a socket. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + */ +RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer); + +/** + * Send data to a socket, including destination address. Mainly useful + * for datagram sockets. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pDstAddr Pointer to destination address. May be NULL. + */ +RTDECL(int) RTSocketWriteTo(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pDstAddr); + +/** + * Checks if the socket is ready for reading (for I/O multiplexing). + * + * @returns IPRT status code. + * @param hSocket The socket handle. + * @param cMillies Number of milliseconds to wait for the socket. Use + * RT_INDEFINITE_WAIT to wait for ever. + */ +RTDECL(int) RTSocketSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies); + +/** @name Select events + * @{ */ +/** Readable without blocking. */ +#define RTSOCKET_EVT_READ RT_BIT_32(0) +/** Writable without blocking. */ +#define RTSOCKET_EVT_WRITE RT_BIT_32(1) +/** Error condition, hangup, exception or similar. */ +#define RTSOCKET_EVT_ERROR RT_BIT_32(2) +/** Mask of the valid bits. */ +#define RTSOCKET_EVT_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Socket I/O multiplexing + * Checks if the socket is ready for one of the given events. + * + * @returns iprt status code. + * @param hSocket The Socket handle. + * @param fEvents Event mask to wait for. + * @param pfEvents Where to store the event mask on return. + * @param cMillies Number of milliseconds to wait for the socket. Use + * RT_INDEFINITE_WAIT to wait for ever. + */ +RTR3DECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies); + +/** + * Shuts down one or both directions of communciation. + * + * @returns IPRT status code. + * @param hSocket The socket handle. + * @param fRead Whether to shutdown our read direction. + * @param fWrite Whether to shutdown our write direction. + */ +RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite); + +/** + * Gets the address of the local side. + * + * @returns IPRT status code. + * @param hSocket The Socket handle. + * @param pAddr Where to store the local address on success. + */ +RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr); + +/** + * Gets the address of the other party. + * + * @returns IPRT status code. + * @param hSocket The Socket handle. + * @param pAddr Where to store the peer address on success. + */ +RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr); + +/** + * Send data from a scatter/gather buffer to a socket. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param pSgBuf Scatter/gather buffer to write data to socket. + */ +RTDECL(int) RTSocketSgWrite(RTSOCKET hSocket, PCRTSGBUF pSgBuf); + +/** + * Send data from multiple buffers to a socket. + * + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * ellipsis. + * @param ... Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTDECL(int) RTSocketSgWriteL(RTSOCKET hSocket, size_t cSegs, ...); + +/** + * Send data from multiple buffers to a socket. + * + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * argument list. + * @param va Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTDECL(int) RTSocketSgWriteLV(RTSOCKET hSocket, size_t cSegs, va_list va); + +/** + * Receive data from a socket. + * + * This version doesn't block if there is no data on the socket. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + */ +RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead); + +/** + * Send data to a socket. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pcbWritten Number of bytes written. + */ +RTDECL(int) RTSocketWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten); + +/** + * Send data to a socket, including destination address. Mainly useful + * for datagram sockets. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pDstAddr Pointer to destination address. May be NULL. + */ +RTDECL(int) RTSocketWriteToNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pDstAddr); + +/** + * Send data from a scatter/gather buffer to a socket. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns iprt status code. + * + * @param hSocket The Socket handle. + * @param pSgBuf Scatter/gather buffer to write data to socket. + * @param pcbWritten Number of bytes written. + */ +RTR3DECL(int) RTSocketSgWriteNB(RTSOCKET hSocket, PCRTSGBUF pSgBuf, size_t *pcbWritten); + + +/** + * Send data from multiple buffers to a socket. + * + * This version doesn't block if there is not enough room for the message. + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * ellipsis. + * @param pcbWritten Number of bytes written. + * @param ... Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTSocketSgWriteLNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, ...); + +/** + * Send data from multiple buffers to a socket. + * + * This version doesn't block if there is not enough room for the message. + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * argument list. + * @param pcbWritten Number of bytes written. + * @param va Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTSocketSgWriteLVNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, va_list va); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_socket_h */ + diff --git a/include/iprt/solaris/kmoddeps.mac b/include/iprt/solaris/kmoddeps.mac new file mode 100644 index 00000000..c9ec53e0 --- /dev/null +++ b/include/iprt/solaris/kmoddeps.mac @@ -0,0 +1,193 @@ +; $Id: kmoddeps.mac $ +;; @file +; Assembly macros for generating Solaris kernel module dependencies +; + +; +; Copyright (C) 2012-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +; Solaris kernel modules use non-standard ELF constructions to express inter- +; module dependencies, namely a DT_NEEDED tag inside a relocatable ELF file. +; The Solaris linker can generate these automatically; since yasm can't +; produce an ELF file which quite fits Solaris's requirements we create one +; manually using flat binary output format. In order to save unnecessary +; repetition, this file defines macros for the repetitive bits which can be +; reused by the actual dependency objects. Certainly not the nicest way to +; get the effect we want, but probably a reasonable compromise between +; cleanness and required effort. +; + +%ifdef RT_ARCH_AMD64 + +BITS 64 +;; +; Native word size +%define DNAT dq + +;; +; ELF machine number for the current architecture. +%define EM_CUR 62 ; EM_X86_64 + +;; +; ELF header class for the current architecture. +%define CLASS 2 + +%else + +BITS 32 +%define DNAT dd +%define EM_CUR 3 ; EM_386 +%define CLASS 1 + +%endif + +;; +; ELF file header, section tables and shared string table for the dependency +; object. +%macro kmoddeps_header 0 +elf_hdr: ; elfxx_hdr structure + db 7fh, "ELF" ; e_ident + db CLASS, 1, 1 ; e_ident + times 9 db 0 ; padding + dw 1 ; e_type ET_REL + dw EM_CUR ; e_machine + dd 1 ; e_version EV_CURRENT + DNAT 0 ; e_entry + DNAT 0 ; e_phoff + DNAT sect_hdr - $$ ; e_shoff + dd 0 ; e_flags + dw elf_hsize ; e_ehsize + dw 0 ; e_phentsize + dw 0 ; e_phnum + dw sect_hsize ; e_shentsize + dw 4 ; e_shnum + dw 1 ; e_shstrndx section .shstrtab +elf_hsize equ $ - elf_hdr + +sect_hdr: ; elfxx_shdr structure + times sect_hsize db 0 ; undefined section + +sect_hdr1: + dd str_shstrtab ; sh_name .shstrtab + dd 3 ; sh_type SHT_STRTAB + DNAT 20h ; sh_flags SHF_STRINGS + DNAT 0 ; sh_addr + DNAT shstrtab - $$ ; sh_offset + DNAT shstrtab_size ; sh_size + dd 0 ; sh_link + dd 0 ; sh_info + DNAT 1 ; sh_addralign + DNAT 0 ; sh_entsize +sect_hsize equ $ - sect_hdr1 + + dd str_dynstr ; sh_name .dynstr + dd 3 ; sh_type SHT_STRTAB + DNAT 20h ; sh_flags SHF_STRINGS + DNAT 0 ; sh_addr + DNAT dynstr - $$ ; sh_offset + DNAT dynstr_size ; sh_size + dd 0 ; sh_link + dd 0 ; sh_info + DNAT 1 ; sh_addralign + DNAT 0 ; sh_entsize + + dd str_dynamic ; sh_name .dynamic + dd 6 ; sh_type SHT_DYNAMIC + DNAT 1 ; sh_flags SHF_WRITE + DNAT 0 ; sh_addr + DNAT dynamic - $$ ; sh_offset + DNAT dynamic_size ; sh_size + dd 2 ; sh_link .dynstr + dd 0 ; sh_info + DNAT 8 ; sh_addralign + DNAT 0 ; sh_entsize + +shstrtab: +str_shstrtab equ $ - shstrtab + db ".shstrtab", 0 +str_dynstr equ $ - shstrtab + db ".dynstr", 0 +str_dynamic equ $ - shstrtab + db ".dynamic", 0 +shstrtab_size equ $ - shstrtab +%endmacro ; kmoddeps_header + +;; +; Start of the .dynstr section for the dependency object. +%macro kmoddeps_dynstr_start 0 +dynstr: + db 0 +%endmacro + +;; +; A .dynstr string entry for the dependency object. +; The parameters are a symbolic name for the string and the string itself. +%macro kmoddeps_dynstr_string 2 +dynstr_name_%1 equ $ - dynstr + db %2, 0 +%endmacro + +;; +; End of the .dynstr section for the dependency object. +%macro kmoddeps_dynstr_end 0 +dynstr_size equ $ - dynstr +%endmacro + +;; +; Start of the .dynamic section for the dependency object. +%macro kmoddeps_dynamic_start 0 +dynamic: +%endmacro + +;; +; A .dynamic DT_NEEDED entry for the dependency object. +; The parameter is a symbolic string name previously defined using +; @a kmoddeps_dynstr_string. +%macro kmoddeps_dynamic_needed 1 + DNAT 1 ; DT_NEEDED + DNAT dynstr_name_%1 +%endmacro + +;; +; End of the .dynamic section for the dependency object. +%macro kmoddeps_dynamic_end 0 + DNAT 1ah ; DT_FLAGS + DNAT 4 ; TEXTREL + DNAT 6ffffffbh ; DT_FLAGS1 + DNAT 0 + DNAT 601900h ; SUNW_STRPAD + DNAT 200h + DNAT 601b00h ; SUNW_LDMACH + DNAT 62 ; EM_X86_64 + times 22 DNAT 0 ; padding +dynamic_size equ $ - dynamic +%endmacro ; kmoddeps_dynamic_end + diff --git a/include/iprt/sort.h b/include/iprt/sort.h new file mode 100644 index 00000000..4e5d47de --- /dev/null +++ b/include/iprt/sort.h @@ -0,0 +1,141 @@ +/** @file + * IPRT - Sorting. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sort_h +#define IPRT_INCLUDED_sort_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_sort RTSort - Sorting Algorithms + * @ingroup grp_rt + * @{ */ + +RT_C_DECLS_BEGIN + +/** + * Callback for comparing two array elements. + * + * @retval 0 if equal. + * @retval -1 if @a pvElement1 comes before @a pvElement2. + * @retval 1 if @a pvElement1 comes after @a pvElement2. + * + * @param pvElement1 The 1st element. + * @param pvElement2 The 2nd element. + * @param pvUser The user argument passed to the sorting function. + */ +typedef DECLCALLBACKTYPE(int, FNRTSORTCMP,(void const *pvElement1, void const *pvElement2, void *pvUser)); +/** Pointer to a compare function. */ +typedef FNRTSORTCMP *PFNRTSORTCMP; + +/** + * Sorter function for an array of variable sized elementes. + * + * @param pvArray The array to sort. + * @param cElements The number of elements in the array. + * @param cbElement The size of an array element. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +typedef DECLCALLBACKTYPE(void, FNRTSORT,(void *pvArray, size_t cElements, size_t cbElement, PFNRTSORTCMP pfnCmp, void *pvUser)); +/** Pointer to a sorter function for an array of variable sized elements. */ +typedef FNRTSORT *PFNRTSORT; + +/** + * Pointer array sorter function. + * + * @param papvArray The array to sort. + * @param cElements The number of elements in the array. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +typedef DECLCALLBACKTYPE(void, FNRTSORTAPV,(void **papvArray, size_t cElements, PFNRTSORTCMP pfnCmp, void *pvUser)); +/** Pointer to a pointer array sorter function. */ +typedef FNRTSORTAPV *PFNRTSORTAPV; + +/** + * Shell sort an array of variable sized elementes. + * + * @param pvArray The array to sort. + * @param cElements The number of elements in the array. + * @param cbElement The size of an array element. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +RTDECL(void) RTSortShell(void *pvArray, size_t cElements, size_t cbElement, PFNRTSORTCMP pfnCmp, void *pvUser); + +/** + * Same as RTSortShell but speciallized for an array containing element + * pointers. + * + * @param papvArray The array to sort. + * @param cElements The number of elements in the array. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +RTDECL(void) RTSortApvShell(void **papvArray, size_t cElements, PFNRTSORTCMP pfnCmp, void *pvUser); + +/** + * Checks if an array of variable sized elementes is sorted. + * + * @returns true if it is sorted, false if it isn't. + * @param pvArray The array to check. + * @param cElements The number of elements in the array. + * @param cbElement The size of an array element. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +RTDECL(bool) RTSortIsSorted(void const *pvArray, size_t cElements, size_t cbElement, PFNRTSORTCMP pfnCmp, void *pvUser); + +/** + * Same as RTSortShell but speciallized for an array containing element + * pointers. + * + * @returns true if it is sorted, false if it isn't. + * @param papvArray The array to check. + * @param cElements The number of elements in the array. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +RTDECL(bool) RTSortApvIsSorted(void const * const *papvArray, size_t cElements, PFNRTSORTCMP pfnCmp, void *pvUser); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_sort_h */ + diff --git a/include/iprt/spinlock.h b/include/iprt/spinlock.h new file mode 100644 index 00000000..683be325 --- /dev/null +++ b/include/iprt/spinlock.h @@ -0,0 +1,105 @@ +/** @file + * IPRT - Spinlocks. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_spinlock_h +#define IPRT_INCLUDED_spinlock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_rt_spinlock RTSpinlock - Spinlocks + * @ingroup grp_rt + * @{ + */ + +/** + * Creates a spinlock. + * + * @returns iprt status code. + * @param pSpinlock Where to store the spinlock handle. + * @param fFlags Creation flags, see RTSPINLOCK_FLAGS_XXX. + * @param pszName Spinlock name, for debugging purposes. String lifetime + * must be the same as the lock as it won't be copied. + */ +RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char *pszName); + +/** @name RTSPINLOCK_FLAGS_XXX + * @{ */ +/** Disable interrupts when taking the spinlock, making it interrupt safe + * (sans NMI of course). + * + * This is generally the safest option, though it isn't really required unless + * the data being protect is also accessed from interrupt handler context. */ +#define RTSPINLOCK_FLAGS_INTERRUPT_SAFE RT_BIT(1) +/** No need to disable interrupts, the protect code/data is not used by + * interrupt handlers. */ +#define RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE RT_BIT(2) +/** @} */ + +/** + * Destroys a spinlock created by RTSpinlockCreate(). + * + * @returns iprt status code. + * @param Spinlock Spinlock returned by RTSpinlockCreate(). + */ +RTDECL(int) RTSpinlockDestroy(RTSPINLOCK Spinlock); + +/** + * Acquires the spinlock. + * + * @param Spinlock The spinlock to acquire. + */ +RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock); + +/** + * Releases the spinlock. + * + * @param Spinlock The spinlock to acquire. + */ +RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_spinlock_h */ + diff --git a/include/iprt/stdarg.h b/include/iprt/stdarg.h new file mode 100644 index 00000000..9d12cd8b --- /dev/null +++ b/include/iprt/stdarg.h @@ -0,0 +1,79 @@ +/** @file + * IPRT - stdarg.h wrapper. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_stdarg_h +#define IPRT_INCLUDED_stdarg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef IPRT_NO_CRT +# include +# include +#else +# include +# if defined(RT_OS_FREEBSD) && defined(_KERNEL) +# include +# elif defined(RT_OS_NETBSD) && defined(_KERNEL) +# include +# elif defined(RT_OS_SOLARIS) && defined(_KERNEL) && defined(__GNUC__) +# include +# if __GNUC__ >= 4 /* System headers refers to __builtin_stdarg_start. */ +# define __builtin_stdarg_start __builtin_va_start +# endif +# elif defined(RT_OS_LINUX) && defined(IN_RING0) +# include "linux/version.h" +# if RTLNX_VER_MIN(5,15,0) || RTLNX_RHEL_MAJ_PREREQ(9,1) +# include +# else +# include +# endif +# else +# include +# endif +#endif + +/* + * Older MSC versions doesn't implement va_copy. Newer (12.0+?) ones does + * implement it like below, but for now it's easier to continue like for the + * older ones so we can more easily handle R0, RC and other weird contexts. + */ +#if !defined(va_copy) || defined(_MSC_VER) +# undef va_copy +# define va_copy(dst, src) do { (dst) = (src); } while (0) /** @todo check AMD64 */ +#endif + +#endif /* !IPRT_INCLUDED_stdarg_h */ + diff --git a/include/iprt/stdint.h b/include/iprt/stdint.h new file mode 100644 index 00000000..c76e5c6f --- /dev/null +++ b/include/iprt/stdint.h @@ -0,0 +1,349 @@ +/** @file + * IPRT - stdint.h wrapper (for backlevel compilers like MSC). + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_stdint_h +#define IPRT_INCLUDED_stdint_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/* + * Use the stdint.h on systems that have one. + */ +#if !(defined(RT_OS_LINUX) && defined(__KERNEL__)) \ + && !(defined(RT_OS_FREEBSD) && defined(_KERNEL)) \ + && !(defined(RT_OS_NETBSD) && defined(_KERNEL)) \ + && RT_MSC_PREREQ_EX(RT_MSC_VER_VS2010, 1 /*non-msc*/) \ + && !defined(__IBMC__) \ + && !defined(__IBMCPP__) \ + && !defined(IPRT_NO_CRT) \ + && !defined(IPRT_DONT_USE_SYSTEM_STDINT_H) \ + && !defined(DOXYGEN_RUNNING) + +# ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +# endif +# ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +# endif +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) +# endif +# include +# ifdef _MSC_VER +# pragma warning(pop) +# endif + +# if defined(RT_OS_DARWIN) && defined(KERNEL) && defined(RT_ARCH_AMD64) + /* + * Kludge to fix the incorrect 32-bit constant macros in + * Kernel.framework/Headers/stdin.h. uint32_t and int32_t are + * int not long as these macros use, which is significant when + * targeting AMD64. (10a222) + */ +# undef INT32_C +# define INT32_C(Value) (Value) +# undef UINT32_C +# define UINT32_C(Value) (Value ## U) +# endif /* 64-bit darwin kludge. */ + +#elif defined(RT_OS_FREEBSD) && defined(_KERNEL) + +# ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +# endif +# ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +# endif +# include + +#elif defined(RT_OS_NETBSD) && defined(_KERNEL) + +# ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +# endif +# ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +# endif +# include + +#else /* No system stdint.h */ + +/* + * Define the types we use. + * The linux kernel defines all these in linux/types.h, so skip it. + */ +# if !(defined(RT_OS_LINUX) && defined(__KERNEL__)) \ + || defined(IPRT_NO_CRT) \ + || defined(IPRT_DONT_USE_SYSTEM_STDINT_H) \ + || defined(DOXGEN_RUNNING) + + /* Simplify the [u]int64_t type detection mess. */ +# undef IPRT_STDINT_USE_STRUCT_FOR_64_BIT_TYPES +# ifdef __IBMCPP__ +# if __IBMCPP__ < 350 && (defined(__WINDOWS__) || defined(_AIX) || defined(__OS2__)) +# define IPRT_STDINT_USE_STRUCT_FOR_64_BIT_TYPES +# endif +# endif +# ifdef __IBMC__ +# if __IBMC__ < 350 && (defined(__WINDOWS__) || defined(_AIX) || defined(__OS2__)) +# define IPRT_STDINT_USE_STRUCT_FOR_64_BIT_TYPES +# endif +# endif + + /* x-bit types */ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) \ + || defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) \ + || defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) +# if !defined(_INT8_T_DECLARED) && !defined(_INT8_T) +typedef signed char int8_t; +# endif +# if !defined(_UINT8_T_DECLARED) && !defined(_UINT8_T) +typedef unsigned char uint8_t; +# endif +# if !defined(_INT16_T_DECLARED) && !defined(_INT16_T) +typedef signed short int16_t; +# endif +# if !defined(_UINT16_T_DECLARED) && !defined(_UINT16_T) +typedef unsigned short uint16_t; +# endif +# if !defined(_INT32_T_DECLARED) && !defined(_INT32_T) +# if ARCH_BITS != 16 +typedef signed int int32_t; +# else +typedef signed long int32_t; +# endif +# endif +# if !defined(_UINT32_T_DECLARED) && !defined(_UINT32_T) +# if ARCH_BITS != 16 +typedef unsigned int uint32_t; +# else +typedef unsigned long uint32_t; +# endif +# endif +# if defined(_MSC_VER) +# if !defined(_INT64_T_DECLARED) && !defined(_INT64_T) +typedef signed _int64 int64_t; +# endif +# if !defined(_UINT64_T_DECLARED) && !defined(_UINT64_T) +typedef unsigned _int64 uint64_t; +# endif +# elif defined(__WATCOMC__) +# if !defined(_INT64_T_DECLARED) && !defined(_INT64_T) +typedef signed __int64 int64_t; +# endif +# if !defined(_UINT64_T_DECLARED) && !defined(_UINT64_T) +typedef unsigned __int64 uint64_t; +# endif +# elif defined(IPRT_STDINT_USE_STRUCT_FOR_64_BIT_TYPES) +# if !defined(_INT64_T_DECLARED) && !defined(_INT64_T) +typedef struct { uint32_t lo; int32_t hi; } int64_t; +# endif +# if !defined(_UINT64_T_DECLARED) && !defined(_UINT64_T) +typedef struct { uint32_t lo; uint32_t hi; } uint64_t; +# endif +# else /* Use long long for 64-bit types */ +# if !defined(_INT64_T_DECLARED) && !defined(_INT64_T) +typedef signed long long int64_t; +# endif +# if !defined(_UINT64_T_DECLARED) && !defined(_UINT64_T) +typedef unsigned long long uint64_t; +# endif +# endif + + /* max integer types */ +# if !defined(_INTMAX_T_DECLARED) && !defined(_INTMAX_T) +typedef int64_t intmax_t; +# endif +# if !defined(_UINTMAX_T_DECLARED) && !defined(_UINTMAX_T) +typedef uint64_t uintmax_t; +# endif + + /* smallest minimum-width integer types - assumes to be the same as above! */ +typedef int8_t int_least8_t; +typedef uint8_t uint_least8_t; +# define INT_LEAST8_MIN INT8_MIN +# define INT_LEAST8_MAX INT8_MAX +# define UINT_LEAST8_MAX UINT8_MAX +typedef int16_t int_least16_t; +typedef uint16_t uint_least16_t; +# define INT_LEAST16_MIN INT16_MIN +# define INT_LEAST16_MAX INT16_MAX +# define UINT_LEAST16_MAX UINT16_MAX +typedef int32_t int_least32_t; +typedef uint32_t uint_least32_t; +# define INT_LEAST32_MIN INT32_MIN +# define INT_LEAST32_MAX INT32_MAX +# define UINT_LEAST32_MAX UINT32_MAX +typedef int64_t int_least64_t; +typedef uint64_t uint_least64_t; +# define INT_LEAST64_MIN INT64_MIN +# define INT_LEAST64_MAX INT64_MAX +# define UINT_LEAST64_MAX UINT64_MAX + + /* fastest minimum-width integer types */ +typedef signed char int_fast8_t; +typedef unsigned char uint_fast8_t; +# define INT_FAST8_MIN INT8_MIN +# define INT_FAST8_MAX INT8_MAX +# define UINT_FAST8_MAX UINT8_MAX +typedef signed int int_fast16_t; +typedef unsigned int uint_fast16_t; +# if ARCH_BITS == 16 +# define INT_FAST16_MIN INT16_MIN +# define INT_FAST16_MAX INT16_MAX +# define UINT_FAST16_MAX UINT16_MAX +# else +# define INT_FAST16_MIN INT32_MIN +# define INT_FAST16_MAX INT32_MAX +# define UINT_FAST16_MAX UINT32_MAX +# endif +typedef int32_t int_fast32_t; +typedef uint32_t uint_fast32_t; +# define INT_FAST32_MIN INT32_MIN +# define INT_FAST32_MAX INT32_MAX +# define UINT_FAST32_MAX UINT32_MAX +typedef int64_t int_fast64_t; +typedef uint64_t uint_fast64_t; +# define INT_FAST64_MIN INT64_MIN +# define INT_FAST64_MAX INT64_MAX +# define UINT_FAST64_MAX UINT64_MAX + +# else +# error "PORTME: Add architecture. Don't forget to check the [U]INTx_C() and [U]INTMAX_MIN/MAX macros." +# endif + +# endif /* !linux kernel or stuff */ + + /* pointer <-> integer types */ +# if (!defined(_MSC_VER) && !defined(__WATCOMC__)) || defined(DOXYGEN_RUNNING) +# if ARCH_BITS == 32 \ + || defined(RT_OS_LINUX) \ + || defined(RT_OS_FREEBSD) +# if !defined(_INTPTR_T_DECLARED) && !defined(_INTPTR_T) && !defined(_INTPTR_T_DEFINED) +typedef signed long intptr_t; +# endif +# if !defined(_UINTPTR_T_DECLARED) && !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) +typedef unsigned long uintptr_t; +# endif +# else +# if !defined(_INTPTR_T_DECLARED) && !defined(_INTPTR_T) && !defined(_INTPTR_T_DEFINED) +typedef int64_t intptr_t; +# endif +# if !defined(_UINTPTR_T_DECLARED) && !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) +typedef uint64_t uintptr_t; +# endif +# endif +# endif /* !_MSC_VER */ + +#endif /* no system stdint.h */ + + +/* + * Make sure the [U]INTx_C(c) macros are present. + * For In C++ source the system stdint.h may have skipped these if it was + * included before we managed to define __STDC_CONSTANT_MACROS. (Kludge alert!) + */ +#if !defined(INT8_C) \ + || !defined(INT16_C) \ + || !defined(INT32_C) \ + || !defined(INT64_C) \ + || !defined(INTMAX_C) \ + || !defined(UINT8_C) \ + || !defined(UINT16_C) \ + || !defined(UINT32_C) \ + || !defined(UINT64_C) \ + || !defined(UINTMAX_C) +# define INT8_C(Value) (Value) +# define INT16_C(Value) (Value) +# define UINT8_C(Value) (Value) +# define UINT16_C(Value) (Value) +# if ARCH_BITS != 16 +# define INT32_C(Value) (Value) +# define UINT32_C(Value) (Value ## U) +# define INT64_C(Value) (Value ## LL) +# define UINT64_C(Value) (Value ## ULL) +# else +# define INT32_C(Value) (Value ## L) +# define UINT32_C(Value) (Value ## UL) +# define INT64_C(Value) (Value ## LL) +# define UINT64_C(Value) (Value ## ULL) +# endif +# define INTMAX_C(Value) INT64_C(Value) +# define UINTMAX_C(Value) UINT64_C(Value) +#endif + + +/* + * Make sure the INTx_MIN and [U]INTx_MAX macros are present. + * For In C++ source the system stdint.h may have skipped these if it was + * included before we managed to define __STDC_LIMIT_MACROS. (Kludge alert!) + */ +#if !defined(INT8_MIN) \ + || !defined(INT16_MIN) \ + || !defined(INT32_MIN) \ + || !defined(INT64_MIN) \ + || !defined(INT8_MAX) \ + || !defined(INT16_MAX) \ + || !defined(INT32_MAX) \ + || !defined(INT64_MAX) \ + || !defined(UINT8_MAX) \ + || !defined(UINT16_MAX) \ + || !defined(UINT32_MAX) \ + || !defined(UINT64_MAX) +# define INT8_MIN (INT8_C(-0x7f) - 1) +# define INT16_MIN (INT16_C(-0x7fff) - 1) +# define INT32_MIN (INT32_C(-0x7fffffff) - 1) +# define INT64_MIN (INT64_C(-0x7fffffffffffffff) - 1) +# define INT8_MAX INT8_C(0x7f) +# define INT16_MAX INT16_C(0x7fff) +# define INT32_MAX INT32_C(0x7fffffff) +# define INT64_MAX INT64_C(0x7fffffffffffffff) +# define UINT8_MAX UINT8_C(0xff) +# define UINT16_MAX UINT16_C(0xffff) +# define UINT32_MAX UINT32_C(0xffffffff) +# define UINT64_MAX UINT64_C(0xffffffffffffffff) + +# define INTMAX_MIN INT64_MIN +# define INTMAX_MAX INT64_MAX +# define UINTMAX_MAX UINT64_MAX +#endif + +#endif /* !IPRT_INCLUDED_stdint_h */ + diff --git a/include/iprt/strcache.h b/include/iprt/strcache.h new file mode 100644 index 00000000..a94fa616 --- /dev/null +++ b/include/iprt/strcache.h @@ -0,0 +1,201 @@ +/* $Id: strcache.h $ */ +/** @file + * IPRT - String Cache, stub implementation. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_strcache_h +#define IPRT_INCLUDED_strcache_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + + +/** + * Create a new string cache. + * + * @returns IPRT status code + * + * @param phStrCache Where to return the string cache handle. + * @param pszName The name of the cache (for debug purposes). + */ +RTDECL(int) RTStrCacheCreate(PRTSTRCACHE phStrCache, const char *pszName); + + +/** + * Destroys a string cache. + * + * This will cause all strings in the cache to be released and thus become + * invalid. + * + * @returns IPRT status. + * + * @param hStrCache Handle to the string cache. The nil and default + * handles are ignored quietly (VINF_SUCCESS). + */ +RTDECL(int) RTStrCacheDestroy(RTSTRCACHE hStrCache); + + +/** + * Enters a string into the cache. + * + * @returns Pointer to a read-only copy of the string. + * + * @param hStrCache Handle to the string cache. + * @param pchString Pointer to a string. This does not need to be + * zero terminated, but must not contain any zero + * characters. + * @param cchString The number of characters (bytes) to enter. + * + * @remarks It is implementation dependent whether the returned string pointer + * differs when entering the same string twice. + */ +RTDECL(const char *) RTStrCacheEnterN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString); + +/** + * Enters a string into the cache. + * + * @returns Pointer to a read-only copy of the string. + * + * @param hStrCache Handle to the string cache. + * @param psz Pointer to a zero terminated string. + * + * @remarks See RTStrCacheEnterN. + */ +RTDECL(const char *) RTStrCacheEnter(RTSTRCACHE hStrCache, const char *psz); + + +/** + * Enters a string into the cache in lower cased form. + * + * @returns Pointer to a read-only lower cased copy of the string. + * + * @param hStrCache Handle to the string cache. + * @param pchString Pointer to a string. This does not need to be + * zero terminated, but must not contain any zero + * characters. + * @param cchString The number of characters (bytes) to enter. + * + * @remarks It is implementation dependent whether the returned string pointer + * differs when entering the same string twice. + */ +RTDECL(const char *) RTStrCacheEnterLowerN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString); + +/** + * Enters a string into the cache in lower cased form. + * + * @returns Pointer to a read-only lower cased copy of the string. + * + * @param hStrCache Handle to the string cache. + * @param psz Pointer to a zero terminated string. + * + * @remarks See RTStrCacheEnterN. + */ +RTDECL(const char *) RTStrCacheEnterLower(RTSTRCACHE hStrCache, const char *psz); + + +/** + * Retains a reference to a string. + * + * @returns The new reference count. UINT32_MAX is returned if the string + * pointer is invalid. + */ +RTDECL(uint32_t) RTStrCacheRetain(const char *psz); + +/** + * Releases a reference to a string. + * + * @returns The new reference count. + * UINT32_MAX is returned if the string pointer is invalid. + * + * @param hStrCache Handle to the string cache. NIL is NOT allowed. + * @param psz Pointer to a cached string. + */ +RTDECL(uint32_t) RTStrCacheRelease(RTSTRCACHE hStrCache, const char *psz); + +/** + * Gets the string length of a cache entry. + * + * @returns The string length. 0 if the string is invalid (asserted). + * + * @param psz Pointer to a cached string. + */ +RTDECL(size_t) RTStrCacheLength(const char *psz); + + +/** + * Gets cache statistics. + * + * All parameters, except @a hStrCache, are optional and can be NULL. + * + * @returns Number of strings, UINT32_MAX on failure (or not supported). + * @param hStrCache Handle to the string cache. + * @param pcbStrings The number of string bytes (including + * terminators) . + * @param pcbChunks Amount of memory we've allocated for the + * internal allocator. + * @param pcbBigEntries Amount of memory we've allocated off the heap + * for really long strings that doesn't fit in the + * internal allocator. + * @param pcHashCollisions Number of hash table insert collisions. + * @param pcHashCollisions2 Number of hash table secondary insert + * collisions. + * @param pcHashInserts Number of hash table inserts. + * @param pcRehashes The number of rehashes. + * + * @remarks This is not a stable interface as it needs to reflect the cache + * implementation. + */ +RTDECL(uint32_t) RTStrCacheGetStats(RTSTRCACHE hStrCache, size_t *pcbStrings, size_t *pcbChunks, size_t *pcbBigEntries, + uint32_t *pcHashCollisions, uint32_t *pcHashCollisions2, uint32_t *pcHashInserts, + uint32_t *pcRehashes); + +/** + * Indicates whether this a real string cache or a cheap place holder. + * + * A real string cache will return the same address when a string is added + * multiple times. + * + * @returns true / false. + */ +RTDECL(bool) RTStrCacheIsRealImpl(void); + + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_strcache_h */ + diff --git a/include/iprt/stream.h b/include/iprt/stream.h new file mode 100644 index 00000000..927fd63a --- /dev/null +++ b/include/iprt/stream.h @@ -0,0 +1,542 @@ +/** @file + * IPRT - I/O Stream. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_stream_h +#define IPRT_INCLUDED_stream_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_stream RTStrm - File Streams + * @ingroup grp_rt + * @{ + */ + +#ifndef IPRT_INCLUDED_message_h +/** Pointer to a stream. */ +typedef struct RTSTREAM *PRTSTREAM; +#endif + +/** Pointer to the standard input stream. */ +extern RTDATADECL(PRTSTREAM) g_pStdIn; + +/** Pointer to the standard error stream. */ +extern RTDATADECL(PRTSTREAM) g_pStdErr; + +/** Pointer to the standard output stream. */ +extern RTDATADECL(PRTSTREAM) g_pStdOut; + + +/** + * Opens a file stream. + * + * @returns iprt status code. + * @param pszFilename Path to the file to open. + * @param pszMode The open mode. See fopen() standard. + * Format: [+][b|t][x][e|N|E] + * - 'a': Open or create file and writes + * append tos it. + * - 'r': Open existing file and read from it. + * - 'w': Open or truncate existing file and write + * to it. + * - '+': Open for both read and write access. + * - 'b' / 't': binary / text + * - 'x': exclusively create, no open. Only + * possible with 'w'. + * - 'e' / 'N': No inherit on exec. (The 'e' is + * how Linux and FreeBSD expresses this, the + * latter is Visual C++). + * @param ppStream Where to store the opened stream. + */ +RTR3DECL(int) RTStrmOpen(const char *pszFilename, const char *pszMode, PRTSTREAM *ppStream); + +/** + * Opens a file stream. + * + * @returns iprt status code. + * @param pszMode The open mode. See fopen() standard. + * Format: [+][b|t][x][e|N|E] + * - 'a': Open or create file and writes + * append tos it. + * - 'r': Open existing file and read from it. + * - 'w': Open or truncate existing file and write + * to it. + * - '+': Open for both read and write access. + * - 'b' / 't': binary / text + * - 'x': exclusively create, no open. Only + * possible with 'w'. + * - 'e' / 'N': No inherit on exec. (The 'e' is + * how Linux and FreeBSD expresses this, the + * latter is Visual C++). + * @param ppStream Where to store the opened stream. + * @param pszFilenameFmt Filename path format string. + * @param args Arguments to the format string. + */ +RTR3DECL(int) RTStrmOpenFV(const char *pszMode, PRTSTREAM *ppStream, const char *pszFilenameFmt, + va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Opens a file stream. + * + * @returns iprt status code. + * @param pszMode The open mode. See fopen() standard. + * Format: [+][b|t][x][e|N|E] + * - 'a': Open or create file and writes + * append tos it. + * - 'r': Open existing file and read from it. + * - 'w': Open or truncate existing file and write + * to it. + * - '+': Open for both read and write access. + * - 'b' / 't': binary / text + * - 'x': exclusively create, no open. Only + * possible with 'w'. + * - 'e' / 'N': No inherit on exec. (The 'e' is + * how Linux and FreeBSD expresses this, the + * latter is Visual C++). + * @param ppStream Where to store the opened stream. + * @param pszFilenameFmt Filename path format string. + * @param ... Arguments to the format string. + */ +RTR3DECL(int) RTStrmOpenF(const char *pszMode, PRTSTREAM *ppStream, const char *pszFilenameFmt, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Opens a file stream for a RTFILE handle, taking ownership of the handle. + * + * @returns iprt status code. + * @param hFile The file handle to use. On success, handle + * ownership is transfered to the stream and it will be + * closed when the stream closes. + * @param pszMode The open mode, accept the same as RTStrOpen and + * friends however it is only used to figure out what + * we can do with the handle. + * @param fFlags Reserved, must be zero. + * @param ppStream Where to store the opened stream. + */ +RTR3DECL(int) RTStrmOpenFileHandle(RTFILE hFile, const char *pszMode, uint32_t fFlags, PRTSTREAM *ppStream); + +/** + * Queries the file handle backing the stream. + * + * @returns iprt status code. + * @retval VERR_NOT_AVAILABLE if the stream has no valid handle associated with + * it. + * + * @param pStream The stream. + * @param phFile Where to return the file handle. This should not be + * closed! + */ +RTR3DECL(int) RTStrmQueryFileHandle(PRTSTREAM pStream, PRTFILE phFile); + +/** + * Closes the specified stream. + * + * @returns iprt status code. + * @param pStream The stream to close. + * + * @note The stream will be closed and freed even when failure is returned. + * It cannot be used again after this call. The error status is only + * to indicate that the flushing of buffers or the closing of the + * underlying file handle failed. + */ +RTR3DECL(int) RTStrmClose(PRTSTREAM pStream); + +/** + * Get the pending error of the stream. + * + * @returns iprt status code. of the stream. + * @param pStream The stream. + */ +RTR3DECL(int) RTStrmError(PRTSTREAM pStream); + +/** + * Clears stream error condition. + * + * All stream operations save RTStrmClose and this will fail + * while an error is asserted on the stream + * + * @returns iprt status code. + * @param pStream The stream. + */ +RTR3DECL(int) RTStrmClearError(PRTSTREAM pStream); + +/** + * Changes the stream mode. + * + * @returns iprt status code. + * @param pStream The stream. + * @param fBinary The desired binary (@c true) / text mode (@c false). + * Pass -1 to leave it unchanged. + * @param fCurrentCodeSet Whether converting the stream from UTF-8 to the + * current code set is desired (@c true) or not (@c + * false). Pass -1 to leave this property unchanged. + */ +RTR3DECL(int) RTStrmSetMode(PRTSTREAM pStream, int fBinary, int fCurrentCodeSet); + +/** Stream buffering modes. */ +typedef enum RTSTRMBUFMODE +{ + RTSTRMBUFMODE_INVALID = 0, + RTSTRMBUFMODE_FULL, /**< Full buffering. */ + RTSTRMBUFMODE_LINE, /**< Line buffering. On Windows this could be the same as RTSTRMBUFMODE_FULL. */ + RTSTRMBUFMODE_UNBUFFERED, /**< No buffering. */ + RTSTRMBUFMODE_END, + RTSTRMBUFMODE_32BIT_HACK = 0x7fffffff +} RTSTRMBUFMODE; + +/** + * Changes the stream buffering mode. + * + * @returns iprt status code. + * @param pStream The stream. + * @param enmBufMode The new buffering mode. + */ +RTR3DECL(int) RTStrmSetBufferingMode(PRTSTREAM pStream, RTSTRMBUFMODE enmBufMode); + +/** + * Returns the current echo mode. + * + * This works only for standard input streams. + * + * @returns iprt status code. + * @retval VERR_INVALID_FUNCTION if not a TTY. + * @param pStream The stream. + * @param pfEchoChars Where to store the flag whether typed characters are echoed. + */ +RTR3DECL(int) RTStrmInputGetEchoChars(PRTSTREAM pStream, bool *pfEchoChars); + +/** + * Changes the behavior for echoing inpit characters on the command line. + * + * This works only for standard input streams. + * + * @returns iprt status code. + * @retval VERR_INVALID_FUNCTION if not a TTY. + * @param pStream The stream. + * @param fEchoChars Flag whether echoing typed characters is wanted. + */ +RTR3DECL(int) RTStrmInputSetEchoChars(PRTSTREAM pStream, bool fEchoChars); + +/** + * Checks if this is a terminal (TTY) or not. + * + * @returns true if it is, false if it isn't or the stream isn't valid. + * @param pStream The stream. + */ +RTR3DECL(bool) RTStrmIsTerminal(PRTSTREAM pStream); + +/** + * Gets the width of the terminal the stream is associated with. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if not connected to a terminal. + * @param pStream The stream. + * @param pcchWidth Where to return the width. This will never be zero + * and always be set, even on error. + */ +RTR3DECL(int) RTStrmQueryTerminalWidth(PRTSTREAM pStream, uint32_t *pcchWidth); + +/** + * Rewinds the stream. + * + * Stream errors will be reset on success. + * + * @returns IPRT status code. + * + * @param pStream The stream. + * + * @remarks Not all streams are rewindable and that behavior is currently + * undefined for those. + */ +RTR3DECL(int) RTStrmRewind(PRTSTREAM pStream); + +/** + * Changes the file position. + * + * @returns IPRT status code. + * + * @param pStream The stream. + * @param off The seek offset. + * @param uMethod Seek method, i.e. one of the RTFILE_SEEK_* defines. + * + * @remarks Not all streams are seekable and that behavior is currently + * undefined for those. + */ +RTR3DECL(int) RTStrmSeek(PRTSTREAM pStream, RTFOFF off, uint32_t uMethod); + +/** + * Tells the stream position. + * + * @returns Stream position or IPRT error status. Non-negative numbers are + * stream positions, while negative numbers are IPRT error stauses. + * + * @param pStream The stream. + * + * @remarks Not all streams have a position and that behavior is currently + * undefined for those. + */ +RTR3DECL(RTFOFF) RTStrmTell(PRTSTREAM pStream); + +/** + * Reads from a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pvBuf Where to put the read bits. + * Must be cbRead bytes or more. + * @param cbToRead Number of bytes to read. + * @param pcbRead Where to store the number of bytes actually read. + * If NULL cbRead bytes are read or an error is returned. + */ +RTR3DECL(int) RTStrmReadEx(PRTSTREAM pStream, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Writes to a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pvBuf Where to get the bits to write from. + * @param cbToWrite Number of bytes to write. + * @param pcbWritten Where to store the number of bytes actually written. + * If NULL cbWrite bytes are written or an error is returned. + */ +RTR3DECL(int) RTStrmWriteEx(PRTSTREAM pStream, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Reads from a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pvBuf Where to put the read bits. + * Must be cbRead bytes or more. + * @param cbToRead Number of bytes to read. + */ +DECLINLINE(int) RTStrmRead(PRTSTREAM pStream, void *pvBuf, size_t cbToRead) +{ + return RTStrmReadEx(pStream, pvBuf, cbToRead, NULL); +} + +/** + * Writes to a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pvBuf Where to get the bits to write from. + * @param cbToWrite Number of bytes to write. + */ +DECLINLINE(int) RTStrmWrite(PRTSTREAM pStream, const void *pvBuf, size_t cbToWrite) +{ + return RTStrmWriteEx(pStream, pvBuf, cbToWrite, NULL); +} + +/** + * Reads a character from a file stream. + * + * @returns The char as an unsigned char cast to int. + * @returns -1 on failure. + * @param pStream The stream. + */ +RTR3DECL(int) RTStrmGetCh(PRTSTREAM pStream); + +/** + * Writes a character to a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param ch The char to write. + */ +RTR3DECL(int) RTStrmPutCh(PRTSTREAM pStream, int ch); + +/** + * Writes a string to a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pszString The string to write. + * No newlines or anything are appended or prepended. + * The terminating '\\0' is not written, of course. + */ +RTR3DECL(int) RTStrmPutStr(PRTSTREAM pStream, const char *pszString); + +/** + * Reads a line from a file stream. + * + * A line ends with a '\\n', '\\r\\n', '\\0' or the end of the file. + * + * @returns iprt status code. + * @retval VINF_BUFFER_OVERFLOW if the buffer wasn't big enough to read an + * entire line. + * @retval VERR_BUFFER_OVERFLOW if a lone '\\r' was encountered at the end of + * the buffer and we ended up dropping the following character. + * + * @param pStream The stream. + * @param pszString Where to store the line. + * The line will *NOT* contain any '\\n'. + * @param cbString The size of the string buffer. + */ +RTR3DECL(int) RTStrmGetLine(PRTSTREAM pStream, char *pszString, size_t cbString); + +/** + * Flushes a stream. + * + * @returns iprt status code. + * @param pStream The stream to flush. + */ +RTR3DECL(int) RTStrmFlush(PRTSTREAM pStream); + +/** + * Prints a formatted string to the specified stream. + * + * @returns Number of bytes printed. + * @param pStream The stream to print to. + * @param pszFormat Runtime format string. + * @param ... Arguments specified by pszFormat. + */ +RTR3DECL(int) RTStrmPrintf(PRTSTREAM pStream, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Prints a formatted string to the specified stream. + * + * @returns Number of bytes printed. + * @param pStream The stream to print to. + * @param pszFormat Runtime format string. + * @param args Arguments specified by pszFormat. + */ +RTR3DECL(int) RTStrmPrintfV(PRTSTREAM pStream, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Prints a formatted string to the specified stream, performing wrapping of + * lines considered too long. + * + * If the stream is to a terminal, the terminal width is used as the max line + * width. Otherwise, the width is taken from @a fFlags + * (RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_MASK / + * RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_SHIFT), defaulting to 80 if zero. + * + * @returns Low 16 bits is the line offset, high 16 bits the number of lines + * outputted. Apply RTSTRMWRAPPED_F_LINE_OFFSET_MASK to the value and + * it can be passed via @a fFlags to the next invocation (not necessary + * if all format strings ends with a newline). + * Negative values are IPRT error status codes. + * @param pStream The stream to print to. + * @param fFlags RTSTRMWRAPPED_F_XXX - flags, configuration and state. + * @param pszFormat Runtime format string. + * @param ... Arguments specified by pszFormat. + * @sa RTStrmWrappedPrintfV, RTStrmPrintf, RTStrmPrintfV + */ +RTDECL(int32_t) RTStrmWrappedPrintf(PRTSTREAM pStream, uint32_t fFlags, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Prints a formatted string to the specified stream, performing wrapping of + * lines considered too long. + * + * If the stream is to a terminal, the terminal width is used as the max line + * width. Otherwise, the width is taken from @a fFlags + * (RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_MASK / + * RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_SHIFT), defaulting to 80 if zero. + * + * @returns Low 16 bits is the line offset, high 16 bits the number of lines + * outputted. Apply RTSTRMWRAPPED_F_LINE_OFFSET_MASK to the value and + * it can be passed via @a fFlags to the next invocation (not necessary + * if all format strings ends with a newline). + * Negative values are IPRT error status codes. + * @param pStream The stream to print to. + * @param fFlags RTSTRMWRAPPED_F_XXX - flags, configuration and state. + * @param pszFormat Runtime format string. + * @param va Arguments specified by pszFormat. + * @sa RTStrmWrappedPrintf, RTStrmPrintf, RTStrmPrintfV + */ +RTDECL(int32_t) RTStrmWrappedPrintfV(PRTSTREAM pStream, uint32_t fFlags, const char *pszFormat, + va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** @name RTSTRMWRAPPED_F_XXX - Flags for RTStrmWrappedPrintf & + * RTStrmWrappedPrintfV. + * @{ */ +/** The current line offset mask. + * This should be used to passed the line off state from one call to the next + * when printing incomplete lines. If all format strings ends with a newline, + * this is not necessary. */ +#define RTSTRMWRAPPED_F_LINE_OFFSET_MASK UINT32_C(0x00000fff) +/** The non-terminal width mask. Defaults to 80 if not specified (zero). */ +#define RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_MASK UINT32_C(0x000ff000) +/** The non-terminal width shift. */ +#define RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_SHIFT 12 +/** The hanging indent level mask - defaults to 4 if zero. + * Used when RTSTRMWRAPPED_F_HANGING_INDENT is set. */ +#define RTSTRMWRAPPED_F_HANGING_INDENT_MASK UINT32_C(0x01f00000) +/** The hanging indent level shift. */ +#define RTSTRMWRAPPED_F_HANGING_INDENT_SHIFT 20 +/** Hanging indent. Used for command synopsis and such. */ +#define RTSTRMWRAPPED_F_HANGING_INDENT UINT32_C(0x80000000) +/** @} */ + +/** + * Dumper vprintf-like function outputting to a stream. + * + * @param pvUser The stream to print to. NULL means standard output. + * @param pszFormat Runtime format string. + * @param va Arguments specified by pszFormat. + */ +RTR3DECL(void) RTStrmDumpPrintfV(void *pvUser, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Prints a formatted string to the standard output stream (g_pStdOut). + * + * @returns Number of bytes printed. + * @param pszFormat Runtime format string. + * @param ... Arguments specified by pszFormat. + */ +RTR3DECL(int) RTPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Prints a formatted string to the standard output stream (g_pStdOut). + * + * @returns Number of bytes printed. + * @param pszFormat Runtime format string. + * @param args Arguments specified by pszFormat. + */ +RTR3DECL(int) RTPrintfV(const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(1, 0); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_stream_h */ + diff --git a/include/iprt/string.h b/include/iprt/string.h new file mode 100644 index 00000000..d7b78bf3 --- /dev/null +++ b/include/iprt/string.h @@ -0,0 +1,3725 @@ +/** @file + * IPRT - String Manipulation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_string_h +#define IPRT_INCLUDED_string_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include /* for VINF_SUCCESS */ +#if defined(RT_OS_LINUX) && defined(__KERNEL__) + /* no C++ hacks ('new' etc) here anymore! */ +# include + +#elif defined(IN_XF86_MODULE) && !defined(NO_ANSIC) + RT_C_DECLS_BEGIN +# include "xf86_ansic.h" + RT_C_DECLS_END + +#elif defined(RT_OS_FREEBSD) && defined(_KERNEL) + RT_C_DECLS_BEGIN +# include + RT_C_DECLS_END + +#elif defined(RT_OS_NETBSD) && defined(_KERNEL) + RT_C_DECLS_BEGIN +# include + RT_C_DECLS_END + +#elif defined(RT_OS_SOLARIS) && defined(_KERNEL) + /* + * Same case as with FreeBSD kernel: + * The string.h stuff clashes with sys/system.h + * ffs = find first set bit. + */ +# define ffs ffs_string_h +# define fls fls_string_h +# include +# undef fls +# undef ffs +# undef strpbrk + +#else +# include +#endif + +/* + * Supply prototypes for standard string functions provided by + * IPRT instead of the operating environment. + */ +#if defined(RT_OS_DARWIN) && defined(KERNEL) +RT_C_DECLS_BEGIN +void *memchr(const void *pv, int ch, size_t cb); +char *strpbrk(const char *pszStr, const char *pszChars); +RT_C_DECLS_END +#endif + +#if defined(RT_OS_FREEBSD) && defined(_KERNEL) +RT_C_DECLS_BEGIN +char *strpbrk(const char *pszStr, const char *pszChars); +RT_C_DECLS_END +#endif + +#if defined(RT_OS_NETBSD) && defined(_KERNEL) +RT_C_DECLS_BEGIN +char *strpbrk(const char *pszStr, const char *pszChars); +RT_C_DECLS_END +#endif + +#if (defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)) && !defined(IPRT_NO_CRT) +RT_C_DECLS_BEGIN +# if !defined(RT_OS_DARWIN) || RT_CLANG_PREREQ(7 /* whatever post gcc-4.2 */, 0) +RTDECL(void *) mempcpy(void *pvDst, const void *pvSrc, size_t cb); +# else +void *mempcpy(void *pvDst, const void *pvSrc, size_t cb); +# endif +RT_C_DECLS_END +#endif + +#if (!defined(RT_OS_LINUX) || !defined(_GNU_SOURCE)) \ + && (!defined(RT_OS_OS2) || !defined(_GNU_SOURCE)) \ + && !defined(RT_OS_FREEBSD) \ + && !defined(RT_OS_NETBSD) +RT_C_DECLS_BEGIN +void *memrchr(const void *pv, int ch, size_t cb); +RT_C_DECLS_END +#endif + + +/** @def RT_USE_RTC_3629 + * When defined the UTF-8 range will stop at 0x10ffff. If not defined, the + * range stops at 0x7fffffff. + * @remarks Must be defined both when building and using the IPRT. */ +#ifdef DOXYGEN_RUNNING +# define RT_USE_RTC_3629 +#endif + + +/** + * Byte zero the specified object. + * + * This will use sizeof(Obj) to figure the size and will call memset, bzero + * or some compiler intrinsic to perform the actual zeroing. + * + * @param Obj The object to zero. Make sure to dereference pointers. + * + * @remarks Because the macro may use memset it has been placed in string.h + * instead of cdefs.h to avoid build issues because someone forgot + * to include this header. + * + * @ingroup grp_rt_cdefs + */ +#define RT_ZERO(Obj) RT_BZERO(&(Obj), sizeof(Obj)) + +/** + * Byte zero the specified memory area. + * + * This will call memset, bzero or some compiler intrinsic to clear the + * specified bytes of memory. + * + * @param pv Pointer to the memory. + * @param cb The number of bytes to clear. Please, don't pass 0. + * + * @remarks Because the macro may use memset it has been placed in string.h + * instead of cdefs.h to avoid build issues because someone forgot + * to include this header. + * + * @ingroup grp_rt_cdefs + */ +#define RT_BZERO(pv, cb) do { memset((pv), 0, cb); } while (0) + + +/** + * For copying a volatile variable to a non-volatile one. + * @param a_Dst The non-volatile destination variable. + * @param a_VolatileSrc The volatile source variable / dereferenced pointer. + */ +#define RT_COPY_VOLATILE(a_Dst, a_VolatileSrc) \ + do { \ + void const volatile *a_pvVolatileSrc_BCopy_Volatile = &(a_VolatileSrc); \ + AssertCompile(sizeof(a_Dst) == sizeof(a_VolatileSrc)); \ + memcpy(&(a_Dst), (void const *)a_pvVolatileSrc_BCopy_Volatile, sizeof(a_Dst)); \ + } while (0) + +/** + * For copy a number of bytes from a volatile buffer to a non-volatile one. + * + * @param a_pDst Pointer to the destination buffer. + * @param a_pVolatileSrc Pointer to the volatile source buffer. + * @param a_cbToCopy Number of bytes to copy. + */ +#define RT_BCOPY_VOLATILE(a_pDst, a_pVolatileSrc, a_cbToCopy) \ + do { \ + void const volatile *a_pvVolatileSrc_BCopy_Volatile = (a_pVolatileSrc); \ + memcpy((a_pDst), (void const *)a_pvVolatileSrc_BCopy_Volatile, (a_cbToCopy)); \ + } while (0) + + +/** @defgroup grp_rt_str RTStr - String Manipulation + * Mostly UTF-8 related helpers where the standard string functions won't do. + * @ingroup grp_rt + * @{ + */ + +RT_C_DECLS_BEGIN + + +/** + * The maximum string length. + */ +#define RTSTR_MAX (~(size_t)0) + + +/** @def RTSTR_TAG + * The default allocation tag used by the RTStr allocation APIs. + * + * When not defined before the inclusion of iprt/string.h, this will default to + * the pointer to the current file name. The string API will make of use of + * this as pointer to a volatile but read-only string. + */ +#if !defined(RTSTR_TAG) || defined(DOXYGEN_RUNNING) +# define RTSTR_TAG (__FILE__) +#endif + + +#ifdef IN_RING3 + +/** + * Allocates tmp buffer with default tag, translates pszString from UTF8 to + * current codepage. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated native CP string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to convert. + */ +#define RTStrUtf8ToCurrentCP(ppszString, pszString) RTStrUtf8ToCurrentCPTag((ppszString), (pszString), RTSTR_TAG) + +/** + * Allocates tmp buffer with custom tag, translates pszString from UTF-8 to + * current codepage. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated native CP string. + * The returned pointer must be freed using + * RTStrFree()., const char *pszTag + * @param pszString UTF-8 string to convert. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR3DECL(int) RTStrUtf8ToCurrentCPTag(char **ppszString, const char *pszString, const char *pszTag); + +/** + * Allocates tmp buffer with default tag, translates pszString from UTF-8 to + * current codepage, extended version. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated native CP string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + */ +#define RTStrUtf8ToCurrentCPEx(ppszString, pszString, cchString) \ + RTStrUtf8ToCurrentCPExTag((ppszString), (pszString), (cchString), RTSTR_TAG) + +/** + * Allocates tmp buffer with custom tag, translates pszString from UTF8 to + * current codepage. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated native CP string. + * The returned pointer must be freed using + * RTStrFree()., const char *pszTag + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR3DECL(int) RTStrUtf8ToCurrentCPExTag(char **ppszString, const char *pszString, size_t cchString, const char *pszTag); + +/** + * Allocates tmp buffer, translates pszString from current codepage to UTF-8. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString Native string to convert. + */ +#define RTStrCurrentCPToUtf8(ppszString, pszString) RTStrCurrentCPToUtf8Tag((ppszString), (pszString), RTSTR_TAG) + +/** + * Allocates tmp buffer, translates pszString from current codepage to UTF-8. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString Native string to convert. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR3DECL(int) RTStrCurrentCPToUtf8Tag(char **ppszString, const char *pszString, const char *pszTag); + +/** + * Allocates tmp buffer, translates pszString from console codepage to UTF-8. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString Native string to convert. + */ +#define RTStrConsoleCPToUtf8(ppszString, pszString) RTStrConsoleCPToUtf8Tag((ppszString), (pszString), RTSTR_TAG) + +/** + * Allocates tmp buffer, translates pszString from console codepage to UTF-8. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString Native string to convert. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR3DECL(int) RTStrConsoleCPToUtf8Tag(char **ppszString, const char *pszString, const char *pszTag); + +#endif /* IN_RING3 */ + +/** + * Free string allocated by any of the non-UCS-2 string functions. + * + * @returns iprt status code. + * @param pszString Pointer to buffer with string to free. + * NULL is accepted. + */ +RTDECL(void) RTStrFree(char *pszString); + +/** + * Allocates a new copy of the given UTF-8 string (default tag). + * + * @returns Pointer to the allocated UTF-8 string. + * @param pszString UTF-8 string to duplicate. + */ +#define RTStrDup(pszString) RTStrDupTag((pszString), RTSTR_TAG) + +/** + * Allocates a new copy of the given UTF-8 string (custom tag). + * + * @returns Pointer to the allocated UTF-8 string. + * @param pszString UTF-8 string to duplicate. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(char *) RTStrDupTag(const char *pszString, const char *pszTag); + +/** + * Allocates a new copy of the given UTF-8 string (default tag). + * + * @returns iprt status code. + * @param ppszCopy Receives pointer of the allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to duplicate. + */ +#define RTStrDupEx(ppszCopy, pszString) RTStrDupExTag((ppszCopy), (pszString), RTSTR_TAG) + +/** + * Allocates a new copy of the given UTF-8 string (custom tag). + * + * @returns iprt status code. + * @param ppszCopy Receives pointer of the allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to duplicate. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrDupExTag(char **ppszCopy, const char *pszString, const char *pszTag); + +/** + * Allocates a new copy of the given UTF-8 substring (default tag). + * + * @returns Pointer to the allocated UTF-8 substring. + * @param pszString UTF-8 string to duplicate. + * @param cchMax The max number of chars to duplicate, not counting + * the terminator. + */ +#define RTStrDupN(pszString, cchMax) RTStrDupNTag((pszString), (cchMax), RTSTR_TAG) + +/** + * Allocates a new copy of the given UTF-8 substring (custom tag). + * + * @returns Pointer to the allocated UTF-8 substring. + * @param pszString UTF-8 string to duplicate. + * @param cchMax The max number of chars to duplicate, not counting + * the terminator. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(char *) RTStrDupNTag(const char *pszString, size_t cchMax, const char *pszTag); + +/** + * Allocates a new copy of the given UTF-8 substring (default tag). + * + * @returns iprt status code (VINF_SUCCESS or VERR_NO_STR_MEMORY). + * @param ppszCopy Receives pointer of the allocated UTF-8 substring. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to duplicate. + * @param cchMax The max number of chars to duplicate, not counting + * the terminator. + */ +#define RTStrDupNEx(ppszCopy, pszString, cchMax) RTStrDupNExTag((ppszCopy), (pszString), (cchMax), RTSTR_TAG) + +/** + * Allocates a new copy of the given UTF-8 substring (custom tag). + * + * @returns iprt status code (VINF_SUCCESS or VERR_NO_STR_MEMORY). + * @param ppszCopy Receives pointer of the allocated UTF-8 substring. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to duplicate. + * @param cchMax The max number of chars to duplicate, not counting + * the terminator. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrDupNExTag(char **ppszCopy, const char *pszString, size_t cchMax, const char *pszTag); + +/** + * Appends a string onto an existing IPRT allocated string (default tag). + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszAppend The string to append. NULL and empty strings + * are quietly ignored. + */ +#define RTStrAAppend(ppsz, pszAppend) RTStrAAppendTag((ppsz), (pszAppend), RTSTR_TAG) + +/** + * Appends a string onto an existing IPRT allocated string (custom tag). + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszAppend The string to append. NULL and empty strings + * are quietly ignored. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAAppendTag(char **ppsz, const char *pszAppend, const char *pszTag); + +/** + * Appends N bytes from a strings onto an existing IPRT allocated string + * (default tag). + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszAppend The string to append. Can be NULL if cchAppend + * is NULL. + * @param cchAppend The number of chars (not code points) to append + * from pszAppend. Must not be more than + * @a pszAppend contains, except for the special + * value RTSTR_MAX that can be used to indicate all + * of @a pszAppend without having to strlen it. + */ +#define RTStrAAppendN(ppsz, pszAppend, cchAppend) RTStrAAppendNTag((ppsz), (pszAppend), (cchAppend), RTSTR_TAG) + +/** + * Appends N bytes from a strings onto an existing IPRT allocated string (custom + * tag). + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszAppend The string to append. Can be NULL if cchAppend + * is NULL. + * @param cchAppend The number of chars (not code points) to append + * from pszAppend. Must not be more than + * @a pszAppend contains, except for the special + * value RTSTR_MAX that can be used to indicate all + * of @a pszAppend without having to strlen it. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAAppendNTag(char **ppsz, const char *pszAppend, size_t cchAppend, const char *pszTag); + +/** + * Appends one or more strings onto an existing IPRT allocated string. + * + * This is a very flexible and efficient alternative to using RTStrAPrintf to + * combine several strings together. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param cPairs The number of string / length pairs in the + * @a va. + * @param va List of string (const char *) and length + * (size_t) pairs. The strings will be appended to + * the string in the first argument. + */ +#define RTStrAAppendExNV(ppsz, cPairs, va) RTStrAAppendExNVTag((ppsz), (cPairs), (va), RTSTR_TAG) + +/** + * Appends one or more strings onto an existing IPRT allocated string. + * + * This is a very flexible and efficient alternative to using RTStrAPrintf to + * combine several strings together. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param cPairs The number of string / length pairs in the + * @a va. + * @param va List of string (const char *) and length + * (size_t) pairs. The strings will be appended to + * the string in the first argument. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAAppendExNVTag(char **ppsz, size_t cPairs, va_list va, const char *pszTag); + +/** + * Appends one or more strings onto an existing IPRT allocated string + * (untagged). + * + * This is a very flexible and efficient alternative to using RTStrAPrintf to + * combine several strings together. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param cPairs The number of string / length pairs in the + * ellipsis. + * @param ... List of string (const char *) and length + * (size_t) pairs. The strings will be appended to + * the string in the first argument. + */ +DECLINLINE(int) RTStrAAppendExN(char **ppsz, size_t cPairs, ...) +{ + int rc; + va_list va; + va_start(va, cPairs); + rc = RTStrAAppendExNVTag(ppsz, cPairs, va, RTSTR_TAG); + va_end(va); + return rc; +} + +/** + * Appends one or more strings onto an existing IPRT allocated string (custom + * tag). + * + * This is a very flexible and efficient alternative to using RTStrAPrintf to + * combine several strings together. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszTag Allocation tag used for statistics and such. + * @param cPairs The number of string / length pairs in the + * ellipsis. + * @param ... List of string (const char *) and length + * (size_t) pairs. The strings will be appended to + * the string in the first argument. + */ +DECLINLINE(int) RTStrAAppendExNTag(char **ppsz, const char *pszTag, size_t cPairs, ...) +{ + int rc; + va_list va; + va_start(va, cPairs); + rc = RTStrAAppendExNVTag(ppsz, cPairs, va, pszTag); + va_end(va); + return rc; +} + +/** + * Truncates an IPRT allocated string (default tag). + * + * @retval VINF_SUCCESS. + * @retval VERR_OUT_OF_RANGE if cchNew is too long. Nothing is done. + * + * @param ppsz Pointer to the string pointer. The string + * pointer can be NULL if @a cchNew is 0, no change + * is made then. If we actually reallocate the + * string, the string pointer might be changed by + * this call. (In/Out) + * @param cchNew The new string length (excluding the + * terminator). The string must be at least this + * long or we'll return VERR_OUT_OF_RANGE and + * assert on you. + */ +#define RTStrATruncate(ppsz, cchNew) RTStrATruncateTag((ppsz), (cchNew), RTSTR_TAG) + +/** + * Truncates an IPRT allocated string. + * + * @retval VINF_SUCCESS. + * @retval VERR_OUT_OF_RANGE if cchNew is too long. Nothing is done. + * + * @param ppsz Pointer to the string pointer. The string + * pointer can be NULL if @a cchNew is 0, no change + * is made then. If we actually reallocate the + * string, the string pointer might be changed by + * this call. (In/Out) + * @param cchNew The new string length (excluding the + * terminator). The string must be at least this + * long or we'll return VERR_OUT_OF_RANGE and + * assert on you. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrATruncateTag(char **ppsz, size_t cchNew, const char *pszTag); + +/** + * Allocates memory for string storage (default tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns Pointer to the allocated string. The first byte is always set + * to the string terminator char, the contents of the remainder of the + * memory is undefined. The string must be freed by calling RTStrFree. + * + * NULL is returned if the allocation failed. Please translate this to + * VERR_NO_STR_MEMORY and not VERR_NO_MEMORY. Also consider + * RTStrAllocEx if an IPRT status code is required. + * + * @param cb How many bytes to allocate. If this is zero, we + * will allocate a terminator byte anyway. + */ +#define RTStrAlloc(cb) RTStrAllocTag((cb), RTSTR_TAG) + +/** + * Allocates memory for string storage (custom tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns Pointer to the allocated string. The first byte is always set + * to the string terminator char, the contents of the remainder of the + * memory is undefined. The string must be freed by calling RTStrFree. + * + * NULL is returned if the allocation failed. Please translate this to + * VERR_NO_STR_MEMORY and not VERR_NO_MEMORY. Also consider + * RTStrAllocEx if an IPRT status code is required. + * + * @param cb How many bytes to allocate. If this is zero, we + * will allocate a terminator byte anyway. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(char *) RTStrAllocTag(size_t cb, const char *pszTag); + +/** + * Allocates memory for string storage, with status code (default tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY + * + * @param ppsz Where to return the allocated string. This will + * be set to NULL on failure. On success, the + * returned memory will always start with a + * terminator char so that it is considered a valid + * C string, the contents of rest of the memory is + * undefined. + * @param cb How many bytes to allocate. If this is zero, we + * will allocate a terminator byte anyway. + */ +#define RTStrAllocEx(ppsz, cb) RTStrAllocExTag((ppsz), (cb), RTSTR_TAG) + +/** + * Allocates memory for string storage, with status code (custom tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY + * + * @param ppsz Where to return the allocated string. This will + * be set to NULL on failure. On success, the + * returned memory will always start with a + * terminator char so that it is considered a valid + * C string, the contents of rest of the memory is + * undefined. + * @param cb How many bytes to allocate. If this is zero, we + * will allocate a terminator byte anyway. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAllocExTag(char **ppsz, size_t cb, const char *pszTag); + +/** + * Reallocates the specified string (default tag). + * + * You should normally not have use this function, except perhaps to truncate a + * really long string you've got from some IPRT string API, but then you should + * use RTStrATruncate. + * + * @returns VINF_SUCCESS. + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string variable containing the + * input and output string. + * + * When not freeing the string, the result will + * always have the last byte set to the terminator + * character so that when used for string + * truncation the result will be a valid C string + * (your job to keep it a valid UTF-8 string). + * + * When the input string is NULL and we're supposed + * to reallocate, the returned string will also + * have the first byte set to the terminator char + * so it will be a valid C string. + * + * @param cbNew When @a cbNew is zero, we'll behave like + * RTStrFree and @a *ppsz will be set to NULL. + * + * When not zero, this will be the new size of the + * memory backing the string, i.e. it includes the + * terminator char. + */ +#define RTStrRealloc(ppsz, cbNew) RTStrReallocTag((ppsz), (cbNew), RTSTR_TAG) + +/** + * Reallocates the specified string (custom tag). + * + * You should normally not have use this function, except perhaps to truncate a + * really long string you've got from some IPRT string API, but then you should + * use RTStrATruncate. + * + * @returns VINF_SUCCESS. + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string variable containing the + * input and output string. + * + * When not freeing the string, the result will + * always have the last byte set to the terminator + * character so that when used for string + * truncation the result will be a valid C string + * (your job to keep it a valid UTF-8 string). + * + * When the input string is NULL and we're supposed + * to reallocate, the returned string will also + * have the first byte set to the terminator char + * so it will be a valid C string. + * + * @param cbNew When @a cbNew is zero, we'll behave like + * RTStrFree and @a *ppsz will be set to NULL. + * + * When not zero, this will be the new size of the + * memory backing the string, i.e. it includes the + * terminator char. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrReallocTag(char **ppsz, size_t cbNew, const char *pszTag); + +/** + * Validates the UTF-8 encoding of the string. + * + * @returns iprt status code. + * @param psz The string. + */ +RTDECL(int) RTStrValidateEncoding(const char *psz); + +/** @name Flags for RTStrValidateEncodingEx and RTUtf16ValidateEncodingEx + * @{ + */ +/** Check that the string is zero terminated within the given size. + * VERR_BUFFER_OVERFLOW will be returned if the check fails. */ +#define RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED RT_BIT_32(0) +/** Check that the string is exactly the given length. + * If it terminates early, VERR_BUFFER_UNDERFLOW will be returned. When used + * together with RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED, the given length must + * include the terminator or VERR_BUFFER_OVERFLOW will be returned. */ +#define RTSTR_VALIDATE_ENCODING_EXACT_LENGTH RT_BIT_32(1) +/** @} */ + +/** + * Validates the UTF-8 encoding of the string. + * + * @returns iprt status code. + * @param psz The string. + * @param cch The max string length (/ size). Use RTSTR_MAX to + * process the entire string. + * @param fFlags Combination of RTSTR_VALIDATE_ENCODING_XXX flags. + */ +RTDECL(int) RTStrValidateEncodingEx(const char *psz, size_t cch, uint32_t fFlags); + +/** + * Checks if the UTF-8 encoding is valid. + * + * @returns true / false. + * @param psz The string. + */ +RTDECL(bool) RTStrIsValidEncoding(const char *psz); + +/** + * Purge all bad UTF-8 encoding in the string, replacing it with '?'. + * + * @returns The number of bad characters (0 if nothing was done). + * @param psz The string to purge. + */ +RTDECL(size_t) RTStrPurgeEncoding(char *psz); + +/** + * Sanitizes a (valid) UTF-8 string by replacing all characters outside a white + * list in-place by an ASCII replacedment character. + * + * Multi-byte characters will be replaced byte by byte. + * + * @returns The number of code points replaced. In the case of an incorrectly + * encoded string -1 will be returned, and the string is not completely + * processed. In the case of puszValidPairs having an odd number of + * code points, -1 will be also return but without any modification to + * the string. + * @param psz The string to sanitise. + * @param puszValidPairs A zero-terminated array of pairs of Unicode points. + * Each pair is the start and end point of a range, + * and the union of these ranges forms the white list. + * @param chReplacement The ASCII replacement character. + */ +RTDECL(ssize_t) RTStrPurgeComplementSet(char *psz, PCRTUNICP puszValidPairs, char chReplacement); + +/** + * Gets the number of code points the string is made up of, excluding + * the terminator. + * + * + * @returns Number of code points (RTUNICP). + * @returns 0 if the string was incorrectly encoded. + * @param psz The string. + */ +RTDECL(size_t) RTStrUniLen(const char *psz); + +/** + * Gets the number of code points the string is made up of, excluding + * the terminator. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings will be rejected. + * + * @returns iprt status code. + * @param psz The string. + * @param cch The max string length. Use RTSTR_MAX to process the entire string. + * @param pcuc Where to store the code point count. + * This is undefined on failure. + */ +RTDECL(int) RTStrUniLenEx(const char *psz, size_t cch, size_t *pcuc); + +/** + * Translate a UTF-8 string into an unicode string (i.e. RTUNICPs), allocating the string buffer. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppUniString Receives pointer to the allocated unicode string. + * The returned string must be freed using RTUniFree(). + */ +RTDECL(int) RTStrToUni(const char *pszString, PRTUNICP *ppUniString); + +/** + * Translates pszString from UTF-8 to an array of code points, allocating the result + * array if requested. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppaCps If cCps is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppusz is NULL or cCps is zero a buffer of at least cCps items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cCps The number of code points in the unicode string. This includes the terminator. + * @param pcCps Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +RTDECL(int) RTStrToUniEx(const char *pszString, size_t cchString, PRTUNICP *ppaCps, size_t cCps, size_t *pcCps); + +/** + * Calculates the length of the string in RTUTF16 items. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTStrToUtf16Ex of the correct size. For most + * other purposes RTStrCalcUtf16LenEx() should be used. + * + * @returns Number of RTUTF16 items. + * @returns 0 if the string was incorrectly encoded. + * @param psz The string. + */ +RTDECL(size_t) RTStrCalcUtf16Len(const char *psz); + +/** + * Calculates the length of the string in RTUTF16 items. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings will be rejected. + * + * @returns iprt status code. + * @param psz The string. + * @param cch The max string length. Use RTSTR_MAX to process the entire string. + * @param pcwc Where to store the string length. Optional. + * This is undefined on failure. + */ +RTDECL(int) RTStrCalcUtf16LenEx(const char *psz, size_t cch, size_t *pcwc); + +/** + * Translate a UTF-8 string into a UTF-16 allocating the result buffer (default + * tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16 string. + * The returned string must be freed using RTUtf16Free(). + */ +#define RTStrToUtf16(pszString, ppwszString) RTStrToUtf16Tag((pszString), (ppwszString), RTSTR_TAG) + +/** + * Translate a UTF-8 string into a UTF-16 allocating the result buffer (custom + * tag). + * + * This differs from RTStrToUtf16 in that it always produces a + * big-endian string. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16 string. + * The returned string must be freed using RTUtf16Free(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToUtf16Tag(const char *pszString, PRTUTF16 *ppwszString, const char *pszTag); + +/** + * Translate a UTF-8 string into a UTF-16BE allocating the result buffer + * (default tag). + * + * This differs from RTStrToUtf16Tag in that it always produces a + * big-endian string. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16BE string. + * The returned string must be freed using RTUtf16Free(). + */ +#define RTStrToUtf16Big(pszString, ppwszString) RTStrToUtf16BigTag((pszString), (ppwszString), RTSTR_TAG) + +/** + * Translate a UTF-8 string into a UTF-16BE allocating the result buffer (custom + * tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16BE string. + * The returned string must be freed using RTUtf16Free(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToUtf16BigTag(const char *pszString, PRTUTF16 *ppwszString, const char *pszTag); + +/** + * Translates pszString from UTF-8 to UTF-16, allocating the result buffer if requested. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at least cwc items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTStrToUtf16Ex(pszString, cchString, ppwsz, cwc, pcwc) \ + RTStrToUtf16ExTag((pszString), (cchString), (ppwsz), (cwc), (pcwc), RTSTR_TAG) + +/** + * Translates pszString from UTF-8 to UTF-16, allocating the result buffer if + * requested (custom tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at least cwc items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToUtf16ExTag(const char *pszString, size_t cchString, + PRTUTF16 *ppwsz, size_t cwc, size_t *pcwc, const char *pszTag); + + +/** + * Translates pszString from UTF-8 to UTF-16BE, allocating the result buffer if requested. + * + * This differs from RTStrToUtf16Ex in that it always produces a + * big-endian string. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at least cwc items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTStrToUtf16BigEx(pszString, cchString, ppwsz, cwc, pcwc) \ + RTStrToUtf16BigExTag((pszString), (cchString), (ppwsz), (cwc), (pcwc), RTSTR_TAG) + +/** + * Translates pszString from UTF-8 to UTF-16BE, allocating the result buffer if + * requested (custom tag). + * + * This differs from RTStrToUtf16ExTag in that it always produces a + * big-endian string. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at least cwc items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToUtf16BigExTag(const char *pszString, size_t cchString, + PRTUTF16 *ppwsz, size_t cwc, size_t *pcwc, const char *pszTag); + + +/** + * Calculates the length of the string in Latin-1 characters. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings as well as string with codepoints outside the latin-1 range will be + * rejected. The primary purpose of this function is to help allocate buffers + * for RTStrToLatin1Ex of the correct size. For most other purposes + * RTStrCalcLatin1LenEx() should be used. + * + * @returns Number of Latin-1 characters. + * @returns 0 if the string was incorrectly encoded. + * @param psz The string. + */ +RTDECL(size_t) RTStrCalcLatin1Len(const char *psz); + +/** + * Calculates the length of the string in Latin-1 characters. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings as well as string with codepoints outside the latin-1 range will be + * rejected. + * + * @returns iprt status code. + * @param psz The string. + * @param cch The max string length. Use RTSTR_MAX to process the + * entire string. + * @param pcch Where to store the string length. Optional. + * This is undefined on failure. + */ +RTDECL(int) RTStrCalcLatin1LenEx(const char *psz, size_t cch, size_t *pcch); + +/** + * Translate a UTF-8 string into a Latin-1 allocating the result buffer (default + * tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppszString Receives pointer to the allocated Latin-1 string. + * The returned string must be freed using RTStrFree(). + */ +#define RTStrToLatin1(pszString, ppszString) RTStrToLatin1Tag((pszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-8 string into a Latin-1 allocating the result buffer (custom + * tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppszString Receives pointer to the allocated Latin-1 string. + * The returned string must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToLatin1Tag(const char *pszString, char **ppszString, const char *pszTag); + +/** + * Translates pszString from UTF-8 to Latin-1, allocating the result buffer if requested. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. + * The conversion stop when it reaches cchString or + * the string terminator ('\\0'). Use RTSTR_MAX to + * translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to + * pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppsz is NULL or cch + * is zero a buffer of at least cch items will be + * allocated to hold the translated string. If a + * buffer was requested it must be freed using + * RTStrFree(). + * @param cch The buffer size in bytes. This includes the + * terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTStrToLatin1Ex(pszString, cchString, ppsz, cch, pcch) \ + RTStrToLatin1ExTag((pszString), (cchString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates pszString from UTF-8 to Latin1, allocating the result buffer if + * requested (custom tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. + * The conversion stop when it reaches cchString or + * the string terminator ('\\0'). Use RTSTR_MAX to + * translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to + * pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppsz is NULL or cch + * is zero a buffer of at least cch items will be + * allocated to hold the translated string. If a + * buffer was requested it must be freed using + * RTStrFree(). + * @param cch The buffer size in bytes. This includes the + * terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToLatin1ExTag(const char *pszString, size_t cchString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag); + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param psz The string. + */ +RTDECL(RTUNICP) RTStrGetCpInternal(const char *psz); + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code + * @returns VERR_INVALID_UTF8_ENCODING if the encoding is invalid. + * @param ppsz The string cursor. + * This is advanced one character forward on failure. + * @param pCp Where to store the unicode code point. + * Stores RTUNICP_INVALID if the encoding is invalid. + */ +RTDECL(int) RTStrGetCpExInternal(const char **ppsz, PRTUNICP pCp); + +/** + * Get the unicode code point at the given string position for a string of a + * given length. + * + * @returns iprt status code + * @retval VERR_INVALID_UTF8_ENCODING if the encoding is invalid. + * @retval VERR_END_OF_STRING if *pcch is 0. *pCp is set to RTUNICP_INVALID. + * + * @param ppsz The string. + * @param pcch Pointer to the length of the string. This will be + * decremented by the size of the code point. + * @param pCp Where to store the unicode code point. + * Stores RTUNICP_INVALID if the encoding is invalid. + */ +RTDECL(int) RTStrGetCpNExInternal(const char **ppsz, size_t *pcch, PRTUNICP pCp); + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by psz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param psz The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the UTF-8 range. + * + * @remark This is a worker function for RTStrPutCp(). + * + */ +RTDECL(char *) RTStrPutCpInternal(char *psz, RTUNICP CodePoint); + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param psz The string. + * + * @remark We optimize this operation by using an inline function for + * the most frequent and simplest sequence, the rest is + * handled by RTStrGetCpInternal(). + */ +DECLINLINE(RTUNICP) RTStrGetCp(const char *psz) +{ + const unsigned char uch = *(const unsigned char *)psz; + if (!(uch & RT_BIT(7))) + return uch; + return RTStrGetCpInternal(psz); +} + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * This is advanced one character forward on failure. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark We optimize this operation by using an inline function for + * the most frequent and simplest sequence, the rest is + * handled by RTStrGetCpExInternal(). + */ +DECLINLINE(int) RTStrGetCpEx(const char **ppsz, PRTUNICP pCp) +{ + const unsigned char uch = **(const unsigned char **)ppsz; + if (!(uch & RT_BIT(7))) + { + (*ppsz)++; + *pCp = uch; + return VINF_SUCCESS; + } + return RTStrGetCpExInternal(ppsz, pCp); +} + +/** + * Get the unicode code point at the given string position for a string of a + * given maximum length. + * + * @returns iprt status code. + * @retval VERR_INVALID_UTF8_ENCODING if the encoding is invalid. + * @retval VERR_END_OF_STRING if *pcch is 0. *pCp is set to RTUNICP_INVALID. + * + * @param ppsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pcch Pointer to the maximum string length. This will be + * decremented by the size of the code point found. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark We optimize this operation by using an inline function for + * the most frequent and simplest sequence, the rest is + * handled by RTStrGetCpNExInternal(). + */ +DECLINLINE(int) RTStrGetCpNEx(const char **ppsz, size_t *pcch, PRTUNICP pCp) +{ + if (RT_LIKELY(*pcch != 0)) + { + const unsigned char uch = **(const unsigned char **)ppsz; + if (!(uch & RT_BIT(7))) + { + (*ppsz)++; + (*pcch)--; + *pCp = uch; + return VINF_SUCCESS; + } + } + return RTStrGetCpNExInternal(ppsz, pcch, pCp); +} + +/** + * Get the UTF-8 size in characters of a given Unicode code point. + * + * The code point is expected to be a valid Unicode one, but not necessarily in + * the range supported by UTF-8. + * + * @returns The number of chars (bytes) required to encode the code point, or + * zero if there is no UTF-8 encoding. + * @param CodePoint The unicode code point. + */ +DECLINLINE(size_t) RTStrCpSize(RTUNICP CodePoint) +{ + if (CodePoint < 0x00000080) + return 1; + if (CodePoint < 0x00000800) + return 2; + if (CodePoint < 0x00010000) + return 3; +#ifdef RT_USE_RTC_3629 + if (CodePoint < 0x00011000) + return 4; +#else + if (CodePoint < 0x00200000) + return 4; + if (CodePoint < 0x04000000) + return 5; + if (CodePoint < 0x7fffffff) + return 6; +#endif + return 0; +} + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by psz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param psz The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the UTF-8 range. + * + * @remark We optimize this operation by using an inline function for + * the most frequent and simplest sequence, the rest is + * handled by RTStrPutCpInternal(). + */ +DECLINLINE(char *) RTStrPutCp(char *psz, RTUNICP CodePoint) +{ + if (CodePoint < 0x80) + { + *psz++ = (char)CodePoint; + return psz; + } + return RTStrPutCpInternal(psz, CodePoint); +} + +/** + * Skips ahead, past the current code point. + * + * @returns Pointer to the char after the current code point. + * @param psz Pointer to the current code point. + * @remark This will not move the next valid code point, only past the current one. + */ +DECLINLINE(char *) RTStrNextCp(const char *psz) +{ + RTUNICP Cp; + RTStrGetCpEx(&psz, &Cp); + return (char *)psz; +} + +/** + * Skips back to the previous code point. + * + * @returns Pointer to the char before the current code point. + * @returns pszStart on failure. + * @param pszStart Pointer to the start of the string. + * @param psz Pointer to the current code point. + */ +RTDECL(char *) RTStrPrevCp(const char *pszStart, const char *psz); + + +/** @page pg_rt_str_format The IPRT Format Strings + * + * IPRT implements most of the commonly used format types and flags with the + * exception of floating point which is completely missing. In addition IPRT + * provides a number of IPRT specific format types for the IPRT typedefs and + * other useful things. Note that several of these extensions are similar to + * \%p and doesn't care much if you try add formating flags/width/precision. + * + * + * Group 0a, The commonly used format types: + * - \%s - Takes a pointer to a zero terminated string (UTF-8) and + * prints it with the optionally adjustment (width, -) and + * length restriction (precision). + * - \%ls - Same as \%s except that the input is UTF-16 (output UTF-8). + * - \%Ls - Same as \%s except that the input is UCS-32 (output UTF-8). + * - \%S - Same as \%s, used to convert to current codeset but this is + * now done by the streams code. Deprecated, use \%s. + * - \%lS - Ditto. Deprecated, use \%ls. + * - \%LS - Ditto. Deprecated, use \%Ls. + * - \%c - Takes a char and prints it. + * - \%d - Takes a signed integer and prints it as decimal. Thousand + * separator (\'), zero padding (0), adjustment (-+), width, + * precision + * - \%i - Same as \%d. + * - \%u - Takes an unsigned integer and prints it as decimal. Thousand + * separator (\'), zero padding (0), adjustment (-+), width, + * precision + * - \%x - Takes an unsigned integer and prints it as lowercased + * hexadecimal. The special hash (\#) flag causes a '0x' + * prefixed to be printed. Zero padding (0), adjustment (-+), + * width, precision. + * - \%X - Same as \%x except that it is uppercased. + * - \%o - Takes an unsigned (?) integer and prints it as octal. Zero + * padding (0), adjustment (-+), width, precision. + * - \%p - Takes a pointer (void technically) and prints it. Zero + * padding (0), adjustment (-+), width, precision. + * + * The \%d, \%i, \%u, \%x, \%X and \%o format types support the following + * argument type specifiers: + * - \%ll - long long (uint64_t). + * - \%L - long long (uint64_t). + * - \%l - long (uint32_t, uint64_t) + * - \%h - short (int16_t). + * - \%hh - char (int8_t). + * - \%H - char (int8_t). + * - \%z - size_t. + * - \%j - intmax_t (int64_t). + * - \%t - ptrdiff_t. + * The type in parentheses is typical sizes, however when printing those types + * you are better off using the special group 2 format types below (\%RX32 and + * such). + * + * + * Group 0b, IPRT format tricks: + * - %M - Replaces the format string, takes a string pointer. + * - %N - Nested formatting, takes a pointer to a format string + * followed by the pointer to a va_list variable. The va_list + * variable will not be modified and the caller must do va_end() + * on it. Make sure the va_list variable is NOT in a parameter + * list or some gcc versions/targets may get it all wrong. + * + * + * Group 1, the basic runtime typedefs (excluding those which obviously are + * pointer): + * - \%RTbool - Takes a bool value and prints 'true', 'false', or '!%d!'. + * - \%RTeic - Takes a #PCRTERRINFO value outputting 'rc: msg', + * or 'rc - msg' with the \# flag. + * - \%RTeim - Takes a #PCRTERRINFO value outputting ': msg', or + * ' - msg' with the \# flag. + * - \%RTfile - Takes a #RTFILE value. + * - \%RTfmode - Takes a #RTFMODE value. + * - \%RTfoff - Takes a #RTFOFF value. + * - \%RTfp16 - Takes a #RTFAR16 value. + * - \%RTfp32 - Takes a #RTFAR32 value. + * - \%RTfp64 - Takes a #RTFAR64 value. + * - \%RTgid - Takes a #RTGID value. + * - \%RTino - Takes a #RTINODE value. + * - \%RTint - Takes a #RTINT value. + * - \%RTiop - Takes a #RTIOPORT value. + * - \%RTldrm - Takes a #RTLDRMOD value. + * - \%RTmac - Takes a #PCRTMAC pointer. + * - \%RTnaddr - Takes a #PCRTNETADDR value. + * - \%RTnaipv4 - Takes a #RTNETADDRIPV4 value. + * - \%RTnaipv6 - Takes a #PCRTNETADDRIPV6 value. + * - \%RTnthrd - Takes a #RTNATIVETHREAD value. + * - \%RTnthrd - Takes a #RTNATIVETHREAD value. + * - \%RTproc - Takes a #RTPROCESS value. + * - \%RTptr - Takes a #RTINTPTR or #RTUINTPTR value (but not void *). + * - \%RTreg - Takes a #RTCCUINTREG value. + * - \%RTsel - Takes a #RTSEL value. + * - \%RTsem - Takes a #RTSEMEVENT, #RTSEMEVENTMULTI, #RTSEMMUTEX, #RTSEMFASTMUTEX, or #RTSEMRW value. + * - \%RTsock - Takes a #RTSOCKET value. + * - \%RTthrd - Takes a #RTTHREAD value. + * - \%RTuid - Takes a #RTUID value. + * - \%RTuint - Takes a #RTUINT value. + * - \%RTunicp - Takes a #RTUNICP value. + * - \%RTutf16 - Takes a #RTUTF16 value. + * - \%RTuuid - Takes a #PCRTUUID and will print the UUID as a string. + * - \%RTxuint - Takes a #RTUINT or #RTINT value, formatting it as hex. + * - \%RGi - Takes a #RTGCINT value. + * - \%RGp - Takes a #RTGCPHYS value. + * - \%RGr - Takes a #RTGCUINTREG value. + * - \%RGu - Takes a #RTGCUINT value. + * - \%RGv - Takes a #RTGCPTR, #RTGCINTPTR or #RTGCUINTPTR value. + * - \%RGx - Takes a #RTGCUINT or #RTGCINT value, formatting it as hex. + * - \%RHi - Takes a #RTHCINT value. + * - \%RHp - Takes a #RTHCPHYS value. + * - \%RHr - Takes a #RTHCUINTREG value. + * - \%RHu - Takes a #RTHCUINT value. + * - \%RHv - Takes a #RTHCPTR, #RTHCINTPTR or #RTHCUINTPTR value. + * - \%RHx - Takes a #RTHCUINT or #RTHCINT value, formatting it as hex. + * - \%RRv - Takes a #RTRCPTR, #RTRCINTPTR or #RTRCUINTPTR value. + * - \%RCi - Takes a #RTINT value. + * - \%RCp - Takes a #RTCCPHYS value. + * - \%RCr - Takes a #RTCCUINTREG value. + * - \%RCu - Takes a #RTUINT value. + * - \%RCv - Takes a #uintptr_t, #intptr_t, void * value. + * - \%RCx - Takes a #RTUINT or #RTINT value, formatting it as hex. + * + * + * Group 2, the generic integer types which are prefered over relying on what + * bit-count a 'long', 'short', or 'long long' has on a platform. This are + * highly prefered for the [u]intXX_t kind of types: + * - \%RI[8|16|32|64] - Signed integer value of the specifed bit count. + * - \%RU[8|16|32|64] - Unsigned integer value of the specifed bit count. + * - \%RX[8|16|32|64] - Hexadecimal integer value of the specifed bit count. + * + * + * Group 3, hex dumpers and other complex stuff which requires more than simple + * formatting: + * - \%Rhxd - Takes a pointer to the memory which is to be dumped in typical + * hex format. Use the precision to specify the length, and the width to + * set the number of bytes per line. Default width and precision is 16. + * - \%RhxD - Same as \%Rhxd, except that it skips duplicate lines. + * - \%Rhxs - Takes a pointer to the memory to be displayed as a hex string, + * i.e. a series of space separated bytes formatted as two digit hex value. + * Use the precision to specify the length. Default length is 16 bytes. + * The width, if specified, is ignored. + * The space separtor can get change to a colon by + * using the ' flag, and removed entirely using \#. + * - \%RhXd - Same as \%Rhxd, but takes an additional uint64_t + * value with the memory start address/offset after + * the memory pointer. + * - \%RhXD - Same as \%RhxD, but takes an additional uint64_t + * value with the memory start address/offset after + * the memory pointer. + * - \%RhXs - Same as \%Rhxs, but takes an additional uint64_t + * value with the memory start address/offset after + * the memory pointer. + * + * - \%Rhcb - Human readable byte size formatting, using + * binary unit prefixes (GiB, MiB and such). Takes a + * 64-bit unsigned integer as input. Does one + * decimal point by default, can do 0-3 via precision + * field. No rounding when calculating fraction. + * The space flag add a space between the value and + * unit. + * - \%RhcB - Same a \%Rhcb only the 'i' is skipped in the unit. + * - \%Rhci - SI variant of \%Rhcb, fraction is rounded. + * - \%Rhub - Human readable number formatting, using + * binary unit prefixes. Takes a 64-bit unsigned + * integer as input. Does one decimal point by + * default, can do 0-3 via precision field. No + * rounding when calculating fraction. The space + * flag add a space between the value and unit. + * - \%RhuB - Same a \%Rhub only the 'i' is skipped in the unit. + * - \%Rhui - SI variant of \%Rhub, fraction is rounded. + * + * - \%Rrc - Takes an integer iprt status code as argument. Will insert the + * status code define corresponding to the iprt status code. + * - \%Rrs - Takes an integer iprt status code as argument. Will insert the + * short description of the specified status code. + * - \%Rrf - Takes an integer iprt status code as argument. Will insert the + * full description of the specified status code. + * Note! Works like \%Rrs when IN_RT_STATIC is defined (so please avoid). + * - \%Rra - Takes an integer iprt status code as argument. Will insert the + * status code define + full description. + * Note! Reduced output when IN_RT_STATIC is defined (so please avoid). + * - \%Rwc - Takes a long Windows error code as argument. Will insert the status + * code define corresponding to the Windows error code. + * - \%Rwf - Takes a long Windows error code as argument. Will insert the + * full description of the specified status code. + * Note! Works like \%Rwc when IN_RT_STATIC is defined. + * - \%Rwa - Takes a long Windows error code as argument. Will insert the + * error code define + full description. + * Note! Reduced output when IN_RT_STATIC is defined (so please avoid). + * + * - \%Rhrc - Takes a COM/XPCOM status code as argument. Will insert the status + * code define corresponding to the Windows error code. + * - \%Rhrf - Takes a COM/XPCOM status code as argument. Will insert the + * full description of the specified status code. + * Note! Works like \%Rhrc when IN_RT_STATIC is + * defined on Windows (so please avoid). + * - \%Rhra - Takes a COM/XPCOM error code as argument. Will insert the + * error code define + full description. + * Note! Reduced output when IN_RT_STATIC is defined on Windows (so please avoid). + * + * - \%Rfn - Pretty printing of a function or method. It drops the + * return code and parameter list. + * - \%Rbn - Prints the base name. For dropping the path in + * order to save space when printing a path name. + * + * - \%lRbs - Same as \%ls except inlut is big endian UTF-16. + * + * On other platforms, \%Rw? simply prints the argument in a form of 0xXXXXXXXX. + * + * + * Group 4, structure dumpers: + * - \%RDtimespec - Takes a PCRTTIMESPEC. + * + * + * Group 5, XML / HTML, JSON and URI escapers: + * - \%RMas - Takes a string pointer (const char *) and outputs + * it as an attribute value with the proper escaping. + * This typically ends up in double quotes. + * + * - \%RMes - Takes a string pointer (const char *) and outputs + * it as an element with the necessary escaping. + * + * - \%RMjs - Takes a string pointer (const char *) and outputs + * it in quotes with proper JSON escaping. + * + * - \%RMpa - Takes a string pointer (const char *) and outputs + * it percent-encoded (RFC-3986). All reserved characters + * are encoded. + * + * - \%RMpf - Takes a string pointer (const char *) and outputs + * it percent-encoded (RFC-3986), form style. This + * means '+' is used to escape space (' ') and '%2B' + * is used to escape '+'. + * + * - \%RMpp - Takes a string pointer (const char *) and outputs + * it percent-encoded (RFC-3986), path style. This + * means '/' will not be escaped. + * + * - \%RMpq - Takes a string pointer (const char *) and outputs + * it percent-encoded (RFC-3986), query style. This + * means '+' will not be escaped. + * + * + * Group 6, CPU Architecture Register dumpers: + * - \%RAx86[reg] - Takes a 64-bit register value if the register is + * 64-bit or smaller. Check the code wrt which + * registers are implemented. + * + */ + +#ifndef DECLARED_FNRTSTROUTPUT /* duplicated in iprt/log.h & errcore.h */ +# define DECLARED_FNRTSTROUTPUT +/** + * Output callback. + * + * @returns number of bytes written. + * @param pvArg User argument. + * @param pachChars Pointer to an array of utf-8 characters. + * @param cbChars Number of bytes in the character array pointed to by pachChars. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSTROUTPUT,(void *pvArg, const char *pachChars, size_t cbChars)); +/** Pointer to callback function. */ +typedef FNRTSTROUTPUT *PFNRTSTROUTPUT; +#endif + +/** @name Format flag. + * These are used by RTStrFormat extensions and RTStrFormatNumber, mind + * that not all flags makes sense to both of the functions. + * @{ */ +#define RTSTR_F_CAPITAL 0x0001 +#define RTSTR_F_LEFT 0x0002 +#define RTSTR_F_ZEROPAD 0x0004 +#define RTSTR_F_SPECIAL 0x0008 +#define RTSTR_F_VALSIGNED 0x0010 +#define RTSTR_F_PLUS 0x0020 +#define RTSTR_F_BLANK 0x0040 +#define RTSTR_F_WIDTH 0x0080 +#define RTSTR_F_PRECISION 0x0100 +#define RTSTR_F_THOUSAND_SEP 0x0200 +#define RTSTR_F_OBFUSCATE_PTR 0x0400 + +#define RTSTR_F_BIT_MASK 0xf800 +#define RTSTR_F_8BIT 0x0800 +#define RTSTR_F_16BIT 0x1000 +#define RTSTR_F_32BIT 0x2000 +#define RTSTR_F_64BIT 0x4000 +#define RTSTR_F_128BIT 0x8000 +/** @} */ + +/** @def RTSTR_GET_BIT_FLAG + * Gets the bit flag for the specified type. + */ +#define RTSTR_GET_BIT_FLAG(type) \ + ( sizeof(type) * 8 == 32 ? RTSTR_F_32BIT \ + : sizeof(type) * 8 == 64 ? RTSTR_F_64BIT \ + : sizeof(type) * 8 == 16 ? RTSTR_F_16BIT \ + : sizeof(type) * 8 == 8 ? RTSTR_F_8BIT \ + : sizeof(type) * 8 == 128 ? RTSTR_F_128BIT \ + : 0) + + +/** + * Callback to format non-standard format specifiers. + * + * @returns The number of bytes formatted. + * @param pvArg Formatter argument. + * @param pfnOutput Pointer to output function. + * @param pvArgOutput Argument for the output function. + * @param ppszFormat Pointer to the format string pointer. Advance this till the char + * after the format specifier. + * @param pArgs Pointer to the argument list. Use this to fetch the arguments. + * @param cchWidth Format Width. -1 if not specified. + * @param cchPrecision Format Precision. -1 if not specified. + * @param fFlags Flags (RTSTR_NTFS_*). + * @param chArgSize The argument size specifier, 'l' or 'L'. + */ +typedef DECLCALLBACKTYPE(size_t, FNSTRFORMAT,(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, + const char **ppszFormat, va_list *pArgs, int cchWidth, + int cchPrecision, unsigned fFlags, char chArgSize)); +/** Pointer to a FNSTRFORMAT() function. */ +typedef FNSTRFORMAT *PFNSTRFORMAT; + + +/** + * Partial implementation of a printf like formatter. + * It doesn't do everything correct, and there is no floating point support. + * However, it supports custom formats by the means of a format callback. + * + * @returns number of bytes formatted. + * @param pfnOutput Output worker. + * Called in two ways. Normally with a string and its length. + * For termination, it's called with NULL for string, 0 for length. + * @param pvArgOutput Argument to the output worker. + * @param pfnFormat Custom format worker. + * @param pvArgFormat Argument to the format worker. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param InArgs Argument list. + */ +RTDECL(size_t) RTStrFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, + const char *pszFormat, va_list InArgs) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * Partial implementation of a printf like formatter. + * + * It doesn't do everything correct, and there is no floating point support. + * However, it supports custom formats by the means of a format callback. + * + * @returns number of bytes formatted. + * @param pfnOutput Output worker. + * Called in two ways. Normally with a string and its length. + * For termination, it's called with NULL for string, 0 for length. + * @param pvArgOutput Argument to the output worker. + * @param pfnFormat Custom format worker. + * @param pvArgFormat Argument to the format worker. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... Argument list. + */ +RTDECL(size_t) RTStrFormat(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Formats an integer number according to the parameters. + * + * @returns Length of the formatted number. + * @param psz Pointer to output string buffer of sufficient size. + * @param u64Value Value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(int) RTStrFormatNumber(char *psz, uint64_t u64Value, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, + unsigned int fFlags); + +/** + * Formats an unsigned 8-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param u8Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatU8(char *pszBuf, size_t cbBuf, uint8_t u8Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 16-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param u16Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatU16(char *pszBuf, size_t cbBuf, uint16_t u16Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 32-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param u32Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatU32(char *pszBuf, size_t cbBuf, uint32_t u32Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 64-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param u64Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatU64(char *pszBuf, size_t cbBuf, uint64_t u64Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 128-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pu128Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + * @remarks The current implementation is limited to base 16 and doesn't do + * width or precision and probably ignores few flags too. + */ +RTDECL(ssize_t) RTStrFormatU128(char *pszBuf, size_t cbBuf, PCRTUINT128U pu128Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 256-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pu256Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + * @remarks The current implementation is limited to base 16 and doesn't do + * width or precision and probably ignores few flags too. + */ +RTDECL(ssize_t) RTStrFormatU256(char *pszBuf, size_t cbBuf, PCRTUINT256U pu256Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 512-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pu512Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + * @remarks The current implementation is limited to base 16 and doesn't do + * width or precision and probably ignores few flags too. + */ +RTDECL(ssize_t) RTStrFormatU512(char *pszBuf, size_t cbBuf, PCRTUINT512U pu512Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an 32-bit extended floating point number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pr32Value The value to format. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatR32(char *pszBuf, size_t cbBuf, PCRTFLOAT32U pr32Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an 64-bit extended floating point number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pr64Value The value to format. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatR64(char *pszBuf, size_t cbBuf, PCRTFLOAT64U pr64Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags); + +#if !defined(__IBMCPP__) && !defined(__IBMC__) + +/** + * Formats an 80-bit extended floating point number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pr80Value The value to format. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatR80(char *pszBuf, size_t cbBuf, PCRTFLOAT80U pr80Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an 80-bit extended floating point number, version 2. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pr80Value The value to format. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatR80u2(char *pszBuf, size_t cbBuf, PCRTFLOAT80U2 pr80Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags); + +#endif /* uint16_t bitfields doesn't work */ + + +/** + * Callback for formatting a type. + * + * This is registered using the RTStrFormatTypeRegister function and will + * be called during string formatting to handle the specified %R[type]. + * The argument for this format type is assumed to be a pointer and it's + * passed in the @a pvValue argument. + * + * @returns Length of the formatted output. + * @param pfnOutput Output worker. + * @param pvArgOutput Argument to the output worker. + * @param pszType The type name. + * @param pvValue The argument value. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags (NTFS_*). + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSTRFORMATTYPE,(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, + const char *pszType, void const *pvValue, + int cchWidth, int cchPrecision, unsigned fFlags, + void *pvUser)); +/** Pointer to a FNRTSTRFORMATTYPE. */ +typedef FNRTSTRFORMATTYPE *PFNRTSTRFORMATTYPE; + + +/** + * Register a format handler for a type. + * + * The format handler is used to handle '%R[type]' format types, where the argument + * in the vector is a pointer value (a bit restrictive, but keeps it simple). + * + * The caller must ensure that no other thread will be making use of any of + * the dynamic formatting type facilities simultaneously with this call. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_ALREADY_EXISTS if the type has already been registered. + * @retval VERR_TOO_MANY_OPEN_FILES if all the type slots has been allocated already. + * + * @param pszType The type name. + * @param pfnHandler The handler address. See FNRTSTRFORMATTYPE for details. + * @param pvUser The user argument to pass to the handler. See RTStrFormatTypeSetUser + * for how to update this later. + */ +RTDECL(int) RTStrFormatTypeRegister(const char *pszType, PFNRTSTRFORMATTYPE pfnHandler, void *pvUser); + +/** + * Deregisters a format type. + * + * The caller must ensure that no other thread will be making use of any of + * the dynamic formatting type facilities simultaneously with this call. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_FILE_NOT_FOUND if not found. + * + * @param pszType The type to deregister. + */ +RTDECL(int) RTStrFormatTypeDeregister(const char *pszType); + +/** + * Sets the user argument for a type. + * + * This can be used if a user argument needs relocating in GC. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_FILE_NOT_FOUND if not found. + * + * @param pszType The type to update. + * @param pvUser The new user argument value. + */ +RTDECL(int) RTStrFormatTypeSetUser(const char *pszType, void *pvUser); + + +/** + * String printf. + * + * @returns The length of the returned string (in pszBuffer) excluding the + * terminator. + * @param pszBuffer Output buffer. + * @param cchBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * + * @deprecated Use RTStrPrintf2V! Problematic return value on overflow. + */ +RTDECL(size_t) RTStrPrintfV(char *pszBuffer, size_t cchBuffer, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * String printf. + * + * @returns The length of the returned string (in pszBuffer) excluding the + * terminator. + * @param pszBuffer Output buffer. + * @param cchBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + * + * @deprecated Use RTStrPrintf2! Problematic return value on overflow. + */ +RTDECL(size_t) RTStrPrintf(char *pszBuffer, size_t cchBuffer, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * String printf with custom formatting. + * + * @returns The length of the returned string (in pszBuffer) excluding the + * terminator. + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pszBuffer Output buffer. + * @param cchBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * + * @deprecated Use RTStrPrintf2ExV! Problematic return value on overflow. + */ +RTDECL(size_t) RTStrPrintfExV(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * String printf with custom formatting. + * + * @returns The length of the returned string (in pszBuffer) excluding the + * terminator. + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pszBuffer Output buffer. + * @param cchBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + * + * @deprecated Use RTStrPrintf2Ex! Problematic return value on overflow. + */ +RTDECL(size_t) RTStrPrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * String printf, version 2. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). + * + * @param pszBuffer Output buffer. + * @param cbBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + */ +RTDECL(ssize_t) RTStrPrintf2V(char *pszBuffer, size_t cbBuffer, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * String printf, version 2. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). + * + * @param pszBuffer Output buffer. + * @param cbBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +RTDECL(ssize_t) RTStrPrintf2(char *pszBuffer, size_t cbBuffer, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * String printf with custom formatting, version 2. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). + * + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pszBuffer Output buffer. + * @param cbBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + */ +RTDECL(ssize_t) RTStrPrintf2ExV(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cbBuffer, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * String printf with custom formatting, version 2. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). + * + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pszBuffer Output buffer. + * @param cbBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +RTDECL(ssize_t) RTStrPrintf2Ex(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cbBuffer, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Allocating string printf (default tag). + * + * @returns The length of the string in the returned *ppszBuffer excluding the + * terminator. + * @returns -1 on failure. + * @param ppszBuffer Where to store the pointer to the allocated output buffer. + * The buffer should be freed using RTStrFree(). + * On failure *ppszBuffer will be set to NULL. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + */ +#define RTStrAPrintfV(ppszBuffer, pszFormat, args) RTStrAPrintfVTag((ppszBuffer), (pszFormat), (args), RTSTR_TAG) + +/** + * Allocating string printf (custom tag). + * + * @returns The length of the string in the returned *ppszBuffer excluding the + * terminator. + * @returns -1 on failure. + * @param ppszBuffer Where to store the pointer to the allocated output buffer. + * The buffer should be freed using RTStrFree(). + * On failure *ppszBuffer will be set to NULL. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAPrintfVTag(char **ppszBuffer, const char *pszFormat, va_list args, const char *pszTag) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Allocating string printf. + * + * @returns The length of the string in the returned *ppszBuffer excluding the + * terminator. + * @returns -1 on failure. + * @param ppszBuffer Where to store the pointer to the allocated output buffer. + * The buffer should be freed using RTStrFree(). + * On failure *ppszBuffer will be set to NULL. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 3) RTStrAPrintf(char **ppszBuffer, const char *pszFormat, ...) +{ + int cbRet; + va_list va; + va_start(va, pszFormat); + cbRet = RTStrAPrintfVTag(ppszBuffer, pszFormat, va, RTSTR_TAG); + va_end(va); + return cbRet; +} + +/** + * Allocating string printf (custom tag). + * + * @returns The length of the string in the returned *ppszBuffer excluding the + * terminator. + * @returns -1 on failure. + * @param ppszBuffer Where to store the pointer to the allocated output buffer. + * The buffer should be freed using RTStrFree(). + * On failure *ppszBuffer will be set to NULL. + * @param pszTag Allocation tag used for statistics and such. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) RTStrAPrintfTag(char **ppszBuffer, const char *pszTag, const char *pszFormat, ...) +{ + int cbRet; + va_list va; + va_start(va, pszFormat); + cbRet = RTStrAPrintfVTag(ppszBuffer, pszFormat, va, pszTag); + va_end(va); + return cbRet; +} + +/** + * Allocating string printf, version 2. + * + * @returns Formatted string. Use RTStrFree() to free it. NULL when out of + * memory. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + */ +#define RTStrAPrintf2V(pszFormat, args) RTStrAPrintf2VTag((pszFormat), (args), RTSTR_TAG) + +/** + * Allocating string printf, version 2. + * + * @returns Formatted string. Use RTStrFree() to free it. NULL when out of + * memory. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(char *) RTStrAPrintf2VTag(const char *pszFormat, va_list args, const char *pszTag) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Allocating string printf, version 2 (default tag). + * + * @returns Formatted string. Use RTStrFree() to free it. NULL when out of + * memory. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +DECLINLINE(char *) RT_IPRT_FORMAT_ATTR(1, 2) RTStrAPrintf2(const char *pszFormat, ...) +{ + char *pszRet; + va_list va; + va_start(va, pszFormat); + pszRet = RTStrAPrintf2VTag(pszFormat, va, RTSTR_TAG); + va_end(va); + return pszRet; +} + +/** + * Allocating string printf, version 2 (custom tag). + * + * @returns Formatted string. Use RTStrFree() to free it. NULL when out of + * memory. + * @param pszTag Allocation tag used for statistics and such. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +DECLINLINE(char *) RT_IPRT_FORMAT_ATTR(2, 3) RTStrAPrintf2Tag(const char *pszTag, const char *pszFormat, ...) +{ + char *pszRet; + va_list va; + va_start(va, pszFormat); + pszRet = RTStrAPrintf2VTag(pszFormat, va, pszTag); + va_end(va); + return pszRet; +} + +/** + * Strips blankspaces from both ends of the string. + * + * @returns Pointer to first non-blank char in the string. + * @param psz The string to strip. + */ +RTDECL(char *) RTStrStrip(char *psz); + +/** + * Strips blankspaces from the start of the string. + * + * @returns Pointer to first non-blank char in the string. + * @param psz The string to strip. + */ +RTDECL(char *) RTStrStripL(const char *psz); + +/** + * Strips blankspaces from the end of the string. + * + * @returns psz. + * @param psz The string to strip. + */ +RTDECL(char *) RTStrStripR(char *psz); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer (in bytes). + * @param pszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTStrCopy(char *pszDst, size_t cbDst, const char *pszSrc); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer (in bytes). + * @param pszSrc The source string. NULL is not OK. + * @param cchSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTStrCopyEx(char *pszDst, size_t cbDst, const char *pszSrc, size_t cchSrcMax); + +/** + * String copy with overflow handling and buffer advancing. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param ppszDst Pointer to the destination buffer pointer. + * This will be advanced to the end of the copied + * bytes (points at the terminator). This is also + * updated on overflow. + * @param pcbDst Pointer to the destination buffer size + * variable. This will be updated in accord with + * the buffer pointer. + * @param pszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTStrCopyP(char **ppszDst, size_t *pcbDst, const char *pszSrc); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param ppszDst Pointer to the destination buffer pointer. + * This will be advanced to the end of the copied + * bytes (points at the terminator). This is also + * updated on overflow. + * @param pcbDst Pointer to the destination buffer size + * variable. This will be updated in accord with + * the buffer pointer. + * @param pszSrc The source string. NULL is not OK. + * @param cchSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTStrCopyPEx(char **ppszDst, size_t *pcbDst, const char *pszSrc, size_t cchSrcMax); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer (in bytes). + * @param pszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTStrCat(char *pszDst, size_t cbDst, const char *pszSrc); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer (in bytes). + * @param pszSrc The source string. NULL is not OK. + * @param cchSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTStrCatEx(char *pszDst, size_t cbDst, const char *pszSrc, size_t cchSrcMax); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param ppszDst Pointer to the destination buffer pointer. + * This will be advanced to the end of the copied + * bytes (points at the terminator). This is also + * updated on overflow. + * @param pcbDst Pointer to the destination buffer size + * variable. This will be updated in accord with + * the buffer pointer. + * @param pszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTStrCatP(char **ppszDst, size_t *pcbDst, const char *pszSrc); + +/** + * String concatenation with overflow handling and buffer advancing. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param ppszDst Pointer to the destination buffer pointer. + * This will be advanced to the end of the copied + * bytes (points at the terminator). This is also + * updated on overflow. + * @param pcbDst Pointer to the destination buffer size + * variable. This will be updated in accord with + * the buffer pointer. + * @param pszSrc The source string. NULL is not OK. + * @param cchSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTStrCatPEx(char **ppszDst, size_t *pcbDst, const char *pszSrc, size_t cchSrcMax); + +/** + * Performs a case sensitive string compare between two UTF-8 strings. + * + * Encoding errors are ignored by the current implementation. So, the only + * difference between this and the CRT strcmp function is the handling of + * NULL arguments. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second UTF-8 string. Null is allowed. + */ +RTDECL(int) RTStrCmp(const char *psz1, const char *psz2); + +/** + * Performs a case sensitive string compare between two UTF-8 strings, given + * a maximum string length. + * + * Encoding errors are ignored by the current implementation. So, the only + * difference between this and the CRT strncmp function is the handling of + * NULL arguments. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second UTF-8 string. Null is allowed. + * @param cchMax The maximum string length + */ +RTDECL(int) RTStrNCmp(const char *psz1, const char *psz2, size_t cchMax); + +/** + * Performs a case insensitive string compare between two UTF-8 strings. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * The result is the difference between the mismatching codepoints after they + * both have been lower cased. + * + * If the string encoding is invalid the function will assert (strict builds) + * and use RTStrCmp for the remainder of the string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second UTF-8 string. Null is allowed. + */ +RTDECL(int) RTStrICmp(const char *psz1, const char *psz2); + +/** + * Performs a case insensitive string compare between two UTF-8 strings, given a + * maximum string length. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * The result is the difference between the mismatching codepoints after they + * both have been lower cased. + * + * If the string encoding is invalid the function will assert (strict builds) + * and use RTStrNCmp for the remainder of the string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second UTF-8 string. Null is allowed. + * @param cchMax Maximum string length + */ +RTDECL(int) RTStrNICmp(const char *psz1, const char *psz2, size_t cchMax); + +/** + * Performs a case insensitive string compare between a UTF-8 string and a 7-bit + * ASCII string. + * + * This is potentially faster than RTStrICmp and drags in less dependencies. It + * is really handy for hardcoded inputs. + * + * If the string encoding is invalid the function will assert (strict builds) + * and use RTStrCmp for the remainder of the string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second string, 7-bit ASCII. Null is allowed. + * @sa RTStrICmp, RTUtf16ICmpAscii + */ +RTDECL(int) RTStrICmpAscii(const char *psz1, const char *psz2); + +/** + * Performs a case insensitive string compare between a UTF-8 string and a 7-bit + * ASCII string, given a maximum string length. + * + * This is potentially faster than RTStrNICmp and drags in less dependencies. + * It is really handy for hardcoded inputs. + * + * If the string encoding is invalid the function will assert (strict builds) + * and use RTStrNCmp for the remainder of the string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second string, 7-bit ASCII. Null is allowed. + * @param cchMax Maximum string length + * @sa RTStrNICmp, RTUtf16NICmpAscii + */ +RTDECL(int) RTStrNICmpAscii(const char *psz1, const char *psz2, size_t cchMax); + +/** + * Checks whether @a pszString starts with @a pszStart. + * + * @returns true / false. + * @param pszString The string to check. + * @param pszStart The start string to check for. + */ +RTDECL(bool) RTStrStartsWith(const char *pszString, const char *pszStart); + +/** + * Checks whether @a pszString starts with @a pszStart, case insensitive. + * + * @returns true / false. + * @param pszString The string to check. + * @param pszStart The start string to check for. + */ +RTDECL(bool) RTStrIStartsWith(const char *pszString, const char *pszStart); + +/** + * Splits a string buffer with a given separator into separate strings. + * If no separators are found, no strings are returned. Consequtive separators will be skipped. + * + * @returns iprt status code. + * @param pcszStrings String buffer to split. + * @param cbStrings Size (in bytes) of string buffer to split, including terminator. + * @param pcszSeparator Separator to use / find for splitting strings. + * @param ppapszStrings Where to return the allocated string array on success. Needs to be free'd by the caller. + * @param pcStrings Where to return the number of split strings in \a ppapszStrings. + */ +RTDECL(int) RTStrSplit(const char *pcszStrings, size_t cbStrings, + const char *pcszSeparator, char ***ppapszStrings, size_t *pcStrings); + +/** + * Locates a case sensitive substring. + * + * If any of the two strings are NULL, then NULL is returned. If the needle is + * an empty string, then the haystack is returned (i.e. matches anything). + * + * @returns Pointer to the first occurrence of the substring if found, NULL if + * not. + * + * @param pszHaystack The string to search. + * @param pszNeedle The substring to search for. + * + * @remarks The difference between this and strstr is the handling of NULL + * pointers. + */ +RTDECL(char *) RTStrStr(const char *pszHaystack, const char *pszNeedle); + +/** + * Locates a case insensitive substring. + * + * If any of the two strings are NULL, then NULL is returned. If the needle is + * an empty string, then the haystack is returned (i.e. matches anything). + * + * @returns Pointer to the first occurrence of the substring if found, NULL if + * not. + * + * @param pszHaystack The string to search. + * @param pszNeedle The substring to search for. + * + */ +RTDECL(char *) RTStrIStr(const char *pszHaystack, const char *pszNeedle); + +/** + * Converts the string to lower case. + * + * @returns Pointer to the converted string. + * @param psz The string to convert. + */ +RTDECL(char *) RTStrToLower(char *psz); + +/** + * Converts the string to upper case. + * + * @returns Pointer to the converted string. + * @param psz The string to convert. + */ +RTDECL(char *) RTStrToUpper(char *psz); + +/** + * Checks if the string is case foldable, i.e. whether it would change if + * subject to RTStrToLower or RTStrToUpper. + * + * @returns true / false + * @param psz The string in question. + */ +RTDECL(bool) RTStrIsCaseFoldable(const char *psz); + +/** + * Checks if the string is upper cased (no lower case chars in it). + * + * @returns true / false + * @param psz The string in question. + */ +RTDECL(bool) RTStrIsUpperCased(const char *psz); + +/** + * Checks if the string is lower cased (no upper case chars in it). + * + * @returns true / false + * @param psz The string in question. + */ +RTDECL(bool) RTStrIsLowerCased(const char *psz); + +/** + * Find the length of a zero-terminated byte string, given + * a max string length. + * + * See also RTStrNLenEx. + * + * @returns The string length or cbMax. The returned length does not include + * the zero terminator if it was found. + * + * @param pszString The string. + * @param cchMax The max string length. + */ +RTDECL(size_t) RTStrNLen(const char *pszString, size_t cchMax); + +/** + * Find the length of a zero-terminated byte string, given + * a max string length. + * + * See also RTStrNLen. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the string has a length less than cchMax. + * @retval VERR_BUFFER_OVERFLOW if the end of the string wasn't found + * before cchMax was reached. + * + * @param pszString The string. + * @param cchMax The max string length. + * @param pcch Where to store the string length excluding the + * terminator. This is set to cchMax if the terminator + * isn't found. + */ +RTDECL(int) RTStrNLenEx(const char *pszString, size_t cchMax, size_t *pcch); + +/** The maximum size argument of a memchr call. */ +#define RTSTR_MEMCHR_MAX ((~(size_t)0 >> 1) - 15) + +/** + * Find the zero terminator in a string with a limited length. + * + * @returns Pointer to the zero terminator. + * @returns NULL if the zero terminator was not found. + * + * @param pszString The string. + * @param cchMax The max string length. RTSTR_MAX is fine. + */ +RTDECL(char *) RTStrEnd(char const *pszString, size_t cchMax); + +/** + * Finds the offset at which a simple character first occurs in a string. + * + * @returns The offset of the first occurence or the terminator offset. + * @param pszHaystack The string to search. + * @param chNeedle The character to search for. + */ +DECLINLINE(size_t) RTStrOffCharOrTerm(const char *pszHaystack, char chNeedle) +{ + const char *psz = pszHaystack; + char ch; + while ( (ch = *psz) != chNeedle + && ch != '\0') + psz++; + return (size_t)(psz - pszHaystack); +} + +/** + * Matches a simple string pattern. + * + * @returns true if the string matches the pattern, otherwise false. + * + * @param pszPattern The pattern. Special chars are '*' and '?', where the + * asterisk matches zero or more characters and question + * mark matches exactly one character. + * @param pszString The string to match against the pattern. + */ +RTDECL(bool) RTStrSimplePatternMatch(const char *pszPattern, const char *pszString); + +/** + * Matches a simple string pattern, neither which needs to be zero terminated. + * + * This is identical to RTStrSimplePatternMatch except that you can optionally + * specify the length of both the pattern and the string. The function will + * stop when it hits a string terminator or either of the lengths. + * + * @returns true if the string matches the pattern, otherwise false. + * + * @param pszPattern The pattern. Special chars are '*' and '?', where the + * asterisk matches zero or more characters and question + * mark matches exactly one character. + * @param cchPattern The pattern length. Pass RTSTR_MAX if you don't know the + * length and wish to stop at the string terminator. + * @param pszString The string to match against the pattern. + * @param cchString The string length. Pass RTSTR_MAX if you don't know the + * length and wish to match up to the string terminator. + */ +RTDECL(bool) RTStrSimplePatternNMatch(const char *pszPattern, size_t cchPattern, + const char *pszString, size_t cchString); + +/** + * Matches multiple patterns against a string. + * + * The patterns are separated by the pipe character (|). + * + * @returns true if the string matches the pattern, otherwise false. + * + * @param pszPatterns The patterns. + * @param cchPatterns The lengths of the patterns to use. Pass RTSTR_MAX to + * stop at the terminator. + * @param pszString The string to match against the pattern. + * @param cchString The string length. Pass RTSTR_MAX stop stop at the + * terminator. + * @param poffPattern Offset into the patterns string of the patttern that + * matched. If no match, this will be set to RTSTR_MAX. + * This is optional, NULL is fine. + */ +RTDECL(bool) RTStrSimplePatternMultiMatch(const char *pszPatterns, size_t cchPatterns, + const char *pszString, size_t cchString, + size_t *poffPattern); + +/** + * Compares two version strings RTStrICmp fashion. + * + * The version string is split up into sections at punctuation, spaces, + * underscores, dashes and plus signs. The sections are then split up into + * numeric and string sub-sections. Finally, the sub-sections are compared + * in a numeric or case insesntivie fashion depending on what they are. + * + * The following strings are considered to be equal: "1.0.0", "1.00.0", "1.0", + * "1". These aren't: "1.0.0r993", "1.0", "1.0r993", "1.0_Beta3", "1.1" + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * + * @param pszVer1 First version string to compare. + * @param pszVer2 Second version string to compare first version with. + */ +RTDECL(int) RTStrVersionCompare(const char *pszVer1, const char *pszVer2); + + +/** @defgroup rt_str_conv String To/From Number Conversions + * @{ */ + +/** + * Converts a string representation of a number to a 64-bit unsigned number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu64 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt64Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint64_t *pu64); + +/** + * Converts a string representation of a number to a 64-bit unsigned number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * @retval VERR_TRAILING_SPACES + * @retval VERR_TRAILING_CHARS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu64 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt64Full(const char *pszValue, unsigned uBaseAndMaxLen, uint64_t *pu64); + +/** + * Converts a string representation of a number to a 64-bit unsigned number. + * The base is guessed. + * + * @returns 64-bit unsigned number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(uint64_t) RTStrToUInt64(const char *pszValue); + +/** + * Converts a string representation of a number to a 32-bit unsigned number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu32 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt32Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint32_t *pu32); + +/** + * Converts a string representation of a number to a 32-bit unsigned number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * @retval VERR_TRAILING_SPACES + * @retval VERR_TRAILING_CHARS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu32 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt32Full(const char *pszValue, unsigned uBaseAndMaxLen, uint32_t *pu32); + +/** + * Converts a string representation of a number to a 32-bit unsigned number. + * The base is guessed. + * + * @returns 32-bit unsigned number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(uint32_t) RTStrToUInt32(const char *pszValue); + +/** + * Converts a string representation of a number to a 16-bit unsigned number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu16 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt16Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint16_t *pu16); + +/** + * Converts a string representation of a number to a 16-bit unsigned number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * @retval VERR_TRAILING_SPACES + * @retval VERR_TRAILING_CHARS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu16 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt16Full(const char *pszValue, unsigned uBaseAndMaxLen, uint16_t *pu16); + +/** + * Converts a string representation of a number to a 16-bit unsigned number. + * The base is guessed. + * + * @returns 16-bit unsigned number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(uint16_t) RTStrToUInt16(const char *pszValue); + +/** + * Converts a string representation of a number to a 8-bit unsigned number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu8 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt8Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint8_t *pu8); + +/** + * Converts a string representation of a number to a 8-bit unsigned number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * @retval VERR_TRAILING_SPACES + * @retval VERR_TRAILING_CHARS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu8 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt8Full(const char *pszValue, unsigned uBaseAndMaxLen, uint8_t *pu8); + +/** + * Converts a string representation of a number to a 8-bit unsigned number. + * The base is guessed. + * + * @returns 8-bit unsigned number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(uint8_t) RTStrToUInt8(const char *pszValue); + +/** + * Converts a string representation of a number to a 64-bit signed number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi64 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt64Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int64_t *pi64); + +/** + * Converts a string representation of a number to a 64-bit signed number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VINF_SUCCESS + * @retval VERR_TRAILING_CHARS + * @retval VERR_TRAILING_SPACES + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi64 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt64Full(const char *pszValue, unsigned uBaseAndMaxLen, int64_t *pi64); + +/** + * Converts a string representation of a number to a 64-bit signed number. + * The base is guessed. + * + * @returns 64-bit signed number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(int64_t) RTStrToInt64(const char *pszValue); + +/** + * Converts a string representation of a number to a 32-bit signed number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi32 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt32Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int32_t *pi32); + +/** + * Converts a string representation of a number to a 32-bit signed number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VINF_SUCCESS + * @retval VERR_TRAILING_CHARS + * @retval VERR_TRAILING_SPACES + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi32 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt32Full(const char *pszValue, unsigned uBaseAndMaxLen, int32_t *pi32); + +/** + * Converts a string representation of a number to a 32-bit signed number. + * The base is guessed. + * + * @returns 32-bit signed number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(int32_t) RTStrToInt32(const char *pszValue); + +/** + * Converts a string representation of a number to a 16-bit signed number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi16 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt16Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int16_t *pi16); + +/** + * Converts a string representation of a number to a 16-bit signed number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VINF_SUCCESS + * @retval VERR_TRAILING_CHARS + * @retval VERR_TRAILING_SPACES + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi16 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt16Full(const char *pszValue, unsigned uBaseAndMaxLen, int16_t *pi16); + +/** + * Converts a string representation of a number to a 16-bit signed number. + * The base is guessed. + * + * @returns 16-bit signed number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(int16_t) RTStrToInt16(const char *pszValue); + +/** + * Converts a string representation of a number to a 8-bit signed number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi8 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt8Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int8_t *pi8); + +/** + * Converts a string representation of a number to a 8-bit signed number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VINF_SUCCESS + * @retval VERR_TRAILING_CHARS + * @retval VERR_TRAILING_SPACES + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi8 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt8Full(const char *pszValue, unsigned uBaseAndMaxLen, int8_t *pi8); + +/** + * Converts a string representation of a number to a 8-bit signed number. + * The base is guessed. + * + * @returns 8-bit signed number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(int8_t) RTStrToInt8(const char *pszValue); + + +/** + * Converts a string to long double floating point, extended edition. + * + * Please note that long double can be double precision, extended precision, or + * quad precision floating point depending on the platform and architecture. See + * RT_COMPILER_WITH_128BIT_LONG_DOUBLE and RT_COMPILER_WITH_80BIT_LONG_DOUBLE. + * + * @returns IPRT status code. + * @retval VERR_NO_DIGITS if no valid digits found. + * @retval VWRN_FLOAT_UNDERFLOW on underflow with denormal/subnormal return + * value + * @retval VERR_FLOAT_UNDERFLOW on underflow, value set to +/- zero. + * @retval VERR_FLOAT_OVERFLOW on overflow, value set to +/- infinity. + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszValue The string to parse. + * @param ppszNext Where to store the pointer to the first char following + * the number. Optional. + * @param cchMax Max number of character to parse. Zero means unlimited. + * @param plrd Where to return the number. Optional. + * + * @note This code isn't entirely perfect yet. It could exhibit rounding + * differences compared to strtold & the compiler, and extreme value + * may overflow/underflow prematurely depending on the build config. + */ +RTDECL(int) RTStrToLongDoubleEx(const char *pszValue, char **ppszNext, size_t cchMax, long double *plrd); + +/** + * Converts a string to double precision floating point, extended edition. + * + * @returns IPRT status code. + * @retval VERR_NO_DIGITS if no valid digits found. + * @retval VWRN_FLOAT_UNDERFLOW on underflow with denormal/subnormal return + * value + * @retval VERR_FLOAT_UNDERFLOW on underflow, value set to +/- zero. + * @retval VERR_FLOAT_OVERFLOW on overflow, value set to +/- infinity. + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszValue The string to parse. + * @param ppszNext Where to store the pointer to the first char following + * the number. Optional. + * @param cchMax Max number of character to parse. Zero means unlimited. + * @param prd Where to return the number. Optional. + * + * @note This code isn't entirely perfect yet. It could exhibit rounding + * differences compared to strtold & the compiler, and extreme value + * may overflow/underflow prematurely depending on the build config. + */ +RTDECL(int) RTStrToDoubleEx(const char *pszValue, char **ppszNext, size_t cchMax, double *prd); + +/** + * Converts a string to single precision floating point, extended edition. + * + * @returns IPRT status code. + * @retval VERR_NO_DIGITS if no valid digits found. + * @retval VWRN_FLOAT_UNDERFLOW on underflow with denormal/subnormal return + * value + * @retval VERR_FLOAT_UNDERFLOW on underflow, value set to +/- zero. + * @retval VERR_FLOAT_OVERFLOW on overflow, value set to +/- infinity. + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszValue The string to parse. + * @param ppszNext Where to store the pointer to the first char following + * the number. Optional. + * @param cchMax Max number of character to parse. Zero means unlimited. + * @param pr Where to return the number. Optional. + * + * @note This code isn't entirely perfect yet. It could exhibit rounding + * differences compared to strtold & the compiler, and extreme value + * may overflow/underflow prematurely depending on the build config. + */ +RTDECL(int) RTStrToFloatEx(const char *pszValue, char **ppszNext, size_t cchMax, float *pr); + + +/** + * Gets a long double NaN. + * + * @returns NaN value. + * @param pszTag Optional NaN tag for modifying the NaN value. We + * recognizes a string of hex digits for inserting into the + * fraction part. This may be followed 'quiet' or + * 'signaling', ignoring case and requiring at only the + * first character. The two components may be separated by + * zero or more '_' characters. Any other stuff in the tag + * will be ignored. + * + * If the tag is empty or we cannot grok any of it, we'll + * return a default quiet NaN. + * @param fPositive Whether the NaN value should be positive or negative + * (for what that's worth). + */ +RTDECL(long double) RTStrNanLongDouble(const char *pszTag, bool fPositive); + +/** + * Gets a double NaN. + * + * @returns NaN value. + * @param pszTag Optional NaN tag for modifying the NaN value. We + * recognizes a string of hex digits for inserting into the + * fraction part. This may be followed 'quiet' or + * 'signaling', ignoring case and requiring at only the + * first character. The two components may be separated by + * zero or more '_' characters. Any other stuff in the tag + * will be ignored. + * + * If the tag is empty or we cannot grok any of it, we'll + * return a default quiet NaN. + * @param fPositive Whether the NaN value should be positive or negative + * (for what that's worth). + */ +RTDECL(double) RTStrNanDouble(const char *pszTag, bool fPositive); + +/** + * Gets a float NaN. + * + * @returns NaN value. + * @param pszTag Optional NaN tag for modifying the NaN value. We + * recognizes a string of hex digits for inserting into the + * fraction part. This may be followed 'quiet' or + * 'signaling', ignoring case and requiring at only the + * first character. The two components may be separated by + * zero or more '_' characters. Any other stuff in the tag + * will be ignored. + * + * If the tag is empty or we cannot grok any of it, we'll + * return a default quiet NaN. + * @param fPositive Whether the NaN value should be positive or negative + * (for what that's worth). + */ +RTDECL(float) RTStrNanFloat(const char *pszTag, bool fPositive); + +/** + * Formats a buffer stream as hex bytes. + * + * The default is no separating spaces or line breaks or anything. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if any of the pointers are wrong. + * @retval VERR_BUFFER_OVERFLOW if the buffer is insufficent to hold the bytes. + * + * @param pszBuf Output string buffer. + * @param cbBuf The size of the output buffer. + * @param pv Pointer to the bytes to stringify. + * @param cb The number of bytes to stringify. + * @param fFlags Combination of RTSTRPRINTHEXBYTES_F_XXX values. + * @sa RTUtf16PrintHexBytes. + */ +RTDECL(int) RTStrPrintHexBytes(char *pszBuf, size_t cbBuf, void const *pv, size_t cb, uint32_t fFlags); +/** @name RTSTRPRINTHEXBYTES_F_XXX - flags for RTStrPrintHexBytes and RTUtf16PritnHexBytes. + * @{ */ +/** Upper case hex digits, the default is lower case. */ +#define RTSTRPRINTHEXBYTES_F_UPPER RT_BIT(0) +/** Add a space between each group. */ +#define RTSTRPRINTHEXBYTES_F_SEP_SPACE RT_BIT(1) +/** Add a colon between each group. */ +#define RTSTRPRINTHEXBYTES_F_SEP_COLON RT_BIT(2) +/** @} */ + +/** + * Converts a string of hex bytes back into binary data. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if any of the pointers are wrong. + * @retval VERR_BUFFER_OVERFLOW if the string contains too many hex bytes. + * @retval VERR_BUFFER_UNDERFLOW if there aren't enough hex bytes to fill up + * the output buffer. + * @retval VERR_UNEVEN_INPUT if the input contains a half byte. + * @retval VERR_NO_DIGITS + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszHex The string containing the hex bytes. + * @param pv Output buffer. + * @param cb The size of the output buffer. + * @param fFlags RTSTRCONVERTHEXBYTES_F_XXX. + */ +RTDECL(int) RTStrConvertHexBytes(char const *pszHex, void *pv, size_t cb, uint32_t fFlags); + +/** @name RTSTRCONVERTHEXBYTES_F_XXX - Flags for RTStrConvertHexBytes() and RTStrConvertHexBytesEx(). + * @{ */ +/** Accept colon as a byte separator. */ +#define RTSTRCONVERTHEXBYTES_F_SEP_COLON RT_BIT(0) +/** @} */ + +/** + * Converts a string of hex bytes back into binary data, extended version. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if any of the pointers are wrong. + * @retval VERR_BUFFER_OVERFLOW if the string contains too many hex bytes. + * @retval VERR_BUFFER_UNDERFLOW if there aren't enough hex bytes to fill up + * the output buffer and *pcbReturned is NULL. + * @retval VINF_BUFFER_UNDERFLOW if there aren't enough hex bytes to fill up + * the output buffer and *pcbReturned is not NULL, *pcbReturned holds + * the actual number of bytes. + * @retval VERR_UNEVEN_INPUT if the input contains a half byte. + * @retval VERR_NO_DIGITS + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszHex The string containing the hex bytes. + * @param pv Output buffer. + * @param cb The size of the output buffer. + * @param fFlags RTSTRCONVERTHEXBYTES_F_XXX. + * @param ppszNext Set to point at where we stopped decoding hex bytes. + * Optional. + * @param pcbReturned Where to return the number of bytes found. Optional. + */ +RTDECL(int) RTStrConvertHexBytesEx(char const *pszHex, void *pv, size_t cb, uint32_t fFlags, + const char **ppszNext, size_t *pcbReturned); + +/** @} */ + + +/** @defgroup rt_str_space Unique String Space + * @{ + */ + +/** Pointer to a string name space container node core. */ +typedef struct RTSTRSPACECORE *PRTSTRSPACECORE; +/** Pointer to a pointer to a string name space container node core. */ +typedef PRTSTRSPACECORE *PPRTSTRSPACECORE; + +/** + * String name space container node core. + */ +typedef struct RTSTRSPACECORE +{ + /** Pointer to the left leaf node. Don't touch. */ + PRTSTRSPACECORE pLeft; + /** Pointer to the left right node. Don't touch. */ + PRTSTRSPACECORE pRight; + /** Pointer to the list of string with the same hash key value. Don't touch. */ + PRTSTRSPACECORE pList; + /** Hash key. Don't touch. */ + uint32_t Key; + /** Height of this tree: max(heigth(left), heigth(right)) + 1. Don't touch */ + unsigned char uchHeight; + /** The string length. Read only! */ + size_t cchString; + /** Pointer to the string. Read only! */ + const char *pszString; +} RTSTRSPACECORE; + +/** String space. (Initialize with NULL.) */ +typedef PRTSTRSPACECORE RTSTRSPACE; +/** Pointer to a string space. */ +typedef PPRTSTRSPACECORE PRTSTRSPACE; + + +/** + * Inserts a string into a unique string space. + * + * @returns true on success. + * @returns false if the string collided with an existing string. + * @param pStrSpace The space to insert it into. + * @param pStr The string node. + */ +RTDECL(bool) RTStrSpaceInsert(PRTSTRSPACE pStrSpace, PRTSTRSPACECORE pStr); + +/** + * Removes a string from a unique string space. + * + * @returns Pointer to the removed string node. + * @returns NULL if the string was not found in the string space. + * @param pStrSpace The space to remove it from. + * @param pszString The string to remove. + */ +RTDECL(PRTSTRSPACECORE) RTStrSpaceRemove(PRTSTRSPACE pStrSpace, const char *pszString); + +/** + * Gets a string from a unique string space. + * + * @returns Pointer to the string node. + * @returns NULL if the string was not found in the string space. + * @param pStrSpace The space to get it from. + * @param pszString The string to get. + */ +RTDECL(PRTSTRSPACECORE) RTStrSpaceGet(PRTSTRSPACE pStrSpace, const char *pszString); + +/** + * Gets a string from a unique string space. + * + * @returns Pointer to the string node. + * @returns NULL if the string was not found in the string space. + * @param pStrSpace The space to get it from. + * @param pszString The string to get. + * @param cchMax The max string length to evaluate. Passing + * RTSTR_MAX is ok and makes it behave just like + * RTStrSpaceGet. + */ +RTDECL(PRTSTRSPACECORE) RTStrSpaceGetN(PRTSTRSPACE pStrSpace, const char *pszString, size_t cchMax); + +/** + * Callback function for RTStrSpaceEnumerate() and RTStrSpaceDestroy(). + * + * @returns 0 on continue. + * @returns Non-zero to aborts the operation. + * @param pStr The string node + * @param pvUser The user specified argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTSTRSPACECALLBACK,(PRTSTRSPACECORE pStr, void *pvUser)); +/** Pointer to callback function for RTStrSpaceEnumerate() and RTStrSpaceDestroy(). */ +typedef FNRTSTRSPACECALLBACK *PFNRTSTRSPACECALLBACK; + +/** + * Destroys the string space. + * + * The caller supplies a callback which will be called for each of the string + * nodes in for freeing their memory and other resources. + * + * @returns 0 or what ever non-zero return value pfnCallback returned + * when aborting the destruction. + * @param pStrSpace The space to destroy. + * @param pfnCallback The callback. + * @param pvUser The user argument. + */ +RTDECL(int) RTStrSpaceDestroy(PRTSTRSPACE pStrSpace, PFNRTSTRSPACECALLBACK pfnCallback, void *pvUser); + +/** + * Enumerates the string space. + * The caller supplies a callback which will be called for each of + * the string nodes. + * + * @returns 0 or what ever non-zero return value pfnCallback returned + * when aborting the destruction. + * @param pStrSpace The space to enumerate. + * @param pfnCallback The callback. + * @param pvUser The user argument. + */ +RTDECL(int) RTStrSpaceEnumerate(PRTSTRSPACE pStrSpace, PFNRTSTRSPACECALLBACK pfnCallback, void *pvUser); + +/** @} */ + + +/** @defgroup rt_str_hash Sting hashing + * @{ */ + +/** + * Hashes the given string using algorithm \#1. + * + * @returns String hash. + * @param pszString The string to hash. + */ +RTDECL(uint32_t) RTStrHash1(const char *pszString); + +/** + * Hashes the given string using algorithm \#1. + * + * @returns String hash. + * @param pszString The string to hash. + * @param cchString The max length to hash. Hashing will stop if the + * terminator character is encountered first. Passing + * RTSTR_MAX is fine. + */ +RTDECL(uint32_t) RTStrHash1N(const char *pszString, size_t cchString); + +/** + * Hashes the given strings as if they were concatenated using algorithm \#1. + * + * @returns String hash. + * @param cPairs The number of string / length pairs in the + * ellipsis. + * @param ... List of string (const char *) and length + * (size_t) pairs. Passing RTSTR_MAX as the size is + * fine. + */ +RTDECL(uint32_t) RTStrHash1ExN(size_t cPairs, ...); + +/** + * Hashes the given strings as if they were concatenated using algorithm \#1. + * + * @returns String hash. + * @param cPairs The number of string / length pairs in the @a va. + * @param va List of string (const char *) and length + * (size_t) pairs. Passing RTSTR_MAX as the size is + * fine. + */ +RTDECL(uint32_t) RTStrHash1ExNV(size_t cPairs, va_list va); + +/** @} */ + + +/** @defgroup rt_str_mem Raw memory operations. + * + * @note Following the memchr/memcpy/memcmp/memset tradition and putting these + * in the string.h header rather than in the mem.h one. + * + * @{ */ + +/** + * Searches @a pvHaystack for a 16-bit sized and aligned @a uNeedle. + * + * @returns Pointer to the first hit if found, NULL if not found. + * @param pvHaystack The memory to search. + * @param uNeedle The 16-bit value to find. + * @param cbHaystack Size of the memory to search. + * @sa memchr, RTStrMemFind32, RTStrMemFind64 + */ +RTDECL(uint16_t *) RTStrMemFind16(const void *pvHaystack, uint16_t uNeedle, size_t cbHaystack); + +/** + * Searches @a pvHaystack for a 32-bit sized and aligned @a uNeedle. + * + * @returns Pointer to the first hit if found, NULL if not found. + * @param pvHaystack The memory to search. + * @param uNeedle The 32-bit value to find. + * @param cbHaystack Size of the memory to search. + * @sa memchr, RTStrMemFind16, RTStrMemFind64 + */ +RTDECL(uint32_t *) RTStrMemFind32(const void *pvHaystack, uint32_t uNeedle, size_t cbHaystack); + +/** + * Searches @a pvHaystack for a 64-bit sized and aligned @a uNeedle. + * + * @returns Pointer to the first hit if found, NULL if not found. + * @param pvHaystack The memory to search. + * @param uNeedle The 64-bit value to find. + * @param cbHaystack Size of the memory to search. + * @sa memchr, RTStrMemFind16, RTStrMemFind32 + */ +RTDECL(uint64_t *) RTStrMemFind64(const void *pvHaystack, uint64_t uNeedle, size_t cbHaystack); + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_string_h */ diff --git a/include/iprt/symlink.h b/include/iprt/symlink.h new file mode 100644 index 00000000..8b5e60f0 --- /dev/null +++ b/include/iprt/symlink.h @@ -0,0 +1,189 @@ +/** @file + * IPRT - Symbolic Link Manipulation. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_symlink_h +#define IPRT_INCLUDED_symlink_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_symlink RTSymlink - Symbolic Link Manipulation + * @ingroup grp_rt + * + * For querying and changing symlink info (mode, ownership, etc) please refer + * to the @ref grp_rt_path "RTPath" API: RTPathQueryInfoEx, RTPathSetOwnerEx, + * RTPathSetModeEx and RTPathSetTimesEx. + * + * @{ + */ + +/** + * Checks if the specified path exists and is a symlink. + * + * @returns true if it's a symlink, false if it isn't. + * @param pszSymlink The path to the symlink. + * + * @sa RTDirExists, RTPathExists, RTSymlinkExists. + */ +RTDECL(bool) RTSymlinkExists(const char *pszSymlink); + +/** + * Checks if this is a dangling link or not. + * + * If the target of @a pszSymlink is a symbolic link, this may return false if + * that or any subsequent links are dangling. + * + * @returns true if it's dangling, false if it isn't. + * @param pszSymlink The path to the symlink. + */ +RTDECL(bool) RTSymlinkIsDangling(const char *pszSymlink); + +/** + * RTSymlinkCreate link type argument. + */ +typedef enum RTSYMLINKTYPE +{ + /** Invalid value. */ + RTSYMLINKTYPE_INVALID = 0, + /** The link targets a directory. */ + RTSYMLINKTYPE_DIR, + /** The link targets a file (or whatever else). */ + RTSYMLINKTYPE_FILE, + /** It is not known what is being targeted. + * @remarks The RTSymlinkCreate API may probe the target to try figure + * out what is being targeted. */ + RTSYMLINKTYPE_UNKNOWN, + /** The end of the valid type values. */ + RTSYMLINKTYPE_END, + /** Blow the type up to 32-bit. */ + RTSYMLINKTYPE_32BIT_HACK = 0x7fffffff +} RTSYMLINKTYPE; + +/** @name RTSymlinkCreate flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTSYMLINKCREATE_FLAGS_NO_SYMLINKS RT_BIT(0) +/** @} */ + +/** + * Creates a symbolic link (@a pszSymlink) targeting @a pszTarget. + * + * @returns IPRT status code. + * + * @param pszSymlink The name of the symbolic link. + * @param pszTarget The path to the symbolic link target. This is + * relative to @a pszSymlink or an absolute path. + * @param enmType The symbolic link type. For Windows compatability + * it is very important to set this correctly. When + * RTSYMLINKTYPE_UNKNOWN is used, the API will try + * make a guess and may attempt query information + * about @a pszTarget in the process. + * @param fCreate Create flags, RTSYMLINKCREATE_FLAGS_*. + */ +RTDECL(int) RTSymlinkCreate(const char *pszSymlink, const char *pszTarget, + RTSYMLINKTYPE enmType, uint32_t fCreate); + +/** @name RTSymlinkDelete flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTSYMLINKDELETE_FLAGS_NO_SYMLINKS RT_BIT(0) +/** @} */ + +/** + * Deletes the specified symbolic link. + * + * This will try to refuse deleting non-symlinks, however there are usually + * races in the implementation of this check so no guarantees can be are made. + * + * @returns IPRT status code. + * @retval VERR_NOT_SYMLINK if @a pszSymlink does not specify a symbolic link. + * + * @param pszSymlink The symbolic link that should be removed. + * @param fDelete Delete flags, RTSYMLINKDELETE_FLAGS_*. + */ +RTDECL(int) RTSymlinkDelete(const char *pszSymlink, uint32_t fDelete); + +/** @name RTSymlinkRead flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTSYMLINKREAD_FLAGS_NO_SYMLINKS RT_BIT(0) +/** @} */ + +/** + * Read the symlink target. + * + * @returns IPRT status code. + * @retval VERR_NOT_SYMLINK if @a pszSymlink does not specify a symbolic link. + * @retval VERR_BUFFER_OVERFLOW if the link is larger than @a cbTarget. The + * buffer will contain what all we managed to read, fully terminated + * if @a cbTarget > 0. + * + * @param pszSymlink The symbolic link that should be read. + * @param pszTarget The target buffer. + * @param cbTarget The size of the target buffer. + * @param fRead Read flags, RTSYMLINKREAD_FLAGS_*. + */ +RTDECL(int) RTSymlinkRead(const char *pszSymlink, char *pszTarget, size_t cbTarget, uint32_t fRead); + +/** + * Read the symlink target into an API allocated buffer. + * + * This API eliminates the race involved in determining the right buffer size. + * + * @returns IPRT status code. + * @retval VERR_NOT_SYMLINK if @a pszSymlink does not specify a symbolic link. + * + * @param pszSymlink The symbolic link that should be read. + * @param ppszTarget Where to return the target string. Free the string + * by calling RTStrFree. + */ +RTDECL(int) RTSymlinkReadA(const char *pszSymlink, char **ppszTarget); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_symlink_h */ + diff --git a/include/iprt/system.h b/include/iprt/system.h new file mode 100644 index 00000000..a4bef54d --- /dev/null +++ b/include/iprt/system.h @@ -0,0 +1,379 @@ +/** @file + * IPRT - System Information. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_system_h +#define IPRT_INCLUDED_system_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_system RTSystem - System Information + * @ingroup grp_rt + * @{ + */ + +/** + * Info level for RTSystemGetOSInfo(). + */ +typedef enum RTSYSOSINFO +{ + RTSYSOSINFO_INVALID = 0, /**< The usual invalid entry. */ + RTSYSOSINFO_PRODUCT, /**< OS product name. (uname -o) */ + RTSYSOSINFO_RELEASE, /**< OS release. (uname -r) */ + RTSYSOSINFO_VERSION, /**< OS version, optional. (uname -v) */ + RTSYSOSINFO_SERVICE_PACK, /**< Service/fix pack level, optional. */ + RTSYSOSINFO_END /**< End of the valid info levels. */ +} RTSYSOSINFO; + + +/** + * Queries information about the OS. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_PARAMETER if enmInfo is invalid. + * @retval VERR_INVALID_POINTER if pszInfoStr is invalid. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer will + * contain the chopped off result in this case, provided cchInfo isn't 0. + * @retval VERR_NOT_SUPPORTED if the info level isn't implemented. The buffer will + * contain an empty string. + * + * @param enmInfo The OS info level. + * @param pszInfo Where to store the result. + * @param cchInfo The size of the output buffer. + */ +RTDECL(int) RTSystemQueryOSInfo(RTSYSOSINFO enmInfo, char *pszInfo, size_t cchInfo); + +/** + * Queries the total amount of RAM in the system. + * + * This figure does not given any information about how much memory is + * currently available. Use RTSystemQueryAvailableRam instead. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pcb on sucess. + * @retval VERR_ACCESS_DENIED if the information isn't accessible to the + * caller. + * + * @param pcb Where to store the result (in bytes). + */ +RTDECL(int) RTSystemQueryTotalRam(uint64_t *pcb); + +/** + * Queries the total amount of RAM accessible to the system. + * + * This figure should not include memory that is installed but not used, + * nor memory that will be slow to bring online. The definition of 'slow' + * here is slower than swapping out a MB of pages to disk. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pcb on success. + * @retval VERR_ACCESS_DENIED if the information isn't accessible to the + * caller. + * + * @param pcb Where to store the result (in bytes). + */ +RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb); + +/** + * Queries the amount of RAM that is currently locked down or in some other + * way made impossible to virtualize within reasonably short time. + * + * The purposes of this API is, when combined with RTSystemQueryTotalRam, to + * be able to determine an absolute max limit for how much fixed memory it is + * (theoretically) possible to allocate (or lock down). + * + * The kind memory covered by this function includes: + * - locked (wired) memory - like for instance RTR0MemObjLockUser + * and RTR0MemObjLockKernel makes, + * - kernel pools and heaps - like for instance the ring-0 variant + * of RTMemAlloc taps into, + * - fixed (not pageable) kernel allocations - like for instance + * all the RTR0MemObjAlloc* functions makes, + * - any similar memory that isn't easily swapped out, discarded, + * or flushed to disk. + * + * This works against the value returned by RTSystemQueryTotalRam, and + * the value reported by this function can never be larger than what a + * call to RTSystemQueryTotalRam returns. + * + * The short time term here is relative to swapping to disk like in + * RTSystemQueryTotalRam. This could mean that (part of) the dirty buffers + * in the dynamic I/O cache could be included in the total. If the dynamic + * I/O cache isn't likely to either flush buffers when the load increases + * and put them back into normal circulation, they should be included in + * the memory accounted for here. + * + * @retval VINF_SUCCESS and *pcb on success. + * @retval VERR_NOT_SUPPORTED if the information isn't available on the + * system in general. The caller must handle this scenario. + * @retval VERR_ACCESS_DENIED if the information isn't accessible to the + * caller. + * + * @param pcb Where to store the result (in bytes). + * + * @remarks This function could've been inverted and called + * RTSystemQueryAvailableRam, but that might give impression that + * it would be possible to allocate the amount of memory it + * indicates for a single purpose, something which would be very + * improbable on most systems. + * + * @remarks We might have to add another output parameter to this function + * that indicates if some of the memory kinds listed above cannot + * be accounted for on the system and therefore is not include in + * the returned amount. + */ +RTDECL(int) RTSystemQueryUnavailableRam(uint64_t *pcb); + + +/** + * The DMI strings. + */ +typedef enum RTSYSDMISTR +{ + /** Invalid zero entry. */ + RTSYSDMISTR_INVALID = 0, + /** The product name. */ + RTSYSDMISTR_PRODUCT_NAME, + /** The product version. */ + RTSYSDMISTR_PRODUCT_VERSION, + /** The product UUID. */ + RTSYSDMISTR_PRODUCT_UUID, + /** The product serial. */ + RTSYSDMISTR_PRODUCT_SERIAL, + /** The system manufacturer. */ + RTSYSDMISTR_MANUFACTURER, + /** The end of the valid strings. */ + RTSYSDMISTR_END, + /** The usual 32-bit hack. */ + RTSYSDMISTR_32_BIT_HACK = 0x7fffffff +} RTSYSDMISTR; + +/** + * Queries a DMI string. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer will + * contain the chopped off result in this case, provided cbBuf isn't 0. + * @retval VERR_ACCESS_DENIED if the information isn't accessible to the + * caller. + * @retval VERR_NOT_SUPPORTED if the information isn't available on the system + * in general. The caller must expect this status code and deal with + * it. + * + * @param enmString Which string to query. + * @param pszBuf Where to store the string. This is always + * terminated, even on error. + * @param cbBuf The buffer size. + */ +RTDECL(int) RTSystemQueryDmiString(RTSYSDMISTR enmString, char *pszBuf, size_t cbBuf); + +/** @name Flags for RTSystemReboot and RTSystemShutdown. + * @{ */ +/** Reboot the system after shutdown. */ +#define RTSYSTEM_SHUTDOWN_REBOOT UINT32_C(0) +/** Reboot the system after shutdown. + * The call may return VINF_SYS_MAY_POWER_OFF if the OS / + * hardware combination may power off instead of halting. */ +#define RTSYSTEM_SHUTDOWN_HALT UINT32_C(1) +/** Power off the system after shutdown. + * This may be equvivalent to a RTSYSTEM_SHUTDOWN_HALT on systems where we + * cannot figure out whether the hardware/OS implements the actual powering + * off. If we can figure out that it's not supported, an + * VERR_SYS_CANNOT_POWER_OFF error is raised. */ +#define RTSYSTEM_SHUTDOWN_POWER_OFF UINT32_C(2) +/** Power off the system after shutdown, or halt it if that's not possible. */ +#define RTSYSTEM_SHUTDOWN_POWER_OFF_HALT UINT32_C(3) +/** The shutdown action mask. */ +#define RTSYSTEM_SHUTDOWN_ACTION_MASK UINT32_C(3) +/** Unplanned shutdown/reboot. */ +#define RTSYSTEM_SHUTDOWN_UNPLANNED UINT32_C(0) +/** Planned shutdown/reboot. */ +#define RTSYSTEM_SHUTDOWN_PLANNED RT_BIT_32(2) +/** Force the system to shutdown/reboot regardless of objecting application + * or other stuff. This flag might not be realized on all systems. */ +#define RTSYSTEM_SHUTDOWN_FORCE RT_BIT_32(3) +/** Parameter validation mask. */ +#define RTSYSTEM_SHUTDOWN_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Shuts down the system. + * + * @returns IPRT status code on failure, on success it may or may not return + * depending on the OS. + * @retval VINF_SUCCESS + * @retval VINF_SYS_MAY_POWER_OFF + * @retval VERR_SYS_SHUTDOWN_FAILED + * @retval VERR_SYS_CANNOT_POWER_OFF + * + * @param cMsDelay The delay before the actual reboot. If this is + * not supported by the OS, an immediate reboot + * will be performed. + * @param fFlags Shutdown flags, see RTSYSTEM_SHUTDOWN_XXX. + * @param pszLogMsg Message for the log and users about why we're + * shutting down. + */ +RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char *pszLogMsg); + +/** + * Checks if we're executing inside a virtual machine (VM). + * + * The current implemention is very simplistic and won't try to detect the + * presence of a virtual machine monitor (VMM) unless it openly tells us it is + * there. + * + * @returns true if inside a VM, false if on real hardware. + * + * @todo If more information is needed, like which VMM it is and which + * version and such, add one or two new APIs. + */ +RTDECL(bool) RTSystemIsInsideVM(void); + +/** + * System firmware types. + */ +typedef enum RTSYSFWTYPE +{ + /** Invalid zero value. */ + RTSYSFWTYPE_INVALID = 0, + /** Unknown firmware. */ + RTSYSFWTYPE_UNKNOWN, + /** Firmware is BIOS. */ + RTSYSFWTYPE_BIOS, + /** Firmware is UEFI. */ + RTSYSFWTYPE_UEFI, + /** End valid firmware values (exclusive). */ + RTSYSFWTYPE_END, + /** The usual 32-bit hack. */ + RTSYSFWTYPE_32_BIT_HACK = 0x7fffffff +} RTSYSFWTYPE; +/** Pointer to a system firmware type. */ +typedef RTSYSFWTYPE *PRTSYSFWTYPE; + +/** + * Queries the system's firmware type. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported or implemented. + * @param penmType Where to return the firmware type on success. + */ +RTDECL(int) RTSystemQueryFirmwareType(PRTSYSFWTYPE penmType); + +/** + * Translates the @a enmType value to a string. + * + * @returns Read-only name. + * @param enmType The firmware type to convert to string. + */ +RTDECL(const char *) RTSystemFirmwareTypeName(RTSYSFWTYPE enmType); + +/** + * Boolean firmware values queriable via RTSystemQueryFirmwareBoolean(). + */ +typedef enum RTSYSFWBOOL +{ + /** Invalid property, do not use. */ + RTSYSFWBOOL_INVALID = 0, + /** Whether Secure Boot is enabled or not (type: boolean). */ + RTSYSFWBOOL_SECURE_BOOT, + /** End of valid */ + RTSYSFWBOOL_END, + /** The usual 32-bit hack. */ + RTSYSFWBOOL_32_BIT_HACK = 0x7fffffff +} RTSYSFWBOOL; + +/** + * Queries the value of a firmware property. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if we cannot query firmware properties on the host. + * @retval VERR_SYS_UNSUPPORTED_FIRMWARE_PROPERTY if @a enmBoolean isn't + * supported. + * @param enmBoolean The value to query. + * @param pfValue Where to return the value. + */ +RTDECL(int) RTSystemQueryFirmwareBoolean(RTSYSFWBOOL enmBoolean, bool *pfValue); + +#ifdef RT_OS_WINDOWS + +/** + * Get the Windows NT build number. + * + * @returns NT build number. + * + * @remarks Windows NT only. Requires IPRT to be initialized. + */ +RTDECL(uint32_t) RTSystemGetNtBuildNo(void); + +/** Makes an NT version for comparison with RTSystemGetNtVersion(). */ +# define RTSYSTEM_MAKE_NT_VERSION(a_uMajor, a_uMinor, a_uBuild) \ + ( ((uint64_t)(a_uMajor) << 52) | ((uint64_t)((a_uMinor) & 0xfffU) << 40) | ((uint32_t)(a_uBuild)) ) +/** Extracts the major version number from a RTSYSTEM_MAKE_NT_VERSION value. */ +# define RTSYSTEM_NT_VERSION_GET_MAJOR(a_uNtVersion) ((uint32_t)((a_uNtVersion) >> 52)) +/** Extracts the minor version number from a RTSYSTEM_MAKE_NT_VERSION value. */ +# define RTSYSTEM_NT_VERSION_GET_MINOR(a_uNtVersion) ((uint32_t)((a_uNtVersion) >> 40) & UINT32_C(0xfff)) +/** Extracts the build number from a RTSYSTEM_MAKE_NT_VERSION value. */ +# define RTSYSTEM_NT_VERSION_GET_BUILD(a_uNtVersion) ((uint32_t)(a_uNtVersion)) + +/** + * Get the Windows NT version number. + * + * @returns Version formatted using RTSYSTEM_MAKE_NT_VERSION(). + * + * @remarks Windows NT only. Requires IPRT to be initialized. + */ +RTDECL(uint64_t) RTSystemGetNtVersion(void); + +/** + * Get the Windows NT product type (OSVERSIONINFOW::wProductType). + */ +RTDECL(uint8_t) RTSystemGetNtProductType(void); + +#endif /* RT_OS_WINDOWS */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_system_h */ + diff --git a/include/iprt/table.h b/include/iprt/table.h new file mode 100644 index 00000000..d8bd8f88 --- /dev/null +++ b/include/iprt/table.h @@ -0,0 +1,726 @@ +/** @file + * IPRT - Abstract Table/Trees. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_table_h +#define IPRT_INCLUDED_table_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_rt_tab RTTab - Generic Tree and Table Interface. + * @ingroup grp_rt + * @{ + */ + +RT_C_DECLS_BEGIN + +/** Pointer to an allocator. */ +typedef struct RTTABALLOCATOR *PRTTABALLOCATOR; + +/** + * Allocates memory. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. (don't throw!) + * @param pAllocator The allocator structure. + * @param cb The number of bytes to allocate. (Never 0.) + */ +typedef DECLCALLBACKTYPE(void *, FNRTTABALLOC,(PRTTABALLOCATOR pAllocator, size_t cb)); +/** Pointer to a FNRTTABALLOC() function. */ +typedef FNRTTABALLOC *PFNRTTABALLOC; + +/** + * Frees memory. + * + * @param pAllocator The allocator structure. + * @param pv The memory to free. (can be NULL) + */ +typedef DECLCALLBACKTYPE(void *, FNRTTABFREE,(PRTTABALLOCATOR pAllocator, void *pv)); +/** Pointer to a FNRTTABFREE() function. */ +typedef FNRTTABFREE *PFNRTTABFREE; + +/** + * The allocator structure. + * (Hint: use this as like 'base class' for your custom allocators.) + */ +typedef struct RTTABALLOCATOR +{ + /** The allocation function. */ + PFNRTTABALLOC pfnAlloc; + /** The free function. */ + PFNRTTABFREE pfnFree; +} RTTABALLOCATOR; + +/** + * Gets the default allocator. + * + * @returns Pointer to the default allocator. + */ +RTDECL(RTTABALLOCATOR) RTTabDefaultAllocator(void); + + +/** + * Compares two table items. + * + * @returns 0 if equal + * @returns <0 if pvItem1 is less than pvItem2 (pvItem2 is then greater than pvItem1). + * @returns >0 if pvItem1 is less than pvItem2 (pvItem1 is then greater than pvItem2). + * + * @param pvItem1 The first item. + * @param pvItem2 The second item. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTTABCOMP,(const void *pvItem1, const void *pvItem2, void *pvUser)); +/** Pointer to a FNRTTABCOMP() function. */ +typedef FNRTTABCOMP *PFNRTTABCOMP; + +/** + * Duplicates a table item. + * This is used when duplicating or copying a table. + * + * @returns Pointer to the copy. + * @returns NULL on failure. + * + * @param pvItem The item to copy. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void *, FNRTTABDUPLICATE,(const void *pvItem, void *pvUser)); +/** Pointer to a FNRTTABDUPLICATE() function. */ +typedef FNRTTABDUPLICATE *PFNRTTABDUPLICATE; + +/** + * Callback function for doing something with an item. + * + * What exactly we're doing is specific to the context of the call. + * + * @param pvItem The item. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTTABCALLBACK,(const void *pvItem, void *pvUser)); +/** Pointer to a FNRTTABCALLBACK() function. */ +typedef FNRTTABCALLBACK *PFNRTTABCALLBACK; + + +/** Pointer to const table operations. */ +typedef const struct RTTABOPS *PCRTTABOPS; +/** Pointer to a table. */ +typedef struct RTTAB *PRTTAB; +/** Pointer to a const table. */ +typedef const struct RTTAB *PCRTTAB; +/** Pointer to a traverser. */ +typedef struct RTTABTRAVERSER *PRTTABTRAVERSER; +/** Pointer to a const traverser. */ +typedef const struct RTTABTRAVERSER *PCRTTABTRAVERSER; +/** Pointer to a traverser core. */ +typedef struct RTTABTRAVERSERCORE *PRTTABTRAVERSERCORE; +/** Pointer to a const traverser core. */ +typedef const struct RTTABTRAVERSERCORE *PCRTTABTRAVERSERCORE; + + +/** + * Table operations. + */ +typedef struct RTTABOPS +{ + /** + * Create a table. + * + * @returns Pointer to the new table. + * @returns NULL if we're out of memory or some other resource. + * @param pOps The table operations. + * @param fCreateFlags The table type specific creation flags. + * @param pAllocator Custom allocator. Pass NULL for the default allocator. + * @param pfnComp The comparision function. + */ + DECLCALLBACKMEMBER(PRTTAB, pfnCreate,(PCRTTABOPS pOps, unsigned fCreateFlags, PRTTABALLOCATOR pAllocator, PFNRTTABCOMP pfnComp)); + + /** + * Duplicates a table to a table of the same type. + * + * @returns Pointer to the new table. + * @returns NULL if we're out of memory or some other resource. + * @param pTab The table to duplicate. + * @param pfnDuplicate Pointer to the item duplication function. If NULL the new table will + * be referencing the same data as the old one. + * @param pfnNewCB Callback which is called for all the items in the new table. Optional. + * @param pAllocator Custom allocator. Pass NULL to use the same allocator as pTab. + */ + DECLCALLBACKMEMBER(PRTTAB, pfnDuplicate,(PCRTTAB pTab, PFNRTTABDUPLICATE pfnDuplicate, PFNRTTABCALLBACK pfnNewCB, PRTTABALLOCATOR pAllocator)); + + /** + * Destroys a table. + * + * @param pTab The table to destroy. + */ + DECLCALLBACKMEMBER(void, pfnDestroy,(PRTTAB pTab)); + + /** + * Inserts an item into the table, if a matching item is encountered + * the pointer to the pointer to it will be returned. + * + * @returns Pointer to the item pointer in the table. + * This can be used to replace existing items (don't break anything, dude). + * @returns NULL if we failed to allocate memory for the new node. + * @param pTab The table. + * @param pvItem The item which will be inserted if an matching item was not found in the table. + */ + DECLCALLBACKMEMBER(void **, pfnProbe,(PRTTAB pTab, void *pvItem)); + + /** + * Inserts an item into the table, fail if a matching item exists. + * + * @returns NULL on success and allocation failure. + * @returns Pointer to the matching item. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnInsert,(PRTTAB pTab, void *pvItem)); + + /** + * Inserts an item into the table, if a matching item is encountered + * it will be replaced and returned. + * + * @returns NULL if inserted and allocation failure. + * @returns Pointer to the replaced item. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnReplace,(PRTTAB pTab, void *pvItem)); + + /** + * Removes an item from the table if found. + * + * @returns Pointer to the removed item. + * @returns NULL if no item matched pvItem. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnRemove,(PRTTAB pTab, const void *pvItem)); + + /** + * Finds an item in the table. + * + * @returns Pointer to the item it found. + * @returns NULL if no item matched pvItem. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnFind,(PRTTAB pTab, const void *pvItem)); + + /** + * Initializes a traverser to the NULL item. + * + * The NULL item is an imaginary table item before the first and after + * the last items in the table. + * + * @returns Pointer to the traverser positioned at the NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravInit,(PRTTAB pTab, PRTTABTRAVERSER pTravNew)); + + /** + * Initializes a traverser to the first item in the table. + * + * If the table is empty, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the first item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravFirst,(PRTTAB pTab, PRTTABTRAVERSER pTravNew)); + + /** + * Initializes a traverser to the last item in the table. + * + * If the table is empty, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the last item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravLast,(PRTTAB pTab, PRTTABTRAVERSER pTravNew)); + + /** + * Initializes a traverser to an item matching the given one. + * + * If the item isn't found, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the matching item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + * @param pvItem The item to find the match to. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravFind,(PRTTAB pTab, PRTTABTRAVERSER pTravNew, const void *pvItem)); + + /** + * Initializes a traverser to the inserted item. + * + * If there already exists an item in the tree matching pvItem, the traverser + * is positioned at that item like with RTTabTravFind(). + * + * If the insert operation failes because of an out of memory condition, the + * traverser will be positioned at the NULL item like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the inserted, existing or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + * @param pvItem The item to be inserted. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravInsert,(PRTTAB pTab, PRTTABTRAVERSER pTravNew, void *pvItem)); + + /** + * Duplicates a traverser. + * + * @returns The pointer to the duplicate. + * @returns NULL on allocation failure. + * + * @param pTrav The traverser to duplicate. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravDuplicate,(PRTTABTRAVERSERCORE pTrav, PCRTTABTRAVERSER pTravNew)); + + /** + * Frees a traverser. + * + * This can safely be called even if the traverser structure + * wasn't dynamically allocated or the constructor failed. + * + * @param pTrav The traverser which is to be free. + */ + DECLCALLBACKMEMBER(void, pfnTravFree,(PRTTABTRAVERSERCORE pTrav)); + + /** + * Gets the current item. + * + * @returns The current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ + DECLCALLBACKMEMBER(void *, pfnTravCur,(PCRTTABTRAVERSERCORE pTrav)); + + /** + * Advances to the next item. + * + * @returns The new current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ + DECLCALLBACKMEMBER(void *, pfnTravNext,(PRTTABTRAVERSERCORE pTrav)); + + /** + * Advances to the previous item. + * + * @returns The new current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ + DECLCALLBACKMEMBER(void *, pfnTravPrev,(PRTTABTRAVERSERCORE pTrav)); + + /** + * Replaces the current item. + * + * This has the same restrictions as RTTabProbe(), e.g. it's not permitted to + * break the order of the table. + * + * @returns The replaced item. + * @returns NULL if the current item is the NULL item. The traverser + * and table remains unchanged. + * @param pTrav The traverser. + * @param pvItem The item to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnTravReplace,(PRTTABTRAVERSERCORE pTrav, void *pvItem)); + + /** The type of table type. */ + const char *pszType; +} RTTABOPS; + +/** + * A table. + */ +typedef struct RTTAB +{ + /** The table operations. */ + PCRTTABOPS pOps; + /** The function for comparing table items. */ + PFNRTTABCOMP pfnComp; + /** The number of items in the table. */ + RTUINT cItems; + /** The table generation number. + * This must be updated whenever the table changes. */ + RTUINT idGeneration; +} RTTAB; + + +/** + * Create a table. + * + * @returns Pointer to the new table. + * @returns NULL if we're out of memory or some other resource. + * @param pOps The table operations. + * @param fCreateFlags The table type specific creation flags. + * @param pAllocator Custom allocator. Pass NULL for the default allocator. + * @param pfnComp The comparision function. + */ +DECLINLINE(PRTTAB) RTTabCreate(PCRTTABOPS pOps, unsigned fCreateFlags, PRTTABALLOCATOR pAllocator, PFNRTTABCOMP pfnComp) +{ + return pOps->pfnCreate(pOps, fCreateFlags, pAllocator, pfnComp); +} + +/** + * Duplicates a table to a table of the same type. + * + * @returns Pointer to the new table. + * @returns NULL if we're out of memory or some other resource. + * @param pTab The table to duplicate. + * @param pfnDuplicate Pointer to the item duplication function. If NULL the new table will + * be referencing the same data as the old one. + * @param pfnNewCB Callback which is called for all the items in the new table. Optional. + * @param pAllocator Custom allocator. Pass NULL to use the same allocator as pTab. + */ +DECLINLINE(PRTTAB) RTTabDuplicate(PCRTTAB pTab, PFNRTTABDUPLICATE pfnDuplicate, PFNRTTABCALLBACK pfnNewCB, PRTTABALLOCATOR pAllocator) +{ + return pTab->pOps->pfnDuplicate(pTab, pfnDuplicate, pfnNewCB, pAllocator); +} + +/** + * Destroys a table. + * + * @param pTab The table to destroy. + */ +DECLINLINE(void) RTTabDestroy(PRTTAB pTab) +{ + pTab->pOps->pfnDestroy(pTab); +} + +/** + * Count the item in the table. + * + * @returns Number of items in the table. + * @param pTab The table to count. + */ +DECLINLINE(RTUINT) RTTabCount(PRTTAB pTab) +{ + return pTab->cItems; +} + +/** + * Inserts an item into the table, if a matching item is encountered + * the pointer to the pointer to it will be returned. + * + * @returns Pointer to the item pointer in the table. + * This can be used to replace existing items (don't break anything, dude). + * @returns NULL if we failed to allocate memory for the new node. + * @param pTab The table. + * @param pvItem The item which will be inserted if an matching item was not found in the table. + */ +DECLINLINE(void **) RTTabProbe(PRTTAB pTab, void *pvItem) +{ + return pTab->pOps->pfnProbe(pTab, pvItem); +} + +/** + * Inserts an item into the table, fail if a matching item exists. + * + * @returns NULL on success and allocation failure. + * @returns Pointer to the matching item. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ +DECLINLINE(void *) RTTabInsert(PRTTAB pTab, void *pvItem) +{ + return pTab->pOps->pfnInsert(pTab, pvItem); +} + +/** + * Inserts an item into the table, if a matching item is encountered + * it will be replaced and returned. + * + * @returns NULL if inserted and allocation failure. + * @returns Pointer to the replaced item. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ +DECLINLINE(void *) RTTabReplace(PRTTAB pTab, void *pvItem) +{ + return pTab->pOps->pfnReplace(pTab, pvItem); +} + +/** + * Removes an item from the table if found. + * + * @returns Pointer to the removed item. + * @returns NULL if no item matched pvItem. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ +DECLINLINE(void *) RTTabRemove(PRTTAB pTab, const void *pvItem) +{ + return pTab->pOps->pfnRemove(pTab, pvItem); +} + +/** + * Finds an item in the table. + * + * @returns Pointer to the item it found. + * @returns NULL if no item matched pvItem. + * @param pTab The table. + * @param pvItem The item to find the match to. + */ +DECLINLINE(void *) RTTabFind(PRTTAB pTab, const void *pvItem) +{ + return pTab->pOps->pfnFind(pTab, pvItem); +} + + +/** + * Common traverser core. + */ +typedef struct RTTABTRAVERSERCORE +{ + /** The table being traversed. */ + PRTTAB pTab; + /** Indicates that this traverser was allocated. */ + bool fAllocated; + /** The table generation id this traverser was last updated for. + * This is used to catch up with table changes. */ + RTUINT idGeneration; +} RTTABTRAVERSERCORE; + +/** + * Generic traverser structure. + * + * Tree implementations will use the tree specific part by mapping + * this structure onto their own internal traverser structure. + * + * @remark It would be better to use alloca() for allocating the structure, + * OTOH this is simpler for the user. + */ +typedef struct RTTABTRAVERSER +{ + /** The common core of the traverser data. */ + RTTABTRAVERSERCORE Core; + /** The tree specific data. */ + void *apvTreeSpecific[32]; +} RTTABTRAVERSER; + + +/** + * Initializes a traverser to the NULL item. + * + * The NULL item is an imaginary table item before the first and after + * the last items in the table. + * + * @returns Pointer to the traverser positioned at the NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravInit(PRTTAB pTab, PRTTABTRAVERSER pTravNew) +{ + return pTab->pOps->pfnTravInit(pTab, pTravNew); +} + +/** + * Initializes a traverser to the first item in the table. + * + * If the table is empty, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the first item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravFirst(PRTTAB pTab, PRTTABTRAVERSER pTravNew) +{ + return pTab->pOps->pfnTravFirst(pTab, pTravNew); +} + +/** + * Initializes a traverser to the last item in the table. + * + * If the table is empty, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the last item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravLast(PRTTAB pTab, PRTTABTRAVERSER pTravNew) +{ + return pTab->pOps->pfnTravLast(pTab, pTravNew); +} + +/** + * Initializes a traverser to an item matching the given one. + * + * If the item isn't found, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the matching item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + * @param pvItem The item to find the match to. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravFind(PRTTAB pTab, PRTTABTRAVERSER pTravNew, const void *pvItem) +{ + return pTab->pOps->pfnTravFind(pTab, pTravNew, pvItem); +} + +/** + * Initializes a traverser to the inserted item. + * + * If there already exists an item in the tree matching pvItem, the traverser + * is positioned at that item like with RTTabTravFind(). + * + * If the insert operation failes because of an out of memory condition, the + * traverser will be positioned at the NULL item like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the inserted, existing or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + * @param pvItem The item to be inserted. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravInsert(PRTTAB pTab, PRTTABTRAVERSER pTravNew, void *pvItem) +{ + return pTab->pOps->pfnTravInsert(pTab, pTravNew, pvItem); +} + +/** + * Duplicates a traverser. + * + * @returns The pointer to the duplicate. + * @returns NULL on allocation failure. + * + * @param pTrav The traverser to duplicate. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravDuplicate(PRTTABTRAVERSERCORE pTrav, PCRTTABTRAVERSER pTravNew) +{ + if (pTrav) + return pTrav->pTab->pOps->pfnTravDuplicate(pTrav, pTravNew); + return NULL; +} + +/** + * Frees a traverser. + * + * This can safely be called even if the traverser structure + * wasn't dynamically allocated or the constructor failed. + * + * @param pTrav The traverser which is to be free. + */ +DECLINLINE(void) RTTabTravFree(PRTTABTRAVERSERCORE pTrav) +{ + if (pTrav && pTrav->fAllocated) + pTrav->pTab->pOps->pfnTravFree(pTrav); +} + +/** + * Gets the current item. + * + * @returns The current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ +DECLINLINE(void *) RTTabTravCur(PCRTTABTRAVERSERCORE pTrav) +{ + return pTrav->pTab->pOps->pfnTravCur(pTrav); +} + +/** + * Advances to the next item. + * + * @returns The new current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ +DECLINLINE(void *) RTTabTravNext(PRTTABTRAVERSERCORE pTrav) +{ + return pTrav->pTab->pOps->pfnTravNext(pTrav); +} + +/** + * Advances to the previous item. + * + * @returns The new current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ +DECLINLINE(void *) RTTabTravPrev(PRTTABTRAVERSERCORE pTrav) +{ + return pTrav->pTab->pOps->pfnTravPrev(pTrav); +} + +/** + * Replaces the current item. + * + * This has the same restrictions as RTTabProbe(), e.g. it's not permitted to + * break the order of the table. + * + * @returns The replaced item. + * @returns NULL if the current item is the NULL item. The traverser + * and table remains unchanged. + * @param pTrav The traverser. + * @param pvItem The item to be inserted. + */ +DECLINLINE(void *) RTTabTravReplace(PRTTABTRAVERSERCORE pTrav, void *pvItem) +{ + return pTrav->pTab->pOps->pfnTravReplace(pTrav, pvItem); +} + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_table_h */ diff --git a/include/iprt/tar.h b/include/iprt/tar.h new file mode 100644 index 00000000..9acc0d40 --- /dev/null +++ b/include/iprt/tar.h @@ -0,0 +1,184 @@ +/** @file + * IPRT - Tar archive I/O. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_tar_h +#define IPRT_INCLUDED_tar_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_tar RTTar - Tar archive I/O + * @ingroup grp_rt + * + * @deprecated Only used for legacy code and writing. Migrate new code to the + * VFS interface, add the write part when needed. + * + * @{ + */ + +/** A tar handle */ +typedef R3PTRTYPE(struct RTTARINTERNAL *) RTTAR; +/** Pointer to a RTTAR interface handle. */ +typedef RTTAR *PRTTAR; +/** Nil RTTAR interface handle. */ +#define NIL_RTTAR ((RTTAR)0) + +/** A tar file handle */ +typedef R3PTRTYPE(struct RTTARFILEINTERNAL *) RTTARFILE; +/** Pointer to a RTTARFILE interface handle. */ +typedef RTTARFILE *PRTTARFILE; +/** Nil RTTARFILE interface handle. */ +#define NIL_RTTARFILE ((RTTARFILE)0) + +/** Maximum length of a tar filename, excluding the terminating '\0'. More + * does not fit into a tar record. */ +#define RTTAR_NAME_MAX 99 + +/** + * Creates a Tar archive. + * + * Use the mask to specify the access type. + * + * @returns IPRT status code. + * + * @param phTar Where to store the RTTAR handle. + * @param pszTarname The file name of the tar archive to create. Should + * not exist. + * @param fMode Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + */ +RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char *pszTarname, uint32_t fMode); + +/** + * Close the Tar archive. + * + * @returns IPRT status code. + * + * @param hTar Handle to the RTTAR interface. + */ +RTR3DECL(int) RTTarClose(RTTAR hTar); + +/** + * Open a file in the Tar archive. + * + * @returns IPRT status code. + * + * @param hTar The handle of the tar archive. + * @param phFile Where to store the handle to the opened file. + * @param pszFilename Path to the file which is to be opened. (UTF-8) + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION flags are mandatory! DENY flags + * are currently not supported. + * + * @remarks Write mode means append mode only. It is not possible to make + * changes to existing files. + * + * @remarks Currently it is not possible to open more than one file in write + * mode. Although open more than one file in read only mode (even when + * one file is opened in write mode) is always possible. + */ +RTR3DECL(int) RTTarFileOpen(RTTAR hTar, PRTTARFILE phFile, const char *pszFilename, uint32_t fOpen); + +/** + * Close the file opened by RTTarFileOpen. + * + * @returns IPRT status code. + * + * @param hFile The file handle to close. + */ +RTR3DECL(int) RTTarFileClose(RTTARFILE hFile); + +/** + * Read bytes from a file at a given offset. + * This function may modify the file position. + * + * @returns IPRT status code. + * + * @param hFile Handle to the file. + * @param off Where to read. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. + * @param pcbRead Where to return how much we actually read. If NULL + * an error will be returned for a partial read. + */ +RTR3DECL(int) RTTarFileReadAt(RTTARFILE hFile, uint64_t off, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Write bytes to a file at a given offset. + * This function may modify the file position. + * + * @returns IPRT status code. + * + * @param hFile Handle to the file. + * @param off Where to write. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten Where to return how much we actually wrote. If NULL + * an error will be returned for a partial write. + */ +RTR3DECL(int) RTTarFileWriteAt(RTTARFILE hFile, uint64_t off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Query the size of the file. + * + * @returns IPRT status code. + * + * @param hFile Handle to the file. + * @param pcbSize Where to store the filesize. + */ +RTR3DECL(int) RTTarFileGetSize(RTTARFILE hFile, uint64_t *pcbSize); + +/** + * Set the size of the file. + * + * @returns IPRT status code. + * + * @param hFile Handle to the file. + * @param cbSize The new file size. + */ +RTR3DECL(int) RTTarFileSetSize(RTTARFILE hFile, uint64_t cbSize); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_tar_h */ + diff --git a/include/iprt/tcp.h b/include/iprt/tcp.h new file mode 100644 index 00000000..c637915e --- /dev/null +++ b/include/iprt/tcp.h @@ -0,0 +1,514 @@ +/** @file + * IPRT - TCP/IP. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_tcp_h +#define IPRT_INCLUDED_tcp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef IN_RING0 +# error "There are no RTFile APIs available Ring-0 Host Context!" +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_tcp RTTcp - TCP/IP + * @ingroup grp_rt + * @{ + */ + + +/** + * Serve a TCP Server connection. + * + * @returns iprt status code. + * @returns VERR_TCP_SERVER_STOP to terminate the server loop forcing + * the RTTcpCreateServer() call to return. + * @param hSocket The socket which the client is connected to. The call + * will close this socket. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTTCPSERVE,(RTSOCKET hSocket, void *pvUser)); +/** Pointer to a RTTCPSERVE(). */ +typedef FNRTTCPSERVE *PFNRTTCPSERVE; + +/** + * Create single connection at a time TCP Server in a separate thread. + * + * The thread will loop accepting connections and call pfnServe for + * each of the incoming connections in turn. The pfnServe function can + * return VERR_TCP_SERVER_STOP too terminate this loop. RTTcpServerDestroy() + * should be used to terminate the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a listening socket. + * If NULL or empty string the server is bound to all interfaces. + * @param uPort The port for creating a listening socket. + * @param enmType The thread type. + * @param pszThrdName The name of the worker thread. + * @param pfnServe The function which will serve a new client connection. + * @param pvUser User argument passed to pfnServe. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTTcpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName, + PFNRTTCPSERVE pfnServe, void *pvUser, PPRTTCPSERVER ppServer); + +/** + * Create single connection at a time TCP Server. + * The caller must call RTTcpServerListen() to actually start the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a listening socket. + * If NULL the server is bound to all interfaces. + * @param uPort The port for creating a listening socket. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTTcpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTTCPSERVER ppServer); + +/** + * Closes down and frees a TCP Server. + * This will also terminate any open connections to the server. + * + * @returns iprt status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTTcpServerDestroy(PRTTCPSERVER pServer); + +/** + * Listen for incoming connections. + * + * The function will loop accepting connections and call pfnServe for + * each of the incoming connections in turn. The pfnServe function can + * return VERR_TCP_SERVER_STOP too terminate this loop. A stopped server + * can only be destroyed. + * + * @returns iprt status code. + * @param pServer The server handle as returned from RTTcpServerCreateEx(). + * @param pfnServe The function which will serve a new client connection. + * @param pvUser User argument passed to pfnServe. + */ +RTR3DECL(int) RTTcpServerListen(PRTTCPSERVER pServer, PFNRTTCPSERVE pfnServe, void *pvUser); + +/** + * Listen and accept one incoming connection. + * + * This is an alternative to RTTcpServerListen for the use the callbacks are not + * possible. + * + * @returns IPRT status code. + * @retval VERR_TCP_SERVER_SHUTDOWN if shut down by RTTcpServerShutdown. + * @retval VERR_INTERRUPTED if the listening was interrupted. + * + * @param pServer The server handle as returned from RTTcpServerCreateEx(). + * @param phClientSocket Where to return the socket handle to the client + * connection (on success only). This must be closed + * by calling RTTcpServerDisconnectClient2(). + */ +RTR3DECL(int) RTTcpServerListen2(PRTTCPSERVER pServer, PRTSOCKET phClientSocket); + +/** + * Terminate the open connection to the server. + * + * @returns iprt status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTTcpServerDisconnectClient(PRTTCPSERVER pServer); + +/** + * Terminates an open client connect when using RTTcpListen2 + * + * @returns IPRT status code. + * @param hClientSocket The client socket handle. This will be invalid upon + * return, whether successful or not. NIL is quietly + * ignored (VINF_SUCCESS). + */ +RTR3DECL(int) RTTcpServerDisconnectClient2(RTSOCKET hClientSocket); + +/** + * Shuts down the server, leaving client connections open. + * + * @returns IPRT status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTTcpServerShutdown(PRTTCPSERVER pServer); + +/** + * Connect (as a client) to a TCP Server. + * + * @returns iprt status code. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param pSock Where to store the handle to the established connection. + */ +RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock); + +/** Opaque pointer used by RTTcpClientConnectEx and RTTcpClientCancelConnect. */ +typedef struct RTTCPCLIENTCONNECTCANCEL *PRTTCPCLIENTCONNECTCANCEL; + +/** + * Connect (as a client) to a TCP Server, extended version. + * + * @returns iprt status code. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param pSock Where to store the handle to the established connection. + * @param cMillies Number of milliseconds to wait for the connect attempt to complete. + * Use RT_INDEFINITE_WAIT to wait for ever. + * Use RT_SOCKETCONNECT_DEFAULT_WAIT to wait for the default time + * configured on the running system. + * @param ppCancelCookie Where to store information for canceling the + * operation (from a different thread). Optional. + * + * The pointer _must_ be initialized to NULL before a + * series of connection attempts begins, i.e. at a time + * where there will be no RTTcpClientCancelConnect + * calls racing access. RTTcpClientCancelConnect will + * set it to a special non-NULL value that causes the + * current or/and next connect call to fail. + * + * @sa RTTcpClientCancelConnect + */ +RTR3DECL(int) RTTcpClientConnectEx(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock, + RTMSINTERVAL cMillies, PRTTCPCLIENTCONNECTCANCEL volatile *ppCancelCookie); + +/** + * Cancels a RTTcpClientConnectEx call on a different thread. + * + * @returns iprt status code. + * @param ppCancelCookie The address of the cookie pointer shared with the + * connect call. + */ +RTR3DECL(int) RTTcpClientCancelConnect(PRTTCPCLIENTCONNECTCANCEL volatile *ppCancelCookie); + +/** + * Close a socket returned by RTTcpClientConnect(). + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + */ +RTR3DECL(int) RTTcpClientClose(RTSOCKET hSocket); + +/** + * Close a socket returned by RTTcpClientConnect(). + * + * @returns iprt status code. + * @param hSocket The socket handle. + * @param fGracefulShutdown If true, try do a graceful shutdown of the + * outgoing pipe and draining any lingering input. + * This is sometimes better for the server side. + * If false, just close the connection without + * further ado. + */ +RTR3DECL(int) RTTcpClientCloseEx(RTSOCKET hSocket, bool fGracefulShutdown); + +/** + * Creates connected pair of TCP sockets. + * + * @returns IPRT status code. + * @param phServer Where to return the "server" side of the pair. + * @param phClient Where to return the "client" side of the pair. + * @param fFlags Reserved, must be zero. + * + * @note There is no server or client side, but we gotta call it something. + */ +RTR3DECL(int) RTTcpCreatePair(PRTSOCKET phServer, PRTSOCKET phClient, uint32_t fFlags); + +/** + * Receive data from a socket. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + * If NULL the entire buffer will be filled upon successful return. + * If not NULL a partial read can be done successfully. + */ +RTR3DECL(int) RTTcpRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead); + +/** + * Send data to a socket. + * + * @returns iprt status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket Socket descriptor. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + */ +RTR3DECL(int) RTTcpWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer); + +/** + * Flush socket write buffers. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + */ +RTR3DECL(int) RTTcpFlush(RTSOCKET hSocket); + +/** + * Enables or disables delaying sends to coalesce packets. + * + * The TCP/IP stack usually uses the Nagle algorithm (RFC 896) to implement the + * coalescing. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param fEnable When set to true enables coalescing. + */ +RTR3DECL(int) RTTcpSetSendCoalescing(RTSOCKET hSocket, bool fEnable); + +/** + * Sets send and receive buffer sizes. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param cbSize Buffer size in bytes. + */ +RTR3DECL(int) RTTcpSetBufferSize(RTSOCKET hSocket, uint32_t cbSize); + +/** + * Socket I/O multiplexing. + * Checks if the socket is ready for reading. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param cMillies Number of milliseconds to wait for the socket. + * Use RT_INDEFINITE_WAIT to wait for ever. + */ +RTR3DECL(int) RTTcpSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies); + +/** + * Socket I/O multiplexing + * Checks if the socket is ready for one of the given events. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param fEvents Event mask to wait for. + * Use the RTSOCKET_EVT_* defines. + * @param pfEvents Where to store the event mask on return. + * @param cMillies Number of milliseconds to wait for the socket. + * Use RT_INDEFINITE_WAIT to wait for ever. + */ +RTR3DECL(int) RTTcpSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies); + +#if 0 /* skipping these for now - RTTcpServer* handles this. */ +/** + * Listen for connection on a socket. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param cBackLog The maximum length the queue of pending connections + * may grow to. + */ +RTR3DECL(int) RTTcpListen(RTSOCKET hSocket, int cBackLog); + +/** + * Accept a connection on a socket. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param uPort The port for accepting connection. + * @param pSockAccepted Where to store the handle to the accepted connection. + */ +RTR3DECL(int) RTTcpAccept(RTSOCKET hSocket, unsigned uPort, PRTSOCKET pSockAccepted); + +#endif + +/** + * Gets the address of the local side. + * + * @returns IPRT status code. + * @param hSocket Socket descriptor. + * @param pAddr Where to store the local address on success. + */ +RTR3DECL(int) RTTcpGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr); + +/** + * Gets the address of the other party. + * + * @returns IPRT status code. + * @param hSocket Socket descriptor. + * @param pAddr Where to store the peer address on success. + */ +RTR3DECL(int) RTTcpGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr); + +/** + * Send data from a scatter/gather buffer to a socket. + * + * @returns iprt status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket Socket descriptor. + * @param pSgBuf Scatter/gather buffer to write data to socket. + */ +RTR3DECL(int) RTTcpSgWrite(RTSOCKET hSocket, PCRTSGBUF pSgBuf); + + +/** + * Send data from multiple buffers to a socket. + * + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * ellipsis. + * @param ... Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTTcpSgWriteL(RTSOCKET hSocket, size_t cSegs, ...); + +/** + * Send data from multiple buffers to a socket. + * + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * argument list. + * @param va Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTTcpSgWriteLV(RTSOCKET hSocket, size_t cSegs, va_list va); + +/** + * Receive data from a socket. + * + * This version doesn't block if there is no data on the socket. + * + * @returns IPRT status code. + * + * @param hSocket Socket descriptor. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + */ +RTR3DECL(int) RTTcpReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead); + +/** + * Send data to a socket. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns IPRT status code. + * + * @param hSocket Socket descriptor. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pcbWritten Number of bytes written. + */ +RTR3DECL(int) RTTcpWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten); + +/** + * Send data from a scatter/gather buffer to a socket. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns iprt status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket Socket descriptor. + * @param pSgBuf Scatter/gather buffer to write data to socket. + * @param pcbWritten Number of bytes written. + */ +RTR3DECL(int) RTTcpSgWriteNB(RTSOCKET hSocket, PCRTSGBUF pSgBuf, size_t *pcbWritten); + + +/** + * Send data from multiple buffers to a socket. + * + * This version doesn't block if there is not enough room for the message. + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * ellipsis. + * @param pcbWritten Number of bytes written. + * @param ... Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTTcpSgWriteLNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, ...); + +/** + * Send data from multiple buffers to a socket. + * + * This version doesn't block if there is not enough room for the message. + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * argument list. + * @param pcbWritten Number of bytes written. + * @param va Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTTcpSgWriteLVNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, va_list va); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_tcp_h */ + diff --git a/include/iprt/test.h b/include/iprt/test.h new file mode 100644 index 00000000..9cd5ddbe --- /dev/null +++ b/include/iprt/test.h @@ -0,0 +1,1485 @@ +/** @file + * IPRT - Testcase Framework. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_test_h +#define IPRT_INCLUDED_test_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_test RTTest - Testcase Framework. + * @ingroup grp_rt + * @{ + */ + +/** A test handle. */ +typedef R3PTRTYPE(struct RTTESTINT *) RTTEST; +/** A pointer to a test handle. */ +typedef RTTEST *PRTTEST; +/** A const pointer to a test handle. */ +typedef RTTEST const *PCRTTEST; + +/** A NIL Test handle. */ +#define NIL_RTTEST ((RTTEST)0) + +/** + * Test message importance level. + */ +typedef enum RTTESTLVL +{ + /** Invalid 0. */ + RTTESTLVL_INVALID = 0, + /** Message should always be printed. */ + RTTESTLVL_ALWAYS, + /** Failure message. */ + RTTESTLVL_FAILURE, + /** Sub-test banner. */ + RTTESTLVL_SUB_TEST, + /** Info message. */ + RTTESTLVL_INFO, + /** Debug message. */ + RTTESTLVL_DEBUG, + /** The last (invalid). */ + RTTESTLVL_END +} RTTESTLVL; + + +/** + * Creates a test instance. + * + * @returns IPRT status code. + * @param pszTest The test name. + * @param phTest Where to store the test instance handle. + */ +RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest); + +/** + * Creates a test instance for a child process. + * + * This differs from RTTestCreate in that it disabled result reporting to file + * and pipe in order to avoid producing invalid XML. + * + * @returns IPRT status code. + * @param pszTest The test name. + * @param phTest Where to store the test instance handle. + */ +RTR3DECL(int) RTTestCreateChild(const char *pszTest, PRTTEST phTest); + +/** @name RTTEST_C_XXX - Flags for RTTestCreateEx. + * @{ */ +/** Whether to check the IPRT_TEST_XXX variables when constructing the + * instance. The following environment variables get checks: + * + * - IPRT_TEST_MAX_LEVEL: String value indicating which level. + * The env. var. is applied if the program specified the default level + * (by passing RTTESTLVL_INVALID). + * + * - IPRT_TEST_PIPE: The native pipe/fifo handle to write XML + * results to. + * The env. var. is applied if iNativeTestPipe is -1. + * + * - IPRT_TEST_FILE: Path to file/named-pipe/fifo/whatever to + * write XML results to. + * The env. var. is applied if the program specified a NULL path, it is + * not applied if the program hands us an empty string. + * + * - IPRT_TEST_OMIT_TOP_TEST: If present, this makes the XML output omit + * the top level test element. + * The env. var is applied when present. + * + */ +#define RTTEST_C_USE_ENV RT_BIT(0) +/** Whether to omit the top test in the XML. */ +#define RTTEST_C_XML_OMIT_TOP_TEST RT_BIT(1) +/** Whether to delay the top test XML element until testing commences. */ +#define RTTEST_C_XML_DELAY_TOP_TEST RT_BIT(2) +/** Whether to try install the test instance in the test TLS slot. Setting + * this flag is incompatible with using the RTTestIXxxx variant of the API. */ +#define RTTEST_C_NO_TLS RT_BIT(3) +/** Don't report to the pipe (IPRT_TEST_PIPE or other). */ +#define RTTEST_C_NO_XML_REPORTING_PIPE RT_BIT(4) +/** Don't report to the results file (IPRT_TEST_FILE or other). */ +#define RTTEST_C_NO_XML_REPORTING_FILE RT_BIT(4) +/** No XML reporting to pipes, file or anything. + * Child processes may want to use this so they don't garble the output of + * the main test process. */ +#define RTTEST_C_NO_XML_REPORTING (RTTEST_C_NO_XML_REPORTING_PIPE | RTTEST_C_NO_XML_REPORTING_FILE) +/** Mask containing the valid bits. */ +#define RTTEST_C_VALID_MASK UINT32_C(0x0000003f) +/** @} */ + + +/** + * Creates a test instance. + * + * @returns IPRT status code. + * @param pszTest The test name. + * @param fFlags Flags, see RTTEST_C_XXX. + * @param enmMaxLevel The max message level. Use RTTESTLVL_INVALID for + * the default output level or one from the + * environment. If specified, the environment variable + * will not be able to override it. + * @param iNativeTestPipe Native handle to a test pipe. -1 if not interested. + * @param pszXmlFile The XML output file name. If NULL the environment + * may be used. To selectively avoid that, pass an + * empty string. + * @param phTest Where to store the test instance handle. + * + * @note At the moment, we don't fail if @a pszXmlFile or @a iNativeTestPipe + * fails to open. This may change later. + */ +RTR3DECL(int) RTTestCreateEx(const char *pszTest, uint32_t fFlags, RTTESTLVL enmMaxLevel, + RTHCINTPTR iNativeTestPipe, const char *pszXmlFile, PRTTEST phTest); + +/** + * Initializes IPRT and creates a test instance. + * + * Typical usage is: + * @code + int main(int argc, char **argv) + { + RTTEST hTest; + int rc = RTTestInitAndCreate("tstSomething", &hTest); + if (rc) + return rc; + ... + } + @endcode + * + * @returns RTEXITCODE_SUCCESS on success. On failure an error message is + * printed and a suitable exit code is return. + * + * @param pszTest The test name. + * @param phTest Where to store the test instance handle. + */ +RTR3DECL(RTEXITCODE) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest); + +/** + * Variant of RTTestInitAndCreate that includes IPRT init flags and argument + * vectors. + * + * @returns RTEXITCODE_SUCCESS on success. On failure an error message is + * printed and a suitable exit code is return. + * + * @param cArgs Pointer to the argument count. + * @param ppapszArgs Pointer to the argument vector pointer. + * @param fRtInit Flags, see RTR3INIT_XXX. + * @param pszTest The test name. + * @param phTest Where to store the test instance handle. + */ +RTR3DECL(RTEXITCODE) RTTestInitExAndCreate(int cArgs, char ***ppapszArgs, uint32_t fRtInit, const char *pszTest, PRTTEST phTest); + +/** + * Destroys a test instance previously created by RTTestCreate. + * + * @returns IPRT status code. + * @param hTest The test handle. NIL_RTTEST is ignored. + */ +RTR3DECL(int) RTTestDestroy(RTTEST hTest); + +/** + * Changes the default test instance for the calling thread. + * + * @returns IPRT status code. + * + * @param hNewDefaultTest The new default test. NIL_RTTEST is fine. + * @param phOldTest Where to store the old test handle. Optional. + */ +RTR3DECL(int) RTTestSetDefault(RTTEST hNewDefaultTest, PRTTEST phOldTest); + +/** + * Changes the test case name. + * + * @returns IRPT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszName The new test case name. Empty string is not accepted, + * nor are strings longer than 127 chars. Keep it short + * but descriptive. + */ +RTR3DECL(int) RTTestChangeName(RTTEST hTest, const char *pszName); + +/** + * Allocate a block of guarded memory. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param cb The amount of memory to allocate. + * @param cbAlign The alignment of the returned block. + * @param fHead Head or tail optimized guard. + * @param ppvUser Where to return the pointer to the block. + */ +RTR3DECL(int) RTTestGuardedAlloc(RTTEST hTest, size_t cb, uint32_t cbAlign, bool fHead, void **ppvUser); + +/** + * Allocates a block of guarded memory where the guarded is immediately after + * the user memory. + * + * @returns Pointer to the allocated memory. NULL on failure. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param cb The amount of memory to allocate. + */ +RTR3DECL(void *) RTTestGuardedAllocTail(RTTEST hTest, size_t cb); + +/** + * Allocates a block of guarded memory where the guarded is right in front of + * the user memory. + * + * @returns Pointer to the allocated memory. NULL on failure. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param cb The amount of memory to allocate. + */ +RTR3DECL(void *) RTTestGuardedAllocHead(RTTEST hTest, size_t cb); + +/** + * Frees a block of guarded memory. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pv The memory. NULL is ignored. + */ +RTR3DECL(int) RTTestGuardedFree(RTTEST hTest, void *pv); + +/** + * Test vprintf making sure the output starts on a new line. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Test printf making sure the output starts on a new line. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Test vprintf, makes sure lines are prefixed and so forth. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestPrintfV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Test printf, makes sure lines are prefixed and so forth. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestPrintf(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Prints the test banner. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(int) RTTestBanner(RTTEST hTest); + +/** + * Summaries the test, destroys the test instance and return an exit code. + * + * @returns Test program exit code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(RTEXITCODE) RTTestSummaryAndDestroy(RTTEST hTest); + +/** + * Skips the test, destroys the test instance and return an exit code. + * + * @returns Test program exit code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszReasonFmt Text explaining why, optional (NULL). + * @param va Arguments for the reason format string. + */ +RTR3DECL(RTEXITCODE) RTTestSkipAndDestroyV(RTTEST hTest, const char *pszReasonFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Skips the test, destroys the test instance and return an exit code. + * + * @returns Test program exit code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszReasonFmt Text explaining why, optional (NULL). + * @param ... Arguments for the reason format string. + */ +RTR3DECL(RTEXITCODE) RTTestSkipAndDestroy(RTTEST hTest, const char *pszReasonFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Starts a sub-test. + * + * This will perform an implicit RTTestSubDone() call if that has not been done + * since the last RTTestSub call. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszSubTest The sub-test name. + */ +RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest); + +/** + * Format string version of RTTestSub. + * + * See RTTestSub for details. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszSubTestFmt The sub-test name format string. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestSubF(RTTEST hTest, const char *pszSubTestFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Format string version of RTTestSub. + * + * See RTTestSub for details. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszSubTestFmt The sub-test name format string. + * @param va Arguments. + */ +RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Completes a sub-test. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(int) RTTestSubDone(RTTEST hTest); + +/** + * Prints an extended PASSED message, optional. + * + * This does not conclude the sub-test, it could be used to report the passing + * of a sub-sub-to-the-power-of-N-test. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Prints an extended PASSED message, optional. + * + * This does not conclude the sub-test, it could be used to report the passing + * of a sub-sub-to-the-power-of-N-test. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Marks the current test as 'SKIPPED' and optionally displays a message + * explaining why. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. Can be NULL or empty. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestSkipped(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(2, 3); + +/** + * Marks the current test as 'SKIPPED' and optionally displays a message + * explaining why. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. Can be NULL or empty. + * @param va The arguments. + */ +RTR3DECL(int) RTTestSkippedV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(2, 0); + + +/** + * Value units. + * + * @remarks This is an interface where we have to be binary compatible with both + * older versions of this header and other components using the same + * contant values. + * @remarks When adding a new item: + * - Always add at the end of the list. + * - Add it to rtTestUnitName in r3/test.cpp. + * - Add it as VMMDEV_TESTING_UNIT_ in include/VBox/VMMDevTesting.h. + * - Add it to g_aszBs2TestUnitNames in + * ValidationKit/bootsectors/bootsector2-common-routines.mac. + * - Add it to g_aszBs3TestUnitNames in bs3kit/bs3-cmn-TestData.c. + * - Add it to ValidationKit/common/constants/valueunit.py both as + * a constant (strip RTTESTUNIT_) and as a name (same as what + * rtTestUnitName returns) for mapping. Testmanager must be + * updated. + * - Add it to Value.kdBestByUnit in ValidationKit/analysis/reader.py. + */ +typedef enum RTTESTUNIT +{ + /** The customary invalid zero value. */ + RTTESTUNIT_INVALID = 0, + + RTTESTUNIT_PCT, /**< Percentage (10^-2). */ + RTTESTUNIT_BYTES, /**< Bytes. */ + RTTESTUNIT_BYTES_PER_SEC, /**< Bytes per second. */ + RTTESTUNIT_KILOBYTES, /**< Kilobytes. */ + RTTESTUNIT_KILOBYTES_PER_SEC, /**< Kilobytes per second. */ + RTTESTUNIT_MEGABYTES, /**< Megabytes. */ + RTTESTUNIT_MEGABYTES_PER_SEC, /**< Megabytes per second. */ + RTTESTUNIT_PACKETS, /**< Packets. */ + RTTESTUNIT_PACKETS_PER_SEC, /**< Packets per second. */ + RTTESTUNIT_FRAMES, /**< Frames. */ + RTTESTUNIT_FRAMES_PER_SEC, /**< Frames per second. */ + RTTESTUNIT_OCCURRENCES, /**< Occurrences. */ + RTTESTUNIT_OCCURRENCES_PER_SEC, /**< Occurrences per second. */ + RTTESTUNIT_CALLS, /**< Calls. */ + RTTESTUNIT_CALLS_PER_SEC, /**< Calls per second. */ + RTTESTUNIT_ROUND_TRIP, /**< Round trips. */ + RTTESTUNIT_SECS, /**< Seconds. */ + RTTESTUNIT_MS, /**< Milliseconds. */ + RTTESTUNIT_NS, /**< Nanoseconds. */ + RTTESTUNIT_NS_PER_CALL, /**< Nanoseconds per call. */ + RTTESTUNIT_NS_PER_FRAME, /**< Nanoseconds per frame. */ + RTTESTUNIT_NS_PER_OCCURRENCE, /**< Nanoseconds per occurrence. */ + RTTESTUNIT_NS_PER_PACKET, /**< Nanoseconds per frame. */ + RTTESTUNIT_NS_PER_ROUND_TRIP, /**< Nanoseconds per round trip. */ + RTTESTUNIT_INSTRS, /**< Instructions. */ + RTTESTUNIT_INSTRS_PER_SEC, /**< Instructions per second. */ + RTTESTUNIT_NONE, /**< No unit. */ + RTTESTUNIT_PP1K, /**< Parts per thousand (10^-3). */ + RTTESTUNIT_PP10K, /**< Parts per ten thousand (10^-4). */ + RTTESTUNIT_PPM, /**< Parts per million (10^-6). */ + RTTESTUNIT_PPB, /**< Parts per billion (10^-9). */ + RTTESTUNIT_TICKS, /**< CPU ticks. */ + RTTESTUNIT_TICKS_PER_CALL, /**< CPU ticks per call. */ + RTTESTUNIT_TICKS_PER_OCCURENCE, /**< CPU ticks per occurence. */ + RTTESTUNIT_PAGES, /**< Page count. */ + RTTESTUNIT_PAGES_PER_SEC, /**< Pages per second. */ + RTTESTUNIT_TICKS_PER_PAGE, /**< CPU ticks per page. */ + RTTESTUNIT_NS_PER_PAGE, /**< Nanoseconds per page. */ + RTTESTUNIT_PS, /**< Picoseconds. */ + RTTESTUNIT_PS_PER_CALL, /**< Picoseconds per call. */ + RTTESTUNIT_PS_PER_FRAME, /**< Picoseconds per frame. */ + RTTESTUNIT_PS_PER_OCCURRENCE, /**< Picoseconds per occurrence. */ + RTTESTUNIT_PS_PER_PACKET, /**< Picoseconds per frame. */ + RTTESTUNIT_PS_PER_ROUND_TRIP, /**< Picoseconds per round trip. */ + RTTESTUNIT_PS_PER_PAGE, /**< Picoseconds per page. */ + + /** The end of valid units. */ + RTTESTUNIT_END +} RTTESTUNIT; +AssertCompile(RTTESTUNIT_INSTRS == 0x19); +AssertCompile(RTTESTUNIT_NONE == 0x1b); +AssertCompile(RTTESTUNIT_NS_PER_PAGE == 0x26); +AssertCompile(RTTESTUNIT_PS_PER_PAGE == 0x2d); + +/** + * Report a named test result value. + * + * This is typically used for benchmarking but can be used for other purposes + * like reporting limits of some implementation. The value gets associated with + * the current sub test, the name must be unique within the sub test. + * + * @returns IPRT status code. + * + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszName The value name. + * @param u64Value The value. + * @param enmUnit The value unit. + */ +RTR3DECL(int) RTTestValue(RTTEST hTest, const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit); + +/** + * Same as RTTestValue, except that the name is now a format string. + * + * @returns IPRT status code. + * + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param u64Value The value. + * @param enmUnit The value unit. + * @param pszNameFmt The value name format string. + * @param ... String arguments. + */ +RTR3DECL(int) RTTestValueF(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Same as RTTestValue, except that the name is now a format string. + * + * @returns IPRT status code. + * + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param u64Value The value. + * @param enmUnit The value unit. + * @param pszNameFmt The value name format string. + * @param va String arguments. + */ +RTR3DECL(int) RTTestValueV(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Increments the error counter. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(int) RTTestErrorInc(RTTEST hTest); + +/** + * Get the current error count. + * + * @returns The error counter, UINT32_MAX if no valid test handle. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest); + +/** + * Get the error count of the current sub test. + * + * @returns The error counter, UINT32_MAX if no valid test handle. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(uint32_t) RTTestSubErrorCount(RTTEST hTest); + +/** + * Increments the error counter and prints a failure message. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestFailedV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Increments the error counter and prints a failure message. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestFailed(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Same as RTTestPrintfV with RTTESTLVL_FAILURE. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestFailureDetailsV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Same as RTTestPrintf with RTTESTLVL_FAILURE. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestFailureDetails(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Sets error context info to be printed with the first failure. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message, no trailing newline. NULL to clear the + * context message. + * @param va The arguments. + */ +RTR3DECL(int) RTTestErrContextV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Sets error context info to be printed with the first failure. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message, no trailing newline. NULL to clear the + * context message. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestErrContext(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Disables and shuts up assertions. + * + * Max 8 nestings. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @sa RTAssertSetMayPanic, RTAssertSetQuiet. + */ +RTR3DECL(int) RTTestDisableAssertions(RTTEST hTest); + +/** + * Restores the previous call to RTTestDisableAssertions. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(int) RTTestRestoreAssertions(RTTEST hTest); + + +/** @def RTTEST_CHECK + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestFailed giving the line number and expression. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + */ +#define RTTEST_CHECK(hTest, expr) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RET + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestFailed giving the line number and + * expression, then return @a rcRet. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + * @param rcRet What to return on failure. + */ +#define RTTEST_CHECK_RET(hTest, expr, rcRet) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RETV + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestFailed giving the line number and + * expression, then return void. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + */ +#define RTTEST_CHECK_RETV(hTest, expr) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + return; \ + } \ + } while (0) +/** @def RTTEST_CHECK_BREAK + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestFailed giving the line number and + * expression, then break. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + */ +#define RTTEST_CHECK_BREAK(hTest, expr) \ + if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + break; \ + } else do {} while (0) + + +/** @def RTTEST_CHECK_MSG + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestFailed giving the line number and expression. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestFailureDetails, including + * parenthesis. + */ +#define RTTEST_CHECK_MSG(hTest, expr, DetailsArgs) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + RTTestFailureDetails DetailsArgs; \ + } \ + } while (0) +/** @def RTTEST_CHECK_MSG_RET + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestFailed giving the line number and expression. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestFailureDetails, including + * parenthesis. + * @param rcRet What to return on failure. + */ +#define RTTEST_CHECK_MSG_RET(hTest, expr, DetailsArgs, rcRet) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + RTTestFailureDetails DetailsArgs; \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTEST_CHECK_MSG_RETV + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestFailed giving the line number and expression. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestFailureDetails, including + * parenthesis. + */ +#define RTTEST_CHECK_MSG_RETV(hTest, expr, DetailsArgs) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + RTTestFailureDetails DetailsArgs; \ + return; \ + } \ + } while (0) + + +/** @def RTTEST_CHECK_RC + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestFailed giving the line + * number, expression, actual and expected status codes. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTEST_CHECK_RC(hTest, rcExpr, rcExpect) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_RET + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestFailed giving the line + * number, expression, actual and expected status codes, then return. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * This will be assigned to a local rcCheck variable + * that can be used as return value. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + * @param rcRet The return code. + */ +#define RTTEST_CHECK_RC_RET(hTest, rcExpr, rcExpect, rcRet) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_RETV + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestFailed giving the line + * number, expression, actual and expected status codes, then return. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTEST_CHECK_RC_RETV(hTest, rcExpr, rcExpect) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + return; \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_BREAK + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestFailed giving the line + * number, expression, actual and expected status codes, then break. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTEST_CHECK_RC_BREAK(hTest, rcExpr, rcExpect) \ + if (1) { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + break; \ + } \ + } else do {} while (0) + + +/** @def RTTEST_CHECK_RC_OK + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestFailed giving the line number, + * expression and status code. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTEST_CHECK_RC_OK(hTest, rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestFailed((hTest), "line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_OK_RET + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestFailed giving the line number, + * expression and status code, then return with the specified value. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * This will be assigned to a local rcCheck variable + * that can be used as return value. + * @param rcRet The return code. + */ +#define RTTEST_CHECK_RC_OK_RET(hTest, rcExpr, rcRet) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestFailed((hTest), "line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_OK_RETV + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestFailed giving the line number, + * expression and status code, then return. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTEST_CHECK_RC_OK_RETV(hTest, rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestFailed((hTest), "line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + return; \ + } \ + } while (0) + + + + +/** @name Implicit Test Handle API Variation + * The test handle is retrieved from the test TLS entry of the calling thread. + * @{ + */ + +/** + * Test vprintf, makes sure lines are prefixed and so forth. + * + * @returns Number of chars printed. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestIPrintfV(RTTESTLVL enmLevel, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Test printf, makes sure lines are prefixed and so forth. + * + * @returns Number of chars printed. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestIPrintf(RTTESTLVL enmLevel, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Starts a sub-test. + * + * This will perform an implicit RTTestSubDone() call if that has not been done + * since the last RTTestSub call. + * + * @returns Number of chars printed. + * @param pszSubTest The sub-test name. + */ +RTR3DECL(int) RTTestISub(const char *pszSubTest); + +/** + * Format string version of RTTestSub. + * + * See RTTestSub for details. + * + * @returns Number of chars printed. + * @param pszSubTestFmt The sub-test name format string. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestISubF(const char *pszSubTestFmt, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Format string version of RTTestSub. + * + * See RTTestSub for details. + * + * @returns Number of chars printed. + * @param pszSubTestFmt The sub-test name format string. + * @param va Arguments. + */ +RTR3DECL(int) RTTestISubV(const char *pszSubTestFmt, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Completes a sub-test. + * + * @returns Number of chars printed. + */ +RTR3DECL(int) RTTestISubDone(void); + +/** + * Prints an extended PASSED message, optional. + * + * This does not conclude the sub-test, it could be used to report the passing + * of a sub-sub-to-the-power-of-N-test. + * + * @returns IPRT status code. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestIPassedV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Prints an extended PASSED message, optional. + * + * This does not conclude the sub-test, it could be used to report the passing + * of a sub-sub-to-the-power-of-N-test. + * + * @returns IPRT status code. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestIPassed(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Report a named test result value. + * + * This is typically used for benchmarking but can be used for other purposes + * like reporting limits of some implementation. The value gets associated with + * the current sub test, the name must be unique within the sub test. + * + * @returns IPRT status code. + * + * @param pszName The value name. + * @param u64Value The value. + * @param enmUnit The value unit. + */ +RTR3DECL(int) RTTestIValue(const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit); + +/** + * Same as RTTestValue, except that the name is now a format string. + * + * @returns IPRT status code. + * + * @param u64Value The value. + * @param enmUnit The value unit. + * @param pszNameFmt The value name format string. + * @param ... String arguments. + */ +RTR3DECL(int) RTTestIValueF(uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Same as RTTestValue, except that the name is now a format string. + * + * @returns IPRT status code. + * + * @param u64Value The value. + * @param enmUnit The value unit. + * @param pszNameFmt The value name format string. + * @param va String arguments. + */ +RTR3DECL(int) RTTestIValueV(uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Increments the error counter. + * + * @returns IPRT status code. + */ +RTR3DECL(int) RTTestIErrorInc(void); + +/** + * Get the current error count. + * + * @returns The error counter, UINT32_MAX if no valid test handle. + */ +RTR3DECL(uint32_t) RTTestIErrorCount(void); + +/** + * Increments the error counter and prints a failure message. + * + * @returns IPRT status code. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestIFailedV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Increments the error counter and prints a failure message. + * + * @returns IPRT status code. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestIFailed(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Increments the error counter, prints a failure message and returns the + * specified status code. + * + * This is mainly a convenience method for saving vertical space in the source + * code. + * + * @returns @a rcRet + * @param rcRet The IPRT status code to return. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestIFailedRcV(int rcRet, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Increments the error counter, prints a failure message and returns the + * specified status code. + * + * This is mainly a convenience method for saving vertical space in the source + * code. + * + * @returns @a rcRet + * @param rcRet The IPRT status code to return. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestIFailedRc(int rcRet, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Same as RTTestIPrintfV with RTTESTLVL_FAILURE. + * + * @returns Number of chars printed. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestIFailureDetailsV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Same as RTTestIPrintf with RTTESTLVL_FAILURE. + * + * @returns Number of chars printed. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestIFailureDetails(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Sets error context info to be printed with the first failure. + * + * @returns IPRT status code. + * @param pszFormat The message, no trailing newline. NULL to clear the + * context message. + * @param va The arguments. + */ +RTR3DECL(int) RTTestIErrContextV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Sets error context info to be printed with the first failure. + * + * @returns IPRT status code. + * @param pszFormat The message, no trailing newline. NULL to clear the + * context message. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestIErrContext(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Disables and shuts up assertions. + * + * Max 8 nestings. + * + * @returns IPRT status code. + * @sa RTAssertSetMayPanic, RTAssertSetQuiet. + */ +RTR3DECL(int) RTTestIDisableAssertions(void); + +/** + * Restores the previous call to RTTestDisableAssertions. + * + * @returns IPRT status code. + */ +RTR3DECL(int) RTTestIRestoreAssertions(void); + + +/** @def RTTESTI_CHECK + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + */ +#define RTTESTI_CHECK(expr) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RET + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression, then return @a rcRet. + * + * @param expr The expression to evaluate. + * @param rcRet What to return on failure. + */ +#define RTTESTI_CHECK_RET(expr, rcRet) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RETV + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression, then return void. + * + * @param expr The expression to evaluate. + */ +#define RTTESTI_CHECK_RETV(expr) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + return; \ + } \ + } while (0) +/** @def RTTESTI_CHECK_BREAK + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression, then break. + * + * @param expr The expression to evaluate. + */ +#define RTTESTI_CHECK_BREAK(expr) \ + if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + break; \ + } else do {} while (0) + + +/** @def RTTESTI_CHECK_MSG + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestIFailureDetails, including + * parenthesis. + */ +#define RTTESTI_CHECK_MSG(expr, DetailsArgs) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + RTTestIFailureDetails DetailsArgs; \ + } \ + } while (0) +/** @def RTTESTI_CHECK_MSG_BREAK + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestIFailureDetails, including + * parenthesis. + */ +#define RTTESTI_CHECK_MSG_BREAK(expr, DetailsArgs) \ + if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + RTTestIFailureDetails DetailsArgs; \ + break; \ + } else do {} while (0) +/** @def RTTESTI_CHECK_MSG_RET + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestIFailureDetails, including + * parenthesis. + * @param rcRet What to return on failure. + */ +#define RTTESTI_CHECK_MSG_RET(expr, DetailsArgs, rcRet) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + RTTestIFailureDetails DetailsArgs; \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_MSG_RETV + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestIFailureDetails, including + * parenthesis. + */ +#define RTTESTI_CHECK_MSG_RETV(expr, DetailsArgs) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + RTTestIFailureDetails DetailsArgs; \ + return; \ + } \ + } while (0) + +/** @def RTTESTI_CHECK_RC + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes. + * + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTESTI_CHECK_RC(rcExpr, rcExpect) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_RET + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes, then return. + * + * @param rcExpr The expression resulting in an IPRT status code. + * This will be assigned to a local rcCheck variable + * that can be used as return value. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + * @param rcRet The return code. + */ +#define RTTESTI_CHECK_RC_RET(rcExpr, rcExpect, rcRet) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_RETV + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes, then return. + * + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTESTI_CHECK_RC_RETV(rcExpr, rcExpect) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + return; \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_BREAK + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes, then break. + * + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTESTI_CHECK_RC_BREAK(rcExpr, rcExpect) \ + if (1) { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + break; \ + } \ + } else do {} while (0) +/** @def RTTESTI_CHECK_RC_OK + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestIFailed giving the line number, + * expression and status code. + * + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTESTI_CHECK_RC_OK(rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_OK_BREAK + * Check whether a IPRT style status code indicates success. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes, then break. + * + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTESTI_CHECK_RC_OK_BREAK(rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + break; \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_OK_RET + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestIFailed giving the line number, + * expression and status code, then return with the specified value. + * + * @param rcExpr The expression resulting in an IPRT status code. + * This will be assigned to a local rcCheck variable + * that can be used as return value. + * @param rcRet The return code. + */ +#define RTTESTI_CHECK_RC_OK_RET(rcExpr, rcRet) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_OK_RETV + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestIFailed giving the line number, + * expression and status code, then return. + * + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTESTI_CHECK_RC_OK_RETV(rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + return; \ + } \ + } while (0) + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_test_h */ + diff --git a/include/iprt/thread.h b/include/iprt/thread.h new file mode 100644 index 00000000..551c8bcc --- /dev/null +++ b/include/iprt/thread.h @@ -0,0 +1,1023 @@ +/** @file + * IPRT - Threads. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_thread_h +#define IPRT_INCLUDED_thread_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_thread RTThread - Thread Management + * @ingroup grp_rt + * @{ + */ + +/** + * The thread state. + */ +typedef enum RTTHREADSTATE +{ + /** The usual invalid 0 value. */ + RTTHREADSTATE_INVALID = 0, + /** The thread is being initialized. */ + RTTHREADSTATE_INITIALIZING, + /** The thread has terminated */ + RTTHREADSTATE_TERMINATED, + /** Probably running. */ + RTTHREADSTATE_RUNNING, + + /** Waiting on a critical section. */ + RTTHREADSTATE_CRITSECT, + /** Waiting on a event semaphore. */ + RTTHREADSTATE_EVENT, + /** Waiting on a event multiple wakeup semaphore. */ + RTTHREADSTATE_EVENT_MULTI, + /** Waiting on a fast mutex. */ + RTTHREADSTATE_FAST_MUTEX, + /** Waiting on a mutex. */ + RTTHREADSTATE_MUTEX, + /** Waiting on a read write semaphore, read (shared) access. */ + RTTHREADSTATE_RW_READ, + /** Waiting on a read write semaphore, write (exclusive) access. */ + RTTHREADSTATE_RW_WRITE, + /** The thread is sleeping. */ + RTTHREADSTATE_SLEEP, + /** Waiting on a spin mutex. */ + RTTHREADSTATE_SPIN_MUTEX, + /** End of the thread states. */ + RTTHREADSTATE_END, + + /** The usual 32-bit size hack. */ + RTTHREADSTATE_32BIT_HACK = 0x7fffffff +} RTTHREADSTATE; + +/** Checks if a thread state indicates that the thread is sleeping. */ +#define RTTHREAD_IS_SLEEPING(enmState) ((enmState) >= RTTHREADSTATE_CRITSECT) + +/** + * Thread types. + * Besides identifying the purpose of the thread, the thread type is + * used to select the scheduling properties. + * + * The types in are placed in a rough order of ascending priority. + */ +typedef enum RTTHREADTYPE +{ + /** Invalid type. */ + RTTHREADTYPE_INVALID = 0, + /** Infrequent poller thread. + * This type of thread will sleep for the most of the time, and do + * infrequent polls on resources at 0.5 sec or higher intervals. + */ + RTTHREADTYPE_INFREQUENT_POLLER, + /** Main heavy worker thread. + * Thread of this type is driving asynchronous tasks in the Main + * API which takes a long time and might involve a bit of CPU. Like + * for instance creating a fixed sized VDI. + */ + RTTHREADTYPE_MAIN_HEAVY_WORKER, + /** The emulation thread type. + * While being a thread with very high workload it still is vital + * that it gets scheduled frequently. When possible all other thread + * types except DEFAULT and GUI should interrupt this one ASAP when + * they become ready. + */ + RTTHREADTYPE_EMULATION, + /** The default thread type. + * Since it doesn't say much about the purpose of the thread + * nothing special is normally done to the scheduling. This type + * should be avoided. + * The main thread is registered with default type during RTR3Init() + * and that's what the default process priority is derived from. + */ + RTTHREADTYPE_DEFAULT, + /** The GUI thread type + * The GUI normally have a low workload but is frequently scheduled + * to handle events. When possible the scheduler should not leave + * threads of this kind waiting for too long (~50ms). + */ + RTTHREADTYPE_GUI, + /** Main worker thread. + * Thread of this type is driving asynchronous tasks in the Main API. + * In most cases this means little work an a lot of waiting. + */ + RTTHREADTYPE_MAIN_WORKER, + /** VRDP I/O thread. + * These threads are I/O threads in the RDP server will hang around + * waiting for data, process it and pass it on. + */ + RTTHREADTYPE_VRDP_IO, + /** The debugger type. + * Threads involved in servicing the debugger. It must remain + * responsive even when things are running wild in. + */ + RTTHREADTYPE_DEBUGGER, + /** Message pump thread. + * Thread pumping messages from one thread/process to another + * thread/process. The workload is very small, most of the time + * it's blocked waiting for messages to be produced or processed. + * This type of thread will be favored after I/O threads. + */ + RTTHREADTYPE_MSG_PUMP, + /** The I/O thread type. + * Doing I/O means shuffling data, waiting for request to arrive and + * for them to complete. The thread should be favored when competing + * with any other threads except timer threads. + */ + RTTHREADTYPE_IO, + /** The timer thread type. + * A timer thread is mostly waiting for the timer to tick + * and then perform a little bit of work. Accuracy is important here, + * so the thread should be favoured over all threads. If premention can + * be configured at thread level, it could be made very short. + */ + RTTHREADTYPE_TIMER, + /** Only used for validation. */ + RTTHREADTYPE_END +} RTTHREADTYPE; + + +#if !defined(IN_RC) || defined(DOXYGEN_RUNNING) + +/** + * Checks if the IPRT thread component has been initialized. + * + * This is used to avoid calling into RTThread before the runtime has been + * initialized. + * + * @returns @c true if it's initialized, @c false if not. + */ +RTDECL(bool) RTThreadIsInitialized(void); + +/** + * Get the thread handle of the current thread. + * + * @returns Thread handle. + */ +RTDECL(RTTHREAD) RTThreadSelf(void); + +/** + * Get the native thread handle of the current thread. + * + * @returns Native thread handle. + */ +RTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void); + +/** + * Millisecond granular sleep function. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_INTERRUPTED if a signal or other asynchronous stuff happened + * which interrupt the peaceful sleep. + * @param cMillies Number of milliseconds to sleep. + * 0 milliseconds means yielding the timeslice - deprecated! + * @remark See RTThreadNanoSleep() for sleeping for smaller periods of time. + */ +RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies); + +/** + * Millisecond granular sleep function, no logger calls. + * + * Same as RTThreadSleep, except it will never call into the IPRT logger. It + * can therefore safely be used in places where the logger is off limits, like + * at termination or init time. The electric fence heap is one consumer of + * this API. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_INTERRUPTED if a signal or other asynchronous stuff happened + * which interrupt the peaceful sleep. + * @param cMillies Number of milliseconds to sleep. + * 0 milliseconds means yielding the timeslice - deprecated! + */ +RTDECL(int) RTThreadSleepNoLog(RTMSINTERVAL cMillies); + +/** + * Yields the CPU. + * + * @returns true if we yielded. + * @returns false if it's probable that we didn't yield. + */ +RTDECL(bool) RTThreadYield(void); + + + +/** + * Thread function. + * + * @returns 0 on success. + * @param ThreadSelf Thread handle to this thread. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTTHREAD,(RTTHREAD ThreadSelf, void *pvUser)); +/** Pointer to a FNRTTHREAD(). */ +typedef FNRTTHREAD *PFNRTTHREAD; + +/** + * Thread creation flags. + */ +typedef enum RTTHREADFLAGS +{ + /** This flag is used to keep the thread structure around so it can + * be waited on after termination. @sa RTThreadWait and + * RTThreadWaitNoResume. Not required for RTThreadUserWait and friends! + */ + RTTHREADFLAGS_WAITABLE = RT_BIT(0), + /** The bit number corresponding to the RTTHREADFLAGS_WAITABLE mask. */ + RTTHREADFLAGS_WAITABLE_BIT = 0, + + /** Call CoInitializeEx w/ COINIT_MULTITHREADED, COINIT_DISABLE_OLE1DDE and + * COINIT_SPEED_OVER_MEMORY. Ignored on non-windows platforms. */ + RTTHREADFLAGS_COM_MTA = RT_BIT(1), + /** Call CoInitializeEx w/ COINIT_APARTMENTTHREADED and + * COINIT_SPEED_OVER_MEMORY. Ignored on non-windows platforms. */ + RTTHREADFLAGS_COM_STA = RT_BIT(2), + + /** Mask all signals that we can mask. Ignored on most non-posix platforms. + * @note RTThreadPoke() will not necessarily work for a thread create with + * this flag. */ + RTTHREADFLAGS_NO_SIGNALS = RT_BIT(3), + + /** Mask of valid flags, use for validation. */ + RTTHREADFLAGS_MASK = UINT32_C(0xf) +} RTTHREADFLAGS; + +/** Max thread name length (including zero terminator). */ +#define RTTHREAD_NAME_LEN 16 + +/** + * Create a new thread. + * + * @returns iprt status code. + * @param pThread Where to store the thread handle to the new thread. (optional) + * @param pfnThread The thread function. + * @param pvUser User argument. + * @param cbStack The size of the stack for the new thread. + * Use 0 for the default stack size. + * @param enmType The thread type. Used for deciding scheduling attributes + * of the thread. + * @param fFlags Flags of the RTTHREADFLAGS type (ORed together). + * @param pszName Thread name. + * + * @remark When called in Ring-0, this API will create a new kernel thread and not a thread in + * the context of the calling process. + */ +RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack, + RTTHREADTYPE enmType, unsigned fFlags, const char *pszName); +#ifndef RT_OS_LINUX /* XXX crashes genksyms at least on 32-bit Linux hosts */ +/** Pointer to a RTThreadCreate function. */ +typedef DECLCALLBACKPTR(int, PFNRTTHREADCREATE,(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack, + RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)); +#endif + + +/** + * Create a new thread. + * + * Same as RTThreadCreate except the name is given in the RTStrPrintfV form. + * + * @returns iprt status code. + * @param pThread See RTThreadCreate. + * @param pfnThread See RTThreadCreate. + * @param pvUser See RTThreadCreate. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param fFlags See RTThreadCreate. + * @param pszNameFmt Thread name format. + * @param va Format arguments. + */ +RTDECL(int) RTThreadCreateV(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack, + RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(7, 0); + +/** + * Create a new thread. + * + * Same as RTThreadCreate except the name is given in the RTStrPrintf form. + * + * @returns iprt status code. + * @param pThread See RTThreadCreate. + * @param pfnThread See RTThreadCreate. + * @param pvUser See RTThreadCreate. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param fFlags See RTThreadCreate. + * @param pszNameFmt Thread name format. + * @param ... Format arguments. + */ +RTDECL(int) RTThreadCreateF(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack, + RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(7, 8); + +/** + * Gets the native thread id of a IPRT thread. + * + * @returns The native thread id. + * @param Thread The IPRT thread. + */ +RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread); + +/** + * Gets the native thread handle for a IPRT thread. + * + * @returns The thread handle. INVALID_HANDLE_VALUE on failure. + * @param hThread The IPRT thread handle. + * + * @note Windows only. + * @note Only valid after parent returns from the thread creation call. + */ +RTDECL(uintptr_t) RTThreadGetNativeHandle(RTTHREAD hThread); + +/** + * Gets the IPRT thread of a native thread. + * + * @returns The IPRT thread handle + * @returns NIL_RTTHREAD if not a thread known to IPRT. + * @param NativeThread The native thread handle/id. + */ +RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread); + +/** + * Changes the type of the specified thread. + * + * @returns iprt status code. + * @param Thread The thread which type should be changed. + * @param enmType The new thread type. + * @remark In Ring-0 it only works if Thread == RTThreadSelf(). + */ +RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType); + +/** + * Wait for the thread to terminate, resume on interruption. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param Thread The thread to wait for. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + * @param prc Where to store the return code of the thread. Optional. + */ +RTDECL(int) RTThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc); + +/** + * Wait for the thread to terminate, return on interruption. + * + * @returns iprt status code. + * @param Thread The thread to wait for. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + * @param prc Where to store the return code of the thread. Optional. + */ +RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc); + +/** + * Gets the name of the current thread thread. + * + * @returns Pointer to readonly name string. + * @returns NULL on failure. + */ +RTDECL(const char *) RTThreadSelfName(void); + +/** + * Gets the name of a thread. + * + * @returns Pointer to readonly name string. + * @returns NULL on failure. + * @param Thread Thread handle of the thread to query the name of. + */ +RTDECL(const char *) RTThreadGetName(RTTHREAD Thread); + +/** + * Gets the type of the specified thread. + * + * @returns The thread type. + * @returns RTTHREADTYPE_INVALID if the thread handle is invalid. + * @param Thread The thread in question. + */ +RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread); + +/** + * Sets the name of a thread. + * + * @returns iprt status code. + * @param Thread Thread handle of the thread to query the name of. + * @param pszName The thread name. + */ +RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName); + +/** + * Checks if the specified thread is the main thread. + * + * @returns true if it is, false if it isn't. + * + * @param hThread The thread handle. + */ +RTDECL(bool) RTThreadIsMain(RTTHREAD hThread); + +/** + * Checks if the calling thread is known to IPRT. + * + * @returns @c true if it is, @c false if it isn't. + */ +RTDECL(bool) RTThreadIsSelfKnown(void); + +/** + * Checks if the calling thread is know to IPRT and is alive. + * + * @returns @c true if it is, @c false if it isn't. + */ +RTDECL(bool) RTThreadIsSelfAlive(void); + +#ifdef IN_RING0 +/** + * Checks whether the specified thread is terminating. + * + * @retval VINF_SUCCESS if not terminating. + * @retval VINF_THREAD_IS_TERMINATING if terminating. + * @retval VERR_INVALID_HANDLE if hThread is not NIL_RTTHREAD. + * @retval VERR_NOT_SUPPORTED if the OS doesn't provide ways to check. + * + * @param hThread The thread to query about, NIL_RTTHREAD is an alias for + * the calling thread. Must be NIL_RTTHREAD for now. + * + * @note Not suppored on all OSes, so check for VERR_NOT_SUPPORTED. + */ +RTDECL(int) RTThreadQueryTerminationStatus(RTTHREAD hThread); +#endif + +/** + * Signal the user event. + * + * @returns iprt status code. + */ +RTDECL(int) RTThreadUserSignal(RTTHREAD Thread); + +/** + * Wait for the user event. + * + * @returns iprt status code. + * @param Thread The thread to wait for. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + */ +RTDECL(int) RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies); + +/** + * Wait for the user event, return on interruption. + * + * @returns iprt status code. + * @param Thread The thread to wait for. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + */ +RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies); + +/** + * Reset the user event. + * + * @returns iprt status code. + * @param Thread The thread to reset. + */ +RTDECL(int) RTThreadUserReset(RTTHREAD Thread); + +/** + * Pokes the thread. + * + * This will wake up or/and signal the thread, attempting to interrupt whatever + * it's currently doing. + * + * The posixy version of this will send a signal to the thread, quite likely + * waking it up from normal sleeps, waits, and I/O. When IPRT is in + * non-obtrusive mode, the posixy version will definitely return + * VERR_NOT_IMPLEMENTED, and it may also do so if no usable signal was found. + * + * On Windows the thread will be alerted, waking it up from most sleeps and + * waits, but not probably very little in the I/O area (needs testing). On NT + * 3.50 and 3.1 VERR_NOT_IMPLEMENTED will be returned. + * + * @returns IPRT status code. + * + * @param hThread The thread to poke. This must not be the + * calling thread. + * + * @note This is *NOT* implemented on all platforms and may cause unresolved + * symbols during linking or VERR_NOT_IMPLEMENTED at runtime. + * + */ +RTDECL(int) RTThreadPoke(RTTHREAD hThread); + +/** + * Controls the masking of the signal used by RTThreadPoke on posix systems. + * + * This function is not available on non-posix systems. + * + * @returns IPRT status code. + * + * @param hThread The current thread. + * @param fEnable Whether to enable poking (unblock) or to disable it + * (block the signal). + */ +RTDECL(int) RTThreadControlPokeSignal(RTTHREAD hThread, bool fEnable); + + +# ifdef IN_RING0 + +/** + * Check if preemption is currently enabled or not for the current thread. + * + * @note This may return true even on systems where preemption isn't + * possible. In that case, it means no call to RTThreadPreemptDisable + * has been made and interrupts are still enabled. + * + * @returns true if preemption is enabled, false if preemetion is disabled. + * @param hThread Must be NIL_RTTHREAD for now. + */ +RTDECL(bool) RTThreadPreemptIsEnabled(RTTHREAD hThread); + +/** + * Check if preemption is pending for the current thread. + * + * This function should be called regularly when executing larger portions of + * code with preemption disabled. + * + * @returns true if pending, false if not. + * @param hThread Must be NIL_RTTHREAD for now. + * + * @note If called with interrupts disabled, the NT kernel may temporarily + * re-enable them while checking. + */ +RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread); + +/** + * Is RTThreadPreemptIsPending reliable? + * + * @returns true if reliable, false if not. + */ +RTDECL(bool) RTThreadPreemptIsPendingTrusty(void); + +/** + * Is preemption possible on this system. + * + * @returns true if possible, false if not. + */ +RTDECL(bool) RTThreadPreemptIsPossible(void); + +/** + * Preemption state saved by RTThreadPreemptDisable and used by + * RTThreadPreemptRestore to restore the previous state. + */ +typedef struct RTTHREADPREEMPTSTATE +{ + /** In debug builds this will be used to check for cpu migration. */ + RTCPUID idCpu; +# ifdef RT_OS_WINDOWS + /** The old IRQL. Don't touch! */ + unsigned char uchOldIrql; + /** Reserved, MBZ. */ + uint8_t bReserved1; + /** Reserved, MBZ. */ + uint8_t bReserved2; + /** Reserved, MBZ. */ + uint8_t bReserved3; +# define RTTHREADPREEMPTSTATE_INITIALIZER { NIL_RTCPUID, 255, 0, 0, 0 } +# elif defined(RT_OS_HAIKU) + /** The cpu_state. Don't touch! */ + uint32_t uOldCpuState; +# define RTTHREADPREEMPTSTATE_INITIALIZER { NIL_RTCPUID, 0 } +# elif defined(RT_OS_SOLARIS) + /** The Old PIL. Don't touch! */ + uint32_t uOldPil; +# define RTTHREADPREEMPTSTATE_INITIALIZER { NIL_RTCPUID, UINT32_MAX } +# else + /** Reserved, MBZ. */ + uint32_t u32Reserved; +# define RTTHREADPREEMPTSTATE_INITIALIZER { NIL_RTCPUID, 0 } +# endif +} RTTHREADPREEMPTSTATE; +/** Pointer to a preemption state. */ +typedef RTTHREADPREEMPTSTATE *PRTTHREADPREEMPTSTATE; + +/** + * Disable preemption. + * + * A call to this function must be matched by exactly one call to + * RTThreadPreemptRestore(). + * + * @param pState Where to store the preemption state. + */ +RTDECL(void) RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState); + +/** + * Restores the preemption state, undoing a previous call to + * RTThreadPreemptDisable. + * + * A call to this function must be matching a previous call to + * RTThreadPreemptDisable. + * + * @param pState The state return by RTThreadPreemptDisable. + */ +RTDECL(void) RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState); + +/** + * Check if the thread is executing in interrupt context. + * + * @returns true if in interrupt context, false if not. + * @param hThread Must be NIL_RTTHREAD for now. + */ +RTDECL(bool) RTThreadIsInInterrupt(RTTHREAD hThread); + + +/** + * Thread context swithcing events. + */ +typedef enum RTTHREADCTXEVENT +{ + /** This thread is being scheduled out on the current CPU (includes preemption, + * waiting, sleep and whatever else may trigger scheduling). */ + RTTHREADCTXEVENT_OUT = 0, + /** This thread is being scheduled in on the current CPU and will resume + * execution. */ + RTTHREADCTXEVENT_IN, + /** The usual 32-bit size hack. */ + RTTHREADCTXEVENT_32BIT_HACK = 0x7fffffff +} RTTHREADCTXEVENT; + +/** + * Thread context switching hook callback. + * + * This hook function is called when a thread is scheduled and preempted. Check + * @a enmEvent to see which it is. Since the function is being called from + * hooks inside the scheduler, it is limited what you can do from this function. + * Do NOT acquire locks, sleep or yield the thread for instance. IRQ safe + * spinlocks are fine though. + * + * @returns IPRT status code. + * @param enmEvent The thread-context event. Please quitely ignore unknown + * events, we may add more (thread exit, ++) later. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTTHREADCTXHOOK,(RTTHREADCTXEVENT enmEvent, void *pvUser)); +/** Pointer to a context switching hook. */ +typedef FNRTTHREADCTXHOOK *PFNRTTHREADCTXHOOK; + +/** + * Initializes a thread context switching hook for the current thread. + * + * The hook is created as disabled, use RTThreadCtxHookEnable to enable it. + * + * @returns IPRT status code. + * @param phCtxHook Where to store the hook handle. + * @param fFlags Reserved for future extensions, must be zero. + * @param pfnCallback Pointer to a the hook function (callback) that + * should be called for all context switching events + * involving the current thread. + * @param pvUser User argument that will be passed to @a pfnCallback. + * @remarks Preemption must be enabled. + */ +RTDECL(int) RTThreadCtxHookCreate(PRTTHREADCTXHOOK phCtxHook, uint32_t fFlags, PFNRTTHREADCTXHOOK pfnCallback, void *pvUser); + +/** + * Destroys a thread context switching hook. + * + * Caller must make sure the hook is disabled before the final reference is + * released. Recommended to call this on the owning thread, otherwise the + * memory backing it may on some systems only be released when the thread + * terminates. + * + * @returns IPRT status code. + * + * @param hCtxHook The context hook handle. NIL_RTTHREADCTXHOOK is + * ignored and the function will return VINF_SUCCESS. + * @remarks Preemption must be enabled. + * @remarks Do not call from FNRTTHREADCTXHOOK. + */ +RTDECL(int) RTThreadCtxHookDestroy(RTTHREADCTXHOOK hCtxHook); + +/** + * Enables the context switching hooks for the current thread. + * + * @returns IPRT status code. + * @param hCtxHook The context hook handle. + * @remarks Should be called with preemption disabled. + */ +RTDECL(int) RTThreadCtxHookEnable(RTTHREADCTXHOOK hCtxHook); + +/** + * Disables the thread context switching hook for the current thread. + * + * Will not assert or fail if called twice or with a NIL handle. + * + * @returns IPRT status code. + * @param hCtxHook The context hook handle. NIL_RTTHREADCTXHOOK is + * ignored and the function wil return VINF_SUCCESS. + * @remarks Should be called with preemption disabled. + * @remarks Do not call from FNRTTHREADCTXHOOK. + */ +RTDECL(int) RTThreadCtxHookDisable(RTTHREADCTXHOOK hCtxHook); + +/** + * Is the thread context switching hook enabled? + * + * @returns true if registered, false if not supported or not registered. + * @param hCtxHook The context hook handle. NIL_RTTHREADCTXHOOK is + * ignored and the function will return false. + * + * @remarks Can be called from any thread, though is naturally subject to races + * when not called from the thread associated with the hook. + */ +RTDECL(bool) RTThreadCtxHookIsEnabled(RTTHREADCTXHOOK hCtxHook); + +# endif /* IN_RING0 */ + + +# ifdef IN_RING3 + +/** + * Adopts a non-IPRT thread. + * + * @returns IPRT status code. + * @param enmType The thread type. + * @param fFlags The thread flags. RTTHREADFLAGS_WAITABLE is not currently allowed. + * @param pszName The thread name. Optional + * @param pThread Where to store the thread handle. Optional. + */ +RTDECL(int) RTThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName, PRTTHREAD pThread); + +/** + * Get the thread handle of the current thread, automatically adopting alien + * threads. + * + * @returns Thread handle. + */ +RTDECL(RTTHREAD) RTThreadSelfAutoAdopt(void); + +/** + * Gets the affinity mask of the current thread. + * + * @returns IPRT status code. + * @param pCpuSet Where to return the CPU affienty set of the calling + * thread. + */ +RTR3DECL(int) RTThreadGetAffinity(PRTCPUSET pCpuSet); + +/** + * Sets the affinity mask of the current thread. + * + * @returns iprt status code. + * @param pCpuSet The set of CPUs this thread can run on. NULL means + * all CPUs. + */ +RTR3DECL(int) RTThreadSetAffinity(PCRTCPUSET pCpuSet); + +/** + * Binds the thread to one specific CPU. + * + * @returns iprt status code. + * @param idCpu The ID of the CPU to bind this thread to. Use + * NIL_RTCPUID to unbind it. + */ +RTR3DECL(int) RTThreadSetAffinityToCpu(RTCPUID idCpu); + +/** + * Unblocks a thread. + * + * This function is paired with RTThreadBlocking and RTThreadBlockingDebug. + * + * @param hThread The current thread. + * @param enmCurState The current state, used to check for nested blocking. + * The new state will be running. + */ +RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState); + +/** + * Change the thread state to blocking. + * + * @param hThread The current thread. + * @param enmState The sleep state. + * @param fReallySleeping Really going to sleep now. Use false before calls + * to other IPRT synchronization methods. + */ +RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState, bool fReallySleeping); + +/** + * Get the current thread state. + * + * A thread that is reported as sleeping may actually still be running inside + * the lock validator or/and in the code of some other IPRT synchronization + * primitive. Use RTThreadGetReallySleeping + * + * @returns The thread state. + * @param hThread The thread. + */ +RTDECL(RTTHREADSTATE) RTThreadGetState(RTTHREAD hThread); + +/** + * Checks if the thread is really sleeping or not. + * + * @returns RTTHREADSTATE_RUNNING if not really sleeping, otherwise the state it + * is sleeping in. + * @param hThread The thread. + */ +RTDECL(RTTHREADSTATE) RTThreadGetReallySleeping(RTTHREAD hThread); + +/** + * Translate a thread state into a string. + * + * @returns Pointer to a read-only string containing the state name. + * @param enmState The state. + */ +RTDECL(const char *) RTThreadStateName(RTTHREADSTATE enmState); + + +/** + * Native thread states returned by RTThreadNativeState. + */ +typedef enum RTTHREADNATIVESTATE +{ + /** Invalid thread handle. */ + RTTHREADNATIVESTATE_INVALID = 0, + /** Unable to determine the thread state. */ + RTTHREADNATIVESTATE_UNKNOWN, + /** The thread is running. */ + RTTHREADNATIVESTATE_RUNNING, + /** The thread is blocked. */ + RTTHREADNATIVESTATE_BLOCKED, + /** The thread is suspended / stopped. */ + RTTHREADNATIVESTATE_SUSPENDED, + /** The thread has terminated. */ + RTTHREADNATIVESTATE_TERMINATED, + /** Make sure it's a 32-bit type. */ + RTTHREADNATIVESTATE_32BIT_HACK = 0x7fffffff +} RTTHREADNATIVESTATE; + + +/** + * Get the native state of a thread. + * + * @returns Native state. + * @param hThread The thread handle. + * + * @remarks Not yet implemented on all systems, so have a backup plan for + * RTTHREADNATIVESTATE_UNKNOWN. + */ +RTDECL(RTTHREADNATIVESTATE) RTThreadGetNativeState(RTTHREAD hThread); + + +/** + * Get the execution times of the specified thread + * + * @returns IPRT status code. + * @param pKernelTime Kernel execution time in ms (out) + * @param pUserTime User execution time in ms (out) + * + */ +RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUserTime); + +/** @name Thread Local Storage + * @{ + */ +/** + * Thread termination callback for destroying a non-zero TLS entry. + * + * @remarks It is not permitable to use any RTTls APIs at this time. Doing so + * may lead to endless loops, crashes, and other bad stuff. + * + * @param pvValue The current value. + */ +typedef DECLCALLBACKTYPE(void, FNRTTLSDTOR,(void *pvValue)); +/** Pointer to a FNRTTLSDTOR. */ +typedef FNRTTLSDTOR *PFNRTTLSDTOR; + +/** + * Allocates a TLS entry (index). + * + * Example code: + * @code + RTTLS g_iTls = NIL_RTTLS; + + ... + + // once for the process, allocate the TLS index + if (g_iTls == NIL_RTTLS) + g_iTls = RTTlsAlloc(); + + // set the thread-local value. + RTTlsSet(g_iTls, pMyData); + + ... + + // get the thread-local value + PMYDATA pMyData = (PMYDATA)RTTlsGet(g_iTls); + + @endcode + * + * @returns the index of the allocated TLS entry. + * @returns NIL_RTTLS on failure. + */ +RTR3DECL(RTTLS) RTTlsAlloc(void); + +/** + * Variant of RTTlsAlloc that returns a status code. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if pfnDestructor is non-NULL and the platform + * doesn't support this feature. + * + * @param piTls Where to store the index of the allocated TLS entry. + * This is set to NIL_RTTLS on failure. + * @param pfnDestructor Optional callback function for cleaning up on + * thread termination. + * @note In static builds on windows, the destructor will only be invoked for + * IPRT threads. + * @note There are probably OS specific restrictions on what operations you + * are allowed to perform from a TLS destructor, so keep it simple. + */ +RTR3DECL(int) RTTlsAllocEx(PRTTLS piTls, PFNRTTLSDTOR pfnDestructor); + +/** + * Frees a TLS entry. + * + * @returns IPRT status code. + * @param iTls The index of the TLS entry. + */ +RTR3DECL(int) RTTlsFree(RTTLS iTls); + +/** + * Get the (thread-local) value stored in a TLS entry. + * + * @returns value in given TLS entry. + * @retval NULL if RTTlsSet() has not yet been called on this thread, or if the + * TLS index is invalid. + * + * @param iTls The index of the TLS entry. + */ +RTR3DECL(void *) RTTlsGet(RTTLS iTls); + +/** + * Get the value stored in a TLS entry. + * + * @returns IPRT status code. + * @param iTls The index of the TLS entry. + * @param ppvValue Where to store the value. The value will be NULL if + * RTTlsSet has not yet been called on this thread. + */ +RTR3DECL(int) RTTlsGetEx(RTTLS iTls, void **ppvValue); + +/** + * Set the value stored in an allocated TLS entry. + * + * @returns IPRT status. + * @param iTls The index of the TLS entry. + * @param pvValue The value to store. + * + * @remarks Note that NULL is considered a special value. + */ +RTR3DECL(int) RTTlsSet(RTTLS iTls, void *pvValue); + +/** @} */ + +# endif /* IN_RING3 */ +#endif /* !IN_RC || defined(DOXYGEN_RUNNING) */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_thread_h */ + diff --git a/include/iprt/time.h b/include/iprt/time.h new file mode 100644 index 00000000..178f1e33 --- /dev/null +++ b/include/iprt/time.h @@ -0,0 +1,1352 @@ +/** @file + * IPRT - Time. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_time_h +#define IPRT_INCLUDED_time_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_time RTTime - Time + * @ingroup grp_rt + * @{ + */ + +/** Time Specification. + * + * Use the inline RTTimeSpecGet/Set to operate on structure this so we + * can easily change the representation if required later. + * + * The current representation is in nanoseconds relative to the unix epoch + * (1970-01-01 00:00:00 UTC). This gives us an approximate span from + * 1678 to 2262 without sacrificing the resolution offered by the various + * host OSes (BSD & LINUX 1ns, NT 100ns). + */ +typedef struct RTTIMESPEC +{ + /** Nanoseconds since epoch. + * The name is intentially too long to be comfortable to use because you should be + * using inline helpers! */ + int64_t i64NanosecondsRelativeToUnixEpoch; +} RTTIMESPEC; + + +/** @name RTTIMESPEC methods + * @{ */ + +/** + * Gets the time as nanoseconds relative to the unix epoch. + * + * @returns Nanoseconds relative to unix epoch. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetNano(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch; +} + + +/** + * Sets the time give by nanoseconds relative to the unix epoch. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Nano The new time in nanoseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetNano(PRTTIMESPEC pTime, int64_t i64Nano) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Nano; + return pTime; +} + + +/** + * Gets the time as microseconds relative to the unix epoch. + * + * @returns microseconds relative to unix epoch. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetMicro(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch / RT_NS_1US; +} + + +/** + * Sets the time given by microseconds relative to the unix epoch. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Micro The new time in microsecond. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetMicro(PRTTIMESPEC pTime, int64_t i64Micro) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Micro * RT_NS_1US; + return pTime; +} + + +/** + * Gets the time as milliseconds relative to the unix epoch. + * + * @returns milliseconds relative to unix epoch. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetMilli(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch / RT_NS_1MS; +} + + +/** + * Sets the time given by milliseconds relative to the unix epoch. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Milli The new time in milliseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetMilli(PRTTIMESPEC pTime, int64_t i64Milli) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Milli * RT_NS_1MS; + return pTime; +} + + +/** + * Gets the time as seconds relative to the unix epoch. + * + * @returns seconds relative to unix epoch. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetSeconds(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch / RT_NS_1SEC; +} + + +/** + * Sets the time given by seconds relative to the unix epoch. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Seconds The new time in seconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetSeconds(PRTTIMESPEC pTime, int64_t i64Seconds) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Seconds * RT_NS_1SEC; + return pTime; +} + + +/** + * Makes the time spec absolute like abs() does (i.e. a positive value). + * + * @returns pTime. + * @param pTime The time spec to modify. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAbsolute(PRTTIMESPEC pTime) +{ + if (pTime->i64NanosecondsRelativeToUnixEpoch < 0) + pTime->i64NanosecondsRelativeToUnixEpoch = -pTime->i64NanosecondsRelativeToUnixEpoch; + return pTime; +} + + +/** + * Negates the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecNegate(PRTTIMESPEC pTime) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = -pTime->i64NanosecondsRelativeToUnixEpoch; + return pTime; +} + + +/** + * Adds a time period to the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimeAdd The time spec to add to pTime. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAdd(PRTTIMESPEC pTime, PCRTTIMESPEC pTimeAdd) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += pTimeAdd->i64NanosecondsRelativeToUnixEpoch; + return pTime; +} + + +/** + * Adds a time period give as nanoseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Nano The time period in nanoseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAddNano(PRTTIMESPEC pTime, int64_t i64Nano) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += i64Nano; + return pTime; +} + + +/** + * Adds a time period give as microseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Micro The time period in microseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAddMicro(PRTTIMESPEC pTime, int64_t i64Micro) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += i64Micro * RT_NS_1US; + return pTime; +} + + +/** + * Adds a time period give as milliseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Milli The time period in milliseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAddMilli(PRTTIMESPEC pTime, int64_t i64Milli) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += i64Milli * RT_NS_1MS; + return pTime; +} + + +/** + * Adds a time period give as seconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Seconds The time period in seconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAddSeconds(PRTTIMESPEC pTime, int64_t i64Seconds) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += i64Seconds * RT_NS_1SEC; + return pTime; +} + + +/** + * Subtracts a time period from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimeSub The time spec to subtract from pTime. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSub(PRTTIMESPEC pTime, PCRTTIMESPEC pTimeSub) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= pTimeSub->i64NanosecondsRelativeToUnixEpoch; + return pTime; +} + + +/** + * Subtracts a time period give as nanoseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Nano The time period in nanoseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSubNano(PRTTIMESPEC pTime, int64_t i64Nano) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= i64Nano; + return pTime; +} + + +/** + * Subtracts a time period give as microseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Micro The time period in microseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSubMicro(PRTTIMESPEC pTime, int64_t i64Micro) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= i64Micro * RT_NS_1US; + return pTime; +} + + +/** + * Subtracts a time period give as milliseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Milli The time period in milliseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSubMilli(PRTTIMESPEC pTime, int64_t i64Milli) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= i64Milli * RT_NS_1MS; + return pTime; +} + + +/** + * Subtracts a time period give as seconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Seconds The time period in seconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSubSeconds(PRTTIMESPEC pTime, int64_t i64Seconds) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= i64Seconds * RT_NS_1SEC; + return pTime; +} + + +/** + * Gives the time in seconds and nanoseconds. + * + * @returns pTime. + * @param pTime The time spec to interpret. + * @param *pi32Seconds Where to store the time period in seconds. + * @param *pi32Nano Where to store the time period in nanoseconds. + */ +DECLINLINE(void) RTTimeSpecGetSecondsAndNano(PRTTIMESPEC pTime, int32_t *pi32Seconds, int32_t *pi32Nano) +{ + int64_t i64 = RTTimeSpecGetNano(pTime); + int32_t i32Nano = (int32_t)(i64 % RT_NS_1SEC); + i64 /= RT_NS_1SEC; + if (i32Nano < 0) + { + i32Nano += RT_NS_1SEC; + i64--; + } + *pi32Seconds = (int32_t)i64; + *pi32Nano = i32Nano; +} + +/** @def RTTIME_LINUX_KERNEL_PREREQ + * Prerequisite minimum linux kernel version. + * @note Cannot really be moved to iprt/cdefs.h, see the-linux-kernel.h */ +/** @def RTTIME_LINUX_KERNEL_PREREQ_LT + * Prerequisite maxium linux kernel version (LT=less-than). + * @note Cannot really be moved to iprt/cdefs.h, see the-linux-kernel.h */ +#if defined(RT_OS_LINUX) && defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION) +# define RTTIME_LINUX_KERNEL_PREREQ(a, b, c) (LINUX_VERSION_CODE >= KERNEL_VERSION(a, b, c)) +# define RTTIME_LINUX_KERNEL_PREREQ_LT(a, b, c) (!RTTIME_LINUX_KERNEL_PREREQ(a, b, c)) +#else +# define RTTIME_LINUX_KERNEL_PREREQ(a, b, c) 0 +# define RTTIME_LINUX_KERNEL_PREREQ_LT(a, b, c) 0 +#endif + +/* PORTME: Add struct timeval guard macro here. */ +#if defined(RTTIME_INCL_TIMEVAL) \ + || defined(_SYS__TIMEVAL_H_) \ + || defined(_SYS_TIME_H) \ + || defined(_TIMEVAL) \ + || defined(_STRUCT_TIMEVAL) \ + || ( defined(RT_OS_LINUX) \ + && defined(_LINUX_TIME_H) \ + && ( !defined(__KERNEL__) \ + || RTTIME_LINUX_KERNEL_PREREQ_LT(5,6,0) /* @bugref{9757} */ ) ) \ + || (defined(RT_OS_NETBSD) && defined(_SYS_TIME_H_)) + +/** + * Gets the time as POSIX timeval. + * + * @returns pTime. + * @param pTime The time spec to interpret. + * @param pTimeval Where to store the time as POSIX timeval. + */ +DECLINLINE(struct timeval *) RTTimeSpecGetTimeval(PCRTTIMESPEC pTime, struct timeval *pTimeval) +{ + int64_t i64 = RTTimeSpecGetMicro(pTime); + int32_t i32Micro = (int32_t)(i64 % RT_US_1SEC); + i64 /= RT_US_1SEC; + if (i32Micro < 0) + { + i32Micro += RT_US_1SEC; + i64--; + } + pTimeval->tv_sec = (time_t)i64; + pTimeval->tv_usec = i32Micro; + return pTimeval; +} + +/** + * Sets the time as POSIX timeval. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimeval Pointer to the POSIX timeval struct with the new time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetTimeval(PRTTIMESPEC pTime, const struct timeval *pTimeval) +{ + return RTTimeSpecAddMicro(RTTimeSpecSetSeconds(pTime, pTimeval->tv_sec), pTimeval->tv_usec); +} + +#endif /* various ways of detecting struct timeval */ + + +/* PORTME: Add struct timespec guard macro here. */ +#if defined(RTTIME_INCL_TIMESPEC) \ + || defined(_SYS__TIMESPEC_H_) \ + || defined(TIMEVAL_TO_TIMESPEC) \ + || defined(_TIMESPEC) \ + || ( defined(_STRUCT_TIMESPEC) \ + && ( !defined(RT_OS_LINUX) \ + || !defined(__KERNEL__) \ + || RTTIME_LINUX_KERNEL_PREREQ_LT(5,6,0) /* @bugref{9757} */ ) ) \ + || (defined(RT_OS_NETBSD) && defined(_SYS_TIME_H_)) + +/** + * Gets the time as POSIX timespec. + * + * @returns pTimespec. + * @param pTime The time spec to interpret. + * @param pTimespec Where to store the time as POSIX timespec. + */ +DECLINLINE(struct timespec *) RTTimeSpecGetTimespec(PCRTTIMESPEC pTime, struct timespec *pTimespec) +{ + int64_t i64 = RTTimeSpecGetNano(pTime); + int32_t i32Nano = (int32_t)(i64 % RT_NS_1SEC); + i64 /= RT_NS_1SEC; + if (i32Nano < 0) + { + i32Nano += RT_NS_1SEC; + i64--; + } + pTimespec->tv_sec = (time_t)i64; + pTimespec->tv_nsec = i32Nano; + return pTimespec; +} + +/** + * Sets the time as POSIX timespec. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimespec Pointer to the POSIX timespec struct with the new time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetTimespec(PRTTIMESPEC pTime, const struct timespec *pTimespec) +{ + return RTTimeSpecAddNano(RTTimeSpecSetSeconds(pTime, pTimespec->tv_sec), pTimespec->tv_nsec); +} + +#endif /* various ways of detecting struct timespec */ + + +#if defined(RT_OS_LINUX) && defined(_LINUX_TIME64_H) /* since linux 3.17 */ + +/** + * Gets the time a linux 64-bit timespec structure. + * @returns pTimespec. + * @param pTime The time spec to modify. + * @param pTimespec Where to store the time as linux 64-bit timespec. + */ +DECLINLINE(struct timespec64 *) RTTimeSpecGetTimespec64(PCRTTIMESPEC pTime, struct timespec64 *pTimespec) +{ + int64_t i64 = RTTimeSpecGetNano(pTime); + int32_t i32Nano = (int32_t)(i64 % RT_NS_1SEC); + i64 /= RT_NS_1SEC; + if (i32Nano < 0) + { + i32Nano += RT_NS_1SEC; + i64--; + } + pTimespec->tv_sec = i64; + pTimespec->tv_nsec = i32Nano; + return pTimespec; +} + +/** + * Sets the time from a linux 64-bit timespec structure. + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimespec Pointer to the linux 64-bit timespec struct with the new time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetTimespec64(PRTTIMESPEC pTime, const struct timespec64 *pTimespec) +{ + return RTTimeSpecAddNano(RTTimeSpecSetSeconds(pTime, pTimespec->tv_sec), pTimespec->tv_nsec); +} + +#endif /* RT_OS_LINUX && _LINUX_TIME64_H */ + + +/** The offset of the unix epoch and the base for NT time (in 100ns units). + * Nt time starts at 1601-01-01 00:00:00. */ +#define RTTIME_NT_TIME_OFFSET_UNIX (116444736000000000LL) + + +/** + * Gets the time as NT time. + * + * @returns NT time. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetNtTime(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch / 100 + + RTTIME_NT_TIME_OFFSET_UNIX; +} + + +/** + * Sets the time given by Nt time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param u64NtTime The new time in Nt time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetNtTime(PRTTIMESPEC pTime, uint64_t u64NtTime) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = + ((int64_t)u64NtTime - RTTIME_NT_TIME_OFFSET_UNIX) * 100; + return pTime; +} + + +#ifdef _FILETIME_ + +/** + * Gets the time as NT file time. + * + * @returns pFileTime. + * @param pTime The time spec to interpret. + * @param pFileTime Pointer to NT filetime structure. + */ +DECLINLINE(PFILETIME) RTTimeSpecGetNtFileTime(PCRTTIMESPEC pTime, PFILETIME pFileTime) +{ + *((uint64_t *)pFileTime) = RTTimeSpecGetNtTime(pTime); + return pFileTime; +} + +/** + * Sets the time as NT file time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pFileTime Where to store the time as Nt file time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetNtFileTime(PRTTIMESPEC pTime, const FILETIME *pFileTime) +{ + return RTTimeSpecSetNtTime(pTime, *(const uint64_t *)pFileTime); +} + +#endif /* _FILETIME_ */ + + +/** The offset to the start of DOS time. + * DOS time starts 1980-01-01 00:00:00. */ +#define RTTIME_OFFSET_DOS_TIME (315532800000000000LL) + + +/** + * Gets the time as seconds relative to the start of dos time. + * + * @returns seconds relative to the start of dos time. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetDosSeconds(PCRTTIMESPEC pTime) +{ + return (pTime->i64NanosecondsRelativeToUnixEpoch - RTTIME_OFFSET_DOS_TIME) + / RT_NS_1SEC; +} + + +/** + * Sets the time given by seconds relative to the start of dos time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Seconds The new time in seconds relative to the start of dos time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetDosSeconds(PRTTIMESPEC pTime, int64_t i64Seconds) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Seconds * RT_NS_1SEC + + RTTIME_OFFSET_DOS_TIME; + return pTime; +} + + +/** + * Compare two time specs. + * + * @returns true they are equal. + * @returns false they are not equal. + * @param pTime1 The 1st time spec. + * @param pTime2 The 2nd time spec. + */ +DECLINLINE(bool) RTTimeSpecIsEqual(PCRTTIMESPEC pTime1, PCRTTIMESPEC pTime2) +{ + return pTime1->i64NanosecondsRelativeToUnixEpoch == pTime2->i64NanosecondsRelativeToUnixEpoch; +} + + +/** + * Compare two time specs. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @returns false they are not equal. + * @param pLeft The 1st time spec. + * @param pRight The 2nd time spec. + */ +DECLINLINE(int) RTTimeSpecCompare(PCRTTIMESPEC pLeft, PCRTTIMESPEC pRight) +{ + if (pLeft->i64NanosecondsRelativeToUnixEpoch == pRight->i64NanosecondsRelativeToUnixEpoch) + return 0; + return pLeft->i64NanosecondsRelativeToUnixEpoch < pRight->i64NanosecondsRelativeToUnixEpoch ? -1 : 1; +} + + +/** + * Converts a time spec to a ISO date string. + * + * @returns psz on success. + * @returns NULL on buffer underflow. + * @param pTime The time spec. + * @param psz Where to store the string. + * @param cb The size of the buffer. + */ +RTDECL(char *) RTTimeSpecToString(PCRTTIMESPEC pTime, char *psz, size_t cb); + +/** + * Attempts to convert an ISO date string to a time structure. + * + * We're a little forgiving with zero padding, unspecified parts, and leading + * and trailing spaces. + * + * @retval pTime on success, + * @retval NULL on failure. + * @param pTime The time spec. + * @param pszString The ISO date string to convert. + */ +RTDECL(PRTTIMESPEC) RTTimeSpecFromString(PRTTIMESPEC pTime, const char *pszString); + +/** + * Formats duration as best we can according to ISO-8601, with no fraction. + * + * See RTTimeFormatDurationEx for details. + * + * @returns Number of characters in the output on success. VERR_BUFFER_OVEFLOW + * on failure. + * @param pszDst Pointer to the output buffer. In case of overflow, + * the max number of characters will be written and + * zero terminated, provided @a cbDst isn't zero. + * @param cbDst The size of the output buffer. + * @param pDuration The duration to format. + */ +RTDECL(int) RTTimeFormatDuration(char *pszDst, size_t cbDst, PCRTTIMESPEC pDuration); + +/** + * Formats duration as best we can according to ISO-8601. + * + * The returned value is on the form "[-]PnnnnnWnDTnnHnnMnn.fffffffffS", where a + * sequence of 'n' can be between 1 and the given lenght, and all but the + * "nn.fffffffffS" part is optional and will only be outputted when the duration + * is sufficiently large. The code currently does not omit any inbetween + * elements other than the day count (D), so an exactly 7 day duration is + * formatted as "P1WT0H0M0.000000000S" when @a cFractionDigits is 9. + * + * @returns Number of characters in the output on success. VERR_BUFFER_OVEFLOW + * on failure. + * @retval VERR_OUT_OF_RANGE if @a cFractionDigits is too large. + * @param pszDst Pointer to the output buffer. In case of overflow, + * the max number of characters will be written and + * zero terminated, provided @a cbDst isn't zero. + * @param cbDst The size of the output buffer. + * @param pDuration The duration to format. + * @param cFractionDigits Number of digits in the second fraction part. Zero + * for whole no fraction. Max is 9 (nano seconds). + */ +RTDECL(ssize_t) RTTimeFormatDurationEx(char *pszDst, size_t cbDst, PCRTTIMESPEC pDuration, uint32_t cFractionDigits); + +/** Max length of a RTTimeFormatDurationEx output string. */ +#define RTTIME_DURATION_STR_LEN (sizeof("-P99999W7D23H59M59.123456789S") + 2) + +/** @} */ + + +/** + * Exploded time. + */ +typedef struct RTTIME +{ + /** The year number. */ + int32_t i32Year; + /** The month of the year (1-12). January is 1. */ + uint8_t u8Month; + /** The day of the week (0-6). Monday is 0. */ + uint8_t u8WeekDay; + /** The day of the year (1-366). January the 1st is 1. */ + uint16_t u16YearDay; + /** The day of the month (1-31). */ + uint8_t u8MonthDay; + /** Hour of the day (0-23). */ + uint8_t u8Hour; + /** The minute of the hour (0-59). */ + uint8_t u8Minute; + /** The second of the minute (0-60). + * (u32Nanosecond / 1000000) */ + uint8_t u8Second; + /** The nanoseconds of the second (0-999999999). */ + uint32_t u32Nanosecond; + /** Flags, of the RTTIME_FLAGS_* \#defines. */ + uint32_t fFlags; + /** UTC time offset in minutes (-840-840). Positive for timezones east of + * UTC, negative for zones to the west. Same as what RTTimeLocalDeltaNano + * & RTTimeLocalDeltaNanoFor returns, just different unit. */ + int32_t offUTC; +} RTTIME; +AssertCompileSize(RTTIME, 24); +/** Pointer to a exploded time structure. */ +typedef RTTIME *PRTTIME; +/** Pointer to a const exploded time structure. */ +typedef const RTTIME *PCRTTIME; + +/** @name RTTIME::fFlags values. + * @{ */ +/** Set if the time is UTC. If clear the time local time. */ +#define RTTIME_FLAGS_TYPE_MASK 3 +/** the time is UTC time. */ +#define RTTIME_FLAGS_TYPE_UTC 2 +/** The time is local time. */ +#define RTTIME_FLAGS_TYPE_LOCAL 3 + +/** Set if the time is local and daylight saving time is in effect. + * Not bit is not valid if RTTIME_FLAGS_NO_DST_DATA is set. */ +#define RTTIME_FLAGS_DST RT_BIT(4) +/** Set if the time is local and there is no data available on daylight saving time. */ +#define RTTIME_FLAGS_NO_DST_DATA RT_BIT(5) +/** Set if the year is a leap year. + * This is mutual exclusiv with RTTIME_FLAGS_COMMON_YEAR. */ +#define RTTIME_FLAGS_LEAP_YEAR RT_BIT(6) +/** Set if the year is a common year. + * This is mutual exclusiv with RTTIME_FLAGS_LEAP_YEAR. */ +#define RTTIME_FLAGS_COMMON_YEAR RT_BIT(7) +/** The mask of valid flags. */ +#define RTTIME_FLAGS_MASK UINT32_C(0xff) +/** @} */ + + +/** + * Gets the current system time (UTC). + * + * @returns pTime. + * @param pTime Where to store the time. + */ +RTDECL(PRTTIMESPEC) RTTimeNow(PRTTIMESPEC pTime); + +/** + * Sets the system time. + * + * @returns IPRT status code + * @param pTime The new system time (UTC). + * + * @remarks This will usually fail because changing the wall time is usually + * requires extra privileges. + */ +RTDECL(int) RTTimeSet(PCRTTIMESPEC pTime); + +/** + * Explodes a time spec (UTC). + * + * @returns pTime. + * @param pTime Where to store the exploded time. + * @param pTimeSpec The time spec to exploded. + */ +RTDECL(PRTTIME) RTTimeExplode(PRTTIME pTime, PCRTTIMESPEC pTimeSpec); + +/** + * Implodes exploded time to a time spec (UTC). + * + * @returns pTime on success. + * @returns NULL if the pTime data is invalid. + * @param pTimeSpec Where to store the imploded UTC time. + * If pTime specifies a time which outside the range, maximum or + * minimum values will be returned. + * @param pTime Pointer to the exploded time to implode. + * The fields u8Month, u8WeekDay and u8MonthDay are not used, + * and all the other fields are expected to be within their + * bounds. Use RTTimeNormalize() to calculate u16YearDay and + * normalize the ranges of the fields. + */ +RTDECL(PRTTIMESPEC) RTTimeImplode(PRTTIMESPEC pTimeSpec, PCRTTIME pTime); + +/** + * Normalizes the fields of a time structure. + * + * It is possible to calculate year-day from month/day and vice + * versa. If you adjust any of of these, make sure to zero the + * other so you make it clear which of the fields to use. If + * it's ambiguous, the year-day field is used (and you get + * assertions in debug builds). + * + * All the time fields and the year-day or month/day fields will + * be adjusted for overflows. (Since all fields are unsigned, there + * is no underflows.) It is possible to exploit this for simple + * date math, though the recommended way of doing that to implode + * the time into a timespec and do the math on that. + * + * @returns pTime on success. + * @returns NULL if the data is invalid. + * + * @param pTime The time structure to normalize. + * + * @remarks This function doesn't work with local time, only with UTC time. + */ +RTDECL(PRTTIME) RTTimeNormalize(PRTTIME pTime); + +/** + * Gets the current local system time. + * + * @returns pTime. + * @param pTime Where to store the local time. + */ +RTDECL(PRTTIMESPEC) RTTimeLocalNow(PRTTIMESPEC pTime); + +/** + * Gets the current delta between UTC and local time. + * + * @code + * RTTIMESPEC LocalTime; + * RTTimeSpecAddNano(RTTimeNow(&LocalTime), RTTimeLocalDeltaNano()); + * @endcode + * + * @returns Returns the nanosecond delta between UTC and local time. + */ +RTDECL(int64_t) RTTimeLocalDeltaNano(void); + +/** + * Gets the delta between UTC and local time at the given time. + * + * @code + * RTTIMESPEC LocalTime; + * RTTimeNow(&LocalTime); + * RTTimeSpecAddNano(&LocalTime, RTTimeLocalDeltaNanoFor(&LocalTime)); + * @endcode + * + * @param pTimeSpec The time spec giving the time to get the delta for. + * @returns Returns the nanosecond delta between UTC and local time. + */ +RTDECL(int64_t) RTTimeLocalDeltaNanoFor(PCRTTIMESPEC pTimeSpec); + +/** + * Explodes a time spec to the localized timezone. + * + * @returns pTime. + * @param pTime Where to store the exploded time. + * @param pTimeSpec The time spec to exploded (UTC). + */ +RTDECL(PRTTIME) RTTimeLocalExplode(PRTTIME pTime, PCRTTIMESPEC pTimeSpec); + +/** + * Normalizes the fields of a time structure containing local time. + * + * See RTTimeNormalize for details. + * + * @returns pTime on success. + * @returns NULL if the data is invalid. + * @param pTime The time structure to normalize. + */ +RTDECL(PRTTIME) RTTimeLocalNormalize(PRTTIME pTime); + +/** + * Converts a time structure to UTC, relying on UTC offset information + * if it contains local time. + * + * @returns pTime on success. + * @returns NULL if the data is invalid. + * @param pTime The time structure to convert. + */ +RTDECL(PRTTIME) RTTimeConvertToZulu(PRTTIME pTime); + +/** + * Converts a time spec to a ISO date string. + * + * @returns psz on success. + * @returns NULL on buffer underflow. + * @param pTime The time. Caller should've normalized this. + * @param psz Where to store the string. + * @param cb The size of the buffer. + */ +RTDECL(char *) RTTimeToString(PCRTTIME pTime, char *psz, size_t cb); + +/** + * Converts a time spec to a ISO date string, extended version. + * + * @returns Output string length on success (positive), VERR_BUFFER_OVERFLOW + * (negative) or VERR_OUT_OF_RANGE (negative) on failure. + * @param pTime The time. Caller should've normalized this. + * @param psz Where to store the string. + * @param cb The size of the buffer. + * @param cFractionDigits Number of digits in the fraction. Max is 9. + */ +RTDECL(ssize_t) RTTimeToStringEx(PCRTTIME pTime, char *psz, size_t cb, unsigned cFractionDigits); + +/** Suggested buffer length for RTTimeToString and RTTimeToStringEx output, including terminator. */ +#define RTTIME_STR_LEN 40 + +/** + * Attempts to convert an ISO date string to a time structure. + * + * We're a little forgiving with zero padding, unspecified parts, and leading + * and trailing spaces. + * + * @retval pTime on success, + * @retval NULL on failure. + * @param pTime Where to store the time on success. + * @param pszString The ISO date string to convert. + */ +RTDECL(PRTTIME) RTTimeFromString(PRTTIME pTime, const char *pszString); + +/** + * Formats the given time on a RTC-2822 compliant format. + * + * @returns Output string length on success (positive), VERR_BUFFER_OVERFLOW + * (negative) on failure. + * @param pTime The time. Caller should've normalized this. + * @param psz Where to store the string. + * @param cb The size of the buffer. + * @param fFlags RTTIME_RFC2822_F_XXX + * @sa RTTIME_RFC2822_LEN + */ +RTDECL(ssize_t) RTTimeToRfc2822(PRTTIME pTime, char *psz, size_t cb, uint32_t fFlags); + +/** Suggested buffer length for RTTimeToRfc2822 output, including terminator. */ +#define RTTIME_RFC2822_LEN 40 +/** @name RTTIME_RFC2822_F_XXX + * @{ */ +/** Use the deprecated GMT timezone instead of +/-0000. + * This is required by the HTTP RFC-7231 7.1.1.1. */ +#define RTTIME_RFC2822_F_GMT RT_BIT_32(0) +/** @} */ + +/** + * Attempts to convert an RFC-2822 date string to a time structure. + * + * We're a little forgiving with zero padding, unspecified parts, and leading + * and trailing spaces. + * + * @retval pTime on success, + * @retval NULL on failure. + * @param pTime Where to store the time on success. + * @param pszString The ISO date string to convert. + */ +RTDECL(PRTTIME) RTTimeFromRfc2822(PRTTIME pTime, const char *pszString); + +/** + * Checks if a year is a leap year or not. + * + * @returns true if it's a leap year. + * @returns false if it's a common year. + * @param i32Year The year in question. + */ +RTDECL(bool) RTTimeIsLeapYear(int32_t i32Year); + +/** + * Compares two normalized time structures. + * + * @retval 0 if equal. + * @retval -1 if @a pLeft is earlier than @a pRight. + * @retval 1 if @a pRight is earlier than @a pLeft. + * + * @param pLeft The left side time. NULL is accepted. + * @param pRight The right side time. NULL is accepted. + * + * @note A NULL time is considered smaller than anything else. If both are + * NULL, they are considered equal. + */ +RTDECL(int) RTTimeCompare(PCRTTIME pLeft, PCRTTIME pRight); + +/** + * Gets the current nanosecond timestamp. + * + * @returns nanosecond timestamp. + */ +RTDECL(uint64_t) RTTimeNanoTS(void); + +/** + * Gets the current millisecond timestamp. + * + * @returns millisecond timestamp. + */ +RTDECL(uint64_t) RTTimeMilliTS(void); + +/** + * Debugging the time api. + * + * @returns the number of 1ns steps which has been applied by RTTimeNanoTS(). + */ +RTDECL(uint32_t) RTTimeDbgSteps(void); + +/** + * Debugging the time api. + * + * @returns the number of times the TSC interval expired RTTimeNanoTS(). + */ +RTDECL(uint32_t) RTTimeDbgExpired(void); + +/** + * Debugging the time api. + * + * @returns the number of bad previous values encountered by RTTimeNanoTS(). + */ +RTDECL(uint32_t) RTTimeDbgBad(void); + +/** + * Debugging the time api. + * + * @returns the number of update races in RTTimeNanoTS(). + */ +RTDECL(uint32_t) RTTimeDbgRaces(void); + + +RTDECL(const char *) RTTimeNanoTSWorkerName(void); + + +/** @name RTTimeNanoTS GIP worker functions, for TM. + * @{ */ + +/** Extra info optionally returned by the RTTimeNanoTS GIP workers. */ +typedef struct RTITMENANOTSEXTRA +{ + /** The TSC value used (delta adjusted). */ + uint64_t uTSCValue; +} RTITMENANOTSEXTRA; +/** Pointer to extra info optionally returned by the RTTimeNanoTS GIP workers. */ +typedef RTITMENANOTSEXTRA *PRTITMENANOTSEXTRA; + +/** Pointer to a RTTIMENANOTSDATA structure. */ +typedef struct RTTIMENANOTSDATA *PRTTIMENANOTSDATA; + +/** + * Nanosecond timestamp data. + * + * This is used to keep track of statistics and callback so IPRT + * and TM (VirtualBox) can share code. + * + * @remark Keep this in sync with the assembly version in timesupA.asm. + */ +typedef struct RTTIMENANOTSDATA +{ + /** Where the previous timestamp is stored. + * This is maintained to ensure that time doesn't go backwards or anything. */ + uint64_t volatile *pu64Prev; + + /** + * Helper function that's used by the assembly routines when something goes bust. + * + * @param pData Pointer to this structure. + * @param u64NanoTS The calculated nano ts. + * @param u64DeltaPrev The delta relative to the previously returned timestamp. + * @param u64PrevNanoTS The previously returned timestamp (as it was read it). + */ + DECLCALLBACKMEMBER(void, pfnBad,(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)); + + /** + * Callback for when rediscovery is required. + * + * @returns Nanosecond timestamp. + * @param pData Pointer to this structure. + * @param pExtra Where to return extra time info. Optional. + */ + DECLCALLBACKMEMBER(uint64_t, pfnRediscover,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); + + /** + * Callback for when some CPU index related stuff goes wrong. + * + * @returns Nanosecond timestamp. + * @param pData Pointer to this structure. + * @param pExtra Where to return extra time info. Optional. + * @param idApic The APIC ID if available, otherwise (UINT16_MAX-1). + * @param iCpuSet The CPU set index if available, otherwise + * (UINT16_MAX-1). + * @param iGipCpu The GIP CPU array index if available, otherwise + * (UINT16_MAX-1). + */ + DECLCALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra, + uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu)); + + /** Number of 1ns steps because of overshooting the period. */ + uint32_t c1nsSteps; + /** The number of times the interval expired (overflow). */ + uint32_t cExpired; + /** Number of "bad" previous values. */ + uint32_t cBadPrev; + /** The number of update races. */ + uint32_t cUpdateRaces; +} RTTIMENANOTSDATA; + +#ifndef IN_RING3 +/** + * The Ring-3 layout of the RTTIMENANOTSDATA structure. + */ +typedef struct RTTIMENANOTSDATAR3 +{ + R3PTRTYPE(uint64_t volatile *) pu64Prev; + DECLR3CALLBACKMEMBER(void, pfnBad,(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)); + DECLR3CALLBACKMEMBER(uint64_t, pfnRediscover,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); + DECLR3CALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra, + uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu)); + uint32_t c1nsSteps; + uint32_t cExpired; + uint32_t cBadPrev; + uint32_t cUpdateRaces; +} RTTIMENANOTSDATAR3; +#else +typedef RTTIMENANOTSDATA RTTIMENANOTSDATAR3; +#endif + +#ifndef IN_RING0 +/** + * The Ring-3 layout of the RTTIMENANOTSDATA structure. + */ +typedef struct RTTIMENANOTSDATAR0 +{ + R0PTRTYPE(uint64_t volatile *) pu64Prev; + DECLR0CALLBACKMEMBER(void, pfnBad,(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)); + DECLR0CALLBACKMEMBER(uint64_t, pfnRediscover,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); + DECLR0CALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra, + uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu)); + uint32_t c1nsSteps; + uint32_t cExpired; + uint32_t cBadPrev; + uint32_t cUpdateRaces; +} RTTIMENANOTSDATAR0; +#else +typedef RTTIMENANOTSDATA RTTIMENANOTSDATAR0; +#endif + +#ifndef IN_RC +/** + * The RC layout of the RTTIMENANOTSDATA structure. + */ +typedef struct RTTIMENANOTSDATARC +{ + RCPTRTYPE(uint64_t volatile *) pu64Prev; + DECLRCCALLBACKMEMBER(void, pfnBad,(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)); + DECLRCCALLBACKMEMBER(uint64_t, pfnRediscover,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); + DECLRCCALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra, + uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu)); + uint32_t c1nsSteps; + uint32_t cExpired; + uint32_t cBadPrev; + uint32_t cUpdateRaces; +} RTTIMENANOTSDATARC; +#else +typedef RTTIMENANOTSDATA RTTIMENANOTSDATARC; +#endif + +/** Internal RTTimeNanoTS worker (assembly). */ +typedef DECLCALLBACKTYPE(uint64_t, FNTIMENANOTSINTERNAL,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); +/** Pointer to an internal RTTimeNanoTS worker (assembly). */ +typedef FNTIMENANOTSINTERNAL *PFNTIMENANOTSINTERNAL; +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarNoDelta(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarNoDelta(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +#ifdef IN_RING3 +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseApicId(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseApicIdExt0B(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseRdtscp(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseIdtrLim(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseApicId(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseApicIdExt0B(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseRdtscp(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseIdtrLim(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +#else +RTDECL(uint64_t) RTTimeNanoTSLegacyAsync(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDelta(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsync(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDelta(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +#endif + +/** @} */ + + +/** + * Gets the current nanosecond timestamp. + * + * This differs from RTTimeNanoTS in that it will use system APIs and not do any + * resolution or performance optimizations. + * + * @returns nanosecond timestamp. + */ +RTDECL(uint64_t) RTTimeSystemNanoTS(void); + +/** + * Gets the current millisecond timestamp. + * + * This differs from RTTimeNanoTS in that it will use system APIs and not do any + * resolution or performance optimizations. + * + * @returns millisecond timestamp. + */ +RTDECL(uint64_t) RTTimeSystemMilliTS(void); + +/** + * Get the nanosecond timestamp relative to program startup. + * + * @returns Timestamp relative to program startup. + */ +RTDECL(uint64_t) RTTimeProgramNanoTS(void); + +/** + * Get the microsecond timestamp relative to program startup. + * + * @returns Timestamp relative to program startup. + */ +RTDECL(uint64_t) RTTimeProgramMicroTS(void); + +/** + * Get the millisecond timestamp relative to program startup. + * + * @returns Timestamp relative to program startup. + */ +RTDECL(uint64_t) RTTimeProgramMilliTS(void); + +/** + * Get the second timestamp relative to program startup. + * + * @returns Timestamp relative to program startup. + */ +RTDECL(uint32_t) RTTimeProgramSecTS(void); + +/** + * Get the RTTimeNanoTS() of when the program started. + * + * @returns Program startup timestamp. + */ +RTDECL(uint64_t) RTTimeProgramStartNanoTS(void); + + +/** + * Time zone information. + */ +typedef struct RTTIMEZONEINFO +{ + /** Unix time zone name (continent/country[/city]|). */ + const char *pszUnixName; + /** Windows time zone name. */ + const char *pszWindowsName; + /** The length of the unix time zone name. */ + uint8_t cchUnixName; + /** The length of the windows time zone name. */ + uint8_t cchWindowsName; + /** Two letter country/territory code if applicable, otherwise 'ZZ'. */ + char szCountry[3]; + /** Two letter windows country/territory code if applicable. + * Empty string if no windows mapping. */ + char szWindowsCountry[3]; +#if 0 /* Add when needed and it's been extracted. */ + /** The standard delta in minutes (add to UTC). */ + int16_t cMinStdDelta; + /** The daylight saving time delta in minutes (add to UTC). */ + int16_t cMinDstDelta; +#endif + /** closest matching windows time zone index. */ + uint32_t idxWindows; + /** Flags, RTTIMEZONEINFO_F_XXX. */ + uint32_t fFlags; +} RTTIMEZONEINFO; +/** Pointer to time zone info. */ +typedef RTTIMEZONEINFO const *PCRTTIMEZONEINFO; + +/** @name RTTIMEZONEINFO_F_XXX - time zone info flags. + * @{ */ +/** Indicates golden mapping entry for a windows time zone name. */ +#define RTTIMEZONEINFO_F_GOLDEN RT_BIT_32(0) +/** @} */ + +/** + * Looks up static time zone information by unix name. + * + * @returns Pointer to info entry if found, NULL if not. + * @param pszName The unix zone name (TZ). + */ +RTDECL(PCRTTIMEZONEINFO) RTTimeZoneGetInfoByUnixName(const char *pszName); + +/** + * Looks up static time zone information by window name. + * + * @returns Pointer to info entry if found, NULL if not. + * @param pszName The windows zone name (reg key). + */ +RTDECL(PCRTTIMEZONEINFO) RTTimeZoneGetInfoByWindowsName(const char *pszName); + +/** + * Looks up static time zone information by windows index. + * + * @returns Pointer to info entry if found, NULL if not. + * @param idxZone The windows timezone index. + */ +RTDECL(PCRTTIMEZONEINFO) RTTimeZoneGetInfoByWindowsIndex(uint32_t idxZone); + +/** + * Get the current time zone (TZ). + * + * @returns IPRT status code. + * @param pszName Where to return the time zone name. + * @param cbName The size of the name buffer. + */ +RTDECL(int) RTTimeZoneGetCurrent(char *pszName, size_t cbName); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_time_h */ + diff --git a/include/iprt/timer.h b/include/iprt/timer.h new file mode 100644 index 00000000..8cb34987 --- /dev/null +++ b/include/iprt/timer.h @@ -0,0 +1,400 @@ +/** @file + * IPRT - Timer. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_timer_h +#define IPRT_INCLUDED_timer_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_timer RTTimer - Timer + * + * The IPRT timer API provides a simple abstraction of recurring and one-shot callback timers. + * + * Because of the great variation in the native APIs and the quality of + * the service delivered by those native APIs, the timers are operated + * on at best effort basis. + * + * All the ring-3 implementations are naturally at the mercy of the scheduler, + * which means that the callback rate might vary quite a bit and we might skip + * ticks. Many systems have a restriction that a process can only have one + * timer. IPRT currently makes no efforts at multiplexing timers in those kind + * of situations and will simply fail if you try to create more than one timer. + * + * Things are generally better in ring-0. The implementations will use interrupt + * time callbacks wherever available, and if not, resort to a high priority + * kernel thread. + * + * @ingroup grp_rt + * @{ + */ + + +/** Timer handle. */ +typedef struct RTTIMER *PRTTIMER; + +/** + * Timer callback function. + * + * The context this call is made in varies with different platforms and + * kernel / user mode IPRT. + * + * In kernel mode a timer callback should not waste time, it shouldn't + * waste stack and it should be prepared that some APIs might not work + * correctly because of weird OS restrictions in this context that we + * haven't discovered and avoided yet. Please fix those APIs so they + * at least avoid panics and weird behaviour. + * + * @param pTimer Timer handle. + * @param pvUser User argument. + * @param iTick The current timer tick. This is always 1 on the first + * callback after the timer was started. For omni timers + * this will be 1 when a cpu comes back online. + */ +typedef DECLCALLBACKTYPE(void, FNRTTIMER,(PRTTIMER pTimer, void *pvUser, uint64_t iTick)); +/** Pointer to FNRTTIMER() function. */ +typedef FNRTTIMER *PFNRTTIMER; + + +/** + * Create a recurring timer. + * + * @returns iprt status code. + * @param ppTimer Where to store the timer handle. + * @param uMilliesInterval Milliseconds between the timer ticks. + * This is rounded up to the system granularity. + * @param pfnTimer Callback function which shall be scheduled for execution + * on every timer tick. + * @param pvUser User argument for the callback. + * @see RTTimerCreateEx, RTTimerStart, RTTimerStop, RTTimerChangeInterval, + * RTTimerDestroy, RTTimerGetSystemGranularity + */ +RTDECL(int) RTTimerCreate(PRTTIMER *ppTimer, unsigned uMilliesInterval, PFNRTTIMER pfnTimer, void *pvUser); + +/** + * Create a suspended timer. + * + * @returns iprt status code. + * @retval VERR_NOT_SUPPORTED if an unsupported flag was specfied. + * @retval VERR_CPU_NOT_FOUND if the specified CPU + * + * @param ppTimer Where to store the timer handle. + * @param u64NanoInterval The interval between timer ticks specified in nanoseconds if it's + * a recurring timer. This is rounded to the fit the system timer granularity. + * For one shot timers, pass 0. + * @param fFlags Timer flags. + * @param pfnTimer Callback function which shall be scheduled for execution + * on every timer tick. + * @param pvUser User argument for the callback. + * @see RTTimerStart, RTTimerStop, RTTimerChangeInterval, RTTimerDestroy, + * RTTimerGetSystemGranularity, RTTimerCanDoHighResolution + */ +RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser); + +/** @name RTTimerCreateEx flags + * @{ */ +/** Any CPU is fine. (Must be 0.) */ +#define RTTIMER_FLAGS_CPU_ANY UINT32_C(0) +/** One specific CPU */ +#define RTTIMER_FLAGS_CPU_SPECIFIC RT_BIT(16) +/** Omni timer, run on all online CPUs. + * @remarks The timer callback isn't necessarily running at the time same time on each CPU. */ +#define RTTIMER_FLAGS_CPU_ALL ( RTTIMER_FLAGS_CPU_MASK | RTTIMER_FLAGS_CPU_SPECIFIC ) +/** CPU mask. */ +#define RTTIMER_FLAGS_CPU_MASK UINT32_C(0xffff) +/** Desire a high resolution timer that works with RTTimerChangeInterval and + * isn't subject to RTTimerGetSystemGranularity rounding. + * @remarks This is quietly ignored if the feature isn't supported. */ +#define RTTIMER_FLAGS_HIGH_RES RT_BIT(17) +/** Convert a CPU set index (0-based) to RTTimerCreateEx flags. + * This will automatically OR in the RTTIMER_FLAGS_CPU_SPECIFIC flag. */ +#define RTTIMER_FLAGS_CPU(iCpu) ( (iCpu) | RTTIMER_FLAGS_CPU_SPECIFIC ) +/** Macro that validates the flags. */ +#define RTTIMER_FLAGS_ARE_VALID(fFlags) \ + ( !((fFlags) & ((fFlags) & RTTIMER_FLAGS_CPU_SPECIFIC ? ~UINT32_C(0x3ffff) : ~UINT32_C(0x30000))) ) +/** @} */ + +/** + * Stops and destroys a running timer. + * + * @returns iprt status code. + * @retval VERR_INVALID_CONTEXT if executing at the wrong IRQL (windows), PIL + * (solaris), or similar. Portable code does not destroy timers with + * preemption (or interrupts) disabled. + * @param pTimer Timer to stop and destroy. NULL is ok. + */ +RTDECL(int) RTTimerDestroy(PRTTIMER pTimer); + +/** + * Starts a suspended timer. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_TIMER_ACTIVE if the timer isn't suspended. + * @retval VERR_CPU_OFFLINE if the CPU the timer was created to run on is not + * online (this include the case where it's not present in the + * system). + * + * @param pTimer The timer to activate. + * @param u64First The RTTimeSystemNanoTS() for when the timer should start + * firing (relative). If 0 is specified, the timer will + * fire ASAP. + * @remarks When RTTimerCanDoHighResolution returns true, this API is + * callable with preemption disabled in ring-0. + * @see RTTimerStop + */ +RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First); + +/** + * Stops an active timer. + * + * @todo May return while the timer callback function is being services on + * some platforms (ring-0 Windows, ring-0 linux). This needs to be + * addressed at some point... + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_TIMER_SUSPENDED if the timer isn't active. + * @retval VERR_NOT_SUPPORTED if the IPRT implementation doesn't support + * stopping a timer. + * + * @param pTimer The timer to suspend. + * @remarks Can be called from the timer callback function to stop it. + * @see RTTimerStart + */ +RTDECL(int) RTTimerStop(PRTTIMER pTimer); + +/** + * Changes the interval of a periodic timer. + * + * If the timer is active, it is implementation dependent whether the change + * takes place immediately or after the next tick. To get defined behavior, + * stop the timer before calling this API. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_NOT_SUPPORTED if not supported. + * @retval VERR_INVALID_STATE if not a periodic timer. + * + * @param pTimer The timer to activate. + * @param u64NanoInterval The interval between timer ticks specified in + * nanoseconds. This is rounded to the fit the + * system timer granularity. + * @remarks Callable from the timer callback. Callable with preemption + * disabled in ring-0. + */ +RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval); + +/** + * Gets the (current) timer granularity of the system. + * + * @returns The timer granularity of the system in nanoseconds. + * @see RTTimerRequestSystemGranularity + */ +RTDECL(uint32_t) RTTimerGetSystemGranularity(void); + +/** + * Requests a specific system timer granularity. + * + * Successfull calls to this API must be coupled with the exact same number of + * calls to RTTimerReleaseSystemGranularity() in order to undo any changes made. + * + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the requested value isn't supported by the host platform + * or if the host platform doesn't support modifying the system timer granularity. + * @retval VERR_PERMISSION_DENIED if the caller doesn't have the necessary privilege to + * modify the system timer granularity. + * + * @param u32Request The requested system timer granularity in nanoseconds. + * @param pu32Granted Where to store the granted system granularity. This is the value + * that should be passed to RTTimerReleaseSystemGranularity(). It + * is what RTTimerGetSystemGranularity() would return immediately + * after the change was made. + * + * The value differ from the request in two ways; rounding and + * scale. Meaning if your request is for 10.000.000 you might + * be granted 10.000.055 or 1.000.000. + * @see RTTimerReleaseSystemGranularity, RTTimerGetSystemGranularity + */ +RTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted); + +/** + * Releases a system timer granularity grant acquired by RTTimerRequestSystemGranularity(). + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the host platform doesn't have any way of modifying + * the system timer granularity. + * @retval VERR_WRONG_ORDER if nobody call RTTimerRequestSystemGranularity() with the + * given grant value. + * @param u32Granted The granted system granularity. + * @see RTTimerRequestSystemGranularity + */ +RTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted); + +/** + * Checks if the system support high resolution timers. + * + * The kind of support we are checking for is the kind of dynamically + * reprogrammable timers employed by recent Solaris and Linux kernels. It also + * implies that we can specify microsecond (or even better maybe) intervals + * without getting into trouble. + * + * @returns true if supported, false it not. + * + * @remarks Returning true also means RTTimerChangeInterval must be implemented + * and RTTimerStart be callable with preemption disabled. + */ +RTDECL(bool) RTTimerCanDoHighResolution(void); + + +/** + * Timer callback function for low res timers. + * + * This is identical to FNRTTIMER except for the first parameter, so + * see FNRTTIMER for details. + * + * @param hTimerLR The low resolution timer handle. + * @param pvUser User argument. + * @param iTick The current timer tick. This is always 1 on the first + * callback after the timer was started. Will jump if we've + * skipped ticks when lagging behind. + */ +typedef DECLCALLBACKTYPE(void, FNRTTIMERLR,(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick)); +/** Pointer to FNRTTIMER() function. */ +typedef FNRTTIMERLR *PFNRTTIMERLR; + + +/** + * Create a recurring low resolution timer. + * + * @returns iprt status code. + * @param phTimerLR Where to store the timer handle. + * @param uMilliesInterval Milliseconds between the timer ticks, at least 100 ms. + * If higher resolution is required use the other API. + * @param pfnTimer Callback function which shall be scheduled for execution + * on every timer tick. + * @param pvUser User argument for the callback. + * @see RTTimerLRCreateEx, RTTimerLRDestroy, RTTimerLRStop + */ +RTDECL(int) RTTimerLRCreate(PRTTIMERLR phTimerLR, uint32_t uMilliesInterval, PFNRTTIMERLR pfnTimer, void *pvUser); + +/** + * Create a suspended low resolution timer. + * + * @returns iprt status code. + * @retval VERR_NOT_SUPPORTED if an unsupported flag was specfied. + * + * @param phTimerLR Where to store the timer handle. + * @param u64NanoInterval The interval between timer ticks specified in nanoseconds if it's + * a recurring timer, the minimum for is 100000000 ns. + * For one shot timers, pass 0. + * @param fFlags Timer flags. Same as RTTimerCreateEx. + * @param pfnTimer Callback function which shall be scheduled for execution + * on every timer tick. + * @param pvUser User argument for the callback. + * @see RTTimerLRStart, RTTimerLRStop, RTTimerLRDestroy + */ +RTDECL(int) RTTimerLRCreateEx(PRTTIMERLR phTimerLR, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMERLR pfnTimer, void *pvUser); + +/** + * Stops and destroys a running low resolution timer. + * + * @returns iprt status code. + * @param hTimerLR The low resolution timer to stop and destroy. + * NIL_RTTIMERLR is accepted. + */ +RTDECL(int) RTTimerLRDestroy(RTTIMERLR hTimerLR); + +/** + * Starts a low resolution timer. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_TIMER_ACTIVE if the timer isn't suspended. + * + * @param hTimerLR The low resolution timer to activate. + * @param u64First The RTTimeSystemNanoTS() for when the timer should start + * firing (relative), the minimum is 100000000 ns. + * If 0 is specified, the timer will fire ASAP. + * + * @see RTTimerLRStop + */ +RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First); + +/** + * Stops an active low resolution timer. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_TIMER_SUSPENDED if the timer isn't active. + * @retval VERR_NOT_SUPPORTED if the IPRT implementation doesn't support stopping a timer. + * + * @param hTimerLR The low resolution timer to suspend. + * + * @see RTTimerLRStart + */ +RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR); + +/** + * Changes the interval of a low resolution timer. + * + * If the timer is active, the next tick will occure immediately just like with + * RTTimerLRStart() when u64First parameter is zero. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_NOT_SUPPORTED if not supported. + * + * @param hTimerLR The low resolution timer to update. + * @param u64NanoInterval The interval between timer ticks specified in + * nanoseconds. This is rounded to the fit the + * system timer granularity. + * @remarks Callable from the timer callback. + */ +RTDECL(int) RTTimerLRChangeInterval(RTTIMERLR hTimerLR, uint64_t u64NanoInterval); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_timer_h */ diff --git a/include/iprt/tpm.h b/include/iprt/tpm.h new file mode 100644 index 00000000..04cd475e --- /dev/null +++ b/include/iprt/tpm.h @@ -0,0 +1,156 @@ +/** @file + * IPRT Trusted Platform Module API abstracting host specific APIs. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_tpm_h +#define IPRT_INCLUDED_tpm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_tpm IPRT Trusted Platform Module API + * @ingroup grp_rt + * + * This API provides a uniform way to access a Trusted Platform Module across all + * supported hosts. + * + * @{ + */ + + +/** + * TPM version. + */ +typedef enum RTTPMVERSION +{ + /** The usual invalid option. */ + RTTPMVERSION_INVALID = 0, + /** TPM conforms to version 1.2 of the TCG specification. */ + RTTPMVERSION_1_2, + /** TPM conforms to version 2.0 of the TCG specification. */ + RTTPMVERSION_2_0, + /** TPM version couldn't be acquired. */ + RTTPMVERSION_UNKNOWN, + /** Usual 32bit hack. */ + RTTPMVERSION_32BIT_HACK = 0x7fffffff +} RTTPMVERSION; +/** Pointer to a TPM version. */ +typedef RTTPMVERSION *PRTTPMVERSION; + +/** TPM handle. */ +typedef struct RTTPMINT *RTTPM; +/** Pointer to a TPM handle. */ +typedef RTTPM *PRTTPM; +/** NIL TPM handle value. */ +#define NIL_RTTPM ((RTTPM)0) + + +/** Default TPM of the host. */ +#define RTTPM_ID_DEFAULT UINT32_C(0xffffffff) + +/** + * Tries to open the given TPM returning a handle. + * + * @returns IPRT status code. + * @param phTpm Where to store the handle to the TPM module on success. + * @param idTpm The TPM to open, use RTTPM_ID_DEFAULT for the default TPM of the system. + */ +RTDECL(int) RTTpmOpen(PRTTPM phTpm, uint32_t idTpm); + + +/** + * Closes the given TPM handle freeing all allocated resources. + * + * @returns IPRT status code. + * @param hTpm Handle of the TPM to close. + */ +RTDECL(int) RTTpmClose(RTTPM hTpm); + + +/** + * Returns the version of the TPM for the given handle. + * + * @returns Version implemented by the TPM. + * @param hTpm Handle of the TPM. + */ +RTDECL(RTTPMVERSION) RTTpmGetVersion(RTTPM hTpm); + + +/** + * Returns the maximum locality supported by the given TPM. + * + * @returns Maximum locality supported (0-4). + * @param hTpm Handle of the TPM. + */ +RTDECL(uint32_t) RTTpmGetLocalityMax(RTTPM hTpm); + + +/** + * Cancels a currently executed request for the given TPM handle. + * + * @returns IPRT status code. + * @param hTpm Handle of the TPM. + */ +RTDECL(int) RTTpmReqCancel(RTTPM hTpm); + + +/** + * Executes the given request on the given TPM handle. + * + * @returns IPRT status code. + * @param hTpm Handle of the TPM. + * @param bLoc The locality to use (only 0 might be supported on some hosts). + * @param pvReq The request data. + * @param cbReq Size of the request in bytes. + * @param pvResp Where to store the response data. + * @param cbRespMax Size of the response buffer. + * @param pcbResp Where to store the actual size of the response, optional. + */ +RTDECL(int) RTTpmReqExec(RTTPM hTpm, uint8_t bLoc, const void *pvReq, size_t cbReq, + void *pvResp, size_t cbRespMax, size_t *pcbResp); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_tpm_h */ + diff --git a/include/iprt/trace.h b/include/iprt/trace.h new file mode 100644 index 00000000..32341d15 --- /dev/null +++ b/include/iprt/trace.h @@ -0,0 +1,228 @@ +/** @file + * IPRT - Tracing. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_trace_h +#define IPRT_INCLUDED_trace_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_trace RTTrace - Tracing + * @ingroup grp_rt + * + * The tracing facility is somewhat similar to a stripped down logger that + * outputs to a circular buffer. Part of the idea here is that it can the + * overhead is much smaller and that it can be done without involving any + * locking or other thing that could throw off timing. + * + * @{ + */ + + +#ifdef DOXYGEN_RUNNING +# define RTTRACE_DISABLED +# define RTTRACE_ENABLED +#endif + +/** @def RTTRACE_DISABLED + * Use this compile time define to disable all tracing macros. This trumps + * RTTRACE_ENABLED. + */ + +/** @def RTTRACE_ENABLED + * Use this compile time define to enable tracing when not in debug mode + */ + +/* + * Determine whether tracing is enabled and forcefully normalize the indicators. + */ +#if (defined(DEBUG) || defined(RTTRACE_ENABLED)) && !defined(RTTRACE_DISABLED) +# undef RTTRACE_DISABLED +# undef RTTRACE_ENABLED +# define RTTRACE_ENABLED +#else +# undef RTTRACE_DISABLED +# undef RTTRACE_ENABLED +# define RTTRACE_DISABLED +#endif + + +/** @name RTTRACEBUF_FLAGS_XXX - RTTraceBufCarve and RTTraceBufCreate flags. + * @{ */ +/** Free the memory block on release using RTMemFree(). */ +#define RTTRACEBUF_FLAGS_FREE_ME RT_BIT_32(0) +/** Whether the trace buffer is disabled or enabled. */ +#define RTTRACEBUF_FLAGS_DISABLED RT_BIT_32(RTTRACEBUF_FLAGS_DISABLED_BIT) +/** The bit number corresponding to the RTTRACEBUF_FLAGS_DISABLED mask. */ +#define RTTRACEBUF_FLAGS_DISABLED_BIT 1 +/** Mask of the valid flags. */ +#define RTTRACEBUF_FLAGS_MASK UINT32_C(0x00000003) +/** @} */ + + +RTDECL(int) RTTraceBufCreate(PRTTRACEBUF hTraceBuf, uint32_t cEntries, uint32_t cbEntry, uint32_t fFlags); +RTDECL(int) RTTraceBufCarve(PRTTRACEBUF hTraceBuf, uint32_t cEntries, uint32_t cbEntry, uint32_t fFlags, + void *pvBlock, size_t *pcbBlock); +RTDECL(uint32_t) RTTraceBufRetain(RTTRACEBUF hTraceBuf); +RTDECL(uint32_t) RTTraceBufRelease(RTTRACEBUF hTraceBuf); +RTDECL(int) RTTraceBufDumpToLog(RTTRACEBUF hTraceBuf); +RTDECL(int) RTTraceBufDumpToAssert(RTTRACEBUF hTraceBuf); + +/** + * Trace buffer callback for processing one entry. + * + * Used by RTTraceBufEnumEntries. + * + * @returns IPRT status code. Any status code but VINF_SUCCESS will abort the + * enumeration and be returned by RTTraceBufEnumEntries. + * @param hTraceBuf The trace buffer handle. + * @param iEntry The entry number. + * @param NanoTS The timestamp of the entry. + * @param idCpu The ID of the CPU which added the entry. + * @param pszMsg The message text. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTTRACEBUFCALLBACK,(RTTRACEBUF hTraceBuf, uint32_t iEntry, uint64_t NanoTS, + RTCPUID idCpu, const char *pszMsg, void *pvUser)); +/** Pointer to trace buffer enumeration callback function. */ +typedef FNRTTRACEBUFCALLBACK *PFNRTTRACEBUFCALLBACK; + +/** + * Enumerates the used trace buffer entries, calling @a pfnCallback for each. + * + * @returns IPRT status code. Should the callback (@a pfnCallback) return + * anything other than VINF_SUCCESS, then the enumeration will be + * aborted and the status code will be returned by this function. + * @retval VINF_SUCCESS + * @retval VERR_INVALID_HANDLE + * @retval VERR_INVALID_PARAMETER + * @retval VERR_INVALID_POINTER + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + * @param pfnCallback The callback to call for each entry. + * @param pvUser The user argument for the callback. + */ +RTDECL(int) RTTraceBufEnumEntries(RTTRACEBUF hTraceBuf, PFNRTTRACEBUFCALLBACK pfnCallback, void *pvUser); + +/** + * Gets the entry size used by the specified trace buffer. + * + * @returns The size on success, 0 if the handle is invalid. + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + */ +RTDECL(uint32_t) RTTraceBufGetEntrySize(RTTRACEBUF hTraceBuf); + +/** + * Gets the number of entries in the specified trace buffer. + * + * @returns The entry count on success, 0 if the handle is invalid. + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + */ +RTDECL(uint32_t) RTTraceBufGetEntryCount(RTTRACEBUF hTraceBuf); + + +/** + * Disables tracing. + * + * @returns @c true if tracing was enabled prior to this call, @c false if + * disabled already. + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + */ +RTDECL(bool) RTTraceBufDisable(RTTRACEBUF hTraceBuf); + +/** + * Enables tracing. + * + * @returns @c true if tracing was enabled prior to this call, @c false if + * disabled already. + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + */ +RTDECL(bool) RTTraceBufEnable(RTTRACEBUF hTraceBuf); + + +RTDECL(int) RTTraceBufAddMsg( RTTRACEBUF hTraceBuf, const char *pszMsg); +RTDECL(int) RTTraceBufAddMsgF( RTTRACEBUF hTraceBuf, const char *pszMsgFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); +RTDECL(int) RTTraceBufAddMsgV( RTTRACEBUF hTraceBuf, const char *pszMsgFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); +RTDECL(int) RTTraceBufAddMsgEx( RTTRACEBUF hTraceBuf, const char *pszMsg, size_t cbMaxMsg); + +RTDECL(int) RTTraceBufAddPos( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL); +RTDECL(int) RTTraceBufAddPosMsg( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsg); +RTDECL(int) RTTraceBufAddPosMsgEx( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsg, size_t cbMaxMsg); +RTDECL(int) RTTraceBufAddPosMsgF( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsgFmt, ...) RT_IPRT_FORMAT_ATTR(5, 6); +RTDECL(int) RTTraceBufAddPosMsgV( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsgFmt, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + + +RTDECL(int) RTTraceSetDefaultBuf(RTTRACEBUF hTraceBuf); +RTDECL(RTTRACEBUF) RTTraceGetDefaultBuf(void); + + +/** @def RTTRACE_BUF + * The trace buffer used by the macros. + */ +#ifndef RTTRACE_BUF +# define RTTRACE_BUF NULL +#endif + +/** + * Record the current source position. + */ +#ifdef RTTRACE_ENABLED +# define RTTRACE_POS() do { RTTraceBufAddPos(RTTRACE_BUF, RT_SRC_POS); } while (0) +#else +# define RTTRACE_POS() do { } while (0) +#endif + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_trace_h */ + diff --git a/include/iprt/tracelog.h b/include/iprt/tracelog.h new file mode 100644 index 00000000..61ae41c0 --- /dev/null +++ b/include/iprt/tracelog.h @@ -0,0 +1,706 @@ +/** @file + * IPRT - Binary trace log API. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_tracelog_h +#define IPRT_INCLUDED_tracelog_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_tracelog RTTraceLog - Binary trace log API + * @ingroup grp_rt + * @{ + */ + +/** + * Trace log item type. + */ +typedef enum RTTRACELOGTYPE +{ + /** Invalid first value. */ + RTTRACELOGTYPE_INVALID = 0, + /** Boolean item type. */ + RTTRACELOGTYPE_BOOL, + /** Unsigned 8bit integer type. */ + RTTRACELOGTYPE_UINT8, + /** Signed 8bit integer type. */ + RTTRACELOGTYPE_INT8, + /** Unsigned 16bit integer type. */ + RTTRACELOGTYPE_UINT16, + /** Signed 16bit integer type. */ + RTTRACELOGTYPE_INT16, + /** Unsigned 32bit integer type. */ + RTTRACELOGTYPE_UINT32, + /** Signed 32bit integer type. */ + RTTRACELOGTYPE_INT32, + /** Unsigned 64bit integer type. */ + RTTRACELOGTYPE_UINT64, + /** Signed 64bit integer type. */ + RTTRACELOGTYPE_INT64, + /** 32bit floating point type. */ + RTTRACELOGTYPE_FLOAT32, + /** 64bit floating point type. */ + RTTRACELOGTYPE_FLOAT64, + /** Raw binary data type. */ + RTTRACELOGTYPE_RAWDATA, + /** Pointer data type. */ + RTTRACELOGTYPE_POINTER, + /** size_t data type. */ + RTTRACELOGTYPE_SIZE, + /** 32-bit hack. */ + RTTRACELOGTYPE_32BIT_HACK = 0x7fffffff +} RTTRACELOGTYPE; +/** Pointer to a trace log item type. */ +typedef RTTRACELOGTYPE *PRTTRACELOGTYPE; +/** Pointer to a const trace log item type. */ +typedef const RTTRACELOGTYPE *PCRTTRACELOGTYPE; + + +/** + * Trace log event severity. + */ +typedef enum RTTRACELOGEVTSEVERITY +{ + /** Invalid severity. */ + RTTRACELOGEVTSEVERITY_INVALID = 0, + /** Informational event. */ + RTTRACELOGEVTSEVERITY_INFO, + /** Warning event. */ + RTTRACELOGEVTSEVERITY_WARNING, + /** Error event. */ + RTTRACELOGEVTSEVERITY_ERROR, + /** Fatal event. */ + RTTRACELOGEVTSEVERITY_FATAL, + /** Debug event. */ + RTTRACELOGEVTSEVERITY_DEBUG, + /** 32bit hack.*/ + RTTRACELOGEVTSEVERITY_32BIT_HACK = 0x7fffffff +} RTTRACELOGEVTSEVERITY; +/** Pointer to a event severity class. */ +typedef RTTRACELOGEVTSEVERITY *PRTTRACELOGEVTSEVERITY; +/** Pointer to a const event severiy class. */ +typedef RTTRACELOGEVTSEVERITY *PCRTTRACELOGEVTSEVERITY; + + +/** + * Trace log reader event. + */ +typedef enum RTTRACELOGRDRPOLLEVT +{ + /** Invalid event. */ + RTTRACELOGRDRPOLLEVT_INVALID = 0, + /** The header was received and valid. */ + RTTRACELOGRDRPOLLEVT_HDR_RECVD, + /** Event data was fetched. */ + RTTRACELOGRDRPOLLEVT_TRACE_EVENT_RECVD, + /** 32bit hack. */ + RTTRACELOGRDRPOLLEVT_32BIT_HACK = 0x7fffffff +} RTTRACELOGRDRPOLLEVT; +/** Pointer to a trace log reader event. */ +typedef RTTRACELOGRDRPOLLEVT *PRTTRACELOGRDRPOLLEVT; + + +/** + * Trace log event item descriptor. + */ +typedef struct RTTRACELOGEVTITEMDESC +{ + /** Event item name. */ + const char *pszName; + /** Event item description. */ + const char *pszDesc; + /** Event item type. */ + RTTRACELOGTYPE enmType; + /** The size of the raw data if static for the item, + * 0 otherwise (and given when the event is logged). + * Only valid for the RTTRACELOGTYPE_RAWDATA type, + * ignored otherwise. */ + size_t cbRawData; +} RTTRACELOGEVTITEMDESC; +/** Pointer to an trace log event item descriptor. */ +typedef RTTRACELOGEVTITEMDESC *PRTTRACELOGEVTITEMDESC; +/** Pointer to a const trace log event item descriptor. */ +typedef const RTTRACELOGEVTITEMDESC *PCRTTRACELOGEVTITEMDESC; +/** Pointer to a trace log event item descriptor pointer. */ +typedef PRTTRACELOGEVTITEMDESC *PPRTTRACELOGEVTITEMDESC; +/** Pointer to a const trace log event item descriptor pointer. */ +typedef PCRTTRACELOGEVTITEMDESC *PPCRTTRACELOGEVTITEMDESC; + + +/** + * Trace log event descriptor. + */ +typedef struct RTTRACELOGEVTDESC +{ + /** Event identifier. */ + const char *pszId; + /** Event description. */ + const char *pszDesc; + /** Severity class of the event. */ + RTTRACELOGEVTSEVERITY enmSeverity; + /** Number of items recorded for an event. */ + uint32_t cEvtItems; + /** Pointer to array of event item descriptors. */ + PCRTTRACELOGEVTITEMDESC paEvtItemDesc; +} RTTRACELOGEVTDESC; +/** Pointer to a trace log event descriptor. */ +typedef RTTRACELOGEVTDESC *PRTTRACELOGEVTDESC; +/** Pointer to a const trace log event descriptor. */ +typedef const RTTRACELOGEVTDESC *PCRTTRACELOGEVTDESC; + + +/** + * Trace log event item value. + */ +typedef struct RTTRACELOGEVTVAL +{ + /** Pointer to the corresponding event item descriptor. */ + PCRTTRACELOGEVTITEMDESC pItemDesc; + /** Value union. */ + union + { + bool f; + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + uint64_t u64; + int64_t i64; + uint64_t sz; + uint64_t uPtr; + float f32; + double f64; + struct + { + size_t cb; + const uint8_t *pb; + } RawData; + } u; +} RTTRACELOGEVTVAL; +/** Pointer to trace log event item value. */ +typedef RTTRACELOGEVTVAL *PRTTRACELOGEVTVAL; +/** Pointer to a const trace log event item value. */ +typedef const RTTRACELOGEVTVAL *PCRTTRACELOGEVTVAL; + + +/** + * Item mapping descriptor. + */ +typedef struct RTTRACELOGRDRMAPITEM +{ + /** The item name. */ + const char *pszName; + /** The value type to map the item to. */ + RTTRACELOGTYPE enmType; +} RTTRACELOGRDRMAPITEM; +/** Pointer to a mapping item descriptor. */ +typedef RTTRACELOGRDRMAPITEM *PRTTRACELOGRDRMAPITEM; +/** Pointer to a const mapping item descriptor. */ +typedef const RTTRACELOGRDRMAPITEM *PCRTTRACELOGRDRMAPITEM; + + +/** + * Event item to value mapping descriptor for RTTraceLogRdrEvtMapToStruct(). + */ +typedef struct RTTRACELOGRDRMAPDESC +{ + /** The event ID this mapping describes. */ + const char *pszEvtId; + /** Number of event items to extract. */ + uint32_t cEvtItems; + /** Pointer to the event items to extract (in the given order). */ + PCRTTRACELOGRDRMAPITEM paMapItems; +} RTTRACELOGRDRMAPDESC; +/** Pointer to a event mapping descriptor. */ +typedef RTTRACELOGRDRMAPDESC *PRTTRACELOGRDRMAPDESC; +/** Pointer to a const event mapping descriptor. */ +typedef const RTTRACELOGRDRMAPDESC *PCRTTRACELOGRDRMAPDESC; + + +/** + * Header for an event mapped to a binary. + */ +typedef struct RTTRACELOGRDREVTHDR +{ + /** The mapping descriptor this event was mapped to. */ + PCRTTRACELOGRDRMAPDESC pEvtMapDesc; + /** The event descriptor as extracted from the event log. */ + PCRTTRACELOGEVTDESC pEvtDesc; + /** Sequence number of the descriptor. */ + uint64_t idSeqNo; + /** The timestamp of the event. */ + uint64_t tsEvt; + /** Pointer to the event data items. */ + PCRTTRACELOGEVTVAL paEvtItems; +} RTTRACELOGRDREVTHDR; +/** Pointer to an event header. */ +typedef RTTRACELOGRDREVTHDR *PRTTRACELOGRDREVTHDR; +/** Pointer to a const event header. */ +typedef const RTTRACELOGRDREVTHDR *PCRTTRACELOGRDREVTHDR; + + +/** Event group ID. */ +typedef uint64_t RTTRACELOGEVTGRPID; +/** Pointer to the event group ID. */ +typedef RTTRACELOGEVTGRPID *PRTTRACELOGEVTGRPID; +/** Trace log event handle. */ +typedef uint64_t RTRACELOGEVT; +/** Pointer to a trace log event handle. */ +typedef RTRACELOGEVT *PRTRACELOGEVT; +/** Trace log writer handle. */ +typedef struct RTTRACELOGWRINT *RTTRACELOGWR; +/** Pointer to a trace log writer handle. */ +typedef RTTRACELOGWR *PRTTRACELOGWR; +/** NIL trace log writer handle value. */ +#define NIL_RTTRACELOGWR ((RTTRACELOGWR)0) +/** Trace log reader handle. */ +typedef struct RTTRACELOGRDRINT *RTTRACELOGRDR; +/** Pointer to a trace log reader handle. */ +typedef RTTRACELOGRDR *PRTTRACELOGRDR; +/** NIL trace log reader handle value. */ +#define NIL_RTTRACELOGRDR ((RTTRACELOGRDR)0) +/** Trace log reader iterator handle. */ +typedef struct RTTRACELOGRDRITINT *RTTRACELOGRDRIT; +/** Pointer to a trace log reader iterator handle. */ +typedef RTTRACELOGRDRIT *PRTTRACELOGRDRIT; +/** NIL trace log reader iterator handle. */ +#define NIL_RTTRACELOGRDRIT ((RTTRACELOGRDRIT)0) +/** Trace log reader event handle. */ +typedef struct RTTRACELOGRDREVTINT *RTTRACELOGRDREVT; +/** Pointer to a trace log reader event handle. */ +typedef RTTRACELOGRDREVT *PRTTRACELOGRDREVT; +/** NIL trace log reader event handle. */ +#define NIL_RTTRACELOGRDREVT ((RTTRACELOGRDREVT)0) + +/** A new grouped event is started. */ +#define RTTRACELOG_WR_ADD_EVT_F_GRP_START RT_BIT_32(0) +/** A grouped event is finished. */ +#define RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH RT_BIT_32(1) + +/** + * Callback to stream out data from the trace log writer. + * + * @returns IPRT status code. + * @param pvUser Opaque user data passed on trace log writer creation. + * @param pvBuf Pointer to the buffer to stream out. + * @param cbBuf Number of bytes to stream. + * @param pcbWritten Where to store the number of bytes written on success, optional. + */ +typedef DECLCALLBACKTYPE(int, FNRTTRACELOGWRSTREAM,(void *pvUser, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)); +/** Pointer to a writer stream callback. */ +typedef FNRTTRACELOGWRSTREAM *PFNRTTRACELOGWRSTREAM; + + +/** + * Callback to stream int data to the trace log reader. + * + * @returns IPRT status code. + * @retval VERR_EOF if the stream reached the end. + * @retval VERR_INTERRUPTED if waiting for something to arrive was interrupted. + * @retval VERR_TIMEOUT if the timeout was reached. + * @param pvUser Opaque user data passed on trace log reader creation. + * @param pvBuf Where to store the read data. + * @param cbBuf Number of bytes the buffer can hold. + * @param pcbRead Where to store the number of bytes read on success. + * @param cMsTimeout How long to wait for something to arrive + */ +typedef DECLCALLBACKTYPE(int, FNRTTRACELOGRDRSTREAM,(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbRead, + RTMSINTERVAL cMsTimeout)); +/** Pointer to a writer stream callback. */ +typedef FNRTTRACELOGRDRSTREAM *PFNRTTRACELOGRDRSTREAM; + + +/** + * Callback to close the stream. + * + * @returns IPRT status code. + * @param pvUser Opaque user data passed on trace log writer creation. + */ +typedef DECLCALLBACKTYPE(int, FNRTTRACELOGSTREAMCLOSE,(void *pvUser)); +/** Pointer to a stream close callback. */ +typedef FNRTTRACELOGSTREAMCLOSE *PFNRTTRACELOGSTREAMCLOSE; + + +/** + * Creates a new trace log writer. + * + * @returns IPRT status code. + * @param phTraceLogWr Where to store the handle to the trace log writer on success. + * @param pszDesc Optional description to store in the header. + * @param pfnStreamOut The callback to use for streaming the trace log data. + * @param pfnStreamClose The callback to use for closing the stream. + * @param pvUser Opaque user data to pass to the streaming callback. + */ +RTDECL(int) RTTraceLogWrCreate(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + PFNRTTRACELOGWRSTREAM pfnStreamOut, + PFNRTTRACELOGSTREAMCLOSE pfnStreamClose, void *pvUser); + + +/** + * Creates a new trace log writer streaming data to the given file. + * + * @returns IPRT status code. + * @param phTraceLogWr Where to store the handle to the trace log writer on success. + * @param pszDesc Optional description to store in the header. + * @param pszFilename The filename to stream the data to. + */ +RTDECL(int) RTTraceLogWrCreateFile(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + const char *pszFilename); + + +/** + * Creates a new TCP server style trace log writer waiting for the other end to connect to it. + * + * @returns IPRT status code. + * @param phTraceLogWr Where to store the handle to the trace log writer on success. + * @param pszDesc Optional description to store in the header. + * @param pszListen The address to listen on, NULL to listen on all interfaces. + * @param uPort The port to listen on. + * + * @note The writer will block here until a client has connected. + */ +RTDECL(int) RTTraceLogWrCreateTcpServer(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + const char *pszListen, unsigned uPort); + + +/** + * Creates a new TCP client style trace log writer connecting to the other end. + * + * @returns IPRT status code. + * @param phTraceLogWr Where to store the handle to the trace log writer on success. + * @param pszDesc Optional description to store in the header. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * + * @note An error is returned if no connection can be established. + */ +RTDECL(int) RTTraceLogWrCreateTcpClient(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + const char *pszAddress, unsigned uPort); + + +/** + * Destroys the given trace log writer instance. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + */ +RTDECL(int) RTTraceLogWrDestroy(RTTRACELOGWR hTraceLogWr); + + +/** + * Adds a given event structure descriptor to the given trace log writer instance + * (for prepopulation). + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event structure descriptor to add. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrAddEvtDesc(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc); + + +/** + * Adds a new event to the trace log. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event descriptor to use for formatting. + * @param fFlags Flags to use for this event.y + * @param uGrpId A unique group ID for grouped events. + * @param uParentGrpId A parent group ID this event originated from. + * @param pvEvtData Pointer to the raw event data. + * @param pacbRawData Pointer to the array of size indicators for non static raw data in the event data stream. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrEvtAdd(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, + const void *pvEvtData, size_t *pacbRawData); + + +/** + * Adds a new event to the trace log. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event descriptor used for formatting the data. + * @param fFlags Flags to use for this event. + * @param uGrpId A unique group ID for grouped events. + * @param uParentGrpId A parent group ID this event originated from. + * @param pSgBufEvtData S/G buffer holding the raw event data. + * @param pacbRawData Pointer to the array of size indicators for non static raw data in the event data stream. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrEvtAddSg(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, + PRTSGBUF *pSgBufEvtData, size_t *pacbRawData); + + +/** + * Adds a new event to the trace log - list variant. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event descriptor used for formatting the data. + * @param fFlags Flags to use for this event. + * @param uGrpId A unique group ID for grouped events. + * @param uParentGrpId A parent group ID this event originated from. + * @param va The event data as single items as described by the descriptor. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrEvtAddLV(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, va_list va); + + +/** + * Adds a new event to the trace log - list variant. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event descriptor used for formatting the data. + * @param fFlags Flags to use for this event. + * @param uGrpId A unique group ID for grouped events. + * @param uParentGrpId A parent group ID this event originated from. + * @param ... The event data as single items as described by the descriptor. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrEvtAddL(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, ...); + + +/** + * Creates a new trace log reader instance. + * + * @returns IPRT status code. + * @param phTraceLogRdr Where to store the handle to the trace log reader instance on success. + * @param pfnStreamIn Callback to stream the data into the reader. + * @param pfnStreamClose The callback to use for closing the stream. + * @param pvUser Opaque user data passed to the stream callback. + */ +RTDECL(int) RTTraceLogRdrCreate(PRTTRACELOGRDR phTraceLogRdr, PFNRTTRACELOGRDRSTREAM pfnStreamIn, + PFNRTTRACELOGSTREAMCLOSE pfnStreamClose, void *pvUser); + + +/** + * Creates a new trace log reader for the given file. + * + * @returns IPRT status code. + * @param phTraceLogRdr Where to store the handle to the trace log reader instance on success. + * @param pszFilename The file to read the trace log data from. + */ +RTDECL(int) RTTraceLogRdrCreateFromFile(PRTTRACELOGRDR phTraceLogRdr, const char *pszFilename); + + +/** + * Destroys the given trace log reader instance. + * + * @returns IPRT status code. + * @param hTraceLogRdr The trace log reader instance handle. + */ +RTDECL(int) RTTraceLogRdrDestroy(RTTRACELOGRDR hTraceLogRdr); + + +/** + * Polls for an event on the trace log reader instance. + * + * @returns IPRT status code. + * @retval VERR_TIMEOUT if the timeout was reached. + * @retval VERR_INTERRUPTED if the poll was interrupted. + * @param hTraceLogRdr The trace log reader instance handle. + * @param penmEvt Where to store the event identifier. + * @param cMsTimeout How long to poll for an event. + */ +RTDECL(int) RTTraceLogRdrEvtPoll(RTTRACELOGRDR hTraceLogRdr, RTTRACELOGRDRPOLLEVT *penmEvt, RTMSINTERVAL cMsTimeout); + +/** + * Queries the last received event from the trace log read instance. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no event was received so far. + * @param hTraceLogRdr The trace log reader instance handle. + * @param phRdrEvt Where to store the event handle on success. + */ +RTDECL(int) RTTraceLogRdrQueryLastEvt(RTTRACELOGRDR hTraceLogRdr, PRTTRACELOGRDREVT phRdrEvt); + +/** + * Queries a new iterator for walking received events. + * + * @returns IPRT status code + * @param hTraceLogRdr The trace log reader instance handle. + * @param phIt Where to store the handle to iterator on success. + */ +RTDECL(int) RTTraceLogRdrQueryIterator(RTTRACELOGRDR hTraceLogRdr, PRTTRACELOGRDRIT phIt); + + +/** + * Extracts the given number of events from the given trace log reader instance returning + * and array of events with the values filled in from the mapping descriptor. + * + * @returns IPRT status code. + * @param hTraceLogRdr The trace log reader instance handle. + * @param fFlags Flags controlling the behavior, MBZ. + * @param cEvts Number of events to extract, UINT32_MAX to map all immediately available events. + * @param paMapDesc Pointer to an array of mapping descriptors describing how to map events. + * @param ppaEvtHdr Where to return the pointer to the allocated array of event headers on success. + * @param pcEvts Where to store the returned number of events on success. + */ +RTDECL(int) RTTraceLogRdrEvtMapToStruct(RTTRACELOGRDR hTraceLogRdr, uint32_t fFlags, uint32_t cEvts, + PCRTTRACELOGRDRMAPDESC paMapDesc, PCRTTRACELOGRDREVTHDR *ppaEvtHdr, + uint32_t *pcEvts); + + +/** + * Frees all resources of the given array of event headers as allocated by RTTraceLogRdrEvtMapToStruct(). + * + * @returns nothing. + * @param paEvtHdr Pointer to the array of events as returned by RTTraceLogRdrEvtMapToStruct(). + * @param cEvts Number of events as returned by RTTraceLogRdrEvtMapToStruct(). + */ +RTDECL(void) RTTraceLogRdrEvtMapFree(PCRTTRACELOGRDREVTHDR paEvtHdr, uint32_t cEvts); + + +/** + * Frees a previously created iterator. + * + * @returns nothing. + * @param hIt The iterator handle to free. + */ +RTDECL(void) RTTraceLogRdrIteratorFree(RTTRACELOGRDRIT hIt); + + +/** + * Advances to the next event. + * + * @returns IPRT status code + * @retval VERR_TRACELOG_READER_ITERATOR_END if the iterator reached the end. + * @param hIt The iterator handle. + */ +RTDECL(int) RTTraceLogRdrIteratorNext(RTTRACELOGRDRIT hIt); + + +/** + * Queries the event at the current iterator position. + * + * @returns IPRT status code. + * @param hIt The iterator handle. + * @param phRdrEvt Where to store the event handle on success. + */ +RTDECL(int) RTTraceLogRdrIteratorQueryEvent(RTTRACELOGRDRIT hIt, PRTTRACELOGRDREVT phRdrEvt); + + +/** + * Returns the sequence number of the given event. + * + * @returns Sequence number of the given event. + * @param hRdrEvt The reader event handle. + */ +RTDECL(uint64_t) RTTraceLogRdrEvtGetSeqNo(RTTRACELOGRDREVT hRdrEvt); + + +/** + * Gets the timestamp of the given event. + * + * @returns Timestamp of the given event. + * @param hRdrEvt The reader event handle. + */ +RTDECL(uint64_t) RTTraceLogRdrEvtGetTs(RTTRACELOGRDREVT hRdrEvt); + + +/** + * Returns whether the given event is part of an event group. + * + * @returns Flag whether the event is part of a group. + * @param hRdrEvt The reader event handle. + */ +RTDECL(bool) RTTraceLogRdrEvtIsGrouped(RTTRACELOGRDREVT hRdrEvt); + + +/** + * Returns the event descriptor associated with the given event. + * + * @returns The trace log event descriptor associated with this event. + * @param hRdrEvt The reader event handle. + */ +RTDECL(PCRTTRACELOGEVTDESC) RTTraceLogRdrEvtGetDesc(RTTRACELOGRDREVT hRdrEvt); + + +/** + * Queries an event item by its name returning the value in the supplied buffer. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the item name was not found for the given event. + * @param hRdrEvt The reader event handle. + * @param pszName The item name to query. + * @param pVal The item value buffer to initialise. + */ +RTDECL(int) RTTraceLogRdrEvtQueryVal(RTTRACELOGRDREVT hRdrEvt, const char *pszName, PRTTRACELOGEVTVAL pVal); + + +/** + * Fills the given value array using the values from the given event. + * + * @returns IPRT status code + * @param hRdrEvt The reader event handle. + * @param idxItemStart The index of the item to start filling the value in. + * @param paVals Array of values to fill. + * @param cVals Number of values the array is able to hold. + * @param pcVals Where to store the number of values filled on success. + */ +RTDECL(int) RTTraceLogRdrEvtFillVals(RTTRACELOGRDREVT hRdrEvt, unsigned idxItemStart, PRTTRACELOGEVTVAL paVals, + unsigned cVals, unsigned *pcVals); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_tracelog_h */ + diff --git a/include/iprt/types.h b/include/iprt/types.h new file mode 100644 index 00000000..366c19a6 --- /dev/null +++ b/include/iprt/types.h @@ -0,0 +1,3890 @@ +/** @file + * IPRT - Types. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_types_h +#define IPRT_INCLUDED_types_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +/* + * Include standard C types. + */ +#if !defined(IPRT_NO_CRT) && !defined(DOXYGEN_RUNNING) + +# if defined(IN_XF86_MODULE) && !defined(NO_ANSIC) + /* + * Kludge for xfree86 modules: size_t and other types are redefined. + */ +RT_C_DECLS_BEGIN +# include "xf86_ansic.h" +# undef NULL +RT_C_DECLS_END + +# elif defined(RT_OS_DARWIN) && defined(KERNEL) + /* + * Kludge for the darwin kernel: + * stddef.h is missing IIRC. + */ +# ifndef _PTRDIFF_T +# define _PTRDIFF_T + typedef __darwin_ptrdiff_t ptrdiff_t; +# endif +# include + +# elif defined(RT_OS_FREEBSD) && defined(_KERNEL) +# include +# undef PVM +# if __FreeBSD_version < 1200000 + /* + * Kludge for the FreeBSD kernel: + * stddef.h and sys/types.h have slightly different offsetof definitions + * when compiling in kernel mode. This is just to make GCC shut up. + */ +# ifndef _STDDEF_H_ +# undef offsetof +# endif +# include +# ifndef _SYS_TYPES_H_ +# undef offsetof +# endif +# include +# ifndef offsetof +# error "offsetof is not defined!" +# endif +# else +# include +# include +# endif + +# elif defined(RT_OS_FREEBSD) && HC_ARCH_BITS == 64 && defined(RT_ARCH_X86) + /* + * Kludge for compiling 32-bit code on a 64-bit FreeBSD: + * FreeBSD declares uint64_t and int64_t wrong (long unsigned and long int + * though they need to be long long unsigned and long long int). These + * defines conflict with our declaration in stdint.h. Adding the defines + * below omits the definitions in the system header. + */ +# include +# define _UINT64_T_DECLARED +# define _INT64_T_DECLARED +# define _UINTPTR_T_DECLARED +# define _INTPTR_T_DECLARED +# include + +# elif defined(RT_OS_NETBSD) && defined(_KERNEL) + +# include + + /* + * Kludge for NetBSD-6.x where the definition of bool in + * does not check for C++. + */ +# if defined(__cplusplus) && defined(bool) +# undef bool +# undef true +# undef false +# endif + + /* + * Kludge for NetBSD-6.x where does not define + * ptrdiff_t for the kernel code. Note that we don't worry about + * redefinition in since that header doesn't exist for + * _KERNEL code. + */ +# ifdef _BSD_PTRDIFF_T_ + typedef _BSD_PTRDIFF_T_ ptrdiff_t; +# endif + +# elif defined(RT_OS_LINUX) && defined(__KERNEL__) + /* + * Kludge for the linux kernel: + * 1. sys/types.h doesn't mix with the kernel. + * 2. Starting with 2.6.19, linux/types.h typedefs bool and linux/stddef.h + * declares false and true as enum values. + * 3. Starting with 2.6.24, linux/types.h typedefs uintptr_t. + * We work around these issues here and nowhere else. + */ +# if defined(__cplusplus) + typedef bool _Bool; +# endif +# define bool linux_bool +# define true linux_true +# define false linux_false +# define uintptr_t linux_uintptr_t +# include +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) +# include +# else +# ifndef AUTOCONF_INCLUDED +# include +# endif +# endif +# include +# if defined(__cplusplus) + /* + * Starting with 3.3, appends 'notrace' (which + * expands to __attribute__((no_instrument_function))) to inline, + * __inline and __inline__. Revert that. + */ +# undef inline +# define inline inline +# undef __inline__ +# define __inline__ __inline__ +# undef __inline +# define __inline __inline +# endif +# include +# include + /* + * Starting with 3.4, defines NULL as '((void*)0)' which + * does not work for C++ code. + */ +# undef NULL +# undef uintptr_t +# ifdef __GNUC__ +# if !RT_GNUC_PREREQ(4, 1) + /* + * does + * #define __inline__ __inline__ __attribute__((always_inline)) + * in some older Linux kernels. Forcing inlining will fail for some RTStrA* + * functions with gcc <= 4.0 due to passing variable argument lists. + */ +# undef __inline__ +# define __inline__ __inline__ +# endif +# endif +# undef false +# undef true +# undef bool + +# elif !defined(DOXYGEN_RUNNING) && RT_MSC_PREREQ(RT_MSC_VER_VC140) && defined(RT_OS_AGNOSTIC) + /* Try avoid needing the UCRT just for stddef.h and sys/types.h. */ + /** @todo refine the RT_OS_AGNOSTIC test? */ +# include + +# else +# include +# include +# endif + + +/* Define any types missing from sys/types.h on Windows and OS/2. */ +# ifdef _MSC_VER +# undef ssize_t +typedef intptr_t ssize_t; +# endif +# if defined(RT_OS_OS2) && (defined(__IBMC__) || defined(__IBMCPP__)) +typedef signed long ssize_t; +# endif + +#else /* no crt */ +# include +#endif /* no crt */ + + + +/** @def NULL + * NULL pointer. + */ +#ifndef NULL +# ifdef __cplusplus +# define NULL 0 +# else +# define NULL ((void*)0) +# endif +#endif + + + +/** @defgroup grp_rt_types IPRT Base Types + * @{ + */ + +/* define wchar_t, we don't wanna include all the wcsstuff to get this. */ +#ifdef _MSC_VER +# ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +# define _WCHAR_T_DEFINED +# endif +#endif +#ifdef __GNUC__ +/** @todo wchar_t on GNUC */ +#endif + +/* + * C doesn't have bool, nor does VisualAge for C++ v3.08. + */ +#if !defined(__cplusplus) || (defined(__IBMCPP__) && defined(RT_OS_OS2)) +# if defined(__GNUC__) +# if defined(RT_OS_LINUX) && __GNUC__ < 3 +typedef uint8_t bool; +# elif defined(RT_OS_FREEBSD) +# ifndef __bool_true_false_are_defined +typedef _Bool bool; +# endif +# elif defined(RT_OS_NETBSD) +# if !defined(_KERNEL) + /* + * For the kernel code is not available, but bool is + * provided by included above. + */ +# include + + /* + * ... but the story doesn't end here. The C standard says that + * defines preprocessor macro "bool" that expands to + * "_Bool", but adds that a program may undefine/redefine it + * (this is 7.16 in C99 and 7.18 in C11). We have to play this + * game here because X11 code uses "bool" as a struct member name + * - so undefine "bool" and provide it as a typedef instead. We + * still keep #include so that any code that might + * include it later doesn't mess things up. + */ +# undef bool + typedef _Bool bool; +# endif +# else +# undef bool /* see above netbsd explanation */ +typedef _Bool bool; +# endif +# else +# if RT_MSC_PREREQ(RT_MSC_VER_VC120) +# include +# else +typedef unsigned char bool; +# endif +# endif +# ifndef true +# define true (1) +# endif +# ifndef false +# define false (0) +# endif +#endif + + +/** + * 128-bit unsigned integer. + */ +#ifdef RT_COMPILER_WITH_128BIT_INT_TYPES +typedef __uint128_t uint128_t; +#else +typedef struct uint128_s +{ +# ifdef RT_BIG_ENDIAN + uint64_t Hi; + uint64_t Lo; +# else + uint64_t Lo; + uint64_t Hi; +# endif +} uint128_t; +#endif + + +/** + * 128-bit signed integer. + */ +#ifdef RT_COMPILER_WITH_128BIT_INT_TYPES +typedef __int128_t int128_t; +#else +typedef struct int128_s +{ +# ifdef RT_BIG_ENDIAN + int64_t Hi; + uint64_t Lo; +# else + uint64_t Lo; + int64_t Hi; +# endif +} int128_t; +#endif + + +/** + * 16-bit unsigned integer union. + */ +typedef union RTUINT16U +{ + /** natural view. */ + uint16_t u; + + /** 16-bit hi/lo view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint8_t Hi; + uint8_t Lo; +#else + uint8_t Lo; + uint8_t Hi; +#endif + } s; + + /** Unsigned 16-bit view. */ + uint16_t au16[1]; + /** Unsigned 8-bit view. */ + uint8_t au8[2]; + + /** Signed 16-bit view. */ + int16_t ai16[1]; + /** Signed 8-bit view. */ + int8_t ai8[2]; +} RTUINT16U; +/** Pointer to a 16-bit unsigned integer union. */ +typedef RTUINT16U RT_FAR *PRTUINT16U; +/** Pointer to a const 32-bit unsigned integer union. */ +typedef const RTUINT16U RT_FAR *PCRTUINT16U; + + +/** + * 32-bit unsigned integer union. + */ +typedef union RTUINT32U +{ + /** natural view. */ + uint32_t u; + /** Hi/Low view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t Hi; + uint16_t Lo; +#else + uint16_t Lo; + uint16_t Hi; +#endif + } s; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; +#endif + } Words; + + /** Unsigned 32-bit view. */ + uint32_t au32[1]; + /** Unsigned 16-bit view. */ + uint16_t au16[2]; + /** Unsigned 8-bit view. */ + uint8_t au8[4]; + + /** Signed 32-bit view. */ + int32_t ai32[1]; + /** Signed 16-bit view. */ + int16_t ai16[2]; + /** Signed 8-bit view. */ + int8_t ai8[4]; +} RTUINT32U; +/** Pointer to a 32-bit unsigned integer union. */ +typedef RTUINT32U RT_FAR *PRTUINT32U; +/** Pointer to a const 32-bit unsigned integer union. */ +typedef const RTUINT32U RT_FAR *PCRTUINT32U; + + +/** + * 64-bit unsigned integer union. + */ +typedef union RTUINT64U +{ + /** Natural view. */ + uint64_t u; + /** Hi/Low view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t Hi; + uint32_t Lo; +#else + uint32_t Lo; + uint32_t Hi; +#endif + } s; + /** Double-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t dw1; + uint32_t dw0; +#else + uint32_t dw0; + uint32_t dw1; +#endif + } DWords; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w3; + uint16_t w2; + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; + uint16_t w2; + uint16_t w3; +#endif + } Words; + + /** Unsigned 64-bit view. */ + uint64_t au64[1]; + /** Unsigned 32-bit view. */ + uint32_t au32[2]; + /** Unsigned 16-bit view. */ + uint16_t au16[4]; + /** Unsigned 8-bit view. */ + uint8_t au8[8]; + + /** Signed 64-bit view. */ + int64_t ai64[1]; + /** Signed 32-bit view. */ + int32_t ai32[2]; + /** Signed 16-bit view. */ + int16_t ai16[4]; + /** Signed 8-bit view. */ + int8_t ai8[8]; +} RTUINT64U; +/** Pointer to a 64-bit unsigned integer union. */ +typedef RTUINT64U RT_FAR *PRTUINT64U; +/** Pointer to a const 64-bit unsigned integer union. */ +typedef const RTUINT64U RT_FAR *PCRTUINT64U; + + +/** + * 128-bit unsigned integer union. + */ +#pragma pack(1) +typedef union RTUINT128U +{ + /** Hi/Low view. + * @remarks We put this first so we can have portable initializers + * (RTUINT128_INIT) */ + struct + { +#ifdef RT_BIG_ENDIAN + uint64_t Hi; + uint64_t Lo; +#else + uint64_t Lo; + uint64_t Hi; +#endif + } s; + + /** Natural view. + * WARNING! This member depends on the compiler supporting 128-bit stuff. */ + uint128_t u; + + /** Quad-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint64_t qw1; + uint64_t qw0; +#else + uint64_t qw0; + uint64_t qw1; +#endif + } QWords; + /** Double-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t dw3; + uint32_t dw2; + uint32_t dw1; + uint32_t dw0; +#else + uint32_t dw0; + uint32_t dw1; + uint32_t dw2; + uint32_t dw3; +#endif + } DWords; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w7; + uint16_t w6; + uint16_t w5; + uint16_t w4; + uint16_t w3; + uint16_t w2; + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; + uint16_t w2; + uint16_t w3; + uint16_t w4; + uint16_t w5; + uint16_t w6; + uint16_t w7; +#endif + } Words; + + /** Unsigned 64-bit view. */ + uint64_t au64[2]; + /** Unsigned 32-bit view. */ + uint32_t au32[4]; + /** Unsigned 16-bit view. */ + uint16_t au16[8]; + /** Unsigned 8-bit view. */ + uint8_t au8[16]; + + /** Signed 64-bit view. */ + int64_t ai64[2]; + /** Signed 32-bit view. */ + int32_t ai32[4]; + /** Signed 16-bit view. */ + int16_t ai16[8]; + /** Signed 8-bit view. */ + int8_t ai8[16]; +} RTUINT128U; +#pragma pack() +/** Pointer to a 128-bit unsigned integer union. */ +typedef RTUINT128U RT_FAR *PRTUINT128U; +/** Pointer to a const 128-bit unsigned integer union. */ +typedef const RTUINT128U RT_FAR *PCRTUINT128U; + +/** @def RTUINT128_INIT + * Portable RTUINT128U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTUINT128_INIT(a_Hi, a_Lo) { { a_Hi, a_Lo } } +#else +# define RTUINT128_INIT(a_Hi, a_Lo) { { a_Lo, a_Hi } } +#endif + +/** @def RTUINT128_INIT_C + * Portable RTUINT128U initializer for 64-bit constants. */ +#ifdef RT_BIG_ENDIAN +# define RTUINT128_INIT_C(a_Hi, a_Lo) { { UINT64_C(a_Hi), UINT64_C(a_Lo) } } +#else +# define RTUINT128_INIT_C(a_Hi, a_Lo) { { UINT64_C(a_Lo), UINT64_C(a_Hi) } } +#endif + + +/** + * 256-bit unsigned integer union. + */ +#pragma pack(1) +typedef union RTUINT256U +{ + /** Quad-Word view (first as it's used by RTUINT256_INIT). */ + struct + { +#ifdef RT_BIG_ENDIAN + uint64_t qw3; + uint64_t qw2; + uint64_t qw1; + uint64_t qw0; +#else + uint64_t qw0; + uint64_t qw1; + uint64_t qw2; + uint64_t qw3; +#endif + } QWords; + /** Double-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t dw7; + uint32_t dw6; + uint32_t dw5; + uint32_t dw4; + uint32_t dw3; + uint32_t dw2; + uint32_t dw1; + uint32_t dw0; +#else + uint32_t dw0; + uint32_t dw1; + uint32_t dw2; + uint32_t dw3; + uint32_t dw4; + uint32_t dw5; + uint32_t dw6; + uint32_t dw7; +#endif + } DWords; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w15; + uint16_t w14; + uint16_t w13; + uint16_t w12; + uint16_t w11; + uint16_t w10; + uint16_t w9; + uint16_t w8; + uint16_t w7; + uint16_t w6; + uint16_t w5; + uint16_t w4; + uint16_t w3; + uint16_t w2; + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; + uint16_t w2; + uint16_t w3; + uint16_t w4; + uint16_t w5; + uint16_t w6; + uint16_t w7; + uint16_t w8; + uint16_t w9; + uint16_t w10; + uint16_t w11; + uint16_t w12; + uint16_t w13; + uint16_t w14; + uint16_t w15; +#endif + } Words; + + /** Double-Quad-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + RTUINT128U dqw1; + RTUINT128U dqw0; +#else + RTUINT128U dqw0; + RTUINT128U dqw1; +#endif + } DQWords; + + /** Unsigned 128-bit view. */ + RTUINT128U au128[2]; + /** Unsigned 64-bit view. */ + uint64_t au64[4]; + /** Unsigned 32-bit view. */ + uint32_t au32[8]; + /** Unsigned 16-bit view. */ + uint16_t au16[16]; + /** Unsigned 8-bit view. */ + uint8_t au8[32]; + + /** Signed 64-bit view. */ + int64_t ai64[4]; + /** Signed 32-bit view. */ + int32_t ai32[8]; + /** Signed 16-bit view. */ + int16_t ai16[16]; + /** Signed 8-bit view. */ + int8_t ai8[32]; +} RTUINT256U; +#pragma pack() +/** Pointer to a 256-bit unsigned integer union. */ +typedef RTUINT256U RT_FAR *PRTUINT256U; +/** Pointer to a const 256-bit unsigned integer union. */ +typedef const RTUINT256U RT_FAR *PCRTUINT256U; + +/** @def RTUINT256_INIT + * Portable RTUINT256U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTUINT256_INIT(a_Qw3, a_Qw2, a_Qw1, a_Qw0) { { a_Qw3, a_Qw2, a_Qw1, a_Qw0 } } +#else +# define RTUINT256_INIT(a_Qw3, a_Qw2, a_Qw1, a_Qw0) { { a_Qw0, a_Qw1, a_Qw2, a_Qw3 } } +#endif + +/** @def RTUINT256_INIT_C + * Portable RTUINT256U initializer for 64-bit constants. */ +#define RTUINT256_INIT_C(a_Qw3, a_Qw2, a_Qw1, a_Qw0) \ + RTUINT256_INIT(UINT64_C(a_Qw3), UINT64_C(a_Qw2), UINT64_C(a_Qw1), UINT64_C(a_Qw0)) + + +/** + * 512-bit unsigned integer union. + */ +#pragma pack(1) +typedef union RTUINT512U +{ + /** Quad-Word view (first as it's used by RTUINT512_INIT). */ + struct + { +#ifdef RT_BIG_ENDIAN + uint64_t qw7; + uint64_t qw6; + uint64_t qw5; + uint64_t qw4; + uint64_t qw3; + uint64_t qw2; + uint64_t qw1; + uint64_t qw0; +#else + uint64_t qw0; + uint64_t qw1; + uint64_t qw2; + uint64_t qw3; + uint64_t qw4; + uint64_t qw5; + uint64_t qw6; + uint64_t qw7; +#endif + } QWords; + /** Double-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t dw15; + uint32_t dw14; + uint32_t dw13; + uint32_t dw12; + uint32_t dw11; + uint32_t dw10; + uint32_t dw9; + uint32_t dw8; + uint32_t dw7; + uint32_t dw6; + uint32_t dw5; + uint32_t dw4; + uint32_t dw3; + uint32_t dw2; + uint32_t dw1; + uint32_t dw0; +#else + uint32_t dw0; + uint32_t dw1; + uint32_t dw2; + uint32_t dw3; + uint32_t dw4; + uint32_t dw5; + uint32_t dw6; + uint32_t dw7; + uint32_t dw8; + uint32_t dw9; + uint32_t dw10; + uint32_t dw11; + uint32_t dw12; + uint32_t dw13; + uint32_t dw14; + uint32_t dw15; +#endif + } DWords; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w31; + uint16_t w30; + uint16_t w29; + uint16_t w28; + uint16_t w27; + uint16_t w26; + uint16_t w25; + uint16_t w24; + uint16_t w23; + uint16_t w22; + uint16_t w21; + uint16_t w20; + uint16_t w19; + uint16_t w18; + uint16_t w17; + uint16_t w16; + uint16_t w15; + uint16_t w14; + uint16_t w13; + uint16_t w12; + uint16_t w11; + uint16_t w10; + uint16_t w9; + uint16_t w8; + uint16_t w7; + uint16_t w6; + uint16_t w5; + uint16_t w4; + uint16_t w3; + uint16_t w2; + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; + uint16_t w2; + uint16_t w3; + uint16_t w4; + uint16_t w5; + uint16_t w6; + uint16_t w7; + uint16_t w8; + uint16_t w9; + uint16_t w10; + uint16_t w11; + uint16_t w12; + uint16_t w13; + uint16_t w14; + uint16_t w15; + uint16_t w16; + uint16_t w17; + uint16_t w18; + uint16_t w19; + uint16_t w20; + uint16_t w21; + uint16_t w22; + uint16_t w23; + uint16_t w24; + uint16_t w25; + uint16_t w26; + uint16_t w27; + uint16_t w28; + uint16_t w29; + uint16_t w30; + uint16_t w31; +#endif + } Words; + + /** Double-Quad-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + RTUINT128U dqw3; + RTUINT128U dqw2; + RTUINT128U dqw1; + RTUINT128U dqw0; +#else + RTUINT128U dqw0; + RTUINT128U dqw1; + RTUINT128U dqw2; + RTUINT128U dqw3; +#endif + } DQWords; + + /** Octo-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + RTUINT256U ow3; + RTUINT256U ow2; + RTUINT256U ow1; + RTUINT256U ow0; +#else + RTUINT256U ow0; + RTUINT256U ow1; + RTUINT256U ow2; + RTUINT256U ow3; +#endif + } OWords; + + /** 256-bit view. */ + RTUINT256U au256[2]; + /** 128-bit view. */ + RTUINT128U au128[4]; + /** 64-bit view. */ + uint64_t au64[8]; + /** 32-bit view. */ + uint32_t au32[16]; + /** 16-bit view. */ + uint16_t au16[32]; + /** 8-bit view. */ + uint8_t au8[64]; +} RTUINT512U; +#pragma pack() +/** Pointer to a 512-bit unsigned integer union. */ +typedef RTUINT512U RT_FAR *PRTUINT512U; +/** Pointer to a const 512-bit unsigned integer union. */ +typedef const RTUINT512U RT_FAR *PCRTUINT512U; + +/** @def RTUINT512_INIT + * Portable RTUINT512U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTUINT512_INIT(a_Qw7, a_Qw6, a_Qw5, a_Qw4, a_Qw3, a_Qw2, a_Qw1, a_Qw0) \ + { { a_Qw7, a_Qw6, a_Qw5, a_Qw4, a_Qw3, a_Qw2, a_Qw1, a_Qw0 } } +#else +# define RTUINT512_INIT(a_Qw7, a_Qw6, a_Qw5, a_Qw4, a_Qw3, a_Qw2, a_Qw1, a_Qw0) \ + { { a_Qw0, a_Qw1, a_Qw2, a_Qw3, a_Qw4, a_Qw5, a_Qw6, a_Qw7 } } +#endif + +/** @def RTUINT512_INIT_C + * Portable RTUINT512U initializer for 64-bit constants. */ +#define RTUINT512_INIT_C(a_Qw7, a_Qw6, a_Qw5, a_Qw4, a_Qw3, a_Qw2, a_Qw1, a_Qw0) \ + RTUINT512_INIT(UINT64_C(a_Qw7), UINT64_C(a_Qw6), UINT64_C(a_Qw5), UINT64_C(a_Qw4), \ + UINT64_C(a_Qw3), UINT64_C(a_Qw2), UINT64_C(a_Qw1), UINT64_C(a_Qw0)) + + +/** + * Single precision floating point format (32-bit). + */ +typedef union RTFLOAT32U +{ + /** Format using regular bitfields. */ + struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + uint32_t fSign : 1; + /** The exponent (offsetted by 127). */ + uint32_t uExponent : 8; + /** The fraction. */ + uint32_t uFraction : 23; +# else + /** The fraction. */ + uint32_t uFraction : 23; + /** The exponent (offsetted by 127). */ + uint32_t uExponent : 8; + /** The sign indicator. */ + uint32_t fSign : 1; +# endif + } s; + +#if 1 /** @todo exclude targets which doesn't have a 64-bit double type. (currently none) */ + /** Double view. */ + float r; +#endif + /** Unsigned integer view. */ + uint32_t u; + /** 32-bit view. */ + uint32_t au32[1]; + /** 16-bit view. */ + uint16_t au16[2]; + /** 8-bit view. */ + uint8_t au8[4]; +} RTFLOAT32U; +/** Pointer to a single precision floating point format union. */ +typedef RTFLOAT32U RT_FAR *PRTFLOAT32U; +/** Pointer to a const single precision floating point format union. */ +typedef const RTFLOAT32U RT_FAR *PCRTFLOAT32U; +/** RTFLOAT32U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTFLOAT32U_INIT(a_fSign, a_uFraction, a_uExponent) { { (a_fSign), (a_uExponent), (a_uFraction) } } +#else +# define RTFLOAT32U_INIT(a_fSign, a_uFraction, a_uExponent) { { (a_uFraction), (a_uExponent), (a_fSign) } } +#endif +#define RTFLOAT32U_INIT_C(a_fSign, a_uFraction, a_uExponent) RTFLOAT32U_INIT((a_fSign), UINT32_C(a_uFraction), (a_uExponent)) +#define RTFLOAT32U_INIT_ZERO(a_fSign) RTFLOAT32U_INIT((a_fSign), 0, 0) +#define RTFLOAT32U_INIT_INF(a_fSign) RTFLOAT32U_INIT((a_fSign), 0, RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_SNAN(a_fSign) RTFLOAT32U_INIT((a_fSign), 1, RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_SNAN_EX(a_fSign, a_uVal) RTFLOAT32U_INIT((a_fSign), (a_uVal) ? (a_uVal) : 1, RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_SIGNALLING_NAN(a_fSign) RTFLOAT32U_INIT_SNAN(a_fSign) +#define RTFLOAT32U_INIT_QNAN(a_fSign) RTFLOAT32U_INIT((a_fSign), RT_BIT_32(RTFLOAT32U_FRACTION_BITS - 1), RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_QNAN_EX(a_fSign, a_uVal) RTFLOAT32U_INIT((a_fSign), RT_BIT_32(RTFLOAT32U_FRACTION_BITS - 1) | (a_uVal), RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_QUIET_NAN(a_fSign) RTFLOAT32U_INIT_QNAN(a_fSign) +#define RTFLOAT32U_INIT_NAN_EX(a_fQuiet, a_fSign, a_uVal) \ + RTFLOAT32U_INIT((a_fSign), \ + ((a_uVal) || (a_fQuiet) ? (a_uVal) : 1) | ((a_fQuiet) ? RT_BIT_32(RTFLOAT32U_FRACTION_BITS - 1) : 0), \ + RTFLOAT32U_EXP_MAX) + +/** The exponent bias for the RTFLOAT32U format. */ +#define RTFLOAT32U_EXP_BIAS (127) +/** The max exponent value for the RTFLOAT32U format. */ +#define RTFLOAT32U_EXP_MAX (255) +/** The exponent bias overflow/underflow adjust for the RTFLOAT32U format. + * @note 754-1985 sec 7.3 & 7.4, not mentioned in later standard versions. */ +#define RTFLOAT32U_EXP_BIAS_ADJUST (192) +/** Fraction width (in bits) for the RTFLOAT32U format. */ +#define RTFLOAT32U_FRACTION_BITS (23) +/** Check if two 32-bit floating values are identical (memcmp, not + * numerically). */ +#define RTFLOAT32U_ARE_IDENTICAL(a_pLeft, a_pRight) ((a_pLeft)->u == (a_pRight)->u) +/** @name RTFLOAT32U classification macros + * @{ */ +#define RTFLOAT32U_IS_ZERO(a_pr32) (((a_pr32)->u & (RT_BIT_32(31) - 1)) == 0) +#define RTFLOAT32U_IS_SUBNORMAL(a_pr32) ((a_pr32)->s.uExponent == 0 && (a_pr32)->s.uFraction != 0) +#define RTFLOAT32U_IS_INF(a_pr32) ((a_pr32)->s.uExponent == 0xff && (a_pr32)->s.uFraction == 0) +#define RTFLOAT32U_IS_SIGNALLING_NAN(a_pr32) ((a_pr32)->s.uExponent == 0xff && !((a_pr32)->s.uFraction & RT_BIT_32(22)) \ + && (a_pr32)->s.uFraction != 0) +#define RTFLOAT32U_IS_QUIET_NAN(a_pr32) ((a_pr32)->s.uExponent == 0xff && ((a_pr32)->s.uFraction & RT_BIT_32(22))) +#define RTFLOAT32U_IS_NAN(a_pr32) ((a_pr32)->s.uExponent == 0xff && (a_pr32)->s.uFraction != 0) +#define RTFLOAT32U_IS_NORMAL(a_pr32) ((a_pr32)->s.uExponent > 0 && (a_pr32)->s.uExponent < 0xff) +/** @} */ + + +/** + * Double precision floating point format (64-bit). + */ +typedef union RTFLOAT64U +{ + /** Format using regular bitfields. */ + struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + uint32_t fSign : 1; + /** The exponent (offsetted by 1023). */ + uint32_t uExponent : 11; + /** The fraction, bits 32 thru 51. */ + uint32_t uFractionHigh : 20; + /** The fraction, bits 0 thru 31. */ + uint32_t uFractionLow; +# else + /** The fraction, bits 0 thru 31. */ + uint32_t uFractionLow; + /** The fraction, bits 32 thru 51. */ + uint32_t uFractionHigh : 20; + /** The exponent (offsetted by 1023). */ + uint32_t uExponent : 11; + /** The sign indicator. */ + uint32_t fSign : 1; +# endif + } s; + +#ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS + /** Format using 64-bit bitfields. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + RT_GCC_EXTENSION uint64_t fSign : 1; + /** The exponent (offsetted by 1023). */ + RT_GCC_EXTENSION uint64_t uExponent : 11; + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 52; +# else + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 52; + /** The exponent (offsetted by 1023). */ + RT_GCC_EXTENSION uint64_t uExponent : 11; + /** The sign indicator. */ + RT_GCC_EXTENSION uint64_t fSign : 1; +# endif + } s64; +#endif + +#if 1 /** @todo exclude targets which doesn't have a 64-bit double type. (currently none) */ + /** Double view. */ + double rd, r; +#endif +#ifdef RT_COMPILER_WITH_64BIT_LONG_DOUBLE + /** Long double view. */ + long double lrd; +#endif + /** Unsigned integer view. */ + uint64_t u; + /** 64-bit view. */ + uint64_t au64[1]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[4]; + /** 8-bit view. */ + uint8_t au8[8]; +} RTFLOAT64U; +/** Pointer to a double precision floating point format union. */ +typedef RTFLOAT64U RT_FAR *PRTFLOAT64U; +/** Pointer to a const double precision floating point format union. */ +typedef const RTFLOAT64U RT_FAR *PCRTFLOAT64U; +/** RTFLOAT64U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTFLOAT64U_INIT(a_fSign, a_uFraction, a_uExponent) \ + { { (a_fSign), (a_uExponent), (uint32_t)((a_uFraction) >> 32), (uint32_t)((a_uFraction) & UINT32_MAX) } } +#else +# define RTFLOAT64U_INIT(a_fSign, a_uFraction, a_uExponent) \ + { { (uint32_t)((a_uFraction) & UINT32_MAX), (uint32_t)((a_uFraction) >> 32), (a_uExponent), (a_fSign) } } +#endif +#define RTFLOAT64U_INIT_C(a_fSign, a_uFraction, a_uExponent) RTFLOAT64U_INIT((a_fSign), UINT64_C(a_uFraction), (a_uExponent)) +#define RTFLOAT64U_INIT_ZERO(a_fSign) RTFLOAT64U_INIT((a_fSign), UINT64_C(0), 0) +#define RTFLOAT64U_INIT_INF(a_fSign) RTFLOAT64U_INIT((a_fSign), UINT64_C(0), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_SNAN(a_fSign) RTFLOAT64U_INIT((a_fSign), UINT64_C(1), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_SNAN_EX(a_fSign, a_uVal) RTFLOAT64U_INIT((a_fSign), (a_uVal) ? (a_uVal) : UINT64_C(1), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_SIGNALLING_NAN(a_fSign) RTFLOAT64U_INIT_SNAN(a_fSign) +#define RTFLOAT64U_INIT_QNAN(a_fSign) RTFLOAT64U_INIT((a_fSign), RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_QNAN_EX(a_fSign, a_uVal) RTFLOAT64U_INIT((a_fSign), RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1) | (a_uVal), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_QUIET_NAN(a_fSign) RTFLOAT64U_INIT_QNAN(a_fSign) +#define RTFLOAT64U_INIT_NAN_EX(a_fQuiet, a_fSign, a_uVal) \ + RTFLOAT64U_INIT((a_fSign), \ + ((a_uVal) || (a_fQuiet) ? (a_uVal) : UINT64_C(1)) | ((a_fQuiet) ? RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1) : UINT64_C(0)), \ + RTFLOAT64U_EXP_MAX) + +/** The exponent bias for the RTFLOAT64U format. */ +#define RTFLOAT64U_EXP_BIAS (1023) +/** The max exponent value for the RTFLOAT64U format. */ +#define RTFLOAT64U_EXP_MAX (2047) +/** The exponent bias overflow/underflow adjust for the RTFLOAT64U format. + * @note 754-1985 sec 7.3 & 7.4, not mentioned in later standard versions. */ +#define RTFLOAT64U_EXP_BIAS_ADJUST (1536) +/** Fraction width (in bits) for the RTFLOAT64U format. */ +#define RTFLOAT64U_FRACTION_BITS (52) +/** Check if two 64-bit floating values are identical (memcmp, not + * numerically). */ +#define RTFLOAT64U_ARE_IDENTICAL(a_pLeft, a_pRight) ((a_pLeft)->u == (a_pRight)->u) +/** @name RTFLOAT64U classification macros + * @{ */ +#define RTFLOAT64U_IS_ZERO(a_pr64) (((a_pr64)->u & (RT_BIT_64(63) - 1)) == 0) +#define RTFLOAT64U_IS_SUBNORMAL(a_pr64) ( (a_pr64)->s.uExponent == 0 \ + && ((a_pr64)->s.uFractionLow != 0 || (a_pr64)->s.uFractionHigh != 0) ) +#define RTFLOAT64U_IS_INF(a_pr64) ( (a_pr64)->s.uExponent == 0x7ff \ + && (a_pr64)->s.uFractionLow == 0 && (a_pr64)->s.uFractionHigh == 0) +#define RTFLOAT64U_IS_SIGNALLING_NAN(a_pr64) ( (a_pr64)->s.uExponent == 0x7ff \ + && !((a_pr64)->s.uFractionHigh & RT_BIT_32(19)) \ + && ((a_pr64)->s.uFractionHigh != 0 || (a_pr64)->s.uFractionLow != 0) ) +#define RTFLOAT64U_IS_QUIET_NAN(a_pr64) ((a_pr64)->s.uExponent == 0x7ff && ((a_pr64)->s.uFractionHigh & RT_BIT_32(19))) +#define RTFLOAT64U_IS_NAN(a_pr64) ( (a_pr64)->s.uExponent == 0x7ff \ + && ((a_pr64)->s.uFractionHigh != 0 || (a_pr64)->s.uFractionLow != 0) ) +#define RTFLOAT64U_IS_NORMAL(a_pr64) ((a_pr64)->s.uExponent > 0 && (a_pr64)->s.uExponent < 0x7ff) +/** @} */ + + + +#if !defined(__IBMCPP__) && !defined(__IBMC__) + +/** + * Extended Double precision floating point format (80-bit). + */ +# pragma pack(1) +typedef union RTFLOAT80U +{ + /** Format using bitfields. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The mantissa. */ + uint64_t uMantissa; +# else + /** The mantissa. */ + uint64_t uMantissa; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } s; + + /** Format for accessing it as two separate components. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; + /** The mantissa. */ + uint64_t uMantissa; +# else + /** The mantissa. */ + uint64_t uMantissa; + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; +# endif + } s2; + +# ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS + /** 64-bit bitfields exposing the J bit and the fraction. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The J bit, aka the integer bit. */ + RT_GCC_EXTENSION uint64_t fInteger : 1; + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 63; +# else + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 63; + /** The J bit, aka the integer bit. */ + RT_GCC_EXTENSION uint64_t fInteger : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } sj64; +# endif + + /** 64-bit view. */ + uint64_t au64[1]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[5]; + /** 8-bit view. */ + uint8_t au8[10]; +} RTFLOAT80U; +# pragma pack() +/** Pointer to a extended precision floating point format union. */ +typedef RTFLOAT80U RT_FAR *PRTFLOAT80U; +/** Pointer to a const extended precision floating point format union. */ +typedef const RTFLOAT80U RT_FAR *PCRTFLOAT80U; +/** RTFLOAT80U initializer. */ +# ifdef RT_BIG_ENDIAN +# define RTFLOAT80U_INIT(a_fSign, a_uMantissa, a_uExponent) { { (a_fSign), (a_uExponent), (a_uMantissa) } } +# else +# define RTFLOAT80U_INIT(a_fSign, a_uMantissa, a_uExponent) { { (a_uMantissa), (a_uExponent), (a_fSign) } } +# endif +# define RTFLOAT80U_INIT_C(a_fSign, a_uMantissa, a_uExponent) RTFLOAT80U_INIT((a_fSign), UINT64_C(a_uMantissa), (a_uExponent)) +# define RTFLOAT80U_INIT_ZERO(a_fSign) RTFLOAT80U_INIT((a_fSign), 0, 0) +# define RTFLOAT80U_INIT_INF(a_fSign) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63), RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_SIGNALLING_NAN(a_fSign) RTFLOAT80U_INIT_SNAN((a_fSign)) +# define RTFLOAT80U_INIT_SNAN(a_fSign) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | 1, RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_SNAN_EX(a_fSign, a_uVal) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | (a_uVal), RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_QUIET_NAN(a_fSign) RTFLOAT80U_INIT_QNAN((a_fSign)) +# define RTFLOAT80U_INIT_QNAN(a_fSign) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | RT_BIT_64(62), RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_QNAN_EX(a_fSign, a_uVal) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | RT_BIT_64(62) | (a_uVal), RTFLOAT80U_EXP_MAX) +#define RTFLOAT80U_INIT_NAN_EX(a_fQuiet, a_fSign, a_uVal) \ + RTFLOAT80U_INIT((a_fSign), \ + ((a_uVal) || (a_fQuiet) ? (a_uVal) : UINT64_C(1)) | ((a_fQuiet) ? RT_BIT_64(63) | RT_BIT_64(62) : RT_BIT_64(63)), \ + RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_INDEFINITE(a_fSign) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | RT_BIT_64(62), RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_IND(a_fSign) RTFLOAT80U_INIT_INDEFINITE(a_fSign) +/** The exponent bias for the RTFLOAT80U format. */ +# define RTFLOAT80U_EXP_BIAS (16383) +/** The max exponent value for the RTFLOAT80U format. */ +# define RTFLOAT80U_EXP_MAX (32767) +/** The exponent bias overflow/underflow adjust for the RTFLOAT80U format. + * @note 754-1985 sec 7.3 & 7.4, not mentioned in later standard versions. */ +# define RTFLOAT80U_EXP_BIAS_ADJUST (24576) +/** Fraction width (in bits) for the RTFLOAT80U format. */ +# define RTFLOAT80U_FRACTION_BITS (63) +/** Check if two 80-bit floating values are identical (memcmp, not + * numberically). */ +# define RTFLOAT80U_ARE_IDENTICAL(a_pLeft, a_pRight) \ + ( (a_pLeft)->au64[0] == (a_pRight)->au64[0] \ + && (a_pLeft)->au16[4] == (a_pRight)->au16[4] ) +/** @name RTFLOAT80U classification macros + * @{ */ +/** Is @a a_pr80 +0 or -0. */ +# define RTFLOAT80U_IS_ZERO(a_pr80) RTFLOAT80U_IS_ZERO_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_ZERO_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0 && (a_uMantissa) == 0) +/** Is @a a_pr80 a denormal (does not match psuedo-denormal). */ +# define RTFLOAT80U_IS_DENORMAL(a_pr80) RTFLOAT80U_IS_DENORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_DENORMAL_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0 && (a_uMantissa) < RT_BIT_64(63) && (a_uMantissa) != 0) +/** Is @a a_pr80 a pseudo-denormal. */ +# define RTFLOAT80U_IS_PSEUDO_DENORMAL(a_pr80) RTFLOAT80U_IS_PSEUDO_DENORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_PSEUDO_DENORMAL_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0 && (a_uMantissa) >= RT_BIT_64(63)) +/** Is @a a_pr80 denormal or pseudo-denormal. */ +# define RTFLOAT80U_IS_DENORMAL_OR_PSEUDO_DENORMAL(a_pr80) \ + RTFLOAT80U_IS_DENORMAL_OR_PSEUDO_DENORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_DENORMAL_OR_PSEUDO_DENORMAL_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0 && (a_uMantissa) != 0) +/** Is @a a_pr80 +/-pseudo-infinity. */ +# define RTFLOAT80U_IS_PSEUDO_INF(a_pr80) RTFLOAT80U_IS_PSEUDO_INF_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_PSEUDO_INF_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0x7fff && (a_uMantissa) == 0) +/** Is @a a_pr80 pseudo-not-a-number. */ +# define RTFLOAT80U_IS_PSEUDO_NAN(a_pr80) RTFLOAT80U_IS_PSEUDO_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_PSEUDO_NAN_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0x7fff && !((a_uMantissa) & RT_BIT_64(63))) +/** Is @a a_pr80 infinity (does not match pseudo-infinity). */ +# define RTFLOAT80U_IS_INF(a_pr80) RTFLOAT80U_IS_INF_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_INF_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0x7fff && (a_uMantissa) == RT_BIT_64(63)) +/** Is @a a_pr80 a signalling not-a-number value. */ +# define RTFLOAT80U_IS_SIGNALLING_NAN(a_pr80) RTFLOAT80U_IS_SIGNALLING_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_SIGNALLING_NAN_EX(a_uMantissa, a_uExponent) \ + ( (a_uExponent) == 0x7fff \ + && ((a_uMantissa) & (RT_BIT_64(63) | RT_BIT_64(62))) == RT_BIT_64(63) \ + && ((a_uMantissa) & (RT_BIT_64(62) - 1)) != 0) +/** Is @a a_pr80 a quiet not-a-number value. */ +# define RTFLOAT80U_IS_QUIET_NAN(a_pr80) RTFLOAT80U_IS_QUIET_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_QUIET_NAN_EX(a_uMantissa, a_uExponent) \ + ( (a_uExponent) == 0x7fff \ + && ((a_uMantissa) & (RT_BIT_64(63) | RT_BIT_64(62))) == (RT_BIT_64(63) | RT_BIT_64(62)) \ + && ((a_uMantissa) & (RT_BIT_64(62) - 1)) != 0) +/** Is @a a_pr80 Signalling-, Quiet- or Pseudo-NaN. */ +# define RTFLOAT80U_IS_NAN(a_pr80) RTFLOAT80U_IS_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_NAN_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0x7fff && ((a_uMantissa) & (RT_BIT_64(63) - 1)) != 0) +/** Is @a a_pr80 Signalling- or Quiet-Nan, but not Pseudo-NaN. */ +# define RTFLOAT80U_IS_QUIET_OR_SIGNALLING_NAN(a_pr80) \ + RTFLOAT80U_IS_QUIET_OR_SIGNALLING_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_QUIET_OR_SIGNALLING_NAN_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0x7fff && ((a_uMantissa) > RT_BIT_64(63))) +/** Is @a a_pr80 indefinite (ignoring sign). */ +# define RTFLOAT80U_IS_INDEFINITE(a_pr80) RTFLOAT80U_IS_INDEFINITE_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_INDEFINITE_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0x7fff && (a_uMantissa) == (RT_BIT_64(63) | RT_BIT_64(62))) +/** Is @a a_pr80 Indefinite, Signalling- or Quiet-Nan, but not Pseudo-NaN (nor Infinity). */ +# define RTFLOAT80U_IS_INDEFINITE_OR_QUIET_OR_SIGNALLING_NAN(a_pr80) \ + RTFLOAT80U_IS_INDEFINITE_OR_QUIET_OR_SIGNALLING_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_INDEFINITE_OR_QUIET_OR_SIGNALLING_NAN_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0x7fff && (a_uMantissa) > RT_BIT_64(63)) +/** Is @a a_pr80 an unnormal value (invalid operand on 387+). */ +# define RTFLOAT80U_IS_UNNORMAL(a_pr80) RTFLOAT80U_IS_UNNORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_UNNORMAL_EX(a_uMantissa, a_uExponent) \ + (!((a_uMantissa) & RT_BIT_64(63)) && (a_uExponent) > 0 && (a_uExponent) < 0x7fff) /* a_uExponent can be signed and up to 64-bit wide */ +/** Is @a a_pr80 a normal value (excludes zero). */ +# define RTFLOAT80U_IS_NORMAL(a_pr80) RTFLOAT80U_IS_NORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_NORMAL_EX(a_uMantissa, a_uExponent) \ + (((a_uMantissa) & RT_BIT_64(63)) && (a_uExponent) > 0 && (a_uExponent) < 0x7fff) /* a_uExponent can be signed and up to 64-bit wide */ +/** Invalid 387 (and later) operands: Pseudo-Infinity, Psuedo-NaN, Unnormals. */ +#define RTFLOAT80U_IS_387_INVALID(a_pr80) RTFLOAT80U_IS_387_INVALID_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +#define RTFLOAT80U_IS_387_INVALID_EX(a_uMantissa, a_uExponent) \ + (!((a_uMantissa) & RT_BIT_64(63)) && (a_uExponent) > 0) +/** @} */ + + +/** + * A variant of RTFLOAT80U that may be larger than 80-bits depending on how the + * compiler implements long double. + * + * @note On AMD64 systems implementing the System V ABI, this will be 16 bytes! + * The last 6 bytes are unused padding taken up by the long double view. + */ +# pragma pack(1) +typedef union RTFLOAT80U2 +{ + /** Format using bitfields. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The mantissa. */ + uint64_t uMantissa; +# else + /** The mantissa. */ + uint64_t uMantissa; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } s; + + /** Format for accessing it as two separate components. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; + /** The mantissa. */ + uint64_t uMantissa; +# else + /** The mantissa. */ + uint64_t uMantissa; + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; +# endif + } s2; + + /** Bitfield exposing the J bit and the fraction. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The J bit, aka the integer bit. */ + uint32_t fInteger : 1; + /** The fraction, bits 32 thru 62. */ + uint32_t uFractionHigh : 31; + /** The fraction, bits 0 thru 31. */ + uint32_t uFractionLow : 32; +# else + /** The fraction, bits 0 thru 31. */ + uint32_t uFractionLow : 32; + /** The fraction, bits 32 thru 62. */ + uint32_t uFractionHigh : 31; + /** The J bit, aka the integer bit. */ + uint32_t fInteger : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } sj; + +# ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS + /** 64-bit bitfields exposing the J bit and the fraction. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The J bit, aka the integer bit. */ + RT_GCC_EXTENSION uint64_t fInteger : 1; + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 63; +# else + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 63; + /** The J bit, aka the integer bit. */ + RT_GCC_EXTENSION uint64_t fInteger : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } sj64; +# endif + +# ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE + /** Long double view. */ + long double lrd, r; +# endif + /** 64-bit view. */ + uint64_t au64[1]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[5]; + /** 8-bit view. */ + uint8_t au8[10]; +} RTFLOAT80U2; +# pragma pack() +/** Pointer to a extended precision floating point format union, 2nd + * variant. */ +typedef RTFLOAT80U2 RT_FAR *PRTFLOAT80U2; +/** Pointer to a const extended precision floating point format union, 2nd + * variant. */ +typedef const RTFLOAT80U2 RT_FAR *PCRTFLOAT80U2; + +#endif /* uint16_t bitfields doesn't work */ + + +/** + * Quadruple precision floating point format (128-bit). + */ +typedef union RTFLOAT128U +{ + /** Format using regular bitfields. */ + struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + uint32_t fSign : 1; + /** The exponent (offsetted by 16383). */ + uint32_t uExponent : 15; + /** The fraction, bits 96 thru 111. */ + uint32_t uFractionHigh : 16; + /** The fraction, bits 64 thru 95. */ + uint32_t uFractionMid; + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLow; +# else + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLow; + /** The fraction, bits 64 thru 95. */ + uint32_t uFractionMid; + /** The fraction, bits 96 thru 111. */ + uint32_t uFractionHigh : 16; + /** The exponent (offsetted by 16383). */ + uint32_t uExponent : 15; + /** The sign indicator. */ + uint32_t fSign : 1; +# endif + } s; + + /** Format for accessing it as two separate components. */ + struct + { +# ifdef RT_BIG_ENDIAN + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; + /** The fraction, bits 96 thru 111. */ + uint16_t uFractionHigh; + /** The fraction, bits 64 thru 95. */ + uint32_t uFractionMid; + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLow; +# else + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLow; + /** The fraction, bits 64 thru 95. */ + uint32_t uFractionMid; + /** The fraction, bits 96 thru 111. */ + uint16_t uFractionHigh; + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; +# endif + } s2; + +#ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS + /** Format using 64-bit bitfields. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + RT_GCC_EXTENSION uint64_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint64_t uExponent : 15; + /** The fraction, bits 64 thru 111. */ + RT_GCC_EXTENSION uint64_t uFractionHi : 48; + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLo; +# else + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLo; + /** The fraction, bits 64 thru 111. */ + RT_GCC_EXTENSION uint64_t uFractionHi : 48; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint64_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint64_t fSign : 1; +# endif + } s64; +#endif + +#ifdef RT_COMPILER_WITH_128BIT_LONG_DOUBLE + /** Long double view. */ + long double lrd, r; +#endif + /** 128-bit view. */ + RTUINT128U u128; + /** 64-bit view. */ + uint64_t au64[2]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 8-bit view. */ + uint8_t au8[16]; +} RTFLOAT128U; +/** Pointer to a quadruple precision floating point format union. */ +typedef RTFLOAT128U RT_FAR *PRTFLOAT128U; +/** Pointer to a const quadruple precision floating point format union. */ +typedef const RTFLOAT128U RT_FAR *PCRTFLOAT128U; +/** RTFLOAT128U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTFLOAT128U_INIT(a_fSign, a_uFractionHi, a_uFractionLo, a_uExponent) \ + { { (a_fSign), (a_uExponent), (uint32_t)((a_uFractionHi) >> 32), (uint32_t)((a_uFractionHi) & UINT32_MAX), (a_uFractionLo) } } +#else +# define RTFLOAT128U_INIT(a_fSign, a_uFractionHi, a_uFractionLo, a_uExponent) \ + { { (a_uFractionLo), (uint32_t)((a_uFractionHi) & UINT32_MAX), (uint32_t)((a_uFractionHi) >> 32), (a_uExponent), (a_fSign) } } +#endif +#define RTFLOAT128U_INIT_C(a_fSign, a_uFractionHi, a_uFractionLo, a_uExponent) \ + RTFLOAT128U_INIT((a_fSign), UINT64_C(a_uFractionHi), UINT64_C(a_uFractionLo), (a_uExponent)) + +#define RTFLOAT128U_INIT_ZERO(a_fSign) RTFLOAT128U_INIT((a_fSign), UINT64_C(0), UINT64_C(0), 0) +#define RTFLOAT128U_INIT_INF(a_fSign) RTFLOAT128U_INIT((a_fSign), UINT64_C(0), UINT64_C(0), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_SNAN(a_fSign) RTFLOAT128U_INIT((a_fSign), UINT64_C(0), UINT64_C(1), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_SNAN_EX(a_fSign, a_uValHi, a_uValLo) \ + RTFLOAT128U_INIT((a_fSign), (a_uValHi), (a_uValHi) || (a_uValLo) ? (a_uValLo) : UINT64_C(1), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_SIGNALLING_NAN(a_fSign) RTFLOAT128U_INIT_SNAN(a_fSign) +#define RTFLOAT128U_INIT_QNAN(a_fSign) \ + RTFLOAT128U_INIT((a_fSign), RT_BIT_64(RTFLOAT128U_FRACTION_BITS - 1 - 64), UINT64_C(0), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_QNAN_EX(a_fSign, a_uValHi, a_uValLo) \ + RTFLOAT128U_INIT((a_fSign), RT_BIT_64(RTFLOAT128U_FRACTION_BITS - 1 - 64) | (a_uValHi), (a_uValLo), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_QUIET_NAN(a_fSign) RTFLOAT128U_INIT_QNAN(a_fSign) +#define RTFLOAT128U_INIT_NAN_EX(a_fQuiet, a_fSign, a_uValHi, a_uValLo) \ + RTFLOAT128U_INIT((a_fSign), \ + ((a_fQuiet) ? RT_BIT_64(RTFLOAT128U_FRACTION_BITS - 1 - 64) : 0) | (a_uValHi), \ + (a_uValLo) || (a_uValHi) || (a_fQuiet) ? (a_uValLo) : UINT64_C(1), \ + RTFLOAT128U_EXP_MAX) + +/** The exponent bias for the RTFLOAT128U format. */ +#define RTFLOAT128U_EXP_BIAS (16383) +/** The max exponent value for the RTFLOAT128U format. */ +#define RTFLOAT128U_EXP_MAX (32767) +/** The exponent bias overflow/underflow adjust for the RTFLOAT128U format. + * @note This is stipulated based on RTFLOAT80U, it doesn't appear in any + * standard text as far as we know. */ +#define RTFLOAT128U_EXP_BIAS_ADJUST (24576) +/** Fraction width (in bits) for the RTFLOAT128U format. */ +#define RTFLOAT128U_FRACTION_BITS (112) +/** Check if two 128-bit floating values are identical (memcmp, not + * numerically). */ +#define RTFLOAT128U_ARE_IDENTICAL(a_pLeft, a_pRight) \ + ( (a_pLeft)->au64[0] == (a_pRight)->au64[0] && (a_pLeft)->au64[1] == (a_pRight)->au64[1] ) +/** @name RTFLOAT128U classification macros + * @{ */ +#define RTFLOAT128U_IS_ZERO(a_pr128) ( (a_pr128)->u128.s.Lo == 0 \ + && ((a_pr128)->u128.s.Hi & (RT_BIT_64(63) - 1)) == 0) +#define RTFLOAT128U_IS_SUBNORMAL(a_pr128) ( (a_pr128)->s.uExponent == 0 \ + && ( (a_pr128)->s.uFractionLow != 0 \ + || (a_pr128)->s.uFractionMid != 0 \ + || (a_pr128)->s.uFractionHigh != 0 ) ) +#define RTFLOAT128U_IS_INF(a_pr128) ( (a_pr128)->s.uExponent == RTFLOAT128U_EXP_MAX \ + && (a_pr128)->s.uFractionHigh == 0 \ + && (a_pr128)->s.uFractionMid == 0 \ + && (a_pr128)->s.uFractionLow == 0 ) +#define RTFLOAT128U_IS_SIGNALLING_NAN(a_pr128) ( (a_pr128)->s.uExponent == RTFLOAT128U_EXP_MAX \ + && !((a_pr128)->s.uFractionHigh & RT_BIT_32(15)) \ + && ( (a_pr128)->s.uFractionHigh != 0 \ + || (a_pr128)->s.uFractionMid != 0 \ + || (a_pr128)->s.uFractionLow != 0) ) +#define RTFLOAT128U_IS_QUIET_NAN(a_pr128) ( (a_pr128)->s.uExponent == RTFLOAT128U_EXP_MAX \ + && ((a_pr128)->s.uFractionHigh & RT_BIT_32(15))) +#define RTFLOAT128U_IS_NAN(a_pr128) ( (a_pr128)->s.uExponent == RTFLOAT128U_EXP_MAX \ + && ( (a_pr128)->s.uFractionLow != 0 \ + || (a_pr128)->s.uFractionMid != 0 \ + || (a_pr128)->s.uFractionHigh != 0) ) +#define RTFLOAT128U_IS_NORMAL(a_pr128) ((a_pr128)->s.uExponent > 0 && (a_pr128)->s.uExponent < RTFLOAT128U_EXP_MAX) +/** @} */ + + +/** + * Packed BCD 18-digit signed integer format (80-bit). + */ +#pragma pack(1) +typedef union RTPBCD80U +{ + /** Format using bitfields. */ + RT_GCC_EXTENSION struct + { + /** 18 packed BCD digits, two to a byte. */ + uint8_t abPairs[9]; + /** Padding, non-zero if indefinite. */ + RT_GCC_EXTENSION uint8_t uPad : 7; + /** The sign indicator. */ + RT_GCC_EXTENSION uint8_t fSign : 1; + } s; + + /** 64-bit view. */ + uint64_t au64[1]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[5]; + /** 8-bit view. */ + uint8_t au8[10]; +} RTPBCD80U; +#pragma pack() +/** Pointer to a packed BCD integer format union. */ +typedef RTPBCD80U RT_FAR *PRTPBCD80U; +/** Pointer to a const packed BCD integer format union. */ +typedef const RTPBCD80U RT_FAR *PCRTPBCD80U; +/** RTPBCD80U initializer. */ +#define RTPBCD80U_INIT_C(a_fSign, a_D17, a_D16, a_D15, a_D14, a_D13, a_D12, a_D11, a_D10, \ + a_D9, a_D8, a_D7, a_D6, a_D5, a_D4, a_D3, a_D2, a_D1, a_D0) \ + RTPBCD80U_INIT_EX_C(0, a_fSign, a_D17, a_D16, a_D15, a_D14, a_D13, a_D12, a_D11, a_D10, \ + a_D9, a_D8, a_D7, a_D6, a_D5, a_D4, a_D3, a_D2, a_D1, a_D0) +/** Extended RTPBCD80U initializer. */ +#define RTPBCD80U_INIT_EX_C(a_uPad, a_fSign, a_D17, a_D16, a_D15, a_D14, a_D13, a_D12, a_D11, a_D10, \ + a_D9, a_D8, a_D7, a_D6, a_D5, a_D4, a_D3, a_D2, a_D1, a_D0) \ + { { { RTPBCD80U_MAKE_PAIR(a_D1, a_D0), \ + RTPBCD80U_MAKE_PAIR(a_D3, a_D2), \ + RTPBCD80U_MAKE_PAIR(a_D5, a_D4), \ + RTPBCD80U_MAKE_PAIR(a_D7, a_D6), \ + RTPBCD80U_MAKE_PAIR(a_D9, a_D8), \ + RTPBCD80U_MAKE_PAIR(a_D11, a_D10), \ + RTPBCD80U_MAKE_PAIR(a_D13, a_D12), \ + RTPBCD80U_MAKE_PAIR(a_D15, a_D14), \ + RTPBCD80U_MAKE_PAIR(a_D17, a_D16), }, (a_uPad), (a_fSign) } } +/** RTPBCD80U initializer for the zero value. */ +#define RTPBCD80U_INIT_ZERO(a_fSign) RTPBCD80U_INIT_C(a_fSign, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0) +/** RTPBCD80U initializer for the indefinite value. */ +#define RTPBCD80U_INIT_INDEFINITE() RTPBCD80U_INIT_EX_C(0x7f,1, 0xf,0xf, 0xc,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0) +/** RTPBCD80U initializer for the minimum value. */ +#define RTPBCD80U_INIT_MIN() RTPBCD80U_INIT_C(1, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9) +/** RTPBCD80U initializer for the maximum value. */ +#define RTPBCD80U_INIT_MAX() RTPBCD80U_INIT_C(0, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9) +/** RTPBCD80U minimum value. */ +#define RTPBCD80U_MIN INT64_C(-999999999999999999) +/** RTPBCD80U maximum value. */ +#define RTPBCD80U_MAX INT64_C(999999999999999999) +/** Makes a packs a pair of BCD digits. */ +#define RTPBCD80U_MAKE_PAIR(a_D1, a_D0) ((a_D0) | ((a_D1) << 4)) +/** Retrieves the lower digit of a BCD digit pair. */ +#define RTPBCD80U_LO_DIGIT(a_bPair) ((a_bPair) & 0xf) +/** Retrieves the higher digit of a BCD digit pair. */ +#define RTPBCD80U_HI_DIGIT(a_bPair) ((a_bPair) >> 4) +/** Checks if the packaged BCD number is representing indefinite. */ +#define RTPBCD80U_IS_INDEFINITE(a_pd80) \ + ( (a_pd80)->s.uPad == 0x7f \ + && (a_pd80)->s.fSign == 1 \ + && (a_pd80)->s.abPairs[8] == 0xff \ + && (a_pd80)->s.abPairs[7] == RTPBCD80U_MAKE_PAIR(0xc, 0) \ + && (a_pd80)->s.abPairs[6] == 0 \ + && (a_pd80)->s.abPairs[5] == 0 \ + && (a_pd80)->s.abPairs[4] == 0 \ + && (a_pd80)->s.abPairs[3] == 0 \ + && (a_pd80)->s.abPairs[2] == 0 \ + && (a_pd80)->s.abPairs[1] == 0 \ + && (a_pd80)->s.abPairs[0] == 0) +/** Check if @a a_pd80Left and @a a_pd80Right are exactly the same. */ +#define RTPBCD80U_ARE_IDENTICAL(a_pd80Left, a_pd80Right) \ + ( (a_pd80Left)->au64[0] == (a_pd80Right)->au64[0] && (a_pd80Left)->au16[4] == (a_pd80Right)->au16[4] ) + + +/** Generic function type. + * @see PFNRT + */ +typedef DECLCALLBACKTYPE(void, FNRT,(void)); + +/** Generic function pointer. + * With -pedantic, gcc-4 complains when casting a function to a data object, for + * example: + * + * @code + * void foo(void) + * { + * } + * + * void *bar = (void *)foo; + * @endcode + * + * The compiler would warn with "ISO C++ forbids casting between + * pointer-to-function and pointer-to-object". The purpose of this warning is + * not to bother the programmer but to point out that he is probably doing + * something dangerous, assigning a pointer to executable code to a data object. + */ +typedef FNRT *PFNRT; + +/** Variant on PFNRT that takes one pointer argument. */ +typedef DECLCALLBACKTYPE(void, FNRT1,(void *pvArg)); +/** Pointer to FNRT1. */ +typedef FNRT1 *PFNRT1; + +/** Millisecond interval. */ +typedef uint32_t RTMSINTERVAL; +/** Pointer to a millisecond interval. */ +typedef RTMSINTERVAL RT_FAR *PRTMSINTERVAL; +/** Pointer to a const millisecond interval. */ +typedef const RTMSINTERVAL RT_FAR *PCRTMSINTERVAL; + +/** Pointer to a time spec structure. */ +typedef struct RTTIMESPEC RT_FAR *PRTTIMESPEC; +/** Pointer to a const time spec structure. */ +typedef const struct RTTIMESPEC RT_FAR *PCRTTIMESPEC; + + + +/** @defgroup grp_rt_types_both Common Guest and Host Context Basic Types + * @{ + */ + +/** Signed integer which can contain both GC and HC pointers. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +typedef int32_t RTINTPTR; +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +typedef int64_t RTINTPTR; +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif +/** Pointer to signed integer which can contain both GC and HC pointers. */ +typedef RTINTPTR RT_FAR *PRTINTPTR; +/** Pointer const to signed integer which can contain both GC and HC pointers. */ +typedef const RTINTPTR RT_FAR *PCRTINTPTR; +/** The maximum value the RTINTPTR type can hold. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +# define RTINTPTR_MAX INT32_MAX +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +# define RTINTPTR_MAX INT64_MAX +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif +/** The minimum value the RTINTPTR type can hold. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +# define RTINTPTR_MIN INT32_MIN +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +# define RTINTPTR_MIN INT64_MIN +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif + +/** Unsigned integer which can contain both GC and HC pointers. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +typedef uint32_t RTUINTPTR; +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +typedef uint64_t RTUINTPTR; +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif +/** Pointer to unsigned integer which can contain both GC and HC pointers. */ +typedef RTUINTPTR RT_FAR *PRTUINTPTR; +/** Pointer const to unsigned integer which can contain both GC and HC pointers. */ +typedef const RTUINTPTR RT_FAR *PCRTUINTPTR; +/** The maximum value the RTUINTPTR type can hold. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +# define RTUINTPTR_MAX UINT32_MAX +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +# define RTUINTPTR_MAX UINT64_MAX +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif + +/** Signed integer. */ +typedef int32_t RTINT; +/** Pointer to signed integer. */ +typedef RTINT RT_FAR *PRTINT; +/** Pointer to const signed integer. */ +typedef const RTINT RT_FAR *PCRTINT; + +/** Unsigned integer. */ +typedef uint32_t RTUINT; +/** Pointer to unsigned integer. */ +typedef RTUINT RT_FAR *PRTUINT; +/** Pointer to const unsigned integer. */ +typedef const RTUINT RT_FAR *PCRTUINT; + +/** A file offset / size (off_t). */ +typedef int64_t RTFOFF; +/** Pointer to a file offset / size. */ +typedef RTFOFF RT_FAR *PRTFOFF; +/** The max value for RTFOFF. */ +#define RTFOFF_MAX INT64_MAX +/** The min value for RTFOFF. */ +#define RTFOFF_MIN INT64_MIN + +/** File mode (see iprt/fs.h). */ +typedef uint32_t RTFMODE; +/** Pointer to file mode. */ +typedef RTFMODE RT_FAR *PRTFMODE; + +/** Device unix number. */ +typedef uint32_t RTDEV; +/** Pointer to a device unix number. */ +typedef RTDEV RT_FAR *PRTDEV; + +/** @name RTDEV Macros + * @{ */ +/** + * Our makedev macro. + * @returns RTDEV + * @param uMajor The major device number. + * @param uMinor The minor device number. + */ +#define RTDEV_MAKE(uMajor, uMinor) ((RTDEV)( ((RTDEV)(uMajor) << 24) | (uMinor & UINT32_C(0x00ffffff)) )) +/** + * Get the major device node number from an RTDEV type. + * @returns The major device number of @a uDev + * @param uDev The device number. + */ +#define RTDEV_MAJOR(uDev) ((uDev) >> 24) +/** + * Get the minor device node number from an RTDEV type. + * @returns The minor device number of @a uDev + * @param uDev The device number. + */ +#define RTDEV_MINOR(uDev) ((uDev) & UINT32_C(0x00ffffff)) +/** @} */ + +/** i-node number. */ +typedef uint64_t RTINODE; +/** Pointer to a i-node number. */ +typedef RTINODE RT_FAR *PRTINODE; + +/** User id. */ +typedef uint32_t RTUID; +/** Pointer to a user id. */ +typedef RTUID RT_FAR *PRTUID; +/** NIL user id. + * @todo check this for portability! */ +#define NIL_RTUID (~(RTUID)0) + +/** Group id. */ +typedef uint32_t RTGID; +/** Pointer to a group id. */ +typedef RTGID RT_FAR *PRTGID; +/** NIL group id. + * @todo check this for portability! */ +#define NIL_RTGID (~(RTGID)0) + +/** I/O Port. */ +typedef uint16_t RTIOPORT; +/** Pointer to I/O Port. */ +typedef RTIOPORT RT_FAR *PRTIOPORT; +/** Pointer to const I/O Port. */ +typedef const RTIOPORT RT_FAR *PCRTIOPORT; + +/** Selector. */ +typedef uint16_t RTSEL; +/** Pointer to selector. */ +typedef RTSEL RT_FAR *PRTSEL; +/** Pointer to const selector. */ +typedef const RTSEL RT_FAR *PCRTSEL; +/** Max selector value. */ +#define RTSEL_MAX UINT16_MAX + +/** Far 16-bit pointer. */ +#pragma pack(1) +typedef struct RTFAR16 +{ + uint16_t off; + RTSEL sel; +} RTFAR16; +#pragma pack() +/** Pointer to Far 16-bit pointer. */ +typedef RTFAR16 RT_FAR *PRTFAR16; +/** Pointer to const Far 16-bit pointer. */ +typedef const RTFAR16 RT_FAR *PCRTFAR16; + +/** Far 32-bit pointer. */ +#pragma pack(1) +typedef struct RTFAR32 +{ + uint32_t off; + RTSEL sel; +} RTFAR32; +#pragma pack() +/** Pointer to Far 32-bit pointer. */ +typedef RTFAR32 RT_FAR *PRTFAR32; +/** Pointer to const Far 32-bit pointer. */ +typedef const RTFAR32 RT_FAR *PCRTFAR32; + +/** Far 64-bit pointer. */ +#pragma pack(1) +typedef struct RTFAR64 +{ + uint64_t off; + RTSEL sel; +} RTFAR64; +#pragma pack() +/** Pointer to Far 64-bit pointer. */ +typedef RTFAR64 RT_FAR *PRTFAR64; +/** Pointer to const Far 64-bit pointer. */ +typedef const RTFAR64 RT_FAR *PCRTFAR64; + +/** @} */ + + +/** @defgroup grp_rt_types_hc Host Context Basic Types + * @{ + */ + +/** HC Natural signed integer. + * @deprecated silly type. */ +typedef int32_t RTHCINT; +/** Pointer to HC Natural signed integer. + * @deprecated silly type. */ +typedef RTHCINT RT_FAR *PRTHCINT; +/** Pointer to const HC Natural signed integer. + * @deprecated silly type. */ +typedef const RTHCINT RT_FAR *PCRTHCINT; + +/** HC Natural unsigned integer. + * @deprecated silly type. */ +typedef uint32_t RTHCUINT; +/** Pointer to HC Natural unsigned integer. + * @deprecated silly type. */ +typedef RTHCUINT RT_FAR *PRTHCUINT; +/** Pointer to const HC Natural unsigned integer. + * @deprecated silly type. */ +typedef const RTHCUINT RT_FAR *PCRTHCUINT; + + +/** Signed integer which can contain a HC pointer. */ +#if HC_ARCH_BITS == 32 || HC_ARCH_BITS == 16 +typedef int32_t RTHCINTPTR; +#elif HC_ARCH_BITS == 64 +typedef int64_t RTHCINTPTR; +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** Pointer to signed integer which can contain a HC pointer. */ +typedef RTHCINTPTR RT_FAR *PRTHCINTPTR; +/** Pointer to const signed integer which can contain a HC pointer. */ +typedef const RTHCINTPTR RT_FAR *PCRTHCINTPTR; +/** Max RTHCINTPTR value. */ +#if HC_ARCH_BITS == 32 +# define RTHCINTPTR_MAX INT32_MAX +#elif HC_ARCH_BITS == 64 +# define RTHCINTPTR_MAX INT64_MAX +#else +# define RTHCINTPTR_MAX INT16_MAX +#endif +/** Min RTHCINTPTR value. */ +#if HC_ARCH_BITS == 32 +# define RTHCINTPTR_MIN INT32_MIN +#elif HC_ARCH_BITS == 64 +# define RTHCINTPTR_MIN INT64_MIN +#else +# define RTHCINTPTR_MIN INT16_MIN +#endif + +/** Signed integer which can contain a HC ring-3 pointer. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +typedef int32_t RTR3INTPTR; +#elif R3_ARCH_BITS == 64 +typedef int64_t RTR3INTPTR; +#else +# error Unsupported R3_ARCH_BITS value. +#endif +/** Pointer to signed integer which can contain a HC ring-3 pointer. */ +typedef RTR3INTPTR RT_FAR *PRTR3INTPTR; +/** Pointer to const signed integer which can contain a HC ring-3 pointer. */ +typedef const RTR3INTPTR RT_FAR *PCRTR3INTPTR; +/** Max RTR3INTPTR value. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +# define RTR3INTPTR_MAX INT32_MAX +#else +# define RTR3INTPTR_MAX INT64_MAX +#endif +/** Min RTR3INTPTR value. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +# define RTR3INTPTR_MIN INT32_MIN +#else +# define RTR3INTPTR_MIN INT64_MIN +#endif + +/** Signed integer which can contain a HC ring-0 pointer. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +typedef int32_t RTR0INTPTR; +#elif R0_ARCH_BITS == 64 +typedef int64_t RTR0INTPTR; +#else +# error Unsupported R0_ARCH_BITS value. +#endif +/** Pointer to signed integer which can contain a HC ring-0 pointer. */ +typedef RTR0INTPTR RT_FAR *PRTR0INTPTR; +/** Pointer to const signed integer which can contain a HC ring-0 pointer. */ +typedef const RTR0INTPTR RT_FAR *PCRTR0INTPTR; +/** Max RTR0INTPTR value. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +# define RTR0INTPTR_MAX INT32_MAX +#else +# define RTR0INTPTR_MAX INT64_MAX +#endif +/** Min RTHCINTPTR value. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +# define RTR0INTPTR_MIN INT32_MIN +#else +# define RTR0INTPTR_MIN INT64_MIN +#endif + + +/** Unsigned integer which can contain a HC pointer. */ +#if HC_ARCH_BITS == 32 || HC_ARCH_BITS == 16 +typedef uint32_t RTHCUINTPTR; +#elif HC_ARCH_BITS == 64 +typedef uint64_t RTHCUINTPTR; +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** Pointer to unsigned integer which can contain a HC pointer. */ +typedef RTHCUINTPTR RT_FAR *PRTHCUINTPTR; +/** Pointer to unsigned integer which can contain a HC pointer. */ +typedef const RTHCUINTPTR RT_FAR *PCRTHCUINTPTR; +/** Max RTHCUINTTPR value. */ +#if HC_ARCH_BITS == 32 || HC_ARCH_BITS == 16 +# define RTHCUINTPTR_MAX UINT32_MAX +#else +# define RTHCUINTPTR_MAX UINT64_MAX +#endif + +/** Unsigned integer which can contain a HC ring-3 pointer. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +typedef uint32_t RTR3UINTPTR; +#elif R3_ARCH_BITS == 64 +typedef uint64_t RTR3UINTPTR; +#else +# error Unsupported R3_ARCH_BITS value. +#endif +/** Pointer to unsigned integer which can contain a HC ring-3 pointer. */ +typedef RTR3UINTPTR RT_FAR *PRTR3UINTPTR; +/** Pointer to unsigned integer which can contain a HC ring-3 pointer. */ +typedef const RTR3UINTPTR RT_FAR *PCRTR3UINTPTR; +/** Max RTHCUINTTPR value. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +# define RTR3UINTPTR_MAX UINT32_MAX +#else +# define RTR3UINTPTR_MAX UINT64_MAX +#endif + +/** Unsigned integer which can contain a HC ring-0 pointer. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +typedef uint32_t RTR0UINTPTR; +#elif R0_ARCH_BITS == 64 +typedef uint64_t RTR0UINTPTR; +#else +# error Unsupported R0_ARCH_BITS value. +#endif +/** Pointer to unsigned integer which can contain a HC ring-0 pointer. */ +typedef RTR0UINTPTR RT_FAR *PRTR0UINTPTR; +/** Pointer to unsigned integer which can contain a HC ring-0 pointer. */ +typedef const RTR0UINTPTR RT_FAR *PCRTR0UINTPTR; +/** Max RTR0UINTTPR value. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +# define RTR0UINTPTR_MAX UINT32_MAX +#else +# define RTR0UINTPTR_MAX UINT64_MAX +#endif + + +/** Host Physical Memory Address. */ +typedef uint64_t RTHCPHYS; +/** Pointer to Host Physical Memory Address. */ +typedef RTHCPHYS RT_FAR *PRTHCPHYS; +/** Pointer to const Host Physical Memory Address. */ +typedef const RTHCPHYS RT_FAR *PCRTHCPHYS; +/** @def NIL_RTHCPHYS + * NIL HC Physical Address. + * NIL_RTHCPHYS is used to signal an invalid physical address, similar + * to the NULL pointer. + */ +#define NIL_RTHCPHYS (~(RTHCPHYS)0) +/** Max RTHCPHYS value. */ +#define RTHCPHYS_MAX UINT64_MAX + + +/** HC pointer. */ +#if !defined(IN_RC) || defined(DOXYGEN_RUNNING) +typedef void RT_FAR *RTHCPTR; +#else +typedef RTHCUINTPTR RTHCPTR; +#endif +/** Pointer to HC pointer. */ +typedef RTHCPTR RT_FAR *PRTHCPTR; +/** Pointer to const HC pointer. */ +typedef const RTHCPTR *PCRTHCPTR; +/** @def NIL_RTHCPTR + * NIL HC pointer. + */ +#define NIL_RTHCPTR ((RTHCPTR)0) +/** Max RTHCPTR value. */ +#define RTHCPTR_MAX ((RTHCPTR)RTHCUINTPTR_MAX) + + +/** HC ring-3 pointer. */ +#ifdef IN_RING3 +typedef void RT_FAR *RTR3PTR; +#else +typedef RTR3UINTPTR RTR3PTR; +#endif +/** Pointer to HC ring-3 pointer. */ +typedef RTR3PTR RT_FAR *PRTR3PTR; +/** Pointer to const HC ring-3 pointer. */ +typedef const RTR3PTR *PCRTR3PTR; +/** @def NIL_RTR3PTR + * NIL HC ring-3 pointer. + */ +#ifndef IN_RING3 +# define NIL_RTR3PTR ((RTR3PTR)0) +#else +# define NIL_RTR3PTR (NULL) +#endif +/** Max RTR3PTR value. */ +#define RTR3PTR_MAX ((RTR3PTR)RTR3UINTPTR_MAX) + +/** HC ring-0 pointer. */ +#ifdef IN_RING0 +typedef void RT_FAR *RTR0PTR; +#else +typedef RTR0UINTPTR RTR0PTR; +#endif +/** Pointer to HC ring-0 pointer. */ +typedef RTR0PTR RT_FAR *PRTR0PTR; +/** Pointer to const HC ring-0 pointer. */ +typedef const RTR0PTR *PCRTR0PTR; +/** @def NIL_RTR0PTR + * NIL HC ring-0 pointer. + */ +#ifndef IN_RING0 +# define NIL_RTR0PTR ((RTR0PTR)0) +#else +# define NIL_RTR0PTR (NULL) +#endif +/** Max RTR3PTR value. */ +#define RTR0PTR_MAX ((RTR0PTR)RTR0UINTPTR_MAX) + + +/** Unsigned integer register in the host context. */ +#if HC_ARCH_BITS == 32 +typedef uint32_t RTHCUINTREG; +#elif HC_ARCH_BITS == 64 +typedef uint64_t RTHCUINTREG; +#elif HC_ARCH_BITS == 16 +typedef uint16_t RTHCUINTREG; +#else +# error "Unsupported HC_ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the host context. */ +typedef RTHCUINTREG RT_FAR *PRTHCUINTREG; +/** Pointer to a const unsigned integer register in the host context. */ +typedef const RTHCUINTREG RT_FAR *PCRTHCUINTREG; + +/** Unsigned integer register in the host ring-3 context. */ +#if R3_ARCH_BITS == 32 +typedef uint32_t RTR3UINTREG; +#elif R3_ARCH_BITS == 64 +typedef uint64_t RTR3UINTREG; +#elif R3_ARCH_BITS == 16 +typedef uint16_t RTR3UINTREG; +#else +# error "Unsupported R3_ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the host ring-3 context. */ +typedef RTR3UINTREG RT_FAR *PRTR3UINTREG; +/** Pointer to a const unsigned integer register in the host ring-3 context. */ +typedef const RTR3UINTREG RT_FAR *PCRTR3UINTREG; + +/** Unsigned integer register in the host ring-3 context. */ +#if R0_ARCH_BITS == 32 +typedef uint32_t RTR0UINTREG; +#elif R0_ARCH_BITS == 64 +typedef uint64_t RTR0UINTREG; +#elif R0_ARCH_BITS == 16 +typedef uint16_t RTR0UINTREG; +#else +# error "Unsupported R3_ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the host ring-3 context. */ +typedef RTR0UINTREG RT_FAR *PRTR0UINTREG; +/** Pointer to a const unsigned integer register in the host ring-3 context. */ +typedef const RTR0UINTREG RT_FAR *PCRTR0UINTREG; + +/** @} */ + + +/** @defgroup grp_rt_types_gc Guest Context Basic Types + * @{ + */ + +/** Natural signed integer in the GC. + * @deprecated silly type. */ +#if GC_ARCH_BITS == 32 +typedef int32_t RTGCINT; +#elif GC_ARCH_BITS == 64 /** @todo this isn't right, natural int is 32-bit, see RTHCINT. */ +typedef int64_t RTGCINT; +#endif +/** Pointer to natural signed integer in GC. + * @deprecated silly type. */ +typedef RTGCINT RT_FAR *PRTGCINT; +/** Pointer to const natural signed integer in GC. + * @deprecated silly type. */ +typedef const RTGCINT RT_FAR *PCRTGCINT; + +/** Natural unsigned integer in the GC. + * @deprecated silly type. */ +#if GC_ARCH_BITS == 32 +typedef uint32_t RTGCUINT; +#elif GC_ARCH_BITS == 64 /** @todo this isn't right, natural int is 32-bit, see RTHCUINT. */ +typedef uint64_t RTGCUINT; +#endif +/** Pointer to natural unsigned integer in GC. + * @deprecated silly type. */ +typedef RTGCUINT RT_FAR *PRTGCUINT; +/** Pointer to const natural unsigned integer in GC. + * @deprecated silly type. */ +typedef const RTGCUINT RT_FAR *PCRTGCUINT; + +/** Signed integer which can contain a GC pointer. */ +#if GC_ARCH_BITS == 32 +typedef int32_t RTGCINTPTR; +#elif GC_ARCH_BITS == 64 +typedef int64_t RTGCINTPTR; +#endif +/** Pointer to signed integer which can contain a GC pointer. */ +typedef RTGCINTPTR RT_FAR *PRTGCINTPTR; +/** Pointer to const signed integer which can contain a GC pointer. */ +typedef const RTGCINTPTR RT_FAR *PCRTGCINTPTR; + +/** Unsigned integer which can contain a GC pointer. */ +#if GC_ARCH_BITS == 32 +typedef uint32_t RTGCUINTPTR; +#elif GC_ARCH_BITS == 64 +typedef uint64_t RTGCUINTPTR; +#else +# error Unsupported GC_ARCH_BITS value. +#endif +/** Pointer to unsigned integer which can contain a GC pointer. */ +typedef RTGCUINTPTR RT_FAR *PRTGCUINTPTR; +/** Pointer to unsigned integer which can contain a GC pointer. */ +typedef const RTGCUINTPTR RT_FAR *PCRTGCUINTPTR; + +/** Unsigned integer which can contain a 32 bits GC pointer. */ +typedef uint32_t RTGCUINTPTR32; +/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */ +typedef RTGCUINTPTR32 RT_FAR *PRTGCUINTPTR32; +/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */ +typedef const RTGCUINTPTR32 RT_FAR *PCRTGCUINTPTR32; + +/** Unsigned integer which can contain a 64 bits GC pointer. */ +typedef uint64_t RTGCUINTPTR64; +/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */ +typedef RTGCUINTPTR64 RT_FAR *PRTGCUINTPTR64; +/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */ +typedef const RTGCUINTPTR64 RT_FAR *PCRTGCUINTPTR64; + +/** Guest Physical Memory Address.*/ +typedef uint64_t RTGCPHYS; +/** Pointer to Guest Physical Memory Address. */ +typedef RTGCPHYS RT_FAR *PRTGCPHYS; +/** Pointer to const Guest Physical Memory Address. */ +typedef const RTGCPHYS RT_FAR *PCRTGCPHYS; +/** @def NIL_RTGCPHYS + * NIL GC Physical Address. + * NIL_RTGCPHYS is used to signal an invalid physical address, similar + * to the NULL pointer. Note that this value may actually be valid in + * some contexts. + */ +#define NIL_RTGCPHYS (~(RTGCPHYS)0U) +/** Max guest physical memory address value. */ +#define RTGCPHYS_MAX UINT64_MAX + + +/** Guest Physical Memory Address; limited to 32 bits.*/ +typedef uint32_t RTGCPHYS32; +/** Pointer to Guest Physical Memory Address. */ +typedef RTGCPHYS32 RT_FAR *PRTGCPHYS32; +/** Pointer to const Guest Physical Memory Address. */ +typedef const RTGCPHYS32 RT_FAR *PCRTGCPHYS32; +/** @def NIL_RTGCPHYS32 + * NIL GC Physical Address. + * NIL_RTGCPHYS32 is used to signal an invalid physical address, similar + * to the NULL pointer. Note that this value may actually be valid in + * some contexts. + */ +#define NIL_RTGCPHYS32 (~(RTGCPHYS32)0) + + +/** Guest Physical Memory Address; limited to 64 bits.*/ +typedef uint64_t RTGCPHYS64; +/** Pointer to Guest Physical Memory Address. */ +typedef RTGCPHYS64 RT_FAR *PRTGCPHYS64; +/** Pointer to const Guest Physical Memory Address. */ +typedef const RTGCPHYS64 RT_FAR *PCRTGCPHYS64; +/** @def NIL_RTGCPHYS64 + * NIL GC Physical Address. + * NIL_RTGCPHYS64 is used to signal an invalid physical address, similar + * to the NULL pointer. Note that this value may actually be valid in + * some contexts. + */ +#define NIL_RTGCPHYS64 (~(RTGCPHYS64)0) + +/** Guest context pointer, 32 bits. + * Keep in mind that this type is an unsigned integer in + * HC and void pointer in GC. + */ +typedef RTGCUINTPTR32 RTGCPTR32; +/** Pointer to a guest context pointer. */ +typedef RTGCPTR32 RT_FAR *PRTGCPTR32; +/** Pointer to a const guest context pointer. */ +typedef const RTGCPTR32 RT_FAR *PCRTGCPTR32; +/** @def NIL_RTGCPTR32 + * NIL GC pointer. + */ +#define NIL_RTGCPTR32 ((RTGCPTR32)0) + +/** Guest context pointer, 64 bits. + */ +typedef RTGCUINTPTR64 RTGCPTR64; +/** Pointer to a guest context pointer. */ +typedef RTGCPTR64 RT_FAR *PRTGCPTR64; +/** Pointer to a const guest context pointer. */ +typedef const RTGCPTR64 RT_FAR *PCRTGCPTR64; +/** @def NIL_RTGCPTR64 + * NIL GC pointer. + */ +#define NIL_RTGCPTR64 ((RTGCPTR64)0) + +/** @typedef RTGCPTR + * Guest context pointer. + * Keep in mind that this type is an unsigned integer in HC and void pointer in GC. */ +/** @typedef PRTGCPTR + * Pointer to a guest context pointer. */ +/** @typedef PCRTGCPTR + * Pointer to a const guest context pointer. */ +/** @def NIL_RTGCPTR + * NIL GC pointer. */ +/** @def RTGCPTR_MAX + * Max RTGCPTR value. */ +#if GC_ARCH_BITS == 64 || defined(DOXYGEN_RUNNING) +typedef RTGCPTR64 RTGCPTR; +typedef PRTGCPTR64 PRTGCPTR; +typedef PCRTGCPTR64 PCRTGCPTR; +# define NIL_RTGCPTR NIL_RTGCPTR64 +# define RTGCPTR_MAX UINT64_MAX +#elif GC_ARCH_BITS == 32 +typedef RTGCPTR32 RTGCPTR; +typedef PRTGCPTR32 PRTGCPTR; +typedef PCRTGCPTR32 PCRTGCPTR; +# define NIL_RTGCPTR NIL_RTGCPTR32 +# define RTGCPTR_MAX UINT32_MAX +#else +# error "Unsupported GC_ARCH_BITS!" +#endif + +/** Unsigned integer register in the guest context. */ +typedef uint32_t RTGCUINTREG32; +/** Pointer to an unsigned integer register in the guest context. */ +typedef RTGCUINTREG32 RT_FAR *PRTGCUINTREG32; +/** Pointer to a const unsigned integer register in the guest context. */ +typedef const RTGCUINTREG32 RT_FAR *PCRTGCUINTREG32; + +typedef uint64_t RTGCUINTREG64; +/** Pointer to an unsigned integer register in the guest context. */ +typedef RTGCUINTREG64 RT_FAR *PRTGCUINTREG64; +/** Pointer to a const unsigned integer register in the guest context. */ +typedef const RTGCUINTREG64 RT_FAR *PCRTGCUINTREG64; + +#if GC_ARCH_BITS == 64 +typedef RTGCUINTREG64 RTGCUINTREG; +#elif GC_ARCH_BITS == 32 +typedef RTGCUINTREG32 RTGCUINTREG; +#else +# error "Unsupported GC_ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the guest context. */ +typedef RTGCUINTREG RT_FAR *PRTGCUINTREG; +/** Pointer to a const unsigned integer register in the guest context. */ +typedef const RTGCUINTREG RT_FAR *PCRTGCUINTREG; + +/** @} */ + +/** @defgroup grp_rt_types_rc Raw mode Context Basic Types + * @{ + */ + +/** Raw mode context pointer; a 32 bits guest context pointer. + * Keep in mind that this type is an unsigned integer in + * HC and void pointer in RC. + */ +#ifdef IN_RC +typedef void RT_FAR *RTRCPTR; +#else +typedef uint32_t RTRCPTR; +#endif +/** Pointer to a raw mode context pointer. */ +typedef RTRCPTR RT_FAR *PRTRCPTR; +/** Pointer to a const raw mode context pointer. */ +typedef const RTRCPTR RT_FAR *PCRTRCPTR; +/** @def NIL_RTRCPTR + * NIL RC pointer. */ +#ifdef IN_RC +# define NIL_RTRCPTR (NULL) +#else +# define NIL_RTRCPTR ((RTRCPTR)0) +#endif +/** @def RTRCPTR_MAX + * The maximum value a RTRCPTR can have. Mostly used as INVALID value. + */ +#define RTRCPTR_MAX ((RTRCPTR)UINT32_MAX) + +/** Raw mode context pointer, unsigned integer variant. */ +typedef int32_t RTRCINTPTR; +/** @def RTRCUINTPTR_MAX + * The maximum value a RTRCUINPTR can have. + */ +#define RTRCUINTPTR_MAX ((RTRCUINTPTR)UINT32_MAX) + +/** Raw mode context pointer, signed integer variant. */ +typedef uint32_t RTRCUINTPTR; +/** @def RTRCINTPTR_MIN + * The minimum value a RTRCINPTR can have. + */ +#define RTRCINTPTR_MIN ((RTRCINTPTR)INT32_MIN) +/** @def RTRCINTPTR_MAX + * The maximum value a RTRCINPTR can have. + */ +#define RTRCINTPTR_MAX ((RTRCINTPTR)INT32_MAX) + +/* The following are only temporarily while we clean up RTRCPTR usage: */ +#ifdef IN_RC +typedef void RT_FAR *RTRGPTR; +#else +typedef uint64_t RTRGPTR; +#endif +typedef RTRGPTR RT_FAR *PRTRGPTR; +typedef const RTRGPTR RT_FAR *PCRTRGPTR; +#ifdef IN_RC +# define NIL_RTRGPTR (NULL) +#else +# define NIL_RTRGPTR ((RTRGPTR)0) +#endif + +/** @} */ + + +/** @defgroup grp_rt_types_cc Current Context Basic Types + * @{ + */ + +/** Current Context Physical Memory Address.*/ +#ifdef IN_RC +typedef RTGCPHYS RTCCPHYS; +#else +typedef RTHCPHYS RTCCPHYS; +#endif +/** Pointer to Current Context Physical Memory Address. */ +typedef RTCCPHYS RT_FAR *PRTCCPHYS; +/** Pointer to const Current Context Physical Memory Address. */ +typedef const RTCCPHYS RT_FAR *PCRTCCPHYS; +/** @def NIL_RTCCPHYS + * NIL CC Physical Address. + * NIL_RTCCPHYS is used to signal an invalid physical address, similar + * to the NULL pointer. + */ +#ifdef IN_RC +# define NIL_RTCCPHYS NIL_RTGCPHYS +#else +# define NIL_RTCCPHYS NIL_RTHCPHYS +#endif + +/** Unsigned integer register in the current context. */ +#if ARCH_BITS == 32 +typedef uint32_t RTCCUINTREG; +#elif ARCH_BITS == 64 +typedef uint64_t RTCCUINTREG; +#elif ARCH_BITS == 16 +typedef uint16_t RTCCUINTREG; +#else +# error "Unsupported ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the current context. */ +typedef RTCCUINTREG RT_FAR *PRTCCUINTREG; +/** Pointer to a const unsigned integer register in the current context. */ +typedef RTCCUINTREG const RT_FAR *PCRTCCUINTREG; + +/** Signed integer register in the current context. */ +#if ARCH_BITS == 32 +typedef int32_t RTCCINTREG; +#elif ARCH_BITS == 64 +typedef int64_t RTCCINTREG; +#elif ARCH_BITS == 16 +typedef int16_t RTCCINTREG; +#endif +/** Pointer to a signed integer register in the current context. */ +typedef RTCCINTREG RT_FAR *PRTCCINTREG; +/** Pointer to a const signed integer register in the current context. */ +typedef RTCCINTREG const RT_FAR *PCRTCCINTREG; + +/** Unsigned integer register in the current context. + * @remarks This is for dealing with EAX in 16-bit mode. */ +#if ARCH_BITS == 16 && defined(RT_ARCH_X86) +typedef uint32_t RTCCUINTXREG; +#else +typedef RTCCUINTREG RTCCUINTXREG; +#endif +/** Pointer to an unsigned integer register in the current context. */ +typedef RTCCUINTREG RT_FAR *PRTCCUINTXREG; +/** Pointer to a const unsigned integer register in the current context. */ +typedef RTCCUINTREG const RT_FAR *PCRTCCUINTXREG; + +/** Signed integer extended register in the current context. + * @remarks This is for dealing with EAX in 16-bit mode. */ +#if ARCH_BITS == 16 && defined(RT_ARCH_X86) +typedef int32_t RTCCINTXREG; +#else +typedef RTCCINTREG RTCCINTXREG; +#endif +/** Pointer to a signed integer extended register in the current context. */ +typedef RTCCINTXREG RT_FAR *PRTCCINTXREG; +/** Pointer to a const signed integer extended register in the current + * context. */ +typedef RTCCINTXREG const RT_FAR *PCRTCCINTXREG; + +/** @def RTCCUINTREG_C + * Defines a constant of RTCCUINTREG type. + * @param a_Value Constant value */ +/** @def RTCCUINTREG_MAX + * Max value that RTCCUINTREG can hold. */ +/** @def RTCCUINTREG_FMT + * Generic IPRT format specifier for RTCCUINTREG. */ +/** @def RTCCUINTREG_XFMT + * Generic IPRT format specifier for RTCCUINTREG, hexadecimal. */ +/** @def RTCCINTREG_C + * Defines a constant of RTCCINTREG type. + * @param a_Value Constant value */ +/** @def RTCCINTREG_MAX + * Max value that RTCCINTREG can hold. */ +/** @def RTCCINTREG_MIN + * Min value that RTCCINTREG can hold. */ +/** @def RTCCINTREG_XFMT + * Generic IPRT format specifier for RTCCINTREG, hexadecimal. */ +#if ARCH_BITS == 32 +# define RTCCUINTREG_C(a_Value) UINT32_C(a_Value) +# define RTCCUINTREG_MAX UINT32_MAX +# define RTCCUINTREG_FMT "RU32" +# define RTCCUINTREG_XFMT "RX32" +# define RTCCINTREG_C(a_Value) INT32_C(a_Value) +# define RTCCINTREG_MAX INT32_MAX +# define RTCCINTREG_MIN INT32_MIN +# define RTCCINTREG_FMT "RI32" +# define RTCCINTREG_XFMT "RX32" +#elif ARCH_BITS == 64 +# define RTCCUINTREG_C(a_Value) UINT64_C(a_Value) +# define RTCCUINTREG_MAX UINT64_MAX +# define RTCCUINTREG_FMT "RU64" +# define RTCCUINTREG_XFMT "RX64" +# define RTCCINTREG_C(a_Value) INT64_C(a_Value) +# define RTCCINTREG_MAX INT64_MAX +# define RTCCINTREG_MIN INT64_MIN +# define RTCCINTREG_FMT "RI64" +# define RTCCINTREG_XFMT "RX64" +#elif ARCH_BITS == 16 +# define RTCCUINTREG_C(a_Value) UINT16_C(a_Value) +# define RTCCUINTREG_MAX UINT16_MAX +# define RTCCUINTREG_FMT "RU16" +# define RTCCUINTREG_XFMT "RX16" +# define RTCCINTREG_C(a_Value) INT16_C(a_Value) +# define RTCCINTREG_MAX INT16_MAX +# define RTCCINTREG_MIN INT16_MIN +# define RTCCINTREG_FMT "RI16" +# define RTCCINTREG_XFMT "RX16" +#else +# error "Unsupported ARCH_BITS!" +#endif +/** @def RTCCUINTXREG_C + * Defines a constant of RTCCUINTXREG type. + * @param a_Value Constant value */ +/** @def RTCCUINTXREG_MAX + * Max value that RTCCUINTXREG can hold. */ +/** @def RTCCUINTXREG_FMT + * Generic IPRT format specifier for RTCCUINTXREG. */ +/** @def RTCCUINTXREG_XFMT + * Generic IPRT format specifier for RTCCUINTXREG, hexadecimal. */ +/** @def RTCCINTXREG_C + * Defines a constant of RTCCINTXREG type. + * @param a_Value Constant value */ +/** @def RTCCINTXREG_MAX + * Max value that RTCCINTXREG can hold. */ +/** @def RTCCINTXREG_MIN + * Min value that RTCCINTXREG can hold. */ +/** @def RTCCINTXREG_FMT + * Generic IPRT format specifier for RTCCINTXREG. */ +/** @def RTCCINTXREG_XFMT + * Generic IPRT format specifier for RTCCINTXREG, hexadecimal. */ +/** @def RTCCINTXREG_BITS + * The width of RTCCINTXREG in bits (32 or 64). */ +#if ARCH_BITS == 16 && defined(RT_ARCH_X86) +# define RTCCUINTXREG_C(a_Value) UINT32_C(a_Value) +# define RTCCUINTXREG_MAX UINT32_MAX +# define RTCCUINTXREG_FMT "RU32" +# define RTCCUINTXREG_XFMT "RX32" +# define RTCCINTXREG_C(a_Value) INT32_C(a_Value) +# define RTCCINTXREG_MAX INT32_MAX +# define RTCCINTXREG_MIN INT32_MIN +# define RTCCINTXREG_FMT "RI32" +# define RTCCINTXREG_XFMT "RX32" +# define RTCCINTXREG_BITS 32 +#else +# define RTCCUINTXREG_C(a_Value) RTCCUINTREG_C(a_Value) +# define RTCCUINTXREG_MAX RTCCUINTREG_MAX +# define RTCCUINTXREG_FMT RTCCUINTREG_FMT +# define RTCCUINTXREG_XFMT RTCCUINTREG_XFMT +# define RTCCINTXREG_C(a_Value) RTCCINTREG_C(a_Value) +# define RTCCINTXREG_MAX RTCCINTREG_MAX +# define RTCCINTXREG_MIN RTCCINTREG_MIN +# define RTCCINTXREG_FMT RTCCINTREG_FMT +# define RTCCINTXREG_XFMT RTCCINTREG_XFMT +# define RTCCINTXREG_BITS ARCH_BITS +#endif +/** @} */ + + + +/** Pointer to a big integer number. */ +typedef struct RTBIGNUM RT_FAR *PRTBIGNUM; +/** Pointer to a const big integer number. */ +typedef struct RTBIGNUM const RT_FAR *PCRTBIGNUM; + + +/** Pointer to a critical section. */ +typedef struct RTCRITSECT RT_FAR *PRTCRITSECT; +/** Pointer to a const critical section. */ +typedef const struct RTCRITSECT RT_FAR *PCRTCRITSECT; + +/** Pointer to a read/write critical section. */ +typedef struct RTCRITSECTRW RT_FAR *PRTCRITSECTRW; +/** Pointer to a const read/write critical section. */ +typedef const struct RTCRITSECTRW RT_FAR *PCRTCRITSECTRW; + + +/** Condition variable handle. */ +typedef R3PTRTYPE(struct RTCONDVARINTERNAL RT_FAR *) RTCONDVAR; +/** Pointer to a condition variable handle. */ +typedef RTCONDVAR RT_FAR *PRTCONDVAR; +/** Nil condition variable handle. */ +#define NIL_RTCONDVAR 0 + +/** Cryptographic (certificate) store handle. */ +typedef R3R0PTRTYPE(struct RTCRSTOREINT RT_FAR *) RTCRSTORE; +/** Pointer to a Cryptographic (certificate) store handle. */ +typedef RTCRSTORE RT_FAR *PRTCRSTORE; +/** Nil Cryptographic (certificate) store handle. */ +#define NIL_RTCRSTORE 0 + +/** Pointer to a const (store) certificate context. */ +typedef struct RTCRCERTCTX const RT_FAR *PCRTCRCERTCTX; + +/** Cryptographic message digest handle. */ +typedef R3R0PTRTYPE(struct RTCRDIGESTINT RT_FAR *) RTCRDIGEST; +/** Pointer to a cryptographic message digest handle. */ +typedef RTCRDIGEST RT_FAR *PRTCRDIGEST; +/** NIL cryptographic message digest handle. */ +#define NIL_RTCRDIGEST (0) + +/** Cryptographic key handle. */ +typedef R3R0PTRTYPE(struct RTCRKEYINT RT_FAR *) RTCRKEY; +/** Pointer to a cryptographic key handle. */ +typedef RTCRKEY RT_FAR *PRTCRKEY; +/** Cryptographic key handle nil value. */ +#define NIL_RTCRKEY (0) + +/** Public key encryption schema handle. */ +typedef R3R0PTRTYPE(struct RTCRPKIXENCRYPTIONINT RT_FAR *) RTCRPKIXENCRYPTION; +/** Pointer to a public key encryption schema handle. */ +typedef RTCRPKIXENCRYPTION RT_FAR *PRTCRPKIXENCRYPTION; +/** NIL public key encryption schema handle */ +#define NIL_RTCRPKIXENCRYPTION (0) + +/** Public key signature schema handle. */ +typedef R3R0PTRTYPE(struct RTCRPKIXSIGNATUREINT RT_FAR *) RTCRPKIXSIGNATURE; +/** Pointer to a public key signature schema handle. */ +typedef RTCRPKIXSIGNATURE RT_FAR *PRTCRPKIXSIGNATURE; +/** NIL public key signature schema handle */ +#define NIL_RTCRPKIXSIGNATURE (0) + +/** X.509 certificate paths builder & validator handle. */ +typedef R3R0PTRTYPE(struct RTCRX509CERTPATHSINT RT_FAR *) RTCRX509CERTPATHS; +/** Pointer to a certificate paths builder & validator handle. */ +typedef RTCRX509CERTPATHS RT_FAR *PRTCRX509CERTPATHS; +/** Nil certificate paths builder & validator handle. */ +#define NIL_RTCRX509CERTPATHS 0 + +/** Directory handle. */ +typedef struct RTDIRINTERNAL *RTDIR; +/** Pointer to directory handle. */ +typedef RTDIR *PRTDIR; +/** NIL directory handle. */ +#define NIL_RTDIR ((RTDIR)0) + +/** File handle. */ +typedef R3R0PTRTYPE(struct RTFILEINT RT_FAR *) RTFILE; +/** Pointer to file handle. */ +typedef RTFILE RT_FAR *PRTFILE; +/** Nil file handle. */ +#define NIL_RTFILE ((RTFILE)~(RTHCINTPTR)0) + +/** Async I/O request handle. */ +typedef R3PTRTYPE(struct RTFILEAIOREQINTERNAL RT_FAR *) RTFILEAIOREQ; +/** Pointer to an async I/O request handle. */ +typedef RTFILEAIOREQ RT_FAR *PRTFILEAIOREQ; +/** Nil request handle. */ +#define NIL_RTFILEAIOREQ 0 + +/** Async I/O completion context handle. */ +typedef R3PTRTYPE(struct RTFILEAIOCTXINTERNAL RT_FAR *) RTFILEAIOCTX; +/** Pointer to an async I/O completion context handle. */ +typedef RTFILEAIOCTX RT_FAR *PRTFILEAIOCTX; +/** Nil context handle. */ +#define NIL_RTFILEAIOCTX 0 + +/** ISO image maker handle. */ +typedef struct RTFSISOMAKERINT RT_FAR *RTFSISOMAKER; +/** Pointer to an ISO image maker handle. */ +typedef RTFSISOMAKER RT_FAR *PRTFSISOMAKER; +/** NIL ISO maker handle. */ +#define NIL_RTFSISOMAKER ((RTFSISOMAKER)0) + +/** INI-file handle. */ +typedef struct RTINIFILEINT RT_FAR *RTINIFILE; +/** Pointer to an INI-file handle. */ +typedef RTINIFILE RT_FAR *PRTINIFILE; +/** NIL INI-file handle. */ +#define NIL_RTINIFILE ((RTINIFILE)0) + +/** Loader module handle. */ +typedef R3R0PTRTYPE(struct RTLDRMODINTERNAL RT_FAR *) RTLDRMOD; +/** Pointer to a loader module handle. */ +typedef RTLDRMOD RT_FAR *PRTLDRMOD; +/** Nil loader module handle. */ +#define NIL_RTLDRMOD 0 + +/** Lock validator class handle. */ +typedef R3R0PTRTYPE(struct RTLOCKVALCLASSINT RT_FAR *) RTLOCKVALCLASS; +/** Pointer to a lock validator class handle. */ +typedef RTLOCKVALCLASS RT_FAR *PRTLOCKVALCLASS; +/** Nil lock validator class handle. */ +#define NIL_RTLOCKVALCLASS ((RTLOCKVALCLASS)0) + +/** Ring-0 memory object handle. */ +typedef R0PTRTYPE(struct RTR0MEMOBJINTERNAL RT_FAR *) RTR0MEMOBJ; +/** Pointer to a Ring-0 memory object handle. */ +typedef RTR0MEMOBJ RT_FAR *PRTR0MEMOBJ; +/** Nil ring-0 memory object handle. */ +#define NIL_RTR0MEMOBJ 0 + +/** Native thread handle. */ +typedef RTHCUINTPTR RTNATIVETHREAD; +/** Pointer to an native thread handle. */ +typedef RTNATIVETHREAD RT_FAR *PRTNATIVETHREAD; +/** Nil native thread handle. */ +#define NIL_RTNATIVETHREAD (~(RTNATIVETHREAD)0) + +/** Pipe handle. */ +typedef R3R0PTRTYPE(struct RTPIPEINTERNAL RT_FAR *) RTPIPE; +/** Pointer to a pipe handle. */ +typedef RTPIPE RT_FAR *PRTPIPE; +/** Nil pipe handle. + * @remarks This is not 0 because of UNIX and OS/2 handle values. Take care! */ +#define NIL_RTPIPE ((RTPIPE)RTHCUINTPTR_MAX) + +/** @typedef RTPOLLSET + * Poll set handle. */ +typedef R3R0PTRTYPE(struct RTPOLLSETINTERNAL RT_FAR *) RTPOLLSET; +/** Pointer to a poll set handle. */ +typedef RTPOLLSET RT_FAR *PRTPOLLSET; +/** Nil poll set handle handle. */ +#define NIL_RTPOLLSET ((RTPOLLSET)0) + +/** Process identifier. */ +typedef uint32_t RTPROCESS; +/** Pointer to a process identifier. */ +typedef RTPROCESS RT_FAR *PRTPROCESS; +/** Nil process identifier. */ +#define NIL_RTPROCESS (~(RTPROCESS)0) + +/** Process ring-0 handle. */ +typedef RTR0UINTPTR RTR0PROCESS; +/** Pointer to a ring-0 process handle. */ +typedef RTR0PROCESS RT_FAR *PRTR0PROCESS; +/** Nil ring-0 process handle. */ +#define NIL_RTR0PROCESS (~(RTR0PROCESS)0) + +/** @typedef RTSEMEVENT + * Event Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMEVENTINTERNAL RT_FAR *) RTSEMEVENT; +/** Pointer to an event semaphore handle. */ +typedef RTSEMEVENT RT_FAR *PRTSEMEVENT; +/** Nil event semaphore handle. */ +#define NIL_RTSEMEVENT 0 + +/** @typedef RTSEMEVENTMULTI + * Event Multiple Release Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMEVENTMULTIINTERNAL RT_FAR *) RTSEMEVENTMULTI; +/** Pointer to an event multiple release semaphore handle. */ +typedef RTSEMEVENTMULTI RT_FAR *PRTSEMEVENTMULTI; +/** Nil multiple release event semaphore handle. */ +#define NIL_RTSEMEVENTMULTI 0 + +/** @typedef RTSEMFASTMUTEX + * Fast mutex Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMFASTMUTEXINTERNAL RT_FAR *) RTSEMFASTMUTEX; +/** Pointer to a fast mutex semaphore handle. */ +typedef RTSEMFASTMUTEX RT_FAR *PRTSEMFASTMUTEX; +/** Nil fast mutex semaphore handle. */ +#define NIL_RTSEMFASTMUTEX 0 + +/** @typedef RTSEMMUTEX + * Mutex Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMMUTEXINTERNAL RT_FAR *) RTSEMMUTEX; +/** Pointer to a mutex semaphore handle. */ +typedef RTSEMMUTEX RT_FAR *PRTSEMMUTEX; +/** Nil mutex semaphore handle. */ +#define NIL_RTSEMMUTEX 0 + +/** @typedef RTSEMSPINMUTEX + * Spinning mutex Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMSPINMUTEXINTERNAL RT_FAR *) RTSEMSPINMUTEX; +/** Pointer to a spinning mutex semaphore handle. */ +typedef RTSEMSPINMUTEX RT_FAR *PRTSEMSPINMUTEX; +/** Nil spinning mutex semaphore handle. */ +#define NIL_RTSEMSPINMUTEX 0 + +/** @typedef RTSEMRW + * Read/Write Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMRWINTERNAL RT_FAR *) RTSEMRW; +/** Pointer to a read/write semaphore handle. */ +typedef RTSEMRW RT_FAR *PRTSEMRW; +/** Nil read/write semaphore handle. */ +#define NIL_RTSEMRW 0 + +/** @typedef RTSEMXROADS + * Crossroads semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMXROADSINTERNAL RT_FAR *) RTSEMXROADS; +/** Pointer to a crossroads semaphore handle. */ +typedef RTSEMXROADS RT_FAR *PRTSEMXROADS; +/** Nil crossroads semaphore handle. */ +#define NIL_RTSEMXROADS ((RTSEMXROADS)0) + +/** Spinlock handle. */ +typedef R3R0PTRTYPE(struct RTSPINLOCKINTERNAL RT_FAR *) RTSPINLOCK; +/** Pointer to a spinlock handle. */ +typedef RTSPINLOCK RT_FAR *PRTSPINLOCK; +/** Nil spinlock handle. */ +#define NIL_RTSPINLOCK 0 + +/** Socket handle. */ +typedef R3R0PTRTYPE(struct RTSOCKETINT RT_FAR *) RTSOCKET; +/** Pointer to socket handle. */ +typedef RTSOCKET RT_FAR *PRTSOCKET; +/** Nil socket handle. */ +#define NIL_RTSOCKET ((RTSOCKET)0) + +/** Pointer to a RTTCPSERVER handle. */ +typedef struct RTTCPSERVER RT_FAR *PRTTCPSERVER; +/** Pointer to a RTTCPSERVER handle. */ +typedef PRTTCPSERVER RT_FAR *PPRTTCPSERVER; +/** Nil RTTCPSERVER handle. */ +#define NIL_RTTCPSERVER ((PRTTCPSERVER)0) + +/** Pointer to a RTUDPSERVER handle. */ +typedef struct RTUDPSERVER RT_FAR *PRTUDPSERVER; +/** Pointer to a RTUDPSERVER handle. */ +typedef PRTUDPSERVER RT_FAR *PPRTUDPSERVER; +/** Nil RTUDPSERVER handle. */ +#define NIL_RTUDPSERVER ((PRTUDPSERVER)0) + +/** Thread handle.*/ +typedef R3R0PTRTYPE(struct RTTHREADINT RT_FAR *) RTTHREAD; +/** Pointer to thread handle. */ +typedef RTTHREAD RT_FAR *PRTTHREAD; +/** Nil thread handle. */ +#define NIL_RTTHREAD 0 + +/** Thread context switching hook handle. */ +typedef R0PTRTYPE(struct RTTHREADCTXHOOKINT RT_FAR *) RTTHREADCTXHOOK; +/** Pointer to Thread context switching hook handle. */ +typedef RTTHREADCTXHOOK RT_FAR *PRTTHREADCTXHOOK; +/** Nil Thread context switching hook handle. */ +#define NIL_RTTHREADCTXHOOK ((RTTHREADCTXHOOK)0) + +/** A TLS index. */ +typedef RTHCINTPTR RTTLS; +/** Pointer to a TLS index. */ +typedef RTTLS RT_FAR *PRTTLS; +/** Pointer to a const TLS index. */ +typedef RTTLS const RT_FAR *PCRTTLS; +/** NIL TLS index value. */ +#define NIL_RTTLS ((RTTLS)-1) + +/** Trace buffer handle. + * @remarks This is not a R3/R0 type like most other handles! + */ +typedef struct RTTRACEBUFINT RT_FAR *RTTRACEBUF; +/** Pointer to a trace buffer handle. */ +typedef RTTRACEBUF RT_FAR *PRTTRACEBUF; +/** Nil trace buffer handle. */ +#define NIL_RTTRACEBUF ((RTTRACEBUF)0) +/** The handle of the default trace buffer. + * This can be used with any of the RTTraceBufAdd APIs. */ +#define RTTRACEBUF_DEFAULT ((RTTRACEBUF)-2) + +/** Handle to a simple heap. */ +typedef R3R0PTRTYPE(struct RTHEAPSIMPLEINTERNAL RT_FAR *) RTHEAPSIMPLE; +/** Pointer to a handle to a simple heap. */ +typedef RTHEAPSIMPLE RT_FAR *PRTHEAPSIMPLE; +/** NIL simple heap handle. */ +#define NIL_RTHEAPSIMPLE ((RTHEAPSIMPLE)0) + +/** Handle to an offset based heap. */ +typedef R3R0PTRTYPE(struct RTHEAPOFFSETINTERNAL RT_FAR *) RTHEAPOFFSET; +/** Pointer to a handle to an offset based heap. */ +typedef RTHEAPOFFSET RT_FAR *PRTHEAPOFFSET; +/** NIL offset based heap handle. */ +#define NIL_RTHEAPOFFSET ((RTHEAPOFFSET)0) + +/** Handle to an environment block. */ +typedef R3PTRTYPE(struct RTENVINTERNAL RT_FAR *) RTENV; +/** Pointer to a handle to an environment block. */ +typedef RTENV RT_FAR *PRTENV; +/** NIL simple heap handle. */ +#define NIL_RTENV ((RTENV)0) + +/** A CPU identifier. + * @remarks This doesn't have to correspond to the APIC ID (intel/amd). Nor + * does it have to correspond to the bits in the affinity mask, at + * least not until we've sorted out Windows NT. */ +typedef uint32_t RTCPUID; +/** Pointer to a CPU identifier. */ +typedef RTCPUID RT_FAR *PRTCPUID; +/** Pointer to a const CPU identifier. */ +typedef RTCPUID const RT_FAR *PCRTCPUID; +/** Nil CPU Id. */ +#define NIL_RTCPUID ((RTCPUID)~0) + +/** The maximum number of CPUs a set can contain and IPRT is able + * to reference. (Should be max of support arch/platforms.) + * @remarks Must be a power of two and multiple of 64 (see RTCPUSET). */ +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +# if defined(RT_OS_OS2) +# define RTCPUSET_MAX_CPUS 64 +# elif defined(RT_OS_DARWIN) || defined(RT_ARCH_X86) +# define RTCPUSET_MAX_CPUS 256 +# else +# define RTCPUSET_MAX_CPUS 1024 +# endif +#elif defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) +# define RTCPUSET_MAX_CPUS 1024 +#else +# define RTCPUSET_MAX_CPUS 64 +#endif +/** A CPU set. + * @note Treat this as an opaque type and always use RTCpuSet* for + * manipulating it. */ +typedef struct RTCPUSET +{ + /** The bitmap. */ + uint64_t bmSet[RTCPUSET_MAX_CPUS / 64]; +} RTCPUSET; +/** Pointer to a CPU set. */ +typedef RTCPUSET RT_FAR *PRTCPUSET; +/** Pointer to a const CPU set. */ +typedef RTCPUSET const RT_FAR *PCRTCPUSET; + +/** A handle table handle. */ +typedef R3R0PTRTYPE(struct RTHANDLETABLEINT RT_FAR *) RTHANDLETABLE; +/** A pointer to a handle table handle. */ +typedef RTHANDLETABLE RT_FAR *PRTHANDLETABLE; +/** @def NIL_RTHANDLETABLE + * NIL handle table handle. */ +#define NIL_RTHANDLETABLE ((RTHANDLETABLE)0) + +/** A handle to a low resolution timer. */ +typedef R3R0PTRTYPE(struct RTTIMERLRINT RT_FAR *) RTTIMERLR; +/** A pointer to a low resolution timer handle. */ +typedef RTTIMERLR RT_FAR *PRTTIMERLR; +/** @def NIL_RTTIMERLR + * NIL low resolution timer handle value. */ +#define NIL_RTTIMERLR ((RTTIMERLR)0) + +/** Handle to a random number generator. */ +typedef R3R0PTRTYPE(struct RTRANDINT RT_FAR *) RTRAND; +/** Pointer to a random number generator handle. */ +typedef RTRAND RT_FAR *PRTRAND; +/** NIL random number generator handle value. */ +#define NIL_RTRAND ((RTRAND)0) + +/** Debug address space handle. */ +typedef R3R0PTRTYPE(struct RTDBGASINT RT_FAR *) RTDBGAS; +/** Pointer to a debug address space handle. */ +typedef RTDBGAS RT_FAR *PRTDBGAS; +/** NIL debug address space handle. */ +#define NIL_RTDBGAS ((RTDBGAS)0) + +/** Debug module handle. */ +typedef R3R0PTRTYPE(struct RTDBGMODINT RT_FAR *) RTDBGMOD; +/** Pointer to a debug module handle. */ +typedef RTDBGMOD RT_FAR *PRTDBGMOD; +/** NIL debug module handle. */ +#define NIL_RTDBGMOD ((RTDBGMOD)0) + +/** Pointer to an unwind machine state. */ +typedef struct RTDBGUNWINDSTATE RT_FAR *PRTDBGUNWINDSTATE; +/** Pointer to a const unwind machine state. */ +typedef struct RTDBGUNWINDSTATE const RT_FAR *PCRTDBGUNWINDSTATE; + +/** Manifest handle. */ +typedef struct RTMANIFESTINT RT_FAR *RTMANIFEST; +/** Pointer to a manifest handle. */ +typedef RTMANIFEST RT_FAR *PRTMANIFEST; +/** NIL manifest handle. */ +#define NIL_RTMANIFEST ((RTMANIFEST)~(uintptr_t)0) + +/** Memory pool handle. */ +typedef R3R0PTRTYPE(struct RTMEMPOOLINT RT_FAR *) RTMEMPOOL; +/** Pointer to a memory pool handle. */ +typedef RTMEMPOOL RT_FAR *PRTMEMPOOL; +/** NIL memory pool handle. */ +#define NIL_RTMEMPOOL ((RTMEMPOOL)0) +/** The default memory pool handle. */ +#define RTMEMPOOL_DEFAULT ((RTMEMPOOL)-2) + +/** String cache handle. */ +typedef R3R0PTRTYPE(struct RTSTRCACHEINT RT_FAR *) RTSTRCACHE; +/** Pointer to a string cache handle. */ +typedef RTSTRCACHE RT_FAR *PRTSTRCACHE; +/** NIL string cache handle. */ +#define NIL_RTSTRCACHE ((RTSTRCACHE)0) +/** The default string cache handle. */ +#define RTSTRCACHE_DEFAULT ((RTSTRCACHE)-2) + + +/** Virtual Filesystem handle. */ +typedef struct RTVFSINTERNAL RT_FAR *RTVFS; +/** Pointer to a VFS handle. */ +typedef RTVFS RT_FAR *PRTVFS; +/** A NIL VFS handle. */ +#define NIL_RTVFS ((RTVFS)~(uintptr_t)0) + +/** Virtual Filesystem base object handle. */ +typedef struct RTVFSOBJINTERNAL RT_FAR *RTVFSOBJ; +/** Pointer to a VFS base object handle. */ +typedef RTVFSOBJ RT_FAR *PRTVFSOBJ; +/** A NIL VFS base object handle. */ +#define NIL_RTVFSOBJ ((RTVFSOBJ)~(uintptr_t)0) + +/** Virtual Filesystem directory handle. */ +typedef struct RTVFSDIRINTERNAL RT_FAR *RTVFSDIR; +/** Pointer to a VFS directory handle. */ +typedef RTVFSDIR RT_FAR *PRTVFSDIR; +/** A NIL VFS directory handle. */ +#define NIL_RTVFSDIR ((RTVFSDIR)~(uintptr_t)0) + +/** Virtual Filesystem filesystem stream handle. */ +typedef struct RTVFSFSSTREAMINTERNAL RT_FAR *RTVFSFSSTREAM; +/** Pointer to a VFS filesystem stream handle. */ +typedef RTVFSFSSTREAM RT_FAR *PRTVFSFSSTREAM; +/** A NIL VFS filesystem stream handle. */ +#define NIL_RTVFSFSSTREAM ((RTVFSFSSTREAM)~(uintptr_t)0) + +/** Virtual Filesystem I/O stream handle. */ +typedef struct RTVFSIOSTREAMINTERNAL RT_FAR *RTVFSIOSTREAM; +/** Pointer to a VFS I/O stream handle. */ +typedef RTVFSIOSTREAM RT_FAR *PRTVFSIOSTREAM; +/** A NIL VFS I/O stream handle. */ +#define NIL_RTVFSIOSTREAM ((RTVFSIOSTREAM)~(uintptr_t)0) + +/** Virtual Filesystem file handle. */ +typedef struct RTVFSFILEINTERNAL RT_FAR *RTVFSFILE; +/** Pointer to a VFS file handle. */ +typedef RTVFSFILE RT_FAR *PRTVFSFILE; +/** A NIL VFS file handle. */ +#define NIL_RTVFSFILE ((RTVFSFILE)~(uintptr_t)0) + +/** Virtual Filesystem symbolic link handle. */ +typedef struct RTVFSSYMLINKINTERNAL RT_FAR *RTVFSSYMLINK; +/** Pointer to a VFS symbolic link handle. */ +typedef RTVFSSYMLINK RT_FAR *PRTVFSSYMLINK; +/** A NIL VFS symbolic link handle. */ +#define NIL_RTVFSSYMLINK ((RTVFSSYMLINK)~(uintptr_t)0) + +/** Async I/O manager handle. */ +typedef struct RTAIOMGRINT RT_FAR *RTAIOMGR; +/** Pointer to a async I/O manager handle. */ +typedef RTAIOMGR RT_FAR *PRTAIOMGR; +/** A NIL async I/O manager handle. */ +#define NIL_RTAIOMGR ((RTAIOMGR)~(uintptr_t)0) + +/** Async I/O manager file handle. */ +typedef struct RTAIOMGRFILEINT RT_FAR *RTAIOMGRFILE; +/** Pointer to a async I/O manager file handle. */ +typedef RTAIOMGRFILE RT_FAR *PRTAIOMGRFILE; +/** A NIL async I/O manager file handle. */ +#define NIL_RTAIOMGRFILE ((RTAIOMGRFILE)~(uintptr_t)0) + +/** Kernel module information record handle. */ +typedef struct RTKRNLMODINFOINT RT_FAR *RTKRNLMODINFO; +/** Pointer to a kernel information record handle. */ +typedef RTKRNLMODINFO RT_FAR *PRTKRNLMODINFO; +/** A NIL kernel module information record handle. */ +#define NIL_RTKRNLMODINFO ((RTKRNLMODINFO)~(uintptr_t)0); + +/** Shared memory object handle. */ +typedef struct RTSHMEMINT RT_FAR *RTSHMEM; +/** Pointer to a shared memory object handle. */ +typedef RTSHMEM RT_FAR *PRTSHMEM; +/** A NIL shared memory object handle. */ +#define NIL_RTSHMEM ((RTSHMEM)~(uintptr_t)0) + +/** EFI signature database handle. */ +typedef struct RTEFISIGDBINT RT_FAR *RTEFISIGDB; +/** Pointer to a EFI signature database handle. */ +typedef RTEFISIGDB RT_FAR *PRTEFISIGDB; +/** A NIL EFI signature database handle. */ +#define NIL_RTEFISIGDB ((RTEFISIGDB)~(uintptr_t)0) + + +/** + * Handle type. + * + * This is usually used together with RTHANDLEUNION. + */ +typedef enum RTHANDLETYPE +{ + /** The invalid zero value. */ + RTHANDLETYPE_INVALID = 0, + /** File handle. */ + RTHANDLETYPE_FILE, + /** Pipe handle */ + RTHANDLETYPE_PIPE, + /** Socket handle. */ + RTHANDLETYPE_SOCKET, + /** Thread handle. */ + RTHANDLETYPE_THREAD, + /** The end of the valid values. */ + RTHANDLETYPE_END, + /** The 32-bit type blow up. */ + RTHANDLETYPE_32BIT_HACK = 0x7fffffff +} RTHANDLETYPE; +/** Pointer to a handle type. */ +typedef RTHANDLETYPE RT_FAR *PRTHANDLETYPE; + +/** + * Handle union. + * + * This is usually used together with RTHANDLETYPE or as RTHANDLE. + */ +typedef union RTHANDLEUNION +{ + RTFILE hFile; /**< File handle. */ + RTPIPE hPipe; /**< Pipe handle. */ + RTSOCKET hSocket; /**< Socket handle. */ + RTTHREAD hThread; /**< Thread handle. */ + /** Generic integer handle value. + * Note that RTFILE is not yet pointer sized, so accessing it via this member + * isn't necessarily safe or fully portable. */ + RTHCUINTPTR uInt; +} RTHANDLEUNION; +/** Pointer to a handle union. */ +typedef RTHANDLEUNION RT_FAR *PRTHANDLEUNION; +/** Pointer to a const handle union. */ +typedef RTHANDLEUNION const RT_FAR *PCRTHANDLEUNION; + +/** + * Generic handle. + */ +typedef struct RTHANDLE +{ + /** The handle type. */ + RTHANDLETYPE enmType; + /** The handle value. */ + RTHANDLEUNION u; +} RTHANDLE; +/** Pointer to a generic handle. */ +typedef RTHANDLE RT_FAR *PRTHANDLE; +/** Pointer to a const generic handle. */ +typedef RTHANDLE const RT_FAR *PCRTHANDLE; + + +/** + * Standard handles. + * + * @remarks These have the correct file descriptor values for unixy systems and + * can be used directly in code specific to those platforms. + */ +typedef enum RTHANDLESTD +{ + /** Invalid standard handle. */ + RTHANDLESTD_INVALID = -1, + /** The standard input handle. */ + RTHANDLESTD_INPUT = 0, + /** The standard output handle. */ + RTHANDLESTD_OUTPUT, + /** The standard error handle. */ + RTHANDLESTD_ERROR, + /** The typical 32-bit type hack. */ + RTHANDLESTD_32BIT_HACK = 0x7fffffff +} RTHANDLESTD; + + +/** + * Error info. + * + * See RTErrInfo*. + */ +typedef struct RTERRINFO +{ + /** Flags, see RTERRINFO_FLAGS_XXX. */ + uint32_t fFlags; + /** The status code. */ + int32_t rc; + /** The size of the message */ + size_t cbMsg; + /** The error buffer. */ + char *pszMsg; + /** Reserved for future use. */ + void *apvReserved[2]; +} RTERRINFO; +/** Pointer to an error info structure. */ +typedef RTERRINFO RT_FAR *PRTERRINFO; +/** Pointer to a const error info structure. */ +typedef RTERRINFO const RT_FAR *PCRTERRINFO; + +/** + * Static error info structure, see RTErrInfoInitStatic. + */ +typedef struct RTERRINFOSTATIC +{ + /** The core error info. */ + RTERRINFO Core; + /** The static message buffer. */ + char szMsg[3072]; +} RTERRINFOSTATIC; +/** Pointer to a error info buffer. */ +typedef RTERRINFOSTATIC RT_FAR *PRTERRINFOSTATIC; +/** Pointer to a const static error info buffer. */ +typedef RTERRINFOSTATIC const RT_FAR *PCRTERRINFOSTATIC; + + +/** + * UUID data type. + * + * See RTUuid*. + * + * @remarks IPRT defines that the first three integers in the @c Gen struct + * interpretation are in little endian representation. This is + * different to many other UUID implementation, and requires + * conversion if you need to achieve consistent results. + */ +typedef union RTUUID +{ + /** 8-bit view. */ + uint8_t au8[16]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 64-bit view. */ + uint64_t au64[2]; + /** The way the UUID is declared by the DCE specification. */ + struct + { + uint32_t u32TimeLow; + uint16_t u16TimeMid; + uint16_t u16TimeHiAndVersion; + uint8_t u8ClockSeqHiAndReserved; + uint8_t u8ClockSeqLow; + uint8_t au8Node[6]; + } Gen; +} RTUUID; +/** Pointer to UUID data. */ +typedef RTUUID RT_FAR *PRTUUID; +/** Pointer to readonly UUID data. */ +typedef const RTUUID RT_FAR *PCRTUUID; + +/** Initializes a RTUUID structure with all zeros (RTUuidIsNull() true). */ +#define RTUUID_INITIALIZE_NULL { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } + +/** UUID string maximum length. */ +#define RTUUID_STR_LENGTH 37 + + +/** Compression handle. */ +typedef struct RTZIPCOMP RT_FAR *PRTZIPCOMP; +/** Decompressor handle. */ +typedef struct RTZIPDECOMP RT_FAR *PRTZIPDECOMP; + + +/** + * Unicode Code Point. + */ +typedef uint32_t RTUNICP; +/** Pointer to an Unicode Code Point. */ +typedef RTUNICP RT_FAR *PRTUNICP; +/** Pointer to an Unicode Code Point. */ +typedef const RTUNICP RT_FAR *PCRTUNICP; +/** Max value a RTUNICP type can hold. */ +#define RTUNICP_MAX ( ~(RTUNICP)0 ) +/** Invalid code point. + * This is returned when encountered invalid encodings or invalid + * unicode code points. */ +#define RTUNICP_INVALID ( UINT32_C(0xfffffffe) ) + + +/** + * UTF-16 character. + * @remark wchar_t is not usable since it's compiler defined. + * @remark When we use the term character we're not talking about unicode code point, but + * the basic unit of the string encoding. Thus cwc - count of wide chars - means + * count of RTUTF16; cuc - count of unicode chars - means count of RTUNICP; + * and cch means count of the typedef 'char', which is assumed to be an octet. + */ +typedef uint16_t RTUTF16; +/** Pointer to a UTF-16 character. */ +typedef RTUTF16 RT_FAR *PRTUTF16; +/** Pointer to a const UTF-16 character. */ +typedef const RTUTF16 RT_FAR *PCRTUTF16; + + +/** + * String tuple to go with the RT_STR_TUPLE macro. + */ +typedef struct RTSTRTUPLE +{ + /** The string. */ + const char *psz; + /** The string length. */ + size_t cch; +} RTSTRTUPLE; +/** Pointer to a string tuple. */ +typedef RTSTRTUPLE RT_FAR *PRTSTRTUPLE; +/** Pointer to a const string tuple. */ +typedef RTSTRTUPLE const RT_FAR *PCRTSTRTUPLE; + +/** + * Wait for ever if we have to. + */ +#define RT_INDEFINITE_WAIT (~0U) + + +/** + * Generic process callback. + * + * @returns VBox status code. Failure will cancel the operation. + * @param uPercentage The percentage of the operation which has been completed. + * @param pvUser The user specified argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTPROGRESS,(unsigned uPercentage, void *pvUser)); +/** Pointer to a generic progress callback function, FNRTPROCESS(). */ +typedef FNRTPROGRESS *PFNRTPROGRESS; + +/** + * Generic vprintf-like callback function for dumpers. + * + * @param pvUser User argument. + * @param pszFormat The format string. + * @param va Arguments for the format string. + */ +typedef DECLCALLBACKTYPE(void, FNRTDUMPPRINTFV,(void *pvUser, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0)); +/** Pointer to a generic printf-like function for dumping. */ +typedef FNRTDUMPPRINTFV *PFNRTDUMPPRINTFV; + + +/** + * A point in a two dimentional coordinate system. + */ +typedef struct RTPOINT +{ + /** X coordinate. */ + int32_t x; + /** Y coordinate. */ + int32_t y; +} RTPOINT; +/** Pointer to a point. */ +typedef RTPOINT RT_FAR *PRTPOINT; +/** Pointer to a const point. */ +typedef const RTPOINT RT_FAR *PCRTPOINT; + + +/** + * Rectangle data type, double point. + */ +typedef struct RTRECT +{ + /** left X coordinate. */ + int32_t xLeft; + /** top Y coordinate. */ + int32_t yTop; + /** right X coordinate. (exclusive) */ + int32_t xRight; + /** bottom Y coordinate. (exclusive) */ + int32_t yBottom; +} RTRECT; +/** Pointer to a double point rectangle. */ +typedef RTRECT RT_FAR *PRTRECT; +/** Pointer to a const double point rectangle. */ +typedef const RTRECT RT_FAR *PCRTRECT; + + +/** + * Rectangle data type, point + size. + */ +typedef struct RTRECT2 +{ + /** X coordinate. + * Unless stated otherwise, this is the top left corner. */ + int32_t x; + /** Y coordinate. + * Unless stated otherwise, this is the top left corner. */ + int32_t y; + /** The width. + * Unless stated otherwise, this is to the right of (x,y) and will not + * be a negative number. */ + int32_t cx; + /** The height. + * Unless stated otherwise, this is down from (x,y) and will not be a + * negative number. */ + int32_t cy; +} RTRECT2; +/** Pointer to a point + size rectangle. */ +typedef RTRECT2 RT_FAR *PRTRECT2; +/** Pointer to a const point + size rectangle. */ +typedef const RTRECT2 RT_FAR *PCRTRECT2; + + +/** + * The size of a rectangle. + */ +typedef struct RTRECTSIZE +{ + /** The width (along the x-axis). */ + uint32_t cx; + /** The height (along the y-axis). */ + uint32_t cy; +} RTRECTSIZE; +/** Pointer to a rectangle size. */ +typedef RTRECTSIZE RT_FAR *PRTRECTSIZE; +/** Pointer to a const rectangle size. */ +typedef const RTRECTSIZE RT_FAR *PCRTRECTSIZE; + + +/** + * Ethernet MAC address. + * + * The first 24 bits make up the Organisationally Unique Identifier (OUI), + * where the first bit (little endian) indicates multicast (set) / unicast, + * and the second bit indicates locally (set) / global administered. If all + * bits are set, it's a broadcast. + */ +typedef union RTMAC +{ + /** @todo add a bitfield view of this stuff. */ + /** 8-bit view. */ + uint8_t au8[6]; + /** 16-bit view. */ + uint16_t au16[3]; +} RTMAC; +/** Pointer to a MAC address. */ +typedef RTMAC RT_FAR *PRTMAC; +/** Pointer to a readonly MAC address. */ +typedef const RTMAC RT_FAR *PCRTMAC; + + +/** Pointer to a lock validator record. + * The structure definition is found in iprt/lockvalidator.h. */ +typedef struct RTLOCKVALRECEXCL RT_FAR *PRTLOCKVALRECEXCL; +/** Pointer to a record of one ownership share. + * The structure definition is found in iprt/lockvalidator.h. */ +typedef struct RTLOCKVALRECSHRD RT_FAR *PRTLOCKVALRECSHRD; +/** Pointer to a lock validator source position. + * The structure definition is found in iprt/lockvalidator.h. */ +typedef struct RTLOCKVALSRCPOS RT_FAR *PRTLOCKVALSRCPOS; +/** Pointer to a const lock validator source position. + * The structure definition is found in iprt/lockvalidator.h. */ +typedef struct RTLOCKVALSRCPOS const RT_FAR *PCRTLOCKVALSRCPOS; + +/** @name Special sub-class values. + * The range 16..UINT32_MAX is available to the user, the range 0..15 is + * reserved for the lock validator. In the user range the locks can only be + * taking in ascending order. + * @{ */ +/** Invalid value. */ +#define RTLOCKVAL_SUB_CLASS_INVALID UINT32_C(0) +/** Not allowed to be taken with any other locks in the same class. + * This is the recommended value. */ +#define RTLOCKVAL_SUB_CLASS_NONE UINT32_C(1) +/** Any order is allowed within the class. */ +#define RTLOCKVAL_SUB_CLASS_ANY UINT32_C(2) +/** The first user value. */ +#define RTLOCKVAL_SUB_CLASS_USER UINT32_C(16) +/** @} */ + + +/** + * Digest types. + */ +typedef enum RTDIGESTTYPE +{ + /** Invalid digest value. */ + RTDIGESTTYPE_INVALID = 0, + /** Unknown digest type. */ + RTDIGESTTYPE_UNKNOWN, + /** CRC32 checksum. */ + RTDIGESTTYPE_CRC32, + /** CRC64 checksum. */ + RTDIGESTTYPE_CRC64, + /** MD2 checksum (unsafe!). */ + RTDIGESTTYPE_MD2, + /** MD4 checksum (unsafe!!). */ + RTDIGESTTYPE_MD4, + /** MD5 checksum (unsafe!). */ + RTDIGESTTYPE_MD5, + /** SHA-1 checksum (unsafe!). */ + RTDIGESTTYPE_SHA1, + /** SHA-224 checksum. */ + RTDIGESTTYPE_SHA224, + /** SHA-256 checksum. */ + RTDIGESTTYPE_SHA256, + /** SHA-384 checksum. */ + RTDIGESTTYPE_SHA384, + /** SHA-512 checksum. */ + RTDIGESTTYPE_SHA512, + /** SHA-512/224 checksum. */ + RTDIGESTTYPE_SHA512T224, + /** SHA-512/256 checksum. */ + RTDIGESTTYPE_SHA512T256, + /** SHA3-224 checksum. */ + RTDIGESTTYPE_SHA3_224, + /** SHA3-256 checksum. */ + RTDIGESTTYPE_SHA3_256, + /** SHA3-384 checksum. */ + RTDIGESTTYPE_SHA3_384, + /** SHA3-512 checksum. */ + RTDIGESTTYPE_SHA3_512, +#if 0 + /** SHAKE128 checksum. */ + RTDIGESTTYPE_SHAKE128, + /** SHAKE256 checksum. */ + RTDIGESTTYPE_SHAKE256, +#endif + /** End of valid types. */ + RTDIGESTTYPE_END, + /** Usual 32-bit type blowup. */ + RTDIGESTTYPE_32BIT_HACK = 0x7fffffff +} RTDIGESTTYPE; + +/** + * Process exit codes. + */ +typedef enum RTEXITCODE +{ + /** Success. */ + RTEXITCODE_SUCCESS = 0, + /** General failure. */ + RTEXITCODE_FAILURE = 1, + /** Invalid arguments. */ + RTEXITCODE_SYNTAX = 2, + /** Initialization failure (usually IPRT, but could be used for other + * components as well). */ + RTEXITCODE_INIT = 3, + /** Test skipped. */ + RTEXITCODE_SKIPPED = 4, + /** The end of valid exit codes. */ + RTEXITCODE_END, + /** The usual 32-bit type hack. */ + RTEXITCODE_32BIT_HACK = 0x7fffffff +} RTEXITCODE; + +/** + * Range descriptor. + */ +typedef struct RTRANGE +{ + /** Start offset. */ + uint64_t offStart; + /** Range size. */ + size_t cbRange; +} RTRANGE; +/** Pointer to a range descriptor. */ +typedef RTRANGE RT_FAR *PRTRANGE; +/** Pointer to a readonly range descriptor. */ +typedef const RTRANGE RT_FAR *PCRTRANGE; + + +/** + * Generic pointer union. + */ +typedef union RTPTRUNION +{ + /** Pointer into the void. */ + void RT_FAR *pv; + /** As a signed integer. */ + intptr_t i; + /** As an unsigned integer. */ + uintptr_t u; + /** Pointer to char value. */ + char RT_FAR *pch; + /** Pointer to char value. */ + unsigned char RT_FAR *puch; + /** Pointer to a int value. */ + int RT_FAR *pi; + /** Pointer to a unsigned int value. */ + unsigned int RT_FAR *pu; + /** Pointer to a long value. */ + long RT_FAR *pl; + /** Pointer to a long value. */ + unsigned long RT_FAR *pul; + /** Pointer to a 8-bit unsigned value. */ + uint8_t RT_FAR *pu8; + /** Pointer to a 16-bit unsigned value. */ + uint16_t RT_FAR *pu16; + /** Pointer to a 32-bit unsigned value. */ + uint32_t RT_FAR *pu32; + /** Pointer to a 64-bit unsigned value. */ + uint64_t RT_FAR *pu64; + /** Pointer to a 8-bit signed value. */ + int8_t RT_FAR *pi8; + /** Pointer to a 16-bit signed value. */ + int16_t RT_FAR *pi16; + /** Pointer to a 32-bit signed value. */ + int32_t RT_FAR *pi32; + /** Pointer to a 64-bit signed value. */ + int64_t RT_FAR *pi64; + /** Pointer to a UTF-16 character. */ + PRTUTF16 pwc; + /** Pointer to a UUID character. */ + PRTUUID pUuid; +} RTPTRUNION; +/** Pointer to a pointer union. */ +typedef RTPTRUNION RT_FAR *PRTPTRUNION; + +/** + * Generic const pointer union. + */ +typedef union RTCPTRUNION +{ + /** Pointer into the void. */ + void const RT_FAR *pv; + /** As a signed integer. */ + intptr_t i; + /** As an unsigned integer. */ + uintptr_t u; + /** Pointer to char value. */ + char const RT_FAR *pch; + /** Pointer to char value. */ + unsigned char const RT_FAR *puch; + /** Pointer to a int value. */ + int const RT_FAR *pi; + /** Pointer to a unsigned int value. */ + unsigned int const RT_FAR *pu; + /** Pointer to a long value. */ + long const RT_FAR *pl; + /** Pointer to a long value. */ + unsigned long const RT_FAR *pul; + /** Pointer to a 8-bit unsigned value. */ + uint8_t const RT_FAR *pu8; + /** Pointer to a 16-bit unsigned value. */ + uint16_t const RT_FAR *pu16; + /** Pointer to a 32-bit unsigned value. */ + uint32_t const RT_FAR *pu32; + /** Pointer to a 64-bit unsigned value. */ + uint64_t const RT_FAR *pu64; + /** Pointer to a 8-bit signed value. */ + int8_t const RT_FAR *pi8; + /** Pointer to a 16-bit signed value. */ + int16_t const RT_FAR *pi16; + /** Pointer to a 32-bit signed value. */ + int32_t const RT_FAR *pi32; + /** Pointer to a 64-bit signed value. */ + int64_t const RT_FAR *pi64; + /** Pointer to a UTF-16 character. */ + PCRTUTF16 pwc; + /** Pointer to a UUID character. */ + PCRTUUID pUuid; +} RTCPTRUNION; +/** Pointer to a const pointer union. */ +typedef RTCPTRUNION RT_FAR *PRTCPTRUNION; + +/** + * Generic volatile pointer union. + */ +typedef union RTVPTRUNION +{ + /** Pointer into the void. */ + void volatile RT_FAR *pv; + /** As a signed integer. */ + intptr_t i; + /** As an unsigned integer. */ + uintptr_t u; + /** Pointer to char value. */ + char volatile RT_FAR *pch; + /** Pointer to char value. */ + unsigned char volatile RT_FAR *puch; + /** Pointer to a int value. */ + int volatile RT_FAR *pi; + /** Pointer to a unsigned int value. */ + unsigned int volatile RT_FAR *pu; + /** Pointer to a long value. */ + long volatile RT_FAR *pl; + /** Pointer to a long value. */ + unsigned long volatile RT_FAR *pul; + /** Pointer to a 8-bit unsigned value. */ + uint8_t volatile RT_FAR *pu8; + /** Pointer to a 16-bit unsigned value. */ + uint16_t volatile RT_FAR *pu16; + /** Pointer to a 32-bit unsigned value. */ + uint32_t volatile RT_FAR *pu32; + /** Pointer to a 64-bit unsigned value. */ + uint64_t volatile RT_FAR *pu64; + /** Pointer to a 8-bit signed value. */ + int8_t volatile RT_FAR *pi8; + /** Pointer to a 16-bit signed value. */ + int16_t volatile RT_FAR *pi16; + /** Pointer to a 32-bit signed value. */ + int32_t volatile RT_FAR *pi32; + /** Pointer to a 64-bit signed value. */ + int64_t volatile RT_FAR *pi64; + /** Pointer to a UTF-16 character. */ + RTUTF16 volatile RT_FAR *pwc; + /** Pointer to a UUID character. */ + RTUUID volatile RT_FAR *pUuid; +} RTVPTRUNION; +/** Pointer to a const pointer union. */ +typedef RTVPTRUNION RT_FAR *PRTVPTRUNION; + +/** + * Generic const volatile pointer union. + */ +typedef union RTCVPTRUNION +{ + /** Pointer into the void. */ + void const volatile RT_FAR *pv; + /** As a signed integer. */ + intptr_t i; + /** As an unsigned integer. */ + uintptr_t u; + /** Pointer to char value. */ + char const volatile RT_FAR *pch; + /** Pointer to char value. */ + unsigned char const volatile RT_FAR *puch; + /** Pointer to a int value. */ + int const volatile RT_FAR *pi; + /** Pointer to a unsigned int value. */ + unsigned int const volatile RT_FAR *pu; + /** Pointer to a long value. */ + long const volatile RT_FAR *pl; + /** Pointer to a long value. */ + unsigned long const volatile RT_FAR *pul; + /** Pointer to a 8-bit unsigned value. */ + uint8_t const volatile RT_FAR *pu8; + /** Pointer to a 16-bit unsigned value. */ + uint16_t const volatile RT_FAR *pu16; + /** Pointer to a 32-bit unsigned value. */ + uint32_t const volatile RT_FAR *pu32; + /** Pointer to a 64-bit unsigned value. */ + uint64_t const volatile RT_FAR *pu64; + /** Pointer to a 8-bit signed value. */ + int8_t const volatile RT_FAR *pi8; + /** Pointer to a 16-bit signed value. */ + int16_t const volatile RT_FAR *pi16; + /** Pointer to a 32-bit signed value. */ + int32_t const volatile RT_FAR *pi32; + /** Pointer to a 64-bit signed value. */ + int64_t const volatile RT_FAR *pi64; + /** Pointer to a UTF-16 character. */ + RTUTF16 const volatile RT_FAR *pwc; + /** Pointer to a UUID character. */ + RTUUID const volatile RT_FAR *pUuid; +} RTCVPTRUNION; +/** Pointer to a const pointer union. */ +typedef RTCVPTRUNION RT_FAR *PRTCVPTRUNION; + + + +#ifdef __cplusplus +/** + * Strict type validation helper class. + * + * See RTErrStrictType and RT_SUCCESS_NP. + */ +class RTErrStrictType2 +{ +protected: + /** The status code. */ + int32_t m_rc; + +public: + /** + * Constructor. + * @param rc IPRT style status code. + */ + RTErrStrictType2(int32_t rc) : m_rc(rc) + { + } + + /** + * Get the status code. + * @returns IPRT style status code. + */ + int32_t getValue() const + { + return m_rc; + } +}; +#endif /* __cplusplus */ +/** @} */ + +#define IPRT_COMPLETED_types_h /* hack for watcom and nocrt headers depending on this one. */ +#endif /* !IPRT_INCLUDED_types_h */ + diff --git a/include/iprt/udp.h b/include/iprt/udp.h new file mode 100644 index 00000000..d06a2388 --- /dev/null +++ b/include/iprt/udp.h @@ -0,0 +1,191 @@ +/** @file + * IPRT - UDP/IP. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_udp_h +#define IPRT_INCLUDED_udp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef IN_RING0 +# error "There are no RTFile APIs available Ring-0 Host Context!" +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_udp RTUdp - UDP/IP + * @ingroup grp_rt + * @{ + */ + + +/** + * Handle incoming UDP datagrams. + * + * @returns iprt status code. + * @returns VERR_UDP_SERVER_STOP to terminate the server loop forcing + * the RTUdpCreateServer() call to return. + * @param Sock The socket on which the datagram needs to be received. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTUDPSERVE,(RTSOCKET Sock, void *pvUser)); +/** Pointer to a RTUDPSERVE(). */ +typedef FNRTUDPSERVE *PFNRTUDPSERVE; + +/** + * Create single datagram at a time UDP Server in a separate thread. + * + * The thread will loop accepting datagrams and call pfnServe for + * each of the incoming datagrams in turn. The pfnServe function can + * return VERR_UDP_SERVER_STOP too terminate this loop. RTUdpServerDestroy() + * should be used to terminate the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a datagram socket. + * If NULL or empty string the server is bound to all interfaces. + * @param uPort The port for creating a datagram socket. + * @param enmType The thread type. + * @param pszThrdName The name of the worker thread. + * @param pfnServe The function which will handle incoming datagrams. + * @param pvUser User argument passed to pfnServe. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTUdpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName, + PFNRTUDPSERVE pfnServe, void *pvUser, PPRTUDPSERVER ppServer); + +/** + * Create single datagram at a time UDP Server. + * The caller must call RTUdpServerReceive() to actually start the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a datagram socket. + * If NULL the server is bound to all interfaces. + * @param uPort The port for creating a datagram socket. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTUdpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTUDPSERVER ppServer); + +/** + * Shuts down the server. + * + * @returns IPRT status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTUdpServerShutdown(PRTUDPSERVER pServer); + +/** + * Closes down and frees a UDP Server. + * + * @returns iprt status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTUdpServerDestroy(PRTUDPSERVER pServer); + +/** + * Listen for incoming datagrams. + * + * The function will loop waiting for datagrams and call pfnServe for + * each of the incoming datagrams in turn. The pfnServe function can + * return VERR_UDP_SERVER_STOP too terminate this loop. A stopped server + * can only be destroyed. + * + * @returns iprt status code. + * @param pServer The server handle as returned from RTUdpServerCreateEx(). + * @param pfnServe The function which will handle incoming datagrams. + * @param pvUser User argument passed to pfnServe. + */ +RTR3DECL(int) RTUdpServerListen(PRTUDPSERVER pServer, PFNRTUDPSERVE pfnServe, void *pvUser); + +/** + * Receive data from a socket. + * + * @returns iprt status code. + * @param Sock Socket descriptor. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. Must be non-NULL. + * @param pSrcAddr The network address to read from. + */ +RTR3DECL(int) RTUdpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr); + +/** + * Send data to a socket. + * + * @returns iprt status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param pServer Handle to the server. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pDstAddr Destination address. + */ +RTR3DECL(int) RTUdpWrite(PRTUDPSERVER pServer, const void *pvBuffer, + size_t cbBuffer, PCRTNETADDR pDstAddr); + +/** + * Create and connect a data socket. + * + * @returns iprt status code. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param pLocalAddr The local address to bind this socket to, can be + * NULL. + * @param pSock Where to store the handle to the established connection. + */ +RTR3DECL(int) RTUdpCreateClientSocket(const char *pszAddress, uint32_t uPort, PRTNETADDR pLocalAddr, PRTSOCKET pSock); + +/** + * Create a data socket acting as a server. + * + * @returns iprt status code. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param pSock Where to store the handle to the established connection. + */ +RTR3DECL(int) RTUdpCreateServerSocket(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_udp_h */ + diff --git a/include/iprt/uint128.h b/include/iprt/uint128.h new file mode 100644 index 00000000..50b19055 --- /dev/null +++ b/include/iprt/uint128.h @@ -0,0 +1,1479 @@ +/** @file + * IPRT - RTUINT128U & uint128_t methods. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uint128_h +#define IPRT_INCLUDED_uint128_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uint128 RTUInt128 - 128-bit Unsigned Integer Methods + * @ingroup grp_rt + * @{ + */ + + +/** + * Test if a 128-bit unsigned integer value is zero. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt128IsZero(PCRTUINT128U pValue) +{ +#if ARCH_BITS >= 64 + return pValue->s.Hi == 0 + && pValue->s.Lo == 0; +#else + return pValue->DWords.dw0 == 0 + && pValue->DWords.dw1 == 0 + && pValue->DWords.dw2 == 0 + && pValue->DWords.dw3 == 0; +#endif +} + + +/** + * Set a 128-bit unsigned integer value to zero. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT128U) RTUInt128SetZero(PRTUINT128U pResult) +{ +#if ARCH_BITS >= 64 + pResult->s.Hi = 0; + pResult->s.Lo = 0; +#else + pResult->DWords.dw0 = 0; + pResult->DWords.dw1 = 0; + pResult->DWords.dw2 = 0; + pResult->DWords.dw3 = 0; +#endif + return pResult; +} + + +/** + * Set a 128-bit unsigned integer value to the maximum value. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT128U) RTUInt128SetMax(PRTUINT128U pResult) +{ +#if ARCH_BITS >= 64 + pResult->s.Hi = UINT64_MAX; + pResult->s.Lo = UINT64_MAX; +#else + pResult->DWords.dw0 = UINT32_MAX; + pResult->DWords.dw1 = UINT32_MAX; + pResult->DWords.dw2 = UINT32_MAX; + pResult->DWords.dw3 = UINT32_MAX; +#endif + return pResult; +} + + + + +/** + * Adds two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Add(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi + pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo + pValue2->s.Lo; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; + return pResult; +} + + +/** + * Adds a 128-bit and a 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT128U) RTUInt128AddU64(PRTUINT128U pResult, PCRTUINT128U pValue1, uint64_t uValue2) +{ + pResult->s.Hi = pValue1->s.Hi; + pResult->s.Lo = pValue1->s.Lo + uValue2; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; + return pResult; +} + + +/** + * Subtracts a 128-bit unsigned integer value from another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The minuend value. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Sub(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Lo = pValue1->s.Lo - pValue2->s.Lo; + pResult->s.Hi = pValue1->s.Hi - pValue2->s.Hi; + if (pResult->s.Lo > pValue1->s.Lo) + pResult->s.Hi--; + return pResult; +} + + +/** + * Multiplies two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Mul(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + RTUINT64U uTmp; + + /* multiply all dwords in v1 by v2.dw0. */ + pResult->s.Lo = (uint64_t)pValue1->DWords.dw0 * pValue2->DWords.dw0; + + uTmp.u = (uint64_t)pValue1->DWords.dw1 * pValue2->DWords.dw0; + pResult->DWords.dw3 = 0; + pResult->DWords.dw2 = uTmp.DWords.dw1; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)pValue1->DWords.dw2 * pValue2->DWords.dw0; + pResult->DWords.dw3 += pValue1->DWords.dw3 * pValue2->DWords.dw0; + + /* multiply dw0, dw1 & dw2 in v1 by v2.dw1. */ + uTmp.u = (uint64_t)pValue1->DWords.dw0 * pValue2->DWords.dw1; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->DWords.dw2 += uTmp.DWords.dw1; + if (pResult->DWords.dw2 < uTmp.DWords.dw1) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)pValue1->DWords.dw1 * pValue2->DWords.dw1; + pResult->DWords.dw3 += pValue1->DWords.dw2 * pValue2->DWords.dw1; + + /* multiply dw0 & dw1 in v1 by v2.dw2. */ + pResult->s.Hi += (uint64_t)pValue1->DWords.dw0 * pValue2->DWords.dw2; + pResult->DWords.dw3 += pValue1->DWords.dw1 * pValue2->DWords.dw2; + + /* multiply dw0 in v1 by v2.dw3. */ + pResult->DWords.dw3 += pValue1->DWords.dw0 * pValue2->DWords.dw3; + + return pResult; +} + + +/** + * Multiplies an 128-bit unsigned integer by a 64-bit unsigned integer value. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +#if defined(RT_ARCH_AMD64) +RTDECL(PRTUINT128U) RTUInt128MulByU64(PRTUINT128U pResult, PCRTUINT128U pValue1, uint64_t uValue2); +#else +DECLINLINE(PRTUINT128U) RTUInt128MulByU64(PRTUINT128U pResult, PCRTUINT128U pValue1, uint64_t uValue2) +{ + uint32_t const uLoValue2 = (uint32_t)uValue2; + uint32_t const uHiValue2 = (uint32_t)(uValue2 >> 32); + RTUINT64U uTmp; + + /* multiply all dwords in v1 by uLoValue1. */ + pResult->s.Lo = (uint64_t)pValue1->DWords.dw0 * uLoValue2; + + uTmp.u = (uint64_t)pValue1->DWords.dw1 * uLoValue2; + pResult->DWords.dw3 = 0; + pResult->DWords.dw2 = uTmp.DWords.dw1; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)pValue1->DWords.dw2 * uLoValue2; + pResult->DWords.dw3 += pValue1->DWords.dw3 * uLoValue2; + + /* multiply dw0, dw1 & dw2 in v1 by uHiValue2. */ + uTmp.u = (uint64_t)pValue1->DWords.dw0 * uHiValue2; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->DWords.dw2 += uTmp.DWords.dw1; + if (pResult->DWords.dw2 < uTmp.DWords.dw1) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)pValue1->DWords.dw1 * uHiValue2; + pResult->DWords.dw3 += pValue1->DWords.dw2 * uHiValue2; + + return pResult; +} +#endif + + +/** + * Multiplies two 64-bit unsigned integer values with 128-bit precision. + * + * @returns pResult + * @param pResult The result variable. + * @param uValue1 The first value. 64-bit. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT128U) RTUInt128MulU64ByU64(PRTUINT128U pResult, uint64_t uValue1, uint64_t uValue2) +{ +#ifdef RT_ARCH_AMD64 + pResult->s.Lo = ASMMult2xU64Ret2xU64(uValue1, uValue2, &pResult->s.Hi); +#else + uint32_t const uLoValue1 = (uint32_t)uValue1; + uint32_t const uHiValue1 = (uint32_t)(uValue1 >> 32); + uint32_t const uLoValue2 = (uint32_t)uValue2; + uint32_t const uHiValue2 = (uint32_t)(uValue2 >> 32); + RTUINT64U uTmp; + + /* Multiply uLoValue1 and uHiValue1 by uLoValue1. */ + pResult->s.Lo = (uint64_t)uLoValue1 * uLoValue2; + + uTmp.u = (uint64_t)uHiValue1 * uLoValue2; + pResult->DWords.dw3 = 0; + pResult->DWords.dw2 = uTmp.DWords.dw1; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + /* Multiply uLoValue1 and uHiValue1 by uHiValue2. */ + uTmp.u = (uint64_t)uLoValue1 * uHiValue2; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->DWords.dw2 += uTmp.DWords.dw1; + if (pResult->DWords.dw2 < uTmp.DWords.dw1) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)uHiValue1 * uHiValue2; +#endif + return pResult; +} + + +/** + * Multiplies an 128-bit unsigned integer by a 64-bit unsigned integer value, + * returning a 256-bit result (top 64 bits are zero). + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +#if defined(RT_ARCH_AMD64) +RTDECL(PRTUINT256U) RTUInt128MulByU64Ex(PRTUINT256U pResult, PCRTUINT128U pValue1, uint64_t uValue2); +#else +DECLINLINE(PRTUINT256U) RTUInt128MulByU64Ex(PRTUINT256U pResult, PCRTUINT128U pValue1, uint64_t uValue2) +{ + /* multiply the two qwords in pValue1 by uValue2. */ + uint64_t uTmp = 0; + pResult->QWords.qw0 = ASMMult2xU64Ret2xU64(pValue1->s.Lo, uValue2, &uTmp); + pResult->QWords.qw1 = ASMMult2xU64Ret2xU64(pValue1->s.Hi, uValue2, &pResult->QWords.qw2); + pResult->QWords.qw3 = 0; + pResult->QWords.qw1 += uTmp; + if (pResult->QWords.qw1 < uTmp) + pResult->QWords.qw2++; /* This cannot overflow AFAIK: 0xffff*0xffff = 0xFFFE0001 */ + + return pResult; +} +#endif + + +/** + * Multiplies two 128-bit unsigned integer values, returning a 256-bit result. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt128MulEx(PRTUINT256U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + RTUInt128MulByU64Ex(pResult, pValue1, pValue2->s.Lo); + if (pValue2->s.Hi) + { + /* Multiply the two qwords in pValue1 by the high part of uValue2. */ + uint64_t uTmpHi = 0; + uint64_t uTmpLo = ASMMult2xU64Ret2xU64(pValue1->s.Lo, pValue2->s.Hi, &uTmpHi); + pResult->QWords.qw1 += uTmpLo; + if (pResult->QWords.qw1 < uTmpLo) + if (++pResult->QWords.qw2 == 0) + pResult->QWords.qw3++; /* (cannot overflow, was == 0) */ + pResult->QWords.qw2 += uTmpHi; + if (pResult->QWords.qw2 < uTmpHi) + pResult->QWords.qw3++; /* (cannot overflow, was <= 1) */ + + uTmpLo = ASMMult2xU64Ret2xU64(pValue1->s.Hi, pValue2->s.Hi, &uTmpHi); + pResult->QWords.qw2 += uTmpLo; + if (pResult->QWords.qw2 < uTmpLo) + pResult->QWords.qw3++; /* (cannot overflow, was <= 2) */ + pResult->QWords.qw3 += uTmpHi; + } + + return pResult; +} + + +DECLINLINE(PRTUINT128U) RTUInt128DivRem(PRTUINT128U pQuotient, PRTUINT128U pRemainder, PCRTUINT128U pValue1, PCRTUINT128U pValue2); + +/** + * Divides a 128-bit unsigned integer value by another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Div(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + RTUINT128U Ignored; + return RTUInt128DivRem(pResult, &Ignored, pValue1, pValue2); +} + + +/** + * Divides a 128-bit unsigned integer value by another, returning the remainder. + * + * @returns pResult + * @param pResult The result variable (remainder). + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Mod(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + RTUINT128U Ignored; + RTUInt128DivRem(&Ignored, pResult, pValue1, pValue2); + return pResult; +} + + +/** + * Bitwise AND of two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128And(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi & pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo & pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise OR of two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Or( PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi | pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo | pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise XOR of two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Xor(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi ^ pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo ^ pValue2->s.Lo; + return pResult; +} + + +/** + * Shifts a 128-bit unsigned integer value @a cBits to the left. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT128U) RTUInt128ShiftLeft(PRTUINT128U pResult, PCRTUINT128U pValue, int cBits) +{ + cBits &= 127; + if (cBits < 64) + { + pResult->s.Lo = pValue->s.Lo << cBits; + pResult->s.Hi = (pValue->s.Hi << cBits) | (pValue->s.Lo >> (64 - cBits)); + } + else + { + pResult->s.Lo = 0; + pResult->s.Hi = pValue->s.Lo << (cBits - 64); + } + return pResult; +} + + +/** + * Shifts a 128-bit unsigned integer value @a cBits to the right. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT128U) RTUInt128ShiftRight(PRTUINT128U pResult, PCRTUINT128U pValue, int cBits) +{ + cBits &= 127; + if (cBits < 64) + { + pResult->s.Hi = pValue->s.Hi >> cBits; + pResult->s.Lo = (pValue->s.Lo >> cBits) | (pValue->s.Hi << (64 - cBits)); + } + else + { + pResult->s.Hi = 0; + pResult->s.Lo = pValue->s.Hi >> (cBits - 64); + } + return pResult; +} + + +/** + * Boolean not (result 0 or 1). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT128U) RTUInt128BooleanNot(PRTUINT128U pResult, PCRTUINT128U pValue) +{ + pResult->s.Lo = pValue->s.Lo || pValue->s.Hi ? 0 : 1; + pResult->s.Hi = 0; + return pResult; +} + + +/** + * Bitwise not (flips each bit of the 128 bits). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT128U) RTUInt128BitwiseNot(PRTUINT128U pResult, PCRTUINT128U pValue) +{ + pResult->s.Hi = ~pValue->s.Hi; + pResult->s.Lo = ~pValue->s.Lo; + return pResult; +} + + +/** + * Assigns one 128-bit unsigned integer value to another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to assign. + */ +DECLINLINE(PRTUINT128U) RTUInt128Assign(PRTUINT128U pResult, PCRTUINT128U pValue) +{ +#if ARCH_BITS >= 64 + pResult->s.Hi = pValue->s.Hi; + pResult->s.Lo = pValue->s.Lo; +#else + pResult->DWords.dw0 = pValue->DWords.dw0; + pResult->DWords.dw1 = pValue->DWords.dw1; + pResult->DWords.dw2 = pValue->DWords.dw2; + pResult->DWords.dw3 = pValue->DWords.dw3; +#endif + return pResult; +} + + +/** + * Assigns a boolean value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param fValue The boolean value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignBoolean(PRTUINT128U pValueResult, bool fValue) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Lo = fValue; + pValueResult->s.Hi = 0; +#else + pValueResult->DWords.dw0 = fValue; + pValueResult->DWords.dw1 = 0; + pValueResult->DWords.dw2 = 0; + pValueResult->DWords.dw3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 8-bit unsigned integer value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u8Value The 8-bit unsigned integer value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignU8(PRTUINT128U pValueResult, uint8_t u8Value) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Lo = u8Value; + pValueResult->s.Hi = 0; +#else + pValueResult->DWords.dw0 = u8Value; + pValueResult->DWords.dw1 = 0; + pValueResult->DWords.dw2 = 0; + pValueResult->DWords.dw3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 16-bit unsigned integer value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u16Value The 16-bit unsigned integer value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignU16(PRTUINT128U pValueResult, uint16_t u16Value) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Lo = u16Value; + pValueResult->s.Hi = 0; +#else + pValueResult->DWords.dw0 = u16Value; + pValueResult->DWords.dw1 = 0; + pValueResult->DWords.dw2 = 0; + pValueResult->DWords.dw3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 32-bit unsigned integer value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u32Value The 32-bit unsigned integer value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignU32(PRTUINT128U pValueResult, uint32_t u32Value) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Lo = u32Value; + pValueResult->s.Hi = 0; +#else + pValueResult->DWords.dw0 = u32Value; + pValueResult->DWords.dw1 = 0; + pValueResult->DWords.dw2 = 0; + pValueResult->DWords.dw3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 64-bit unsigned integer value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u64Value The 64-bit unsigned integer value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignU64(PRTUINT128U pValueResult, uint64_t u64Value) +{ + pValueResult->s.Lo = u64Value; + pValueResult->s.Hi = 0; + return pValueResult; +} + + +/** + * Adds two 128-bit unsigned integer values, storing the result in the first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignAdd(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + uint64_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo += pValue2->s.Lo; + if (pValue1Result->s.Lo < uTmp) + pValue1Result->s.Hi++; + pValue1Result->s.Hi += pValue2->s.Hi; + return pValue1Result; +} + + +/** + * Adds a 64-bit unsigned integer value to a 128-bit unsigned integer values, + * storing the result in the 128-bit one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignAddU64(PRTUINT128U pValue1Result, uint64_t uValue2) +{ + pValue1Result->s.Lo += uValue2; + if (pValue1Result->s.Lo < uValue2) + pValue1Result->s.Hi++; + return pValue1Result; +} + + +/** + * Subtracts two 128-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The minuend value and result. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignSub(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + uint64_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo -= pValue2->s.Lo; + if (pValue1Result->s.Lo > uTmp) + pValue1Result->s.Hi--; + pValue1Result->s.Hi -= pValue2->s.Hi; + return pValue1Result; +} + + +/** + * Negates a 128 number, storing the result in the input. + * + * @returns pValueResult. + * @param pValueResult The value to negate. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignNeg(PRTUINT128U pValueResult) +{ + /* result = 0 - value */ + if (pValueResult->s.Lo != 0) + { + pValueResult->s.Lo = UINT64_C(0) - pValueResult->s.Lo; + pValueResult->s.Hi = UINT64_MAX - pValueResult->s.Hi; + } + else + pValueResult->s.Hi = UINT64_C(0) - pValueResult->s.Hi; + return pValueResult; +} + + +/** + * Multiplies two 128-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignMul(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + RTUINT128U Result; + RTUInt128Mul(&Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 128-bit unsigned integer value by another, storing the result in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignDiv(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + RTUINT128U Result; + RTUINT128U Ignored; + RTUInt128DivRem(&Result, &Ignored, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 128-bit unsigned integer value by another, storing the remainder in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result (remainder). + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignMod(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + RTUINT128U Ignored; + RTUINT128U Result; + RTUInt128DivRem(&Ignored, &Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of two 128-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignAnd(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + pValue1Result->s.Hi &= pValue2->s.Hi; + pValue1Result->s.Lo &= pValue2->s.Lo; +#else + pValue1Result->DWords.dw0 &= pValue2->DWords.dw0; + pValue1Result->DWords.dw1 &= pValue2->DWords.dw1; + pValue1Result->DWords.dw2 &= pValue2->DWords.dw2; + pValue1Result->DWords.dw3 &= pValue2->DWords.dw3; +#endif + return pValue1Result; +} + + +/** + * Performs a bitwise AND of a 128-bit unsigned integer value and a mask made + * up of the first N bits, assigning the result to the the 128-bit value. + * + * @returns pValueResult. + * @param pValueResult The value and result. + * @param cBits The number of bits to AND (counting from the first + * bit). + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignAndNFirstBits(PRTUINT128U pValueResult, unsigned cBits) +{ + if (cBits <= 64) + { + if (cBits != 64) + pValueResult->s.Lo &= (RT_BIT_64(cBits) - 1); + pValueResult->s.Hi = 0; + } + else if (cBits < 128) + pValueResult->s.Hi &= (RT_BIT_64(cBits - 64) - 1); +/** @todo \#if ARCH_BITS >= 64 */ + return pValueResult; +} + + +/** + * Performs a bitwise OR of two 128-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignOr(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + pValue1Result->s.Hi |= pValue2->s.Hi; + pValue1Result->s.Lo |= pValue2->s.Lo; +#else + pValue1Result->DWords.dw0 |= pValue2->DWords.dw0; + pValue1Result->DWords.dw1 |= pValue2->DWords.dw1; + pValue1Result->DWords.dw2 |= pValue2->DWords.dw2; + pValue1Result->DWords.dw3 |= pValue2->DWords.dw3; +#endif + return pValue1Result; +} + + +/** + * ORs in a bit and assign the result to the input value. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param iBit The bit to set (0 based). + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignOrBit(PRTUINT128U pValue1Result, uint32_t iBit) +{ +#if ARCH_BITS >= 64 + if (iBit >= 64) + pValue1Result->s.Hi |= RT_BIT_64(iBit - 64); + else + pValue1Result->s.Lo |= RT_BIT_64(iBit); +#else + if (iBit >= 64) + { + if (iBit >= 96) + pValue1Result->DWords.dw3 |= RT_BIT_32(iBit - 96); + else + pValue1Result->DWords.dw2 |= RT_BIT_32(iBit - 64); + } + else + { + if (iBit >= 32) + pValue1Result->DWords.dw1 |= RT_BIT_32(iBit - 32); + else + pValue1Result->DWords.dw0 |= RT_BIT_32(iBit); + } +#endif + return pValue1Result; +} + + + +/** + * Performs a bitwise XOR of two 128-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignXor(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + pValue1Result->s.Hi ^= pValue2->s.Hi; + pValue1Result->s.Lo ^= pValue2->s.Lo; +#else + pValue1Result->DWords.dw0 ^= pValue2->DWords.dw0; + pValue1Result->DWords.dw1 ^= pValue2->DWords.dw1; + pValue1Result->DWords.dw2 ^= pValue2->DWords.dw2; + pValue1Result->DWords.dw3 ^= pValue2->DWords.dw3; +#endif + return pValue1Result; +} + + +/** + * Performs a bitwise left shift on a 128-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignShiftLeft(PRTUINT128U pValueResult, int cBits) +{ + RTUINT128U const InVal = *pValueResult; +/** @todo \#if ARCH_BITS >= 64 */ + if (cBits > 0) + { + /* (left shift) */ + if (cBits >= 128) + RTUInt128SetZero(pValueResult); + else if (cBits >= 64) + { + pValueResult->s.Lo = 0; + pValueResult->s.Hi = InVal.s.Lo << (cBits - 64); + } + else + { + pValueResult->s.Hi = InVal.s.Hi << cBits; + pValueResult->s.Hi |= InVal.s.Lo >> (64 - cBits); + pValueResult->s.Lo = InVal.s.Lo << cBits; + } + } + else if (cBits < 0) + { + /* (right shift) */ + cBits = -cBits; + if (cBits >= 128) + RTUInt128SetZero(pValueResult); + else if (cBits >= 64) + { + pValueResult->s.Hi = 0; + pValueResult->s.Lo = InVal.s.Hi >> (cBits - 64); + } + else + { + pValueResult->s.Lo = InVal.s.Lo >> cBits; + pValueResult->s.Lo |= InVal.s.Hi << (64 - cBits); + pValueResult->s.Hi = InVal.s.Hi >> cBits; + } + } + return pValueResult; +} + + +/** + * Performs a bitwise left shift on a 128-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignShiftRight(PRTUINT128U pValueResult, int cBits) +{ + return RTUInt128AssignShiftLeft(pValueResult, -cBits); +} + + +/** + * Performs a bitwise NOT on a 128-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignBitwiseNot(PRTUINT128U pValueResult) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Hi = ~pValueResult->s.Hi; + pValueResult->s.Lo = ~pValueResult->s.Lo; +#else + pValueResult->DWords.dw0 = ~pValueResult->DWords.dw0; + pValueResult->DWords.dw1 = ~pValueResult->DWords.dw1; + pValueResult->DWords.dw2 = ~pValueResult->DWords.dw2; + pValueResult->DWords.dw3 = ~pValueResult->DWords.dw3; +#endif + return pValueResult; +} + + +/** + * Performs a boolean NOT on a 128-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignBooleanNot(PRTUINT128U pValueResult) +{ + return RTUInt128AssignBoolean(pValueResult, RTUInt128IsZero(pValueResult)); +} + + +/** + * Compares two 128-bit unsigned integer values. + * + * @retval 0 if equal. + * @retval -1 if the first value is smaller than the second. + * @retval 1 if the first value is larger than the second. + * + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(int) RTUInt128Compare(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + if (pValue1->s.Hi != pValue2->s.Hi) + return pValue1->s.Hi > pValue2->s.Hi ? 1 : -1; + if (pValue1->s.Lo != pValue2->s.Lo) + return pValue1->s.Lo > pValue2->s.Lo ? 1 : -1; + return 0; +#else + if (pValue1->DWords.dw3 != pValue2->DWords.dw3) + return pValue1->DWords.dw3 > pValue2->DWords.dw3 ? 1 : -1; + if (pValue1->DWords.dw2 != pValue2->DWords.dw2) + return pValue1->DWords.dw2 > pValue2->DWords.dw2 ? 1 : -1; + if (pValue1->DWords.dw1 != pValue2->DWords.dw1) + return pValue1->DWords.dw1 > pValue2->DWords.dw1 ? 1 : -1; + if (pValue1->DWords.dw0 != pValue2->DWords.dw0) + return pValue1->DWords.dw0 > pValue2->DWords.dw0 ? 1 : -1; + return 0; +#endif +} + + +/** + * Tests if a 128-bit unsigned integer value is smaller than another. + * + * @returns true if the first value is smaller, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsSmaller(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + return pValue1->s.Hi < pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo < pValue2->s.Lo); +#else + return pValue1->DWords.dw3 < pValue2->DWords.dw3 + || ( pValue1->DWords.dw3 == pValue2->DWords.dw3 + && ( pValue1->DWords.dw2 < pValue2->DWords.dw2 + || ( pValue1->DWords.dw2 == pValue2->DWords.dw2 + && ( pValue1->DWords.dw1 < pValue2->DWords.dw1 + || ( pValue1->DWords.dw1 == pValue2->DWords.dw1 + && pValue1->DWords.dw0 < pValue2->DWords.dw0))))); +#endif +} + + +/** + * Tests if a 128-bit unsigned integer value is larger than another. + * + * @returns true if the first value is larger, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsLarger(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo > pValue2->s.Lo); +#else + return pValue1->DWords.dw3 > pValue2->DWords.dw3 + || ( pValue1->DWords.dw3 == pValue2->DWords.dw3 + && ( pValue1->DWords.dw2 > pValue2->DWords.dw2 + || ( pValue1->DWords.dw2 == pValue2->DWords.dw2 + && ( pValue1->DWords.dw1 > pValue2->DWords.dw1 + || ( pValue1->DWords.dw1 == pValue2->DWords.dw1 + && pValue1->DWords.dw0 > pValue2->DWords.dw0))))); +#endif +} + + +/** + * Tests if a 128-bit unsigned integer value is larger or equal than another. + * + * @returns true if the first value is larger or equal, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsLargerOrEqual(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo >= pValue2->s.Lo); +#else + return pValue1->DWords.dw3 > pValue2->DWords.dw3 + || ( pValue1->DWords.dw3 == pValue2->DWords.dw3 + && ( pValue1->DWords.dw2 > pValue2->DWords.dw2 + || ( pValue1->DWords.dw2 == pValue2->DWords.dw2 + && ( pValue1->DWords.dw1 > pValue2->DWords.dw1 + || ( pValue1->DWords.dw1 == pValue2->DWords.dw1 + && pValue1->DWords.dw0 >= pValue2->DWords.dw0))))); +#endif +} + + +/** + * Tests if two 128-bit unsigned integer values not equal. + * + * @returns true if equal, false if not equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsEqual(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + return pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo == pValue2->s.Lo; +#else + return pValue1->DWords.dw0 == pValue2->DWords.dw0 + && pValue1->DWords.dw1 == pValue2->DWords.dw1 + && pValue1->DWords.dw2 == pValue2->DWords.dw2 + && pValue1->DWords.dw3 == pValue2->DWords.dw3; +#endif +} + + +/** + * Tests if two 128-bit unsigned integer values are not equal. + * + * @returns true if not equal, false if equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsNotEqual(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + return !RTUInt128IsEqual(pValue1, pValue2); +} + + +/** + * Sets a bit in a 128-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT128U) RTUInt128BitSet(PRTUINT128U pValueResult, unsigned iBit) +{ + if (iBit < 64) + { +#if ARCH_BITS >= 64 + pValueResult->s.Lo |= RT_BIT_64(iBit); +#else + if (iBit < 32) + pValueResult->DWords.dw0 |= RT_BIT_32(iBit); + else + pValueResult->DWords.dw1 |= RT_BIT_32(iBit - 32); +#endif + } + else if (iBit < 128) + { +#if ARCH_BITS >= 64 + pValueResult->s.Hi |= RT_BIT_64(iBit - 64); +#else + if (iBit < 96) + pValueResult->DWords.dw2 |= RT_BIT_32(iBit - 64); + else + pValueResult->DWords.dw3 |= RT_BIT_32(iBit - 96); +#endif + } + return pValueResult; +} + + +/** + * Sets a bit in a 128-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT128U) RTUInt128BitClear(PRTUINT128U pValueResult, unsigned iBit) +{ + if (iBit < 64) + { +#if ARCH_BITS >= 64 + pValueResult->s.Lo &= ~RT_BIT_64(iBit); +#else + if (iBit < 32) + pValueResult->DWords.dw0 &= ~RT_BIT_32(iBit); + else + pValueResult->DWords.dw1 &= ~RT_BIT_32(iBit - 32); +#endif + } + else if (iBit < 128) + { +#if ARCH_BITS >= 64 + pValueResult->s.Hi &= ~RT_BIT_64(iBit - 64); +#else + if (iBit < 96) + pValueResult->DWords.dw2 &= ~RT_BIT_32(iBit - 64); + else + pValueResult->DWords.dw3 &= ~RT_BIT_32(iBit - 96); +#endif + } + return pValueResult; +} + + +/** + * Tests if a bit in a 128-bit unsigned integer value is set. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to test. + */ +DECLINLINE(bool) RTUInt128BitTest(PRTUINT128U pValueResult, unsigned iBit) +{ + bool fRc; + if (iBit < 64) + { +#if ARCH_BITS >= 64 + fRc = RT_BOOL(pValueResult->s.Lo & RT_BIT_64(iBit)); +#else + if (iBit < 32) + fRc = RT_BOOL(pValueResult->DWords.dw0 & RT_BIT_32(iBit)); + else + fRc = RT_BOOL(pValueResult->DWords.dw1 & RT_BIT_32(iBit - 32)); +#endif + } + else if (iBit < 128) + { +#if ARCH_BITS >= 64 + fRc = RT_BOOL(pValueResult->s.Hi & RT_BIT_64(iBit - 64)); +#else + if (iBit < 96) + fRc = RT_BOOL(pValueResult->DWords.dw2 & RT_BIT_32(iBit - 64)); + else + fRc = RT_BOOL(pValueResult->DWords.dw3 & RT_BIT_32(iBit - 96)); +#endif + } + else + fRc = false; + return fRc; +} + + +/** + * Set a range of bits a 128-bit unsigned integer value. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iFirstBit The first bit to test. + * @param cBits The number of bits to set. + */ +DECLINLINE(PRTUINT128U) RTUInt128BitSetRange(PRTUINT128U pValueResult, unsigned iFirstBit, unsigned cBits) +{ + /* bounds check & fix. */ + if (iFirstBit < 128) + { + if (iFirstBit + cBits > 128) + cBits = 128 - iFirstBit; + +#if ARCH_BITS >= 64 + if (iFirstBit + cBits < 64) + pValueResult->s.Lo |= (RT_BIT_64(cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 128 && iFirstBit >= 64) + pValueResult->s.Hi |= (RT_BIT_64(cBits) - 1) << (iFirstBit - 64); + else +#else + if (iFirstBit + cBits < 32) + pValueResult->DWords.dw0 |= (RT_BIT_32(cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 64 && iFirstBit >= 32) + pValueResult->DWords.dw1 |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 32); + else if (iFirstBit + cBits < 96 && iFirstBit >= 64) + pValueResult->DWords.dw2 |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 64); + else if (iFirstBit + cBits < 128 && iFirstBit >= 96) + pValueResult->DWords.dw3 |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 96); + else +#endif + while (cBits-- > 0) + RTUInt128BitSet(pValueResult, iFirstBit++); + } + return pValueResult; +} + + +/** + * Test if all the bits of a 128-bit unsigned integer value are set. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt128BitAreAllSet(PRTUINT128U pValue) +{ +#if ARCH_BITS >= 64 + return pValue->s.Hi == UINT64_MAX + && pValue->s.Lo == UINT64_MAX; +#else + return pValue->DWords.dw0 == UINT32_MAX + && pValue->DWords.dw1 == UINT32_MAX + && pValue->DWords.dw2 == UINT32_MAX + && pValue->DWords.dw3 == UINT32_MAX; +#endif +} + + +/** + * Test if all the bits of a 128-bit unsigned integer value are clear. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt128BitAreAllClear(PRTUINT128U pValue) +{ +#if ARCH_BITS >= 64 + return pValue->s.Hi == 0 + && pValue->s.Lo == 0; +#else + return pValue->DWords.dw0 == 0 + && pValue->DWords.dw1 == 0 + && pValue->DWords.dw2 == 0 + && pValue->DWords.dw3 == 0; +#endif +} + + +/** + * Number of significant bits in the value. + * + * This is the same a ASMBitLastSetU64 and ASMBitLastSetU32. + * + * @returns 0 if zero, 1-base index of the last bit set. + * @param pValue The value to examine. + */ +DECLINLINE(uint32_t) RTUInt128BitCount(PCRTUINT128U pValue) +{ + uint32_t cBits; + if (pValue->s.Hi != 0) + { + if (pValue->DWords.dw3) + cBits = 96 + ASMBitLastSetU32(pValue->DWords.dw3); + else + cBits = 64 + ASMBitLastSetU32(pValue->DWords.dw2); + } + else + { + if (pValue->DWords.dw1) + cBits = 32 + ASMBitLastSetU32(pValue->DWords.dw1); + else + cBits = 0 + ASMBitLastSetU32(pValue->DWords.dw0); + } + return cBits; +} + + +/** + * Divides a 128-bit unsigned integer value by another, returning both quotient + * and remainder. + * + * @returns pQuotient, NULL if pValue2 is 0. + * @param pQuotient Where to return the quotient. + * @param pRemainder Where to return the remainder. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128DivRem(PRTUINT128U pQuotient, PRTUINT128U pRemainder, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + int iDiff; + + /* + * Sort out all the special cases first. + */ + /* Divide by zero or 1? */ + if (!pValue2->s.Hi) + { + if (!pValue2->s.Lo) + return NULL; + + if (pValue2->s.Lo == 1) + { + RTUInt128SetZero(pRemainder); + *pQuotient = *pValue1; + return pQuotient; + } + /** @todo RTUint128DivModBy64 */ + } + + /* Dividend is smaller? */ + iDiff = RTUInt128Compare(pValue1, pValue2); + if (iDiff < 0) + { + *pRemainder = *pValue1; + RTUInt128SetZero(pQuotient); + } + + /* The values are equal? */ + else if (iDiff == 0) + { + RTUInt128SetZero(pRemainder); + RTUInt128AssignU64(pQuotient, 1); + } + else + { + /* + * Prepare. + */ + uint32_t iBitAdder = RTUInt128BitCount(pValue1) - RTUInt128BitCount(pValue2); + RTUINT128U NormDivisor = *pValue2; + if (iBitAdder) + { + RTUInt128ShiftLeft(&NormDivisor, pValue2, iBitAdder); + if (RTUInt128IsLarger(&NormDivisor, pValue1)) + { + RTUInt128AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + else + NormDivisor = *pValue2; + + RTUInt128SetZero(pQuotient); + *pRemainder = *pValue1; + + /* + * Do the division. + */ + if (RTUInt128IsLargerOrEqual(pRemainder, pValue2)) + { + for (;;) + { + if (RTUInt128IsLargerOrEqual(pRemainder, &NormDivisor)) + { + RTUInt128AssignSub(pRemainder, &NormDivisor); + RTUInt128AssignOrBit(pQuotient, iBitAdder); + } + if (RTUInt128IsSmaller(pRemainder, pValue2)) + break; + RTUInt128AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + } + return pQuotient; +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uint128_h */ + diff --git a/include/iprt/uint256.h b/include/iprt/uint256.h new file mode 100644 index 00000000..351f7f4e --- /dev/null +++ b/include/iprt/uint256.h @@ -0,0 +1,1241 @@ +/** @file + * IPRT - RTUINT256U methods. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uint256_h +#define IPRT_INCLUDED_uint256_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uint256 RTUInt256 - 256-bit Unsigned Integer Methods + * @ingroup grp_rt + * @{ + */ + + +/** + * Test if a 256-bit unsigned integer value is zero. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt256IsZero(PCRTUINT256U pValue) +{ +#if ARCH_BITS >= 64 + return pValue->QWords.qw0 == 0 + && pValue->QWords.qw1 == 0 + && pValue->QWords.qw2 == 0 + && pValue->QWords.qw3 == 0; +#else + return pValue->DWords.dw0 == 0 + && pValue->DWords.dw1 == 0 + && pValue->DWords.dw2 == 0 + && pValue->DWords.dw3 == 0 + && pValue->DWords.dw4 == 0 + && pValue->DWords.dw5 == 0 + && pValue->DWords.dw6 == 0 + && pValue->DWords.dw7 == 0; +#endif +} + + +/** + * Set a 256-bit unsigned integer value to zero. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT256U) RTUInt256SetZero(PRTUINT256U pResult) +{ +#if ARCH_BITS >= 64 + pResult->QWords.qw0 = 0; + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = 0; +#else + pResult->DWords.dw0 = 0; + pResult->DWords.dw1 = 0; + pResult->DWords.dw2 = 0; + pResult->DWords.dw3 = 0; + pResult->DWords.dw4 = 0; + pResult->DWords.dw5 = 0; + pResult->DWords.dw6 = 0; + pResult->DWords.dw7 = 0; +#endif + return pResult; +} + + +/** + * Set a 256-bit unsigned integer value to the maximum value. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT256U) RTUInt256SetMax(PRTUINT256U pResult) +{ +#if ARCH_BITS >= 64 + pResult->QWords.qw0 = UINT64_MAX; + pResult->QWords.qw1 = UINT64_MAX; + pResult->QWords.qw2 = UINT64_MAX; + pResult->QWords.qw3 = UINT64_MAX; +#else + pResult->DWords.dw0 = UINT32_MAX; + pResult->DWords.dw1 = UINT32_MAX; + pResult->DWords.dw2 = UINT32_MAX; + pResult->DWords.dw3 = UINT32_MAX; + pResult->DWords.dw4 = UINT32_MAX; + pResult->DWords.dw5 = UINT32_MAX; + pResult->DWords.dw6 = UINT32_MAX; + pResult->DWords.dw7 = UINT32_MAX; +#endif + return pResult; +} + + + + +/** + * Adds two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Add(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + unsigned uCarry; + pResult->QWords.qw0 = pValue1->QWords.qw0 + pValue2->QWords.qw0; + uCarry = pResult->QWords.qw0 < pValue1->QWords.qw0; + + pResult->QWords.qw1 = pValue1->QWords.qw1 + pValue2->QWords.qw1 + uCarry; + uCarry = uCarry ? pResult->QWords.qw1 <= pValue1->QWords.qw1 : pResult->QWords.qw1 < pValue1->QWords.qw1; + + pResult->QWords.qw2 = pValue1->QWords.qw2 + pValue2->QWords.qw2 + uCarry; + uCarry = uCarry ? pResult->QWords.qw2 <= pValue1->QWords.qw2 : pResult->QWords.qw2 < pValue1->QWords.qw2; + + pResult->QWords.qw3 = pValue1->QWords.qw3 + pValue2->QWords.qw3 + uCarry; + return pResult; +} + + +/** + * Adds a 256-bit and a 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT256U) RTUInt256AddU64(PRTUINT256U pResult, PCRTUINT256U pValue1, uint64_t uValue2) +{ + pResult->QWords.qw3 = pValue1->QWords.qw3; + pResult->QWords.qw2 = pValue1->QWords.qw2; + pResult->QWords.qw1 = pValue1->QWords.qw1; + pResult->QWords.qw0 = pValue1->QWords.qw0 + uValue2; + if (pResult->QWords.qw0 < uValue2) + if (pResult->QWords.qw1++ == UINT64_MAX) + if (pResult->QWords.qw2++ == UINT64_MAX) + pResult->QWords.qw3++; + return pResult; +} + + +/** + * Subtracts a 256-bit unsigned integer value from another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The minuend value. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Sub(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + unsigned uBorrow; + pResult->QWords.qw0 = pValue1->QWords.qw0 - pValue2->QWords.qw0; + uBorrow = pResult->QWords.qw0 > pValue1->QWords.qw0; + + pResult->QWords.qw1 = pValue1->QWords.qw1 - pValue2->QWords.qw1 - uBorrow; + uBorrow = uBorrow ? pResult->QWords.qw1 >= pValue1->QWords.qw1 : pResult->QWords.qw1 > pValue1->QWords.qw1; + + pResult->QWords.qw2 = pValue1->QWords.qw2 - pValue2->QWords.qw2 - uBorrow; + uBorrow = uBorrow ? pResult->QWords.qw2 >= pValue1->QWords.qw2 : pResult->QWords.qw2 > pValue1->QWords.qw2; + + pResult->QWords.qw3 = pValue1->QWords.qw3 - pValue2->QWords.qw3 - uBorrow; + return pResult; +} + + +/** + * Multiplies two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +RTDECL(PRTUINT256U) RTUInt256Mul(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2); + +/** + * Multiplies an 256-bit unsigned integer by a 64-bit unsigned integer value. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +RTDECL(PRTUINT256U) RTUInt256MulByU64(PRTUINT256U pResult, PCRTUINT256U pValue1, uint64_t uValue2); + +/** + * Divides a 256-bit unsigned integer value by another, returning both quotient + * and remainder. + * + * @returns pQuotient, NULL if pValue2 is 0. + * @param pQuotient Where to return the quotient. + * @param pRemainder Where to return the remainder. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +RTDECL(PRTUINT256U) RTUInt256DivRem(PRTUINT256U pQuotient, PRTUINT256U pRemainder, PCRTUINT256U pValue1, PCRTUINT256U pValue2); + +/** + * Divides a 256-bit unsigned integer value by another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Div(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + RTUINT256U Ignored; + return RTUInt256DivRem(pResult, &Ignored, pValue1, pValue2); +} + + +/** + * Divides a 256-bit unsigned integer value by another, returning the remainder. + * + * @returns pResult + * @param pResult The result variable (remainder). + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Mod(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + RTUINT256U Ignored; + RTUInt256DivRem(&Ignored, pResult, pValue1, pValue2); + return pResult; +} + + +/** + * Bitwise AND of two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256And(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + pResult->QWords.qw0 = pValue1->QWords.qw0 & pValue2->QWords.qw0; + pResult->QWords.qw1 = pValue1->QWords.qw1 & pValue2->QWords.qw1; + pResult->QWords.qw2 = pValue1->QWords.qw2 & pValue2->QWords.qw2; + pResult->QWords.qw3 = pValue1->QWords.qw3 & pValue2->QWords.qw3; + return pResult; +} + + +/** + * Bitwise OR of two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Or( PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + pResult->QWords.qw0 = pValue1->QWords.qw0 | pValue2->QWords.qw0; + pResult->QWords.qw1 = pValue1->QWords.qw1 | pValue2->QWords.qw1; + pResult->QWords.qw2 = pValue1->QWords.qw2 | pValue2->QWords.qw2; + pResult->QWords.qw3 = pValue1->QWords.qw3 | pValue2->QWords.qw3; + return pResult; +} + + +/** + * Bitwise XOR of two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Xor(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + pResult->QWords.qw0 = pValue1->QWords.qw0 ^ pValue2->QWords.qw0; + pResult->QWords.qw1 = pValue1->QWords.qw1 ^ pValue2->QWords.qw1; + pResult->QWords.qw2 = pValue1->QWords.qw2 ^ pValue2->QWords.qw2; + pResult->QWords.qw3 = pValue1->QWords.qw3 ^ pValue2->QWords.qw3; + return pResult; +} + + +/** + * Shifts a 256-bit unsigned integer value @a cBits to the left. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. This is masked + * by 255 before shifting. + */ +DECLINLINE(PRTUINT256U) RTUInt256ShiftLeft(PRTUINT256U pResult, PCRTUINT256U pValue, unsigned cBits) +{ + /* This is a bit bulky & impractical since we cannot access the data using + an array because it is organized according to host endianness. Sigh. */ + cBits &= 255; + if (!(cBits & 0x3f)) + { + if (cBits == 0) + *pResult = *pValue; + else + { + pResult->QWords.qw0 = 0; + if (cBits == 64) + { + pResult->QWords.qw1 = pValue->QWords.qw0; + pResult->QWords.qw2 = pValue->QWords.qw1; + pResult->QWords.qw3 = pValue->QWords.qw2; + } + else + { + pResult->QWords.qw1 = 0; + if (cBits == 128) + { + pResult->QWords.qw2 = pValue->QWords.qw0; + pResult->QWords.qw3 = pValue->QWords.qw1; + } + else + { + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = pValue->QWords.qw0; + } + } + } + } + else if (cBits < 128) + { + if (cBits < 64) + { + pResult->QWords.qw0 = pValue->QWords.qw0 << cBits; + pResult->QWords.qw1 = pValue->QWords.qw0 >> (64 - cBits); + pResult->QWords.qw1 |= pValue->QWords.qw1 << cBits; + pResult->QWords.qw2 = pValue->QWords.qw1 >> (64 - cBits); + pResult->QWords.qw2 |= pValue->QWords.qw2 << cBits; + pResult->QWords.qw3 = pValue->QWords.qw2 >> (64 - cBits); + pResult->QWords.qw3 |= pValue->QWords.qw3 << cBits; + } + else + { + cBits -= 64; + pResult->QWords.qw0 = 0; + pResult->QWords.qw1 = pValue->QWords.qw0 << cBits; + pResult->QWords.qw2 = pValue->QWords.qw0 >> (64 - cBits); + pResult->QWords.qw2 |= pValue->QWords.qw1 << cBits; + pResult->QWords.qw3 = pValue->QWords.qw1 >> (64 - cBits); + pResult->QWords.qw3 |= pValue->QWords.qw2 << cBits; + } + } + else + { + if (cBits < 192) + { + cBits -= 128; + pResult->QWords.qw0 = 0; + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = pValue->QWords.qw0 << cBits; + pResult->QWords.qw3 = pValue->QWords.qw0 >> (64 - cBits); + pResult->QWords.qw3 |= pValue->QWords.qw1 << cBits; + } + else + { + cBits -= 192; + pResult->QWords.qw0 = 0; + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = pValue->QWords.qw0 << cBits; + } + } + return pResult; +} + + +/** + * Shifts a 256-bit unsigned integer value @a cBits to the right. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. This is masked + * by 255 before shifting. + */ +DECLINLINE(PRTUINT256U) RTUInt256ShiftRight(PRTUINT256U pResult, PCRTUINT256U pValue, unsigned cBits) +{ + /* This is a bit bulky & impractical since we cannot access the data using + an array because it is organized according to host endianness. Sigh. */ + cBits &= 255; + if (!(cBits & 0x3f)) + { + if (cBits == 0) + *pResult = *pValue; + else + { + if (cBits == 64) + { + pResult->QWords.qw0 = pValue->QWords.qw1; + pResult->QWords.qw1 = pValue->QWords.qw2; + pResult->QWords.qw2 = pValue->QWords.qw3; + } + else + { + if (cBits == 128) + { + pResult->QWords.qw0 = pValue->QWords.qw2; + pResult->QWords.qw1 = pValue->QWords.qw3; + } + else + { + pResult->QWords.qw0 = pValue->QWords.qw3; + pResult->QWords.qw1 = 0; + } + pResult->QWords.qw2 = 0; + } + pResult->QWords.qw3 = 0; + } + } + else if (cBits < 128) + { + if (cBits < 64) + { + pResult->QWords.qw0 = pValue->QWords.qw0 >> cBits; + pResult->QWords.qw0 |= pValue->QWords.qw1 << (64 - cBits); + pResult->QWords.qw1 = pValue->QWords.qw1 >> cBits; + pResult->QWords.qw1 |= pValue->QWords.qw2 << (64 - cBits); + pResult->QWords.qw2 = pValue->QWords.qw2 >> cBits; + pResult->QWords.qw2 |= pValue->QWords.qw3 << (64 - cBits); + pResult->QWords.qw3 = pValue->QWords.qw3 >> cBits; + } + else + { + cBits -= 64; + pResult->QWords.qw0 = pValue->QWords.qw1 >> cBits; + pResult->QWords.qw0 |= pValue->QWords.qw2 << (64 - cBits); + pResult->QWords.qw1 = pValue->QWords.qw2 >> cBits; + pResult->QWords.qw1 |= pValue->QWords.qw3 << (64 - cBits); + pResult->QWords.qw2 = pValue->QWords.qw3 >> cBits; + pResult->QWords.qw3 = 0; + } + } + else + { + if (cBits < 192) + { + cBits -= 128; + pResult->QWords.qw0 = pValue->QWords.qw2 >> cBits; + pResult->QWords.qw0 |= pValue->QWords.qw3 << (64 - cBits); + pResult->QWords.qw1 = pValue->QWords.qw3 >> cBits; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = 0; + } + else + { + cBits -= 192; + pResult->QWords.qw0 = pValue->QWords.qw3 >> cBits; + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = 0; + } + } + return pResult; +} + + +/** + * Boolean not (result 0 or 1). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT256U) RTUInt256BooleanNot(PRTUINT256U pResult, PCRTUINT256U pValue) +{ + pResult->QWords.qw0 = RTUInt256IsZero(pValue); + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = 0; + return pResult; +} + + +/** + * Bitwise not (flips each bit of the 256 bits). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT256U) RTUInt256BitwiseNot(PRTUINT256U pResult, PCRTUINT256U pValue) +{ + pResult->QWords.qw0 = ~pValue->QWords.qw0; + pResult->QWords.qw1 = ~pValue->QWords.qw1; + pResult->QWords.qw2 = ~pValue->QWords.qw2; + pResult->QWords.qw3 = ~pValue->QWords.qw3; + return pResult; +} + + +/** + * Assigns one 256-bit unsigned integer value to another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to assign. + */ +DECLINLINE(PRTUINT256U) RTUInt256Assign(PRTUINT256U pResult, PCRTUINT256U pValue) +{ + pResult->QWords.qw0 = pValue->QWords.qw0; + pResult->QWords.qw1 = pValue->QWords.qw1; + pResult->QWords.qw2 = pValue->QWords.qw2; + pResult->QWords.qw3 = pValue->QWords.qw3; + return pResult; +} + + +/** + * Assigns a boolean value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param fValue The boolean value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignBoolean(PRTUINT256U pValueResult, bool fValue) +{ + pValueResult->QWords.qw0 = fValue; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Assigns a 8-bit unsigned integer value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u8Value The 8-bit unsigned integer value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignU8(PRTUINT256U pValueResult, uint8_t u8Value) +{ + pValueResult->QWords.qw0 = u8Value; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Assigns a 16-bit unsigned integer value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u16Value The 16-bit unsigned integer value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignU16(PRTUINT256U pValueResult, uint16_t u16Value) +{ + pValueResult->QWords.qw0 = u16Value; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Assigns a 32-bit unsigned integer value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u32Value The 32-bit unsigned integer value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignU32(PRTUINT256U pValueResult, uint32_t u32Value) +{ + pValueResult->QWords.qw0 = u32Value; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Assigns a 64-bit unsigned integer value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u64Value The 64-bit unsigned integer value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignU64(PRTUINT256U pValueResult, uint64_t u64Value) +{ + pValueResult->QWords.qw0 = u64Value; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Adds two 256-bit unsigned integer values, storing the result in the first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignAdd(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U const uTmpValue1 = *pValue1Result; /* lazy bird */ + return RTUInt256Add(pValue1Result, &uTmpValue1, pValue2); +} + + +/** + * Adds a 64-bit unsigned integer value to a 256-bit unsigned integer values, + * storing the result in the 256-bit one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignAddU64(PRTUINT256U pValue1Result, uint64_t uValue2) +{ + RTUINT256U const uTmpValue1 = *pValue1Result; /* lazy bird */ + return RTUInt256AddU64(pValue1Result, &uTmpValue1, uValue2); +} + + +/** + * Subtracts two 256-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The minuend value and result. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignSub(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U const uTmpValue1 = *pValue1Result; /* lazy bird */ + return RTUInt256Sub(pValue1Result, &uTmpValue1, pValue2); +} + + +#if 0 +/** + * Negates a 256 number, storing the result in the input. + * + * @returns pValueResult. + * @param pValueResult The value to negate. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignNeg(PRTUINT256U pValueResult) +{ + /* result = 0 - value */ + if (pValueResult->s.Lo != 0) + { + pValueResult->s.Lo = UINT64_C(0) - pValueResult->s.Lo; + pValueResult->s.Hi = UINT64_MAX - pValueResult->s.Hi; + } + else + pValueResult->s.Hi = UINT64_C(0) - pValueResult->s.Hi; + return pValueResult; +} +#endif + + +/** + * Multiplies two 256-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignMul(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U Result; + RTUInt256Mul(&Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 256-bit unsigned integer value by another, storing the result in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignDiv(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U Result; + RTUINT256U Ignored; + RTUInt256DivRem(&Result, &Ignored, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 256-bit unsigned integer value by another, storing the remainder in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result (remainder). + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignMod(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U Ignored; + RTUINT256U Result; + RTUInt256DivRem(&Ignored, &Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of two 256-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignAnd(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + pValue1Result->QWords.qw0 &= pValue2->QWords.qw0; + pValue1Result->QWords.qw1 &= pValue2->QWords.qw1; + pValue1Result->QWords.qw2 &= pValue2->QWords.qw2; + pValue1Result->QWords.qw3 &= pValue2->QWords.qw3; + return pValue1Result; +} + + +#if 0 +/** + * Performs a bitwise AND of a 256-bit unsigned integer value and a mask made + * up of the first N bits, assigning the result to the the 256-bit value. + * + * @returns pValueResult. + * @param pValueResult The value and result. + * @param cBits The number of bits to AND (counting from the first + * bit). + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignAndNFirstBits(PRTUINT256U pValueResult, unsigned cBits) +{ + if (cBits <= 64) + { + if (cBits != 64) + pValueResult->s.Lo &= (RT_BIT_64(cBits) - 1); + pValueResult->s.Hi = 0; + } + else if (cBits < 256) + pValueResult->s.Hi &= (RT_BIT_64(cBits - 64) - 1); +/** @todo \#if ARCH_BITS >= 64 */ + return pValueResult; +} +#endif + + +/** + * Performs a bitwise OR of two 256-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignOr(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + pValue1Result->QWords.qw0 |= pValue2->QWords.qw0; + pValue1Result->QWords.qw1 |= pValue2->QWords.qw1; + pValue1Result->QWords.qw2 |= pValue2->QWords.qw2; + pValue1Result->QWords.qw3 |= pValue2->QWords.qw3; + return pValue1Result; +} + + +DECLINLINE(PRTUINT256U) RTUInt256BitSet(PRTUINT256U pValueResult, unsigned iBit); + +/** + * ORs in a bit and assign the result to the input value. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param iBit The bit to set (0 based). + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignOrBit(PRTUINT256U pValue1Result, uint32_t iBit) +{ + return RTUInt256BitSet(pValue1Result, (unsigned)iBit); +} + + +/** + * Performs a bitwise XOR of two 256-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignXor(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + pValue1Result->QWords.qw0 ^= pValue2->QWords.qw0; + pValue1Result->QWords.qw1 ^= pValue2->QWords.qw1; + pValue1Result->QWords.qw2 ^= pValue2->QWords.qw2; + pValue1Result->QWords.qw3 ^= pValue2->QWords.qw3; + return pValue1Result; +} + + +/** + * Performs a bitwise left shift on a 256-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift - signed. Negative + * values are translated to right shifts. If the + * absolute value is 256 or higher, the value is set to + * zero. + * + * @note This works differently from RTUInt256ShiftLeft and + * RTUInt256ShiftRight in that the shift count is signed and not masked + * by 255. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignShiftLeft(PRTUINT256U pValueResult, int cBits) +{ + if (cBits == 0) + return pValueResult; + if (cBits > 0) + { + /* (left shift) */ + if (cBits < 256) + { + RTUINT256U const InVal = *pValueResult; + return RTUInt256ShiftLeft(pValueResult, &InVal, cBits); + } + } + else if (cBits > -256) + { + /* (right shift) */ + cBits = -cBits; + RTUINT256U const InVal = *pValueResult; + return RTUInt256ShiftRight(pValueResult, &InVal, cBits); + } + return RTUInt256SetZero(pValueResult); +} + + +/** + * Performs a bitwise left shift on a 256-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift - signed. Negative + * values are translated to left shifts. If the + * absolute value is 256 or higher, the value is set to + * zero. + * + * @note This works differently from RTUInt256ShiftRight and + * RTUInt256ShiftLeft in that the shift count is signed and not masked + * by 255. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignShiftRight(PRTUINT256U pValueResult, int cBits) +{ + if (cBits == 0) + return pValueResult; + if (cBits > 0) + { + /* (right shift) */ + if (cBits < 256) + { + RTUINT256U const InVal = *pValueResult; + return RTUInt256ShiftRight(pValueResult, &InVal, cBits); + } + } + else if (cBits > -256) + { + /* (left shift) */ + cBits = -cBits; + RTUINT256U const InVal = *pValueResult; + return RTUInt256ShiftLeft(pValueResult, &InVal, cBits); + } + return RTUInt256SetZero(pValueResult); +} + + +/** + * Performs a bitwise NOT on a 256-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignBitwiseNot(PRTUINT256U pValueResult) +{ + pValueResult->QWords.qw0 = ~pValueResult->QWords.qw0; + pValueResult->QWords.qw1 = ~pValueResult->QWords.qw1; + pValueResult->QWords.qw2 = ~pValueResult->QWords.qw2; + pValueResult->QWords.qw3 = ~pValueResult->QWords.qw3; + return pValueResult; +} + + +/** + * Performs a boolean NOT on a 256-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignBooleanNot(PRTUINT256U pValueResult) +{ + return RTUInt256AssignBoolean(pValueResult, RTUInt256IsZero(pValueResult)); +} + + +/** + * Compares two 256-bit unsigned integer values. + * + * @retval 0 if equal. + * @retval -1 if the first value is smaller than the second. + * @retval 1 if the first value is larger than the second. + * + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(int) RTUInt256Compare(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + if (pValue1->QWords.qw3 != pValue2->QWords.qw3) + return pValue1->QWords.qw3 > pValue2->QWords.qw3 ? 1 : -1; + if (pValue1->QWords.qw2 != pValue2->QWords.qw2) + return pValue1->QWords.qw2 > pValue2->QWords.qw2 ? 1 : -1; + if (pValue1->QWords.qw1 != pValue2->QWords.qw1) + return pValue1->QWords.qw1 > pValue2->QWords.qw1 ? 1 : -1; + if (pValue1->QWords.qw0 != pValue2->QWords.qw0) + return pValue1->QWords.qw3 > pValue2->QWords.qw3 ? 1 : -1; + return 0; +} + + +/** + * Tests if a 256-bit unsigned integer value is smaller than another. + * + * @returns true if the first value is smaller, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsSmaller(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return pValue1->QWords.qw3 < pValue2->QWords.qw3 + || ( pValue1->QWords.qw3 == pValue2->QWords.qw3 + && ( pValue1->QWords.qw2 < pValue2->QWords.qw2 + || ( pValue1->QWords.qw2 == pValue2->QWords.qw2 + && ( pValue1->QWords.qw1 < pValue2->QWords.qw1 + || ( pValue1->QWords.qw1 == pValue2->QWords.qw1 + && pValue1->QWords.qw0 < pValue2->QWords.qw0))))); +} + + +/** + * Tests if a 256-bit unsigned integer value is larger than another. + * + * @returns true if the first value is larger, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsLarger(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return pValue1->QWords.qw3 > pValue2->QWords.qw3 + || ( pValue1->QWords.qw3 == pValue2->QWords.qw3 + && ( pValue1->QWords.qw2 > pValue2->QWords.qw2 + || ( pValue1->QWords.qw2 == pValue2->QWords.qw2 + && ( pValue1->QWords.qw1 > pValue2->QWords.qw1 + || ( pValue1->QWords.qw1 == pValue2->QWords.qw1 + && pValue1->QWords.qw0 > pValue2->QWords.qw0))))); +} + + +/** + * Tests if a 256-bit unsigned integer value is larger or equal than another. + * + * @returns true if the first value is larger or equal, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsLargerOrEqual(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return pValue1->QWords.qw3 > pValue2->QWords.qw3 + || ( pValue1->QWords.qw3 == pValue2->QWords.qw3 + && ( pValue1->QWords.qw2 > pValue2->QWords.qw2 + || ( pValue1->QWords.qw2 == pValue2->QWords.qw2 + && ( pValue1->QWords.qw1 > pValue2->QWords.qw1 + || ( pValue1->QWords.qw1 == pValue2->QWords.qw1 + && pValue1->QWords.qw0 >= pValue2->DWords.dw0))))); +} + + +/** + * Tests if two 256-bit unsigned integer values not equal. + * + * @returns true if equal, false if not equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsEqual(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return pValue1->QWords.qw0 == pValue2->QWords.qw0 + && pValue1->QWords.qw1 == pValue2->QWords.qw1 + && pValue1->QWords.qw2 == pValue2->QWords.qw2 + && pValue1->QWords.qw3 == pValue2->QWords.qw3; +} + + +/** + * Tests if two 256-bit unsigned integer values are not equal. + * + * @returns true if not equal, false if equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsNotEqual(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return !RTUInt256IsEqual(pValue1, pValue2); +} + + +/** + * Sets a bit in a 256-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT256U) RTUInt256BitSet(PRTUINT256U pValueResult, unsigned iBit) +{ + if (iBit < 256) + { + unsigned idxQWord = iBit >> 6; +#ifdef RT_BIG_ENDIAN + idxQWord = RT_ELEMENTS(pValueResult->au64) - idxQWord; +#endif + iBit &= 0x3f; + pValueResult->au64[idxQWord] |= RT_BIT_64(iBit); + } + return pValueResult; +} + + +/** + * Sets a bit in a 256-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT256U) RTUInt256BitClear(PRTUINT256U pValueResult, unsigned iBit) +{ + if (iBit < 256) + { + unsigned idxQWord = iBit >> 6; +#ifdef RT_BIG_ENDIAN + idxQWord = RT_ELEMENTS(pValueResult->au64) - idxQWord; +#endif + iBit &= 0x3f; + pValueResult->au64[idxQWord] &= ~RT_BIT_64(iBit); + } + return pValueResult; +} + + +/** + * Tests if a bit in a 256-bit unsigned integer value is set. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to test. + */ +DECLINLINE(bool) RTUInt256BitTest(PRTUINT256U pValueResult, unsigned iBit) +{ + bool fRc; + if (iBit < 256) + { + unsigned idxQWord = iBit >> 6; +#ifdef RT_BIG_ENDIAN + idxQWord = RT_ELEMENTS(pValueResult->au64) - idxQWord; +#endif + iBit &= 0x3f; + fRc = RT_BOOL(pValueResult->au64[idxQWord] & RT_BIT_64(iBit)); + } + else + fRc = false; + return fRc; +} + + +/** + * Set a range of bits a 256-bit unsigned integer value. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iFirstBit The first bit to test. + * @param cBits The number of bits to set. + */ +DECLINLINE(PRTUINT256U) RTUInt256BitSetRange(PRTUINT256U pValueResult, unsigned iFirstBit, unsigned cBits) +{ + /* bounds check & fix. */ + if (iFirstBit < 256) + { + if (iFirstBit + cBits > 256) + cBits = 256 - iFirstBit; + + /* Work the au64 array: */ +#ifdef RT_BIG_ENDIAN + int idxQWord = RT_ELEMENTS(pValueResult->au64) - (iFirstBit >> 6); + int const idxInc = -1; +#else + int idxQWord = iFirstBit >> 6; + int const idxInc = 1; +#endif + while (cBits > 0) + { + unsigned iQWordFirstBit = iFirstBit & 0x3f; + unsigned cQWordBits = cBits + iQWordFirstBit >= 64 ? 64 - iQWordFirstBit : cBits; + pValueResult->au64[idxQWord] |= cQWordBits < 64 ? (RT_BIT_64(cQWordBits) - 1) << iQWordFirstBit : UINT64_MAX; + + idxQWord += idxInc; + iFirstBit += cQWordBits; + cBits -= cQWordBits; + } + } + return pValueResult; +} + + +/** + * Test if all the bits of a 256-bit unsigned integer value are set. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt256BitAreAllSet(PRTUINT256U pValue) +{ + return pValue->QWords.qw0 == UINT64_MAX + && pValue->QWords.qw1 == UINT64_MAX + && pValue->QWords.qw2 == UINT64_MAX + && pValue->QWords.qw3 == UINT64_MAX; +} + + +/** + * Test if all the bits of a 256-bit unsigned integer value are clear. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt256BitAreAllClear(PRTUINT256U pValue) +{ + return RTUInt256IsZero(pValue); +} + + +/** + * Number of significant bits in the value. + * + * This is the same a ASMBitLastSetU64 and ASMBitLastSetU32. + * + * @returns 0 if zero, 1-base index of the last bit set. + * @param pValue The value to examine. + */ +DECLINLINE(uint32_t) RTUInt256BitCount(PCRTUINT256U pValue) +{ + uint64_t u64; + uint32_t cBits; + if ((u64 = pValue->QWords.qw3) != 0) + cBits = 192; + else if ((u64 = pValue->QWords.qw2) != 0) + cBits = 128; + else if ((u64 = pValue->QWords.qw1) != 0) + cBits = 64; + else + { + u64 = pValue->QWords.qw0; + cBits = 0; + } + return cBits + ASMBitLastSetU64(u64); +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uint256_h */ + diff --git a/include/iprt/uint32.h b/include/iprt/uint32.h new file mode 100644 index 00000000..46140142 --- /dev/null +++ b/include/iprt/uint32.h @@ -0,0 +1,1068 @@ +/** @file + * IPRT - RTUINT32U methods for old 16-bit compilers (mainly for division). + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uint32_h +#define IPRT_INCLUDED_uint32_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uint32 RTUInt32 - 32-bit Unsigned Integer Methods for 16-bit compilers. + * @ingroup grp_rt + * @{ + */ + +#define RTUINT32_HAVE_32BIT_BASICS + + +/** + * Test if a 32-bit unsigned integer value is zero. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt32IsZero(PRTUINT32U pValue) +{ + return pValue->s.Lo == 0 + && pValue->s.Hi == 0; +} + + +/** + * Set a 32-bit unsigned integer value to zero. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT32U) RTUInt32SetZero(PRTUINT32U pResult) +{ + pResult->s.Hi = 0; + pResult->s.Lo = 0; + return pResult; +} + + +/** + * Set a 32-bit unsigned integer value to the maximum value. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT32U) RTUInt32SetMax(PRTUINT32U pResult) +{ + pResult->s.Hi = UINT16_MAX; + pResult->s.Lo = UINT16_MAX; + return pResult; +} + + + + +/** + * Adds two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Add(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue1->u + pValue2->u; +#else + pResult->s.Hi = pValue1->s.Hi + pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo + pValue2->s.Lo; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; +#endif + return pResult; +} + + +/** + * Adds a 32-bit and a 16-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 16-bit. + */ +DECLINLINE(PRTUINT32U) RTUInt32AddU16(PRTUINT32U pResult, PCRTUINT32U pValue1, uint16_t uValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue1->u + uValue2; +#else + pResult->s.Hi = pValue1->s.Hi; + pResult->s.Lo = pValue1->s.Lo + uValue2; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; +#endif + return pResult; +} + + +/** + * Subtracts a 32-bit unsigned integer value from another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The minuend value. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Sub(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue1->u - pValue2->u; +#else + pResult->s.Lo = pValue1->s.Lo - pValue2->s.Lo; + pResult->s.Hi = pValue1->s.Hi - pValue2->s.Hi; + if (pResult->s.Lo > pValue1->s.Lo) + pResult->s.Hi--; +#endif + return pResult; +} + + +/** + * Multiplies two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Mul(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + pResult->u = (uint32_t)pValue1->s.Lo * pValue2->s.Lo; + pResult->s.Hi += pValue1->s.Hi * pValue2->s.Lo; + pResult->s.Hi += pValue1->s.Lo * pValue2->s.Hi; + + return pResult; +} + + +/** + * Multiplies an 32-bit unsigned integer by a 16-bit unsigned integer value. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 16-bit. + */ +DECLINLINE(PRTUINT32U) RTUInt32MulByU16(PRTUINT32U pResult, PCRTUINT32U pValue1, uint16_t uValue2) +{ + pResult->u = (uint32_t)pValue1->s.Lo * uValue2; + pResult->s.Hi += pValue1->s.Hi * uValue2; + return pResult; +} + + +DECLINLINE(PRTUINT32U) RTUInt32DivRem(PRTUINT32U pQuotient, PRTUINT32U pRemainder, PCRTUINT32U pValue1, PCRTUINT32U pValue2); + +/** + * Divides a 32-bit unsigned integer value by another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Div(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + RTUINT32U Ignored; + return RTUInt32DivRem(pResult, &Ignored, pValue1, pValue2); +} + + +/** + * Divides a 32-bit unsigned integer value by another, returning the remainder. + * + * @returns pResult + * @param pResult The result variable (remainder). + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Mod(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + RTUINT32U Ignored; + RTUInt32DivRem(&Ignored, pResult, pValue1, pValue2); + return pResult; +} + + +/** + * Bitwise AND of two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32And(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi & pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo & pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise OR of two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Or( PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi | pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo | pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise XOR of two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Xor(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi ^ pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo ^ pValue2->s.Lo; + return pResult; +} + + +/** + * Shifts a 32-bit unsigned integer value @a cBits to the left. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT32U) RTUInt32ShiftLeft(PRTUINT32U pResult, PCRTUINT32U pValue, int cBits) +{ + cBits &= 31; +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue->u << cBits; +#else + if (cBits < 16) + { + pResult->s.Lo = pValue->s.Lo << cBits; + pResult->s.Hi = (pValue->s.Hi << cBits) | (pValue->s.Lo >> (16 - cBits)); + } + else + { + pResult->s.Lo = 0; + pResult->s.Hi = pValue->s.Lo << (cBits - 16); + } +#endif + return pResult; +} + + +/** + * Shifts a 32-bit unsigned integer value @a cBits to the right. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT32U) RTUInt32ShiftRight(PRTUINT32U pResult, PCRTUINT32U pValue, int cBits) +{ + cBits &= 31; +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue->u >> cBits; +#else + if (cBits < 16) + { + pResult->s.Hi = pValue->s.Hi >> cBits; + pResult->s.Lo = (pValue->s.Lo >> cBits) | (pValue->s.Hi << (16 - cBits)); + } + else + { + pResult->s.Hi = 0; + pResult->s.Lo = pValue->s.Hi >> (cBits - 16); + } +#endif + return pResult; +} + + +/** + * Boolean not (result 0 or 1). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT32U) RTUInt32BooleanNot(PRTUINT32U pResult, PCRTUINT32U pValue) +{ + pResult->s.Lo = pValue->s.Lo || pValue->s.Hi ? 0 : 1; + pResult->s.Hi = 0; + return pResult; +} + + +/** + * Bitwise not (flips each bit of the 32 bits). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT32U) RTUInt32BitwiseNot(PRTUINT32U pResult, PCRTUINT32U pValue) +{ + pResult->s.Hi = ~pValue->s.Hi; + pResult->s.Lo = ~pValue->s.Lo; + return pResult; +} + + +/** + * Assigns one 32-bit unsigned integer value to another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to assign. + */ +DECLINLINE(PRTUINT32U) RTUInt32Assign(PRTUINT32U pResult, PCRTUINT32U pValue) +{ + pResult->s.Hi = pValue->s.Hi; + pResult->s.Lo = pValue->s.Lo; + return pResult; +} + + +/** + * Assigns a boolean value to 32-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param fValue The boolean value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignBoolean(PRTUINT32U pValueResult, bool fValue) +{ + pValueResult->s.Lo = fValue; + pValueResult->s.Hi = 0; + return pValueResult; +} + + +/** + * Assigns a 8-bit unsigned integer value to 32-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u8Value The 8-bit unsigned integer value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignU8(PRTUINT32U pValueResult, uint8_t u8Value) +{ + pValueResult->s.Lo = u8Value; + pValueResult->s.Hi = 0; + return pValueResult; +} + + +/** + * Assigns a 16-bit unsigned integer value to 32-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u16Value The 16-bit unsigned integer value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignU16(PRTUINT32U pValueResult, uint16_t u16Value) +{ + pValueResult->s.Lo = u16Value; + pValueResult->s.Hi = 0; + return pValueResult; +} + + +/** + * Adds two 32-bit unsigned integer values, storing the result in the first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignAdd(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValue1Result->u += pValue2->u; +#else + uint16_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo += pValue2->s.Lo; + if (pValue1Result->s.Lo < uTmp) + pValue1Result->s.Hi++; + pValue1Result->s.Hi += pValue2->s.Hi; +#endif + return pValue1Result; +} + + +/** + * Subtracts two 32-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The minuend value and result. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignSub(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValue1Result->u -= pValue2->u; +#else + uint32_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo -= pValue2->s.Lo; + if (pValue1Result->s.Lo > uTmp) + pValue1Result->s.Hi--; + pValue1Result->s.Hi -= pValue2->s.Hi; +#endif + return pValue1Result; +} + + +/** + * Multiplies two 32-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignMul(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + RTUINT32U Result; + RTUInt32Mul(&Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 32-bit unsigned integer value by another, storing the result in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignDiv(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + RTUINT32U Result; + RTUINT32U Ignored; + RTUInt32DivRem(&Result, &Ignored, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 32-bit unsigned integer value by another, storing the remainder in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result (remainder). + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignMod(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + RTUINT32U Ignored; + RTUINT32U Result; + RTUInt32DivRem(&Ignored, &Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of two 32-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignAnd(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + pValue1Result->s.Hi &= pValue2->s.Hi; + pValue1Result->s.Lo &= pValue2->s.Lo; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of a 32-bit unsigned integer value and a mask made up + * of the first N bits, assigning the result to the the 32-bit value. + * + * @returns pValueResult. + * @param pValueResult The value and result. + * @param cBits The number of bits to AND (counting from the first + * bit). + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignAndNFirstBits(PRTUINT32U pValueResult, unsigned cBits) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (cBits < 32) + pValueResult->u &= RT_BIT_32(cBits) - 1; +#else + if (cBits <= 16) + { + if (cBits != 16) + pValueResult->s.Lo &= (UINT16_C(1) << cBits) - 1; + pValueResult->s.Hi = 0; + } + else if (cBits < 16) + pValueResult->s.Hi &= (UINT16_C(1) << (cBits - 16)) - 1; +#endif + return pValueResult; +} + + +/** + * Performs a bitwise OR of two 32-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignOr(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + pValue1Result->s.Hi |= pValue2->s.Hi; + pValue1Result->s.Lo |= pValue2->s.Lo; + return pValue1Result; +} + + +/** + * ORs in a bit and assign the result to the input value. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param iBit The bit to set (0 based). + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignOrBit(PRTUINT32U pValue1Result, unsigned iBit) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValue1Result->u |= RT_BIT_32(iBit); +#else + if (iBit >= 32) + pValue1Result->s.Hi |= UINT16_C(1) << (iBit - 32); + else + pValue1Result->s.Lo |= UINT16_C(1) << iBit; +#endif + return pValue1Result; +} + + + +/** + * Performs a bitwise XOR of two 32-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignXor(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + pValue1Result->s.Hi ^= pValue2->s.Hi; + pValue1Result->s.Lo ^= pValue2->s.Lo; + return pValue1Result; +} + + +/** + * Performs a bitwise left shift on a 32-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignShiftLeft(PRTUINT32U pValueResult, int cBits) +{ +#ifndef RTUINT32_HAVE_32BIT_BASICS + RTUINT32U const InVal = *pValueResult; +#endif + if (cBits > 0) + { + /* (left shift) */ + cBits &= 31; +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValueResult->u <<= cBits; +#else + if (cBits >= 16) + { + pValueResult->s.Lo = 0; + pValueResult->s.Hi = InVal.s.Lo << (cBits - 16); + } + else + { + pValueResult->s.Hi = InVal.s.Hi << cBits; + pValueResult->s.Hi |= InVal.s.Lo >> (16 - cBits); + pValueResult->s.Lo = InVal.s.Lo << cBits; + } +#endif + } + else if (cBits < 0) + { + /* (right shift) */ + cBits = -cBits; + cBits &= 31; +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValueResult->u >>= cBits; +#else + if (cBits >= 16) + { + pValueResult->s.Hi = 0; + pValueResult->s.Lo = InVal.s.Hi >> (cBits - 16); + } + else + { + pValueResult->s.Lo = InVal.s.Lo >> cBits; + pValueResult->s.Lo |= InVal.s.Hi << (16 - cBits); + pValueResult->s.Hi = InVal.s.Hi >> cBits; + } +#endif + } + return pValueResult; +} + + +/** + * Performs a bitwise left shift on a 32-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignShiftRight(PRTUINT32U pValueResult, int cBits) +{ + return RTUInt32AssignShiftLeft(pValueResult, -cBits); +} + + +/** + * Performs a bitwise NOT on a 32-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignBitwiseNot(PRTUINT32U pValueResult) +{ + pValueResult->s.Hi = ~pValueResult->s.Hi; + pValueResult->s.Lo = ~pValueResult->s.Lo; + return pValueResult; +} + + +/** + * Performs a boolean NOT on a 32-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignBooleanNot(PRTUINT32U pValueResult) +{ + return RTUInt32AssignBoolean(pValueResult, RTUInt32IsZero(pValueResult)); +} + + +/** + * Compares two 32-bit unsigned integer values. + * + * @retval 0 if equal. + * @retval -1 if the first value is smaller than the second. + * @retval 1 if the first value is larger than the second. + * + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(int) RTUInt32Compare(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + if (pValue1->s.Hi != pValue2->s.Hi) + return pValue1->s.Hi > pValue2->s.Hi ? 1 : -1; + if (pValue1->s.Lo != pValue2->s.Lo) + return pValue1->s.Lo > pValue2->s.Lo ? 1 : -1; + return 0; +} + + +/** + * Tests if a 64-bit unsigned integer value is smaller than another. + * + * @returns true if the first value is smaller, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsSmaller(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + return pValue1->u < pValue2->u; +#else + return pValue1->s.Hi < pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo < pValue2->s.Lo); +#endif +} + + +/** + * Tests if a 32-bit unsigned integer value is larger than another. + * + * @returns true if the first value is larger, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsLarger(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + return pValue1->u > pValue2->u; +#else + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo > pValue2->s.Lo); +#endif +} + + +/** + * Tests if a 64-bit unsigned integer value is larger or equal than another. + * + * @returns true if the first value is larger or equal, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsLargerOrEqual(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + return pValue1->u >= pValue2->u; +#else + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo >= pValue2->s.Lo); +#endif +} + + +/** + * Tests if two 64-bit unsigned integer values not equal. + * + * @returns true if equal, false if not equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsEqual(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + return pValue1->u == pValue2->u; +#else + return pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo == pValue2->s.Lo; +#endif +} + + +/** + * Tests if two 64-bit unsigned integer values are not equal. + * + * @returns true if not equal, false if equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsNotEqual(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + return !RTUInt32IsEqual(pValue1, pValue2); +} + + +/** + * Sets a bit in a 32-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT32U) RTUInt32BitSet(PRTUINT32U pValueResult, unsigned iBit) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (iBit < 32) + pValueResult->u |= RT_BIT_32(iBit); +#else + if (iBit < 16) + pValueResult->s.Lo |= UINT16_C(1) << iBit; + else if (iBit < 32) + pValueResult->s.Hi |= UINT16_C(1) << (iBit - 32); +#endif + return pValueResult; +} + + +/** + * Sets a bit in a 32-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT32U) RTUInt32BitClear(PRTUINT32U pValueResult, unsigned iBit) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (iBit < 32) + pValueResult->u &= ~RT_BIT_32(iBit); + +#else + if (iBit < 16) + pValueResult->s.Lo &= ~RT_BIT_32(iBit); + else if (iBit < 32) + pValueResult->s.Hi &= ~RT_BIT_32(iBit - 32); +#endif + return pValueResult; +} + + +/** + * Tests if a bit in a 32-bit unsigned integer value is set. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to test. + */ +DECLINLINE(bool) RTUInt32BitTest(PRTUINT32U pValueResult, unsigned iBit) +{ + bool fRc; +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (iBit < 32) + fRc = RT_BOOL(pValueResult->u & RT_BIT_32(iBit)); +#else + if (iBit < 16) + fRc = RT_BOOL(pValueResult->s.Lo & (UINT16_C(1) << iBit)); + else if (iBit < 32) + fRc = RT_BOOL(pValueResult->s.Hi & (UINT16_C(1) << (iBit - 64))); +#endif + else + fRc = false; + return fRc; +} + + +/** + * Set a range of bits a 32-bit unsigned integer value. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iFirstBit The first bit to test. + * @param cBits The number of bits to set. + */ +DECLINLINE(PRTUINT32U) RTUInt32BitSetRange(PRTUINT32U pValueResult, unsigned iFirstBit, unsigned cBits) +{ + /* bounds check & fix. */ + if (iFirstBit < 32) + { +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (iFirstBit + cBits < 32) + pValueResult->u |= (RT_BIT_32(cBits) - 1) << iFirstBit; + else + pValueResult->u = UINT32_MAX << iFirstBit; +#else + if (iFirstBit + cBits > 32) + cBits = 32 - iFirstBit; + if (iFirstBit + cBits < 16) + pValueResult->s.Lo |= ((UINT16_C(1) << cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 32 && iFirstBit >= 16) + pValueResult->s.Hi |= ((UINT16_C(1) << cBits) - 1) << (iFirstBit - 16); + else + while (cBits-- > 0) + RTUInt32BitSet(pValueResult, iFirstBit++); +#endif + } + return pValueResult; +} + + +/** + * Test if all the bits of a 32-bit unsigned integer value are set. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt32BitAreAllSet(PRTUINT32U pValue) +{ + return pValue->s.Hi == UINT16_MAX + && pValue->s.Lo == UINT16_MAX; +} + + +/** + * Test if all the bits of a 32-bit unsigned integer value are clear. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt32BitAreAllClear(PRTUINT32U pValue) +{ + return RTUInt32IsZero(pValue); +} + + +DECLINLINE(unsigned) RTUInt32BitCount(PCRTUINT32U pValue) +{ + unsigned cBits; + if (pValue->s.Hi != 0) + cBits = 16 + ASMBitLastSetU16(pValue->s.Hi); + else + cBits = ASMBitLastSetU16(pValue->s.Lo); + return cBits; +} + + +/** + * Divides a 32-bit unsigned integer value by another, returning both quotient + * and remainder. + * + * @returns pQuotient, NULL if pValue2 is 0. + * @param pQuotient Where to return the quotient. + * @param pRemainder Where to return the remainder. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32DivRem(PRTUINT32U pQuotient, PRTUINT32U pRemainder, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + int iDiff; + + /* + * Sort out all the special cases first. + */ + /* Divide by zero or 1? */ + if (!pValue2->s.Hi) + { + if (!pValue2->s.Lo) + return NULL; + + if (pValue2->s.Lo == 1) + { + RTUInt32SetZero(pRemainder); + *pQuotient = *pValue1; + return pQuotient; + } + /** @todo RTUInt32DivModByU32 */ + } + + /* Dividend is smaller? */ + iDiff = RTUInt32Compare(pValue1, pValue2); + if (iDiff < 0) + { + *pRemainder = *pValue1; + RTUInt32SetZero(pQuotient); + } + + /* The values are equal? */ + else if (iDiff == 0) + { + RTUInt32SetZero(pRemainder); + RTUInt32AssignU8(pQuotient, 1); + } + else + { + /* + * Prepare. + */ + unsigned iBitAdder = RTUInt32BitCount(pValue1) - RTUInt32BitCount(pValue2); + RTUINT32U NormDivisor = *pValue2; + if (iBitAdder) + { + RTUInt32ShiftLeft(&NormDivisor, pValue2, iBitAdder); + if (RTUInt32IsLarger(&NormDivisor, pValue1)) + { + RTUInt32AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + else + NormDivisor = *pValue2; + + RTUInt32SetZero(pQuotient); + *pRemainder = *pValue1; + + /* + * Do the division. + */ + if (RTUInt32IsLargerOrEqual(pRemainder, pValue2)) + { + for (;;) + { + if (RTUInt32IsLargerOrEqual(pRemainder, &NormDivisor)) + { + RTUInt32AssignSub(pRemainder, &NormDivisor); + RTUInt32AssignOrBit(pQuotient, iBitAdder); + } + if (RTUInt32IsSmaller(pRemainder, pValue2)) + break; + RTUInt32AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + } + return pQuotient; +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uint32_h */ + diff --git a/include/iprt/uint64.h b/include/iprt/uint64.h new file mode 100644 index 00000000..8e9cf0e5 --- /dev/null +++ b/include/iprt/uint64.h @@ -0,0 +1,1343 @@ +/** @file + * IPRT - RTUINT64U methods for old 32-bit and 16-bit compilers. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uint64_h +#define IPRT_INCLUDED_uint64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uint64 RTUInt64 - 64-bit Unsigned Integer Methods for ancient compilers + * @ingroup grp_rt + * @{ + */ + + +/** + * Test if a 128-bit unsigned integer value is zero. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt64IsZero(PRTUINT64U pValue) +{ +#if ARCH_BITS >= 32 + return pValue->s.Lo == 0 + && pValue->s.Hi == 0; +#else + return pValue->Words.w0 == 0 + && pValue->Words.w1 == 0 + && pValue->Words.w2 == 0 + && pValue->Words.w3 == 0; +#endif +} + + +/** + * Set a 128-bit unsigned integer value to zero. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT64U) RTUInt64SetZero(PRTUINT64U pResult) +{ +#if ARCH_BITS >= 32 + pResult->s.Hi = 0; + pResult->s.Lo = 0; +#else + pResult->Words.w0 = 0; + pResult->Words.w1 = 0; + pResult->Words.w2 = 0; + pResult->Words.w3 = 0; +#endif + return pResult; +} + + +/** + * Set a 32-bit unsigned integer value to the maximum value. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT64U) RTUInt64SetMax(PRTUINT64U pResult) +{ +#if ARCH_BITS >= 32 + pResult->s.Hi = UINT32_MAX; + pResult->s.Lo = UINT32_MAX; +#else + pResult->Words.w0 = UINT16_MAX; + pResult->Words.w1 = UINT16_MAX; + pResult->Words.w2 = UINT16_MAX; + pResult->Words.w3 = UINT16_MAX; +#endif + return pResult; +} + + + + +/** + * Adds two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Add(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi + pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo + pValue2->s.Lo; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; + return pResult; +} + + +/** + * Adds a 64-bit and a 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 32-bit. + */ +DECLINLINE(PRTUINT64U) RTUInt64AddU32(PRTUINT64U pResult, PCRTUINT64U pValue1, uint32_t uValue2) +{ + pResult->s.Hi = pValue1->s.Hi; + pResult->s.Lo = pValue1->s.Lo + uValue2; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; + return pResult; +} + + +/** + * Subtracts a 64-bit unsigned integer value from another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The minuend value. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Sub(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Lo = pValue1->s.Lo - pValue2->s.Lo; + pResult->s.Hi = pValue1->s.Hi - pValue2->s.Hi; + if (pResult->s.Lo > pValue1->s.Lo) + pResult->s.Hi--; + return pResult; +} + + +/** + * Multiplies two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Mul(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + RTUINT32U uTmp; + + /* multiply all words in v1 by v2.w0. */ + pResult->s.Lo = (uint32_t)pValue1->Words.w0 * pValue2->Words.w0; + + uTmp.u = (uint32_t)pValue1->Words.w1 * pValue2->Words.w0; + pResult->Words.w3 = 0; + pResult->Words.w2 = uTmp.Words.w1; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)pValue1->Words.w2 * pValue2->Words.w0; + pResult->Words.w3 += pValue1->Words.w3 * pValue2->Words.w0; + + /* multiply w0, w1 & w2 in v1 by v2.w1. */ + uTmp.u = (uint32_t)pValue1->Words.w0 * pValue2->Words.w1; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->Words.w2 += uTmp.Words.w1; + if (pResult->Words.w2 < uTmp.Words.w1) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)pValue1->Words.w1 * pValue2->Words.w1; + pResult->Words.w3 += pValue1->Words.w2 * pValue2->Words.w1; + + /* multiply w0 & w1 in v1 by v2.w2. */ + pResult->s.Hi += (uint32_t)pValue1->Words.w0 * pValue2->Words.w2; + pResult->Words.w3 += pValue1->Words.w1 * pValue2->Words.w2; + + /* multiply w0 in v1 by v2.w3. */ + pResult->Words.w3 += pValue1->Words.w0 * pValue2->Words.w3; + + return pResult; +} + + +/** + * Multiplies an 64-bit unsigned integer by a 32-bit unsigned integer value. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 32-bit. + */ +DECLINLINE(PRTUINT64U) RTUInt64MulByU32(PRTUINT64U pResult, PCRTUINT64U pValue1, uint32_t uValue2) +{ + uint16_t const uLoValue2 = (uint16_t)uValue2; + uint16_t const uHiValue2 = (uint16_t)(uValue2 >> 16); + RTUINT32U uTmp; + + /* multiply all words in v1 by uLoValue1. */ + pResult->s.Lo = (uint32_t)pValue1->Words.w0 * uLoValue2; + + uTmp.u = (uint32_t)pValue1->Words.w1 * uLoValue2; + pResult->Words.w3 = 0; + pResult->Words.w2 = uTmp.Words.w1; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)pValue1->Words.w2 * uLoValue2; + pResult->Words.w3 += pValue1->Words.w3 * uLoValue2; + + /* multiply w0, w1 & w2 in v1 by uHiValue2. */ + uTmp.u = (uint32_t)pValue1->Words.w0 * uHiValue2; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->Words.w2 += uTmp.Words.w1; + if (pResult->Words.w2 < uTmp.Words.w1) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)pValue1->Words.w1 * uHiValue2; + pResult->Words.w3 += pValue1->Words.w2 * uHiValue2; + + return pResult; +} + + +/** + * Multiplies two 32-bit unsigned integer values with 64-bit precision. + * + * @returns pResult + * @param pResult The result variable. + * @param uValue1 The first value. 32-bit. + * @param uValue2 The second value, 32-bit. + */ +DECLINLINE(PRTUINT64U) RTUInt64MulU32ByU32(PRTUINT64U pResult, uint32_t uValue1, uint32_t uValue2) +{ + uint16_t const uLoValue1 = (uint16_t)uValue1; + uint16_t const uHiValue1 = (uint16_t)(uValue1 >> 16); + uint16_t const uLoValue2 = (uint16_t)uValue2; + uint16_t const uHiValue2 = (uint16_t)(uValue2 >> 16); + RTUINT32U uTmp; + + /* Multiply uLoValue1 and uHiValue1 by uLoValue1. */ + pResult->s.Lo = (uint32_t)uLoValue1 * uLoValue2; + + uTmp.u = (uint32_t)uHiValue1 * uLoValue2; + pResult->Words.w3 = 0; + pResult->Words.w2 = uTmp.Words.w1; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + /* Multiply uLoValue1 and uHiValue1 by uHiValue2. */ + uTmp.u = (uint32_t)uLoValue1 * uHiValue2; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->Words.w2 += uTmp.Words.w1; + if (pResult->Words.w2 < uTmp.Words.w1) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)uHiValue1 * uHiValue2; + return pResult; +} + + +DECLINLINE(PRTUINT64U) RTUInt64DivRem(PRTUINT64U pQuotient, PRTUINT64U pRemainder, PCRTUINT64U pValue1, PCRTUINT64U pValue2); + +/** + * Divides a 64-bit unsigned integer value by another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Div(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + RTUINT64U Ignored; + return RTUInt64DivRem(pResult, &Ignored, pValue1, pValue2); +} + + +/** + * Divides a 64-bit unsigned integer value by another, returning the remainder. + * + * @returns pResult + * @param pResult The result variable (remainder). + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Mod(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + RTUINT64U Ignored; + RTUInt64DivRem(&Ignored, pResult, pValue1, pValue2); + return pResult; +} + + +/** + * Bitwise AND of two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64And(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi & pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo & pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise OR of two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Or( PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi | pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo | pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise XOR of two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Xor(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi ^ pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo ^ pValue2->s.Lo; + return pResult; +} + + +/** + * Shifts a 64-bit unsigned integer value @a cBits to the left. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT64U) RTUInt64ShiftLeft(PRTUINT64U pResult, PCRTUINT64U pValue, int cBits) +{ + cBits &= 63; + if (cBits < 32) + { + pResult->s.Lo = pValue->s.Lo << cBits; + pResult->s.Hi = (pValue->s.Hi << cBits) | (pValue->s.Lo >> (32 - cBits)); + } + else + { + pResult->s.Lo = 0; + pResult->s.Hi = pValue->s.Lo << (cBits - 32); + } + return pResult; +} + + +/** + * Shifts a 64-bit unsigned integer value @a cBits to the right. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT64U) RTUInt64ShiftRight(PRTUINT64U pResult, PCRTUINT64U pValue, int cBits) +{ + cBits &= 63; + if (cBits < 32) + { + pResult->s.Hi = pValue->s.Hi >> cBits; + pResult->s.Lo = (pValue->s.Lo >> cBits) | (pValue->s.Hi << (32 - cBits)); + } + else + { + pResult->s.Hi = 0; + pResult->s.Lo = pValue->s.Hi >> (cBits - 32); + } + return pResult; +} + + +/** + * Boolean not (result 0 or 1). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT64U) RTUInt64BooleanNot(PRTUINT64U pResult, PCRTUINT64U pValue) +{ + pResult->s.Lo = pValue->s.Lo || pValue->s.Hi ? 0 : 1; + pResult->s.Hi = 0; + return pResult; +} + + +/** + * Bitwise not (flips each bit of the 64 bits). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT64U) RTUInt64BitwiseNot(PRTUINT64U pResult, PCRTUINT64U pValue) +{ + pResult->s.Hi = ~pValue->s.Hi; + pResult->s.Lo = ~pValue->s.Lo; + return pResult; +} + + +/** + * Assigns one 64-bit unsigned integer value to another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to assign. + */ +DECLINLINE(PRTUINT64U) RTUInt64Assign(PRTUINT64U pResult, PCRTUINT64U pValue) +{ +#if ARCH_BITS >= 32 + pResult->s.Hi = pValue->s.Hi; + pResult->s.Lo = pValue->s.Lo; +#else + pResult->Words.w0 = pValue->Words.w0; + pResult->Words.w1 = pValue->Words.w1; + pResult->Words.w2 = pValue->Words.w2; + pResult->Words.w3 = pValue->Words.w3; +#endif + return pResult; +} + + +/** + * Assigns a boolean value to 64-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param fValue The boolean value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignBoolean(PRTUINT64U pValueResult, bool fValue) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Lo = fValue; + pValueResult->s.Hi = 0; +#else + pValueResult->Words.w0 = fValue; + pValueResult->Words.w1 = 0; + pValueResult->Words.w2 = 0; + pValueResult->Words.w3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 8-bit unsigned integer value to 64-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u8Value The 8-bit unsigned integer value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignU8(PRTUINT64U pValueResult, uint8_t u8Value) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Lo = u8Value; + pValueResult->s.Hi = 0; +#else + pValueResult->Words.w0 = u8Value; + pValueResult->Words.w1 = 0; + pValueResult->Words.w2 = 0; + pValueResult->Words.w3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 16-bit unsigned integer value to 64-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u16Value The 16-bit unsigned integer value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignU16(PRTUINT64U pValueResult, uint16_t u16Value) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Lo = u16Value; + pValueResult->s.Hi = 0; +#else + pValueResult->Words.w0 = u16Value; + pValueResult->Words.w1 = 0; + pValueResult->Words.w2 = 0; + pValueResult->Words.w3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 32-bit unsigned integer value to 64-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u32Value The 32-bit unsigned integer value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignU32(PRTUINT64U pValueResult, uint32_t u32Value) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Lo = u32Value; + pValueResult->s.Hi = 0; +#else + pValueResult->Words.w0 = (uint16_t)u32Value; + pValueResult->Words.w1 = u32Value >> 16; + pValueResult->Words.w2 = 0; + pValueResult->Words.w3 = 0; +#endif + return pValueResult; +} + + +/** + * Adds two 64-bit unsigned integer values, storing the result in the first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignAdd(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + uint32_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo += pValue2->s.Lo; + if (pValue1Result->s.Lo < uTmp) + pValue1Result->s.Hi++; + pValue1Result->s.Hi += pValue2->s.Hi; + return pValue1Result; +} + + +/** + * Subtracts two 64-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The minuend value and result. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignSub(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + uint32_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo -= pValue2->s.Lo; + if (pValue1Result->s.Lo > uTmp) + pValue1Result->s.Hi--; + pValue1Result->s.Hi -= pValue2->s.Hi; + return pValue1Result; +} + + +/** + * Multiplies two 64-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignMul(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + RTUINT64U Result; + RTUInt64Mul(&Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 64-bit unsigned integer value by another, storing the result in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignDiv(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + RTUINT64U Result; + RTUINT64U Ignored; + RTUInt64DivRem(&Result, &Ignored, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 64-bit unsigned integer value by another, storing the remainder in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result (remainder). + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignMod(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + RTUINT64U Ignored; + RTUINT64U Result; + RTUInt64DivRem(&Ignored, &Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of two 64-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignAnd(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + pValue1Result->s.Hi &= pValue2->s.Hi; + pValue1Result->s.Lo &= pValue2->s.Lo; +#else + pValue1Result->Words.w0 &= pValue2->Words.w0; + pValue1Result->Words.w1 &= pValue2->Words.w1; + pValue1Result->Words.w2 &= pValue2->Words.w2; + pValue1Result->Words.w3 &= pValue2->Words.w3; +#endif + return pValue1Result; +} + + +/** + * Performs a bitwise AND of a 64-bit unsigned integer value and a mask made + * up of the first N bits, assigning the result to the the 64-bit value. + * + * @returns pValueResult. + * @param pValueResult The value and result. + * @param cBits The number of bits to AND (counting from the first + * bit). + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignAndNFirstBits(PRTUINT64U pValueResult, unsigned cBits) +{ + if (cBits <= 32) + { + if (cBits != 32) + pValueResult->s.Lo &= (RT_BIT_32(cBits) - 1); + pValueResult->s.Hi = 0; + } + else if (cBits < 64) + pValueResult->s.Hi &= (RT_BIT_32(cBits - 32) - 1); + return pValueResult; +} + + +/** + * Performs a bitwise OR of two 64-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignOr(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + pValue1Result->s.Hi |= pValue2->s.Hi; + pValue1Result->s.Lo |= pValue2->s.Lo; +#else + pValue1Result->Words.w0 |= pValue2->Words.w0; + pValue1Result->Words.w1 |= pValue2->Words.w1; + pValue1Result->Words.w2 |= pValue2->Words.w2; + pValue1Result->Words.w3 |= pValue2->Words.w3; +#endif + return pValue1Result; +} + + +/** + * ORs in a bit and assign the result to the input value. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param iBit The bit to set (0 based). + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignOrBit(PRTUINT64U pValue1Result, unsigned iBit) +{ +#if ARCH_BITS >= 32 + if (iBit >= 32) + pValue1Result->s.Hi |= RT_BIT_32(iBit - 32); + else + pValue1Result->s.Lo |= RT_BIT_32(iBit); +#else + if (iBit >= 32) + { + if (iBit >= 48) + pValue1Result->Words.w3 |= UINT16_C(1) << (iBit - 48); + else + pValue1Result->Words.w2 |= UINT16_C(1) << (iBit - 32); + } + else + { + if (iBit >= 16) + pValue1Result->Words.w1 |= UINT16_C(1) << (iBit - 16); + else + pValue1Result->Words.w0 |= UINT16_C(1) << (iBit); + } +#endif + return pValue1Result; +} + + + +/** + * Performs a bitwise XOR of two 64-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignXor(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + pValue1Result->s.Hi ^= pValue2->s.Hi; + pValue1Result->s.Lo ^= pValue2->s.Lo; +#else + pValue1Result->Words.w0 ^= pValue2->Words.w0; + pValue1Result->Words.w1 ^= pValue2->Words.w1; + pValue1Result->Words.w2 ^= pValue2->Words.w2; + pValue1Result->Words.w3 ^= pValue2->Words.w3; +#endif + return pValue1Result; +} + + +/** + * Performs a bitwise left shift on a 64-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignShiftLeft(PRTUINT64U pValueResult, int cBits) +{ + RTUINT64U const InVal = *pValueResult; + if (cBits > 0) + { + /* (left shift) */ + cBits &= 31; + if (cBits >= 32) + { + pValueResult->s.Lo = 0; + pValueResult->s.Hi = InVal.s.Lo << (cBits - 32); + } + else + { + pValueResult->s.Hi = InVal.s.Hi << cBits; + pValueResult->s.Hi |= InVal.s.Lo >> (32 - cBits); + pValueResult->s.Lo = InVal.s.Lo << cBits; + } + } + else if (cBits < 0) + { + /* (right shift) */ + cBits = -cBits; + cBits &= 31; + if (cBits >= 32) + { + pValueResult->s.Hi = 0; + pValueResult->s.Lo = InVal.s.Hi >> (cBits - 32); + } + else + { + pValueResult->s.Lo = InVal.s.Lo >> cBits; + pValueResult->s.Lo |= InVal.s.Hi << (32 - cBits); + pValueResult->s.Hi = InVal.s.Hi >> cBits; + } + } + return pValueResult; +} + + +/** + * Performs a bitwise left shift on a 64-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignShiftRight(PRTUINT64U pValueResult, int cBits) +{ + return RTUInt64AssignShiftLeft(pValueResult, -cBits); +} + + +/** + * Performs a bitwise NOT on a 64-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignBitwiseNot(PRTUINT64U pValueResult) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Hi = ~pValueResult->s.Hi; + pValueResult->s.Lo = ~pValueResult->s.Lo; +#else + pValueResult->Words.w0 = ~pValueResult->Words.w0; + pValueResult->Words.w1 = ~pValueResult->Words.w1; + pValueResult->Words.w2 = ~pValueResult->Words.w2; + pValueResult->Words.w3 = ~pValueResult->Words.w3; +#endif + return pValueResult; +} + + +/** + * Performs a boolean NOT on a 64-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignBooleanNot(PRTUINT64U pValueResult) +{ + return RTUInt64AssignBoolean(pValueResult, RTUInt64IsZero(pValueResult)); +} + + +/** + * Compares two 64-bit unsigned integer values. + * + * @retval 0 if equal. + * @retval -1 if the first value is smaller than the second. + * @retval 1 if the first value is larger than the second. + * + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(int) RTUInt64Compare(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + if (pValue1->s.Hi != pValue2->s.Hi) + return pValue1->s.Hi > pValue2->s.Hi ? 1 : -1; + if (pValue1->s.Lo != pValue2->s.Lo) + return pValue1->s.Lo > pValue2->s.Lo ? 1 : -1; + return 0; +#else + if (pValue1->Words.w3 != pValue2->Words.w3) + return pValue1->Words.w3 > pValue2->Words.w3 ? 1 : -1; + if (pValue1->Words.w2 != pValue2->Words.w2) + return pValue1->Words.w2 > pValue2->Words.w2 ? 1 : -1; + if (pValue1->Words.w1 != pValue2->Words.w1) + return pValue1->Words.w1 > pValue2->Words.w1 ? 1 : -1; + if (pValue1->Words.w0 != pValue2->Words.w0) + return pValue1->Words.w0 > pValue2->Words.w0 ? 1 : -1; + return 0; +#endif +} + + +/** + * Tests if a 64-bit unsigned integer value is smaller than another. + * + * @returns true if the first value is smaller, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsSmaller(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + return pValue1->s.Hi < pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo < pValue2->s.Lo); +#else + return pValue1->Words.w3 < pValue2->Words.w3 + || ( pValue1->Words.w3 == pValue2->Words.w3 + && ( pValue1->Words.w2 < pValue2->Words.w2 + || ( pValue1->Words.w2 == pValue2->Words.w2 + && ( pValue1->Words.w1 < pValue2->Words.w1 + || ( pValue1->Words.w1 == pValue2->Words.w1 + && pValue1->Words.w0 < pValue2->Words.w0))))); +#endif +} + + +/** + * Tests if a 32-bit unsigned integer value is larger than another. + * + * @returns true if the first value is larger, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsLarger(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo > pValue2->s.Lo); +#else + return pValue1->Words.w3 > pValue2->Words.w3 + || ( pValue1->Words.w3 == pValue2->Words.w3 + && ( pValue1->Words.w2 > pValue2->Words.w2 + || ( pValue1->Words.w2 == pValue2->Words.w2 + && ( pValue1->Words.w1 > pValue2->Words.w1 + || ( pValue1->Words.w1 == pValue2->Words.w1 + && pValue1->Words.w0 > pValue2->Words.w0))))); +#endif +} + + +/** + * Tests if a 64-bit unsigned integer value is larger or equal than another. + * + * @returns true if the first value is larger or equal, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsLargerOrEqual(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo >= pValue2->s.Lo); +#else + return pValue1->Words.w3 > pValue2->Words.w3 + || ( pValue1->Words.w3 == pValue2->Words.w3 + && ( pValue1->Words.w2 > pValue2->Words.w2 + || ( pValue1->Words.w2 == pValue2->Words.w2 + && ( pValue1->Words.w1 > pValue2->Words.w1 + || ( pValue1->Words.w1 == pValue2->Words.w1 + && pValue1->Words.w0 >= pValue2->Words.w0))))); +#endif +} + + +/** + * Tests if two 64-bit unsigned integer values not equal. + * + * @returns true if equal, false if not equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsEqual(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + return pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo == pValue2->s.Lo; +#else + return pValue1->Words.w0 == pValue2->Words.w0 + && pValue1->Words.w1 == pValue2->Words.w1 + && pValue1->Words.w2 == pValue2->Words.w2 + && pValue1->Words.w3 == pValue2->Words.w3; +#endif +} + + +/** + * Tests if two 64-bit unsigned integer values are not equal. + * + * @returns true if not equal, false if equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsNotEqual(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + return !RTUInt64IsEqual(pValue1, pValue2); +} + + +/** + * Sets a bit in a 64-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT64U) RTUInt64BitSet(PRTUINT64U pValueResult, unsigned iBit) +{ + if (iBit < 32) + { +#if ARCH_BITS >= 32 + pValueResult->s.Lo |= RT_BIT_32(iBit); +#else + if (iBit < 16) + pValueResult->Words.w0 |= UINT16_C(1) << iBit; + else + pValueResult->Words.w1 |= UINT16_C(1) << (iBit - 32); +#endif + } + else if (iBit < 64) + { +#if ARCH_BITS >= 32 + pValueResult->s.Hi |= RT_BIT_32(iBit - 32); +#else + if (iBit < 48) + pValueResult->Words.w2 |= UINT16_C(1) << (iBit - 64); + else + pValueResult->Words.w3 |= UINT16_C(1) << (iBit - 96); +#endif + } + return pValueResult; +} + + +/** + * Sets a bit in a 64-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT64U) RTUInt64BitClear(PRTUINT64U pValueResult, unsigned iBit) +{ + if (iBit < 32) + { +#if ARCH_BITS >= 32 + pValueResult->s.Lo &= ~RT_BIT_32(iBit); +#else + if (iBit < 48) + pValueResult->Words.w0 &= ~(UINT16_C(1) << (iBit)); + else + pValueResult->Words.w1 &= ~(UINT16_C(1) << (iBit - 32)); +#endif + } + else if (iBit < 64) + { +#if ARCH_BITS >= 32 + pValueResult->s.Hi &= ~RT_BIT_32(iBit - 32); +#else + if (iBit < 48) + pValueResult->Words.w2 &= ~(UINT16_C(1) << (iBit - 64)); + else + pValueResult->Words.w3 &= ~(UINT16_C(1) << (iBit - 96)); +#endif + } + return pValueResult; +} + + +/** + * Tests if a bit in a 64-bit unsigned integer value is set. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to test. + */ +DECLINLINE(bool) RTUInt64BitTest(PRTUINT64U pValueResult, unsigned iBit) +{ + bool fRc; + if (iBit < 32) + { +#if ARCH_BITS >= 32 + fRc = RT_BOOL(pValueResult->s.Lo & RT_BIT_32(iBit)); +#else + if (iBit < 16) + fRc = RT_BOOL(pValueResult->Words.w0 & (UINT16_C(1) << (iBit))); + else + fRc = RT_BOOL(pValueResult->Words.w1 & (UINT16_C(1) << (iBit - 16))); +#endif + } + else if (iBit < 64) + { +#if ARCH_BITS >= 32 + fRc = RT_BOOL(pValueResult->s.Hi & RT_BIT_32(iBit - 32)); +#else + if (iBit < 48) + fRc = RT_BOOL(pValueResult->Words.w2 & (UINT16_C(1) << (iBit - 32))); + else + fRc = RT_BOOL(pValueResult->Words.w3 & (UINT16_C(1) << (iBit - 48))); +#endif + } + else + fRc = false; + return fRc; +} + + +/** + * Set a range of bits a 64-bit unsigned integer value. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iFirstBit The first bit to test. + * @param cBits The number of bits to set. + */ +DECLINLINE(PRTUINT64U) RTUInt64BitSetRange(PRTUINT64U pValueResult, unsigned iFirstBit, unsigned cBits) +{ + /* bounds check & fix. */ + if (iFirstBit < 64) + { + if (iFirstBit + cBits > 64) + cBits = 64 - iFirstBit; + +#if ARCH_BITS >= 32 + if (iFirstBit + cBits < 32) + pValueResult->s.Lo |= (RT_BIT_32(cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 64 && iFirstBit >= 32) + pValueResult->s.Hi |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 32); + else +#else + if (iFirstBit + cBits < 16) + pValueResult->Words.w0 |= ((UINT16_C(1) << cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 32 && iFirstBit >= 16) + pValueResult->Words.w1 |= ((UINT16_C(1) << cBits) - 1) << (iFirstBit - 16); + else if (iFirstBit + cBits < 48 && iFirstBit >= 32) + pValueResult->Words.w2 |= ((UINT16_C(1) << cBits) - 1) << (iFirstBit - 32); + else if (iFirstBit + cBits < 64 && iFirstBit >= 48) + pValueResult->Words.w3 |= ((UINT16_C(1) << cBits) - 1) << (iFirstBit - 48); + else +#endif + while (cBits-- > 0) + RTUInt64BitSet(pValueResult, iFirstBit++); + } + return pValueResult; +} + + +/** + * Test if all the bits of a 64-bit unsigned integer value are set. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt64BitAreAllSet(PRTUINT64U pValue) +{ +#if ARCH_BITS >= 32 + return pValue->s.Hi == UINT32_MAX + && pValue->s.Lo == UINT32_MAX; +#else + return pValue->Words.w0 == UINT16_MAX + && pValue->Words.w1 == UINT16_MAX + && pValue->Words.w2 == UINT16_MAX + && pValue->Words.w3 == UINT16_MAX; +#endif +} + + +/** + * Test if all the bits of a 64-bit unsigned integer value are clear. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt64BitAreAllClear(PRTUINT64U pValue) +{ + return RTUInt64IsZero(pValue); +} + + +DECLINLINE(unsigned) RTUInt64BitCount(PCRTUINT64U pValue) +{ + unsigned cBits; + if (pValue->s.Hi != 0) + { +#if ARCH_BITS >= 32 + cBits = 32 + ASMBitLastSetU32(pValue->s.Hi); +#else + if (pValue->Words.w3) + cBits = 48 + ASMBitLastSetU16(pValue->Words.w3); + else + cBits = 32 + ASMBitLastSetU16(pValue->Words.w2); +#endif + } + else + { +#if ARCH_BITS >= 32 + cBits = ASMBitLastSetU32(pValue->s.Lo); +#else + if (pValue->Words.w1) + cBits = 16 + ASMBitLastSetU16(pValue->Words.w1); + else + cBits = 0 + ASMBitLastSetU16(pValue->Words.w0); +#endif + } + return cBits; +} + + +/** + * Divides a 64-bit unsigned integer value by another, returning both quotient + * and remainder. + * + * @returns pQuotient, NULL if pValue2 is 0. + * @param pQuotient Where to return the quotient. + * @param pRemainder Where to return the remainder. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64DivRem(PRTUINT64U pQuotient, PRTUINT64U pRemainder, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + int iDiff; + + /* + * Sort out all the special cases first. + */ + /* Divide by zero or 1? */ + if (!pValue2->s.Hi) + { + if (!pValue2->s.Lo) + return NULL; + + if (pValue2->s.Lo == 1) + { + RTUInt64SetZero(pRemainder); + *pQuotient = *pValue1; + return pQuotient; + } + /** @todo RTUInt64DivModByU32 */ + } + + /* Dividend is smaller? */ + iDiff = RTUInt64Compare(pValue1, pValue2); + if (iDiff < 0) + { + *pRemainder = *pValue1; + RTUInt64SetZero(pQuotient); + } + + /* The values are equal? */ + else if (iDiff == 0) + { + RTUInt64SetZero(pRemainder); + RTUInt64AssignU8(pQuotient, 1); + } + else + { + /* + * Prepare. + */ + unsigned iBitAdder = RTUInt64BitCount(pValue1) - RTUInt64BitCount(pValue2); + RTUINT64U NormDivisor = *pValue2; + if (iBitAdder) + { + RTUInt64ShiftLeft(&NormDivisor, pValue2, iBitAdder); + if (RTUInt64IsLarger(&NormDivisor, pValue1)) + { + RTUInt64AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + else + NormDivisor = *pValue2; + + RTUInt64SetZero(pQuotient); + *pRemainder = *pValue1; + + /* + * Do the division. + */ + if (RTUInt64IsLargerOrEqual(pRemainder, pValue2)) + { + for (;;) + { + if (RTUInt64IsLargerOrEqual(pRemainder, &NormDivisor)) + { + RTUInt64AssignSub(pRemainder, &NormDivisor); + RTUInt64AssignOrBit(pQuotient, iBitAdder); + } + if (RTUInt64IsSmaller(pRemainder, pValue2)) + break; + RTUInt64AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + } + return pQuotient; +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uint64_h */ + diff --git a/include/iprt/uni.h b/include/iprt/uni.h new file mode 100644 index 00000000..ad804dcb --- /dev/null +++ b/include/iprt/uni.h @@ -0,0 +1,491 @@ +/** @file + * IPRT - Unicode Code Points. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uni_h +#define IPRT_INCLUDED_uni_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** @defgroup grp_rt_uni RTUniCp - Unicode Code Points + * @ingroup grp_rt + * @{ + */ + +/** @def RTUNI_USE_WCTYPE + * Define RTUNI_USE_WCTYPE to not use the IPRT unicode data but the + * data which the C runtime library provides. */ +#ifdef DOXYGEN_RUNNING +# define RTUNI_USE_WCTYPE +#endif + +#include +#ifdef RTUNI_USE_WCTYPE +# include +#endif + +RT_C_DECLS_BEGIN + + +#ifndef RTUNI_USE_WCTYPE + +/** + * A unicode flags range. + * @internal + */ +typedef struct RTUNIFLAGSRANGE +{ + /** The first code point of the range. */ + RTUNICP BeginCP; + /** The last + 1 code point of the range. */ + RTUNICP EndCP; + /** Pointer to the array of case folded code points. */ + const uint8_t *pafFlags; +} RTUNIFLAGSRANGE; +/** Pointer to a flags range. + * @internal */ +typedef RTUNIFLAGSRANGE *PRTUNIFLAGSRANGE; +/** Pointer to a const flags range. + * @internal */ +typedef const RTUNIFLAGSRANGE *PCRTUNIFLAGSRANGE; + +/** + * A unicode case folded range. + * @internal + */ +typedef struct RTUNICASERANGE +{ + /** The first code point of the range. */ + RTUNICP BeginCP; + /** The last + 1 code point of the range. */ + RTUNICP EndCP; + /** Pointer to the array of case folded code points. */ + PCRTUNICP paFoldedCPs; +} RTUNICASERANGE; +/** Pointer to a case folded range. + * @internal */ +typedef RTUNICASERANGE *PRTUNICASERANGE; +/** Pointer to a const case folded range. + * @internal */ +typedef const RTUNICASERANGE *PCRTUNICASERANGE; + +/** @name Unicode Code Point Flags. + * @internal + * @{ */ +#define RTUNI_UPPER RT_BIT(0) +#define RTUNI_LOWER RT_BIT(1) +#define RTUNI_ALPHA RT_BIT(2) +#define RTUNI_XDIGIT RT_BIT(3) +#define RTUNI_DDIGIT RT_BIT(4) +#define RTUNI_WSPACE RT_BIT(5) +/*#define RTUNI_BSPACE RT_BIT(6) - later */ +/** When set, the codepoint requires further checking wrt NFC and NFD + * normalization. I.e. set when either of QC_NFD and QC_NFC are not Y. */ +#define RTUNI_QC_NFX RT_BIT(7) +/** @} */ + + +/** + * Array of flags ranges. + * @internal + */ +extern RTDATADECL(const RTUNIFLAGSRANGE) g_aRTUniFlagsRanges[]; + +/** + * Gets the flags for a unicode code point. + * + * @returns The flag mask. (RTUNI_*) + * @param CodePoint The unicode code point. + * @internal + */ +DECLINLINE(RTUNICP) rtUniCpFlags(RTUNICP CodePoint) +{ + PCRTUNIFLAGSRANGE pCur = &g_aRTUniFlagsRanges[0]; + do + { + if (pCur->EndCP > CodePoint) + { + if (pCur->BeginCP <= CodePoint) + return pCur->pafFlags[CodePoint - pCur->BeginCP]; + break; + } + pCur++; + } while (pCur->EndCP != RTUNICP_MAX); + return 0; +} + + +/** + * Checks if a unicode code point is upper case. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsUpper(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_UPPER) != 0; +} + + +/** + * Checks if a unicode code point is lower case. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsLower(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_LOWER) != 0; +} + + +/** + * Checks if a unicode code point is case foldable. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsFoldable(RTUNICP CodePoint) +{ + /* Right enough. */ + return (rtUniCpFlags(CodePoint) & (RTUNI_LOWER | RTUNI_UPPER)) != 0; +} + + +/** + * Checks if a unicode code point is alphabetic. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsAlphabetic(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_ALPHA) != 0; +} + + +/** + * Checks if a unicode code point is a decimal digit. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsDecDigit(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_DDIGIT) != 0; +} + + +/** + * Checks if a unicode code point is a hexadecimal digit. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsHexDigit(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_XDIGIT) != 0; +} + + +/** + * Checks if a unicode code point is white space. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsSpace(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_WSPACE) != 0; +} + + + +/** + * Array of uppercase ranges. + * @internal + */ +extern RTDATADECL(const RTUNICASERANGE) g_aRTUniUpperRanges[]; + +/** + * Array of lowercase ranges. + * @internal + */ +extern RTDATADECL(const RTUNICASERANGE) g_aRTUniLowerRanges[]; + + +/** + * Folds a unicode code point using the specified range array. + * + * @returns FOlded code point. + * @param CodePoint The unicode code point to fold. + * @param pCur The case folding range to use. + */ +DECLINLINE(RTUNICP) rtUniCpFold(RTUNICP CodePoint, PCRTUNICASERANGE pCur) +{ + do + { + if (pCur->EndCP > CodePoint) + { + if (pCur->BeginCP <= CodePoint) + CodePoint = pCur->paFoldedCPs[CodePoint - pCur->BeginCP]; + break; + } + pCur++; + } while (pCur->EndCP != RTUNICP_MAX); + return CodePoint; +} + + +/** + * Folds a unicode code point to upper case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(RTUNICP) RTUniCpToUpper(RTUNICP CodePoint) +{ + return rtUniCpFold(CodePoint, &g_aRTUniUpperRanges[0]); +} + + +/** + * Folds a unicode code point to lower case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(RTUNICP) RTUniCpToLower(RTUNICP CodePoint) +{ + return rtUniCpFold(CodePoint, &g_aRTUniLowerRanges[0]); +} + + +#else /* RTUNI_USE_WCTYPE */ + + +/** + * Checks if a unicode code point is upper case. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsUpper(RTUNICP CodePoint) +{ + return !!iswupper(CodePoint); +} + + +/** + * Checks if a unicode code point is lower case. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsLower(RTUNICP CodePoint) +{ + return !!iswlower(CodePoint); +} + + +/** + * Checks if a unicode code point is case foldable. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsFoldable(RTUNICP CodePoint) +{ + /* Right enough. */ + return iswupper(CodePoint) || iswlower(CodePoint); +} + + +/** + * Checks if a unicode code point is alphabetic. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsAlphabetic(RTUNICP CodePoint) +{ + return !!iswalpha(CodePoint); +} + + +/** + * Checks if a unicode code point is a decimal digit. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsDecDigit(RTUNICP CodePoint) +{ + return !!iswdigit(CodePoint); +} + + +/** + * Checks if a unicode code point is a hexadecimal digit. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsHexDigit(RTUNICP CodePoint) +{ + return !!iswxdigit(CodePoint); +} + + +/** + * Checks if a unicode code point is white space. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsSpace(RTUNICP CodePoint) +{ + return !!iswspace(CodePoint); +} + + +/** + * Folds a unicode code point to upper case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(RTUNICP) RTUniCpToUpper(RTUNICP CodePoint) +{ + return towupper(CodePoint); +} + + +/** + * Folds a unicode code point to lower case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(RTUNICP) RTUniCpToLower(RTUNICP CodePoint) +{ + return towlower(CodePoint); +} + + +#endif /* RTUNI_USE_WCTYPE */ + + +/** + * Frees a unicode string. + * + * @param pusz The string to free. + */ +RTDECL(void) RTUniFree(PRTUNICP pusz); + + +/** + * Checks if a code point valid. + * + * Any code point (defined or not) within the 17 unicode planes (0 thru 16), + * except surrogates will be considered valid code points by this function. + * + * @returns true if in range, false if not. + * @param CodePoint The unicode code point to validate. + */ +DECLINLINE(bool) RTUniCpIsValid(RTUNICP CodePoint) +{ + return CodePoint <= 0x00d7ff + || ( CodePoint <= 0x10ffff + && CodePoint >= 0x00e000); +} + + +/** + * Checks if the given code point is in the BMP range. + * + * Surrogates are not considered in the BMP range by this function. + * + * @returns true if in BMP, false if not. + * @param CodePoint The unicode code point to consider. + */ +DECLINLINE(bool) RTUniCpIsBMP(RTUNICP CodePoint) +{ + return CodePoint <= 0xd7ff + || ( CodePoint <= 0xffff + && CodePoint >= 0xe000); +} + + +/** + * Folds a unicode code point to lower case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(size_t) RTUniCpCalcUtf8Len(RTUNICP CodePoint) +{ + if (CodePoint < 0x80) + return 1; + return 2 + + (CodePoint >= 0x00000800) + + (CodePoint >= 0x00010000) + + (CodePoint >= 0x00200000) + + (CodePoint >= 0x04000000) + + (CodePoint >= 0x80000000) /* illegal */; +} + + + +RT_C_DECLS_END +/** @} */ + + +#endif /* !IPRT_INCLUDED_uni_h */ + diff --git a/include/iprt/uri.h b/include/iprt/uri.h new file mode 100644 index 00000000..75787cd4 --- /dev/null +++ b/include/iprt/uri.h @@ -0,0 +1,380 @@ +/** @file + * IPRT - Uniform Resource Identifier handling. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uri_h +#define IPRT_INCLUDED_uri_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uri RTUri - Uri parsing and creation + * + * URI parsing and creation based on RFC-3986. + * + * @remarks The whole specification isn't implemented and we only provide scheme + * specific special APIs for "file://". + * + * @ingroup grp_rt + * @{ + */ + + +/** + * Parsed URI. + * + * @remarks This structure is subject to change. + */ +typedef struct RTURIPARSED +{ + /** Magic value (for internal use only). */ + uint32_t u32Magic; + /** RTURIPARSED_F_XXX. */ + uint32_t fFlags; + + /** The length of the scheme. */ + size_t cchScheme; + + /** The offset into the string of the authority. */ + size_t offAuthority; + /** The authority length. + * @remarks The authority component can be zero length, so to check whether + * it's there or not consult RTURIPARSED_F_HAVE_AUTHORITY. */ + size_t cchAuthority; + + /** The offset into the string of the path. */ + size_t offPath; + /** The length of the path. */ + size_t cchPath; + + /** The offset into the string of the query. */ + size_t offQuery; + /** The length of the query. */ + size_t cchQuery; + + /** The offset into the string of the fragment. */ + size_t offFragment; + /** The length of the fragment. */ + size_t cchFragment; + + /** @name Authority subdivisions + * @{ */ + /** If there is a userinfo part, this is the start of it. Otherwise it's the + * same as offAuthorityHost. */ + size_t offAuthorityUsername; + /** The length of the username (zero if not present). */ + size_t cchAuthorityUsername; + /** If there is a userinfo part containing a password, this is the start of it. + * Otherwise it's the same as offAuthorityHost. */ + size_t offAuthorityPassword; + /** The length of the password (zero if not present). */ + size_t cchAuthorityPassword; + /** The offset of the host part of the authority. */ + size_t offAuthorityHost; + /** The length of the host part of the authority. */ + size_t cchAuthorityHost; + /** The authority port number, UINT32_MAX if not present or empty. */ + uint32_t uAuthorityPort; + /** @} */ +} RTURIPARSED; +/** Pointer to a parsed URI. */ +typedef RTURIPARSED *PRTURIPARSED; +/** Pointer to a const parsed URI. */ +typedef RTURIPARSED const *PCRTURIPARSED; + +/** @name RTURIPARSED_F_XXX - RTURIPARSED::fFlags + * @{ */ +/** Set if the URI contains escaped characters. */ +#define RTURIPARSED_F_CONTAINS_ESCAPED_CHARS UINT32_C(0x00000001) +/** Set if the URI has an authority component. Necessary since the authority + * component can have a zero length. */ +#define RTURIPARSED_F_HAS_AUTHORITY UINT32_C(0x00000002) +/** Set if there is a port component. */ +#define RTURIPARSED_F_HAS_PORT UINT32_C(0x00000004) +/** @} */ + +/** + * Parses a URI. + * + * @returns IPRT status code. + * @param pszUri The URI to parse. + * @param pParsed Where to return the details. This can be handed + * to the RTUriParsed* APIs for retriving + * information. + */ +RTDECL(int) RTUriParse(const char *pszUri, PRTURIPARSED pParsed); + +/** + * Extract the scheme out of a parsed URI. + * + * @returns the scheme if the URI is valid, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(char *) RTUriParsedScheme(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the authority out of a parsed URI. + * + * @returns the authority if the URI contains one, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + * @remarks The authority can have a zero length. + */ +RTDECL(char *) RTUriParsedAuthority(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the username out of the authority component in a parsed URI. + * + * @returns The username if the URI contains one, otherwise NULL. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + * + * @todo This may currently be returning NULL when it maybe would be more + * appropriate to return an empty string... + */ +RTDECL(char *) RTUriParsedAuthorityUsername(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the password out of the authority component in a parsed URI. + * + * @returns The password if the URI contains one, otherwise NULL. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + * + * @todo This may currently be returning NULL when it maybe would be more + * appropriate to return an empty string... + */ +RTDECL(char *) RTUriParsedAuthorityPassword(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the host out of the authority component in a parsed URI. + * + * @returns The host if the URI contains one, otherwise NULL. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + * + * @todo This may currently be returning NULL when it maybe would be more + * appropriate to return an empty string... + */ +RTDECL(char *) RTUriParsedAuthorityHost(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the port number out of the authority component in a parsed URI. + * + * @returns The port number if the URI contains one, otherwise UINT32_MAX. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(uint32_t) RTUriParsedAuthorityPort(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the path out of a parsed URI. + * + * @returns the path if the URI contains one, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(char *) RTUriParsedPath(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the query out of a parsed URI. + * + * @returns the query if the URI contains one, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(char *) RTUriParsedQuery(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the fragment out of a parsed URI. + * + * @returns the fragment if the URI contains one, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(char *) RTUriParsedFragment(const char *pszUri, PCRTURIPARSED pParsed); + + + +/** + * Creates a generic URI. + * + * The returned pointer must be freed using RTStrFree(). + * + * @returns the new URI on success, NULL otherwise. + * @param pszScheme The URI scheme. + * @param pszAuthority The authority part of the URI (optional). + * @param pszPath The path part of the URI (optional). + * @param pszQuery The query part of the URI (optional). + * @param pszFragment The fragment part of the URI (optional). + */ +RTDECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, + const char *pszFragment); + +/** + * Check whether the given scheme matches that of the URI. + * + * This does not validate the URI, it just compares the scheme, no more, no + * less. Thus it's much faster than using RTUriParsedScheme. + * + * @returns true if the scheme match, false if not. + * @param pszUri The URI to check. + * @param pszScheme The scheme to compare with. + */ +RTDECL(bool) RTUriIsSchemeMatch(const char *pszUri, const char *pszScheme); + +/** @defgroup grp_rt_uri_file RTUriFile - Uri file parsing and creation + * + * Implements basic "file:" scheme support to the generic RTUri interface. This + * is partly documented in RFC-1738. + * + * @{ + */ + +/** + * Creates a file URI. + * + * The returned pointer must be freed using RTStrFree(). + * + * @returns The new URI on success, NULL otherwise. Free With RTStrFree. + * @param pszPath The path to create an 'file://' URI for. This is + * assumed to be using the default path style of the + * system. + * + * @sa RTUriFileCreateEx, RTUriCreate + */ +RTDECL(char *) RTUriFileCreate(const char *pszPath); + +/** + * Creates an file URL for the given path. + * + * This API works like RTStrToUtf16Ex with regard to result allocation or + * buffering (i.e. it's a bit complicated but very flexible). + * + * @returns iprt status code. + * @param pszPath The path to convert to a file:// URL. + * @param fPathStyle The input path style, exactly one of + * RTPATH_STR_F_STYLE_HOST, RTPATH_STR_F_STYLE_DOS and + * RTPATH_STR_F_STYLE_UNIX. Must include iprt/path.h. + * @param ppszUri If cbUri is non-zero, this must either be pointing + * to pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppszUri is NULL or + * cbUri is zero a buffer of at least cbUri chars will + * be allocated to hold the URI. If a buffer was + * requested it must be freed using RTStrFree(). + * @param cbUri The buffer size in bytes (includes terminator). + * @param pcchUri Where to store the length of the URI string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @sa RTUriCreate, RTUriFileCreate + */ +RTDECL(int) RTUriFileCreateEx(const char *pszPath, uint32_t fPathStyle, char **ppszUri, size_t cbUri, size_t *pcchUri); + +/** + * Returns the file path encoded in the file URI. + * + * This differs a quite a bit from RTUriParsedPath in that it tries to be + * compatible with URL produced by older windows version. This API is basically + * producing the same results as the PathCreateFromUrl API on Windows. + * + * @returns The path if the URI contains one, system default path style, + * otherwise NULL. + * @param pszUri The alleged 'file://' URI to extract the path from. + * + * @sa RTUriParsedPath, RTUriFilePathEx + */ +RTDECL(char *) RTUriFilePath(const char *pszUri); + +/** + * Queries the file path for the given file URI. + * + * This API works like RTStrToUtf16Ex with regard to result allocation or + * buffering (i.e. it's a bit complicated but very flexible). + * + * This differs a quite a bit from RTUriParsedPath in that it tries to be + * compatible with URL produced by older windows version. This API is basically + * producing the same results as the PathCreateFromUrl API on Windows. + * + * @returns IPRT status code. + * @retval VERR_URI_NOT_FILE_SCHEME if not file scheme. + * + * @param pszUri The alleged file:// URI to extract the path from. + * @param fPathStyle The output path style, exactly one of + * RTPATH_STR_F_STYLE_HOST, RTPATH_STR_F_STYLE_DOS and + * RTPATH_STR_F_STYLE_UNIX. Must include iprt/path.h. + * @param ppszPath If cbPath is non-zero, this must either be pointing + * to pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppszPath is NULL or + * cbPath is zero a buffer of at least cbPath chars + * will be allocated to hold the path. If a buffer was + * requested it must be freed using RTStrFree(). + * @param cbPath The buffer size in bytes (includes terminator). + * @param pcchPath Where to store the length of the path string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @sa RTUriParsedPath, RTUriFilePath + */ +RTDECL(int) RTUriFilePathEx(const char *pszUri, uint32_t fPathStyle, char **ppszPath, size_t cbPath, size_t *pcchPath); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uri_h */ + diff --git a/include/iprt/utf16.h b/include/iprt/utf16.h new file mode 100644 index 00000000..ed193b1e --- /dev/null +++ b/include/iprt/utf16.h @@ -0,0 +1,1527 @@ +/** @file + * IPRT - String Manipulation, UTF-16 encoding. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_utf16_h +#define IPRT_INCLUDED_utf16_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup rt_str_utf16 UTF-16 String Manipulation + * @ingroup grp_rt_str + * @{ + */ + +/** + * Allocates memory for UTF-16 string storage (default tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns Pointer to the allocated UTF-16 string. The first wide char is + * always set to the string terminator char, the contents of the + * remainder of the memory is undefined. The string must be freed by + * calling RTUtf16Free. + * + * NULL is returned if the allocation failed. Please translate this to + * VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY. Also consider + * RTUtf16AllocEx if an IPRT status code is required. + * + * @param cb How many bytes to allocate, will be rounded up + * to a multiple of two. If this is zero, we will + * allocate a terminator wide char anyway. + */ +#define RTUtf16Alloc(cb) RTUtf16AllocTag((cb), RTSTR_TAG) + +/** + * Allocates memory for UTF-16 string storage (custom tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns Pointer to the allocated UTF-16 string. The first wide char is + * always set to the string terminator char, the contents of the + * remainder of the memory is undefined. The string must be freed by + * calling RTUtf16Free. + * + * NULL is returned if the allocation failed. Please translate this to + * VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY. Also consider + * RTUtf16AllocExTag if an IPRT status code is required. + * + * @param cb How many bytes to allocate, will be rounded up + * to a multiple of two. If this is zero, we will + * allocate a terminator wide char anyway. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag); + +/** + * Reallocates the specified UTF-16 string (default tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns VINF_SUCCESS. + * @retval VERR_NO_UTF16_MEMORY if we failed to reallocate the string, @a + * *ppwsz remains unchanged. + * + * @param ppwsz Pointer to the string variable containing the + * input and output string. + * + * When not freeing the string, the result will + * always have the last RTUTF16 set to the + * terminator character so that when used for + * string truncation the result will be a valid + * C-style string (your job to keep it a valid + * UTF-16 string). + * + * When the input string is NULL and we're supposed + * to reallocate, the returned string will also + * have the first RTUTF16 set to the terminator + * char so it will be a valid C-style string. + * + * @param cbNew When @a cbNew is zero, we'll behave like + * RTUtf16Free and @a *ppwsz will be set to NULL. + * + * When not zero, this will be rounded up to a + * multiple of two, and used as the new size of the + * memory backing the string, i.e. it includes the + * terminator (RTUTF16) char. + */ +#define RTUtf16Realloc(ppwsz, cbNew) RTUtf16ReallocTag((ppwsz), (cbNew), RTSTR_TAG) + +/** + * Reallocates the specified UTF-16 string (custom tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns VINF_SUCCESS. + * @retval VERR_NO_UTF16_MEMORY if we failed to reallocate the string, @a + * *ppwsz remains unchanged. + * + * @param ppwsz Pointer to the string variable containing the + * input and output string. + * + * When not freeing the string, the result will + * always have the last RTUTF16 set to the + * terminator character so that when used for + * string truncation the result will be a valid + * C-style string (your job to keep it a valid + * UTF-16 string). + * + * When the input string is NULL and we're supposed + * to reallocate, the returned string will also + * have the first RTUTF16 set to the terminator + * char so it will be a valid C-style string. + * + * @param cbNew When @a cbNew is zero, we'll behave like + * RTUtf16Free and @a *ppwsz will be set to NULL. + * + * When not zero, this will be rounded up to a + * multiple of two, and used as the new size of the + * memory backing the string, i.e. it includes the + * terminator (RTUTF16) char. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ReallocTag(PRTUTF16 *ppwsz, size_t cbNew, const char *pszTag); + +/** + * Free a UTF-16 string allocated by RTStrToUtf16(), RTStrToUtf16Ex(), + * RTLatin1ToUtf16(), RTLatin1ToUtf16Ex(), RTUtf16Dup() or RTUtf16DupEx(). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to free. NULL is accepted. + */ +RTDECL(void) RTUtf16Free(PRTUTF16 pwszString); + +/** + * Allocates a new copy of the specified UTF-16 string (default tag). + * + * @returns Pointer to the allocated string copy. Use RTUtf16Free() to free it. + * @returns NULL when out of memory. + * @param pwszString UTF-16 string to duplicate. + * @remark This function will not make any attempt to validate the encoding. + */ +#define RTUtf16Dup(pwszString) RTUtf16DupTag((pwszString), RTSTR_TAG) + +/** + * Allocates a new copy of the specified UTF-16 string (custom tag). + * + * @returns Pointer to the allocated string copy. Use RTUtf16Free() to free it. + * @returns NULL when out of memory. + * @param pwszString UTF-16 string to duplicate. + * @param pszTag Allocation tag used for statistics and such. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(PRTUTF16) RTUtf16DupTag(PCRTUTF16 pwszString, const char *pszTag); + +/** + * Allocates a new copy of the specified UTF-16 string (default tag). + * + * @returns iprt status code. + * @param ppwszString Receives pointer of the allocated UTF-16 string. + * The returned pointer must be freed using RTUtf16Free(). + * @param pwszString UTF-16 string to duplicate. + * @param cwcExtra Number of extra RTUTF16 items to allocate. + * @remark This function will not make any attempt to validate the encoding. + */ +#define RTUtf16DupEx(ppwszString, pwszString, cwcExtra) \ + RTUtf16DupExTag((ppwszString), (pwszString), (cwcExtra), RTSTR_TAG) + +/** + * Allocates a new copy of the specified UTF-16 string (custom tag). + * + * @returns iprt status code. + * @param ppwszString Receives pointer of the allocated UTF-16 string. + * The returned pointer must be freed using RTUtf16Free(). + * @param pwszString UTF-16 string to duplicate. + * @param cwcExtra Number of extra RTUTF16 items to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16DupExTag(PRTUTF16 *ppwszString, PCRTUTF16 pwszString, size_t cwcExtra, const char *pszTag); + +/** + * Returns the length of a UTF-16 string in UTF-16 characters + * without trailing '\\0'. + * + * Surrogate pairs counts as two UTF-16 characters here. Use RTUtf16CpCnt() + * to get the exact number of code points in the string. + * + * @returns The number of RTUTF16 items in the string. + * @param pwszString Pointer the UTF-16 string. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(size_t) RTUtf16Len(PCRTUTF16 pwszString); + +/** + * Find the length of a zero-terminated byte string, given a max string length. + * + * @returns The string length or cbMax. The returned length does not include + * the zero terminator if it was found. + * + * @param pwszString The string. + * @param cwcMax The max string length in RTUTF16s. + * @sa RTUtf16NLenEx, RTStrNLen. + */ +RTDECL(size_t) RTUtf16NLen(PCRTUTF16 pwszString, size_t cwcMax); + +/** + * Find the length of a zero-terminated byte string, given + * a max string length. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the string has a length less than cchMax. + * @retval VERR_BUFFER_OVERFLOW if the end of the string wasn't found + * before cwcMax was reached. + * + * @param pwszString The string. + * @param cwcMax The max string length in RTUTF16s. + * @param pcwc Where to store the string length excluding the + * terminator. This is set to cwcMax if the terminator + * isn't found. + * @sa RTUtf16NLen, RTStrNLenEx. + */ +RTDECL(int) RTUtf16NLenEx(PCRTUTF16 pwszString, size_t cwcMax, size_t *pcwc); + +/** + * Find the zero terminator in a string with a limited length. + * + * @returns Pointer to the zero terminator. + * @returns NULL if the zero terminator was not found. + * + * @param pwszString The string. + * @param cwcMax The max string length. RTSTR_MAX is fine. + */ +RTDECL(PCRTUTF16) RTUtf16End(PCRTUTF16 pwszString, size_t cwcMax); + +/** + * Finds a give UTF-16 character in a UTF-16 string. + * + * @returns Pointer to the first occurence of @a wc. + * @returns NULL if @a wc was not found. + * + * @param pwszString The string to search. + * @param wc The UTF-16 character to search for. + */ +RTDECL(PRTUTF16) RTUtf16Chr(PCRTUTF16 pwszString, RTUTF16 wc); + +/** + * Strips blankspaces from both ends of the string. + * + * @returns Pointer to first non-blank char in the string. + * @param pwsz The string to strip. + */ +RTDECL(PRTUTF16) RTUtf16Strip(PRTUTF16 pwsz); + +/** + * Strips blankspaces from the start of the string. + * + * @returns Pointer to first non-blank char in the string. + * @param pwsz The string to strip. + */ +RTDECL(PRTUTF16) RTUtf16StripL(PCRTUTF16 pwsz); + +/** + * Strips blankspaces from the end of the string. + * + * @returns pwsz. + * @param pwsz The string to strip. + */ +RTDECL(PRTUTF16) RTUtf16StripR(PRTUTF16 pwsz); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pwszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTUtf16Copy(PRTUTF16 pwszDst, size_t cwcDst, PCRTUTF16 pwszSrc); + +/** + * String copy with overflow handling, ASCII source. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pszSrc The source string, pure ASCII. NULL is not OK. + */ +RTDECL(int) RTUtf16CopyAscii(PRTUTF16 pwszDst, size_t cwcDst, const char *pszSrc); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pwszSrc The source string. NULL is not OK. + * @param cwcSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTUtf16CopyEx(PRTUTF16 pwszDst, size_t cwcDst, PCRTUTF16 pwszSrc, size_t cwcSrcMax); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pwszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTUtf16Cat(PRTUTF16 pwszDst, size_t cwcDst, PCRTUTF16 pwszSrc); + +/** + * String concatenation with overflow handling, ASCII source. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pszSrc The source string, pure ASCII. NULL is not OK. + */ +RTDECL(int) RTUtf16CatAscii(PRTUTF16 pwszDst, size_t cwcDst, const char *pszSrc); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pwszSrc The source string. NULL is not OK. + * @param cwcSrcMax The maximum number of UTF-16 chars (not code + * points) to copy from the source string, not + * counting the terminator as usual. + */ +RTDECL(int) RTUtf16CatEx(PRTUTF16 pwszDst, size_t cwcDst, PCRTUTF16 pwszSrc, size_t cwcSrcMax); + +/** + * Performs a case sensitive string compare between two UTF-16 strings. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16Cmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2); + +/** + * Performs a case sensitive string compare between an UTF-16 string and a pure + * ASCII string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, pure ASCII. Null is allowed. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16CmpAscii(PCRTUTF16 pwsz1, const char *psz2); + +/** + * Performs a case sensitive string compare between an UTF-16 string and a UTF-8 + * string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, UTF-8. Null is allowed. + * @remarks NULL and empty strings are treated equally. + */ +RTDECL(int) RTUtf16CmpUtf8(PCRTUTF16 pwsz1, const char *psz2); + + +/** + * Performs a case sensitive and length limited string compare between two UTF-16 strings. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + * @param cwcMax Maximum number of characters (RTUTF16) from the first + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16NCmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2, size_t cwcMax); + +/** + * Performs a case sensitive and length limited string compare between an UTF-16 + * string and a pure ASCII string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, pure ASCII. Null is allowed. + * @param cwcMax Maximum number of characters (RTUTF16) to compare. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16NCmpAscii(PCRTUTF16 pwsz1, const char *psz2, size_t cwcMax); + +/** + * Performs a case sensitive and length limited string compare between an UTF-16 + * string and a UTF-8 string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, UTF-8. Null is allowed. + * @param cwcMax1 Maximum number of UTF-16 characters (RTUTF16) from the + * first string to compare. + * @param cchMax2 Maximum number of UTF-8 characters (char) from the + * second string to compare. + * @remarks NULL and empty strings are treated equally. + */ +RTDECL(int) RTUtf16NCmpUtf8(PCRTUTF16 pwsz1, const char *psz2, size_t cwcMax1, size_t cchMax2); + + +/** + * Performs a case insensitive string compare between two UTF-16 strings. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + */ +RTDECL(int) RTUtf16ICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2); + +/** + * Performs a case insensitive string compare between two big endian UTF-16 + * strings. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First big endian UTF-16 string. Null is allowed. + * @param pwsz2 Second big endian UTF-16 string. Null is allowed. + */ +RTDECL(int) RTUtf16BigICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2); + +/** + * Performs a case insensitive string compare between an UTF-16 string and a + * UTF-8 string. + * + * @returns < 0 if the first string less than the second string.s + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, UTF-8. Null is allowed. + * @remarks NULL and empty strings are treated equally. + */ +RTDECL(int) RTUtf16ICmpUtf8(PCRTUTF16 pwsz1, const char *psz2); + +/** + * Performs a case insensitive string compare between an UTF-16 string and a + * pure ASCII string. + * + * Since this compare only takes cares about the first 128 codepoints in + * unicode, no tables are needed and there aren't any real complications. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, pure ASCII. Null is allowed. + */ +RTDECL(int) RTUtf16ICmpAscii(PCRTUTF16 pwsz1, const char *psz2); + +/** + * Performs a case insensitive string compare between two UTF-16 strings + * using the current locale of the process (if applicable). + * + * This differs from RTUtf16ICmp() in that it will try, if a locale with the + * required data is available, to do a correct case-insensitive compare. It + * follows that it is more complex and thereby likely to be more expensive. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + */ +RTDECL(int) RTUtf16LocaleICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2); + +/** + * Performs a case insensitive string compare between two UTF-16 strings, + * stopping after N characters. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + * @param cwcMax Maximum number of characters to compare. + */ +RTDECL(int) RTUtf16NICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2, size_t cwcMax); + +/** + * Performs a case insensitive string compare between two big endian UTF-16 + * strings, stopping after N characters. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First big endian UTF-16 string. Null is allowed. + * @param pwsz2 Second big endian UTF-16 string. Null is allowed. + * @param cwcMax Maximum number of characters to compare. + */ +RTDECL(int) RTUtf16BigNICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2, size_t cwcMax); + +/** + * Performs a case insensitive string compare between a UTF-16 string and a pure + * ASCII string, stopping after N characters. + * + * Since this compare only takes cares about the first 128 codepoints in + * unicode, no tables are needed and there aren't any real complications. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 The UTF-16 first string. Null is allowed. + * @param psz2 The pure ASCII second string. Null is allowed. + * @param cwcMax Maximum number of UTF-16 characters to compare. + */ +RTDECL(int) RTUtf16NICmpAscii(PCRTUTF16 pwsz1, const char *psz2, size_t cwcMax); + + +/** + * Locates a substring, ascii version. + * + * @returns Offset into @a pwszString of the substring if found, -1 if not. + * @param pwszString The UTF-16 to search. NULL is allowed (no match). + * @param pszSubStr The pure ASCII substring to locate. NULL is allowed (not + * matching anything, just like an empty string). + */ +RTDECL(ssize_t) RTUtf16FindAscii(PCRTUTF16 pwszString, const char *pszSubStr); + + +/** + * Folds a UTF-16 string to lowercase. + * + * This is a very simple folding; is uses the simple lowercase + * code point, it is not related to any locale just the most common + * lowercase codepoint setup by the unicode specs, and it will not + * create new surrogate pairs or remove existing ones. + * + * @returns Pointer to the passed in string. + * @param pwsz The string to fold. + */ +RTDECL(PRTUTF16) RTUtf16ToLower(PRTUTF16 pwsz); + +/** + * Folds a UTF-16 string to uppercase. + * + * This is a very simple folding; is uses the simple uppercase + * code point, it is not related to any locale just the most common + * uppercase codepoint setup by the unicode specs, and it will not + * create new surrogate pairs or remove existing ones. + * + * @returns Pointer to the passed in string. + * @param pwsz The string to fold. + */ +RTDECL(PRTUTF16) RTUtf16ToUpper(PRTUTF16 pwsz); + +/** + * Validates the UTF-16 encoding of the string. + * + * @returns iprt status code. + * @param pwsz The string. + */ +RTDECL(int) RTUtf16ValidateEncoding(PCRTUTF16 pwsz); + +/** + * Validates the UTF-16 encoding of the string. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length (/ size) in UTF-16 units. Use + * RTSTR_MAX to process the entire string. + * @param fFlags Combination of RTSTR_VALIDATE_ENCODING_XXX flags. + */ +RTDECL(int) RTUtf16ValidateEncodingEx(PCRTUTF16 pwsz, size_t cwc, uint32_t fFlags); + +/** + * Checks if the UTF-16 encoding is valid. + * + * @returns true / false. + * @param pwsz The string. + */ +RTDECL(bool) RTUtf16IsValidEncoding(PCRTUTF16 pwsz); + +/** + * Sanitise a (valid) UTF-16 string by replacing all characters outside a white + * list in-place by an ASCII replacement character. + * + * Surrogate paris will be replaced by two chars. + * + * @returns The number of code points replaced. In the case of an incorrectly + * encoded string -1 will be returned, and the string is not completely + * processed. In the case of puszValidPairs having an odd number of + * code points, -1 will be also return but without any modification to + * the string. + * @param pwsz The string to sanitise. + * @param puszValidPairs A zero-terminated array of pairs of Unicode points. + * Each pair is the start and end point of a range, + * and the union of these ranges forms the white list. + * @param chReplacement The ASCII replacement character. + * @sa RTStrPurgeComplementSet + */ +RTDECL(ssize_t) RTUtf16PurgeComplementSet(PRTUTF16 pwsz, PCRTUNICP puszValidPairs, char chReplacement); + + +/** + * Translate a UTF-16 string into a UTF-8 allocating the result buffer (default + * tag). + * + * @returns iprt status code. + * @param pwszString UTF-16 string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTUtf16ToUtf8(pwszString, ppszString) RTUtf16ToUtf8Tag((pwszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-16 string into a UTF-8 allocating the result buffer. + * + * @returns iprt status code. + * @param pwszString UTF-16 string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ToUtf8Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag); + +/** + * Translate a UTF-16BE string into a UTF-8 allocating the result buffer + * (default tag). + * + * This differs from RTUtf16ToUtf8 in that the input is always a + * big-endian string. + * + * @returns iprt status code. + * @param pwszString UTF-16BE string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTUtf16BigToUtf8(pwszString, ppszString) RTUtf16BigToUtf8Tag((pwszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-16BE string into a UTF-8 allocating the result buffer. + * + * This differs from RTUtf16ToUtf8Tag in that the input is always a + * big-endian string. + * + * @returns iprt status code. + * @param pwszString UTF-16BE string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16BigToUtf8Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag); + +/** + * Translate a UTF-16LE string into a UTF-8 allocating the result buffer + * (default tag). + * + * This differs from RTUtf16ToUtf8 in that the input is always a + * little-endian string. + * + * @returns iprt status code. + * @param pwszString UTF-16LE string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTUtf16LittleToUtf8(pwszString, ppszString) RTUtf16LittleToUtf8Tag((pwszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-16LE string into a UTF-8 allocating the result buffer. + * + * This differs from RTUtf16ToUtf8Tag in that the input is always a + * little-endian string. + * + * @returns iprt status code. + * @param pwszString UTF-16LE string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16LittleToUtf8Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag); + + +/** + * Translates UTF-16 to UTF-8 using buffer provided by the caller or a fittingly + * sized buffer allocated by the function (default tag). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTUtf16ToUtf8Ex(pwszString, cwcString, ppsz, cch, pcch) \ + RTUtf16ToUtf8ExTag((pwszString), (cwcString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates UTF-16 to UTF-8 using buffer provided by the caller or a fittingly + * sized buffer allocated by the function (custom tag). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ToUtf8ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag); + +/** + * Translates UTF-16BE to UTF-8 using buffer provided by the caller or a + * fittingly sized buffer allocated by the function (default tag). + * + * This differs from RTUtf16ToUtf8Ex in that the input is always a + * big-endian string. + * + * @returns iprt status code. + * @param pwszString The UTF-16BE string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTUtf16BigToUtf8Ex(pwszString, cwcString, ppsz, cch, pcch) \ + RTUtf16BigToUtf8ExTag((pwszString), (cwcString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates UTF-16BE to UTF-8 using buffer provided by the caller or a + * fittingly sized buffer allocated by the function (custom tag). + * + * This differs from RTUtf16ToUtf8ExTag in that the input is always a + * big-endian string. + * + * @returns iprt status code. + * @param pwszString The UTF-16BE string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16BigToUtf8ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag); + +/** + * Translates UTF-16LE to UTF-8 using buffer provided by the caller or a + * fittingly sized buffer allocated by the function (default tag). + * + * This differs from RTUtf16ToUtf8Ex in that the input is always a + * little-endian string. + * + * @returns iprt status code. + * @param pwszString The UTF-16LE string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTUtf16LittleToUtf8Ex(pwszString, cwcString, ppsz, cch, pcch) \ + RTUtf16LittleToUtf8ExTag((pwszString), (cwcString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates UTF-16LE to UTF-8 using buffer provided by the caller or a + * fittingly sized buffer allocated by the function (custom tag). + * + * This differs from RTUtf16ToUtf8ExTag in that the input is always a + * little-endian string. + * + * @returns iprt status code. + * @param pwszString The UTF-16LE string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16LittleToUtf8ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, + const char *pszTag); + +/** + * Calculates the length of the UTF-16 string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16 + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTUtf16ToUtf8() of the correct size. For most + * other purposes RTUtf16ToUtf8Ex() should be used. + * + * @returns Number of char (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pwsz The UTF-16 string. + */ +RTDECL(size_t) RTUtf16CalcUtf8Len(PCRTUTF16 pwsz); + +/** + * Calculates the length of the UTF-16BE string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16BE + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTUtf16BigToUtf8() of the correct size. For most + * other purposes RTUtf16BigToUtf8Ex() should be used. + * + * @returns Number of char (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pwsz The UTF-16BE string. + */ +RTDECL(size_t) RTUtf16BigCalcUtf8Len(PCRTUTF16 pwsz); + +/** + * Calculates the length of the UTF-16LE string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16LE + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTUtf16LittleToUtf8() of the correct size. For + * most other purposes RTUtf16LittleToUtf8Ex() should be used. + * + * @returns Number of char (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pwsz The UTF-16LE string. + */ +RTDECL(size_t) RTUtf16LittleCalcUtf8Len(PCRTUTF16 pwsz); + +/** + * Calculates the length of the UTF-16 string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16 + * strings will be rejected. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length. Use RTSTR_MAX to process the entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTUtf16CalcUtf8LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch); + +/** + * Calculates the length of the UTF-16BE string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16BE + * strings will be rejected. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length. Use RTSTR_MAX to process the entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTUtf16BigCalcUtf8LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch); + +/** + * Calculates the length of the UTF-16LE string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16LE + * strings will be rejected. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length. Use RTSTR_MAX to process the entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTUtf16LittleCalcUtf8LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch); + +/** + * Translate a UTF-16 string into a Latin-1 (ISO-8859-1) allocating the result + * buffer (default tag). + * + * @returns iprt status code. + * @param pwszString UTF-16 string to convert. + * @param ppszString Receives pointer of allocated Latin1 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTUtf16ToLatin1(pwszString, ppszString) RTUtf16ToLatin1Tag((pwszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-16 string into a Latin-1 (ISO-8859-1) allocating the result + * buffer (custom tag). + * + * @returns iprt status code. + * @param pwszString UTF-16 string to convert. + * @param ppszString Receives pointer of allocated Latin1 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ToLatin1Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag); + +/** + * Translates UTF-16 to Latin-1 (ISO-8859-1) using buffer provided by the caller + * or a fittingly sized buffer allocated by the function (default tag). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to convert. + * @param cwcString The number of RTUTF16 items to translate from + * pwszString. The translation will stop when reaching + * cwcString or the terminator ('\\0'). Use RTSTR_MAX + * to translate the entire string. + * @param ppsz Pointer to the pointer to the Latin-1 string. The + * buffer can optionally be preallocated by the caller. + * + * If cch is zero, *ppsz is undefined. + * + * If cch is non-zero and *ppsz is not NULL, then this + * will be used as the output buffer. + * VERR_BUFFER_OVERFLOW will be returned if this is + * insufficient. + * + * If cch is zero or *ppsz is NULL, then a buffer of + * sufficient size is allocated. cch can be used to + * specify a minimum size of this buffer. Use + * RTUtf16Free() to free the result. + * + * @param cch The buffer size in chars (the type). This includes + * the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTUtf16ToLatin1Ex(pwszString, cwcString, ppsz, cch, pcch) \ + RTUtf16ToLatin1ExTag((pwszString), (cwcString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates UTF-16 to Latin-1 (ISO-8859-1) using buffer provided by the caller + * or a fittingly sized buffer allocated by the function (custom tag). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to convert. + * @param cwcString The number of RTUTF16 items to translate from + * pwszString. The translation will stop when reaching + * cwcString or the terminator ('\\0'). Use RTSTR_MAX + * to translate the entire string. + * @param ppsz Pointer to the pointer to the Latin-1 string. The + * buffer can optionally be preallocated by the caller. + * + * If cch is zero, *ppsz is undefined. + * + * If cch is non-zero and *ppsz is not NULL, then this + * will be used as the output buffer. + * VERR_BUFFER_OVERFLOW will be returned if this is + * insufficient. + * + * If cch is zero or *ppsz is NULL, then a buffer of + * sufficient size is allocated. cch can be used to + * specify a minimum size of this buffer. Use + * RTUtf16Free() to free the result. + * + * @param cch The buffer size in chars (the type). This includes + * the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ToLatin1ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag); + +/** + * Calculates the length of the UTF-16 string in Latin-1 (ISO-8859-1) chars. + * + * This function will validate the string, and incorrectly encoded UTF-16 + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTUtf16ToLatin1() of the correct size. For most + * other purposes RTUtf16ToLatin1Ex() should be used. + * + * @returns Number of char (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pwsz The UTF-16 string. + */ +RTDECL(size_t) RTUtf16CalcLatin1Len(PCRTUTF16 pwsz); + +/** + * Calculates the length of the UTF-16 string in Latin-1 (ISO-8859-1) chars. + * + * This function will validate the string, and incorrectly encoded UTF-16 + * strings will be rejected. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length. Use RTSTR_MAX to process the + * entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTUtf16CalcLatin1LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch); + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param pwsz The string. + * + * @remark This is an internal worker for RTUtf16GetCp(). + */ +RTDECL(RTUNICP) RTUtf16GetCpInternal(PCRTUTF16 pwsz); + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark This is an internal worker for RTUtf16GetCpEx(). + */ +RTDECL(int) RTUtf16GetCpExInternal(PCRTUTF16 *ppwsz, PRTUNICP pCp); + +/** + * Get the unicode code point at the given string position with length + * restriction. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pcwc Pointer to the max string length. This will be + * decremented corrsponding to the advancement of @a ppwsz. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark This is an internal worker for RTUtf16GetCpNEx(). + */ +RTDECL(int) RTUtf16GetCpNExInternal(PCRTUTF16 *ppwsz, size_t *pcwc, PRTUNICP pCp); + +/** + * Get the unicode code point at the given string position, big endian. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark This is an internal worker for RTUtf16BigGetCpEx(). + */ +RTDECL(int) RTUtf16BigGetCpExInternal(PCRTUTF16 *ppwsz, PRTUNICP pCp); + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by pwsz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param pwsz The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the UTF-16 range. + * + * @remark This is an internal worker for RTUtf16GetCpEx(). + */ +RTDECL(PRTUTF16) RTUtf16PutCpInternal(PRTUTF16 pwsz, RTUNICP CodePoint); + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param pwsz The string. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or an endian indicator. + */ +DECLINLINE(RTUNICP) RTUtf16GetCp(PCRTUTF16 pwsz) +{ + const RTUTF16 wc = *pwsz; + if (wc < 0xd800 || (wc > 0xdfff && wc < 0xfffe)) + return wc; + return RTUtf16GetCpInternal(pwsz); +} + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or and endian indicator. + */ +DECLINLINE(int) RTUtf16GetCpEx(PCRTUTF16 *ppwsz, PRTUNICP pCp) +{ + const RTUTF16 wc = **ppwsz; + if (wc < 0xd800 || (wc > 0xdfff && wc < 0xfffe)) + { + (*ppwsz)++; + *pCp = wc; + return VINF_SUCCESS; + } + return RTUtf16GetCpExInternal(ppwsz, pCp); +} + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pcwc Pointer to the max string length. This will be + * decremented corrsponding to the advancement of @a ppwsz. + * @param pCp Where to store the code point. RTUNICP_INVALID is stored + * here on failure. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or and endian indicator. + */ +DECLINLINE(int) RTUtf16GetCpNEx(PCRTUTF16 *ppwsz, size_t *pcwc, PRTUNICP pCp) +{ + const size_t cwc = *pcwc; + if (cwc > 0) + { + const PCRTUTF16 pwsz = *ppwsz; + const RTUTF16 wc = *pwsz; + if (wc < 0xd800 || (wc > 0xdfff && wc < 0xfffe)) + { + *pCp = wc; + *pcwc = cwc - 1; + *ppwsz = pwsz + 1; + return VINF_SUCCESS; + } + } + return RTUtf16GetCpNExInternal(ppwsz, pcwc, pCp); +} + +/** + * Get the unicode code point at the given string position, big endian version. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or and endian indicator. + */ +DECLINLINE(int) RTUtf16BigGetCpEx(PCRTUTF16 *ppwsz, PRTUNICP pCp) +{ +#ifdef RT_BIG_ENDIAN + return RTUtf16GetCpEx(ppwsz, pCp); +#else +# ifdef IPRT_INCLUDED_asm_h + const RTUTF16 wc = RT_BE2H_U16(**ppwsz); + if (wc < 0xd800 || (wc > 0xdfff && wc < 0xfffe)) + { + (*ppwsz)++; + *pCp = wc; + return VINF_SUCCESS; + } +# endif + return RTUtf16BigGetCpExInternal(ppwsz, pCp); +#endif +} + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by pwsz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param pwsz The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the UTF-16 range. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or and endian indicator. + */ +DECLINLINE(PRTUTF16) RTUtf16PutCp(PRTUTF16 pwsz, RTUNICP CodePoint) +{ + if (CodePoint < 0xd800 || (CodePoint > 0xd800 && CodePoint < 0xfffe)) + { + *pwsz++ = (RTUTF16)CodePoint; + return pwsz; + } + return RTUtf16PutCpInternal(pwsz, CodePoint); +} + +/** + * Skips ahead, past the current code point. + * + * @returns Pointer to the char after the current code point. + * @param pwsz Pointer to the current code point. + * @remark This will not move the next valid code point, only past the current one. + */ +DECLINLINE(PRTUTF16) RTUtf16NextCp(PCRTUTF16 pwsz) +{ + RTUNICP Cp; + RTUtf16GetCpEx(&pwsz, &Cp); + return (PRTUTF16)pwsz; +} + +/** + * Skips backwards, to the previous code point. + * + * @returns Pointer to the char after the current code point. + * @param pwszStart Pointer to the start of the string. + * @param pwsz Pointer to the current code point. + */ +RTDECL(PRTUTF16) RTUtf16PrevCp(PCRTUTF16 pwszStart, PCRTUTF16 pwsz); + + +/** + * Checks if the UTF-16 char is the high surrogate char (i.e. + * the 1st char in the pair). + * + * @returns true if it is. + * @returns false if it isn't. + * @param wc The character to investigate. + */ +DECLINLINE(bool) RTUtf16IsHighSurrogate(RTUTF16 wc) +{ + return wc >= 0xd800 && wc <= 0xdbff; +} + +/** + * Checks if the UTF-16 char is the low surrogate char (i.e. + * the 2nd char in the pair). + * + * @returns true if it is. + * @returns false if it isn't. + * @param wc The character to investigate. + */ +DECLINLINE(bool) RTUtf16IsLowSurrogate(RTUTF16 wc) +{ + return wc >= 0xdc00 && wc <= 0xdfff; +} + + +/** + * Checks if the two UTF-16 chars form a valid surrogate pair. + * + * @returns true if they do. + * @returns false if they doesn't. + * @param wcHigh The high (1st) character. + * @param wcLow The low (2nd) character. + */ +DECLINLINE(bool) RTUtf16IsSurrogatePair(RTUTF16 wcHigh, RTUTF16 wcLow) +{ + return RTUtf16IsHighSurrogate(wcHigh) + && RTUtf16IsLowSurrogate(wcLow); +} + +/** + * Formats a buffer stream as hex bytes. + * + * The default is no separating spaces or line breaks or anything. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if any of the pointers are wrong. + * @retval VERR_BUFFER_OVERFLOW if the buffer is insufficent to hold the bytes. + * + * @param pwszBuf Output string buffer. + * @param cwcBuf The size of the output buffer in RTUTF16 units. + * @param pv Pointer to the bytes to stringify. + * @param cb The number of bytes to stringify. + * @param fFlags Combination of RTSTRPRINTHEXBYTES_F_XXX values. + * @sa RTStrPrintHexBytes. + */ +RTDECL(int) RTUtf16PrintHexBytes(PRTUTF16 pwszBuf, size_t cwcBuf, void const *pv, size_t cb, uint32_t fFlags); + +/** + * String printf producing UTF-16 output. + * + * @returns On success, positive count of formatted RTUTF16 units excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator) in RTUTF16 units. + * + * @param pwszBuffer Output buffer. + * @param cwcBuffer Size of the output buffer in RTUTF16 units. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * + * @note This is similar to RTStrPrintf2V (not RTStrPrintfV)! + */ +RTDECL(ssize_t) RTUtf16PrintfV(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * String printf producing UTF-16 output. + * + * @returns On success, positive count of formatted RTUTF16 units excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator) in RTUTF16 units. + * + * @param pwszBuffer Output buffer. + * @param cwcBuffer Size of the output buffer in RTUTF16 units. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + * + * @note This is similar to RTStrPrintf2 (not RTStrPrintf)! + */ +RTDECL(ssize_t) RTUtf16Printf(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * String printf producing UTF-16 output with custom formatting. + * + * @returns On success, positive count of formatted RTUTF16 units excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator) in RTUTF16 units. + * + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pwszBuffer Output buffer. + * @param cwcBuffer Size of the output buffer in RTUTF16 units. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * + * @note This is similar to RTStrPrintf2ExV (not RTStrPrintfExV)! + */ +RTDECL(ssize_t) RTUtf16PrintfExV(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * String printf producing UTF-16 output with custom formatting. + * + * @returns On success, positive count of formatted RTUTF16 units excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator) in RTUTF16 units. + * + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pwszBuffer Output buffer. + * @param cwcBuffer Size of the output buffer in RTUTF16 units. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + * + * @note This is similar to RTStrPrintf2Ex (not RTStrPrintfEx)! + */ +RTDECL(ssize_t) RTUtf16PrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_utf16_h */ + diff --git a/include/iprt/uuid.h b/include/iprt/uuid.h new file mode 100644 index 00000000..3c95a641 --- /dev/null +++ b/include/iprt/uuid.h @@ -0,0 +1,198 @@ +/** @file + * IPRT - Universal Unique Identifiers (UUID). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uuid_h +#define IPRT_INCLUDED_uuid_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uuid RTUuid - Universally Unique Identifiers + * @ingroup grp_rt + * @{ + */ + +/** + * Generates new UUID value. + * + * @note IPRT uses little endian byte ordering in the UUID integer fields. If + * you want to pass IPRT UUIDs in binary representation to other UUID libraries + * and expect to get exactly the same string representation as in IPRT, you + * need to convert the first three integer fields (one 32 bit value, two 16 bit + * values) separately to big endian (also called network byte order). + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Where to store generated uuid. + */ +RTDECL(int) RTUuidCreate(PRTUUID pUuid); + +/** + * Makes null UUID value. + * + * @returns iprt status code. + * @param pUuid Where to store generated null uuid. + */ +RTDECL(int) RTUuidClear(PRTUUID pUuid); + +/** + * Checks if UUID is null. + * + * @returns true if UUID is null. + * @param pUuid uuid to check. + */ +RTDECL(bool) RTUuidIsNull(PCRTUUID pUuid); + +/** + * Compares two UUID values. + * + * @returns 0 if eq, < 0 or > 0. + * @param pUuid1 First value to compare. NULL is treated like if + * RTUuidIsNull() return true. + * @param pUuid2 Second value to compare. NULL is treated like if + * RTUuidIsNull() return true. + */ +RTDECL(int) RTUuidCompare(PCRTUUID pUuid1, PCRTUUID pUuid2); + +/** + * Compares a UUID value with a UUID string. + * + * @note IPRT uses little endian byte ordering in the UUID integer fields. If + * you want to pass IPRT UUIDs in binary representation to other UUID libraries + * and expect to get exactly the same string representation as in IPRT, you need + * to convert the first three integer fields (one 32 bit value, two 16 bit + * values) separately to big endian (also called network byte order). + * Correspondingly, if you want to get the right result with UUIDs which are in + * big endian format, you need to convert them before using this function. + * + * @sa RTUUID::Gen + * + * @returns 0 if eq, < 0 or > 0. + * @param pUuid1 First value to compare. NULL is not allowed. + * @param pszString2 The 2nd UUID in string form. NULL or malformed + * string is not permitted. + */ +RTDECL(int) RTUuidCompareStr(PCRTUUID pUuid1, const char *pszString2); + +/** + * Compares two UUID strings. + * + * @returns 0 if eq, < 0 or > 0. + * @param pszString1 The 1st UUID in string from. NULL or malformed + * string is not permitted. + * @param pszString2 The 2nd UUID in string form. NULL or malformed + * string is not permitted. + */ +RTDECL(int) RTUuidCompare2Strs(const char *pszString1, const char *pszString2); + +/** + * Converts binary UUID to its string representation. + * + * @note IPRT uses little endian byte ordering in the UUID integer fields. If + * you want to pass IPRT UUIDs in binary representation to other UUID libraries + * and expect to get exactly the same string representation as in IPRT, you + * need to convert the first three integer fields (one 32 bit value, two 16 bit + * values) separately to big endian (also called network byte order). + * Correspondingly, if you want to get the right result with UUIDs which are in + * big endian format, you need to convert them before using this function. + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Uuid to convert. + * @param pszString Where to store result string. + * @param cchString pszString buffer length, must be >= RTUUID_STR_LENGTH. + */ +RTDECL(int) RTUuidToStr(PCRTUUID pUuid, char *pszString, size_t cchString); + +/** + * Converts UUID from its string representation to binary format. + * + * @note IPRT uses little endian byte ordering in the UUID integer fields. If + * you want to pass IPRT UUIDs in binary representation to other UUID libraries + * and expect to get exactly the same string representation as in IPRT, you + * need to convert the first three integer fields (one 32 bit value, two 16 bit + * values) separately to big endian (also called network byte order). + * Correspondingly, if you want to get the right result with UUIDs which are in + * big endian format, you need to convert them before using this function. + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Where to store result Uuid. + * @param pszString String with UUID text data. + */ +RTDECL(int) RTUuidFromStr(PRTUUID pUuid, const char *pszString); + +/** + * Converts binary UUID to its UTF-16 string representation. + * + * @note See note in RTUuidToStr. + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Uuid to convert. + * @param pwszString Where to store result string. + * @param cwcString pszString buffer length, must be >= + * RTUUID_STR_LENGTH. + */ +RTDECL(int) RTUuidToUtf16(PCRTUUID pUuid, PRTUTF16 pwszString, size_t cwcString); + +/** + * Converts UUID from its UTF-16 string representation to binary format. + * + * @note See note in RTUuidFromStr. + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Where to store result Uuid. + * @param pwszString String with UUID text data. + */ +RTDECL(int) RTUuidFromUtf16(PRTUUID pUuid, PCRTUTF16 pwszString); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uuid_h */ + diff --git a/include/iprt/vector.h b/include/iprt/vector.h new file mode 100644 index 00000000..0e3f6a8a --- /dev/null +++ b/include/iprt/vector.h @@ -0,0 +1,389 @@ +/** @file + * IPRT - Vector - STL-inspired vector implementation in C. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** + * @todo the right Doxygen tag here + * This file defines a set of macros which provide a functionality and an + * interface roughly similar to the C++ STL vector container. To create a + * vector of a particular type one must first explicitly instantiate such a + * vector in the source file, e.g. + * RTVEC_DECL(TopLevels, Window *) + * without a semi-colon. This macro will define a structure (struct TopLevels) + * which contains a dynamically resizeable array of Window * elements. It + * will also define a number of inline methods for manipulating the structure, + * such as + * Window *TopLevelsPushBack(struct TopLevels *) + * which adds a new element to the end of the array and returns it, optionally + * reallocating the array if there is not enough space for the new element. + * (This particular method prototype differs from the STL equivalent - + * push_back - more than most of the other methods). + * + * To create a vector, one simply needs to declare the structure, in this case + * struct TopLevels = RTVEC_INITIALIZER; + * + * There are various other macros for declaring vectors with different + * allocators (e.g. RTVEC_DECL_ALLOCATOR) or with clean-up functions + * (e.g. RTVEC_DECL_DELETE). See the descriptions of the generic methods and + * the declarator macros below. + * + * One particular use of vectors is to assemble an array of a particular type + * in heap memory without knowing - or counting - the number of elements in + * advance. To do this, add the elements onto the array using PushBack, then + * extract the array from the vector using the (non-STL) Detach method. + * + * @note functions in this file are inline to prevent warnings about + * unused static functions. I assume that in this day and age a + * compiler makes its own decisions about whether to actually + * inline a function. + * @note since vector structures must be explicitly instanciated unlike the + * C++ vector template, care must be taken not to instanciate a + * particular type twice, e.g. once in a header and once in a code file. + * Only using vectors in code files and keeping them out of interfaces + * (or passing them as anonymously) makes it easier to take care of this. + */ + +#ifndef IPRT_INCLUDED_vector_h +#define IPRT_INCLUDED_vector_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/******************************************************************************* +* Header Files * +*******************************************************************************/ + +#include +#include +#include +#include /** @todo Should the caller include this if they need + * it? */ + + +/** + * Generic vector structure + */ +/** @todo perhaps we should include an additional member for a parameter to + * three-argument reallocators, so that we can support e.g. mempools? */ +#define RTVEC_DECL_STRUCT(name, type) \ +struct name \ +{ \ + /** The number of elements in the vector */ \ + size_t mcElements; \ + /** The current capacity of the vector */ \ + size_t mcCapacity; \ + /** The elements themselves */ \ + type *mpElements; \ +}; + +/** Initialiser for an empty vector structure */ +#define RTVEC_INITIALIZER { 0, 0, NULL } + +/** The unit by which the vector capacity is increased */ +#define RTVECIMPL_ALLOC_UNIT 16 + +/** + * Generic method - get the size of a vector + */ +/** @todo What is the correct way to do doxygen for this sort of macro? */ +#define RTVEC_DECLFN_SIZE(name, type) \ +DECLINLINE(size_t) name ## Size(struct name *pVec) \ +{ \ + return(pVec->mcElements); \ +} + +/** + * Generic method - expand a vector + */ +#define RTVEC_DECLFN_RESERVE(name, type, pfnRealloc) \ +DECLINLINE(int) name ## Reserve(struct name *pVec, size_t cNewCapacity) \ +{ \ + void *pvNew; \ + \ + if (cNewCapacity <= pVec->mcCapacity) \ + return VINF_SUCCESS; \ + pvNew = pfnRealloc(pVec->mpElements, cNewCapacity * sizeof(type)); \ + if (!pvNew) \ + return VERR_NO_MEMORY; \ + pVec->mcCapacity = cNewCapacity; \ + pVec->mpElements = (type *)pvNew; \ + return VINF_SUCCESS; \ +} + +/** + * Generic method - return a pointer to the first element in the vector. + */ +#define RTVEC_DECLFN_BEGIN(name, type) \ +DECLINLINE(type *) name ## Begin(struct name *pVec) \ +{ \ + return(pVec->mpElements); \ +} + +/** + * Generic method - return a pointer to one past the last element in the + * vector. + */ +#define RTVEC_DECLFN_END(name, type) \ +DECLINLINE(type *) name ## End(struct name *pVec) \ +{ \ + return(&pVec->mpElements[pVec->mcElements]); \ +} + +/** + * Generic method - add a new, uninitialised element onto a vector and return + * it. + * @note this method differs from the STL equivalent by letting the caller + * post-initialise the new element rather than copying it from its + * argument. + */ +#define RTVEC_DECLFN_PUSHBACK(name, type) \ +DECLINLINE(type *) name ## PushBack(struct name *pVec) \ +{ \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + if ( pVec->mcElements == pVec->mcCapacity \ + && RT_FAILURE(name ## Reserve(pVec, pVec->mcCapacity \ + + RTVECIMPL_ALLOC_UNIT))) \ + return NULL; \ + ++pVec->mcElements; \ + return &pVec->mpElements[pVec->mcElements - 1]; \ +} + +/** + * Generic method - drop the last element from the vector. + */ +#define RTVEC_DECLFN_POPBACK(name) \ +DECLINLINE(void) name ## PopBack(struct name *pVec) \ +{ \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + --pVec->mcElements; \ +} + +/** + * Generic method - drop the last element from the vector, calling a clean-up + * method first. + * + * By taking an adapter function for the element to be dropped as an + * additional macro parameter we can support clean-up by pointer + * (pfnAdapter maps T* -> T*) or by value (maps T* -> T). pfnAdapter takes + * one argument of type @a type * and must return whatever type pfnDelete + * expects. + */ +/** @todo find a better name for pfnAdapter? */ +#define RTVEC_DECLFN_POPBACK_DELETE(name, type, pfnDelete, pfnAdapter) \ +DECLINLINE(void) name ## PopBack(struct name *pVec) \ +{ \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + --pVec->mcElements; \ + pfnDelete(pfnAdapter(&pVec->mpElements[pVec->mcElements])); \ +} + +/** + * Generic method - reset a vector to empty. + * @note This function does not free any memory + */ +#define RTVEC_DECLFN_CLEAR(name) \ +DECLINLINE(void) name ## Clear(struct name *pVec) \ +{ \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + pVec->mcElements = 0; \ +} + +/** + * Generic method - reset a vector to empty, calling a clean-up method on each + * element first. + * @note See @a RTVEC_DECLFN_POPBACK_DELETE for an explanation of pfnAdapter + * @note This function does not free any memory + * @note The cleanup function is currently called on the elements from first + * to last. The testcase expects this. + */ +#define RTVEC_DECLFN_CLEAR_DELETE(name, pfnDelete, pfnAdapter) \ +DECLINLINE(void) name ## Clear(struct name *pVec) \ +{ \ + size_t i; \ + \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + for (i = 0; i < pVec->mcElements; ++i) \ + pfnDelete(pfnAdapter(&pVec->mpElements[i])); \ + pVec->mcElements = 0; \ +} + +/** + * Generic method - detach the array contained inside a vector and reset the + * vector to empty. + * @note This function does not free any memory + */ +#define RTVEC_DECLFN_DETACH(name, type) \ +DECLINLINE(type *) name ## Detach(struct name *pVec) \ +{ \ + type *pArray = pVec->mpElements; \ + \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + pVec->mcElements = 0; \ + pVec->mpElements = NULL; \ + pVec->mcCapacity = 0; \ + return pArray; \ +} + +/** Common declarations for all vector types */ +#define RTVEC_DECL_COMMON(name, type, pfnRealloc) \ + RTVEC_DECL_STRUCT(name, type) \ + RTVEC_DECLFN_SIZE(name, type) \ + RTVEC_DECLFN_RESERVE(name, type, pfnRealloc) \ + RTVEC_DECLFN_BEGIN(name, type) \ + RTVEC_DECLFN_END(name, type) \ + RTVEC_DECLFN_PUSHBACK(name, type) \ + RTVEC_DECLFN_DETACH(name, type) + +/** + * Declarator macro - declare a vector type + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnRealloc the memory reallocation function used for expanding the + * vector + */ +#define RTVEC_DECL_ALLOCATOR(name, type, pfnRealloc) \ + RTVEC_DECL_COMMON(name, type, pfnRealloc) \ + RTVEC_DECLFN_POPBACK(name) \ + RTVEC_DECLFN_CLEAR(name) + +/** + * Generic method - inline id mapping delete adapter function - see the + * explanation of pfnAdapter in @a RTVEC_DECLFN_POPBACK_DELETE. + */ +#define RTVEC_DECLFN_DELETE_ADAPTER_ID(name, type) \ +DECLINLINE(type *) name ## DeleteAdapterId(type *arg) \ +{ \ + return arg; \ +} + +/** + * Generic method - inline pointer-to-value mapping delete adapter function - + * see the explanation of pfnAdapter in @a RTVEC_DECLFN_POPBACK_DELETE. + */ +#define RTVEC_DECLFN_DELETE_ADAPTER_TO_VALUE(name, type) \ +DECLINLINE(type) name ## DeleteAdapterToValue(type *arg) \ +{ \ + return *arg; \ +} + +/** + * Declarator macro - declare a vector type with a cleanup callback to be used + * when elements are dropped from the vector. The callback takes a pointer to + * @a type, + * NOT a value of type @a type. + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnRealloc the memory reallocation function used for expanding the + * vector + * @param pfnDelete the cleanup callback function - signature + * void pfnDelete(type *) + */ +#define RTVEC_DECL_ALLOCATOR_DELETE(name, type, pfnRealloc, pfnDelete) \ + RTVEC_DECL_COMMON(name, type, pfnRealloc) \ + RTVEC_DECLFN_DELETE_ADAPTER_ID(name, type) \ + RTVEC_DECLFN_POPBACK_DELETE(name, type, pfnDelete, \ + name ## DeleteAdapterId) \ + RTVEC_DECLFN_CLEAR_DELETE(name, pfnDelete, name ## DeleteAdapterId) + +/** + * Declarator macro - declare a vector type with a cleanup callback to be used + * when elements are dropped from the vector. The callback takes a parameter + * of type @a type, NOT a pointer to @a type. + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnRealloc the memory reallocation function used for expanding the + * vector + * @param pfnDelete the cleanup callback function - signature + * void pfnDelete(type) + */ +#define RTVEC_DECL_ALLOCATOR_DELETE_BY_VALUE(name, type, pfnRealloc, \ + pfnDelete) \ + RTVEC_DECL_COMMON(name, type, pfnRealloc) \ + RTVEC_DECLFN_DELETE_ADAPTER_TO_VALUE(name, type) \ + RTVEC_DECLFN_POPBACK_DELETE(name, type, pfnDelete, \ + name ## DeleteAdapterToValue) \ + RTVEC_DECLFN_CLEAR_DELETE(name, pfnDelete, \ + name ## DeleteAdapterToValue) + +/** + * Inline wrapper around RTMemRealloc macro to get a function usable as a + * callback. + */ +DECLINLINE(void *) rtvecReallocDefTag(void *pv, size_t cbNew) +{ + return RTMemRealloc(pv, cbNew); +} + +/** + * Declarator macro - declare a vector type (see @a RTVEC_DECL_ALLOCATOR) + * using RTMemRealloc as a memory allocator + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + */ +#define RTVEC_DECL(name, type) \ + RTVEC_DECL_ALLOCATOR(name, type, rtvecReallocDefTag) + +/** + * Declarator macro - declare a vector type with a cleanup by pointer callback + * (see @a RTVEC_DECL_ALLOCATOR_DELETE) using RTMemRealloc as a memory + * allocator + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnDelete the cleanup callback function - signature + * void pfnDelete(type *) + */ +#define RTVEC_DECL_DELETE(name, type, pfnDelete) \ + RTVEC_DECL_ALLOCATOR_DELETE(name, type, rtvecReallocDefTag, pfnDelete) + +/** + * Declarator macro - declare a vector type with a cleanup by value callback + * (see @a RTVEC_DECL_ALLOCATOR_DELETE_BY_VALUE) using RTMemRealloc as a memory + * allocator + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnDelete the cleanup callback function - signature + * void pfnDelete(type) + */ +#define RTVEC_DECL_DELETE_BY_VALUE(name, type, pfnDelete) \ + RTVEC_DECL_ALLOCATOR_DELETE_BY_VALUE(name, type, rtvecReallocDefTag, \ + pfnDelete) + +#endif /* !IPRT_INCLUDED_vector_h */ + diff --git a/include/iprt/vfs.h b/include/iprt/vfs.h new file mode 100644 index 00000000..21fccdf6 --- /dev/null +++ b/include/iprt/vfs.h @@ -0,0 +1,2021 @@ +/** @file + * IPRT - Virtual Filesystem. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_vfs_h +#define IPRT_INCLUDED_vfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_vfs RTVfs - Virtual Filesystem + * @ingroup grp_rt + * + * The virtual filesystem APIs are intended to make it possible to work on + * container files, file system sub-trees, file system overlays and other custom + * filesystem configurations. It also makes it possible to create filters, like + * automatically gunzipping a tar.gz file before feeding it to the RTTar API for + * unpacking - or vice versa. + * + * The virtual filesystem APIs are intended to mirror the RTDir, RTFile, RTPath + * and RTFs APIs pretty closely so that rewriting a piece of code to work with + * it should be easy. However there are some differences to the way the APIs + * works and the user should heed the documentation. The differences are + * usually motivated by simplification and in some case to make the VFS more + * flexible. + * + * @{ + */ + +/** + * The object type. + */ +typedef enum RTVFSOBJTYPE +{ + /** Invalid type. */ + RTVFSOBJTYPE_INVALID = 0, + /** Pure base object. + * This is returned by the filesystem stream to represent directories, + * devices, fifos and similar that needs to be created. */ + RTVFSOBJTYPE_BASE, + /** Virtual filesystem. */ + RTVFSOBJTYPE_VFS, + /** Filesystem stream. */ + RTVFSOBJTYPE_FS_STREAM, + /** Pure I/O stream. */ + RTVFSOBJTYPE_IO_STREAM, + /** Directory. */ + RTVFSOBJTYPE_DIR, + /** File. */ + RTVFSOBJTYPE_FILE, + /** Symbolic link. */ + RTVFSOBJTYPE_SYMLINK, + /** End of valid object types. */ + RTVFSOBJTYPE_END, + /** Pure I/O stream. */ + RTVFSOBJTYPE_32BIT_HACK = 0x7fffffff +} RTVFSOBJTYPE; +/** Pointer to a VFS object type. */ +typedef RTVFSOBJTYPE *PRTVFSOBJTYPE; + +/** + * Translates a RTVFSOBJTYPE value into a string. + * + * @returns Pointer to readonly name. + * @param enmType The object type to name. + */ +RTDECL(const char *) RTVfsTypeName(RTVFSOBJTYPE enmType); + + + +/** @name RTVfsCreate flags + * @{ */ +/** Whether the file system is read-only. */ +#define RTVFS_C_READONLY RT_BIT(0) +/** Whether we the VFS should be thread safe (i.e. automaticaly employ + * locks). */ +#define RTVFS_C_THREAD_SAFE RT_BIT(1) +/** @} */ + +/** + * Creates an empty virtual filesystem. + * + * @returns IPRT status code. + * @param pszName Name, for logging and such. + * @param fFlags Flags, MBZ. + * @param phVfs Where to return the VFS handle. Release the returned + * reference by calling RTVfsRelease. + */ +RTDECL(int) RTVfsCreate(const char *pszName, uint32_t fFlags, PRTVFS phVfs); +RTDECL(uint32_t) RTVfsRetain(RTVFS hVfs); +RTDECL(uint32_t) RTVfsRetainDebug(RTVFS hVfs, RT_SRC_POS_DECL); +RTDECL(uint32_t) RTVfsRelease(RTVFS hVfs); + +/** @name RTVFSMNT_F_XXX - Flags for RTVfsMount + * @{ */ +/** Mount read-only. */ +#define RTVFSMNT_F_READ_ONLY RT_BIT_32(0) +/** Purpose is . */ +#define RTVFSMNT_F_FOR_RANGE_IN_USE RT_BIT_32(1) +/** Valid mask. */ +#define RTVFSMNT_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Does the file system detection and mounting. + * + * @returns IPRT status code. + * @retval VERR_VFS_UNSUPPORTED_FORMAT if not recognized as a support file + * system. + * @param hVfsFileIn The file handle of the volume. + * @param fFlags RTVFSMTN_F_XXX. + * @param phVfs Where to return the VFS handle on success. + * @param pErrInfo Where to return additional error information. + * Optional. + */ +RTDECL(int) RTVfsMountVol(RTVFSFILE hVfsFileIn, uint32_t fFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + +RTDECL(int) RTVfsAttach(RTVFS hVfs, const char *pszMountPoint, uint32_t fFlags, RTVFS hVfsAttach); +RTDECL(int) RTVfsDetach(RTVFS hVfs, const char *pszMountPoint, RTVFS hVfsToDetach, PRTVFS *phVfsDetached); +RTDECL(uint32_t) RTVfsGetAttachmentCount(RTVFS hVfs); +RTDECL(int) RTVfsGetAttachment(RTVFS hVfs, uint32_t iOrdinal, PRTVFS *phVfsAttached, uint32_t *pfFlags, + char *pszMountPoint, size_t cbMountPoint); + +/** + * Opens the root director of the given VFS. + * + * @returns IPRT status code. + * @param hVfs VFS handle. + * @param phDir Where to return the root directory handle. + */ +RTDECL(int) RTVfsOpenRoot(RTVFS hVfs, PRTVFSDIR phDir); + +/** + * Queries information about a object in the virtual filesystem. + * + * @returns IPRT Status code. + * @param hVfs VFS handle. + * @param pszPath Path to the object, relative to the VFS root. + * @param pObjInfo Where to return info. + * @param enmAddAttr What to return. + * @param fFlags RTPATH_F_XXX. + * @sa RTPathQueryInfoEx, RTVfsDirQueryPathInfo, RTVfsObjQueryInfo + */ +RTDECL(int) RTVfsQueryPathInfo(RTVFS hVfs, const char *pszPath, PRTFSOBJINFO pObjInfo, + RTFSOBJATTRADD enmAddAttr, uint32_t fFlags); + +/** + * Checks whether a given range is in use by the virtual filesystem. + * + * @returns IPRT status code. + * @param hVfs VFS handle. + * @param off Start offset to check. + * @param cb Number of bytes to check. + * @param pfUsed Where to store the result. + */ +RTDECL(int) RTVfsQueryRangeState(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed); + +/** + * Queries the volume label. + * + * @returns IPRT status code. + * @param hVfs VFS handle. + * @param fAlternative For use with ISO files to retrieve the primary lable + * rather than the joliet / UDF one that the mount + * options would indicate. For other file systems, as + * well for ISO not mounted in joliet / UDF mode, the + * flag is ignored. + * @param pszLabel Where to store the lable. + * @param cbLabel Size of the buffer @a pszLable points at. + * @param pcbActual Where to return the label length, including the + * terminator. In case of VERR_BUFFER_OVERFLOW + * returns, this will be set to the required buffer + * size. Optional. + */ +RTDECL(int) RTVfsQueryLabel(RTVFS hVfs, bool fAlternative, char *pszLabel, size_t cbLabel, size_t *pcbActual); + + +/** @defgroup grp_rt_vfs_obj VFS Base Object API + * @{ + */ + +/** + * Retains a reference to the VFS base object handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(uint32_t) RTVfsObjRetain(RTVFSOBJ hVfsObj); +RTDECL(uint32_t) RTVfsObjRetainDebug(RTVFSOBJ hVfsObj, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS base handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(uint32_t) RTVfsObjRelease(RTVFSOBJ hVfsObj); + +/** @name RTVFSOBJ_F_XXX - Flags or RTVfsObjOpen and RTVfsDirOpenObj. + * @note Must leave space for RTPATH_F_XXX. + * @{ */ +/** Directory (RTFS_TYPE_DIRECTORY). */ +#define RTVFSOBJ_F_OPEN_DIRECTORY RT_BIT_32(8) +/** Symbolic link (RTFS_TYPE_SYMLINK). */ +#define RTVFSOBJ_F_OPEN_SYMLINK RT_BIT_32(9) +/** Regular file (RTFS_TYPE_FILE). */ +#define RTVFSOBJ_F_OPEN_FILE RT_BIT_32(10) +/** Character device (RTFS_TYPE_DEV_CHAR). */ +#define RTVFSOBJ_F_OPEN_DEV_CHAR RT_BIT_32(11) +/** Block device (RTFS_TYPE_DEV_BLOCK). */ +#define RTVFSOBJ_F_OPEN_DEV_BLOCK RT_BIT_32(12) +/** Named pipe (fifo) (RTFS_TYPE_FIFO). */ +#define RTVFSOBJ_F_OPEN_FIFO RT_BIT_32(13) +/** Socket (RTFS_TYPE_SOCKET). */ +#define RTVFSOBJ_F_OPEN_SOCKET RT_BIT_32(14) +/** Mounted VFS. */ +#define RTVFSOBJ_F_OPEN_MOUNT RT_BIT_32(15) +/** Mask object types we wish to open. */ +#define RTVFSOBJ_F_OPEN_MASK UINT32_C(0x0000ff00) +/** Any kind of object that translates to RTVFSOBJTYPE_FILE. */ +#define RTVFSOBJ_F_OPEN_ANY_FILE (RTVFSOBJ_F_OPEN_FILE | RTVFSOBJ_F_OPEN_DEV_BLOCK) +/** Any kind of object that translates to RTVFSOBJTYPE_IOS or + * RTVFSOBJTYPE_FILE. */ +#define RTVFSOBJ_F_OPEN_ANY_IO_STREAM ( RTVFSOBJ_F_ANY_OPEN_FILE | RTVFSOBJ_F_DEV_OPEN_BLOCK \ + | RTVFSOBJ_F_OPEN_FIFO | RTVFSOBJ_F_OPEN_SOCKET) +/** Any kind of object. */ +#define RTVFSOBJ_F_OPEN_ANY RTVFSOBJ_F_OPEN_MASK + +/** Do't create anything, return file not found. */ +#define RTVFSOBJ_F_CREATE_NOTHING UINT32_C(0x00000000) +/** Create a file if the if the object was not found and the RTFILE_O_XXX + * flags allows it. */ +#define RTVFSOBJ_F_CREATE_FILE UINT32_C(0x00010000) +/** Create a directory if the object was not found and the RTFILE_O_XXX + * flags allows it. */ +#define RTVFSOBJ_F_CREATE_DIRECTORY UINT32_C(0x00020000) +/** The creation type mask. */ +#define RTVFSOBJ_F_CREATE_MASK UINT32_C(0x00070000) + +/** Indicate that this call is for traversal. + * @internal only */ +#define RTVFSOBJ_F_TRAVERSAL RT_BIT_32(31) +/** Valid mask for external callers. */ +#define RTVFSOBJ_F_VALID_MASK UINT32_C(0x0007ff00) +/** @} */ + +/** + * Opens any file system object in the given VFS. + * + * @returns IPRT status code. + * @param hVfs The VFS to open the object within. + * @param pszPath Path to the file. + * @param fFileOpen RTFILE_O_XXX flags. + * @param fObjFlags More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX. + * @param phVfsObj Where to return the object handle. + * @sa RTVfsDirOpenObj, RTVfsDirOpenDir, RTVfsDirOpenFile + */ +RTDECL(int) RTVfsObjOpen(RTVFS hVfs, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj); + +/** + * Query information about the object. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the @a enmAddAttr value is not handled by the + * implementation. + * + * @param hVfsObj The VFS object handle. + * @param pObjInfo Where to return the info. + * @param enmAddAttr Which additional attributes should be retrieved. + * @sa RTVfsIoStrmQueryInfo, RTVfsFileQueryInfo, RTFileQueryInfo, + * RTPathQueryInfo + */ +RTDECL(int) RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Sets the file mode for the given VFS object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if the object type has no file mode to set. + * Only directories, files and symbolic links support this operation. + * + * @param hVfsObj The VFS object handle. + * @param fMode The mode mask. + * @param fMask The bits in the mode mask which should be changed. + */ +RTDECL(int) RTVfsObjSetMode(RTVFSOBJ hVfsObj, RTFMODE fMode, RTFMODE fMask); + +/** + * Sets one or more timestamps for the given VFS object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if the object type has no file mode to set. + * Only directories, files and symbolic links support this operation. + * + * @param hVfsObj The VFS object handle. + * @param pAccessTime Pointer to the new access time. NULL if not to + * be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if not + * to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not to + * be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to + * be changed. + * + * @remarks See RTFileSetTimes for restrictions and behavior imposed by the + * host OS or underlying VFS provider. + * @sa RTFileSetTimes, RTPathSetTimes + */ +RTDECL(int) RTVfsObjSetTimes(RTVFSOBJ hVfsObj, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + +/** + * Set the unix style owner and group on the given VFS object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if the object type has no file mode to set. + * Only directories, files and symbolic links support this operation. + * + * @param hVfsObj The VFS object handle. + * @param uid The user ID of the new owner. NIL_RTUID if + * unchanged. + * @param gid The group ID of the new owner group. NIL_RTGID if + * unchanged. + * + * @sa RTFileSetOwner, RTPathSetOwner. + */ +RTDECL(int) RTVfsObjSetOwner(RTVFSOBJ hVfsObj, RTUID uid, RTGID gid); + + +/** + * Gets the type of a VFS object. + * + * @returns The VFS object type on success, RTVFSOBJTYPE_INVALID on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSOBJTYPE) RTVfsObjGetType(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFS) RTVfsObjToVfs(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS filesystem stream handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSFSSTREAM) RTVfsObjToFsStream(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS directory handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSDIR) RTVfsObjToDir(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS I/O stream handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSIOSTREAM) RTVfsObjToIoStream(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS file handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSFILE) RTVfsObjToFile(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS symbolic link handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSSYMLINK) RTVfsObjToSymlink(RTVFSOBJ hVfsObj); + + +/** + * Converts a VFS handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfs The VFS handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromVfs(RTVFS hVfs); + +/** + * Converts a VFS filesystem stream handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsFss The VFS filesystem stream handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromFsStream(RTVFSFSSTREAM hVfsFss); + +/** + * Converts a VFS directory handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsDir The VFS directory handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromDir(RTVFSDIR hVfsDir); + +/** + * Converts a VFS I/O stream handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromIoStream(RTVFSIOSTREAM hVfsIos); + +/** + * Converts a VFS file handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsFile The VFS file handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromFile(RTVFSFILE hVfsFile); + +/** + * Converts a VFS symbolic link handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsSym The VFS symbolic link handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromSymlink(RTVFSSYMLINK hVfsSym); + +/** @} */ + + +/** @defgroup grp_rt_vfs_fsstream VFS Filesystem Stream API + * + * Filesystem streams are for tar, cpio and similar. Any virtual filesystem can + * be turned into a filesystem stream using RTVfsFsStrmFromVfs. + * + * @{ + */ + +RTDECL(uint32_t) RTVfsFsStrmRetain(RTVFSFSSTREAM hVfsFss); +RTDECL(uint32_t) RTVfsFsStrmRetainDebug(RTVFSFSSTREAM hVfsFss, RT_SRC_POS_DECL); +RTDECL(uint32_t) RTVfsFsStrmRelease(RTVFSFSSTREAM hVfsFss); +RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Gets the next object in the stream. + * + * This call may affect the stream posision of a previously returned object. + * + * The type of object returned here typically boils down to three types: + * - I/O streams (representing files), + * - symbolic links + * - base object + * The base objects represent anything not convered by the two other, i.e. + * directories, device nodes, fifos, sockets and whatnot. The details can be + * queried using RTVfsObjQueryInfo. + * + * That said, absolutely any object except for filesystem stream objects can be + * returned by this call. Any generic code is adviced to just deal with it all. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if a new object was retrieved. + * @retval VERR_EOF when there are no more objects. + * @retval VERR_INVALID_FUNCTION if called on a non-readable stream. + * + * @param hVfsFss The file system stream handle. + * @param ppszName Where to return the object name. Must be freed by + * calling RTStrFree. + * @param penmType Where to return the object type. + * @param phVfsObj Where to return the object handle (referenced). This + * must be cast to the desired type before use. + */ +RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj); + +/** + * Appends a VFS object to the stream. + * + * The stream must be writable. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if called on a non-writable stream. + * @param hVfsFss The file system stream handle. + * @param pszPath The path. + * @param hVfsObj The VFS object to add. + * @param fFlags RTVFSFSSTRM_ADD_F_XXX. + */ +RTDECL(int) RTVfsFsStrmAdd(RTVFSFSSTREAM hVfsFss, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags); + +/** @name RTVFSFSSTRM_ADD_F_XXX - Flags for RTVfsFsStrmAdd. + * @{ */ +/** Input is an I/O stream of indeterminate length, read to the end and then + * update the file header. + * @note This is *only* possible if the output stream is actually a file. */ +#define RTVFSFSSTRM_ADD_F_STREAM RT_BIT_32(0) +/** Mask of flags specific to the target stream. */ +#define RTVFSFSSTRM_ADD_F_SPECIFIC_MASK UINT32_C(0xff000000) +/** Valid bits. */ +#define RTVFSFSSTRM_ADD_F_VALID_MASK UINT32_C(0xff000001) +/** @} */ + +/** + * Pushes an byte stream onto the stream. + * + * The stream must be writable. + * + * This differs from RTVfsFsStrmAdd() in that it will create a regular file in + * the output file system stream and provide the actual content bytes via the + * returned I/O stream object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if called on a non-writable stream. + * @param hVfsFss The file system stream handle. + * @param pszPath The path to the file. + * @param cbFile The file size. This can also be set to UINT64_MAX if + * the file system stream is backed by a file. + * @param paObjInfo Array of zero or more RTFSOBJINFO structures containing + * different pieces of information about the file. If any + * provided, the first one should be a RTFSOBJATTRADD_UNIX + * one, additional can be supplied if wanted. What exactly + * is needed depends on the underlying FS stream + * implementation. + * @param cObjInfo Number of items in the array @a paObjInfo points at. + * @param fFlags RTVFSFSSTRM_PUSH_F_XXX. + * @param phVfsIos Where to return the I/O stream to feed the file content + * to. If the FS stream is backed by a file, the returned + * handle can be cast to a file if necessary. + */ +RTDECL(int) RTVfsFsStrmPushFile(RTVFSFSSTREAM hVfsFss, const char *pszPath, uint64_t cbFile, + PCRTFSOBJINFO paObjInfo, uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos); + +/** @name RTVFSFSSTRM_PUSH_F_XXX - Flags for RTVfsFsStrmPushFile. + * @{ */ +/** Input is an I/O stream of indeterminate length, read to the end and then + * update the file header. + * @note This is *only* possible if the output stream is actually a file. */ +#define RTVFSFSSTRM_PUSH_F_STREAM RT_BIT_32(0) +/** Mask of flags specific to the target stream. */ +#define RTVFSFSSTRM_PUSH_F_SPECIFIC_MASK UINT32_C(0xff000000) +/** Valid bits. */ +#define RTVFSFSSTRM_PUSH_F_VALID_MASK UINT32_C(0xff000001) +/** @} */ + +/** + * Marks the end of the stream. + * + * The stream must be writable. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if called on a non-writable stream. + * @param hVfsFss The file system stream handle. + */ +RTDECL(int) RTVfsFsStrmEnd(RTVFSFSSTREAM hVfsFss); + +/** @} */ + + +/** @defgroup grp_rt_vfs_dir VFS Directory API + * @{ + */ + +/** + * Retains a reference to the VFS directory handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsDir The VFS directory handle. + */ +RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir); +RTDECL(uint32_t) RTVfsDirRetainDebug(RTVFSDIR hVfsDir, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS directory handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsDir The VFS directory handle. + */ +RTDECL(uint32_t) RTVfsDirRelease(RTVFSDIR hVfsDir); + +/** + * Opens a directory in the specified file system. + * + * @returns IPRT status code. + * @param hVfs The VFS to open the directory within. + * @param pszPath Path to the directory, relative to the root. + * @param fFlags Reserved, MBZ. + * @param phVfsDir Where to return the directory. + */ +RTDECL(int) RTVfsDirOpen(RTVFS hVfs, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir); + +/** + * Opens any file system object in or under the given directory. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the file. + * @param fFileOpen RTFILE_O_XXX flags. + * @param fObjFlags More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX. + * @param phVfsObj Where to return the object handle. + * @sa RTVfsObjOpen, RTVfsDirOpenDir, RTVfsDirOpenFile + */ +RTDECL(int) RTVfsDirOpenObj(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj); + +/** + * Opens a file in or under the given directory. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the file. + * @param fOpen RTFILE_O_XXX flags. + * @param phVfsFile Where to return the file. + * @sa RTVfsDirOpenFileAsIoStream + */ +RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile); + +/** + * Convenience wrapper around RTVfsDirOpenFile that returns an I/O stream. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the file. + * @param fOpen RTFILE_O_XXX flags. + * @param phVfsIos Where to return the I/O stream handle of the file. + * @sa RTVfsDirOpenFile + */ +RTDECL(int) RTVfsDirOpenFileAsIoStream(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos); + +/** + * Opens a directory in or under the given directory. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the file. + * @param fFlags Reserved, MBZ. + * @param phVfsDir Where to return the directory. + */ +RTDECL(int) RTVfsDirOpenDir(RTVFSDIR hVfsDir, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir); + +/** + * Creates a directory relative to @a hVfsDir. + * + * @returns IPRT status code + * @param hVfsDir The directory the path is relative to. + * @param pszRelPath The relative path to the new directory. + * @param fMode The file mode for the new directory. + * @param fFlags Directory creation flags, RTDIRCREATE_FLAGS_XXX. + * @param phVfsDir Where to return the handle to the newly created + * directory. Optional. + * @sa RTDirCreate, RTDirRelDirCreate + */ +RTDECL(int) RTVfsDirCreateDir(RTVFSDIR hVfsDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags, PRTVFSDIR phVfsDir); + +/** + * Create a VFS directory handle from a standard IPRT directory handle (RTDIR). + * + * @returns IPRT status code. + * @param hDir The standard IPRT directory handle. + * @param fLeaveOpen Whether to leave the handle open when the VFS + * directory is released, or to close it (@c false). + * @param phVfsDir Where to return the VFS directory handle. + */ +RTDECL(int) RTVfsDirFromRTDir(RTDIR hDir, bool fLeaveOpen, PRTVFSDIR phVfsDir); + +/** + * RTDirOpen + RTVfsDirFromRTDir. + * + * @returns IPRT status code. + * @param pszPath The path to the directory. + * @param fFlags RTDIR_F_XXX. + * @param phVfsDir Where to return the VFS directory handle. + */ +RTDECL(int) RTVfsDirOpenNormal(const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir); + +/** Checks if @a hVfsDir was opened using RTVfsDirOpenNormal() or + * RTVfsDirFromRTDir(), either directly or indirectly. */ +RTDECL(bool) RTVfsDirIsStdDir(RTVFSDIR hVfsDir); + +/** + * Queries information about a object in or under the given directory. + * + * @returns IPRT Status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the object. + * @param pObjInfo Where to return info. + * @param enmAddAttr What to return. + * @param fFlags RTPATH_F_XXX. + * @sa RTPathQueryInfoEx, RTVfsQueryPathInfo, RTVfsObjQueryInfo + */ +RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo, + RTFSOBJATTRADD enmAddAttr, uint32_t fFlags); + +/** + * Removes a directory relative to @a hVfsDir. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory to start walking the @a pszRelPath + * relative to. + * @param pszRelPath The path to the directory that should be removed. + * @param fFlags Reserved, MBZ. + */ +RTDECL(int) RTVfsDirRemoveDir(RTVFSDIR hVfsDir, const char *pszRelPath, uint32_t fFlags); + +/** + * Reads the next entry in the directory returning extended information. + * + * @returns VINF_SUCCESS and data in pDirEntry on success. + * @returns VERR_NO_MORE_FILES when the end of the directory has been reached. + * @returns VERR_BUFFER_OVERFLOW if the buffer is too small to contain the filename. If + * pcbDirEntry is specified it will be updated with the required buffer size. + * @returns suitable iprt status code on other errors. + * + * @param hVfsDir The VFS directory. + * @param pDirEntry Where to store the information about the next + * directory entry on success. + * @param pcbDirEntry Optional parameter used for variable buffer size. + * + * On input the variable pointed to contains the size of the pDirEntry + * structure. This must be at least OFFSET(RTDIRENTRYEX, szName[2]) bytes. + * + * On successful output the field is updated to + * OFFSET(RTDIRENTRYEX, szName[pDirEntry->cbName + 1]). + * + * When the data doesn't fit in the buffer and VERR_BUFFER_OVERFLOW is + * returned, this field contains the required buffer size. + * + * The value is unchanged in all other cases. + * @param enmAddAttr Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + * + * @sa RTDirReadEx + */ +RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr); + +/** + * Rewind and restart the directory reading. + * + * @returns IRPT status code. + * @param hVfsDir The VFS directory. + */ +RTDECL(int) RTVfsDirRewind(RTVFSDIR hVfsDir); + +/** @} */ + + +/** @defgroup grp_rt_vfs_symlink VFS Symbolic Link API + * + * @remarks The TAR VFS and filesystem stream uses symbolic links for + * describing hard links as well. The users must use RTFS_IS_SYMLINK + * to check if it is a real symlink in those cases. + * + * @remarks Any VFS which is backed by a real file system may be subject to + * races with other processes or threads, so the user may get + * unexpected errors when this happends. This is a bit host specific, + * i.e. it might be prevent on windows if we care. + * + * @{ + */ + + +/** + * Retains a reference to the VFS symbolic link handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsSym The VFS symbolic link handle. + */ +RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym); +RTDECL(uint32_t) RTVfsSymlinkRetainDebug(RTVFSSYMLINK hVfsSym, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS symbolic link handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsSym The VFS symbolic link handle. + */ +RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym); + +/** + * Query information about the symbolic link. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param pObjInfo Where to return the info. + * @param enmAddAttr Which additional attributes should be retrieved. + * + * @sa RTFileQueryInfo, RTPathQueryInfo, RTPathQueryInfoEx + */ +RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Set the unix style owner and group. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param fMode The new mode bits. + * @param fMask The mask indicating which bits we are changing. + * @sa RTFileSetMode, RTPathSetMode + */ +RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask); + +/** + * Set the timestamps associated with the object. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param pAccessTime Pointer to the new access time. NULL if not + * to be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if + * not to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not to be + * changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be + * changed. + * @remarks See RTFileSetTimes for restrictions and behavior imposed by the + * host OS or underlying VFS provider. + * @sa RTFileSetTimes, RTPathSetTimes + */ +RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + +/** + * Set the unix style owner and group. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param uid The user ID of the new owner. NIL_RTUID if + * unchanged. + * @param gid The group ID of the new owner group. NIL_RTGID if + * unchanged. + * @sa RTFileSetOwner, RTPathSetOwner. + */ +RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid); + +/** + * Read the symbolic link target. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param pszTarget The target buffer. + * @param cbTarget The size of the target buffer. + * @sa RTSymlinkRead + */ +RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget); + +/** @} */ + + + +/** @defgroup grp_rt_vfs_iostream VFS I/O Stream API + * @{ + */ + +/** + * Creates a VFS file from a memory buffer. + * + * @returns IPRT status code. + * + * @param fFlags A combination of RTFILE_O_READ and RTFILE_O_WRITE. + * @param pvBuf The buffer. This will be copied and not referenced + * after this function returns. + * @param cbBuf The buffer size. + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmFromBuffer(uint32_t fFlags, void const *pvBuf, size_t cbBuf, PRTVFSIOSTREAM phVfsIos); + +/** + * Creates a VFS I/O stream handle from a standard IPRT file handle (RTFILE). + * + * @returns IPRT status code. + * @param hFile The standard IPRT file handle. + * @param fOpen The flags the handle was opened with. Pass 0 to + * have these detected. + * @param fLeaveOpen Whether to leave the handle open when the VFS file + * is released, or to close it (@c false). + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos); + +/** + * Creates a VFS I/O stream handle from a standard IPRT pipe handle (RTPIPE). + * + * @returns IPRT status code. + * @param hPipe The standard IPRT pipe handle. + * @param fLeaveOpen Whether to leave the handle open when the VFS file + * is released, or to close it (@c false). + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmFromRTPipe(RTPIPE hPipe, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos); + +/** + * Convenience function combining RTFileOpen with RTVfsIoStrmFromRTFile. + * + * @returns IPRT status code. + * @param pszFilename The path to the file in the normal file system. + * @param fOpen The flags to pass to RTFileOpen when opening the + * file, i.e. RTFILE_O_XXX. + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos); + +/** + * Create a VFS I/O stream handle from one of the standard handles. + * + * @returns IPRT status code. + * @param enmStdHandle The standard IPRT file handle. + * @param fOpen The flags the handle was opened with. Pass 0 to + * have these detected. + * @param fLeaveOpen Whether to leave the handle open when the VFS file + * is released, or to close it (@c false). + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmFromStdHandle(RTHANDLESTD enmStdHandle, uint64_t fOpen, bool fLeaveOpen, + PRTVFSIOSTREAM phVfsIos); + +/** + * Retains a reference to the VFS I/O stream handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos); +RTDECL(uint32_t) RTVfsIoStrmRetainDebug(RTVFSIOSTREAM hVfsIos, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS I/O stream handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos); + +/** + * Convert the VFS I/O stream handle to a VFS file handle. + * + * @returns The VFS file handle on success, this must be released. + * NIL_RTVFSFILE if the I/O stream handle is invalid. + * @param hVfsIos The VFS I/O stream handle. + * @sa RTVfsFileToIoStream + */ +RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos); + +/** + * Query information about the I/O stream. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param pObjInfo Where to return the info. + * @param enmAddAttr Which additional attributes should be retrieved. + * @sa RTFileQueryInfo + */ +RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Read bytes from the I/O stream. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_TRY_AGAIN if @a fBlocking is @c false, @a pcbRead is not NULL, + * and no data was available. @a *pcbRead will be set to 0. + * @retval VINF_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the stream was reached before this call). + * When the last byte of the read request is the last byte in the + * stream, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the stream. + * @retval VERR_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the stream is not readable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param pvBuf Where to store the read bytes. + * @param cbToRead The number of bytes to read. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbRead parameter must not be NULL. + * @param pcbRead Where to always store the number of bytes actually + * read. This can be NULL if @a fBlocking is true. + * @sa RTVfsFileRead, RTFileRead, RTPipeRead, RTPipeReadBlocking, + * RTSocketRead + */ +RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead); + +/** + * Read bytes from the I/O stream, optionally with offset. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_TRY_AGAIN if @a fBlocking is @c false, @a pcbRead is not NULL, + * and no data was available. @a *pcbRead will be set to 0. + * @retval VINF_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the stream was reached before this call). + * When the last byte of the read request is the last byte in the + * stream, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the stream. + * @retval VERR_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the stream is not readable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param off Where to read at, -1 for the current position. + * @param pvBuf Where to store the read bytes. + * @param cbToRead The number of bytes to read. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbRead parameter must not be NULL. + * @param pcbRead Where to always store the number of bytes actually + * read. This can be NULL if @a fBlocking is true. + * @sa RTVfsFileRead, RTFileRead, RTPipeRead, RTPipeReadBlocking, + * RTSocketRead + */ +RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead); + +/** + * Reads the remainder of the stream into a memory buffer. + * + * For simplifying string-style processing, the is a zero byte after the + * returned buffer, making sure it can be used as a zero terminated string. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param ppvBuf Where to return the buffer. Must pass to + * RTVfsIoStrmReadAllFree for freeing, not RTMemFree! + * @param pcbBuf Where to return the buffer size. + */ +RTDECL(int) RTVfsIoStrmReadAll(RTVFSIOSTREAM hVfsIos, void **ppvBuf, size_t *pcbBuf); + +/** + * Free memory buffer returned by RTVfsIoStrmReadAll. + * + * @param pvBuf What RTVfsIoStrmReadAll returned. + * @param cbBuf What RTVfsIoStrmReadAll returned. + */ +RTDECL(void) RTVfsIoStrmReadAllFree(void *pvBuf, size_t cbBuf); + +/** + * Write bytes to the I/O stream. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if the stream is not writable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param pvBuf The bytes to write. + * @param cbToWrite The number of bytes to write. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbWritten parameter must not be NULL. + * @param pcbWritten Where to always store the number of bytes actually + * written. This can be NULL if @a fBlocking is true. + * @sa RTVfsFileWrite, RTFileWrite, RTPipeWrite, RTPipeWriteBlocking, + * RTSocketWrite + */ +RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten); +RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten); + +/** + * Reads bytes from the I/O stream into a scatter buffer. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_TRY_AGAIN if @a fBlocking is @c false, @a pcbRead is not NULL, + * and no data was available. @a *pcbRead will be set to 0. + * @retval VINF_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the stream was reached before this call). + * When the last byte of the read request is the last byte in the + * stream, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the stream. + * @retval VERR_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the stream is not readable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param off Where to read at, -1 for the current position. + * @param pSgBuf Pointer to a scatter buffer descriptor. The number + * of bytes described by the segments is what will be + * attemted read. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbRead parameter must not be NULL. + * @param pcbRead Where to always store the number of bytes actually + * read. This can be NULL if @a fBlocking is true. + * @sa RTFileSgRead, RTSocketSgRead, RTPipeRead, RTPipeReadBlocking + */ +RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead); + +/** + * Write bytes to the I/O stream from a gather buffer. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if the stream is not writable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param off Where to write at, -1 for the current position. + * @param pSgBuf Pointer to a gather buffer descriptor. The number + * of bytes described by the segments is what will be + * attemted written. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbWritten parameter must not be NULL. + * @param pcbWritten Where to always store the number of bytes actually + * written. This can be NULL if @a fBlocking is true. + * @sa RTFileSgWrite, RTSocketSgWrite + */ +RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten); + +/** + * Flush any buffered data to the I/O stream. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @sa RTVfsFileFlush, RTFileFlush, RTPipeFlush + */ +RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos); + +/** + * Poll for events. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param fEvents The events to poll for (RTPOLL_EVT_XXX). + * @param cMillies How long to wait for event to eventuate. + * @param fIntr Whether the wait is interruptible and can return + * VERR_INTERRUPTED (@c true) or if this condition + * should be hidden from the caller (@c false). + * @param pfRetEvents Where to return the event mask. + * @sa RTVfsFilePoll, RTPollSetAdd, RTPoll, RTPollNoResume. + */ +RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, + uint32_t *pfRetEvents); +/** + * Tells the current I/O stream position. + * + * @returns Zero or higher - where to return the I/O stream offset. Values + * below zero are IPRT status codes (VERR_XXX). + * @param hVfsIos The VFS I/O stream handle. + * @sa RTFileTell + */ +RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos); + +/** + * Skips @a cb ahead in the stream. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param cb The number bytes to skip. + */ +RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb); + +/** + * Fills the stream with @a cb zeros. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param cb The number of zero bytes to insert. + */ +RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb); + +/** + * Checks if we're at the end of the I/O stream. + * + * @returns true if at EOS, otherwise false. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos); + +/** + * Get the RTFILE_O_XXX flags for the I/O stream. + * + * @returns RTFILE_O_XXX, 0 on failure. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(uint64_t) RTVfsIoStrmGetOpenFlags(RTVFSIOSTREAM hVfsIos); + +/** + * Process the rest of the stream, checking if it's all valid UTF-8 encoding. + * + * @returns IPRT status code. + * + * @param hVfsIos The VFS I/O stream handle. + * @param fFlags Flags governing the validation, see + * RTVFS_VALIDATE_UTF8_XXX. + * @param poffError Where to return the error offset. Optional. + */ +RTDECL(int) RTVfsIoStrmValidateUtf8Encoding(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTFOFF poffError); + +/** @defgroup RTVFS_VALIDATE_UTF8_XXX RTVfsIoStrmValidateUtf8Encoding flags. + * @{ */ +/** The text must not contain any null terminator codepoints. */ +#define RTVFS_VALIDATE_UTF8_NO_NULL RT_BIT_32(0) +/** The codepoints must be in the range covered by RTC-3629. */ +#define RTVFS_VALIDATE_UTF8_BY_RTC_3629 RT_BIT_32(1) +/** Mask of valid flags. */ +#define RTVFS_VALIDATE_UTF8_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Printf-like write function. + * + * @returns Number of characters written on success, negative error status on + * failure. + * @param hVfsIos The VFS I/O stream handle to write to. + * @param pszFormat The format string. + * @param ... Format arguments. + */ +RTDECL(ssize_t) RTVfsIoStrmPrintf(RTVFSIOSTREAM hVfsIos, const char *pszFormat, ...); + +/** + * Printf-like write function. + * + * @returns Number of characters written on success, negative error status on + * failure. + * @param hVfsIos The VFS I/O stream handle to write to. + * @param pszFormat The format string. + * @param va Format arguments. + */ +RTDECL(ssize_t) RTVfsIoStrmPrintfV(RTVFSIOSTREAM hVfsIos, const char *pszFormat, va_list va); + +/** + * VFS I/O stream output buffer structure to use with + * RTVfsIoStrmStrOutputCallback(). + */ +typedef struct VFSIOSTRMOUTBUF +{ + /** The I/O stream handle. */ + RTVFSIOSTREAM hVfsIos; + /** Size of this structure (for sanity). */ + size_t cbSelf; + /** Status code of the operation. */ + int rc; + /** Current offset into szBuf (number of output bytes pending). */ + size_t offBuf; + /** Modest output buffer. */ + char szBuf[256]; +} VFSIOSTRMOUTBUF; +/** Pointer to an VFS I/O stream output buffer for use with + * RTVfsIoStrmStrOutputCallback() */ +typedef VFSIOSTRMOUTBUF *PVFSIOSTRMOUTBUF; + +/** Initializer for a VFS I/O stream output buffer. */ +#define VFSIOSTRMOUTBUF_INIT(a_pOutBuf, a_hVfsIos) \ + do { \ + (a_pOutBuf)->hVfsIos = a_hVfsIos; \ + (a_pOutBuf)->cbSelf = sizeof(*(a_pOutBuf)); \ + (a_pOutBuf)->rc = VINF_SUCCESS; \ + (a_pOutBuf)->offBuf = 0; \ + (a_pOutBuf)->szBuf[0] = '\0'; \ + } while (0) + +/** + * @callback_method_impl{FNRTSTROUTPUT, + * For use with VFSIOSTRMOUTBUF. + * + * Users must use VFSIOSTRMOUTBUF_INIT to initialize a VFSIOSTRMOUTBUF and pass + * that as the outputter argument to the function this callback is handed to.} + */ +RTDECL(size_t) RTVfsIoStrmStrOutputCallback(void *pvArg, const char *pachChars, size_t cbChars); + +/** @} */ + + +/** @defgroup grp_rt_vfs_file VFS File API + * @{ + */ +RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile); + +/** + * Create a VFS file handle from a standard IPRT file handle (RTFILE). + * + * @returns IPRT status code. + * @param hFile The standard IPRT file handle. + * @param fOpen The flags the handle was opened with. Pass 0 to + * have these detected. + * @param fLeaveOpen Whether to leave the handle open when the VFS file + * is released, or to close it (@c false). + * @param phVfsFile Where to return the VFS file handle. + */ +RTDECL(int) RTVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile); +RTDECL(RTHCUINTPTR) RTVfsFileToNative(RTFILE hVfsFile); + +/** + * Convenience function combining RTFileOpen with RTVfsFileFromRTFile. + * + * @returns IPRT status code. + * @param pszFilename The path to the file in the normal file system. + * @param fOpen The flags to pass to RTFileOpen when opening the + * file, i.e. RTFILE_O_XXX. + * @param phVfsFile Where to return the VFS file handle. + */ +RTDECL(int) RTVfsFileOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile); + +/** + * Convert the VFS file handle to a VFS I/O stream handle. + * + * @returns The VFS I/O stream handle on success, this must be released. + * NIL_RTVFSIOSTREAM if the file handle is invalid. + * @param hVfsFile The VFS file handle. + * @sa RTVfsIoStrmToFile + */ +RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile); + +/** + * Retains a reference to the VFS file handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsFile The VFS file handle. + */ +RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile); +RTDECL(uint32_t) RTVfsFileRetainDebug(RTVFSFILE hVfsFile, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS file handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsFile The VFS file handle. + */ +RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile); + +/** + * Query information about the object. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the @a enmAddAttr value is not handled by the + * implementation. + * + * @param hVfsFile The VFS file handle. + * @param pObjInfo Where to return the info. + * @param enmAddAttr Which additional attributes should be retrieved. + * @sa RTVfsObjQueryInfo, RTVfsFsStrmQueryInfo, RTVfsDirQueryInfo, + * RTVfsIoStrmQueryInfo, RTVfsFileQueryInfo, RTFileQueryInfo, + * RTPathQueryInfo. + */ +RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Read bytes from the file at the current position. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_EOF when trying to read __beyond__ the end of the file and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the file was reached before this call). + * When the last byte of the read request is the last byte in the + * file, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the file. + * @retval VERR_EOF when trying to read __beyond__ the end of the file and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the file is not readable. + * + * @param hVfsFile The VFS file handle. + * @param pvBuf Where to store the read bytes. + * @param cbToRead The number of bytes to read. + * @param pcbRead Where to always store the number of bytes actually + * read. Optional. + * @sa RTVfsIoStrmRead, RTFileRead, RTPipeRead, RTPipeReadBlocking, + * RTSocketRead + */ +RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead); +RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Write bytes to the file at the current position. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if the file is not writable. + * + * @param hVfsFile The VFS file handle. + * @param pvBuf The bytes to write. + * @param cbToWrite The number of bytes to write. + * @param pcbWritten Where to always store the number of bytes actually + * written. This can be NULL. + * @sa RTVfsIoStrmRead, RTFileWrite, RTPipeWrite, RTPipeWriteBlocking, + * RTSocketWrite + */ +RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); +RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + + +/** + * Reads bytes from the file into a scatter buffer. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_TRY_AGAIN if @a fBlocking is @c false, @a pcbRead is not NULL, + * and no data was available. @a *pcbRead will be set to 0. + * @retval VINF_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the stream was reached before this call). + * When the last byte of the read request is the last byte in the + * stream, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the stream. + * @retval VERR_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the stream is not readable. + * + * @param hVfsFile The VFS file handle. + * @param off Where to read at, -1 for the current position. + * @param pSgBuf Pointer to a scatter buffer descriptor. The number + * of bytes described by the segments is what will be + * attemted read. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbRead parameter must not be NULL. + * @param pcbRead Where to always store the number of bytes actually + * read. This can be NULL if @a fBlocking is true. + * @sa RTFileSgRead, RTSocketSgRead, RTPipeRead, RTPipeReadBlocking + */ +RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead); + +/** + * Write bytes to the file from a gather buffer. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if the stream is not writable. + * + * @param hVfsFile The VFS file handle. + * @param off Where to write at, -1 for the current position. + * @param pSgBuf Pointer to a gather buffer descriptor. The number + * of bytes described by the segments is what will be + * attemted written. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbWritten parameter must not be NULL. + * @param pcbWritten Where to always store the number of bytes actually + * written. This can be NULL if @a fBlocking is true. + * @sa RTFileSgWrite, RTSocketSgWrite + */ +RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten); + +/** + * Flush any buffered data to the file. + * + * @returns IPRT status code. + * @param hVfsFile The VFS file handle. + * @sa RTVfsIoStrmFlush, RTFileFlush, RTPipeFlush + */ +RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile); + +/** + * Poll for events. + * + * @returns IPRT status code. + * @param hVfsFile The VFS file handle. + * @param fEvents The events to poll for (RTPOLL_EVT_XXX). + * @param cMillies How long to wait for event to eventuate. + * @param fIntr Whether the wait is interruptible and can return + * VERR_INTERRUPTED (@c true) or if this condition + * should be hidden from the caller (@c false). + * @param pfRetEvents Where to return the event mask. + * @sa RTVfsIoStrmPoll, RTPollSetAdd, RTPoll, RTPollNoResume. + */ +RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, + uint32_t *pfRetEvents); + +/** + * Tells the current file position. + * + * @returns Zero or higher - where to return the file offset. Values + * below zero are IPRT status codes (VERR_XXX). + * @param hVfsFile The VFS file handle. + * @sa RTFileTell, RTVfsIoStrmTell. + */ +RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile); + +/** + * Changes the current read/write position of a file. + * + * @returns IPRT status code. + * + * @param hVfsFile The VFS file handle. + * @param offSeek The seek offset. + * @param uMethod The seek method. + * @param poffActual Where to optionally return the new file offset. + * + * @sa RTFileSeek + */ +RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual); + +/** + * Sets the size of a file. + * + * This may also be used for preallocating space + * (RTVFSFILE_SIZE_F_PREALLOC_KEEP_SIZE). + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if handle isn't writable. + * @retval VERR_WRITE_PROTECT if read-only file system. + * @retval VERR_FILE_TOO_BIG if cbSize is larger than what the file system can + * theoretically deal with. + * @retval VERR_DISK_FULL if the file system if full. + * @retval VERR_NOT_SUPPORTED if fFlags indicates some operation that's not + * supported by the file system / host operating system. + * + * @param hVfsFile The VFS file handle. + * @param cbSize The new file size. + * @param fFlags RTVFSFILE_SIZE_F_NORMAL, RTVFSFILE_SIZE_F_GROW, or + * RTVFSFILE_SIZE_F_GROW_KEEP_SIZE. + * + * @sa RTFileSetSize, RTFileSetAllocationSize + */ +RTDECL(int) RTVfsFileSetSize(RTVFSFILE hVfsFile, uint64_t cbSize, uint32_t fFlags); + +/** @name RTVFSFILE_SIZE_F_XXX - RTVfsFileSetSize flags. + * @{ */ +/** Normal truncate or grow (zero'ed) like RTFileSetSize . */ +#define RTVFSFILE_SIZE_F_NORMAL UINT32_C(0x00000001) +/** Only grow the file, ignore call if cbSize would truncate the file. + * This is what RTFileSetAllocationSize does by default. */ +#define RTVFSFILE_SIZE_F_GROW UINT32_C(0x00000002) +/** Only grow the file, ignore call if cbSize would truncate the file. + * This is what RTFileSetAllocationSize does by default. */ +#define RTVFSFILE_SIZE_F_GROW_KEEP_SIZE UINT32_C(0x00000003) +/** Action mask. */ +#define RTVFSFILE_SIZE_F_ACTION_MASK UINT32_C(0x00000003) +/** Validate the flags. + * Will reference @a a_fFlags more than once. */ +#define RTVFSFILE_SIZE_F_IS_VALID(a_fFlags) \ + ( !((a_fFlags) & ~RTVFSFILE_SIZE_F_ACTION_MASK) && ((a_fFlags) & RTVFSFILE_SIZE_F_ACTION_MASK) != 0 ) +/** Mask of valid flags. */ +#define RTFILE_ALLOC_SIZE_F_VALID (RTFILE_ALLOC_SIZE_F_KEEP_SIZE) +/** @} */ + + +RTDECL(int) RTVfsFileQuerySize(RTVFSFILE hVfsFile, uint64_t *pcbSize); +RTDECL(RTFOFF) RTVfsFileGetMaxSize(RTVFSFILE hVfsFile); +RTDECL(int) RTVfsFileQueryMaxSize(RTVFSFILE hVfsFile, uint64_t *pcbMax); + +/** + * Get the RTFILE_O_XXX flags for the I/O stream. + * + * @returns RTFILE_O_XXX, 0 on failure. + * @param hVfsFile The VFS file handle. + */ +RTDECL(uint64_t) RTVfsFileGetOpenFlags(RTVFSFILE hVfsFile); + +/** + * Printf-like write function. + * + * @returns Number of characters written on success, negative error status on + * failure. + * @param hVfsFile The VFS file handle to write to. + * @param pszFormat The format string. + * @param ... Format arguments. + */ +RTDECL(ssize_t) RTVfsFilePrintf(RTVFSFILE hVfsFile, const char *pszFormat, ...); + +/** + * Printf-like write function. + * + * @returns Number of characters written on success, negative error status on + * failure. + * @param hVfsFile The VFS file handle to write to. + * @param pszFormat The format string. + * @param va Format arguments. + */ +RTDECL(ssize_t) RTVfsFilePrintfV(RTVFSFILE hVfsFile, const char *pszFormat, va_list va); + +/** @} */ + + +#ifdef DEBUG +# undef RTVfsRetain +# define RTVfsRetain(hVfs) RTVfsRetainDebug(hVfs, RT_SRC_POS) +# undef RTVfsObjRetain +# define RTVfsObjRetain(hVfsObj) RTVfsObjRetainDebug(hVfsObj, RT_SRC_POS) +# undef RTVfsDirRetain +# define RTVfsDirRetain(hVfsDir) RTVfsDirRetainDebug(hVfsDir, RT_SRC_POS) +# undef RTVfsFileRetain +# define RTVfsFileRetain(hVfsFile) RTVfsFileRetainDebug(hVfsFile, RT_SRC_POS) +# undef RTVfsIoStrmRetain +# define RTVfsIoStrmRetain(hVfsIos) RTVfsIoStrmRetainDebug(hVfsIos, RT_SRC_POS) +# undef RTVfsFsStrmRetain +# define RTVfsFsStrmRetain(hVfsFss) RTVfsFsStrmRetainDebug(hVfsFss, RT_SRC_POS) +#endif + + + +/** @defgroup grp_rt_vfs_misc VFS Miscellaneous + * @{ + */ + +/** + * Memorizes the I/O stream as a file backed by memory. + * + * @returns IPRT status code. + * + * @param hVfsIos The VFS I/O stream to memorize. This will be read + * to the end on success, on failure its position is + * undefined. + * @param fFlags A combination of RTFILE_O_READ and RTFILE_O_WRITE. + * @param phVfsFile Where to return the handle to the memory file on + * success. + */ +RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile); + +/** + * Creates a VFS file from a memory buffer. + * + * @returns IPRT status code. + * + * @param fFlags A combination of RTFILE_O_READ and RTFILE_O_WRITE. + * @param pvBuf The buffer. This will be copied and not referenced + * after this function returns. + * @param cbBuf The buffer size. + * @param phVfsFile Where to return the handle to the memory file on + * success. + */ +RTDECL(int) RTVfsFileFromBuffer(uint32_t fFlags, void const *pvBuf, size_t cbBuf, PRTVFSFILE phVfsFile); + +/** + * Creates a memory backed VFS file object for read and write. + * + * @returns IPRT status code. + * + * @param hVfsIos The VFS I/O stream to memorize. This will be read + * to the end on success, on failure its position is + * undefined. + * @param cbEstimate The estimated file size. + * @param phVfsFile Where to return the handle to the memory file on + * success. + * @sa RTVfsMemIoStrmCreate + */ +RTDECL(int) RTVfsMemFileCreate(RTVFSIOSTREAM hVfsIos, size_t cbEstimate, PRTVFSFILE phVfsFile); + +/** + * Creates a memory backed VFS file object for read and write. + * + * @returns IPRT status code. + * + * @param hVfsIos The VFS I/O stream to memorize. This will be read + * to the end on success, on failure its position is + * undefined. + * @param cbEstimate The estimated file size. + * @param phVfsIos Where to return the handle to the memory I/O stream + * on success. + * @sa RTVfsMemFileCreate + */ +RTDECL(int) RTVfsMemIoStrmCreate(RTVFSIOSTREAM hVfsIos, size_t cbEstimate, PRTVFSIOSTREAM phVfsIos); + +/** + * Pumps data from one I/O stream to another. + * + * The data is read in chunks from @a hVfsIosSrc and written to @a hVfsIosDst + * until @a hVfsIosSrc indicates end of stream. + * + * @returns IPRT status code + * + * @param hVfsIosSrc The input stream. + * @param hVfsIosDst The output stream. + * @param cbBufHint Hints at a good temporary buffer size, pass 0 if + * clueless. + */ +RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint); + + +/** + * Creates a progress wrapper for an I/O stream. + * + * @returns IRPT status code. + * @param hVfsIos The I/O stream to wrap. + * @param pfnProgress The progress callback. The return code is + * ignored by default, see + * RTVFSPROGRESS_F_CANCELABLE. + * @param pvUser The user argument to @a pfnProgress. + * @param fFlags RTVFSPROGRESS_F_XXX + * @param cbExpectedRead The expected number of bytes read. + * @param cbExpectedWritten The execpted number of bytes written. + * @param phVfsIos Where to return the I/O stream handle. + */ +RTDECL(int) RTVfsCreateProgressForIoStream(RTVFSIOSTREAM hVfsIos, PFNRTPROGRESS pfnProgress, void *pvUser, uint32_t fFlags, + uint64_t cbExpectedRead, uint64_t cbExpectedWritten, PRTVFSIOSTREAM phVfsIos); + +/** + * Creates a progress wrapper for a file stream. + * + * @returns IRPT status code. + * @param hVfsFile The file to wrap. + * @param pfnProgress The progress callback. The return code is + * ignored by default, see + * RTVFSPROGRESS_F_CANCELABLE. + * @param pvUser The user argument to @a pfnProgress. + * @param fFlags RTVFSPROGRESS_F_XXX + * @param cbExpectedRead The expected number of bytes read. + * @param cbExpectedWritten The execpted number of bytes written. + * @param phVfsFile Where to return the file handle. + */ +RTDECL(int) RTVfsCreateProgressForFile(RTVFSFILE hVfsFile, PFNRTPROGRESS pfnProgress, void *pvUser, uint32_t fFlags, + uint64_t cbExpectedRead, uint64_t cbExpectedWritten, PRTVFSFILE phVfsFile); + +/** @name RTVFSPROGRESS_F_XXX - Flags for RTVfsCreateProcessForIoStream and + * RTVfsCreateProcessForFile. + * @{ */ +/** Cancel if the callback returns a failure status code. + * This isn't default behavior because the cancelation is delayed one I/O + * operation in most cases and it's uncertain how the VFS user will handle the + * cancellation status code. */ +#define RTVFSPROGRESS_F_CANCELABLE RT_BIT_32(0) +/** Account forward seeks as reads. */ +#define RTVFSPROGRESS_F_FORWARD_SEEK_AS_READ RT_BIT_32(1) +/** Account fprward seeks as writes. */ +#define RTVFSPROGRESS_F_FORWARD_SEEK_AS_WRITE RT_BIT_32(2) +/** Valid bits. */ +#define RTVFSPROGRESS_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * Create an I/O stream instance performing simple sequential read-ahead. + * + * @returns IPRT status code. + * @param hVfsIos The input stream to perform read ahead on. If this is + * actually for a file object, the returned I/O stream + * handle can also be cast to a file handle. + * @param fFlags Flags reserved for future use, MBZ. + * @param cBuffers How many read ahead buffers to use. Specify 0 for + * default value. + * @param cbBuffer The size of each read ahead buffer. Specify 0 for + * default value. + * @param phVfsIos Where to return the read ahead I/O stream handle. + * + * @remarks Careful using this on a message pipe or socket. The reads are + * performed in blocked mode and it may be host and/or implementation + * dependent whether they will return ready data immediate or wait + * until there's a whole @a cbBuffer (or default) worth ready. + * + * @sa RTVfsCreateReadAheadForFile + */ +RTDECL(int) RTVfsCreateReadAheadForIoStream(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, uint32_t cBuffers, uint32_t cbBuffer, + PRTVFSIOSTREAM phVfsIos); + +/** + * Create an I/O stream instance performing simple sequential read-ahead. + * + * @returns IPRT status code. + * @param hVfsFile The input file to perform read ahead on. + * @param fFlags Flags reserved for future use, MBZ. + * @param cBuffers How many read ahead buffers to use. Specify 0 for + * default value. + * @param cbBuffer The size of each read ahead buffer. Specify 0 for + * default value. + * @param phVfsFile Where to return the read ahead file handle. + * @sa RTVfsCreateReadAheadForIoStream + */ +RTDECL(int) RTVfsCreateReadAheadForFile(RTVFSFILE hVfsFile, uint32_t fFlags, uint32_t cBuffers, uint32_t cbBuffer, + PRTVFSFILE phVfsFile); + + +/** + * Create a file system stream for writing to a directory. + * + * This is just supposed to be a drop in replacement for the TAR creator stream + * that instead puts the files and stuff in a directory instead of a TAR + * archive. In addition, it has an undo feature for simplying cleaning up after + * a botched run + * + * @returns IPRT status code. + * @param hVfsBaseDir The base directory. + * @param fFlags RTVFSFSS2DIR_F_XXX + * @param phVfsFss Where to return the FSS handle. + * @sa RTVfsFsStrmToNormalDir, RTVfsFsStrmToDirUndo + */ +RTDECL(int) RTVfsFsStrmToDir(RTVFSDIR hVfsBaseDir, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** + * Create a file system stream for writing to a normal directory. + * + * This is just supposed to be a drop in replacement for the TAR creator stream + * that instead puts the files and stuff in a directory instead of a TAR + * archive. In addition, it has an undo feature for simplying cleaning up after + * a botched run + * + * @returns IPRT status code. + * @param pszBaseDir The base directory. Must exist. + * @param fFlags RTVFSFSS2DIR_F_XXX + * @param phVfsFss Where to return the FSS handle. + * @sa RTVfsFsStrmToDir, RTVfsFsStrmToDirUndo + */ +RTDECL(int) RTVfsFsStrmToNormalDir(const char *pszBaseDir, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** @name RTVFSFSS2DIR_F_XXX - Flags for RTVfsFsStrmToNormalDir + * @{ */ +/** Overwrite existing files (default is to not overwrite anything). */ +#define RTVFSFSS2DIR_F_OVERWRITE_FILES RT_BIT_32(0) +/** Valid bits. */ +#define RTVFSFSS2DIR_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Deletes files, directories, symlinks and stuff created by a FSS returned by + * RTVfsFsStrmToNormalDir or RTVfsFsStrmToDir. + * + * @returns IPRT status code. + * @param hVfsFss The write-to-directory FSS handle. + */ +RTDECL(int) RTVfsFsStrmToDirUndo(RTVFSFSSTREAM hVfsFss); + + + +/** @} */ + + +/** @defgroup grp_rt_vfs_chain VFS Chains + * + * VFS chains is for doing pipe like things with VFS objects from the command + * line. Imagine you want to cat the readme.gz of an ISO you could do + * something like: + * RTCat :iprtvfs:file(stdfile,live.iso)|vfs(isofs)|iso(open,readme.gz)|ios(gunzip) + * or + * RTCat :iprtvfs:file(stdfile,live.iso)|ios(isofs,readme.gz)|ios(gunzip) + * + * Or say you want to read the README.TXT on a floppy image: + * RTCat :iprtvfs:file(stdfile,floppy.img,r)|vfs(fat)|ios(open,README.TXT) + * or + * RTCat :iprtvfs:file(stdfile,floppy.img,r)|vfs(fat)|README.TXT + * + * Or in the other direction, you want to write a STUFF.TGZ file to the above + * floppy image, using a lazy writer thread for compressing the data: + * RTTar cf :iprtvfs:file(stdfile,floppy.img,rw)|ios(fat,STUFF.TGZ)|ios(gzip)|ios(push) . + * + * + * A bit more formally: + * :iprtvfs:{type}({provider}[,provider-args])[{separator}{type}...][{separator}{path}] + * + * The @c type refers to VFS object that should be created by the @c provider. + * Valid types: + * - vfs: A virtual file system (volume). + * - fss: A file system stream (e.g. tar). + * - ios: An I/O stream. + * - file: A file. + * - dir: A directory. + * - sym: A symbolic link (not sure how useful this is). + * + * The @c provider refers to registered chain element providers (see + * RTVFSCHAINELEMENTREG for how that works internally). These are asked to + * create a VFS object of the specified type using the given arguments (if any). + * Default providers: + * - std: Standard file, directory and file system. + * - open: Opens a file, I/O stream or directory in a vfs or directory object. + * - pull: Read-ahead buffering thread on file or I/O stream. + * - push: Lazy-writer buffering thread on file or I/O stream. + * - gzip: Compresses an I/O stream. + * - gunzip: Decompresses an I/O stream. + * - fat: FAT file system accessor. + * - isofs: ISOFS file system accessor. + * + * As element @c separator we allow both colon (':') and the pipe character + * ('|'). The latter the conventional one, but since it's inconvenient on the + * command line, colon is provided as an alternative. + * + * In the final element we allow a simple @a path to be specified instead of the + * type-provider-arguments stuff. The previous object must be a directory, file + * system or file system stream. The application will determin exactly which + * operation or operations which will be performed. + * + * @{ + */ + +/** The path prefix used to identify an VFS chain specification. */ +#define RTVFSCHAIN_SPEC_PREFIX ":iprtvfs:" + +RTDECL(int) RTVfsChainOpenVfs(const char *pszSpec, PRTVFS phVfs, uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenFsStream(const char *pszSpec, PRTVFSFSSTREAM phVfsFss, uint32_t *poffError, PRTERRINFO pErrInfo); + +/** + * Opens any kind of file system object. + * + * @returns IPRT status code. + * @param pszSpec The VFS chain specification or plain path. + * @param fFileOpen RTFILE_O_XXX flags. + * @param fObjFlags More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX. + * @param phVfsObj Where to return the handle to the opened object. + * @param poffError Where to on error return an offset into @a pszSpec + * of what cause the error. Optional. + * @param pErrInfo Where to return additional error information. + * Optional. + */ +RTDECL(int) RTVfsChainOpenObj(const char *pszSpec, uint64_t fFileOpen, uint32_t fObjFlags, + PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo); + +RTDECL(int) RTVfsChainOpenDir(const char *pszSpec, uint32_t fOpen, PRTVFSDIR phVfsDir, uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenParentDir(const char *pszSpec, uint32_t fOpen, PRTVFSDIR phVfsDir, const char **ppszChild, + uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenFile(const char *pszSpec, uint64_t fOpen, PRTVFSFILE phVfsFile, uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenIoStream(const char *pszSpec, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos, uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenSymlink(const char *pszSpec, PRTVFSSYMLINK phVfsSym, uint32_t *poffError, PRTERRINFO pErrInfo); + +RTDECL(int) RTVfsChainQueryInfo(const char *pszSpec, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, + uint32_t fFlags, uint32_t *poffError, PRTERRINFO pErrInfo); + +/** + * Tests if the given string is a chain specification or not. + * + * @returns true if it is, false if it isn't. + * @param pszSpec The alleged chain spec. + */ +RTDECL(bool) RTVfsChainIsSpec(const char *pszSpec); + +/** + * Queries the path from the final element. + * + * @returns IPRT status code. + * @retval VERR_VFS_CHAIN_NOT_PATH_ONLY if the final element isn't just a + * simple path. + * @param pszSpec The chain spec. + * @param ppszFinalPath Where to return a copy of the final path on success. + * Call RTStrFree when done. + * @param poffError Where to on error return an offset into @a pszSpec + * of what cause the error. Optional. + * + */ +RTDECL(int) RTVfsChainQueryFinalPath(const char *pszSpec, char **ppszFinalPath, uint32_t *poffError); + +/** + * Splits the given chain spec into a final path and the preceeding spec. + * + * This works on plain paths too. + * + * @returns IPRT status code. + * @param pszSpec The chain spec to split. This will be modified! + * @param ppszSpec Where to return the pointer to the chain spec part. + * This is set to NULL if it's a plain path or a chain + * spec with only a final-path element. + * @param ppszFinalPath Where to return the pointer to the final path. This + * is set to NULL if no final path. + * @param poffError Where to on error return an offset into @a pszSpec + * of what cause the error. Optional. + */ +RTDECL(int) RTVfsChainSplitOffFinalPath(char *pszSpec, char **ppszSpec, char **ppszFinalPath, uint32_t *poffError); + +/** + * Common code for reporting errors of a RTVfsChainOpen* API. + * + * @param pszFunction The API called. + * @param pszSpec The VFS chain specification or file path passed to the. + * @param rc The return code. + * @param offError The error offset value returned (0 if not captured). + * @param pErrInfo Additional error information. Optional. + * + * @sa RTVfsChainMsgErrorExitFailure + * @sa RTVfsChainOpenVfs, RTVfsChainOpenFsStream, RTVfsChainOpenDir, + * RTVfsChainOpenFile, RTVfsChainOpenIoStream, RTVfsChainOpenSymlink + */ +RTDECL(void) RTVfsChainMsgError(const char *pszFunction, const char *pszSpec, int rc, uint32_t offError, PRTERRINFO pErrInfo); + +/** + * Common code for reporting errors of a RTVfsChainOpen* API. + * + * @returns RTEXITCODE_FAILURE + * + * @param pszFunction The API called. + * @param pszSpec The VFS chain specification or file path passed to the. + * @param rc The return code. + * @param offError The error offset value returned (0 if not captured). + * @param pErrInfo Additional error information. Optional. + * + * @sa RTVfsChainMsgError + * @sa RTVfsChainOpenVfs, RTVfsChainOpenFsStream, RTVfsChainOpenDir, + * RTVfsChainOpenFile, RTVfsChainOpenIoStream, RTVfsChainOpenSymlink + */ +RTDECL(RTEXITCODE) RTVfsChainMsgErrorExitFailure(const char *pszFunction, const char *pszSpec, + int rc, uint32_t offError, PRTERRINFO pErrInfo); + + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_vfs_h */ + diff --git a/include/iprt/vfslowlevel.h b/include/iprt/vfslowlevel.h new file mode 100644 index 00000000..aba442ca --- /dev/null +++ b/include/iprt/vfslowlevel.h @@ -0,0 +1,1588 @@ +/** @file + * IPRT - Virtual Filesystem. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_vfslowlevel_h +#define IPRT_INCLUDED_vfslowlevel_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_vfs_lowlevel RTVfs - Low-level Interface. + * @ingroup grp_rt_vfs + * @{ + */ + + +/** @name VFS Lock Abstraction + * @todo This should be moved somewhere else as it is of general use. + * @{ */ + +/** + * VFS lock types. + */ +typedef enum RTVFSLOCKTYPE +{ + /** Invalid lock type. */ + RTVFSLOCKTYPE_INVALID = 0, + /** Read write semaphore. */ + RTVFSLOCKTYPE_RW, + /** Fast mutex semaphore (critical section in ring-3). */ + RTVFSLOCKTYPE_FASTMUTEX, + /** Full fledged mutex semaphore. */ + RTVFSLOCKTYPE_MUTEX, + /** The end of valid lock types. */ + RTVFSLOCKTYPE_END, + /** The customary 32-bit type hack. */ + RTVFSLOCKTYPE_32BIT_HACK = 0x7fffffff +} RTVFSLOCKTYPE; + +/** VFS lock handle. */ +typedef struct RTVFSLOCKINTERNAL *RTVFSLOCK; +/** Pointer to a VFS lock handle. */ +typedef RTVFSLOCK *PRTVFSLOCK; +/** Nil VFS lock handle. */ +#define NIL_RTVFSLOCK ((RTVFSLOCK)~(uintptr_t)0) + +/** Special handle value for creating a new read/write semaphore based lock. */ +#define RTVFSLOCK_CREATE_RW ((RTVFSLOCK)~(uintptr_t)1) +/** Special handle value for creating a new fast mutex semaphore based lock. */ +#define RTVFSLOCK_CREATE_FASTMUTEX ((RTVFSLOCK)~(uintptr_t)2) +/** Special handle value for creating a new mutex semaphore based lock. */ +#define RTVFSLOCK_CREATE_MUTEX ((RTVFSLOCK)~(uintptr_t)3) + +/** + * Retains a reference to the VFS lock handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hLock The VFS lock handle. + */ +RTDECL(uint32_t) RTVfsLockRetain(RTVFSLOCK hLock); + +/** + * Releases a reference to the VFS lock handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hLock The VFS lock handle. + */ +RTDECL(uint32_t) RTVfsLockRelease(RTVFSLOCK hLock); + +/** + * Gets the lock type. + * + * @returns The lock type on success, RTVFSLOCKTYPE_INVALID if the handle is + * not valid. + * @param hLock The lock handle. + */ +RTDECL(RTVFSLOCKTYPE) RTVfsLockGetType(RTVFSLOCK hLock); + + + +RTDECL(void) RTVfsLockAcquireReadSlow(RTVFSLOCK hLock); +RTDECL(void) RTVfsLockReleaseReadSlow(RTVFSLOCK hLock); +RTDECL(void) RTVfsLockAcquireWriteSlow(RTVFSLOCK hLock); +RTDECL(void) RTVfsLockReleaseWriteSlow(RTVFSLOCK hLock); + +/** + * Acquire a read lock. + * + * @param hLock The lock handle, can be NIL. + */ +DECLINLINE(void) RTVfsLockAcquireRead(RTVFSLOCK hLock) +{ + if (hLock != NIL_RTVFSLOCK) + RTVfsLockAcquireReadSlow(hLock); +} + + +/** + * Release a read lock. + * + * @param hLock The lock handle, can be NIL. + */ +DECLINLINE(void) RTVfsLockReleaseRead(RTVFSLOCK hLock) +{ + if (hLock != NIL_RTVFSLOCK) + RTVfsLockReleaseReadSlow(hLock); +} + + +/** + * Acquire a write lock. + * + * @param hLock The lock handle, can be NIL. + */ +DECLINLINE(void) RTVfsLockAcquireWrite(RTVFSLOCK hLock) +{ + if (hLock != NIL_RTVFSLOCK) + RTVfsLockAcquireWriteSlow(hLock); +} + + +/** + * Release a write lock. + * + * @param hLock The lock handle, can be NIL. + */ +DECLINLINE(void) RTVfsLockReleaseWrite(RTVFSLOCK hLock) +{ + if (hLock != NIL_RTVFSLOCK) + RTVfsLockReleaseWriteSlow(hLock); +} + +/** @} */ + +/** + * Info queried via RTVFSOBJOPS::pfnQueryInfoEx, ++. + */ +typedef enum RTVFSQIEX +{ + /** Invalid zero value. */ + RTVFSQIEX_INVALID = 0, + /** Volume label. + * Returns a UTF-8 string. */ + RTVFSQIEX_VOL_LABEL, + /** Alternative volume label, the primary one for ISOs, otherwise treated same + * as RTVFSQIEX_VOL_LABEL. */ + RTVFSQIEX_VOL_LABEL_ALT, + /** Volume serial number. + * Returns a uint32_t, uint64_t or RTUUID. */ + RTVFSQIEX_VOL_SERIAL, + /** End of valid queries. */ + RTVFSQIEX_END, + + /** The usual 32-bit hack. */ + RTVFSQIEX_32BIT_SIZE_HACK = 0x7fffffff +} RTVFSQIEX; + + +/** + * The basis for all virtual file system objects. + */ +typedef struct RTVFSOBJOPS +{ + /** The structure version (RTVFSOBJOPS_VERSION). */ + uint32_t uVersion; + /** The object type for type introspection. */ + RTVFSOBJTYPE enmType; + /** The name of the operations. */ + const char *pszName; + + /** + * Close the object. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + */ + DECLCALLBACKMEMBER(int, pfnClose,(void *pvThis)); + + /** + * Get information about the file. + * + * @returns IPRT status code. See RTVfsObjQueryInfo. + * @retval VERR_WRONG_TYPE if file system or file system stream. + * + * @param pvThis The implementation specific file data. + * @param pObjInfo Where to return the object info on success. + * @param enmAddAttr Which set of additional attributes to request. + * @sa RTVfsObjQueryInfo, RTFileQueryInfo, RTPathQueryInfo + */ + DECLCALLBACKMEMBER(int, pfnQueryInfo,(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)); + + /** + * Query arbritray information about the file, volume, or whatever. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW sets pcbRet. + * + * @param pvThis The implementation specific file data. + * @param enmInfo The information being queried. + * @param pvInfo Where to return the info. + * @param cbInfo The size of the @a pvInfo buffer. + * @param pcbRet The size of the returned data. In case of + * VERR_BUFFER_OVERFLOW this will be set to the required + * buffer size. + */ + DECLCALLBACKMEMBER(int, pfnQueryInfoEx,(void *pvThis, RTVFSQIEX enmInfo, void *pvInfo, size_t cbInfo, size_t *pcbRet)); + + /** Marks the end of the structure (RTVFSOBJOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSOBJOPS; +/** Pointer to constant VFS object operations. */ +typedef RTVFSOBJOPS const *PCRTVFSOBJOPS; + +/** The RTVFSOBJOPS structure version. */ +#define RTVFSOBJOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x1f,2,0) + + +/** + * The VFS operations. + */ +typedef struct RTVFSOPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSOPS_VERSION). */ + uint32_t uVersion; + /** The virtual file system feature mask. */ + uint32_t fFeatures; + + /** + * Opens the root directory. + * + * @returns IPRT status code. + * @param pvThis The implementation specific data. + * @param phVfsDir Where to return the handle to the root directory. + */ + DECLCALLBACKMEMBER(int, pfnOpenRoot,(void *pvThis, PRTVFSDIR phVfsDir)); + + /** + * Query the status of the given storage range (optional). + * + * This can be used by the image compaction utilites to evict non-zero blocks + * that aren't currently being used by the file system. + * + * @returns IPRT status code. + * @param pvThis The implementation specific data. + * @param off Start offset to check. + * @param cb Number of bytes to check. + * @param pfUsed Where to store whether the given range is in use. + */ + DECLCALLBACKMEMBER(int, pfnQueryRangeState,(void *pvThis, uint64_t off, size_t cb, bool *pfUsed)); + + /** @todo There will be more methods here to optimize opening and + * querying. */ + +#if 0 + /** + * Optional entry point for optimizing path traversal within the file system. + * + * @returns IPRT status code. + * @param pvThis The implementation specific data. + * @param pszPath The path to resolve. + * @param poffPath The current path offset on input, what we've + * traversed to on successful return. + * @param phVfs??? Return handle to what we've traversed. + * @param p??? Return other stuff... + */ + DECLCALLBACKMEMBER(int, pfnTraverse,(void *pvThis, const char *pszPath, size_t *poffPath, PRTVFS??? phVfs?, ???* p???)); +#endif + + /** @todo need rename API */ + + /** Marks the end of the structure (RTVFSOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSOPS; +/** Pointer to constant VFS operations. */ +typedef RTVFSOPS const *PCRTVFSOPS; + +/** The RTVFSOPS structure version. */ +#define RTVFSOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x0f,1,0) + +/** @name RTVFSOPS::fFeatures + * @{ */ +/** The VFS supports attaching other systems. */ +#define RTVFSOPS_FEAT_ATTACH RT_BIT_32(0) +/** @} */ + +/** + * Creates a new VFS handle. + * + * @returns IPRT status code + * @param pVfsOps The VFS operations. + * @param cbInstance The size of the instance data. + * @param hVfs The VFS handle to associate this VFS with. + * NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfs Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNew(PCRTVFSOPS pVfsOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFS phVfs, void **ppvInstance); + + +/** + * Creates a new VFS base object handle. + * + * @returns IPRT status code + * @param pObjOps The base object operations. + * @param cbInstance The size of the instance data. + * @param hVfs The VFS handle to associate this base object + * with. NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsObj Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewBaseObj(PCRTVFSOBJOPS pObjOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSOBJ phVfsObj, void **ppvInstance); + + +/** + * Gets the private data of a base object. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsObj The I/O base object handle. + * @param pObjOps The base object operations. This servers as a + * sort of password. + */ +RTDECL(void *) RTVfsObjToPrivate(RTVFSOBJ hVfsObj, PCRTVFSOBJOPS pObjOps); + +/** + * Additional operations for setting object attributes. + */ +typedef struct RTVFSOBJSETOPS +{ + /** The structure version (RTVFSOBJSETOPS_VERSION). */ + uint32_t uVersion; + /** The offset back to the RTVFSOBJOPS structure. */ + uint32_t offObjOps; + + /** + * Set the unix style owner and group. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param fMode The new mode bits. + * @param fMask The mask indicating which bits we are + * changing. + * @note Optional, failing with VERR_WRITE_PROTECT if NULL. + * @sa RTFileSetMode + */ + DECLCALLBACKMEMBER(int, pfnSetMode,(void *pvThis, RTFMODE fMode, RTFMODE fMask)); + + /** + * Set the timestamps associated with the object. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param pAccessTime Pointer to the new access time. NULL if not + * to be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if + * not to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not + * to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if + * not to be changed. + * @remarks See RTFileSetTimes for restrictions and behavior imposed by the + * host OS or underlying VFS provider. + * @note Optional, failing with VERR_WRITE_PROTECT if NULL. + * @sa RTFileSetTimes + */ + DECLCALLBACKMEMBER(int, pfnSetTimes,(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)); + + /** + * Set the unix style owner and group. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param uid The user ID of the new owner. NIL_RTUID if + * unchanged. + * @param gid The group ID of the new owner group. NIL_RTGID if + * unchanged. + * @note Optional, failing with VERR_WRITE_PROTECT if NULL. + * @sa RTFileSetOwner + */ + DECLCALLBACKMEMBER(int, pfnSetOwner,(void *pvThis, RTUID uid, RTGID gid)); + + /** Marks the end of the structure (RTVFSOBJSETOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSOBJSETOPS; +/** Pointer to const object attribute setter operations. */ +typedef RTVFSOBJSETOPS const *PCRTVFSOBJSETOPS; + +/** The RTVFSOBJSETOPS structure version. */ +#define RTVFSOBJSETOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x2f,1,0) + + +/** + * The filesystem stream operations. + * + * @extends RTVFSOBJOPS + */ +typedef struct RTVFSFSSTREAMOPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSFSSTREAMOPS_VERSION). */ + uint32_t uVersion; + /** Reserved field, MBZ. */ + uint32_t fReserved; + + /** + * Gets the next object in the stream. + * + * Readable streams only. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if a new object was retrieved. + * @retval VERR_EOF when there are no more objects. + * @param pvThis The implementation specific directory data. + * @param ppszName Where to return the object name. Must be freed by + * calling RTStrFree. + * @param penmType Where to return the object type. + * @param phVfsObj Where to return the object handle (referenced). This + * must be cast to the desired type before use. + * @sa RTVfsFsStrmNext + * + * @note Setting this member to NULL is okay for write-only streams. + */ + DECLCALLBACKMEMBER(int, pfnNext,(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)); + + /** + * Adds another object into the stream. + * + * Writable streams only. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszPath The path to the object. + * @param hVfsObj The object to add. + * @param fFlags Reserved for the future, MBZ. + * @sa RTVfsFsStrmAdd + * + * @note Setting this member to NULL is okay for read-only streams. + */ + DECLCALLBACKMEMBER(int, pfnAdd,(void *pvThis, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags)); + + /** + * Pushes an byte stream onto the stream (optional). + * + * Writable streams only. + * + * This differs from RTVFSFSSTREAMOPS::pfnAdd() in that it will create a regular + * file in the output file system stream and provide the actual content bytes + * via the returned I/O stream object. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszPath The path to the file. + * @param cbFile The file size. This can also be set to UINT64_MAX if + * the file system stream is backed by a file. + * @param paObjInfo Array of zero or more RTFSOBJINFO structures containing + * different pieces of information about the file. If any + * provided, the first one should be a RTFSOBJATTRADD_UNIX + * one, additional can be supplied if wanted. What exactly + * is needed depends on the underlying FS stream + * implementation. + * @param cObjInfo Number of items in the array @a paObjInfo points at. + * @param fFlags RTVFSFSSTRM_PUSH_F_XXX. + * @param phVfsIos Where to return the I/O stream to feed the file content + * to. If the FS stream is backed by a file, the returned + * handle can be cast to a file if necessary. + */ + DECLCALLBACKMEMBER(int, pfnPushFile,(void *pvThis, const char *pszPath, uint64_t cbFile, + PCRTFSOBJINFO paObjInfo, uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)); + + /** + * Marks the end of the stream. + * + * Writable streams only. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @sa RTVfsFsStrmEnd + * + * @note Setting this member to NULL is okay for read-only streams. + */ + DECLCALLBACKMEMBER(int, pfnEnd,(void *pvThis)); + + /** Marks the end of the structure (RTVFSFSSTREAMOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSFSSTREAMOPS; +/** Pointer to const object attribute setter operations. */ +typedef RTVFSFSSTREAMOPS const *PCRTVFSFSSTREAMOPS; + +/** The RTVFSFSSTREAMOPS structure version. */ +#define RTVFSFSSTREAMOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x3f,2,0) + + +/** + * Creates a new VFS filesystem stream handle. + * + * @returns IPRT status code + * @param pFsStreamOps The filesystem stream operations. + * @param cbInstance The size of the instance data. + * @param hVfs The VFS handle to associate this filesystem + * stream with. NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param fAccess RTFILE_O_READ and/or RTFILE_O_WRITE. + * @param phVfsFss Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, uint32_t fAccess, + PRTVFSFSSTREAM phVfsFss, void **ppvInstance); + +/** + * Gets the private data of an filesystem stream. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsFss The FS stream handle. + * @param pFsStreamOps The FS stream operations. This servers as a + * sort of password. + */ +RTDECL(void *) RTVfsFsStreamToPrivate(RTVFSFSSTREAM hVfsFss, PCRTVFSFSSTREAMOPS pFsStreamOps); + + +/** + * The directory operations. + * + * @extends RTVFSOBJOPS + * @extends RTVFSOBJSETOPS + */ +typedef struct RTVFSDIROPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSDIROPS_VERSION). */ + uint32_t uVersion; + /** Reserved field, MBZ. */ + uint32_t fReserved; + /** The object setter operations. */ + RTVFSOBJSETOPS ObjSet; + + /** + * Generic method for opening any kind of file system object. + * + * Can also create files and directories. Symbolic links, devices and such + * needs to be created using special methods or this would end up being way more + * complicated than it already is. + * + * There are optional specializations available. + * + * @returns IPRT status code. + * @retval VERR_PATH_NOT_FOUND or VERR_FILE_NOT_FOUND if @a pszEntry was not + * found. + * @retval VERR_IS_A_FILE if @a pszEntry is a file or similar but @a fFlags + * indicates that the type of object should not be opened. + * @retval VERR_IS_A_DIRECTORY if @a pszEntry is a directory but @a fFlags + * indicates that directories should not be opened. + * @retval VERR_IS_A_SYMLINK if @a pszEntry is a symbolic link but @a fFlags + * indicates that symbolic links should not be opened (or followed). + * @retval VERR_IS_A_FIFO if @a pszEntry is a FIFO but @a fFlags indicates that + * FIFOs should not be opened. + * @retval VERR_IS_A_SOCKET if @a pszEntry is a socket but @a fFlags indicates + * that sockets should not be opened. + * @retval VERR_IS_A_BLOCK_DEVICE if @a pszEntry is a block device but + * @a fFlags indicates that block devices should not be opened, or vice + * versa. + * + * @param pvThis The implementation specific directory data. + * @param pszEntry The name of the immediate file to open or create. + * @param fOpenFile RTFILE_O_XXX combination. + * @param fObjFlags More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX. + * The meaning of RTPATH_F_FOLLOW_LINK differs here, if + * @a pszEntry is a symlink it should be opened for + * traversal rather than according to @a fOpenFile. + * @param phVfsObj Where to return the handle to the opened object. + * @sa RTFileOpen, RTDirOpen + */ + DECLCALLBACKMEMBER(int, pfnOpen,(void *pvThis, const char *pszEntry, uint64_t fOpenFile, + uint32_t fObjFlags, PRTVFSOBJ phVfsObj)); + + /** + * Optional method for symbolic link handling in the vfsstddir.cpp. + * + * This is really just a hack to make symbolic link handling work when working + * with directory objects that doesn't have an associated VFS. It also helps + * deal with drive letters in symbolic links on Windows and OS/2. + * + * @returns IPRT status code. + * @retval VERR_PATH_IS_RELATIVE if @a pszPath isn't absolute and should be + * handled using pfnOpen(). + * + * @param pvThis The implementation specific directory data. + * @param pszRoot Path to the alleged root. + * @param phVfsDir Where to return the handle to the specified root + * directory (or may current dir on a drive letter). + */ + DECLCALLBACKMEMBER(int, pfnFollowAbsoluteSymlink,(void *pvThis, const char *pszRoot, PRTVFSDIR phVfsDir)); + + /** + * Open or create a file. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszFilename The name of the immediate file to open or create. + * @param fOpen The open flags (RTFILE_O_XXX). + * @param phVfsFile Where to return the handle to the opened file. + * @note Optional. RTVFSDIROPS::pfnOpenObj will be used if NULL. + * @sa RTFileOpen. + */ + DECLCALLBACKMEMBER(int, pfnOpenFile,(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)); + + /** + * Open an existing subdirectory. + * + * @returns IPRT status code. + * @retval VERR_IS_A_SYMLINK if @a pszSubDir is a symbolic link. + * @retval VERR_NOT_A_DIRECTORY is okay for symbolic links too. + * + * @param pvThis The implementation specific directory data. + * @param pszSubDir The name of the immediate subdirectory to open. + * @param fFlags RTDIR_F_XXX. + * @param phVfsDir Where to return the handle to the opened directory. + * Optional. + * @note Optional. RTVFSDIROPS::pfnOpenObj will be used if NULL. + * @sa RTDirOpen. + */ + DECLCALLBACKMEMBER(int, pfnOpenDir,(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)); + + /** + * Creates a new subdirectory. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszSubDir The name of the immediate subdirectory to create. + * @param fMode The mode mask of the new directory. + * @param phVfsDir Where to optionally return the handle to the newly + * create directory. + * @note Optional. RTVFSDIROPS::pfnOpenObj will be used if NULL. + * @sa RTDirCreate. + */ + DECLCALLBACKMEMBER(int, pfnCreateDir,(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)); + + /** + * Opens an existing symbolic link. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszSymlink The name of the immediate symbolic link to open. + * @param phVfsSymlink Where to optionally return the handle to the + * newly create symbolic link. + * @note Optional. RTVFSDIROPS::pfnOpenObj will be used if NULL. + * @sa RTSymlinkCreate. + */ + DECLCALLBACKMEMBER(int, pfnOpenSymlink,(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)); + + /** + * Creates a new symbolic link. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszSymlink The name of the immediate symbolic link to create. + * @param pszTarget The symbolic link target. + * @param enmType The symbolic link type. + * @param phVfsSymlink Where to optionally return the handle to the + * newly create symbolic link. + * @sa RTSymlinkCreate. + */ + DECLCALLBACKMEMBER(int, pfnCreateSymlink,(void *pvThis, const char *pszSymlink, const char *pszTarget, + RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)); + + /** + * Query information about an entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszEntry The name of the directory entry to remove. + * @param pObjInfo Where to return the info on success. + * @param enmAddAttr Which set of additional attributes to request. + * @note Optional. RTVFSDIROPS::pfnOpenObj and RTVFSOBJOPS::pfnQueryInfo + * will be used if NULL. + * @sa RTPathQueryInfo, RTVFSOBJOPS::pfnQueryInfo + */ + DECLCALLBACKMEMBER(int, pfnQueryEntryInfo,(void *pvThis, const char *pszEntry, + PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)); + + /** + * Removes a directory entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszEntry The name of the directory entry to remove. + * @param fType If non-zero, this restricts the type of the entry to + * the object type indicated by the mask + * (RTFS_TYPE_XXX). + * @sa RTFileRemove, RTDirRemove, RTSymlinkRemove. + */ + DECLCALLBACKMEMBER(int, pfnUnlinkEntry,(void *pvThis, const char *pszEntry, RTFMODE fType)); + + /** + * Renames a directory entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszEntry The name of the directory entry to rename. + * @param fType If non-zero, this restricts the type of the entry to + * the object type indicated by the mask + * (RTFS_TYPE_XXX). + * @param pszNewName The new entry name. + * @sa RTPathRename + * + * @todo This API is not flexible enough, must be able to rename between + * directories within a file system. + */ + DECLCALLBACKMEMBER(int, pfnRenameEntry,(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)); + + /** + * Rewind the directory stream so that the next read returns the first + * entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + */ + DECLCALLBACKMEMBER(int, pfnRewindDir,(void *pvThis)); + + /** + * Rewind the directory stream so that the next read returns the first + * entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pDirEntry Output buffer. + * @param pcbDirEntry Complicated, see RTDirReadEx. + * @param enmAddAttr Which set of additional attributes to request. + * @sa RTDirReadEx + */ + DECLCALLBACKMEMBER(int, pfnReadDir,(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)); + + /** Marks the end of the structure (RTVFSDIROPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSDIROPS; +/** Pointer to const directory operations. */ +typedef RTVFSDIROPS const *PCRTVFSDIROPS; +/** The RTVFSDIROPS structure version. */ +#define RTVFSDIROPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x4f,1,0) + + +/** + * Creates a new VFS directory handle. + * + * @returns IPRT status code + * @param pDirOps The directory operations. + * @param cbInstance The size of the instance data. + * @param fFlags RTVFSDIR_F_XXX + * @param hVfs The VFS handle to associate this directory with. + * NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsDir Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewDir(PCRTVFSDIROPS pDirOps, size_t cbInstance, uint32_t fFlags, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSDIR phVfsDir, void **ppvInstance); + +/** @name RTVFSDIR_F_XXX + * @{ */ +/** Don't reference the @a hVfs parameter passed to RTVfsNewDir. + * This is a permanent root directory hack. */ +#define RTVFSDIR_F_NO_VFS_REF RT_BIT_32(0) +/** @} */ + +/** + * Gets the private data of a directory. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsDir The directory handle. + * @param pDirOps The directory operations. This servers as a + * sort of password. + */ +RTDECL(void *) RTVfsDirToPrivate(RTVFSDIR hVfsDir, PCRTVFSDIROPS pDirOps); + + +/** + * The symbolic link operations. + * + * @extends RTVFSOBJOPS + * @extends RTVFSOBJSETOPS + */ +typedef struct RTVFSSYMLINKOPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSSYMLINKOPS_VERSION). */ + uint32_t uVersion; + /** Reserved field, MBZ. */ + uint32_t fReserved; + /** The object setter operations. */ + RTVFSOBJSETOPS ObjSet; + + /** + * Read the symbolic link target. + * + * @returns IPRT status code. + * @param pvThis The implementation specific symbolic link data. + * @param pszTarget The target buffer. + * @param cbTarget The size of the target buffer. + * @sa RTSymlinkRead + */ + DECLCALLBACKMEMBER(int, pfnRead,(void *pvThis, char *pszTarget, size_t cbTarget)); + + /** Marks the end of the structure (RTVFSSYMLINKOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSSYMLINKOPS; +/** Pointer to const symbolic link operations. */ +typedef RTVFSSYMLINKOPS const *PCRTVFSSYMLINKOPS; +/** The RTVFSSYMLINKOPS structure version. */ +#define RTVFSSYMLINKOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x5f,1,0) + + +/** + * Creates a new VFS symlink handle. + * + * @returns IPRT status code + * @param pSymlinkOps The symlink operations. + * @param cbInstance The size of the instance data. + * @param hVfs The VFS handle to associate this symlink object + * with. NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsSym Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSSYMLINK phVfsSym, void **ppvInstance); + + +/** + * Gets the private data of a symbolic link. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsSym The symlink handle. + * @param pSymlinkOps The symlink operations. This servers as a sort + * of password. + */ +RTDECL(void *) RTVfsSymlinkToPrivate(RTVFSSYMLINK hVfsSym, PCRTVFSSYMLINKOPS pSymlinkOps); + +/** + * The basis for all I/O objects (files, pipes, sockets, devices, ++). + * + * @extends RTVFSOBJOPS + */ +typedef struct RTVFSIOSTREAMOPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSIOSTREAMOPS_VERSION). */ + uint32_t uVersion; + /** Feature field. */ + uint32_t fFeatures; + + /** + * Reads from the file/stream. + * + * @returns IPRT status code. See RTVfsIoStrmRead. + * @param pvThis The implementation specific file data. + * @param off Where to read at, -1 for the current position. + * @param pSgBuf Gather buffer describing the bytes that are to be + * written. + * @param fBlocking If @c true, the call is blocking, if @c false it + * should not block. + * @param pcbRead Where return the number of bytes actually read. + * This is set it 0 by the caller. If NULL, try read + * all and fail if incomplete. + * @sa RTVfsIoStrmRead, RTVfsIoStrmSgRead, RTVfsFileRead, + * RTVfsFileReadAt, RTFileRead, RTFileReadAt. + */ + DECLCALLBACKMEMBER(int, pfnRead,(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)); + + /** + * Writes to the file/stream. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param off Where to start wrinting, -1 for the current + * position. + * @param pSgBuf Gather buffers describing the bytes that are to be + * written. + * @param fBlocking If @c true, the call is blocking, if @c false it + * should not block. + * @param pcbWritten Where to return the number of bytes actually + * written. This is set it 0 by the caller. If + * NULL, try write it all and fail if incomplete. + * @note Optional, failing with VERR_WRITE_PROTECT if NULL. + * @sa RTFileWrite, RTFileWriteAt. + */ + DECLCALLBACKMEMBER(int, pfnWrite,(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)); + + /** + * Flushes any pending data writes to the stream. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @sa RTFileFlush. + */ + DECLCALLBACKMEMBER(int, pfnFlush,(void *pvThis)); + + /** + * Poll for events. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param fEvents The events to poll for (RTPOLL_EVT_XXX). + * @param cMillies How long to wait for event to eventuate. + * @param fIntr Whether the wait is interruptible and can return + * VERR_INTERRUPTED (@c true) or if this condition + * should be hidden from the caller (@c false). + * @param pfRetEvents Where to return the event mask. + * @note Optional. If NULL, immediately return all requested non-error + * events, waiting for errors works like sleep. + * @sa RTPollSetAdd, RTPoll, RTPollNoResume. + */ + DECLCALLBACKMEMBER(int, pfnPollOne,(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, + uint32_t *pfRetEvents)); + + /** + * Tells the current file/stream position. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param poffActual Where to return the actual offset. + * @sa RTFileTell + */ + DECLCALLBACKMEMBER(int, pfnTell,(void *pvThis, PRTFOFF poffActual)); + + /** + * Skips @a cb ahead in the stream. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param cb The number bytes to skip. + * @remarks This is optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnSkip,(void *pvThis, RTFOFF cb)); + + /** + * Fills the stream with @a cb zeros. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param cb The number of zero bytes to insert. + * @remarks This is optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnZeroFill,(void *pvThis, RTFOFF cb)); + + /** Marks the end of the structure (RTVFSIOSTREAMOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSIOSTREAMOPS; +/** Pointer to const I/O stream operations. */ +typedef RTVFSIOSTREAMOPS const *PCRTVFSIOSTREAMOPS; + +/** The RTVFSIOSTREAMOPS structure version. */ +#define RTVFSIOSTREAMOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x6f,1,0) + +/** @name RTVFSIOSTREAMOPS::fFeatures + * @{ */ +/** No scatter gather lists, thank you. */ +#define RTVFSIOSTREAMOPS_FEAT_NO_SG RT_BIT_32(0) +/** Mask of the valid I/O stream feature flags. */ +#define RTVFSIOSTREAMOPS_FEAT_VALID_MASK UINT32_C(0x00000001) +/** @} */ + + +/** + * Creates a new VFS I/O stream handle. + * + * @returns IPRT status code + * @param pIoStreamOps The I/O stream operations. + * @param cbInstance The size of the instance data. + * @param fOpen The open flags. The minimum is the access mask. + * @param hVfs The VFS handle to associate this I/O stream + * with. NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsIos Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSIOSTREAM phVfsIos, void **ppvInstance); + + +/** + * Gets the private data of an I/O stream. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsIos The I/O stream handle. + * @param pIoStreamOps The I/O stream operations. This servers as a + * sort of password. + */ +RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps); + + +/** + * The file operations. + * + * @extends RTVFSIOSTREAMOPS + * @extends RTVFSOBJSETOPS + */ +typedef struct RTVFSFILEOPS +{ + /** The I/O stream and basis object operations. */ + RTVFSIOSTREAMOPS Stream; + /** The structure version (RTVFSFILEOPS_VERSION). */ + uint32_t uVersion; + /** Reserved field, MBZ. */ + uint32_t fReserved; + /** The object setter operations. */ + RTVFSOBJSETOPS ObjSet; + + /** + * Changes the current file position. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param offSeek The offset to seek. + * @param uMethod The seek method, i.e. what the seek is relative to. + * @param poffActual Where to return the actual offset. + * @sa RTFileSeek + */ + DECLCALLBACKMEMBER(int, pfnSeek,(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)); + + /** + * Get the current file size. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param pcbFile Where to store the current file size. + * @sa RTFileQuerySize + */ + DECLCALLBACKMEMBER(int, pfnQuerySize,(void *pvThis, uint64_t *pcbFile)); + + /** + * Change the file size. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if handle isn't writable. + * @retval VERR_WRITE_PROTECT if read-only file system. + * @retval VERR_FILE_TOO_BIG if cbSize is larger than what the file system can + * theoretically deal with. + * @retval VERR_DISK_FULL if the file system if full. + * @retval VERR_NOT_SUPPORTED if fFlags indicates some operation that's not + * supported by the file system / host operating system. + * + * @param pvThis The implementation specific file data. + * @param pcbFile Where to store the current file size. + * @param fFlags RTVFSFILE_SET_SIZE_F_XXX. + * @note Optional. If NULL, VERR_WRITE_PROTECT will be returned. + * @sa RTFileSetSize, RTFileSetAllocationSize + */ + DECLCALLBACKMEMBER(int, pfnSetSize,(void *pvThis, uint64_t cbFile, uint32_t fFlags)); + + /** + * Determine the maximum file size. + * + * This won't take amount of freespace into account, just the limitations of the + * underlying file system / host operating system. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param pcbMax Where to return the max file size. + * @note Optional. If NULL, VERR_NOT_IMPLEMENTED will be returned. + * @sa RTFileQueryMaxSizeEx + */ + DECLCALLBACKMEMBER(int, pfnQueryMaxSize,(void *pvThis, uint64_t *pcbMax)); + + /** @todo There will be more methods here. */ + + /** Marks the end of the structure (RTVFSFILEOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSFILEOPS; +/** Pointer to const file operations. */ +typedef RTVFSFILEOPS const *PCRTVFSFILEOPS; + +/** The RTVFSFILEOPS structure version. */ +#define RTVFSFILEOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x7f,2,0) + +/** + * Creates a new VFS file handle. + * + * @returns IPRT status code + * @param pFileOps The file operations. + * @param cbInstance The size of the instance data. + * @param fOpen The open flags. The minimum is the access mask. + * @param hVfs The VFS handle to associate this file with. + * NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsFile Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSFILE phVfsFile, void **ppvInstance); + + +/** @defgroup grp_rt_vfs_ll_util VFS Utility APIs + * @{ */ + +/** + * Parsed path. + */ +typedef struct RTVFSPARSEDPATH +{ + /** The length of the path in szCopy. */ + uint16_t cch; + /** The number of path components. */ + uint16_t cComponents; + /** Set if the path ends with slash, indicating that it's a directory + * reference and not a file reference. The slash has been removed from + * the copy. */ + bool fDirSlash; + /** Set if absolute. */ + bool fAbsolute; + /** The offset where each path component starts, i.e. the char after the + * slash. The array has cComponents + 1 entries, where the final one is + * cch + 1 so that one can always terminate the current component by + * szPath[aoffComponent[i] - 1] = '\0'. */ + uint16_t aoffComponents[RTPATH_MAX / 2 + 1]; + /** A normalized copy of the path. + * Reserve some extra space so we can be more relaxed about overflow + * checks and terminator paddings, especially when recursing. */ + char szPath[RTPATH_MAX]; +} RTVFSPARSEDPATH; +/** Pointer to a parsed path. */ +typedef RTVFSPARSEDPATH *PRTVFSPARSEDPATH; + +/** The max accepted path length. + * This must be a few chars shorter than RTVFSPARSEDPATH::szPath because we + * use two terminators and wish be a little bit lazy with checking. */ +#define RTVFSPARSEDPATH_MAX (RTPATH_MAX - 4) + +/** + * Appends @a pszPath (relative) to the already parsed path @a pPath. + * + * @retval VINF_SUCCESS + * @retval VERR_FILENAME_TOO_LONG + * @retval VERR_INTERNAL_ERROR_4 + * @param pPath The parsed path to append @a pszPath onto. + * This is both input and output. + * @param pszPath The path to append. This must be relative. + * @param piRestartComp The component to restart parsing at. This is + * input/output. The input does not have to be + * within the valid range. Optional. + */ +RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp); + +/** + * Parses a path. + * + * @retval VINF_SUCCESS + * @retval VERR_FILENAME_TOO_LONG + * @param pPath Where to store the parsed path. + * @param pszPath The path to parse. Absolute or relative to @a + * pszCwd. + * @param pszCwd The current working directory. Must be + * absolute. + */ +RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd); + +/** + * Same as RTVfsParsePath except that it allocates a temporary buffer. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_TMP_MEMORY + * @retval VERR_FILENAME_TOO_LONG + * @param pszPath The path to parse. Absolute or relative to @a + * pszCwd. + * @param pszCwd The current working directory. Must be + * absolute. + * @param ppPath Where to store the pointer to the allocated + * buffer containing the parsed path. This must + * be freed by calling RTVfsParsePathFree. NULL + * will be stored on failured. + */ +RTDECL(int) RTVfsParsePathA(const char *pszPath, const char *pszCwd, PRTVFSPARSEDPATH *ppPath); + +/** + * Frees a buffer returned by RTVfsParsePathA. + * + * @param pPath The parsed path buffer to free. NULL is fine. + */ +RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath); + +/** + * Dummy implementation of RTVFSIOSTREAMOPS::pfnPollOne. + * + * This handles the case where there is no chance any events my be raised and + * all that is required is to wait according to the parameters. + * + * @returns IPRT status code. + * @param fEvents The events to poll for (RTPOLL_EVT_XXX). + * @param cMillies How long to wait for event to eventuate. + * @param fIntr Whether the wait is interruptible and can return + * VERR_INTERRUPTED (@c true) or if this condition + * should be hidden from the caller (@c false). + * @param pfRetEvents Where to return the event mask. + * @sa RTVFSIOSTREAMOPS::pfnPollOne, RTPollSetAdd, RTPoll, RTPollNoResume. + */ +RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents); + +/** @} */ + + +/** @defgroup grp_rt_vfs_lowlevel_chain VFS Chains (Low Level) + * @ref grp_rt_vfs_chain + * @{ + */ + +/** Pointer to a VFS chain element registration record. */ +typedef struct RTVFSCHAINELEMENTREG *PRTVFSCHAINELEMENTREG; +/** Pointer to a const VFS chain element registration record. */ +typedef struct RTVFSCHAINELEMENTREG const *PCRTVFSCHAINELEMENTREG; + +/** + * VFS chain element argument. + */ +typedef struct RTVFSCHAINELEMENTARG +{ + /** The string argument value. */ + char *psz; + /** The specification offset of this argument. */ + uint16_t offSpec; + /** Provider specific value. */ + uint64_t uProvider; +} RTVFSCHAINELEMENTARG; +/** Pointer to a VFS chain element argument. */ +typedef RTVFSCHAINELEMENTARG *PRTVFSCHAINELEMENTARG; + + +/** + * VFS chain element specification. + */ +typedef struct RTVFSCHAINELEMSPEC +{ + /** The provider name. + * This can be NULL if this is the final component and it's just a path. */ + char *pszProvider; + /** The input type, RTVFSOBJTYPE_INVALID if first. */ + RTVFSOBJTYPE enmTypeIn; + /** The element type. + * RTVFSOBJTYPE_END if this is the final component and it's just a path. */ + RTVFSOBJTYPE enmType; + /** The input spec offset of this element. */ + uint16_t offSpec; + /** The length of the input spec. */ + uint16_t cchSpec; + /** The number of arguments. */ + uint32_t cArgs; + /** Arguments. */ + PRTVFSCHAINELEMENTARG paArgs; + + /** The provider. */ + PCRTVFSCHAINELEMENTREG pProvider; + /** Provider specific value. */ + uint64_t uProvider; + /** The object (with reference). */ + RTVFSOBJ hVfsObj; +} RTVFSCHAINELEMSPEC; +/** Pointer to a chain element specification. */ +typedef RTVFSCHAINELEMSPEC *PRTVFSCHAINELEMSPEC; +/** Pointer to a const chain element specification. */ +typedef RTVFSCHAINELEMSPEC const *PCRTVFSCHAINELEMSPEC; + + +/** + * Parsed VFS chain specification. + */ +typedef struct RTVFSCHAINSPEC +{ + /** Open directory flags (RTFILE_O_XXX). */ + uint64_t fOpenFile; + /** To be defined. */ + uint32_t fOpenDir; + /** The type desired by the caller. */ + RTVFSOBJTYPE enmDesiredType; + /** The number of elements. */ + uint32_t cElements; + /** The elements. */ + PRTVFSCHAINELEMSPEC paElements; +} RTVFSCHAINSPEC; +/** Pointer to a parsed VFS chain specification. */ +typedef RTVFSCHAINSPEC *PRTVFSCHAINSPEC; +/** Pointer to a const, parsed VFS chain specification. */ +typedef RTVFSCHAINSPEC const *PCRTVFSCHAINSPEC; + + +/** + * A chain element provider registration record. + */ +typedef struct RTVFSCHAINELEMENTREG +{ + /** The version (RTVFSCHAINELEMENTREG_VERSION). */ + uint32_t uVersion; + /** Reserved, MBZ. */ + uint32_t fReserved; + /** The provider name (unique). */ + const char *pszName; + /** For chaining the providers. */ + RTLISTNODE ListEntry; + /** Help text. */ + const char *pszHelp; + + /** + * Checks the element specification. + * + * This is allowed to parse arguments and use pSpec->uProvider and + * pElement->paArgs[].uProvider to store information that pfnInstantiate and + * pfnCanReuseElement may use later on, thus avoiding duplicating work/code. + * + * @returns IPRT status code. + * @param pProviderReg Pointer to the element provider registration. + * @param pSpec The chain specification. + * @param pElement The chain element specification to validate. + * @param poffError Where to return error offset on failure. This is + * set to the pElement->offSpec on input, so it only + * needs to be adjusted if an argument is at fault. + * @param pErrInfo Where to return additional error information, if + * available. Optional. + */ + DECLCALLBACKMEMBER(int, pfnValidate,(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec, + PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)); + + /** + * Create a VFS object according to the element specification. + * + * @returns IPRT status code. + * @param pProviderReg Pointer to the element provider registration. + * @param pSpec The chain specification. + * @param pElement The chain element specification to instantiate. + * @param hPrevVfsObj Handle to the previous VFS object, NIL_RTVFSOBJ if + * first. + * @param phVfsObj Where to return the VFS object handle. + * @param poffError Where to return error offset on failure. This is + * set to the pElement->offSpec on input, so it only + * needs to be adjusted if an argument is at fault. + * @param pErrInfo Where to return additional error information, if + * available. Optional. + */ + DECLCALLBACKMEMBER(int, pfnInstantiate,(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec, + PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj, + PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)); + + /** + * Determins whether the element can be reused. + * + * This is for handling situations accessing the same file system twice, like + * for both the source and destiation of a copy operation. This allows not only + * sharing resources and avoid doing things twice, but also helps avoid file + * sharing violations and inconsistencies araising from the image being updated + * and read independently. + * + * @returns true if the element from @a pReuseSpec an be reused, false if not. + * @param pProviderReg Pointer to the element provider registration. + * @param pSpec The chain specification. + * @param pElement The chain element specification. + * @param pReuseSpec The chain specification of the existing chain. + * @param pReuseElement The chain element specification of the existing + * element that is being considered for reuse. + */ + DECLCALLBACKMEMBER(bool, pfnCanReuseElement,(PCRTVFSCHAINELEMENTREG pProviderReg, + PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement, + PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)); + + /** End marker (RTVFSCHAINELEMENTREG_VERSION). */ + uintptr_t uEndMarker; +} RTVFSCHAINELEMENTREG; + +/** The VFS chain element registration record version number. */ +#define RTVFSCHAINELEMENTREG_VERSION RT_MAKE_U32_FROM_U8(0xff, 0x7f, 1, 0) + + +/** + * Parses the specification. + * + * @returns IPRT status code. + * @param pszSpec The specification string to parse. + * @param fFlags Flags, see RTVFSCHAIN_PF_XXX. + * @param enmDesiredType The object type the caller wants to interface with. + * @param ppSpec Where to return the pointer to the parsed + * specification. This must be freed by calling + * RTVfsChainSpecFree. Will always be set (unless + * invalid parameters.) + * @param poffError Where to return the offset into the input + * specification of what's causing trouble. Always + * set, unless this argument causes an invalid pointer + * error. + */ +RTDECL(int) RTVfsChainSpecParse(const char *pszSpec, uint32_t fFlags, RTVFSOBJTYPE enmDesiredType, + PRTVFSCHAINSPEC *ppSpec, uint32_t *poffError); + +/** @name RTVfsChainSpecParse + * @{ */ +/** Mask of valid flags. */ +#define RTVFSCHAIN_PF_VALID_MASK UINT32_C(0x00000000) +/** @} */ + +/** + * Checks and setups the chain. + * + * @returns IPRT status code. + * @param pSpec The parsed specification. + * @param pReuseSpec Spec to reuse if applicable. Optional. + * @param phVfsObj Where to return the VFS object. + * @param ppszFinalPath Where to return the pointer to the final path if + * applicable. The caller needs to check whether this + * is NULL or a path, in the former case nothing more + * needs doing, whereas in the latter the caller must + * perform the desired operation(s) on *phVfsObj using + * the final path. + * @param poffError Where to return the offset into the input + * specification of what's causing trouble. Always + * set, unless this argument causes an invalid pointer + * error. + * @param pErrInfo Where to return additional error information, if + * available. Optional. + */ +RTDECL(int) RTVfsChainSpecCheckAndSetup(PRTVFSCHAINSPEC pSpec, PCRTVFSCHAINSPEC pReuseSpec, + PRTVFSOBJ phVfsObj, const char **ppszFinalPath, uint32_t *poffError, PRTERRINFO pErrInfo); + +/** + * Frees a parsed chain specification. + * + * @param pSpec What RTVfsChainSpecParse returned. NULL is + * quietly ignored. + */ +RTDECL(void) RTVfsChainSpecFree(PRTVFSCHAINSPEC pSpec); + +/** + * Registers a chain element provider. + * + * @returns IPRT status code + * @param pRegRec The registration record. + * @param fFromCtor Indicates where we're called from. + */ +RTDECL(int) RTVfsChainElementRegisterProvider(PRTVFSCHAINELEMENTREG pRegRec, bool fFromCtor); + +/** + * Deregisters a chain element provider. + * + * @returns IPRT status code + * @param pRegRec The registration record. + * @param fFromDtor Indicates where we're called from. + */ +RTDECL(int) RTVfsChainElementDeregisterProvider(PRTVFSCHAINELEMENTREG pRegRec, bool fFromDtor); + + +/** @def RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER + * Automatically registers a chain element provider using a global constructor + * and destructor hack. + * + * @param pRegRec Pointer to the registration record. + * @param name Some unique variable name prefix. + */ + +#ifdef __cplusplus +/** + * Class used for registering a VFS chain element provider. + */ +class RTVfsChainElementAutoRegisterHack +{ +private: + /** The registration record, NULL if registration failed. */ + PRTVFSCHAINELEMENTREG m_pRegRec; + +public: + RTVfsChainElementAutoRegisterHack(PRTVFSCHAINELEMENTREG a_pRegRec) + : m_pRegRec(a_pRegRec) + { + int rc = RTVfsChainElementRegisterProvider(m_pRegRec, true); + if (RT_FAILURE(rc)) + m_pRegRec = NULL; + } + + ~RTVfsChainElementAutoRegisterHack() + { + RTVfsChainElementDeregisterProvider(m_pRegRec, true); + m_pRegRec = NULL; + } +}; + +# define RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(pRegRec, name) \ + static RTVfsChainElementAutoRegisterHack name ## AutoRegistrationHack(pRegRec) + +#else +# define RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(pRegRec, name) \ + extern void *name ## AutoRegistrationHack = \ + &Sorry_but_RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER_does_not_work_in_c_source_files +#endif + + +/** + * Common worker for the 'stdfile' and 'open' providers for implementing + * RTVFSCHAINELEMENTREG::pfnValidate. + * + * Stores the RTFILE_O_XXX flags in pSpec->uProvider. + * + * @returns IPRT status code. + * @param pSpec The chain specification. + * @param pElement The chain element specification to validate. + * @param poffError Where to return error offset on failure. This is set to + * the pElement->offSpec on input, so it only needs to be + * adjusted if an argument is at fault. + * @param pErrInfo Where to return additional error information, if + * available. Optional. + */ +RTDECL(int) RTVfsChainValidateOpenFileOrIoStream(PRTVFSCHAINSPEC pSpec, PRTVFSCHAINELEMSPEC pElement, + uint32_t *poffError, PRTERRINFO pErrInfo); + + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_vfslowlevel_h */ + diff --git a/include/iprt/win/Makefile.kup b/include/iprt/win/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/iprt/win/audioclient.h b/include/iprt/win/audioclient.h new file mode 100644 index 00000000..4fb3fed1 --- /dev/null +++ b/include/iprt/win/audioclient.h @@ -0,0 +1,59 @@ +/** @file + * Safe way to include audioclient.h. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_audioclient_h +#define IPRT_INCLUDED_win_audioclient_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* ks.h(1978): warning C4668: '_WIN64' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' [SDK 7.1] */ +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:4091) /* ksmedia.h(4356): warning C4091: 'typedef ': ignored on left of '' when no variable is declared [SDK 7.1] */ +# endif +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_audioclient_h */ + diff --git a/include/iprt/win/commctrl.h b/include/iprt/win/commctrl.h new file mode 100644 index 00000000..349bac97 --- /dev/null +++ b/include/iprt/win/commctrl.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include commctrl.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_commctrl_h +#define IPRT_INCLUDED_win_commctrl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* commctrl.h(8323): warning C5039: 'DSA_DestroyCallback': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# ifdef __cplusplus +# pragma warning(disable:4668) /* um\prsht.h(130): warning C4668: 'ISOLATION_AWARE_ENABLED' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# endif +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_commctrl_h */ + diff --git a/include/iprt/win/context-amd64.mac b/include/iprt/win/context-amd64.mac new file mode 100644 index 00000000..5a1ec649 --- /dev/null +++ b/include/iprt/win/context-amd64.mac @@ -0,0 +1,118 @@ +;; @file +; IPRT - Windows - AMD64 CPU Context Record for NASM/YASM. +; + +; +; Copyright (C) 2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_win_context_amd64_mac +%define ___iprt_win_context_amd64_mac + +%include "iprt/asmdefs.mac" + +struc CONTEXT + .P1Home resq 1 + .P2Home resq 1 + .P3Home resq 1 + .P4Home resq 1 + .P5Home resq 1 + .P6Home resq 1 + + .ContextFlags resd 1 + .MxCsr resd 1 + + .SegCs resw 1 ; CONTEXT_CONTROL + .SegDs resw 1 + .SegEs resw 1 + .SegFs resw 1 + .SegGs resw 1 + .SegSs resw 1 ; CONTEXT_CONTROL + .EFlags resd 1 ; CONTEXT_CONTROL + + .Dr0 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr1 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr2 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr3 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr6 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr7 resq 1 ; CONTEXT_DEBUG_REGISTERS + + .Rax resq 1 ; CONTEXT_INTEGER + .Rcx resq 1 ; CONTEXT_INTEGER + .Rdx resq 1 ; CONTEXT_INTEGER + .Rbx resq 1 ; CONTEXT_INTEGER + .Rsp resq 1 ; CONTEXT_CONTROL + .Rbp resq 1 ; CONTEXT_INTEGER + .Rsi resq 1 ; CONTEXT_INTEGER + .Rdi resq 1 ; CONTEXT_INTEGER + .R8 resq 1 ; CONTEXT_INTEGER + .R9 resq 1 ; CONTEXT_INTEGER + .R10 resq 1 ; CONTEXT_INTEGER + .R11 resq 1 ; CONTEXT_INTEGER + .R12 resq 1 ; CONTEXT_INTEGER + .R13 resq 1 ; CONTEXT_INTEGER + .R14 resq 1 ; CONTEXT_INTEGER + .R15 resq 1 ; CONTEXT_INTEGER + + .Rip resq 1 ; CONTEXT_CONTROL + + .FltSave resb 512 ; X86FXSTATE - CONTEXT_FLOATING_POINT = Xmm0-Xmm15 + + .VectorRegisters resb (26 * 16) + .VectorControl resq 1 + + .DebugControl resq 1 + .LastBranchToRip resq 1 + .LastBranchFromRip resq 1 + .LastExceptionToRip resq 1 + .LastExceptionFromRip resq 1 +endstruc +%define CONTEXT_SIZE (0x4d0) +AssertCompileSize(CONTEXT, CONTEXT_SIZE) + +%define CONTEXT_AMD64 (0x00100000) +%define CONTEXT_CONTROL (0x00000001 | CONTEXT_AMD64) +%define CONTEXT_INTEGER (0x00000002 | CONTEXT_AMD64) +%define CONTEXT_SEGMENTS (0x00000004 | CONTEXT_AMD64) +%define CONTEXT_FLOATING_POINT (0x00000008 | CONTEXT_AMD64) +%define CONTEXT_DEBUG_REGISTERS (0x00000010 | CONTEXT_AMD64) +%define CONTEXT_FULL (0x0000000b | CONTEXT_AMD64) +%define CONTEXT_ALL (0x0000001f | CONTEXT_AMD64) + +%define CONTEXT_XSTATE (0x00000040 | CONTEXT_AMD64) +%define CONTEXT_KERNEL_CET (0x00000080 | CONTEXT_AMD64) +%define CONTEXT_EXCEPTION_ACTIVE (0x08000000) +%define CONTEXT_SERVICE_ACTIVE (0x10000000) +%define CONTEXT_UNWOUND_TO_CALL (0x20000000) +%define CONTEXT_EXCEPTION_REQUEST (0x40000000) +%define CONTEXT_EXCEPTION_REPORTING (0x80000000) + +%endif + diff --git a/include/iprt/win/context-x86.mac b/include/iprt/win/context-x86.mac new file mode 100644 index 00000000..1f126295 --- /dev/null +++ b/include/iprt/win/context-x86.mac @@ -0,0 +1,101 @@ +;; @file +; IPRT - Windows - X86 CPU Context Record for NASM/YASM. +; + +; +; Copyright (C) 2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_win_context_x86_mac +%define ___iprt_win_context_x86_mac + +%include "iprt/asmdefs.mac" + +struc CONTEXT + .ContextFlags resd 1 + + ; CONTEXT_DEBUG_REGISTERS: + .Dr0 resd 1 + .Dr1 resd 1 + .Dr2 resd 1 + .Dr3 resd 1 + .Dr6 resd 1 + .Dr7 resd 1 + + ; CONTEXT_FLOATING_POINT: + .FloatSave resb 112 ; X86FPUSTATE + 4 bytes + + ; CONTEXT_SEGMENTS: + .SegGs resd 1 + .SegFs resd 1 + .SegEs resd 1 + .SegDs resd 1 + + ; CONTEXT_INTEGER: + .Edi resd 1 + .Esi resd 1 + .Ebx resd 1 + .Edx resd 1 + .Ecx resd 1 + .Eax resd 1 + + ; CONTEXT_CONTROL: + .Ebp resd 1 + .Eip resd 1 + .SegCs resd 1 + .EFlags resd 1 + .Esp resd 1 + .SegSs resd 1 + + ; CONTEXT_EXTENDED_REGISTERS: + .ExtendedRegisters resb 512 +endstruc +%define CONTEXT_SIZE (0x2cc) +AssertCompileSize(CONTEXT, CONTEXT_SIZE) + +%define CONTEXT_i386 (0x00010000) +%define CONTEXT_CONTROL (0x00000001 | CONTEXT_i386) +%define CONTEXT_INTEGER (0x00000002 | CONTEXT_i386) +%define CONTEXT_SEGMENTS (0x00000004 | CONTEXT_i386) +%define CONTEXT_FLOATING_POINT (0x00000008 | CONTEXT_i386) +%define CONTEXT_DEBUG_REGISTERS (0x00000010 | CONTEXT_i386) +%define CONTEXT_EXTENDED_REGISTERS (0x00000020 | CONTEXT_i386) +%define CONTEXT_FULL (0x00000007 | CONTEXT_i386) +%define CONTEXT_ALL (0x0000003f | CONTEXT_i386) + +%define CONTEXT_XSTATE (0x00000040 | CONTEXT_i386) +%define CONTEXT_EXCEPTION_ACTIVE (0x08000000) +%define CONTEXT_SERVICE_ACTIVE (0x10000000) +; 0x20000000 = CONTEXT_UNWOUND_TO_CALL ? +%define CONTEXT_EXCEPTION_REQUEST (0x40000000) +%define CONTEXT_EXCEPTION_REPORTING (0x80000000) + +%endif + diff --git a/include/iprt/win/credentialprovider.h b/include/iprt/win/credentialprovider.h new file mode 100644 index 00000000..2d71cb6f --- /dev/null +++ b/include/iprt/win/credentialprovider.h @@ -0,0 +1,58 @@ +/** @file + * Safe way to include credentialprovider.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_credentialprovider_h +#define IPRT_INCLUDED_win_credentialprovider_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* commctrl.h(8323): warning C5039: 'DSA_DestroyCallback': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_credentialprovider_h */ + diff --git a/include/iprt/win/d3d8.h b/include/iprt/win/d3d8.h new file mode 100644 index 00000000..14f1c4ed --- /dev/null +++ b/include/iprt/win/d3d8.h @@ -0,0 +1,60 @@ +/** @file + * Safe way to include d3d8.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_d3d8_h +#define IPRT_INCLUDED_win_d3d8_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +/*# pragma warning(disable:4163)*/ +# pragma warning(disable:4668) /* warning C4668: 'WHEA_DOWNLEVEL_TYPE_NAMES' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# pragma warning(disable:4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + + +#endif /* !IPRT_INCLUDED_win_d3d8_h */ + diff --git a/include/iprt/win/d3d9.h b/include/iprt/win/d3d9.h new file mode 100644 index 00000000..52c02c53 --- /dev/null +++ b/include/iprt/win/d3d9.h @@ -0,0 +1,68 @@ +/** @file + * Safe way to include d3d9.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_d3d9_h +#define IPRT_INCLUDED_win_d3d9_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* d3d9.h includes windows.h (via objbase.h -> rpc.h), so do it up front using + our wrappers to avoid needing to duplicate warning workarounds for it. */ +#include + +#ifdef _MSC_VER +# pragma warning(push) +/*# pragma warning(disable:4163)*/ +# pragma warning(disable:4668) /* warning C4668: 'WHEA_DOWNLEVEL_TYPE_NAMES' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# pragma warning(disable:4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_d3d9_h */ + diff --git a/include/iprt/win/d3dkmthk.h b/include/iprt/win/d3dkmthk.h new file mode 100644 index 00000000..af8fa34f --- /dev/null +++ b/include/iprt/win/d3dkmthk.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include d3dkmthk.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_d3dkmthk_h +#define IPRT_INCLUDED_win_d3dkmthk_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:4255) /* d3dkmthk.h(2061): warning C4255: 'PFND3DKMT_CHECKEXCLUSIVEOWNERSHIP': no function prototype given: converting '()' to '(void)' */ +# endif +#endif + +/* 10.0.22000.0 SDK: */ +#define DXGKDDI_INTERFACE_VERSION_WDDM_1_3 DXGKDDI_INTERFACE_VERSION_WDDM1_3 +#define DXGKDDI_INTERFACE_VERSION_WDDM_2_0 DXGKDDI_INTERFACE_VERSION_WDDM2_0 +#define DXGKDDI_INTERFACE_VERSION_WDDM1_3_M1 DXGKDDI_INTERFACE_VERSION_WDDM1_3 + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_d3dkmthk_h */ + diff --git a/include/iprt/win/dbghelp.h b/include/iprt/win/dbghelp.h new file mode 100644 index 00000000..00d50b32 --- /dev/null +++ b/include/iprt/win/dbghelp.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include Dbghelp.h. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_dbghelp_h +#define IPRT_INCLUDED_win_dbghelp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the Windows.h file in SDK 7.1 is not clean wrt warning C4091 with VCC140+: + * Dbghelp.h(1540): warning C4091: 'typedef ': ignored on left of '' when no variable is declared + * Dbghelp.h(3056): warning C4091: 'typedef ': ignored on left of '' when no variable is declared + */ +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:4091) +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_dbghelp_h */ + diff --git a/include/iprt/win/dshow.h b/include/iprt/win/dshow.h new file mode 100644 index 00000000..eab1fdce --- /dev/null +++ b/include/iprt/win/dshow.h @@ -0,0 +1,56 @@ +/** @file + * Safe way to include dshow.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_dshow_h +#define IPRT_INCLUDED_win_dshow_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER >= 1920 /*RT_MSC_VER_VC142*/ +# pragma warning(disable:5204) /* strmif.h(16270): warning C5204: 'IAMFilterGraphCallback': class has virtual functions, but its trivial destructor is not virtual; instances of objects derived from this class may not be destructed correctly */ +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_dshow_h */ + diff --git a/include/iprt/win/endpointvolume.h b/include/iprt/win/endpointvolume.h new file mode 100644 index 00000000..ec9cced5 --- /dev/null +++ b/include/iprt/win/endpointvolume.h @@ -0,0 +1,58 @@ +/** @file + * Safe way to include endpointvolume.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_endpointvolume_h +#define IPRT_INCLUDED_win_endpointvolume_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4201) +# pragma warning(disable:4668) /* ks.h(1978): warning C4668: '_WIN64' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' [SDK 7.1] */ +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable: 4091) /* v7.1\include\ksmedia.h(4356): warning C4091: 'typedef ': ignored on left of '' when no variable is declared */ +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_endpointvolume_h */ + diff --git a/include/iprt/win/imagehlp.h b/include/iprt/win/imagehlp.h new file mode 100644 index 00000000..138bdd3b --- /dev/null +++ b/include/iprt/win/imagehlp.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include ImageHlp.h. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_imagehlp_h +#define IPRT_INCLUDED_win_imagehlp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the ImageHlp.h file in SDK 7.1 is not clean wrt warning C4091 with VCC141: + * ImageHlp.h(1869): warning C4091: 'typedef ': ignored on left of '' when no variable is declared + * ImageHlp.h(3385): warning C4091: 'typedef ': ignored on left of '' when no variable is declared + */ +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:4091) +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_imagehlp_h */ + diff --git a/include/iprt/win/intsafe.h b/include/iprt/win/intsafe.h new file mode 100644 index 00000000..182b93de --- /dev/null +++ b/include/iprt/win/intsafe.h @@ -0,0 +1,77 @@ +/** @file + * Safe way to include intsafe.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_intsafe_h +#define IPRT_INCLUDED_win_intsafe_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* There's a conflict between the Visual C++ 2010 stdint.h and wDK 7.1 intsafe.h + that we must to mediate here. Current approach is to use the stuff from + intsafe.h rather than the other. */ +#ifndef _INTSAFE_H_INCLUDED_ +# include +# undef INT8_MIN +# undef INT16_MIN +# undef INT32_MIN +# undef INT8_MAX +# undef INT16_MAX +# undef INT32_MAX +# undef UINT8_MAX +# undef UINT16_MAX +# undef UINT32_MAX +# undef INT64_MIN +# undef INT64_MAX +# undef UINT64_MAX + +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* intsafe.h(55) : warning C4668: '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# endif + +# include + +# ifdef _MSC_VER +# pragma warning(pop) +# endif + +#endif /* !_INTSAFE_H_INCLUDED_ */ + +#endif /* !IPRT_INCLUDED_win_intsafe_h */ + diff --git a/include/iprt/win/iphlpapi.h b/include/iprt/win/iphlpapi.h new file mode 100644 index 00000000..d823e1ac --- /dev/null +++ b/include/iprt/win/iphlpapi.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include iphlpapi.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_iphlpapi_h +#define IPRT_INCLUDED_win_iphlpapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* 'NDIS_SUPPORT_NDIS6' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ + +#include + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_iphlpapi_h */ + diff --git a/include/iprt/win/ks.h b/include/iprt/win/ks.h new file mode 100644 index 00000000..6febf26c --- /dev/null +++ b/include/iprt/win/ks.h @@ -0,0 +1,54 @@ +/** @file + * Safe way to include ks.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ks_h +#define IPRT_INCLUDED_win_ks_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* C4668: '_WIN64' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_ks_h */ + diff --git a/include/iprt/win/lazy-dbghelp.h b/include/iprt/win/lazy-dbghelp.h new file mode 100644 index 00000000..a6924bb1 --- /dev/null +++ b/include/iprt/win/lazy-dbghelp.h @@ -0,0 +1,151 @@ +/** @file + * Symbols from dbghelp.dll, allowing us to select which one to load. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_lazy_dbghelp_h +#define IPRT_INCLUDED_win_lazy_dbghelp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +/** + * Custom loader callback. + * @returns Module handle or NIL_RTLDRMOD. + */ +static int rtLdrLazyLoadDbgHelp(const char *pszFile, PRTLDRMOD phMod) +{ + static const struct + { + const char *pszEnv; + const char *pszSubDir; + } s_aLocations[] = + { +#ifdef RT_ARCH_AMD64 + { "ProgramFiles(x86)", "Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, + { "ProgramFiles(x86)", "Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, + { "ProgramFiles", "Debugging Tools for Windows (x64)\\dbghelp.dll" }, +#else + { "ProgramFiles", "Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, + { "ProgramFiles", "Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, + { "ProgramFiles", "Debugging Tools for Windows (x86)\\dbghelp.dll" }, +#endif /** @todo More places we should look? */ + }; + uint32_t i; + for (i = 0; i < RT_ELEMENTS(s_aLocations); i++) + { + char szPath[RTPATH_MAX]; + size_t cchPath; + int rc = RTEnvGetEx(RTENV_DEFAULT, s_aLocations[i].pszEnv, szPath, sizeof(szPath), &cchPath); + if (RT_SUCCESS(rc)) + { + rc = RTPathAppend(szPath, sizeof(szPath), s_aLocations[i].pszSubDir); + if (RT_SUCCESS(rc)) + { + rc = RTLdrLoad(szPath, phMod); + if (RT_SUCCESS(rc)) + return rc; + } + } + } + + /* Fall back on the system one, if present. */ + return RTLdrLoadSystem(pszFile, true /*fNoUnload*/, phMod); +} + +RTLDRLAZY_MODULE_EX(dbghelp, "dbghelp.dll", rtLdrLazyLoadDbgHelp); + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymInitialize, (HANDLE a1, PCWSTR a2, BOOL a3), (a1, a2, a3), FALSE); +#undef SymInitialize +#define SymInitialize RTLDRLAZY_FUNC_NAME(dbghelp, SymInitialize) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymCleanup, (HANDLE a1), (a1), FALSE); +#undef SymCleanup +#define SymCleanup RTLDRLAZY_FUNC_NAME(dbghelp, SymCleanup) + +RTLDRLAZY_FUNC(dbghelp, DWORD, WINAPI, SymGetOptions, (VOID), (), 0); +#undef SymGetOptions +#define SymGetOptions RTLDRLAZY_FUNC_NAME(dbghelp, SymGetOptions) + +RTLDRLAZY_FUNC(dbghelp, DWORD, WINAPI, SymSetOptions, (DWORD a1), (a1), 0); +#undef SymSetOptions +#define SymSetOptions RTLDRLAZY_FUNC_NAME(dbghelp, SymSetOptions) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymRegisterCallback64, (HANDLE a1, PSYMBOL_REGISTERED_CALLBACK64 a2, ULONG64 a3), + (a1, a2, a3), FALSE); +#undef SymRegisterCallback64 +#define SymRegisterCallback64 RTLDRLAZY_FUNC_NAME(dbghelp, SymRegisterCallback64) + +RTLDRLAZY_FUNC(dbghelp, DWORD64, WINAPI, SymLoadModuleEx, + (HANDLE a1, HANDLE a2, PCSTR a3, PCSTR a4, DWORD64 a5, DWORD a6, PMODLOAD_DATA a7, DWORD a8), + (a1, a2, a3, a4, a5, a6, a7, a8), 0); +#undef SymLoadModuleEx +#define SymLoadModuleEx RTLDRLAZY_FUNC_NAME(dbghelp, SymLoadModuleEx) + +RTLDRLAZY_FUNC(dbghelp, DWORD64, WINAPI, SymLoadModuleExW, + (HANDLE a1, HANDLE a2, PCWSTR a3, PCWSTR a4, DWORD64 a5, DWORD a6, PMODLOAD_DATA a7, DWORD a8), + (a1, a2, a3, a4, a5, a6, a7, a8), 0); +#undef SymLoadModuleExW +#define SymLoadModuleExW RTLDRLAZY_FUNC_NAME(dbghelp, SymLoadModuleExW) + +RTLDRLAZY_FUNC(dbghelp, DWORD64, WINAPI, SymUnloadModule64, (HANDLE a1, DWORD64 a2), (a1, a2), 0); +#undef SymUnloadModule64 +#define SymUnloadModule64 RTLDRLAZY_FUNC_NAME(dbghelp, SymUnloadModule64) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymEnumSymbols, + (HANDLE a1, ULONG64 a2, PCSTR a3, PSYM_ENUMERATESYMBOLS_CALLBACK a4, PVOID a5), + (a1, a2, a3, a4, a5), FALSE); +#undef SymEnumSymbols +#define SymEnumSymbols RTLDRLAZY_FUNC_NAME(dbghelp, SymEnumSymbols) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymEnumLinesW, + (HANDLE a1, ULONG64 a2, PCWSTR a3, PCWSTR a4, PSYM_ENUMLINES_CALLBACKW a5, PVOID a6), + (a1, a2, a3, a4, a5, a6), FALSE); +#undef SymEnumLinesW +#define SymEnumLinesW RTLDRLAZY_FUNC_NAME(dbghelp, SymEnumLinesW) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymGetModuleInfo64, (HANDLE a1, DWORD64 a2, PIMAGEHLP_MODULE64 a3), (a1, a2, a3), FALSE); +#undef SymGetModuleInfo64 +#define SymGetModuleInfo64 RTLDRLAZY_FUNC_NAME(dbghelp, SymGetModuleInfo64) + + + + +#endif /* !IPRT_INCLUDED_win_lazy_dbghelp_h */ + diff --git a/include/iprt/win/mmreg.h b/include/iprt/win/mmreg.h new file mode 100644 index 00000000..8be69c7c --- /dev/null +++ b/include/iprt/win/mmreg.h @@ -0,0 +1,53 @@ +/** @file + * Safe way to include mmreg.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_mmreg_h +#define IPRT_INCLUDED_win_mmreg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) /* Looks like this header messes with warning config, at least in the 7.1 SDK. */ +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_mmreg_h */ + diff --git a/include/iprt/win/netioapi.h b/include/iprt/win/netioapi.h new file mode 100644 index 00000000..5abf1bac --- /dev/null +++ b/include/iprt/win/netioapi.h @@ -0,0 +1,46 @@ +/** @file + * Safe way to include netioapi.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_netioapi_h +#define IPRT_INCLUDED_win_netioapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include /* this one has problems with -Wall */ +#include + +#endif /* !IPRT_INCLUDED_win_netioapi_h */ + diff --git a/include/iprt/win/ntdddisk.h b/include/iprt/win/ntdddisk.h new file mode 100644 index 00000000..452a5ac5 --- /dev/null +++ b/include/iprt/win/ntdddisk.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include ntdddisk.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ntdddisk_h +#define IPRT_INCLUDED_win_ntdddisk_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* ntdddisk.h(137) : warning C4668: 'NTDDI_WIN2003' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ + +#include + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_ntdddisk_h */ + diff --git a/include/iprt/win/ntddndis.h b/include/iprt/win/ntddndis.h new file mode 100644 index 00000000..fc9b8520 --- /dev/null +++ b/include/iprt/win/ntddndis.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include ntddndis.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ntddndis_h +#define IPRT_INCLUDED_win_ntddndis_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* 'NDIS_SUPPORT_NDIS6' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ + +#include + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_ntddndis_h */ + diff --git a/include/iprt/win/ntverp.h b/include/iprt/win/ntverp.h new file mode 100644 index 00000000..484d8152 --- /dev/null +++ b/include/iprt/win/ntverp.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include ntverp.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ntverp_h +#define IPRT_INCLUDED_win_ntverp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /*ntverp.h(126) : warning C4668: 'OFFICIAL_BUILD' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ + +#include + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_ntverp_h */ + diff --git a/include/iprt/win/objbase.h b/include/iprt/win/objbase.h new file mode 100644 index 00000000..8bcb5c00 --- /dev/null +++ b/include/iprt/win/objbase.h @@ -0,0 +1,69 @@ +/** @file + * Safe way to include objbase.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_objbase_h +#define IPRT_INCLUDED_win_objbase_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* objbase.h includes windows.h via rpc.h, so get ahead of it and include + it here via our cleanup wrapper. */ +#include + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if !defined(__cplusplus) +# pragma warning(disable:4255) /* 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_objbase_h */ + diff --git a/include/iprt/win/objidl.h b/include/iprt/win/objidl.h new file mode 100644 index 00000000..d12e8bd7 --- /dev/null +++ b/include/iprt/win/objidl.h @@ -0,0 +1,63 @@ +/** @file + * Safe way to include objidl.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_objidl_h +#define IPRT_INCLUDED_win_objidl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4255) /* windef.h(227) : warning C4255: 'NEARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_objidl_h */ + diff --git a/include/iprt/win/rpcproxy.h b/include/iprt/win/rpcproxy.h new file mode 100644 index 00000000..8d355bb2 --- /dev/null +++ b/include/iprt/win/rpcproxy.h @@ -0,0 +1,75 @@ +/** @file + * Safe way to include rpcproxy.h (not C++ clean). + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_rpcproxy_h +#define IPRT_INCLUDED_win_rpcproxy_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#ifdef __cplusplus + +typedef struct IRpcStubBufferVtbl +{ + BEGIN_INTERFACE + HRESULT (STDMETHODCALLTYPE *QueryInterface)(IRpcStubBuffer *, REFIID, void **); + ULONG (STDMETHODCALLTYPE *AddRef)(IRpcStubBuffer *); + ULONG (STDMETHODCALLTYPE *Release)(IRpcStubBuffer *); + HRESULT (STDMETHODCALLTYPE *Connect)(IRpcStubBuffer *, IUnknown *); + void (STDMETHODCALLTYPE *Disconnect)(IRpcStubBuffer *); + HRESULT (STDMETHODCALLTYPE *Invoke)(IRpcStubBuffer *, RPCOLEMESSAGE *, IRpcChannelBuffer *); + IRpcStubBuffer * (STDMETHODCALLTYPE *IsIIDSupported)(IRpcStubBuffer *, REFIID); + ULONG (STDMETHODCALLTYPE *CountRefs)(IRpcStubBuffer *); + HRESULT (STDMETHODCALLTYPE *DebugServerQueryInterface)(IRpcStubBuffer *, void **); + void (STDMETHODCALLTYPE *DebugServerRelease)(IRpcStubBuffer *, void *); +} IRpcStubBufferVtbl; + +typedef struct IPSFactoryBufferVtbl +{ + HRESULT (STDMETHODCALLTYPE *QueryInterface)(IPSFactoryBuffer *, REFIID, void **); + ULONG (STDMETHODCALLTYPE *AddRef)(IPSFactoryBuffer *); + ULONG (STDMETHODCALLTYPE *Release)(IPSFactoryBuffer *); + HRESULT (STDMETHODCALLTYPE *CreateProxy)(IPSFactoryBuffer *, IUnknown *, REFIID riid, IRpcProxyBuffer **, void **); + HRESULT (STDMETHODCALLTYPE *CreateStub)(IPSFactoryBuffer *, REFIID, IUnknown *, IRpcStubBuffer **); +} IPSFactoryBufferVtbl; + +#endif /* __cplusplus */ + +#include + +#endif /* !IPRT_INCLUDED_win_rpcproxy_h */ + diff --git a/include/iprt/win/setupapi.h b/include/iprt/win/setupapi.h new file mode 100644 index 00000000..704cedaf --- /dev/null +++ b/include/iprt/win/setupapi.h @@ -0,0 +1,59 @@ +/** @file + * Safe way to include setupapi.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_setupapi_h +#define IPRT_INCLUDED_win_setupapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'USE_SP_ALTPLATFORM_INFO_V1' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_setupapi_h */ + diff --git a/include/iprt/win/shlobj.h b/include/iprt/win/shlobj.h new file mode 100644 index 00000000..bcbfd343 --- /dev/null +++ b/include/iprt/win/shlobj.h @@ -0,0 +1,67 @@ +/** @file + * Safe way to include shlobj.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_shlobj_h +#define IPRT_INCLUDED_win_shlobj_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'USE_SP_ALTPLATFORM_INFO_V1' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4255) /* windef.h(227) : warning C4255: 'NEARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:4091) /* sdk/v7.1/include/shlobj.h(1151): warning C4091: 'typedef ': ignored on left of 'tagGPFIDL_FLAGS' when no variable is declared */ +# ifdef __cplusplus +# pragma warning(disable:5039) /* commctrl.h(8323): warning C5039: 'DSA_DestroyCallback': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +# if _MSC_VER >= 1910 /*RT_MSC_VER_VC141*/ +# pragma warning(disable:4768) /* sdk/v7.1/include/shlobj.h(1065): warning C4768: __declspec attributes before linkage specification are ignored */ +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_shlobj_h */ + diff --git a/include/iprt/win/shlwapi.h b/include/iprt/win/shlwapi.h new file mode 100644 index 00000000..f1b037d1 --- /dev/null +++ b/include/iprt/win/shlwapi.h @@ -0,0 +1,53 @@ +/** @file + * Safe way to include shlwapi.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_shlwapi_h +#define IPRT_INCLUDED_win_shlwapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* warning C4668: 'USE_SP_ALTPLATFORM_INFO_V1' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable:4255) /* warning C4255: 'I_RpcMgmtEnableDedicatedThreadPool' : no function prototype given: converting '()' to '(void)' */ +#if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +#endif +#include + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_shlwapi_h */ + diff --git a/include/iprt/win/windef.h b/include/iprt/win/windef.h new file mode 100644 index 00000000..44c6a6ee --- /dev/null +++ b/include/iprt/win/windef.h @@ -0,0 +1,65 @@ +/** @file + * Safe way to include windef.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_windef_h +#define IPRT_INCLUDED_win_windef_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the windef.h file in SDK 7.1 is not clean wrt warning C4668: + * basetsd.h(114) : warning C4668: '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + * winnt.h(13017) : warning C4668: '_DBG_MEMCPY_INLINE_' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + */ +# pragma warning(push) +# pragma warning(disable:4668) +# ifndef __cplusplus +# pragma warning(disable:4255) /* warning C4255: 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_windef_h */ + diff --git a/include/iprt/win/windows.h b/include/iprt/win/windows.h new file mode 100644 index 00000000..b1612713 --- /dev/null +++ b/include/iprt/win/windows.h @@ -0,0 +1,110 @@ +/** @file + * Safe way to include Windows.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_windows_h +#define IPRT_INCLUDED_win_windows_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* winioctl.h in windows 10 SDKs up to 22000(?) has a warning(push/pop) bug in the + portion taken from ntddscm.h causing trouble when using _WIN32_WINNT or NTDDI_VERSION + older than NTDDI_WIN10_RS5. In 18362 winioctl.h also tests against _WIN32_WINNT_WIN10_TH2 + and other sdkddkver.h defines which only exist in NTDDI variants, not in _WIN32_WINNT_XXX, + so we fake up those too to keep the precompiler warning free. + + Work around this by blocking out the buggy section on winioctl.h for now if the + NTDDI_VERSION target is too small. + + WDK_NTDDI_VERSION is not present in the W7 SDK, not sure when exactly it was added. + NTDDI_WIN10_RS5 is W10 1809. NTDDI_WIN10_CO is Windows 11? */ +#include +#ifdef _WIN32_WINNT_WIN10 +# ifndef _WIN32_WINNT_WIN10_TH2 +# define _WIN32_WINNT_WIN10_TH2 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS1 +# define _WIN32_WINNT_WIN10_RS1 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS2 +# define _WIN32_WINNT_WIN10_RS2 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS3 +# define _WIN32_WINNT_WIN10_RS3 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS4 +# define _WIN32_WINNT_WIN10_RS4 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS5 +# define _WIN32_WINNT_WIN10_RS5 _WIN32_WINNT_WIN10 +# endif +#endif +#if defined(NTDDI_WIN10_RS5) && !defined(NTDDI_WIN10_CO) && defined(WDK_NTDDI_VERSION) +# if NTDDI_VERSION < NTDDI_WIN10_RS5 +# define _NTDDSCM_H_ buggy, hope nobody needs it. +# endif +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the Windows.h file in SDK 7.1 is not clean wrt warning C4668: + * wincrypt.h(1848) : warning C4668: 'NTDDI_WINLH' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + */ +# pragma warning(push) +# pragma warning(disable:4668) +# pragma warning(disable:4480) /* W10/wincrypt.h(9193) : warning C4480: nonstandard extension used: specifying underlying type for enum 'CertKeyType' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# else +# pragma warning(disable:4255) /* warning C4255: 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +/* VS2010: Something causes this to be re-enabled above and triggering errors using RT_FLEXIBLE_ARRAY. */ +# pragma warning(disable:4200) +#endif + +#endif /* !IPRT_INCLUDED_win_windows_h */ + diff --git a/include/iprt/win/winsock.h b/include/iprt/win/winsock.h new file mode 100644 index 00000000..aabc3372 --- /dev/null +++ b/include/iprt/win/winsock.h @@ -0,0 +1,64 @@ +/** @file + * Safe way to include winsock2.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_winsock_h +#define IPRT_INCLUDED_win_winsock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the Windows.h file in SDK 7.1 is not clean wrt warning C4668: + * wincrypt.h(1848) : warning C4668: 'NTDDI_WINLH' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + */ +# pragma warning(push) +# pragma warning(disable:4668) +# ifndef __cplusplus +# pragma warning(disable:4255) /* warning C4255: 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_winsock_h */ + diff --git a/include/iprt/win/winsock2.h b/include/iprt/win/winsock2.h new file mode 100644 index 00000000..4c834b9a --- /dev/null +++ b/include/iprt/win/winsock2.h @@ -0,0 +1,74 @@ +/** @file + * Safe way to include winsock2.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_winsock2_h +#define IPRT_INCLUDED_win_winsock2_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* winsock2.h includes windows.h, but without winsock.h, so we need to do it + up front using our wrapper header to avoid repeating tricks here. */ +#define _WINSOCKAPI_ /* do not include winsock.h via windows.h */ +#include + +#ifdef _MSC_VER +/* + * Unfortunately, the Windows.h file in SDK 7.1 is not clean wrt warning C4668: + * wincrypt.h(1848) : warning C4668: 'NTDDI_WINLH' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + */ +# pragma warning(push) +# pragma warning(disable:4668) +# ifndef __cplusplus +# pragma warning(disable:4255) /* warning C4255: 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_winsock2_h */ + diff --git a/include/iprt/win/ws2tcpip.h b/include/iprt/win/ws2tcpip.h new file mode 100644 index 00000000..ea5e7f2a --- /dev/null +++ b/include/iprt/win/ws2tcpip.h @@ -0,0 +1,67 @@ +/** @file + * Safe way to include ws2tcpip.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ws2tcpip_h +#define IPRT_INCLUDED_win_ws2tcpip_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* ws2tcpip.h includes winsock2.h, so get ahead of it and include our cleanly + wrapped version first to avoid duplicating stuff here. */ +#include + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* 'NDIS_SUPPORT_NDIS6' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4255) /* windef.h(227) : warning C4255: 'NEARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* ws2tcpip.h(874): warning C5039: 'WSAIoctl': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_ws2tcpip_h */ + diff --git a/include/iprt/x86-helpers.h b/include/iprt/x86-helpers.h new file mode 100644 index 00000000..78f88762 --- /dev/null +++ b/include/iprt/x86-helpers.h @@ -0,0 +1,261 @@ +/** @file + * IPRT - X86 and AMD64 Helpers. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_x86_helpers_h +#define IPRT_INCLUDED_x86_helpers_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_rt_x86_helpers x86 Helper Functions + * @ingroup grp_rt_x86 + * @{ + */ + + +/** + * Tests if it a genuine Intel CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0) + * @param uECX ECX return from ASMCpuId(0) + * @param uEDX EDX return from ASMCpuId(0) + */ +DECLINLINE(bool) RTX86IsIntelCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* 'GenuineIntel' */ + return uEBX == UINT32_C(0x756e6547) /* 'Genu' */ + && uEDX == UINT32_C(0x49656e69) /* 'ineI' */ + && uECX == UINT32_C(0x6c65746e); /* 'ntel' */ +} + + +/** + * Tests if it an authentic AMD CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0) + * @param uECX ECX return from ASMCpuId(0) + * @param uEDX EDX return from ASMCpuId(0) + */ +DECLINLINE(bool) RTX86IsAmdCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* 'AuthenticAMD' */ + return uEBX == UINT32_C(0x68747541) /* 'Auth' */ + && uEDX == UINT32_C(0x69746e65) /* 'enti' */ + && uECX == UINT32_C(0x444d4163); /* 'dAMD' */ +} + + +/** + * Tests if it a centaur hauling VIA CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0). + * @param uECX ECX return from ASMCpuId(0). + * @param uEDX EDX return from ASMCpuId(0). + */ +DECLINLINE(bool) RTX86IsViaCentaurCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* 'CentaurHauls' */ + return uEBX == UINT32_C(0x746e6543) /* 'Cent' */ + && uEDX == UINT32_C(0x48727561) /* 'aurH' */ + && uECX == UINT32_C(0x736c7561); /* 'auls' */ +} + + +/** + * Tests if it a Shanghai CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0). + * @param uECX ECX return from ASMCpuId(0). + * @param uEDX EDX return from ASMCpuId(0). + */ +DECLINLINE(bool) RTX86IsShanghaiCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* ' Shanghai ' */ + return uEBX == UINT32_C(0x68532020) /* ' Sh' */ + && uEDX == UINT32_C(0x68676e61) /* 'angh' */ + && uECX == UINT32_C(0x20206961); /* 'ai ' */ +} + + +/** + * Tests if it a genuine Hygon CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0) + * @param uECX ECX return from ASMCpuId(0) + * @param uEDX EDX return from ASMCpuId(0) + */ +DECLINLINE(bool) RTX86IsHygonCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* 'HygonGenuine' */ + return uEBX == UINT32_C(0x6f677948) /* Hygo */ + && uECX == UINT32_C(0x656e6975) /* uine */ + && uEDX == UINT32_C(0x6e65476e); /* nGen */ +} + + +/** + * Checks whether ASMCpuId_EAX(0x00000000) indicates a valid range. + * + * + * @returns true/false. + * @param uEAX The EAX value of CPUID leaf 0x00000000. + * + * @note This only succeeds if there are at least two leaves in the range. + * @remarks The upper range limit is just some half reasonable value we've + * picked out of thin air. + */ +DECLINLINE(bool) RTX86IsValidStdRange(uint32_t uEAX) +{ + return uEAX >= UINT32_C(0x00000001) && uEAX <= UINT32_C(0x000fffff); +} + + +/** + * Checks whether ASMCpuId_EAX(0x80000000) indicates a valid range. + * + * This only succeeds if there are at least two leaves in the range. + * + * @returns true/false. + * @param uEAX The EAX value of CPUID leaf 0x80000000. + * + * @note This only succeeds if there are at least two leaves in the range. + * @remarks The upper range limit is just some half reasonable value we've + * picked out of thin air. + */ +DECLINLINE(bool) RTX86IsValidExtRange(uint32_t uEAX) +{ + return uEAX >= UINT32_C(0x80000001) && uEAX <= UINT32_C(0x800fffff); +} + + +/** + * Checks whether ASMCpuId_EAX(0x40000000) indicates a valid range. + * + * This only succeeds if there are at least two leaves in the range. + * + * @returns true/false. + * @param uEAX The EAX value of CPUID leaf 0x40000000. + * + * @note Unlike RTX86IsValidStdRange() and RTX86IsValidExtRange(), a single + * leaf is okay here. So, you always need to check the range. + * @remarks The upper range limit is take from the intel docs. + */ +DECLINLINE(bool) RTX86IsValidHypervisorRange(uint32_t uEAX) +{ + return uEAX >= UINT32_C(0x40000000) && uEAX <= UINT32_C(0x4fffffff); +} + + +/** + * Extracts the CPU family from ASMCpuId(1) or ASMCpuId(0x80000001) + * + * @returns Family. + * @param uEAX EAX return from ASMCpuId(1) or ASMCpuId(0x80000001). + */ +DECLINLINE(uint32_t) RTX86GetCpuFamily(uint32_t uEAX) +{ + return ((uEAX >> 8) & 0xf) == 0xf + ? ((uEAX >> 20) & 0x7f) + 0xf + : ((uEAX >> 8) & 0xf); +} + + +/** + * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001), Intel variant. + * + * @returns Model. + * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001). + */ +DECLINLINE(uint32_t) RTX86GetCpuModelIntel(uint32_t uEAX) +{ + return ((uEAX >> 8) & 0xf) == 0xf || (((uEAX >> 8) & 0xf) == 0x6) /* family! */ + ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0) + : ((uEAX >> 4) & 0xf); +} + + +/** + * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001), AMD variant. + * + * @returns Model. + * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001). + */ +DECLINLINE(uint32_t) RTX86GetCpuModelAMD(uint32_t uEAX) +{ + return ((uEAX >> 8) & 0xf) == 0xf + ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0) + : ((uEAX >> 4) & 0xf); +} + + +/** + * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001) + * + * @returns Model. + * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001). + * @param fIntel Whether it's an intel CPU. Use RTX86IsIntelCpu() or + * RTX86IsIntelCpu(). + */ +DECLINLINE(uint32_t) RTX86GetCpuModel(uint32_t uEAX, bool fIntel) +{ + return ((uEAX >> 8) & 0xf) == 0xf || (((uEAX >> 8) & 0xf) == 0x6 && fIntel) /* family! */ + ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0) + : ((uEAX >> 4) & 0xf); +} + + +/** + * Extracts the CPU stepping from ASMCpuId(1) or ASMCpuId(0x80000001) + * + * @returns Model. + * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001). + */ +DECLINLINE(uint32_t) RTX86GetCpuStepping(uint32_t uEAX) +{ + return uEAX & 0xf; +} + + +/** @} */ +#endif /* !IPRT_INCLUDED_x86_helpers_h */ + diff --git a/include/iprt/x86.h b/include/iprt/x86.h new file mode 100644 index 00000000..fe4e8ddf --- /dev/null +++ b/include/iprt/x86.h @@ -0,0 +1,4860 @@ +/** @file + * IPRT - X86 and AMD64 Structures and Definitions. + * + * @note x86.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_x86_h +#define IPRT_INCLUDED_x86_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_FOR_DTRACE_LIB +# include +# include +#else +# pragma D depends_on library vbox-types.d +#endif + +/** Workaround for Solaris sys/regset.h defining CS, DS and sys/controlregs.h + * defining MSR_IA32_FLUSH_CMD */ +#ifdef RT_OS_SOLARIS +# undef CS +# undef DS +# undef MSR_IA32_FLUSH_CMD +#endif + +/** @defgroup grp_rt_x86 x86 Types and Definitions + * @ingroup grp_rt + * @{ + */ + +#ifndef VBOX_FOR_DTRACE_LIB +/** + * EFLAGS Bits. + */ +typedef struct X86EFLAGSBITS +{ + /** Bit 0 - CF - Carry flag - Status flag. */ + unsigned u1CF : 1; + /** Bit 1 - 1 - Reserved flag. */ + unsigned u1Reserved0 : 1; + /** Bit 2 - PF - Parity flag - Status flag. */ + unsigned u1PF : 1; + /** Bit 3 - 0 - Reserved flag. */ + unsigned u1Reserved1 : 1; + /** Bit 4 - AF - Auxiliary carry flag - Status flag. */ + unsigned u1AF : 1; + /** Bit 5 - 0 - Reserved flag. */ + unsigned u1Reserved2 : 1; + /** Bit 6 - ZF - Zero flag - Status flag. */ + unsigned u1ZF : 1; + /** Bit 7 - SF - Signed flag - Status flag. */ + unsigned u1SF : 1; + /** Bit 8 - TF - Trap flag - System flag. */ + unsigned u1TF : 1; + /** Bit 9 - IF - Interrupt flag - System flag. */ + unsigned u1IF : 1; + /** Bit 10 - DF - Direction flag - Control flag. */ + unsigned u1DF : 1; + /** Bit 11 - OF - Overflow flag - Status flag. */ + unsigned u1OF : 1; + /** Bit 12-13 - IOPL - I/O privilege level flag - System flag. */ + unsigned u2IOPL : 2; + /** Bit 14 - NT - Nested task flag - System flag. */ + unsigned u1NT : 1; + /** Bit 15 - 0 - Reserved flag. */ + unsigned u1Reserved3 : 1; + /** Bit 16 - RF - Resume flag - System flag. */ + unsigned u1RF : 1; + /** Bit 17 - VM - Virtual 8086 mode - System flag. */ + unsigned u1VM : 1; + /** Bit 18 - AC - Alignment check flag - System flag. Works with CR0.AM. */ + unsigned u1AC : 1; + /** Bit 19 - VIF - Virtual interrupt flag - System flag. */ + unsigned u1VIF : 1; + /** Bit 20 - VIP - Virtual interrupt pending flag - System flag. */ + unsigned u1VIP : 1; + /** Bit 21 - ID - CPUID flag - System flag. If this responds to flipping CPUID is supported. */ + unsigned u1ID : 1; + /** Bit 22-31 - 0 - Reserved flag. */ + unsigned u10Reserved4 : 10; +} X86EFLAGSBITS; +/** Pointer to EFLAGS bits. */ +typedef X86EFLAGSBITS *PX86EFLAGSBITS; +/** Pointer to const EFLAGS bits. */ +typedef const X86EFLAGSBITS *PCX86EFLAGSBITS; +#endif /* !VBOX_FOR_DTRACE_LIB */ + +/** + * EFLAGS. + */ +typedef union X86EFLAGS +{ + /** The plain unsigned view. */ + uint32_t u; +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif + /** The 8-bit view. */ + uint8_t au8[4]; + /** The 16-bit view. */ + uint16_t au16[2]; + /** The 32-bit view. */ + uint32_t au32[1]; + /** The 32-bit view. */ + uint32_t u32; +} X86EFLAGS; +/** Pointer to EFLAGS. */ +typedef X86EFLAGS *PX86EFLAGS; +/** Pointer to const EFLAGS. */ +typedef const X86EFLAGS *PCX86EFLAGS; + +/** + * RFLAGS (32 upper bits are reserved). + */ +typedef union X86RFLAGS +{ + /** The plain unsigned view. */ + uint64_t u; +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif + /** The 8-bit view. */ + uint8_t au8[8]; + /** The 16-bit view. */ + uint16_t au16[4]; + /** The 32-bit view. */ + uint32_t au32[2]; + /** The 64-bit view. */ + uint64_t au64[1]; + /** The 64-bit view. */ + uint64_t u64; +} X86RFLAGS; +/** Pointer to RFLAGS. */ +typedef X86RFLAGS *PX86RFLAGS; +/** Pointer to const RFLAGS. */ +typedef const X86RFLAGS *PCX86RFLAGS; + + +/** @name EFLAGS + * @{ + */ +/** Bit 0 - CF - Carry flag - Status flag. */ +#define X86_EFL_CF RT_BIT_32(0) +#define X86_EFL_CF_BIT 0 +/** Bit 1 - Reserved, reads as 1. */ +#define X86_EFL_1 RT_BIT_32(1) +/** Bit 2 - PF - Parity flag - Status flag. */ +#define X86_EFL_PF RT_BIT_32(2) +#define X86_EFL_PF_BIT 2 +/** Bit 4 - AF - Auxiliary carry flag - Status flag. */ +#define X86_EFL_AF RT_BIT_32(4) +#define X86_EFL_AF_BIT 4 +/** Bit 6 - ZF - Zero flag - Status flag. */ +#define X86_EFL_ZF RT_BIT_32(6) +#define X86_EFL_ZF_BIT 6 +/** Bit 7 - SF - Signed flag - Status flag. */ +#define X86_EFL_SF RT_BIT_32(7) +#define X86_EFL_SF_BIT 7 +/** Bit 8 - TF - Trap flag - System flag. */ +#define X86_EFL_TF RT_BIT_32(8) +#define X86_EFL_TF_BIT 8 +/** Bit 9 - IF - Interrupt flag - System flag. */ +#define X86_EFL_IF RT_BIT_32(9) +#define X86_EFL_IF_BIT 9 +/** Bit 10 - DF - Direction flag - Control flag. */ +#define X86_EFL_DF RT_BIT_32(10) +#define X86_EFL_DF_BIT 10 +/** Bit 11 - OF - Overflow flag - Status flag. */ +#define X86_EFL_OF RT_BIT_32(11) +#define X86_EFL_OF_BIT 11 +/** Bit 12-13 - IOPL - I/O privilege level flag - System flag. */ +#define X86_EFL_IOPL (RT_BIT_32(12) | RT_BIT_32(13)) +/** Bit 14 - NT - Nested task flag - System flag. */ +#define X86_EFL_NT RT_BIT_32(14) +#define X86_EFL_NT_BIT 14 +/** Bit 16 - RF - Resume flag - System flag. */ +#define X86_EFL_RF RT_BIT_32(16) +#define X86_EFL_RF_BIT 16 +/** Bit 17 - VM - Virtual 8086 mode - System flag. */ +#define X86_EFL_VM RT_BIT_32(17) +#define X86_EFL_VM_BIT 17 +/** Bit 18 - AC - Alignment check flag - System flag. Works with CR0.AM. */ +#define X86_EFL_AC RT_BIT_32(18) +#define X86_EFL_AC_BIT 18 +/** Bit 19 - VIF - Virtual interrupt flag - System flag. */ +#define X86_EFL_VIF RT_BIT_32(19) +#define X86_EFL_VIF_BIT 19 +/** Bit 20 - VIP - Virtual interrupt pending flag - System flag. */ +#define X86_EFL_VIP RT_BIT_32(20) +#define X86_EFL_VIP_BIT 20 +/** Bit 21 - ID - CPUID flag - System flag. If this responds to flipping CPUID is supported. */ +#define X86_EFL_ID RT_BIT_32(21) +#define X86_EFL_ID_BIT 21 +/** All live bits. */ +#define X86_EFL_LIVE_MASK UINT32_C(0x003f7fd5) +/** Read as 1 bits. */ +#define X86_EFL_RA1_MASK RT_BIT_32(1) +/** Read as 0 bits, excluding bits 31:22. + * Bits 3, 5, 15, and 22 thru 31. */ +#define X86_EFL_RAZ_MASK UINT32_C(0xffc08028) +/** Read as 0 bits, excluding bits 31:22. + * Bits 3, 5 and 15. */ +#define X86_EFL_RAZ_LO_MASK UINT32_C(0x00008028) +/** IOPL shift. */ +#define X86_EFL_IOPL_SHIFT 12 +/** The IOPL level from the flags. */ +#define X86_EFL_GET_IOPL(efl) (((efl) >> X86_EFL_IOPL_SHIFT) & 3) +/** Bits restored by popf */ +#define X86_EFL_POPF_BITS ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF \ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_AC | X86_EFL_ID ) +/** Bits restored by popf */ +#define X86_EFL_POPF_BITS_386 ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF \ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT ) +/** The status bits commonly updated by arithmetic instructions. */ +#define X86_EFL_STATUS_BITS ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF ) +/** @} */ + + +/** CPUID Feature information - ECX. + * CPUID query with EAX=1. + */ +#ifndef VBOX_FOR_DTRACE_LIB +typedef struct X86CPUIDFEATECX +{ + /** Bit 0 - SSE3 - Supports SSE3 or not. */ + unsigned u1SSE3 : 1; + /** Bit 1 - PCLMULQDQ. */ + unsigned u1PCLMULQDQ : 1; + /** Bit 2 - DS Area 64-bit layout. */ + unsigned u1DTE64 : 1; + /** Bit 3 - MONITOR - Supports MONITOR/MWAIT. */ + unsigned u1Monitor : 1; + /** Bit 4 - CPL-DS - CPL Qualified Debug Store. */ + unsigned u1CPLDS : 1; + /** Bit 5 - VMX - Virtual Machine Technology. */ + unsigned u1VMX : 1; + /** Bit 6 - SMX: Safer Mode Extensions. */ + unsigned u1SMX : 1; + /** Bit 7 - EST - Enh. SpeedStep Tech. */ + unsigned u1EST : 1; + /** Bit 8 - TM2 - Terminal Monitor 2. */ + unsigned u1TM2 : 1; + /** Bit 9 - SSSE3 - Supplemental Streaming SIMD Extensions 3. */ + unsigned u1SSSE3 : 1; + /** Bit 10 - CNTX-ID - L1 Context ID. */ + unsigned u1CNTXID : 1; + /** Bit 11 - Reserved. */ + unsigned u1Reserved1 : 1; + /** Bit 12 - FMA. */ + unsigned u1FMA : 1; + /** Bit 13 - CX16 - CMPXCHG16B. */ + unsigned u1CX16 : 1; + /** Bit 14 - xTPR Update Control. Processor supports changing IA32_MISC_ENABLES[bit 23]. */ + unsigned u1TPRUpdate : 1; + /** Bit 15 - PDCM - Perf/Debug Capability MSR. */ + unsigned u1PDCM : 1; + /** Bit 16 - Reserved. */ + unsigned u1Reserved2 : 1; + /** Bit 17 - PCID - Process-context identifiers. */ + unsigned u1PCID : 1; + /** Bit 18 - Direct Cache Access. */ + unsigned u1DCA : 1; + /** Bit 19 - SSE4_1 - Supports SSE4_1 or not. */ + unsigned u1SSE4_1 : 1; + /** Bit 20 - SSE4_2 - Supports SSE4_2 or not. */ + unsigned u1SSE4_2 : 1; + /** Bit 21 - x2APIC. */ + unsigned u1x2APIC : 1; + /** Bit 22 - MOVBE - Supports MOVBE. */ + unsigned u1MOVBE : 1; + /** Bit 23 - POPCNT - Supports POPCNT. */ + unsigned u1POPCNT : 1; + /** Bit 24 - TSC-Deadline. */ + unsigned u1TSCDEADLINE : 1; + /** Bit 25 - AES. */ + unsigned u1AES : 1; + /** Bit 26 - XSAVE - Supports XSAVE. */ + unsigned u1XSAVE : 1; + /** Bit 27 - OSXSAVE - Supports OSXSAVE. */ + unsigned u1OSXSAVE : 1; + /** Bit 28 - AVX - Supports AVX instruction extensions. */ + unsigned u1AVX : 1; + /** Bit 29 - F16C - Supports 16-bit floating point conversion instructions. */ + unsigned u1F16C : 1; + /** Bit 30 - RDRAND - Supports RDRAND. */ + unsigned u1RDRAND : 1; + /** Bit 31 - Hypervisor present (we're a guest). */ + unsigned u1HVP : 1; +} X86CPUIDFEATECX; +#else /* VBOX_FOR_DTRACE_LIB */ +typedef uint32_t X86CPUIDFEATECX; +#endif /* VBOX_FOR_DTRACE_LIB */ +/** Pointer to CPUID Feature Information - ECX. */ +typedef X86CPUIDFEATECX *PX86CPUIDFEATECX; +/** Pointer to const CPUID Feature Information - ECX. */ +typedef const X86CPUIDFEATECX *PCX86CPUIDFEATECX; + + +/** CPUID Feature Information - EDX. + * CPUID query with EAX=1. + */ +#ifndef VBOX_FOR_DTRACE_LIB /* DTrace different (brain-dead from a C pov) bitfield implementation */ +typedef struct X86CPUIDFEATEDX +{ + /** Bit 0 - FPU - x87 FPU on Chip. */ + unsigned u1FPU : 1; + /** Bit 1 - VME - Virtual 8086 Mode Enhancements. */ + unsigned u1VME : 1; + /** Bit 2 - DE - Debugging extensions. */ + unsigned u1DE : 1; + /** Bit 3 - PSE - Page Size Extension. */ + unsigned u1PSE : 1; + /** Bit 4 - TSC - Time Stamp Counter. */ + unsigned u1TSC : 1; + /** Bit 5 - MSR - Model Specific Registers RDMSR and WRMSR Instructions. */ + unsigned u1MSR : 1; + /** Bit 6 - PAE - Physical Address Extension. */ + unsigned u1PAE : 1; + /** Bit 7 - MCE - Machine Check Exception. */ + unsigned u1MCE : 1; + /** Bit 8 - CX8 - CMPXCHG8B instruction. */ + unsigned u1CX8 : 1; + /** Bit 9 - APIC - APIC On-Chip. */ + unsigned u1APIC : 1; + /** Bit 10 - Reserved. */ + unsigned u1Reserved1 : 1; + /** Bit 11 - SEP - SYSENTER and SYSEXIT. */ + unsigned u1SEP : 1; + /** Bit 12 - MTRR - Memory Type Range Registers. */ + unsigned u1MTRR : 1; + /** Bit 13 - PGE - PTE Global Bit. */ + unsigned u1PGE : 1; + /** Bit 14 - MCA - Machine Check Architecture. */ + unsigned u1MCA : 1; + /** Bit 15 - CMOV - Conditional Move Instructions. */ + unsigned u1CMOV : 1; + /** Bit 16 - PAT - Page Attribute Table. */ + unsigned u1PAT : 1; + /** Bit 17 - PSE-36 - 36-bit Page Size Extension. */ + unsigned u1PSE36 : 1; + /** Bit 18 - PSN - Processor Serial Number. */ + unsigned u1PSN : 1; + /** Bit 19 - CLFSH - CLFLUSH Instruction. */ + unsigned u1CLFSH : 1; + /** Bit 20 - Reserved. */ + unsigned u1Reserved2 : 1; + /** Bit 21 - DS - Debug Store. */ + unsigned u1DS : 1; + /** Bit 22 - ACPI - Thermal Monitor and Software Controlled Clock Facilities. */ + unsigned u1ACPI : 1; + /** Bit 23 - MMX - Intel MMX 'Technology'. */ + unsigned u1MMX : 1; + /** Bit 24 - FXSR - FXSAVE and FXRSTOR Instructions. */ + unsigned u1FXSR : 1; + /** Bit 25 - SSE - SSE Support. */ + unsigned u1SSE : 1; + /** Bit 26 - SSE2 - SSE2 Support. */ + unsigned u1SSE2 : 1; + /** Bit 27 - SS - Self Snoop. */ + unsigned u1SS : 1; + /** Bit 28 - HTT - Hyper-Threading Technology. */ + unsigned u1HTT : 1; + /** Bit 29 - TM - Thermal Monitor. */ + unsigned u1TM : 1; + /** Bit 30 - Reserved - . */ + unsigned u1Reserved3 : 1; + /** Bit 31 - PBE - Pending Break Enabled. */ + unsigned u1PBE : 1; +} X86CPUIDFEATEDX; +#else /* VBOX_FOR_DTRACE_LIB */ +typedef uint32_t X86CPUIDFEATEDX; +#endif /* VBOX_FOR_DTRACE_LIB */ +/** Pointer to CPUID Feature Information - EDX. */ +typedef X86CPUIDFEATEDX *PX86CPUIDFEATEDX; +/** Pointer to const CPUID Feature Information - EDX. */ +typedef const X86CPUIDFEATEDX *PCX86CPUIDFEATEDX; + +/** @name CPUID Vendor information. + * CPUID query with EAX=0. + * @{ + */ +#define X86_CPUID_VENDOR_INTEL_EBX 0x756e6547 /* Genu */ +#define X86_CPUID_VENDOR_INTEL_ECX 0x6c65746e /* ntel */ +#define X86_CPUID_VENDOR_INTEL_EDX 0x49656e69 /* ineI */ + +#define X86_CPUID_VENDOR_AMD_EBX 0x68747541 /* Auth */ +#define X86_CPUID_VENDOR_AMD_ECX 0x444d4163 /* cAMD */ +#define X86_CPUID_VENDOR_AMD_EDX 0x69746e65 /* enti */ + +#define X86_CPUID_VENDOR_VIA_EBX 0x746e6543 /* Cent */ +#define X86_CPUID_VENDOR_VIA_ECX 0x736c7561 /* auls */ +#define X86_CPUID_VENDOR_VIA_EDX 0x48727561 /* aurH */ + +#define X86_CPUID_VENDOR_SHANGHAI_EBX 0x68532020 /* Sh */ +#define X86_CPUID_VENDOR_SHANGHAI_ECX 0x20206961 /* ai */ +#define X86_CPUID_VENDOR_SHANGHAI_EDX 0x68676e61 /* angh */ + +#define X86_CPUID_VENDOR_HYGON_EBX 0x6f677948 /* Hygo */ +#define X86_CPUID_VENDOR_HYGON_ECX 0x656e6975 /* uine */ +#define X86_CPUID_VENDOR_HYGON_EDX 0x6e65476e /* nGen */ +/** @} */ + + +/** @name CPUID Feature information. + * CPUID query with EAX=1. + * @{ + */ +/** ECX Bit 0 - SSE3 - Supports SSE3 or not. */ +#define X86_CPUID_FEATURE_ECX_SSE3 RT_BIT_32(0) +/** ECX Bit 1 - PCLMUL - PCLMULQDQ support (for AES-GCM). */ +#define X86_CPUID_FEATURE_ECX_PCLMUL RT_BIT_32(1) +/** ECX Bit 2 - DTES64 - DS Area 64-bit Layout. */ +#define X86_CPUID_FEATURE_ECX_DTES64 RT_BIT_32(2) +/** ECX Bit 3 - MONITOR - Supports MONITOR/MWAIT. */ +#define X86_CPUID_FEATURE_ECX_MONITOR RT_BIT_32(3) +/** ECX Bit 4 - CPL-DS - CPL Qualified Debug Store. */ +#define X86_CPUID_FEATURE_ECX_CPLDS RT_BIT_32(4) +/** ECX Bit 5 - VMX - Virtual Machine Technology. */ +#define X86_CPUID_FEATURE_ECX_VMX RT_BIT_32(5) +/** ECX Bit 6 - SMX - Safer Mode Extensions. */ +#define X86_CPUID_FEATURE_ECX_SMX RT_BIT_32(6) +/** ECX Bit 7 - EST - Enh. SpeedStep Tech. */ +#define X86_CPUID_FEATURE_ECX_EST RT_BIT_32(7) +/** ECX Bit 8 - TM2 - Terminal Monitor 2. */ +#define X86_CPUID_FEATURE_ECX_TM2 RT_BIT_32(8) +/** ECX Bit 9 - SSSE3 - Supplemental Streaming SIMD Extensions 3. */ +#define X86_CPUID_FEATURE_ECX_SSSE3 RT_BIT_32(9) +/** ECX Bit 10 - CNTX-ID - L1 Context ID. */ +#define X86_CPUID_FEATURE_ECX_CNTXID RT_BIT_32(10) +/** ECX Bit 11 - SDBG - Sillicon debug interface (IA32_DEBUG_INTERFACE MSR). + * See figure 3-6 and table 3-10, in intel Vol. 2A. from 2015-01-01. */ +#define X86_CPUID_FEATURE_ECX_SDBG RT_BIT_32(11) +/** ECX Bit 12 - FMA. */ +#define X86_CPUID_FEATURE_ECX_FMA RT_BIT_32(12) +/** ECX Bit 13 - CX16 - CMPXCHG16B. */ +#define X86_CPUID_FEATURE_ECX_CX16 RT_BIT_32(13) +/** ECX Bit 14 - xTPR Update Control. Processor supports changing IA32_MISC_ENABLES[bit 23]. */ +#define X86_CPUID_FEATURE_ECX_TPRUPDATE RT_BIT_32(14) +/** ECX Bit 15 - PDCM - Perf/Debug Capability MSR. */ +#define X86_CPUID_FEATURE_ECX_PDCM RT_BIT_32(15) +/** ECX Bit 17 - PCID - Process-context identifiers. */ +#define X86_CPUID_FEATURE_ECX_PCID RT_BIT_32(17) +/** ECX Bit 18 - DCA - Direct Cache Access. */ +#define X86_CPUID_FEATURE_ECX_DCA RT_BIT_32(18) +/** ECX Bit 19 - SSE4_1 - Supports SSE4_1 or not. */ +#define X86_CPUID_FEATURE_ECX_SSE4_1 RT_BIT_32(19) +/** ECX Bit 20 - SSE4_2 - Supports SSE4_2 or not. */ +#define X86_CPUID_FEATURE_ECX_SSE4_2 RT_BIT_32(20) +/** ECX Bit 21 - x2APIC support. */ +#define X86_CPUID_FEATURE_ECX_X2APIC RT_BIT_32(21) +/** ECX Bit 22 - MOVBE instruction. */ +#define X86_CPUID_FEATURE_ECX_MOVBE RT_BIT_32(22) +/** ECX Bit 23 - POPCNT instruction. */ +#define X86_CPUID_FEATURE_ECX_POPCNT RT_BIT_32(23) +/** ECX Bir 24 - TSC-Deadline. */ +#define X86_CPUID_FEATURE_ECX_TSCDEADL RT_BIT_32(24) +/** ECX Bit 25 - AES instructions. */ +#define X86_CPUID_FEATURE_ECX_AES RT_BIT_32(25) +/** ECX Bit 26 - XSAVE instruction. */ +#define X86_CPUID_FEATURE_ECX_XSAVE RT_BIT_32(26) +/** ECX Bit 27 - Copy of CR4.OSXSAVE. */ +#define X86_CPUID_FEATURE_ECX_OSXSAVE RT_BIT_32(27) +/** ECX Bit 28 - AVX. */ +#define X86_CPUID_FEATURE_ECX_AVX RT_BIT_32(28) +/** ECX Bit 29 - F16C - Half-precision convert instruction support. */ +#define X86_CPUID_FEATURE_ECX_F16C RT_BIT_32(29) +/** ECX Bit 30 - RDRAND instruction. */ +#define X86_CPUID_FEATURE_ECX_RDRAND RT_BIT_32(30) +/** ECX Bit 31 - Hypervisor Present (software only). */ +#define X86_CPUID_FEATURE_ECX_HVP RT_BIT_32(31) + + +/** Bit 0 - FPU - x87 FPU on Chip. */ +#define X86_CPUID_FEATURE_EDX_FPU RT_BIT_32(0) +/** Bit 1 - VME - Virtual 8086 Mode Enhancements. */ +#define X86_CPUID_FEATURE_EDX_VME RT_BIT_32(1) +/** Bit 2 - DE - Debugging extensions. */ +#define X86_CPUID_FEATURE_EDX_DE RT_BIT_32(2) +/** Bit 3 - PSE - Page Size Extension. */ +#define X86_CPUID_FEATURE_EDX_PSE RT_BIT_32(3) +#define X86_CPUID_FEATURE_EDX_PSE_BIT 3 /**< Bit number for X86_CPUID_FEATURE_EDX_PSE. */ +/** Bit 4 - TSC - Time Stamp Counter. */ +#define X86_CPUID_FEATURE_EDX_TSC RT_BIT_32(4) +/** Bit 5 - MSR - Model Specific Registers RDMSR and WRMSR Instructions. */ +#define X86_CPUID_FEATURE_EDX_MSR RT_BIT_32(5) +/** Bit 6 - PAE - Physical Address Extension. */ +#define X86_CPUID_FEATURE_EDX_PAE RT_BIT_32(6) +#define X86_CPUID_FEATURE_EDX_PAE_BIT 6 /**< Bit number for X86_CPUID_FEATURE_EDX_PAE. */ +/** Bit 7 - MCE - Machine Check Exception. */ +#define X86_CPUID_FEATURE_EDX_MCE RT_BIT_32(7) +/** Bit 8 - CX8 - CMPXCHG8B instruction. */ +#define X86_CPUID_FEATURE_EDX_CX8 RT_BIT_32(8) +/** Bit 9 - APIC - APIC On-Chip. */ +#define X86_CPUID_FEATURE_EDX_APIC RT_BIT_32(9) +/** Bit 11 - SEP - SYSENTER and SYSEXIT Present. */ +#define X86_CPUID_FEATURE_EDX_SEP RT_BIT_32(11) +/** Bit 12 - MTRR - Memory Type Range Registers. */ +#define X86_CPUID_FEATURE_EDX_MTRR RT_BIT_32(12) +/** Bit 13 - PGE - PTE Global Bit. */ +#define X86_CPUID_FEATURE_EDX_PGE RT_BIT_32(13) +/** Bit 14 - MCA - Machine Check Architecture. */ +#define X86_CPUID_FEATURE_EDX_MCA RT_BIT_32(14) +/** Bit 15 - CMOV - Conditional Move Instructions. */ +#define X86_CPUID_FEATURE_EDX_CMOV RT_BIT_32(15) +/** Bit 16 - PAT - Page Attribute Table. */ +#define X86_CPUID_FEATURE_EDX_PAT RT_BIT_32(16) +/** Bit 17 - PSE-36 - 36-bit Page Size Extension. */ +#define X86_CPUID_FEATURE_EDX_PSE36 RT_BIT_32(17) +/** Bit 18 - PSN - Processor Serial Number. */ +#define X86_CPUID_FEATURE_EDX_PSN RT_BIT_32(18) +/** Bit 19 - CLFSH - CLFLUSH Instruction. */ +#define X86_CPUID_FEATURE_EDX_CLFSH RT_BIT_32(19) +/** Bit 21 - DS - Debug Store. */ +#define X86_CPUID_FEATURE_EDX_DS RT_BIT_32(21) +/** Bit 22 - ACPI - Thermal Monitor and Software Controlled Clock Facilities. */ +#define X86_CPUID_FEATURE_EDX_ACPI RT_BIT_32(22) +/** Bit 23 - MMX - Intel MMX Technology. */ +#define X86_CPUID_FEATURE_EDX_MMX RT_BIT_32(23) +/** Bit 24 - FXSR - FXSAVE and FXRSTOR Instructions. */ +#define X86_CPUID_FEATURE_EDX_FXSR RT_BIT_32(24) +/** Bit 25 - SSE - SSE Support. */ +#define X86_CPUID_FEATURE_EDX_SSE RT_BIT_32(25) +/** Bit 26 - SSE2 - SSE2 Support. */ +#define X86_CPUID_FEATURE_EDX_SSE2 RT_BIT_32(26) +/** Bit 27 - SS - Self Snoop. */ +#define X86_CPUID_FEATURE_EDX_SS RT_BIT_32(27) +/** Bit 28 - HTT - Hyper-Threading Technology. */ +#define X86_CPUID_FEATURE_EDX_HTT RT_BIT_32(28) +/** Bit 29 - TM - Therm. Monitor. */ +#define X86_CPUID_FEATURE_EDX_TM RT_BIT_32(29) +/** Bit 31 - PBE - Pending Break Enabled. */ +#define X86_CPUID_FEATURE_EDX_PBE RT_BIT_32(31) +/** @} */ + +/** @name CPUID mwait/monitor information. + * CPUID query with EAX=5. + * @{ + */ +/** ECX Bit 0 - MWAITEXT - Supports mwait/monitor extensions or not. */ +#define X86_CPUID_MWAIT_ECX_EXT RT_BIT_32(0) +/** ECX Bit 1 - MWAITBREAK - Break mwait for external interrupt even if EFLAGS.IF=0. */ +#define X86_CPUID_MWAIT_ECX_BREAKIRQIF0 RT_BIT_32(1) +/** @} */ + + +/** @name CPUID Structured Extended Feature information. + * CPUID query with EAX=7. + * @{ + */ +/** EBX Bit 0 - FSGSBASE - Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE. */ +#define X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE RT_BIT_32(0) +/** EBX Bit 1 - TSCADJUST - Supports MSR_IA32_TSC_ADJUST. */ +#define X86_CPUID_STEXT_FEATURE_EBX_TSC_ADJUST RT_BIT_32(1) +/** EBX Bit 2 - SGX - Supports Software Guard Extensions . */ +#define X86_CPUID_STEXT_FEATURE_EBX_SGX RT_BIT_32(2) +/** EBX Bit 3 - BMI1 - Advanced Bit Manipulation extension 1. */ +#define X86_CPUID_STEXT_FEATURE_EBX_BMI1 RT_BIT_32(3) +/** EBX Bit 4 - HLE - Hardware Lock Elision. */ +#define X86_CPUID_STEXT_FEATURE_EBX_HLE RT_BIT_32(4) +/** EBX Bit 5 - AVX2 - Advanced Vector Extensions 2. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX2 RT_BIT_32(5) +/** EBX Bit 6 - FDP_EXCPTN_ONLY - FPU data pointer only updated on exceptions if set. */ +#define X86_CPUID_STEXT_FEATURE_EBX_FDP_EXCPTN_ONLY RT_BIT_32(6) +/** EBX Bit 7 - SMEP - Supervisor Mode Execution Prevention. */ +#define X86_CPUID_STEXT_FEATURE_EBX_SMEP RT_BIT_32(7) +/** EBX Bit 8 - BMI2 - Advanced Bit Manipulation extension 2. */ +#define X86_CPUID_STEXT_FEATURE_EBX_BMI2 RT_BIT_32(8) +/** EBX Bit 9 - ERMS - Supports Enhanced REP MOVSB/STOSB. */ +#define X86_CPUID_STEXT_FEATURE_EBX_ERMS RT_BIT_32(9) +/** EBX Bit 10 - INVPCID - Supports INVPCID. */ +#define X86_CPUID_STEXT_FEATURE_EBX_INVPCID RT_BIT_32(10) +/** EBX Bit 11 - RTM - Supports Restricted Transactional Memory. */ +#define X86_CPUID_STEXT_FEATURE_EBX_RTM RT_BIT_32(11) +/** EBX Bit 12 - PQM - Supports Platform Quality of Service Monitoring. */ +#define X86_CPUID_STEXT_FEATURE_EBX_PQM RT_BIT_32(12) +/** EBX Bit 13 - DEPFPU_CS_DS - Deprecates FPU CS, FPU DS values if set. */ +#define X86_CPUID_STEXT_FEATURE_EBX_DEPR_FPU_CS_DS RT_BIT_32(13) +/** EBX Bit 14 - MPE - Supports Intel Memory Protection Extensions. */ +#define X86_CPUID_STEXT_FEATURE_EBX_MPE RT_BIT_32(14) +/** EBX Bit 15 - PQE - Supports Platform Quality of Service Enforcement. */ +#define X86_CPUID_STEXT_FEATURE_EBX_PQE RT_BIT_32(15) +/** EBX Bit 16 - AVX512F - Supports AVX512F. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX512F RT_BIT_32(16) +/** EBX Bit 18 - RDSEED - Supports RDSEED. */ +#define X86_CPUID_STEXT_FEATURE_EBX_RDSEED RT_BIT_32(18) +/** EBX Bit 19 - ADX - Supports ADCX/ADOX. */ +#define X86_CPUID_STEXT_FEATURE_EBX_ADX RT_BIT_32(19) +/** EBX Bit 20 - SMAP - Supports Supervisor Mode Access Prevention. */ +#define X86_CPUID_STEXT_FEATURE_EBX_SMAP RT_BIT_32(20) +/** EBX Bit 23 - CLFLUSHOPT - Supports CLFLUSHOPT (Cache Line Flush). */ +#define X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT RT_BIT_32(23) +/** EBX Bit 25 - INTEL_PT - Supports Intel Processor Trace. */ +#define X86_CPUID_STEXT_FEATURE_EBX_INTEL_PT RT_BIT_32(25) +/** EBX Bit 26 - AVX512PF - Supports AVX512PF. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX512PF RT_BIT_32(26) +/** EBX Bit 27 - AVX512ER - Supports AVX512ER. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX512ER RT_BIT_32(27) +/** EBX Bit 28 - AVX512CD - Supports AVX512CD. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX512CD RT_BIT_32(28) +/** EBX Bit 29 - SHA - Supports Secure Hash Algorithm extensions. */ +#define X86_CPUID_STEXT_FEATURE_EBX_SHA RT_BIT_32(29) + +/** ECX Bit 0 - PREFETCHWT1 - Supports the PREFETCHWT1 instruction. */ +#define X86_CPUID_STEXT_FEATURE_ECX_PREFETCHWT1 RT_BIT_32(0) +/** ECX Bit 2 - UIMP - Supports user mode instruction prevention. */ +#define X86_CPUID_STEXT_FEATURE_ECX_UMIP RT_BIT_32(2) +/** ECX Bit 3 - PKU - Supports protection keys for user-mode pages. */ +#define X86_CPUID_STEXT_FEATURE_ECX_PKU RT_BIT_32(3) +/** ECX Bit 4 - OSPKE - Protection keys for user mode pages enabled. */ +#define X86_CPUID_STEXT_FEATURE_ECX_OSPKE RT_BIT_32(4) +/** ECX Bits 17-21 - MAWAU - Value used by BNDLDX and BNDSTX. */ +#define X86_CPUID_STEXT_FEATURE_ECX_MAWAU UINT32_C(0x003e0000) +/** ECX Bit 22 - RDPID - Support pread process ID. */ +#define X86_CPUID_STEXT_FEATURE_ECX_RDPID RT_BIT_32(2) +/** ECX Bit 30 - SGX_LC - Supports SGX launch configuration. */ +#define X86_CPUID_STEXT_FEATURE_ECX_SGX_LC RT_BIT_32(30) + +/** EDX Bit 10 - MD_CLEAR - Supports flushing MDS related buffers. */ +#define X86_CPUID_STEXT_FEATURE_EDX_MD_CLEAR RT_BIT_32(10) +/** EDX Bit 26 - IBRS & IBPB - Supports the IBRS flag in IA32_SPEC_CTRL and + * IBPB command in IA32_PRED_CMD. */ +#define X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB RT_BIT_32(26) +/** EDX Bit 27 - IBRS & IBPB - Supports the STIBP flag in IA32_SPEC_CTRL. */ +#define X86_CPUID_STEXT_FEATURE_EDX_STIBP RT_BIT_32(27) +/** EDX Bit 28 - FLUSH_CMD - Supports IA32_FLUSH_CMD MSR. */ +#define X86_CPUID_STEXT_FEATURE_EDX_FLUSH_CMD RT_BIT_32(28) +/** EDX Bit 29 - ARCHCAP - Supports the IA32_ARCH_CAPABILITIES MSR. */ +#define X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP RT_BIT_32(29) +/** EDX Bit 31 - SSBD - Supports the SSBD flag in IA32_SPEC_CTRL. */ +#define X86_CPUID_STEXT_FEATURE_EDX_SSBD RT_BIT_32(31) + +/** @} */ + + +/** @name CPUID Extended Feature information. + * CPUID query with EAX=0x80000001. + * @{ + */ +/** ECX Bit 0 - LAHF/SAHF support in 64-bit mode. */ +#define X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF RT_BIT_32(0) + +/** EDX Bit 11 - SYSCALL/SYSRET. */ +#define X86_CPUID_EXT_FEATURE_EDX_SYSCALL RT_BIT_32(11) +/** EDX Bit 20 - No-Execute/Execute-Disable. */ +#define X86_CPUID_EXT_FEATURE_EDX_NX RT_BIT_32(20) +/** EDX Bit 26 - 1 GB large page. */ +#define X86_CPUID_EXT_FEATURE_EDX_PAGE1GB RT_BIT_32(26) +/** EDX Bit 27 - RDTSCP. */ +#define X86_CPUID_EXT_FEATURE_EDX_RDTSCP RT_BIT_32(27) +/** EDX Bit 29 - AMD Long Mode/Intel-64 Instructions. */ +#define X86_CPUID_EXT_FEATURE_EDX_LONG_MODE RT_BIT_32(29) +/** @}*/ + +/** @name CPUID AMD Feature information. + * CPUID query with EAX=0x80000001. + * @{ + */ +/** Bit 0 - FPU - x87 FPU on Chip. */ +#define X86_CPUID_AMD_FEATURE_EDX_FPU RT_BIT_32(0) +/** Bit 1 - VME - Virtual 8086 Mode Enhancements. */ +#define X86_CPUID_AMD_FEATURE_EDX_VME RT_BIT_32(1) +/** Bit 2 - DE - Debugging extensions. */ +#define X86_CPUID_AMD_FEATURE_EDX_DE RT_BIT_32(2) +/** Bit 3 - PSE - Page Size Extension. */ +#define X86_CPUID_AMD_FEATURE_EDX_PSE RT_BIT_32(3) +/** Bit 4 - TSC - Time Stamp Counter. */ +#define X86_CPUID_AMD_FEATURE_EDX_TSC RT_BIT_32(4) +/** Bit 5 - MSR - K86 Model Specific Registers RDMSR and WRMSR Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_MSR RT_BIT_32(5) +/** Bit 6 - PAE - Physical Address Extension. */ +#define X86_CPUID_AMD_FEATURE_EDX_PAE RT_BIT_32(6) +/** Bit 7 - MCE - Machine Check Exception. */ +#define X86_CPUID_AMD_FEATURE_EDX_MCE RT_BIT_32(7) +/** Bit 8 - CX8 - CMPXCHG8B instruction. */ +#define X86_CPUID_AMD_FEATURE_EDX_CX8 RT_BIT_32(8) +/** Bit 9 - APIC - APIC On-Chip. */ +#define X86_CPUID_AMD_FEATURE_EDX_APIC RT_BIT_32(9) +/** Bit 12 - MTRR - Memory Type Range Registers. */ +#define X86_CPUID_AMD_FEATURE_EDX_MTRR RT_BIT_32(12) +/** Bit 13 - PGE - PTE Global Bit. */ +#define X86_CPUID_AMD_FEATURE_EDX_PGE RT_BIT_32(13) +/** Bit 14 - MCA - Machine Check Architecture. */ +#define X86_CPUID_AMD_FEATURE_EDX_MCA RT_BIT_32(14) +/** Bit 15 - CMOV - Conditional Move Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_CMOV RT_BIT_32(15) +/** Bit 16 - PAT - Page Attribute Table. */ +#define X86_CPUID_AMD_FEATURE_EDX_PAT RT_BIT_32(16) +/** Bit 17 - PSE-36 - 36-bit Page Size Extension. */ +#define X86_CPUID_AMD_FEATURE_EDX_PSE36 RT_BIT_32(17) +/** Bit 22 - AXMMX - AMD Extensions to MMX Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_AXMMX RT_BIT_32(22) +/** Bit 23 - MMX - Intel MMX Technology. */ +#define X86_CPUID_AMD_FEATURE_EDX_MMX RT_BIT_32(23) +/** Bit 24 - FXSR - FXSAVE and FXRSTOR Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_FXSR RT_BIT_32(24) +/** Bit 25 - FFXSR - AMD fast FXSAVE and FXRSTOR Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_FFXSR RT_BIT_32(25) +/** Bit 30 - 3DNOWEXT - AMD Extensions to 3DNow. */ +#define X86_CPUID_AMD_FEATURE_EDX_3DNOW_EX RT_BIT_32(30) +/** Bit 31 - 3DNOW - AMD 3DNow. */ +#define X86_CPUID_AMD_FEATURE_EDX_3DNOW RT_BIT_32(31) + +/** Bit 1 - CmpLegacy - Core multi-processing legacy mode. */ +#define X86_CPUID_AMD_FEATURE_ECX_CMPL RT_BIT_32(1) +/** Bit 2 - SVM - AMD VM extensions. */ +#define X86_CPUID_AMD_FEATURE_ECX_SVM RT_BIT_32(2) +/** Bit 3 - EXTAPIC - AMD extended APIC registers starting at 0x400. */ +#define X86_CPUID_AMD_FEATURE_ECX_EXT_APIC RT_BIT_32(3) +/** Bit 4 - CR8L - AMD LOCK MOV CR0 means MOV CR8. */ +#define X86_CPUID_AMD_FEATURE_ECX_CR8L RT_BIT_32(4) +/** Bit 5 - ABM - AMD Advanced bit manipulation. LZCNT instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_ABM RT_BIT_32(5) +/** Bit 6 - SSE4A - AMD EXTRQ, INSERTQ, MOVNTSS, and MOVNTSD instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_SSE4A RT_BIT_32(6) +/** Bit 7 - MISALIGNSSE - AMD Misaligned SSE mode. */ +#define X86_CPUID_AMD_FEATURE_ECX_MISALNSSE RT_BIT_32(7) +/** Bit 8 - 3DNOWPRF - AMD PREFETCH and PREFETCHW instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_3DNOWPRF RT_BIT_32(8) +/** Bit 9 - OSVW - AMD OS visible workaround. */ +#define X86_CPUID_AMD_FEATURE_ECX_OSVW RT_BIT_32(9) +/** Bit 10 - IBS - Instruct based sampling. */ +#define X86_CPUID_AMD_FEATURE_ECX_IBS RT_BIT_32(10) +/** Bit 11 - XOP - Extended operation support (see APM6). */ +#define X86_CPUID_AMD_FEATURE_ECX_XOP RT_BIT_32(11) +/** Bit 12 - SKINIT - AMD SKINIT: SKINIT, STGI, and DEV support. */ +#define X86_CPUID_AMD_FEATURE_ECX_SKINIT RT_BIT_32(12) +/** Bit 13 - WDT - AMD Watchdog timer support. */ +#define X86_CPUID_AMD_FEATURE_ECX_WDT RT_BIT_32(13) +/** Bit 15 - LWP - Lightweight profiling support. */ +#define X86_CPUID_AMD_FEATURE_ECX_LWP RT_BIT_32(15) +/** Bit 16 - FMA4 - Four operand FMA instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_FMA4 RT_BIT_32(16) +/** Bit 19 - NodeId - Indicates support for + * MSR_C001_100C[NodeId,NodesPerProcessr]. */ +#define X86_CPUID_AMD_FEATURE_ECX_NODEID RT_BIT_32(19) +/** Bit 21 - TBM - Trailing bit manipulation instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_TBM RT_BIT_32(21) +/** Bit 22 - TopologyExtensions - . */ +#define X86_CPUID_AMD_FEATURE_ECX_TOPOEXT RT_BIT_32(22) +/** @} */ + + +/** @name CPUID AMD Feature information. + * CPUID query with EAX=0x80000007. + * @{ + */ +/** Bit 0 - TS - Temperature Sensor. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_TS RT_BIT_32(0) +/** Bit 1 - FID - Frequency ID Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_FID RT_BIT_32(1) +/** Bit 2 - VID - Voltage ID Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_VID RT_BIT_32(2) +/** Bit 3 - TTP - THERMTRIP. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_TTP RT_BIT_32(3) +/** Bit 4 - TM - Hardware Thermal Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_TM RT_BIT_32(4) +/** Bit 5 - STC - Software Thermal Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_STC RT_BIT_32(5) +/** Bit 6 - MC - 100 Mhz Multiplier Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_MC RT_BIT_32(6) +/** Bit 7 - HWPSTATE - Hardware P-State Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_HWPSTATE RT_BIT_32(7) +/** Bit 8 - TSCINVAR - TSC Invariant. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR RT_BIT_32(8) +/** Bit 9 - CPB - TSC Invariant. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_CPB RT_BIT_32(9) +/** Bit 10 - EffFreqRO - MPERF/APERF. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_EFRO RT_BIT_32(10) +/** Bit 11 - PFI - Processor feedback interface (see EAX). */ +#define X86_CPUID_AMD_ADVPOWER_EDX_PFI RT_BIT_32(11) +/** Bit 12 - PA - Processor accumulator (MSR c001_007a). */ +#define X86_CPUID_AMD_ADVPOWER_EDX_PA RT_BIT_32(12) +/** @} */ + + +/** @name CPUID AMD extended feature extensions ID (EBX). + * CPUID query with EAX=0x80000008. + * @{ + */ +/** Bit 0 - CLZERO - Clear zero instruction. */ +#define X86_CPUID_AMD_EFEID_EBX_CLZERO RT_BIT_32(0) +/** Bit 1 - IRPerf - Instructions retired count support. */ +#define X86_CPUID_AMD_EFEID_EBX_IRPERF RT_BIT_32(1) +/** Bit 2 - XSaveErPtr - Always XSAVE* and XRSTR* error pointers. */ +#define X86_CPUID_AMD_EFEID_EBX_XSAVE_ER_PTR RT_BIT_32(2) +/** Bit 4 - RDPRU - Supports the RDPRU instruction. */ +#define X86_CPUID_AMD_EFEID_EBX_RDPRU RT_BIT_32(4) +/** Bit 8 - MCOMMIT - Supports the MCOMMIT instruction. */ +#define X86_CPUID_AMD_EFEID_EBX_MCOMMIT RT_BIT_32(8) +/* AMD pipeline length: 9 feature bits ;-) */ +/** Bit 12 - IBPB - Supports the IBPB command in IA32_PRED_CMD. */ +#define X86_CPUID_AMD_EFEID_EBX_IBPB RT_BIT_32(12) +/** Bit 14 - IBRS - Supports the IBRS bit in IA32_SPEC_CTRL. */ +#define X86_CPUID_AMD_EFEID_EBX_IBRS RT_BIT_32(14) +/** Bit 15 - STIBP - Supports the STIBP bit in IA32_SPEC_CTRL. */ +#define X86_CPUID_AMD_EFEID_EBX_STIBP RT_BIT_32(15) +/** Bit 16 - IBRS always on mode - IBRS should be set once during boot only. */ +#define X86_CPUID_AMD_EFEID_EBX_IBRS_ALWAYS_ON RT_BIT_32(16) +/** Bit 17 - STIBP always on mode - STIBP should be set once during boot only. */ +#define X86_CPUID_AMD_EFEID_EBX_STIBP_ALWAYS_ON RT_BIT_32(17) +/** Bit 18 - IBRS preferred - IBRS is preferred over software mitigations. */ +#define X86_CPUID_AMD_EFEID_EBX_IBRS_PREFERRED RT_BIT_32(18) +/** Bit 24 - Speculative Store Bypass Disable supported in SPEC_CTL. */ +#define X86_CPUID_AMD_EFEID_EBX_SPEC_CTRL_SSBD RT_BIT_32(24) +/** Bit 25 - Speculative Store Bypass Disable supported in VIRT_SPEC_CTL. */ +#define X86_CPUID_AMD_EFEID_EBX_VIRT_SPEC_CTRL_SSBD RT_BIT_32(25) +/** Bit 26 - Speculative Store Bypass Disable not required. */ +#define X86_CPUID_AMD_EFEID_EBX_NO_SSBD_REQUIRED RT_BIT_32(26) +/** @} */ + + +/** @name CPUID AMD SVM Feature information. + * CPUID query with EAX=0x8000000a. + * @{ + */ +/** Bit 0 - NP - Nested Paging supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_NESTED_PAGING RT_BIT(0) +/** Bit 1 - LbrVirt - Support for saving five debug MSRs. */ +#define X86_CPUID_SVM_FEATURE_EDX_LBR_VIRT RT_BIT(1) +/** Bit 2 - SVML - SVM locking bit supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_SVM_LOCK RT_BIT(2) +/** Bit 3 - NRIPS - Saving the next instruction pointer is supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE RT_BIT(3) +/** Bit 4 - TscRateMsr - Support for MSR TSC ratio. */ +#define X86_CPUID_SVM_FEATURE_EDX_TSC_RATE_MSR RT_BIT(4) +/** Bit 5 - VmcbClean - Support VMCB clean bits. */ +#define X86_CPUID_SVM_FEATURE_EDX_VMCB_CLEAN RT_BIT(5) +/** Bit 6 - FlushByAsid - Indicate TLB flushing for current ASID only, and that + * VMCB.TLB_Control is supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID RT_BIT(6) +/** Bit 7 - DecodeAssists - Indicate decode assists is supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSISTS RT_BIT(7) +/** Bit 10 - PauseFilter - Indicates support for the PAUSE intercept filter. */ +#define X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER RT_BIT(10) +/** Bit 12 - PauseFilterThreshold - Indicates support for the PAUSE + * intercept filter cycle count threshold. */ +#define X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER_THRESHOLD RT_BIT(12) +/** Bit 13 - AVIC - Advanced Virtual Interrupt Controller. */ +#define X86_CPUID_SVM_FEATURE_EDX_AVIC RT_BIT(13) +/** Bit 15 - VMSAVEvirt - Supports virtualized VMSAVE/VMLOAD. */ +#define X86_CPUID_SVM_FEATURE_EDX_VIRT_VMSAVE_VMLOAD RT_BIT(15) +/** Bit 16 - VGIF - Supports virtualized GIF. */ +#define X86_CPUID_SVM_FEATURE_EDX_VGIF RT_BIT(16) +/** Bit 17 - GMET - Supports Guest Mode Execute Trap Extensions. */ +#define X86_CPUID_SVM_FEATURE_EDX_GMET RT_BIT(17) +/** Bit 19 - SSSCheck - SVM supervisor shadow stack restrictions. */ +#define X86_CPUID_SVM_FEATURE_EDX_SSSCHECK RT_BIT(19) +/** Bit 20 - SpecCtrl - Supports SPEC_CTRL Virtualization. */ +#define X86_CPUID_SVM_FEATURE_EDX_SPEC_CTRL RT_BIT(20) +/** Bit 23 - HOST_MCE_OVERRIDE - Supports host \#MC exception override. */ +#define X86_CPUID_SVM_FEATURE_EDX_HOST_MCE_OVERRIDE RT_BIT(23) +/** Bit 24 - TlbiCtl - Supports INVLPGB/TLBSYNC in VMCB and TLBSYNC intercept. */ +#define X86_CPUID_SVM_FEATURE_EDX_TLBICTL RT_BIT(24) +/** @} */ + + +/** @name CR0 + * @remarks The 286 (MSW), 386 and 486 ignores attempts at setting + * reserved flags. + * @{ */ +/** Bit 0 - PE - Protection Enabled */ +#define X86_CR0_PE RT_BIT_32(0) +#define X86_CR0_PROTECTION_ENABLE RT_BIT_32(0) +/** Bit 1 - MP - Monitor Coprocessor */ +#define X86_CR0_MP RT_BIT_32(1) +#define X86_CR0_MONITOR_COPROCESSOR RT_BIT_32(1) +/** Bit 2 - EM - Emulation. */ +#define X86_CR0_EM RT_BIT_32(2) +#define X86_CR0_EMULATE_FPU RT_BIT_32(2) +/** Bit 3 - TS - Task Switch. */ +#define X86_CR0_TS RT_BIT_32(3) +#define X86_CR0_TASK_SWITCH RT_BIT_32(3) +/** Bit 4 - ET - Extension flag. (386, 'hardcoded' to 1 on 486+) */ +#define X86_CR0_ET RT_BIT_32(4) +#define X86_CR0_EXTENSION_TYPE RT_BIT_32(4) +/** Bit 5 - NE - Numeric error (486+). */ +#define X86_CR0_NE RT_BIT_32(5) +#define X86_CR0_NUMERIC_ERROR RT_BIT_32(5) +/** Bit 16 - WP - Write Protect (486+). */ +#define X86_CR0_WP RT_BIT_32(16) +#define X86_CR0_WRITE_PROTECT RT_BIT_32(16) +/** Bit 18 - AM - Alignment Mask (486+). */ +#define X86_CR0_AM RT_BIT_32(18) +#define X86_CR0_ALIGMENT_MASK RT_BIT_32(18) +/** Bit 29 - NW - Not Write-though (486+). */ +#define X86_CR0_NW RT_BIT_32(29) +#define X86_CR0_NOT_WRITE_THROUGH RT_BIT_32(29) +/** Bit 30 - WP - Cache Disable (486+). */ +#define X86_CR0_CD RT_BIT_32(30) +#define X86_CR0_CACHE_DISABLE RT_BIT_32(30) +/** Bit 31 - PG - Paging. */ +#define X86_CR0_PG RT_BIT_32(31) +#define X86_CR0_PAGING RT_BIT_32(31) +#define X86_CR0_BIT_PG 31 /**< Bit number of X86_CR0_PG */ +/** @} */ + + +/** @name CR3 + * @{ */ +/** Bit 3 - PWT - Page-level Writes Transparent. */ +#define X86_CR3_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page-level Cache Disable. */ +#define X86_CR3_PCD RT_BIT_32(4) +/** Bits 12-31 - - Page directory page number. */ +#define X86_CR3_PAGE_MASK (0xfffff000) +/** Bits 5-31 - - PAE Page directory page number. */ +#define X86_CR3_PAE_PAGE_MASK (0xffffffe0) +/** Bits 12-51 - - AMD64 PML4 page number. + * @note This is a maxed out mask, the actual acceptable CR3 value can + * be lower depending on the PhysAddrSize from CPUID Fn8000_0008. */ +#define X86_CR3_AMD64_PAGE_MASK UINT64_C(0x000ffffffffff000) +/** Bits 12-51 - - Intel EPT PML4 page number (EPTP). + * @note This is a maxed out mask, the actual acceptable CR3/EPTP value can + * be lower depending on the PhysAddrSize from CPUID Fn8000_0008. */ +#define X86_CR3_EPT_PAGE_MASK UINT64_C(0x000ffffffffff000) +/** @} */ + + +/** @name CR4 + * @{ */ +/** Bit 0 - VME - Virtual-8086 Mode Extensions. */ +#define X86_CR4_VME RT_BIT_32(0) +/** Bit 1 - PVI - Protected-Mode Virtual Interrupts. */ +#define X86_CR4_PVI RT_BIT_32(1) +/** Bit 2 - TSD - Time Stamp Disable. */ +#define X86_CR4_TSD RT_BIT_32(2) +/** Bit 3 - DE - Debugging Extensions. */ +#define X86_CR4_DE RT_BIT_32(3) +/** Bit 4 - PSE - Page Size Extension. */ +#define X86_CR4_PSE RT_BIT_32(4) +/** Bit 5 - PAE - Physical Address Extension. */ +#define X86_CR4_PAE RT_BIT_32(5) +/** Bit 6 - MCE - Machine-Check Enable. */ +#define X86_CR4_MCE RT_BIT_32(6) +/** Bit 7 - PGE - Page Global Enable. */ +#define X86_CR4_PGE RT_BIT_32(7) +/** Bit 8 - PCE - Performance-Monitoring Counter Enable. */ +#define X86_CR4_PCE RT_BIT_32(8) +/** Bit 9 - OSFXSR - Operating System Support for FXSAVE and FXRSTORE instructions. */ +#define X86_CR4_OSFXSR RT_BIT_32(9) +/** Bit 10 - OSXMMEEXCPT - Operating System Support for Unmasked SIMD Floating-Point Exceptions. */ +#define X86_CR4_OSXMMEEXCPT RT_BIT_32(10) +/** Bit 11 - UMIP - User-Mode Instruction Prevention. */ +#define X86_CR4_UMIP RT_BIT_32(11) +/** Bit 13 - VMXE - VMX mode is enabled. */ +#define X86_CR4_VMXE RT_BIT_32(13) +/** Bit 14 - SMXE - Safer Mode Extensions Enabled. */ +#define X86_CR4_SMXE RT_BIT_32(14) +/** Bit 16 - FSGSBASE - Read/write FSGSBASE instructions Enable. */ +#define X86_CR4_FSGSBASE RT_BIT_32(16) +/** Bit 17 - PCIDE - Process-Context Identifiers Enabled. */ +#define X86_CR4_PCIDE RT_BIT_32(17) +/** Bit 18 - OSXSAVE - Operating System Support for XSAVE and processor + * extended states. */ +#define X86_CR4_OSXSAVE RT_BIT_32(18) +/** Bit 20 - SMEP - Supervisor-mode Execution Prevention enabled. */ +#define X86_CR4_SMEP RT_BIT_32(20) +/** Bit 21 - SMAP - Supervisor-mode Access Prevention enabled. */ +#define X86_CR4_SMAP RT_BIT_32(21) +/** Bit 22 - PKE - Protection Key Enable. */ +#define X86_CR4_PKE RT_BIT_32(22) +/** Bit 23 - CET - Control-flow Enhancement Technology enabled. */ +#define X86_CR4_CET RT_BIT_32(23) +/** @} */ + + +/** @name DR6 + * @{ */ +/** Bit 0 - B0 - Breakpoint 0 condition detected. */ +#define X86_DR6_B0 RT_BIT_32(0) +/** Bit 1 - B1 - Breakpoint 1 condition detected. */ +#define X86_DR6_B1 RT_BIT_32(1) +/** Bit 2 - B2 - Breakpoint 2 condition detected. */ +#define X86_DR6_B2 RT_BIT_32(2) +/** Bit 3 - B3 - Breakpoint 3 condition detected. */ +#define X86_DR6_B3 RT_BIT_32(3) +/** Mask of all the Bx bits. */ +#define X86_DR6_B_MASK UINT64_C(0x0000000f) +/** Bit 13 - BD - Debug register access detected. Corresponds to the X86_DR7_GD bit. */ +#define X86_DR6_BD RT_BIT_32(13) +/** Bit 14 - BS - Single step */ +#define X86_DR6_BS RT_BIT_32(14) +/** Bit 15 - BT - Task switch. (TSS T bit.) */ +#define X86_DR6_BT RT_BIT_32(15) +/** Bit 16 - RTM - Cleared if debug exception inside RTM (@sa X86_DR7_RTM). */ +#define X86_DR6_RTM RT_BIT_32(16) +/** Value of DR6 after powerup/reset. */ +#define X86_DR6_INIT_VAL UINT64_C(0xffff0ff0) +/** Bits which must be 1s in DR6. */ +#define X86_DR6_RA1_MASK UINT64_C(0xffff0ff0) +/** Bits which must be 1s in DR6, when RTM is supported. */ +#define X86_DR6_RA1_MASK_RTM UINT64_C(0xfffe0ff0) +/** Bits which must be 0s in DR6. */ +#define X86_DR6_RAZ_MASK RT_BIT_64(12) +/** Bits which must be 0s on writes to DR6. */ +#define X86_DR6_MBZ_MASK UINT64_C(0xffffffff00000000) +/** @} */ + +/** Get the DR6.Bx bit for a the given breakpoint. */ +#define X86_DR6_B(iBp) RT_BIT_64(iBp) + + +/** @name DR7 + * @{ */ +/** Bit 0 - L0 - Local breakpoint enable. Cleared on task switch. */ +#define X86_DR7_L0 RT_BIT_32(0) +/** Bit 1 - G0 - Global breakpoint enable. Not cleared on task switch. */ +#define X86_DR7_G0 RT_BIT_32(1) +/** Bit 2 - L1 - Local breakpoint enable. Cleared on task switch. */ +#define X86_DR7_L1 RT_BIT_32(2) +/** Bit 3 - G1 - Global breakpoint enable. Not cleared on task switch. */ +#define X86_DR7_G1 RT_BIT_32(3) +/** Bit 4 - L2 - Local breakpoint enable. Cleared on task switch. */ +#define X86_DR7_L2 RT_BIT_32(4) +/** Bit 5 - G2 - Global breakpoint enable. Not cleared on task switch. */ +#define X86_DR7_G2 RT_BIT_32(5) +/** Bit 6 - L3 - Local breakpoint enable. Cleared on task switch. */ +#define X86_DR7_L3 RT_BIT_32(6) +/** Bit 7 - G3 - Global breakpoint enable. Not cleared on task switch. */ +#define X86_DR7_G3 RT_BIT_32(7) +/** Bit 8 - LE - Local breakpoint exact. (Not supported (read ignored) by P6 and later.) */ +#define X86_DR7_LE RT_BIT_32(8) +/** Bit 9 - GE - Global breakpoint exact. (Not supported (read ignored) by P6 and later.) */ +#define X86_DR7_GE RT_BIT_32(9) + +/** L0, L1, L2, and L3. */ +#define X86_DR7_LE_ALL UINT64_C(0x0000000000000055) +/** L0, L1, L2, and L3. */ +#define X86_DR7_GE_ALL UINT64_C(0x00000000000000aa) + +/** Bit 11 - RTM - Enable advanced debugging of RTM transactions. + * Requires IA32_DEBUGCTL.RTM=1 too, and RTM HW support of course. */ +#define X86_DR7_RTM RT_BIT_32(11) +/** Bit 12 - IR (ICE) - Interrupt redirection on Pentium. When set, the in + * Circuit Emulator (ICE) will break emulation on breakpoints and stuff. + * May cause CPU hang if enabled without ICE attached when the ICEBP/INT1 + * instruction is executed. + * @see http://www.rcollins.org/secrets/DR7.html */ +#define X86_DR7_ICE_IR RT_BIT_32(12) +/** Bit 13 - GD - General detect enable. Enables emulators to get exceptions when + * any DR register is accessed. */ +#define X86_DR7_GD RT_BIT_32(13) +/** Bit 14 - TR1 (ICE) - Code discontinuity trace for use with ICE on + * Pentium. */ +#define X86_DR7_ICE_TR1 RT_BIT_32(14) +/** Bit 15 - TR2 (ICE) - Controls unknown ICE trace feature of the pentium. */ +#define X86_DR7_ICE_TR2 RT_BIT_32(15) +/** Bit 16 & 17 - R/W0 - Read write field 0. Values X86_DR7_RW_*. */ +#define X86_DR7_RW0_MASK (3 << 16) +/** Bit 18 & 19 - LEN0 - Length field 0. Values X86_DR7_LEN_*. */ +#define X86_DR7_LEN0_MASK (3 << 18) +/** Bit 20 & 21 - R/W1 - Read write field 0. Values X86_DR7_RW_*. */ +#define X86_DR7_RW1_MASK (3 << 20) +/** Bit 22 & 23 - LEN1 - Length field 0. Values X86_DR7_LEN_*. */ +#define X86_DR7_LEN1_MASK (3 << 22) +/** Bit 24 & 25 - R/W2 - Read write field 0. Values X86_DR7_RW_*. */ +#define X86_DR7_RW2_MASK (3 << 24) +/** Bit 26 & 27 - LEN2 - Length field 0. Values X86_DR7_LEN_*. */ +#define X86_DR7_LEN2_MASK (3 << 26) +/** Bit 28 & 29 - R/W3 - Read write field 0. Values X86_DR7_RW_*. */ +#define X86_DR7_RW3_MASK (3 << 28) +/** Bit 30 & 31 - LEN3 - Length field 0. Values X86_DR7_LEN_*. */ +#define X86_DR7_LEN3_MASK (3 << 30) + +/** Bits which reads as 1s. */ +#define X86_DR7_RA1_MASK RT_BIT_32(10) +/** Bits which reads as zeros. These are related to ICE (bits 12, 14, 15). */ +#define X86_DR7_RAZ_MASK UINT64_C(0x0000d800) +/** Bits which must be 0s when writing to DR7. */ +#define X86_DR7_MBZ_MASK UINT64_C(0xffffffff00000000) + +/** Calcs the L bit of Nth breakpoint. + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_L(iBp) ( UINT32_C(1) << (iBp * 2) ) + +/** Calcs the G bit of Nth breakpoint. + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_G(iBp) ( UINT32_C(1) << (iBp * 2 + 1) ) + +/** Calcs the L and G bits of Nth breakpoint. + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_L_G(iBp) ( UINT32_C(3) << (iBp * 2) ) + +/** @name Read/Write values. + * @{ */ +/** Break on instruction fetch only. */ +#define X86_DR7_RW_EO UINT32_C(0) +/** Break on write only. */ +#define X86_DR7_RW_WO UINT32_C(1) +/** Break on I/O read/write. This is only defined if CR4.DE is set. */ +#define X86_DR7_RW_IO UINT32_C(2) +/** Break on read or write (but not instruction fetches). */ +#define X86_DR7_RW_RW UINT32_C(3) +/** @} */ + +/** Shifts a X86_DR7_RW_* value to its right place. + * @param iBp The breakpoint number [0..3]. + * @param fRw One of the X86_DR7_RW_* value. + */ +#define X86_DR7_RW(iBp, fRw) ( (fRw) << ((iBp) * 4 + 16) ) + +/** Fetch the R/Wx bits for a given breakpoint (so it can be compared with + * one of the X86_DR7_RW_XXX constants). + * + * @returns X86_DR7_RW_XXX + * @param uDR7 DR7 value + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_GET_RW(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 16) ) & UINT32_C(3) ) + +/** R/W0, R/W1, R/W2, and R/W3. */ +#define X86_DR7_RW_ALL_MASKS UINT32_C(0x33330000) + +#ifndef VBOX_FOR_DTRACE_LIB +/** Checks the RW and LEN fields are set up for an instruction breakpoint. + * @note This does not check if it's enabled. */ +# define X86_DR7_IS_EO_CFG(a_uDR7, a_iBp) ( ((a_uDR7) & (UINT32_C(0x000f0000) << ((a_iBp) * 4))) == 0 ) +/** Checks if an instruction breakpoint is enabled and configured correctly. + * @sa X86_DR7_IS_EO_CFG, X86_DR7_ANY_EO_ENABLED */ +# define X86_DR7_IS_EO_ENABLED(a_uDR7, a_iBp) \ + ( ((a_uDR7) & (UINT32_C(0x03) << ((a_iBp) * 2))) != 0 && X86_DR7_IS_EO_CFG(a_uDR7, a_iBp) ) +/** Checks if there are any instruction fetch breakpoint types configured in the + * RW and LEN registers. + * @sa X86_DR7_IS_EO_CFG, X86_DR7_IS_EO_ENABLED */ +# define X86_DR7_ANY_EO_ENABLED(a_uDR7) \ + ( (((a_uDR7) & UINT32_C(0x03)) != 0 && ((a_uDR7) & UINT32_C(0x000f0000)) == 0) \ + || (((a_uDR7) & UINT32_C(0x0c)) != 0 && ((a_uDR7) & UINT32_C(0x00f00000)) == 0) \ + || (((a_uDR7) & UINT32_C(0x30)) != 0 && ((a_uDR7) & UINT32_C(0x0f000000)) == 0) \ + || (((a_uDR7) & UINT32_C(0xc0)) != 0 && ((a_uDR7) & UINT32_C(0xf0000000)) == 0) ) + +/** Checks if there are any I/O breakpoint types configured in the RW + * registers. Does NOT check if these are enabled, sorry. */ +# define X86_DR7_ANY_RW_IO(uDR7) \ + ( ( UINT32_C(0x22220000) & (uDR7) ) /* any candidates? */ \ + && ( ( (UINT32_C(0x22220000) & (uDR7) ) >> 1 ) & ~(uDR7) ) ) +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x33330000)) == 0); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x22220000)) == 1); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x32320000)) == 1); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x23230000)) == 1); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00000000)) == 0); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00010000)) == 0); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00020000)) == 1); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00030000)) == 0); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00040000)) == 0); + +#endif /* !VBOX_FOR_DTRACE_LIB */ + +/** @name Length values. + * @{ */ +#define X86_DR7_LEN_BYTE UINT32_C(0) +#define X86_DR7_LEN_WORD UINT32_C(1) +#define X86_DR7_LEN_QWORD UINT32_C(2) /**< AMD64 long mode only. */ +#define X86_DR7_LEN_DWORD UINT32_C(3) +/** @} */ + +/** Shifts a X86_DR7_LEN_* value to its right place. + * @param iBp The breakpoint number [0..3]. + * @param cb One of the X86_DR7_LEN_* values. + */ +#define X86_DR7_LEN(iBp, cb) ( (cb) << ((iBp) * 4 + 18) ) + +/** Fetch the breakpoint length bits from the DR7 value. + * @param uDR7 DR7 value + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_GET_LEN(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 18) ) & UINT32_C(0x3) ) + +/** Mask used to check if any breakpoints are enabled. */ +#define X86_DR7_ENABLED_MASK UINT32_C(0x000000ff) + +/** LEN0, LEN1, LEN2, and LEN3. */ +#define X86_DR7_LEN_ALL_MASKS UINT32_C(0xcccc0000) +/** R/W0, R/W1, R/W2, R/W3,LEN0, LEN1, LEN2, and LEN3. */ +#define X86_DR7_RW_LEN_ALL_MASKS UINT32_C(0xffff0000) + +/** Value of DR7 after powerup/reset. */ +#define X86_DR7_INIT_VAL 0x400 +/** @} */ + + +/** @name Machine Specific Registers + * @{ + */ +/** Machine check address register (P5). */ +#define MSR_P5_MC_ADDR UINT32_C(0x00000000) +/** Machine check type register (P5). */ +#define MSR_P5_MC_TYPE UINT32_C(0x00000001) +/** Time Stamp Counter. */ +#define MSR_IA32_TSC 0x10 +#define MSR_IA32_CESR UINT32_C(0x00000011) +#define MSR_IA32_CTR0 UINT32_C(0x00000012) +#define MSR_IA32_CTR1 UINT32_C(0x00000013) + +#define MSR_IA32_PLATFORM_ID 0x17 + +#ifndef MSR_IA32_APICBASE /* qemu cpu.h kludge */ +# define MSR_IA32_APICBASE 0x1b +/** Local APIC enabled. */ +# define MSR_IA32_APICBASE_EN RT_BIT_64(11) +/** X2APIC enabled (requires the EN bit to be set). */ +# define MSR_IA32_APICBASE_EXTD RT_BIT_64(10) +/** The processor is the boot strap processor (BSP). */ +# define MSR_IA32_APICBASE_BSP RT_BIT_64(8) +/** Minimum base address mask, consult CPUID leaf 0x80000008 for the actual + * width. */ +# define MSR_IA32_APICBASE_BASE_MIN UINT64_C(0x0000000ffffff000) +/** The default physical base address of the APIC. */ +# define MSR_IA32_APICBASE_ADDR UINT64_C(0x00000000fee00000) +/** Gets the physical base address from the MSR. */ +# define MSR_IA32_APICBASE_GET_ADDR(a_Msr) ((a_Msr) & X86_PAGE_4K_BASE_MASK) +#endif + +/** Undocumented intel MSR for reporting thread and core counts. + * Judging from the XNU sources, it seems to be introduced in Nehalem. The + * first 16 bits is the thread count. The next 16 bits the core count, except + * on Westmere where it seems it's only the next 4 bits for some reason. */ +#define MSR_CORE_THREAD_COUNT 0x35 + +/** CPU Feature control. */ +#define MSR_IA32_FEATURE_CONTROL 0x3A +/** Feature control - Lock MSR from writes (R/W0). */ +#define MSR_IA32_FEATURE_CONTROL_LOCK RT_BIT_64(0) +/** Feature control - Enable VMX inside SMX operation (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SMX_VMXON RT_BIT_64(1) +/** Feature control - Enable VMX outside SMX operation (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_VMXON RT_BIT_64(2) +/** Feature control - SENTER local functions enable (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_0 RT_BIT_64(8) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_1 RT_BIT_64(9) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_2 RT_BIT_64(10) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_3 RT_BIT_64(11) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_4 RT_BIT_64(12) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_5 RT_BIT_64(13) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_6 RT_BIT_64(14) +/** Feature control - SENTER global enable (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SENTER_GLOBAL_EN RT_BIT_64(15) +/** Feature control - SGX launch control enable (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SGX_LAUNCH_EN RT_BIT_64(17) +/** Feature control - SGX global enable (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SGX_GLOBAL_EN RT_BIT_64(18) +/** Feature control - LMCE on (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_LMCE RT_BIT_64(20) + +/** Per-processor TSC adjust MSR. */ +#define MSR_IA32_TSC_ADJUST 0x3B + +/** Spectre control register. + * Logical processor scope. Reset value 0, unaffected by SIPI & INIT. */ +#define MSR_IA32_SPEC_CTRL 0x48 +/** IBRS - Indirect branch restricted speculation. */ +#define MSR_IA32_SPEC_CTRL_F_IBRS RT_BIT_32(0) +/** STIBP - Single thread indirect branch predictors. */ +#define MSR_IA32_SPEC_CTRL_F_STIBP RT_BIT_32(1) +/** SSBD - Speculative Store Bypass Disable. */ +#define MSR_IA32_SPEC_CTRL_F_SSBD RT_BIT_32(2) + +/** Prediction command register. + * Write only, logical processor scope, no state since write only. */ +#define MSR_IA32_PRED_CMD 0x49 +/** IBPB - Indirect branch prediction barrie when written as 1. */ +#define MSR_IA32_PRED_CMD_F_IBPB RT_BIT_32(0) + +/** BIOS update trigger (microcode update). */ +#define MSR_IA32_BIOS_UPDT_TRIG 0x79 + +/** BIOS update signature (microcode). */ +#define MSR_IA32_BIOS_SIGN_ID 0x8B + +/** SMM monitor control. */ +#define MSR_IA32_SMM_MONITOR_CTL 0x9B +/** SMM control - Valid. */ +#define MSR_IA32_SMM_MONITOR_VALID RT_BIT_64(0) +/** SMM control - VMXOFF unblocks SMI. */ +#define MSR_IA32_SMM_MONITOR_VMXOFF_UNBLOCK_SMI RT_BIT_64(2) +/** SMM control - MSEG base physical address. */ +#define MSR_IA32_SMM_MONITOR_MSGEG_PHYSADDR(a) (((a) >> 12) & UINT64_C(0xfffff)) + +/** SMBASE - Base address of SMRANGE image (Read-only, SMM only). */ +#define MSR_IA32_SMBASE 0x9E + +/** General performance counter no. 0. */ +#define MSR_IA32_PMC0 0xC1 +/** General performance counter no. 1. */ +#define MSR_IA32_PMC1 0xC2 +/** General performance counter no. 2. */ +#define MSR_IA32_PMC2 0xC3 +/** General performance counter no. 3. */ +#define MSR_IA32_PMC3 0xC4 +/** General performance counter no. 4. */ +#define MSR_IA32_PMC4 0xC5 +/** General performance counter no. 5. */ +#define MSR_IA32_PMC5 0xC6 +/** General performance counter no. 6. */ +#define MSR_IA32_PMC6 0xC7 +/** General performance counter no. 7. */ +#define MSR_IA32_PMC7 0xC8 + +/** Nehalem power control. */ +#define MSR_IA32_PLATFORM_INFO 0xCE + +/** Get FSB clock status (Intel-specific). */ +#define MSR_IA32_FSB_CLOCK_STS 0xCD + +/** C-State configuration control. Intel specific: Nehalem, Sandy Bridge. */ +#define MSR_PKG_CST_CONFIG_CONTROL UINT32_C(0x000000e2) + +/** C0 Maximum Frequency Clock Count */ +#define MSR_IA32_MPERF 0xE7 +/** C0 Actual Frequency Clock Count */ +#define MSR_IA32_APERF 0xE8 + +/** MTRR Capabilities. */ +#define MSR_IA32_MTRR_CAP 0xFE + +/** Architecture capabilities (bugfixes). */ +#define MSR_IA32_ARCH_CAPABILITIES UINT32_C(0x10a) +/** CPU is no subject to meltdown problems. */ +#define MSR_IA32_ARCH_CAP_F_RDCL_NO RT_BIT_32(0) +/** CPU has better IBRS and you can leave it on all the time. */ +#define MSR_IA32_ARCH_CAP_F_IBRS_ALL RT_BIT_32(1) +/** CPU has return stack buffer (RSB) override. */ +#define MSR_IA32_ARCH_CAP_F_RSBO RT_BIT_32(2) +/** Virtual machine monitors need not flush the level 1 data cache on VM entry. + * This is also the case when MSR_IA32_ARCH_CAP_F_RDCL_NO is set. */ +#define MSR_IA32_ARCH_CAP_F_VMM_NEED_NOT_FLUSH_L1D RT_BIT_32(3) +/** CPU does not suffer from MDS issues. */ +#define MSR_IA32_ARCH_CAP_F_MDS_NO RT_BIT_32(4) + +/** Flush command register. */ +#define MSR_IA32_FLUSH_CMD UINT32_C(0x10b) +/** Flush the level 1 data cache when this bit is written. */ +#define MSR_IA32_FLUSH_CMD_F_L1D RT_BIT_32(0) + +/** Cache control/info. */ +#define MSR_BBL_CR_CTL3 UINT32_C(0x11e) + +#ifndef MSR_IA32_SYSENTER_CS /* qemu cpu.h kludge */ +/** SYSENTER_CS - the R0 CS, indirectly giving R0 SS, R3 CS and R3 DS. + * R0 SS == CS + 8 + * R3 CS == CS + 16 + * R3 SS == CS + 24 + */ +#define MSR_IA32_SYSENTER_CS 0x174 +/** SYSENTER_ESP - the R0 ESP. */ +#define MSR_IA32_SYSENTER_ESP 0x175 +/** SYSENTER_EIP - the R0 EIP. */ +#define MSR_IA32_SYSENTER_EIP 0x176 +#endif + +/** Machine Check Global Capabilities Register. */ +#define MSR_IA32_MCG_CAP 0x179 +/** Machine Check Global Status Register. */ +#define MSR_IA32_MCG_STATUS 0x17A +/** Machine Check Global Control Register. */ +#define MSR_IA32_MCG_CTRL 0x17B + +/** Page Attribute Table. */ +#define MSR_IA32_CR_PAT 0x277 +/** Default PAT MSR value on processor powerup / reset (see Intel spec. 11.12.4 + * "Programming the PAT", AMD spec. 7.8.2 "PAT Indexing") */ +#define MSR_IA32_CR_PAT_INIT_VAL UINT64_C(0x0007040600070406) + +/** Performance event select MSRs. (Intel only) */ +#define MSR_IA32_PERFEVTSEL0 0x186 +#define MSR_IA32_PERFEVTSEL1 0x187 +#define MSR_IA32_PERFEVTSEL2 0x188 +#define MSR_IA32_PERFEVTSEL3 0x189 + +/** Flexible ratio, seems to be undocumented, used by XNU (tsc.c). + * The 16th bit whether flex ratio is being used, in which case bits 15:8 + * holds a ratio that Apple takes for TSC granularity. + * + * @note This MSR conflicts the P4 MSR_MCG_R12 register. */ +#define MSR_FLEX_RATIO 0x194 +/** Performance state value and starting with Intel core more. + * Apple uses the >=core features to determine TSC granularity on older CPUs. */ +#define MSR_IA32_PERF_STATUS 0x198 +#define MSR_IA32_PERF_CTL 0x199 +#define MSR_IA32_THERM_STATUS 0x19c + +/** Offcore response event select registers. */ +#define MSR_OFFCORE_RSP_0 0x1a6 +#define MSR_OFFCORE_RSP_1 0x1a7 + +/** Enable misc. processor features (R/W). */ +#define MSR_IA32_MISC_ENABLE 0x1A0 +/** Enable fast-strings feature (for REP MOVS and REP STORS). */ +#define MSR_IA32_MISC_ENABLE_FAST_STRINGS RT_BIT_64(0) +/** Automatic Thermal Control Circuit Enable (R/W). */ +#define MSR_IA32_MISC_ENABLE_TCC RT_BIT_64(3) +/** Performance Monitoring Available (R). */ +#define MSR_IA32_MISC_ENABLE_PERF_MON RT_BIT_64(7) +/** Branch Trace Storage Unavailable (R/O). */ +#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL RT_BIT_64(11) +/** Precise Event Based Sampling (PEBS) Unavailable (R/O). */ +#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL RT_BIT_64(12) +/** Enhanced Intel SpeedStep Technology Enable (R/W). */ +#define MSR_IA32_MISC_ENABLE_SST_ENABLE RT_BIT_64(16) +/** If MONITOR/MWAIT is supported (R/W). */ +#define MSR_IA32_MISC_ENABLE_MONITOR RT_BIT_64(18) +/** Limit CPUID Maxval to 3 leafs (R/W). */ +#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID RT_BIT_64(22) +/** When set to 1, xTPR messages are disabled (R/W). */ +#define MSR_IA32_MISC_ENABLE_XTPR_MSG_DISABLE RT_BIT_64(23) +/** When set to 1, the Execute Disable Bit feature (XD Bit) is disabled (R/W). */ +#define MSR_IA32_MISC_ENABLE_XD_DISABLE RT_BIT_64(34) + +/** Trace/Profile Resource Control (R/W) */ +#define MSR_IA32_DEBUGCTL UINT32_C(0x000001d9) +/** Last branch record. */ +#define MSR_IA32_DEBUGCTL_LBR RT_BIT_64(0) +/** Branch trace flag (single step on branches). */ +#define MSR_IA32_DEBUGCTL_BTF RT_BIT_64(1) +/** Performance monitoring pin control (AMD only). */ +#define MSR_IA32_DEBUGCTL_PB0 RT_BIT_64(2) +#define MSR_IA32_DEBUGCTL_PB1 RT_BIT_64(3) +#define MSR_IA32_DEBUGCTL_PB2 RT_BIT_64(4) +#define MSR_IA32_DEBUGCTL_PB3 RT_BIT_64(5) +/** Trace message enable (Intel only). */ +#define MSR_IA32_DEBUGCTL_TR RT_BIT_64(6) +/** Branch trace store (Intel only). */ +#define MSR_IA32_DEBUGCTL_BTS RT_BIT_64(7) +/** Branch trace interrupt (Intel only). */ +#define MSR_IA32_DEBUGCTL_BTINT RT_BIT_64(8) +/** Branch trace off in privileged code (Intel only). */ +#define MSR_IA32_DEBUGCTL_BTS_OFF_OS RT_BIT_64(9) +/** Branch trace off in user code (Intel only). */ +#define MSR_IA32_DEBUGCTL_BTS_OFF_USER RT_BIT_64(10) +/** Freeze LBR on PMI flag (Intel only). */ +#define MSR_IA32_DEBUGCTL_FREEZE_LBR_ON_PMI RT_BIT_64(11) +/** Freeze PERFMON on PMI flag (Intel only). */ +#define MSR_IA32_DEBUGCTL_FREEZE_PERFMON_ON_PMI RT_BIT_64(12) +/** Freeze while SMM enabled (Intel only). */ +#define MSR_IA32_DEBUGCTL_FREEZE_WHILE_SMM_EM RT_BIT_64(14) +/** Advanced debugging of RTM regions (Intel only). */ +#define MSR_IA32_DEBUGCTL_RTM RT_BIT_64(15) +/** Debug control MSR valid bits (Intel only). */ +#define MSR_IA32_DEBUGCTL_VALID_MASK_INTEL ( MSR_IA32_DEBUGCTL_LBR | MSR_IA32_DEBUGCTL_BTF | MSR_IA32_DEBUGCTL_TR \ + | MSR_IA32_DEBUGCTL_BTS | MSR_IA32_DEBUGCTL_BTINT | MSR_IA32_DEBUGCTL_BTS_OFF_OS \ + | MSR_IA32_DEBUGCTL_BTS_OFF_USER | MSR_IA32_DEBUGCTL_FREEZE_LBR_ON_PMI \ + | MSR_IA32_DEBUGCTL_FREEZE_PERFMON_ON_PMI | MSR_IA32_DEBUGCTL_FREEZE_WHILE_SMM_EM \ + | MSR_IA32_DEBUGCTL_RTM) + +/** @name Last branch registers for P4 and Xeon, models 0 thru 2. + * @{ */ +#define MSR_P4_LASTBRANCH_0 0x1db +#define MSR_P4_LASTBRANCH_1 0x1dc +#define MSR_P4_LASTBRANCH_2 0x1dd +#define MSR_P4_LASTBRANCH_3 0x1de + +/** LBR Top-of-stack MSR (index to most recent record). */ +#define MSR_P4_LASTBRANCH_TOS 0x1da +/** @} */ + +/** @name Last branch registers for Core 2 and related Xeons. + * @{ */ +#define MSR_CORE2_LASTBRANCH_0_FROM_IP 0x40 +#define MSR_CORE2_LASTBRANCH_1_FROM_IP 0x41 +#define MSR_CORE2_LASTBRANCH_2_FROM_IP 0x42 +#define MSR_CORE2_LASTBRANCH_3_FROM_IP 0x43 + +#define MSR_CORE2_LASTBRANCH_0_TO_IP 0x60 +#define MSR_CORE2_LASTBRANCH_1_TO_IP 0x61 +#define MSR_CORE2_LASTBRANCH_2_TO_IP 0x62 +#define MSR_CORE2_LASTBRANCH_3_TO_IP 0x63 + +/** LBR Top-of-stack MSR (index to most recent record). */ +#define MSR_CORE2_LASTBRANCH_TOS 0x1c9 +/** @} */ + +/** @name Last branch registers. + * @{ */ +#define MSR_LASTBRANCH_0_FROM_IP 0x680 +#define MSR_LASTBRANCH_1_FROM_IP 0x681 +#define MSR_LASTBRANCH_2_FROM_IP 0x682 +#define MSR_LASTBRANCH_3_FROM_IP 0x683 +#define MSR_LASTBRANCH_4_FROM_IP 0x684 +#define MSR_LASTBRANCH_5_FROM_IP 0x685 +#define MSR_LASTBRANCH_6_FROM_IP 0x686 +#define MSR_LASTBRANCH_7_FROM_IP 0x687 +#define MSR_LASTBRANCH_8_FROM_IP 0x688 +#define MSR_LASTBRANCH_9_FROM_IP 0x689 +#define MSR_LASTBRANCH_10_FROM_IP 0x68a +#define MSR_LASTBRANCH_11_FROM_IP 0x68b +#define MSR_LASTBRANCH_12_FROM_IP 0x68c +#define MSR_LASTBRANCH_13_FROM_IP 0x68d +#define MSR_LASTBRANCH_14_FROM_IP 0x68e +#define MSR_LASTBRANCH_15_FROM_IP 0x68f +#define MSR_LASTBRANCH_16_FROM_IP 0x690 +#define MSR_LASTBRANCH_17_FROM_IP 0x691 +#define MSR_LASTBRANCH_18_FROM_IP 0x692 +#define MSR_LASTBRANCH_19_FROM_IP 0x693 +#define MSR_LASTBRANCH_20_FROM_IP 0x694 +#define MSR_LASTBRANCH_21_FROM_IP 0x695 +#define MSR_LASTBRANCH_22_FROM_IP 0x696 +#define MSR_LASTBRANCH_23_FROM_IP 0x697 +#define MSR_LASTBRANCH_24_FROM_IP 0x698 +#define MSR_LASTBRANCH_25_FROM_IP 0x699 +#define MSR_LASTBRANCH_26_FROM_IP 0x69a +#define MSR_LASTBRANCH_27_FROM_IP 0x69b +#define MSR_LASTBRANCH_28_FROM_IP 0x69c +#define MSR_LASTBRANCH_29_FROM_IP 0x69d +#define MSR_LASTBRANCH_30_FROM_IP 0x69e +#define MSR_LASTBRANCH_31_FROM_IP 0x69f + +#define MSR_LASTBRANCH_0_TO_IP 0x6c0 +#define MSR_LASTBRANCH_1_TO_IP 0x6c1 +#define MSR_LASTBRANCH_2_TO_IP 0x6c2 +#define MSR_LASTBRANCH_3_TO_IP 0x6c3 +#define MSR_LASTBRANCH_4_TO_IP 0x6c4 +#define MSR_LASTBRANCH_5_TO_IP 0x6c5 +#define MSR_LASTBRANCH_6_TO_IP 0x6c6 +#define MSR_LASTBRANCH_7_TO_IP 0x6c7 +#define MSR_LASTBRANCH_8_TO_IP 0x6c8 +#define MSR_LASTBRANCH_9_TO_IP 0x6c9 +#define MSR_LASTBRANCH_10_TO_IP 0x6ca +#define MSR_LASTBRANCH_11_TO_IP 0x6cb +#define MSR_LASTBRANCH_12_TO_IP 0x6cc +#define MSR_LASTBRANCH_13_TO_IP 0x6cd +#define MSR_LASTBRANCH_14_TO_IP 0x6ce +#define MSR_LASTBRANCH_15_TO_IP 0x6cf +#define MSR_LASTBRANCH_16_TO_IP 0x6d0 +#define MSR_LASTBRANCH_17_TO_IP 0x6d1 +#define MSR_LASTBRANCH_18_TO_IP 0x6d2 +#define MSR_LASTBRANCH_19_TO_IP 0x6d3 +#define MSR_LASTBRANCH_20_TO_IP 0x6d4 +#define MSR_LASTBRANCH_21_TO_IP 0x6d5 +#define MSR_LASTBRANCH_22_TO_IP 0x6d6 +#define MSR_LASTBRANCH_23_TO_IP 0x6d7 +#define MSR_LASTBRANCH_24_TO_IP 0x6d8 +#define MSR_LASTBRANCH_25_TO_IP 0x6d9 +#define MSR_LASTBRANCH_26_TO_IP 0x6da +#define MSR_LASTBRANCH_27_TO_IP 0x6db +#define MSR_LASTBRANCH_28_TO_IP 0x6dc +#define MSR_LASTBRANCH_29_TO_IP 0x6dd +#define MSR_LASTBRANCH_30_TO_IP 0x6de +#define MSR_LASTBRANCH_31_TO_IP 0x6df + +#define MSR_LASTBRANCH_0_INFO 0xdc0 +#define MSR_LASTBRANCH_1_INFO 0xdc1 +#define MSR_LASTBRANCH_2_INFO 0xdc2 +#define MSR_LASTBRANCH_3_INFO 0xdc3 +#define MSR_LASTBRANCH_4_INFO 0xdc4 +#define MSR_LASTBRANCH_5_INFO 0xdc5 +#define MSR_LASTBRANCH_6_INFO 0xdc6 +#define MSR_LASTBRANCH_7_INFO 0xdc7 +#define MSR_LASTBRANCH_8_INFO 0xdc8 +#define MSR_LASTBRANCH_9_INFO 0xdc9 +#define MSR_LASTBRANCH_10_INFO 0xdca +#define MSR_LASTBRANCH_11_INFO 0xdcb +#define MSR_LASTBRANCH_12_INFO 0xdcc +#define MSR_LASTBRANCH_13_INFO 0xdcd +#define MSR_LASTBRANCH_14_INFO 0xdce +#define MSR_LASTBRANCH_15_INFO 0xdcf +#define MSR_LASTBRANCH_16_INFO 0xdd0 +#define MSR_LASTBRANCH_17_INFO 0xdd1 +#define MSR_LASTBRANCH_18_INFO 0xdd2 +#define MSR_LASTBRANCH_19_INFO 0xdd3 +#define MSR_LASTBRANCH_20_INFO 0xdd4 +#define MSR_LASTBRANCH_21_INFO 0xdd5 +#define MSR_LASTBRANCH_22_INFO 0xdd6 +#define MSR_LASTBRANCH_23_INFO 0xdd7 +#define MSR_LASTBRANCH_24_INFO 0xdd8 +#define MSR_LASTBRANCH_25_INFO 0xdd9 +#define MSR_LASTBRANCH_26_INFO 0xdda +#define MSR_LASTBRANCH_27_INFO 0xddb +#define MSR_LASTBRANCH_28_INFO 0xddc +#define MSR_LASTBRANCH_29_INFO 0xddd +#define MSR_LASTBRANCH_30_INFO 0xdde +#define MSR_LASTBRANCH_31_INFO 0xddf + +/** LBR branch tracking selection MSR. */ +#define MSR_LASTBRANCH_SELECT 0x1c8 +/** LBR Top-of-stack MSR (index to most recent record). */ +#define MSR_LASTBRANCH_TOS 0x1c9 +/** @} */ + +/** @name Last event record registers. + * @{ */ +/** Last event record source IP register. */ +#define MSR_LER_FROM_IP 0x1dd +/** Last event record destination IP register. */ +#define MSR_LER_TO_IP 0x1de +/** @} */ + +/** Intel TSX (Transactional Synchronization Extensions) control MSR. */ +#define MSR_IA32_TSX_CTRL 0x122 + +/** Variable range MTRRs. + * @{ */ +#define MSR_IA32_MTRR_PHYSBASE0 0x200 +#define MSR_IA32_MTRR_PHYSMASK0 0x201 +#define MSR_IA32_MTRR_PHYSBASE1 0x202 +#define MSR_IA32_MTRR_PHYSMASK1 0x203 +#define MSR_IA32_MTRR_PHYSBASE2 0x204 +#define MSR_IA32_MTRR_PHYSMASK2 0x205 +#define MSR_IA32_MTRR_PHYSBASE3 0x206 +#define MSR_IA32_MTRR_PHYSMASK3 0x207 +#define MSR_IA32_MTRR_PHYSBASE4 0x208 +#define MSR_IA32_MTRR_PHYSMASK4 0x209 +#define MSR_IA32_MTRR_PHYSBASE5 0x20a +#define MSR_IA32_MTRR_PHYSMASK5 0x20b +#define MSR_IA32_MTRR_PHYSBASE6 0x20c +#define MSR_IA32_MTRR_PHYSMASK6 0x20d +#define MSR_IA32_MTRR_PHYSBASE7 0x20e +#define MSR_IA32_MTRR_PHYSMASK7 0x20f +#define MSR_IA32_MTRR_PHYSBASE8 0x210 +#define MSR_IA32_MTRR_PHYSMASK8 0x211 +#define MSR_IA32_MTRR_PHYSBASE9 0x212 +#define MSR_IA32_MTRR_PHYSMASK9 0x213 +/** @} */ + +/** Fixed range MTRRs. + * @{ */ +#define MSR_IA32_MTRR_FIX64K_00000 0x250 +#define MSR_IA32_MTRR_FIX16K_80000 0x258 +#define MSR_IA32_MTRR_FIX16K_A0000 0x259 +#define MSR_IA32_MTRR_FIX4K_C0000 0x268 +#define MSR_IA32_MTRR_FIX4K_C8000 0x269 +#define MSR_IA32_MTRR_FIX4K_D0000 0x26a +#define MSR_IA32_MTRR_FIX4K_D8000 0x26b +#define MSR_IA32_MTRR_FIX4K_E0000 0x26c +#define MSR_IA32_MTRR_FIX4K_E8000 0x26d +#define MSR_IA32_MTRR_FIX4K_F0000 0x26e +#define MSR_IA32_MTRR_FIX4K_F8000 0x26f +/** @} */ + +/** MTRR Default Range. */ +#define MSR_IA32_MTRR_DEF_TYPE 0x2FF + +/** Global performance counter control facilities (Intel only). */ +#define MSR_IA32_PERF_GLOBAL_STATUS 0x38E +#define MSR_IA32_PERF_GLOBAL_CTRL 0x38F +#define MSR_IA32_PERF_GLOBAL_OVF_CTRL 0x390 + +/** Precise Event Based sampling (Intel only). */ +#define MSR_IA32_PEBS_ENABLE 0x3F1 + +#define MSR_IA32_MC0_CTL 0x400 +#define MSR_IA32_MC0_STATUS 0x401 + +/** Basic VMX information. */ +#define MSR_IA32_VMX_BASIC 0x480 +/** Allowed settings for pin-based VM execution controls. */ +#define MSR_IA32_VMX_PINBASED_CTLS 0x481 +/** Allowed settings for proc-based VM execution controls. */ +#define MSR_IA32_VMX_PROCBASED_CTLS 0x482 +/** Allowed settings for the VM-exit controls. */ +#define MSR_IA32_VMX_EXIT_CTLS 0x483 +/** Allowed settings for the VM-entry controls. */ +#define MSR_IA32_VMX_ENTRY_CTLS 0x484 +/** Misc VMX info. */ +#define MSR_IA32_VMX_MISC 0x485 +/** Fixed cleared bits in CR0. */ +#define MSR_IA32_VMX_CR0_FIXED0 0x486 +/** Fixed set bits in CR0. */ +#define MSR_IA32_VMX_CR0_FIXED1 0x487 +/** Fixed cleared bits in CR4. */ +#define MSR_IA32_VMX_CR4_FIXED0 0x488 +/** Fixed set bits in CR4. */ +#define MSR_IA32_VMX_CR4_FIXED1 0x489 +/** Information for enumerating fields in the VMCS. */ +#define MSR_IA32_VMX_VMCS_ENUM 0x48A +/** Allowed settings for secondary processor-based VM-execution controls. */ +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B +/** EPT capabilities. */ +#define MSR_IA32_VMX_EPT_VPID_CAP 0x48C +/** Allowed settings of all pin-based VM execution controls. */ +#define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x48D +/** Allowed settings of all proc-based VM execution controls. */ +#define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x48E +/** Allowed settings of all VMX exit controls. */ +#define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x48F +/** Allowed settings of all VMX entry controls. */ +#define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x490 +/** Allowed settings for the VM-function controls. */ +#define MSR_IA32_VMX_VMFUNC 0x491 +/** Tertiary processor-based VM execution controls. */ +#define MSR_IA32_VMX_PROCBASED_CTLS3 0x492 +/** Secondary VM-exit controls. */ +#define MSR_IA32_VMX_EXIT_CTLS2 0x493 + +/** Intel PT - Enable and control for trace packet generation. */ +#define MSR_IA32_RTIT_CTL 0x570 + +/** DS Save Area (R/W). */ +#define MSR_IA32_DS_AREA 0x600 +/** Running Average Power Limit (RAPL) power units. */ +#define MSR_RAPL_POWER_UNIT 0x606 +/** Package C3 Interrupt Response Limit. */ +#define MSR_PKGC3_IRTL 0x60a +/** Package C6/C7S Interrupt Response Limit 1. */ +#define MSR_PKGC_IRTL1 0x60b +/** Package C6/C7S Interrupt Response Limit 2. */ +#define MSR_PKGC_IRTL2 0x60c +/** Package C2 Residency Counter. */ +#define MSR_PKG_C2_RESIDENCY 0x60d +/** PKG RAPL Power Limit Control. */ +#define MSR_PKG_POWER_LIMIT 0x610 +/** PKG Energy Status. */ +#define MSR_PKG_ENERGY_STATUS 0x611 +/** PKG Perf Status. */ +#define MSR_PKG_PERF_STATUS 0x613 +/** PKG RAPL Parameters. */ +#define MSR_PKG_POWER_INFO 0x614 +/** DRAM RAPL Power Limit Control. */ +#define MSR_DRAM_POWER_LIMIT 0x618 +/** DRAM Energy Status. */ +#define MSR_DRAM_ENERGY_STATUS 0x619 +/** DRAM Performance Throttling Status. */ +#define MSR_DRAM_PERF_STATUS 0x61b +/** DRAM RAPL Parameters. */ +#define MSR_DRAM_POWER_INFO 0x61c +/** Package C10 Residency Counter. */ +#define MSR_PKG_C10_RESIDENCY 0x632 +/** PP0 Energy Status. */ +#define MSR_PP0_ENERGY_STATUS 0x639 +/** PP1 Energy Status. */ +#define MSR_PP1_ENERGY_STATUS 0x641 +/** Turbo Activation Ratio. */ +#define MSR_TURBO_ACTIVATION_RATIO 0x64c +/** Core Performance Limit Reasons. */ +#define MSR_CORE_PERF_LIMIT_REASONS 0x64f + +/** X2APIC MSR range start. */ +#define MSR_IA32_X2APIC_START 0x800 +/** X2APIC MSR - APIC ID Register. */ +#define MSR_IA32_X2APIC_ID 0x802 +/** X2APIC MSR - APIC Version Register. */ +#define MSR_IA32_X2APIC_VERSION 0x803 +/** X2APIC MSR - Task Priority Register. */ +#define MSR_IA32_X2APIC_TPR 0x808 +/** X2APIC MSR - Processor Priority register. */ +#define MSR_IA32_X2APIC_PPR 0x80A +/** X2APIC MSR - End Of Interrupt register. */ +#define MSR_IA32_X2APIC_EOI 0x80B +/** X2APIC MSR - Logical Destination Register. */ +#define MSR_IA32_X2APIC_LDR 0x80D +/** X2APIC MSR - Spurious Interrupt Vector Register. */ +#define MSR_IA32_X2APIC_SVR 0x80F +/** X2APIC MSR - In-service Register (bits 31:0). */ +#define MSR_IA32_X2APIC_ISR0 0x810 +/** X2APIC MSR - In-service Register (bits 63:32). */ +#define MSR_IA32_X2APIC_ISR1 0x811 +/** X2APIC MSR - In-service Register (bits 95:64). */ +#define MSR_IA32_X2APIC_ISR2 0x812 +/** X2APIC MSR - In-service Register (bits 127:96). */ +#define MSR_IA32_X2APIC_ISR3 0x813 +/** X2APIC MSR - In-service Register (bits 159:128). */ +#define MSR_IA32_X2APIC_ISR4 0x814 +/** X2APIC MSR - In-service Register (bits 191:160). */ +#define MSR_IA32_X2APIC_ISR5 0x815 +/** X2APIC MSR - In-service Register (bits 223:192). */ +#define MSR_IA32_X2APIC_ISR6 0x816 +/** X2APIC MSR - In-service Register (bits 255:224). */ +#define MSR_IA32_X2APIC_ISR7 0x817 +/** X2APIC MSR - Trigger Mode Register (bits 31:0). */ +#define MSR_IA32_X2APIC_TMR0 0x818 +/** X2APIC MSR - Trigger Mode Register (bits 63:32). */ +#define MSR_IA32_X2APIC_TMR1 0x819 +/** X2APIC MSR - Trigger Mode Register (bits 95:64). */ +#define MSR_IA32_X2APIC_TMR2 0x81A +/** X2APIC MSR - Trigger Mode Register (bits 127:96). */ +#define MSR_IA32_X2APIC_TMR3 0x81B +/** X2APIC MSR - Trigger Mode Register (bits 159:128). */ +#define MSR_IA32_X2APIC_TMR4 0x81C +/** X2APIC MSR - Trigger Mode Register (bits 191:160). */ +#define MSR_IA32_X2APIC_TMR5 0x81D +/** X2APIC MSR - Trigger Mode Register (bits 223:192). */ +#define MSR_IA32_X2APIC_TMR6 0x81E +/** X2APIC MSR - Trigger Mode Register (bits 255:224). */ +#define MSR_IA32_X2APIC_TMR7 0x81F +/** X2APIC MSR - Interrupt Request Register (bits 31:0). */ +#define MSR_IA32_X2APIC_IRR0 0x820 +/** X2APIC MSR - Interrupt Request Register (bits 63:32). */ +#define MSR_IA32_X2APIC_IRR1 0x821 +/** X2APIC MSR - Interrupt Request Register (bits 95:64). */ +#define MSR_IA32_X2APIC_IRR2 0x822 +/** X2APIC MSR - Interrupt Request Register (bits 127:96). */ +#define MSR_IA32_X2APIC_IRR3 0x823 +/** X2APIC MSR - Interrupt Request Register (bits 159:128). */ +#define MSR_IA32_X2APIC_IRR4 0x824 +/** X2APIC MSR - Interrupt Request Register (bits 191:160). */ +#define MSR_IA32_X2APIC_IRR5 0x825 +/** X2APIC MSR - Interrupt Request Register (bits 223:192). */ +#define MSR_IA32_X2APIC_IRR6 0x826 +/** X2APIC MSR - Interrupt Request Register (bits 255:224). */ +#define MSR_IA32_X2APIC_IRR7 0x827 +/** X2APIC MSR - Error Status Register. */ +#define MSR_IA32_X2APIC_ESR 0x828 +/** X2APIC MSR - LVT CMCI Register. */ +#define MSR_IA32_X2APIC_LVT_CMCI 0x82F +/** X2APIC MSR - Interrupt Command Register. */ +#define MSR_IA32_X2APIC_ICR 0x830 +/** X2APIC MSR - LVT Timer Register. */ +#define MSR_IA32_X2APIC_LVT_TIMER 0x832 +/** X2APIC MSR - LVT Thermal Sensor Register. */ +#define MSR_IA32_X2APIC_LVT_THERMAL 0x833 +/** X2APIC MSR - LVT Performance Counter Register. */ +#define MSR_IA32_X2APIC_LVT_PERF 0x834 +/** X2APIC MSR - LVT LINT0 Register. */ +#define MSR_IA32_X2APIC_LVT_LINT0 0x835 +/** X2APIC MSR - LVT LINT1 Register. */ +#define MSR_IA32_X2APIC_LVT_LINT1 0x836 +/** X2APIC MSR - LVT Error Register . */ +#define MSR_IA32_X2APIC_LVT_ERROR 0x837 +/** X2APIC MSR - Timer Initial Count Register. */ +#define MSR_IA32_X2APIC_TIMER_ICR 0x838 +/** X2APIC MSR - Timer Current Count Register. */ +#define MSR_IA32_X2APIC_TIMER_CCR 0x839 +/** X2APIC MSR - Timer Divide Configuration Register. */ +#define MSR_IA32_X2APIC_TIMER_DCR 0x83E +/** X2APIC MSR - Self IPI. */ +#define MSR_IA32_X2APIC_SELF_IPI 0x83F +/** X2APIC MSR range end. */ +#define MSR_IA32_X2APIC_END 0x8FF +/** X2APIC MSR - LVT start range. */ +#define MSR_IA32_X2APIC_LVT_START MSR_IA32_X2APIC_LVT_TIMER +/** X2APIC MSR - LVT end range (inclusive). */ +#define MSR_IA32_X2APIC_LVT_END MSR_IA32_X2APIC_LVT_ERROR + +/** K6 EFER - Extended Feature Enable Register. */ +#define MSR_K6_EFER UINT32_C(0xc0000080) +/** @todo document EFER */ +/** Bit 0 - SCE - System call extensions (SYSCALL / SYSRET). (R/W) */ +#define MSR_K6_EFER_SCE RT_BIT_32(0) +/** Bit 8 - LME - Long mode enabled. (R/W) */ +#define MSR_K6_EFER_LME RT_BIT_32(8) +#define MSR_K6_EFER_BIT_LME 8 /**< Bit number of MSR_K6_EFER_LME */ +/** Bit 10 - LMA - Long mode active. (R) */ +#define MSR_K6_EFER_LMA RT_BIT_32(10) +#define MSR_K6_EFER_BIT_LMA 10 /**< Bit number of MSR_K6_EFER_LMA */ +/** Bit 11 - NXE - No-Execute Page Protection Enabled. (R/W) */ +#define MSR_K6_EFER_NXE RT_BIT_32(11) +#define MSR_K6_EFER_BIT_NXE 11 /**< Bit number of MSR_K6_EFER_NXE */ +/** Bit 12 - SVME - Secure VM Extension Enabled. (R/W) */ +#define MSR_K6_EFER_SVME RT_BIT_32(12) +/** Bit 13 - LMSLE - Long Mode Segment Limit Enable. (R/W?) */ +#define MSR_K6_EFER_LMSLE RT_BIT_32(13) +/** Bit 14 - FFXSR - Fast FXSAVE / FXRSTOR (skip XMM*). (R/W) */ +#define MSR_K6_EFER_FFXSR RT_BIT_32(14) +/** Bit 15 - TCE - Translation Cache Extension. (R/W) */ +#define MSR_K6_EFER_TCE RT_BIT_32(15) +/** Bit 17 - MCOMMIT - Commit Stores to memory. (R/W) */ +#define MSR_K6_EFER_MCOMMIT RT_BIT_32(17) + +/** K6 STAR - SYSCALL/RET targets. */ +#define MSR_K6_STAR UINT32_C(0xc0000081) +/** Shift value for getting the SYSRET CS and SS value. */ +#define MSR_K6_STAR_SYSRET_CS_SS_SHIFT 48 +/** Shift value for getting the SYSCALL CS and SS value. */ +#define MSR_K6_STAR_SYSCALL_CS_SS_SHIFT 32 +/** Selector mask for use after shifting. */ +#define MSR_K6_STAR_SEL_MASK UINT32_C(0xffff) +/** The mask which give the SYSCALL EIP. */ +#define MSR_K6_STAR_SYSCALL_EIP_MASK UINT32_C(0xffffffff) +/** K6 WHCR - Write Handling Control Register. */ +#define MSR_K6_WHCR UINT32_C(0xc0000082) +/** K6 UWCCR - UC/WC Cacheability Control Register. */ +#define MSR_K6_UWCCR UINT32_C(0xc0000085) +/** K6 PSOR - Processor State Observability Register. */ +#define MSR_K6_PSOR UINT32_C(0xc0000087) +/** K6 PFIR - Page Flush/Invalidate Register. */ +#define MSR_K6_PFIR UINT32_C(0xc0000088) + +/** Performance counter MSRs. (AMD only) */ +#define MSR_K7_EVNTSEL0 UINT32_C(0xc0010000) +#define MSR_K7_EVNTSEL1 UINT32_C(0xc0010001) +#define MSR_K7_EVNTSEL2 UINT32_C(0xc0010002) +#define MSR_K7_EVNTSEL3 UINT32_C(0xc0010003) +#define MSR_K7_PERFCTR0 UINT32_C(0xc0010004) +#define MSR_K7_PERFCTR1 UINT32_C(0xc0010005) +#define MSR_K7_PERFCTR2 UINT32_C(0xc0010006) +#define MSR_K7_PERFCTR3 UINT32_C(0xc0010007) + +/** K8 LSTAR - Long mode SYSCALL target (RIP). */ +#define MSR_K8_LSTAR UINT32_C(0xc0000082) +/** K8 CSTAR - Compatibility mode SYSCALL target (RIP). */ +#define MSR_K8_CSTAR UINT32_C(0xc0000083) +/** K8 SF_MASK - SYSCALL flag mask. (aka SFMASK) */ +#define MSR_K8_SF_MASK UINT32_C(0xc0000084) +/** K8 FS.base - The 64-bit base FS register. */ +#define MSR_K8_FS_BASE UINT32_C(0xc0000100) +/** K8 GS.base - The 64-bit base GS register. */ +#define MSR_K8_GS_BASE UINT32_C(0xc0000101) +/** K8 KernelGSbase - Used with SWAPGS. */ +#define MSR_K8_KERNEL_GS_BASE UINT32_C(0xc0000102) +/** K8 TSC_AUX - Used with RDTSCP. */ +#define MSR_K8_TSC_AUX UINT32_C(0xc0000103) +#define MSR_K8_SYSCFG UINT32_C(0xc0010010) +#define MSR_K8_HWCR UINT32_C(0xc0010015) +#define MSR_K8_IORRBASE0 UINT32_C(0xc0010016) +#define MSR_K8_IORRMASK0 UINT32_C(0xc0010017) +#define MSR_K8_IORRBASE1 UINT32_C(0xc0010018) +#define MSR_K8_IORRMASK1 UINT32_C(0xc0010019) +#define MSR_K8_TOP_MEM1 UINT32_C(0xc001001a) +#define MSR_K8_TOP_MEM2 UINT32_C(0xc001001d) + +/** SMM MSRs. */ +#define MSR_K7_SMBASE UINT32_C(0xc0010111) +#define MSR_K7_SMM_ADDR UINT32_C(0xc0010112) +#define MSR_K7_SMM_MASK UINT32_C(0xc0010113) + +/** North bridge config? See BIOS & Kernel dev guides for + * details. */ +#define MSR_K8_NB_CFG UINT32_C(0xc001001f) + +/** Hypertransport interrupt pending register. + * "BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors" */ +#define MSR_K8_INT_PENDING UINT32_C(0xc0010055) + +/** SVM Control. */ +#define MSR_K8_VM_CR UINT32_C(0xc0010114) +/** Disables HDT (Hardware Debug Tool) and certain internal debug + * features. */ +#define MSR_K8_VM_CR_DPD RT_BIT_32(0) +/** If set, non-intercepted INIT signals are converted to \#SX + * exceptions. */ +#define MSR_K8_VM_CR_R_INIT RT_BIT_32(1) +/** Disables A20 masking. */ +#define MSR_K8_VM_CR_DIS_A20M RT_BIT_32(2) +/** Lock bit for this MSR controlling bits 3 (LOCK) and 4 (SVMDIS). */ +#define MSR_K8_VM_CR_LOCK RT_BIT_32(3) +/** SVM disable. When set, writes to EFER.SVME are treated as MBZ. When + * clear, EFER.SVME can be written normally. */ +#define MSR_K8_VM_CR_SVM_DISABLE RT_BIT_32(4) + +#define MSR_K8_IGNNE UINT32_C(0xc0010115) +#define MSR_K8_SMM_CTL UINT32_C(0xc0010116) +/** SVM - VM_HSAVE_PA - Physical address for saving and restoring + * host state during world switch. */ +#define MSR_K8_VM_HSAVE_PA UINT32_C(0xc0010117) + +/** Virtualized speculation control for AMD processors. + * + * Unified interface among different CPU generations. + * The VMM will set any architectural MSRs based on the CPU. + * See "White Paper: AMD64 Technology Speculative Store Bypass Disable 5.21.18" + * (12441_AMD64_SpeculativeStoreBypassDisable_Whitepaper_final.pdf) */ +#define MSR_AMD_VIRT_SPEC_CTL UINT32_C(0xc001011f) +/** Speculative Store Bypass Disable. */ +# define MSR_AMD_VIRT_SPEC_CTL_F_SSBD RT_BIT(2) + +/** @} */ + + +/** @name Page Table / Directory / Directory Pointers / L4. + * @{ + */ + +/** Page table/directory entry as an unsigned integer. */ +typedef uint32_t X86PGUINT; +/** Pointer to a page table/directory table entry as an unsigned integer. */ +typedef X86PGUINT *PX86PGUINT; +/** Pointer to an const page table/directory table entry as an unsigned integer. */ +typedef X86PGUINT const *PCX86PGUINT; + +/** Number of entries in a 32-bit PT/PD. */ +#define X86_PG_ENTRIES 1024 + + +/** PAE page table/page directory/pdpt/l4/l5 entry as an unsigned integer. */ +typedef uint64_t X86PGPAEUINT; +/** Pointer to a PAE page table/page directory/pdpt/l4/l5 entry as an unsigned integer. */ +typedef X86PGPAEUINT *PX86PGPAEUINT; +/** Pointer to an const PAE page table/page directory/pdpt/l4/l5 entry as an unsigned integer. */ +typedef X86PGPAEUINT const *PCX86PGPAEUINT; + +/** Number of entries in a PAE PT/PD. */ +#define X86_PG_PAE_ENTRIES 512 +/** Number of entries in a PAE PDPT. */ +#define X86_PG_PAE_PDPE_ENTRIES 4 + +/** Number of entries in an AMD64 PT/PD/PDPT/L4/L5. */ +#define X86_PG_AMD64_ENTRIES X86_PG_PAE_ENTRIES +/** Number of entries in an AMD64 PDPT. + * Just for complementing X86_PG_PAE_PDPE_ENTRIES, using X86_PG_AMD64_ENTRIES for this is fine too. */ +#define X86_PG_AMD64_PDPE_ENTRIES X86_PG_AMD64_ENTRIES + +/** The size of a default page. */ +#define X86_PAGE_SIZE X86_PAGE_4K_SIZE +/** The page shift of a default page. */ +#define X86_PAGE_SHIFT X86_PAGE_4K_SHIFT +/** The default page offset mask. */ +#define X86_PAGE_OFFSET_MASK X86_PAGE_4K_OFFSET_MASK +/** The default page base mask for virtual addresses. */ +#define X86_PAGE_BASE_MASK X86_PAGE_4K_BASE_MASK +/** The default page base mask for virtual addresses - 32bit version. */ +#define X86_PAGE_BASE_MASK_32 X86_PAGE_4K_BASE_MASK_32 + +/** The size of a 4KB page. */ +#define X86_PAGE_4K_SIZE _4K +/** The page shift of a 4KB page. */ +#define X86_PAGE_4K_SHIFT 12 +/** The 4KB page offset mask. */ +#define X86_PAGE_4K_OFFSET_MASK 0xfff +/** The 4KB page base mask for virtual addresses. */ +#define X86_PAGE_4K_BASE_MASK 0xfffffffffffff000ULL +/** The 4KB page base mask for virtual addresses - 32bit version. */ +#define X86_PAGE_4K_BASE_MASK_32 0xfffff000U + +/** The size of a 2MB page. */ +#define X86_PAGE_2M_SIZE _2M +/** The page shift of a 2MB page. */ +#define X86_PAGE_2M_SHIFT 21 +/** The 2MB page offset mask. */ +#define X86_PAGE_2M_OFFSET_MASK 0x001fffff +/** The 2MB page base mask for virtual addresses. */ +#define X86_PAGE_2M_BASE_MASK 0xffffffffffe00000ULL +/** The 2MB page base mask for virtual addresses - 32bit version. */ +#define X86_PAGE_2M_BASE_MASK_32 0xffe00000U + +/** The size of a 4MB page. */ +#define X86_PAGE_4M_SIZE _4M +/** The page shift of a 4MB page. */ +#define X86_PAGE_4M_SHIFT 22 +/** The 4MB page offset mask. */ +#define X86_PAGE_4M_OFFSET_MASK 0x003fffff +/** The 4MB page base mask for virtual addresses. */ +#define X86_PAGE_4M_BASE_MASK 0xffffffffffc00000ULL +/** The 4MB page base mask for virtual addresses - 32bit version. */ +#define X86_PAGE_4M_BASE_MASK_32 0xffc00000U + +/** The size of a 1GB page. */ +#define X86_PAGE_1G_SIZE _1G +/** The page shift of a 1GB page. */ +#define X86_PAGE_1G_SHIFT 30 +/** The 1GB page offset mask. */ +#define X86_PAGE_1G_OFFSET_MASK 0x3fffffff +/** The 1GB page base mask for virtual addresses. */ +#define X86_PAGE_1G_BASE_MASK UINT64_C(0xffffffffc0000000) + +/** + * Check if the given address is canonical. + */ +#define X86_IS_CANONICAL(a_u64Addr) ((uint64_t)(a_u64Addr) + UINT64_C(0x800000000000) < UINT64_C(0x1000000000000)) + +/** + * Gets the page base mask given the page shift. + */ +#define X86_GET_PAGE_BASE_MASK(a_cShift) (UINT64_C(0xffffffffffffffff) << (a_cShift)) + +/** + * Gets the page offset mask given the page shift. + */ +#define X86_GET_PAGE_OFFSET_MASK(a_cShift) (~X86_GET_PAGE_BASE_MASK(a_cShift)) + + +/** @name Page Table Entry + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PTE_BIT_P 0 +/** Bit 1 - R/W - Read (clear) / Write (set) bit. */ +#define X86_PTE_BIT_RW 1 +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. */ +#define X86_PTE_BIT_US 2 +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PTE_BIT_PWT 3 +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PTE_BIT_PCD 4 +/** Bit 5 - A - Access bit. */ +#define X86_PTE_BIT_A 5 +/** Bit 6 - D - Dirty bit. */ +#define X86_PTE_BIT_D 6 +/** Bit 7 - PAT - Page Attribute Table index bit. Reserved and 0 if not supported. */ +#define X86_PTE_BIT_PAT 7 +/** Bit 8 - G - Global flag. */ +#define X86_PTE_BIT_G 8 +/** Bits 63 - NX - PAE/LM - No execution flag. */ +#define X86_PTE_PAE_BIT_NX 63 + +/** Bit 0 - P - Present bit mask. */ +#define X86_PTE_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit mask. */ +#define X86_PTE_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit mask. */ +#define X86_PTE_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit mask. */ +#define X86_PTE_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit mask. */ +#define X86_PTE_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit mask. */ +#define X86_PTE_A RT_BIT_32(5) +/** Bit 6 - D - Dirty bit mask. */ +#define X86_PTE_D RT_BIT_32(6) +/** Bit 7 - PAT - Page Attribute Table index bit mask. Reserved and 0 if not supported. */ +#define X86_PTE_PAT RT_BIT_32(7) +/** Bit 8 - G - Global bit mask. */ +#define X86_PTE_G RT_BIT_32(8) + +/** Bits 9-11 - - Available for use to system software. */ +#define X86_PTE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bits 12-31 - - Physical Page number of the next level. */ +#define X86_PTE_PG_MASK ( 0xfffff000 ) + +/** Bits 12-51 - - PAE - Physical Page number of the next level. */ +#define X86_PTE_PAE_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bits 63 - NX - PAE/LM - No execution flag. */ +#define X86_PTE_PAE_NX RT_BIT_64(63) +/** Bits 62-52 - - PAE - MBZ bits when NX is active. */ +#define X86_PTE_PAE_MBZ_MASK_NX UINT64_C(0x7ff0000000000000) +/** Bits 63-52 - - PAE - MBZ bits when no NX. */ +#define X86_PTE_PAE_MBZ_MASK_NO_NX UINT64_C(0xfff0000000000000) +/** No bits - - LM - MBZ bits when NX is active. */ +#define X86_PTE_LM_MBZ_MASK_NX UINT64_C(0x0000000000000000) +/** Bits 63 - - LM - MBZ bits when no NX. */ +#define X86_PTE_LM_MBZ_MASK_NO_NX UINT64_C(0x8000000000000000) + +/** + * Page table entry. + */ +typedef struct X86PTEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Dirty flag. + * Indicates that the page has been written to. */ + uint32_t u1Dirty : 1; + /** Reserved / If PAT enabled, bit 2 of the index. */ + uint32_t u1PAT : 1; + /** Global flag. (Ignored in all but final level.) */ + uint32_t u1Global : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level. */ + uint32_t u20PageNo : 20; +} X86PTEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTEBITS, 4); +#endif +/** Pointer to a page table entry. */ +typedef X86PTEBITS *PX86PTEBITS; +/** Pointer to a const page table entry. */ +typedef const X86PTEBITS *PCX86PTEBITS; + +/** + * Page table entry. + */ +typedef union X86PTE +{ + /** Unsigned integer view */ + X86PGUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Bit field view. */ + X86PTEBITS n; +#endif + /** 32-bit view. */ + uint32_t au32[1]; + /** 16-bit view. */ + uint16_t au16[2]; + /** 8-bit view. */ + uint8_t au8[4]; +} X86PTE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTE, 4); +#endif +/** Pointer to a page table entry. */ +typedef X86PTE *PX86PTE; +/** Pointer to a const page table entry. */ +typedef const X86PTE *PCX86PTE; + + +/** + * PAE page table entry. + */ +typedef struct X86PTEPAEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor(=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Dirty flag. + * Indicates that the page has been written to. */ + uint32_t u1Dirty : 1; + /** Reserved / If PAT enabled, bit 2 of the index. */ + uint32_t u1PAT : 1; + /** Global flag. (Ignored in all but final level.) */ + uint32_t u1Global : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use this. */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use this. */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PTEPAEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTEPAEBITS, 8); +#endif +/** Pointer to a page table entry. */ +typedef X86PTEPAEBITS *PX86PTEPAEBITS; +/** Pointer to a page table entry. */ +typedef const X86PTEPAEBITS *PCX86PTEPAEBITS; + +/** + * PAE Page table entry. + */ +typedef union X86PTEPAE +{ + /** Unsigned integer view */ + X86PGPAEUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Bit field view. */ + X86PTEPAEBITS n; +#endif + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[4]; + /** 8-bit view. */ + uint8_t au8[8]; +} X86PTEPAE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTEPAE, 8); +#endif +/** Pointer to a PAE page table entry. */ +typedef X86PTEPAE *PX86PTEPAE; +/** Pointer to a const PAE page table entry. */ +typedef const X86PTEPAE *PCX86PTEPAE; +/** @} */ + +/** + * Page table. + */ +typedef struct X86PT +{ + /** PTE Array. */ + X86PTE a[X86_PG_ENTRIES]; +} X86PT; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PT, 4096); +#endif +/** Pointer to a page table. */ +typedef X86PT *PX86PT; +/** Pointer to a const page table. */ +typedef const X86PT *PCX86PT; + +/** The page shift to get the PT index. */ +#define X86_PT_SHIFT 12 +/** The PT index mask (apply to a shifted page address). */ +#define X86_PT_MASK 0x3ff + + +/** + * Page directory. + */ +typedef struct X86PTPAE +{ + /** PTE Array. */ + X86PTEPAE a[X86_PG_PAE_ENTRIES]; +} X86PTPAE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTPAE, 4096); +#endif +/** Pointer to a page table. */ +typedef X86PTPAE *PX86PTPAE; +/** Pointer to a const page table. */ +typedef const X86PTPAE *PCX86PTPAE; + +/** The page shift to get the PA PTE index. */ +#define X86_PT_PAE_SHIFT 12 +/** The PAE PT index mask (apply to a shifted page address). */ +#define X86_PT_PAE_MASK 0x1ff + + +/** @name 4KB Page Directory Entry + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PDE_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit. */ +#define X86_PDE_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. */ +#define X86_PDE_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PDE_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PDE_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit. */ +#define X86_PDE_A RT_BIT_32(5) +/** Bit 7 - PS - Page size attribute. + * Clear mean 4KB pages, set means large pages (2/4MB). */ +#define X86_PDE_PS RT_BIT_32(7) +/** Bits 9-11 - - Available for use to system software. */ +#define X86_PDE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bits 12-31 - - Physical Page number of the next level. */ +#define X86_PDE_PG_MASK ( 0xfffff000 ) + +/** Bits 12-51 - - PAE - Physical Page number of the next level. */ +#define X86_PDE_PAE_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bits 63 - NX - PAE/LM - No execution flag. */ +#define X86_PDE_PAE_NX RT_BIT_64(63) +/** Bits 62-52, 7 - - PAE - MBZ bits when NX is active. */ +#define X86_PDE_PAE_MBZ_MASK_NX UINT64_C(0x7ff0000000000080) +/** Bits 63-52, 7 - - PAE - MBZ bits when no NX. */ +#define X86_PDE_PAE_MBZ_MASK_NO_NX UINT64_C(0xfff0000000000080) +/** Bit 7 - - LM - MBZ bits when NX is active. */ +#define X86_PDE_LM_MBZ_MASK_NX UINT64_C(0x0000000000000080) +/** Bits 63, 7 - - LM - MBZ bits when no NX. */ +#define X86_PDE_LM_MBZ_MASK_NO_NX UINT64_C(0x8000000000000080) + +/** + * Page directory entry. + */ +typedef struct X86PDEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page has been read or written to. */ + uint32_t u1Accessed : 1; + /** Reserved / Ignored (dirty bit). */ + uint32_t u1Reserved0 : 1; + /** Size bit if PSE is enabled - in any event it's 0. */ + uint32_t u1Size : 1; + /** Reserved / Ignored (global bit). */ + uint32_t u1Reserved1 : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level. */ + uint32_t u20PageNo : 20; +} X86PDEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDEBITS, 4); +#endif +/** Pointer to a page directory entry. */ +typedef X86PDEBITS *PX86PDEBITS; +/** Pointer to a const page directory entry. */ +typedef const X86PDEBITS *PCX86PDEBITS; + + +/** + * PAE page directory entry. + */ +typedef struct X86PDEPAEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page has been read or written to. */ + uint32_t u1Accessed : 1; + /** Reserved / Ignored (dirty bit). */ + uint32_t u1Reserved0 : 1; + /** Size bit if PSE is enabled - in any event it's 0. */ + uint32_t u1Size : 1; + /** Reserved / Ignored (global bit). / */ + uint32_t u1Reserved1 : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use! */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PDEPAEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDEPAEBITS, 8); +#endif +/** Pointer to a page directory entry. */ +typedef X86PDEPAEBITS *PX86PDEPAEBITS; +/** Pointer to a const page directory entry. */ +typedef const X86PDEPAEBITS *PCX86PDEPAEBITS; + +/** @} */ + + +/** @name 2/4MB Page Directory Entry + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PDE4M_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit. */ +#define X86_PDE4M_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. */ +#define X86_PDE4M_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PDE4M_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PDE4M_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit. */ +#define X86_PDE4M_A RT_BIT_32(5) +/** Bit 6 - D - Dirty bit. */ +#define X86_PDE4M_D RT_BIT_32(6) +/** Bit 7 - PS - Page size attribute. Clear mean 4KB pages, set means large pages (2/4MB). */ +#define X86_PDE4M_PS RT_BIT_32(7) +/** Bit 8 - G - Global flag. */ +#define X86_PDE4M_G RT_BIT_32(8) +/** Bits 9-11 - AVL - Available for use to system software. */ +#define X86_PDE4M_AVL (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bit 12 - PAT - Page Attribute Table index bit. Reserved and 0 if not supported. */ +#define X86_PDE4M_PAT RT_BIT_32(12) +/** Shift to get from X86_PTE_PAT to X86_PDE4M_PAT. */ +#define X86_PDE4M_PAT_SHIFT (12 - 7) +/** Bits 22-31 - - Physical Page number. */ +#define X86_PDE4M_PG_MASK ( 0xffc00000 ) +/** Bits 20-13 - - Physical Page number high part (32-39 bits). AMD64 hack. */ +#define X86_PDE4M_PG_HIGH_MASK ( 0x001fe000 ) +/** The number of bits to the high part of the page number. */ +#define X86_PDE4M_PG_HIGH_SHIFT 19 +/** Bit 21 - - MBZ bits for AMD CPUs, no PSE36. */ +#define X86_PDE4M_MBZ_MASK RT_BIT_32(21) + +/** Bits 21-51 - - PAE/LM - Physical Page number. + * (Bits 40-51 (long mode) & bits 36-51 (pae legacy) are reserved according to the Intel docs; AMD allows for more.) */ +#define X86_PDE2M_PAE_PG_MASK UINT64_C(0x000fffffffe00000) +/** Bits 63 - NX - PAE/LM - No execution flag. */ +#define X86_PDE2M_PAE_NX RT_BIT_64(63) +/** Bits 62-52, 20-13 - - PAE - MBZ bits when NX is active. */ +#define X86_PDE2M_PAE_MBZ_MASK_NX UINT64_C(0x7ff00000001fe000) +/** Bits 63-52, 20-13 - - PAE - MBZ bits when no NX. */ +#define X86_PDE2M_PAE_MBZ_MASK_NO_NX UINT64_C(0xfff00000001fe000) +/** Bits 20-13 - - LM - MBZ bits when NX is active. */ +#define X86_PDE2M_LM_MBZ_MASK_NX UINT64_C(0x00000000001fe000) +/** Bits 63, 20-13 - - LM - MBZ bits when no NX. */ +#define X86_PDE2M_LM_MBZ_MASK_NO_NX UINT64_C(0x80000000001fe000) + +/** + * 4MB page directory entry. + */ +typedef struct X86PDE4MBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Dirty flag. + * Indicates that the page has been written to. */ + uint32_t u1Dirty : 1; + /** Page size flag - always 1 for 4MB entries. */ + uint32_t u1Size : 1; + /** Global flag. */ + uint32_t u1Global : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Reserved / If PAT enabled, bit 2 of the index. */ + uint32_t u1PAT : 1; + /** Bits 32-39 of the page number on AMD64. + * This AMD64 hack allows accessing 40bits of physical memory without PAE. */ + uint32_t u8PageNoHigh : 8; + /** Reserved. */ + uint32_t u1Reserved : 1; + /** Physical Page number of the page. */ + uint32_t u10PageNo : 10; +} X86PDE4MBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDE4MBITS, 4); +#endif +/** Pointer to a page table entry. */ +typedef X86PDE4MBITS *PX86PDE4MBITS; +/** Pointer to a const page table entry. */ +typedef const X86PDE4MBITS *PCX86PDE4MBITS; + + +/** + * 2MB PAE page directory entry. + */ +typedef struct X86PDE2MPAEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor(=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Dirty flag. + * Indicates that the page has been written to. */ + uint32_t u1Dirty : 1; + /** Page size flag - always 1 for 2MB entries. */ + uint32_t u1Size : 1; + /** Global flag. */ + uint32_t u1Global : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Reserved / If PAT enabled, bit 2 of the index. */ + uint32_t u1PAT : 1; + /** Reserved. */ + uint32_t u9Reserved : 9; + /** Physical Page number of the next level - Low part. Don't use! */ + uint32_t u10PageNoLow : 10; + /** Physical Page number of the next level - High part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PDE2MPAEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDE2MPAEBITS, 8); +#endif +/** Pointer to a 2MB PAE page table entry. */ +typedef X86PDE2MPAEBITS *PX86PDE2MPAEBITS; +/** Pointer to a 2MB PAE page table entry. */ +typedef const X86PDE2MPAEBITS *PCX86PDE2MPAEBITS; + +/** @} */ + +/** + * Page directory entry. + */ +typedef union X86PDE +{ + /** Unsigned integer view. */ + X86PGUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + X86PDEBITS n; + /** 4MB view (big). */ + X86PDE4MBITS b; +#endif + /** 8 bit unsigned integer view. */ + uint8_t au8[4]; + /** 16 bit unsigned integer view. */ + uint16_t au16[2]; + /** 32 bit unsigned integer view. */ + uint32_t au32[1]; +} X86PDE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDE, 4); +#endif +/** Pointer to a page directory entry. */ +typedef X86PDE *PX86PDE; +/** Pointer to a const page directory entry. */ +typedef const X86PDE *PCX86PDE; + +/** + * PAE page directory entry. + */ +typedef union X86PDEPAE +{ + /** Unsigned integer view. */ + X86PGPAEUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + X86PDEPAEBITS n; + /** 2MB page view (big). */ + X86PDE2MPAEBITS b; +#endif + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} X86PDEPAE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDEPAE, 8); +#endif +/** Pointer to a page directory entry. */ +typedef X86PDEPAE *PX86PDEPAE; +/** Pointer to a const page directory entry. */ +typedef const X86PDEPAE *PCX86PDEPAE; + +/** + * Page directory. + */ +typedef struct X86PD +{ + /** PDE Array. */ + X86PDE a[X86_PG_ENTRIES]; +} X86PD; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PD, 4096); +#endif +/** Pointer to a page directory. */ +typedef X86PD *PX86PD; +/** Pointer to a const page directory. */ +typedef const X86PD *PCX86PD; + +/** The page shift to get the PD index. */ +#define X86_PD_SHIFT 22 +/** The PD index mask (apply to a shifted page address). */ +#define X86_PD_MASK 0x3ff + + +/** + * PAE page directory. + */ +typedef struct X86PDPAE +{ + /** PDE Array. */ + X86PDEPAE a[X86_PG_PAE_ENTRIES]; +} X86PDPAE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPAE, 4096); +#endif +/** Pointer to a PAE page directory. */ +typedef X86PDPAE *PX86PDPAE; +/** Pointer to a const PAE page directory. */ +typedef const X86PDPAE *PCX86PDPAE; + +/** The page shift to get the PAE PD index. */ +#define X86_PD_PAE_SHIFT 21 +/** The PAE PD index mask (apply to a shifted page address). */ +#define X86_PD_PAE_MASK 0x1ff + + +/** @name Page Directory Pointer Table Entry (PAE) + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PDPE_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit. Long Mode only. */ +#define X86_PDPE_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. Long Mode only. */ +#define X86_PDPE_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PDPE_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PDPE_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit. Long Mode only. */ +#define X86_PDPE_A RT_BIT_32(5) +/** Bit 7 - PS - Page size (1GB). Long Mode only. */ +#define X86_PDPE_LM_PS RT_BIT_32(7) +/** Bits 9-11 - - Available for use to system software. */ +#define X86_PDPE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bits 12-51 - - PAE - Physical Page number of the next level. */ +#define X86_PDPE_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bits 30-51 - - PG - Physical address of the 1GB page referenced by this entry. */ +#define X86_PDPE1G_PG_MASK UINT64_C(0x000fffffc0000000) +/** Bits 63-52, 8-5, 2-1 - - PAE - MBZ bits (NX is long mode only). */ +#define X86_PDPE_PAE_MBZ_MASK UINT64_C(0xfff00000000001e6) +/** Bits 63 - NX - LM - No execution flag. Long Mode only. */ +#define X86_PDPE_LM_NX RT_BIT_64(63) +/** Bits 8, 7 - - LM - MBZ bits when NX is active. */ +#define X86_PDPE_LM_MBZ_MASK_NX UINT64_C(0x0000000000000180) +/** Bits 63, 8, 7 - - LM - MBZ bits when no NX. */ +#define X86_PDPE_LM_MBZ_MASK_NO_NX UINT64_C(0x8000000000000180) +/** Bits 29-13 - - LM - MBZ bits for 1GB page entry when NX is active. */ +#define X86_PDPE1G_LM_MBZ_MASK_NX UINT64_C(0x000000003fffe000) +/** Bits 63, 29-13 - - LM - MBZ bits for 1GB page entry when no NX. */ +#define X86_PDPE1G_LM_MBZ_MASK_NO_NX UINT64_C(0x800000003fffe000) + + +/** + * Page directory pointer table entry. + */ +typedef struct X86PDPEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Chunk of reserved bits. */ + uint32_t u2Reserved : 2; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Chunk of reserved bits. */ + uint32_t u4Reserved : 4; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use! */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u12Reserved : 12; +} X86PDPEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPEBITS, 8); +#endif +/** Pointer to a page directory pointer table entry. */ +typedef X86PDPEBITS *PX86PTPEBITS; +/** Pointer to a const page directory pointer table entry. */ +typedef const X86PDPEBITS *PCX86PTPEBITS; + +/** + * Page directory pointer table entry. AMD64 version + */ +typedef struct X86PDPEAMD64BITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Chunk of reserved bits. */ + uint32_t u3Reserved : 3; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use! */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PDPEAMD64BITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPEAMD64BITS, 8); +#endif +/** Pointer to a page directory pointer table entry. */ +typedef X86PDPEAMD64BITS *PX86PDPEAMD64BITS; +/** Pointer to a const page directory pointer table entry. */ +typedef const X86PDPEAMD64BITS *PCX86PDPEAMD64BITS; + +/** + * Page directory pointer table entry for 1GB page. (AMD64 only) + */ +typedef struct X86PDPE1GB +{ + /** 0: Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** 1: Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** 2: User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** 3: Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** 4: Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** 5: Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** 6: Dirty flag for 1GB pages. */ + uint32_t u1Dirty : 1; + /** 7: Indicates 1GB page if set. */ + uint32_t u1Size : 1; + /** 8: Global 1GB page. */ + uint32_t u1Global: 1; + /** 9-11: Available for use to system software. */ + uint32_t u3Available : 3; + /** 12: PAT bit for 1GB page. */ + uint32_t u1PAT : 1; + /** 13-29: MBZ bits. */ + uint32_t u17Reserved : 17; + /** 30-31: Physical page number - Low Part. Don't use! */ + uint32_t u2PageNoLow : 2; + /** 32-51: Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** 52-62: MBZ bits */ + uint32_t u11Reserved : 11; + /** 63: No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PDPE1GB; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPE1GB, 8); +#endif +/** Pointer to a page directory pointer table entry for a 1GB page. */ +typedef X86PDPE1GB *PX86PDPE1GB; +/** Pointer to a const page directory pointer table entry for a 1GB page. */ +typedef const X86PDPE1GB *PCX86PDPE1GB; + +/** + * Page directory pointer table entry. + */ +typedef union X86PDPE +{ + /** Unsigned integer view. */ + X86PGPAEUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + X86PDPEBITS n; + /** AMD64 view. */ + X86PDPEAMD64BITS lm; + /** AMD64 big view. */ + X86PDPE1GB b; +#endif + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} X86PDPE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPE, 8); +#endif +/** Pointer to a page directory pointer table entry. */ +typedef X86PDPE *PX86PDPE; +/** Pointer to a const page directory pointer table entry. */ +typedef const X86PDPE *PCX86PDPE; + + +/** + * Page directory pointer table. + */ +typedef struct X86PDPT +{ + /** PDE Array. */ + X86PDPE a[X86_PG_AMD64_PDPE_ENTRIES]; +} X86PDPT; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPT, 4096); +#endif +/** Pointer to a page directory pointer table. */ +typedef X86PDPT *PX86PDPT; +/** Pointer to a const page directory pointer table. */ +typedef const X86PDPT *PCX86PDPT; + +/** The page shift to get the PDPT index. */ +#define X86_PDPT_SHIFT 30 +/** The PDPT index mask (apply to a shifted page address). (32 bits PAE) */ +#define X86_PDPT_MASK_PAE 0x3 +/** The PDPT index mask (apply to a shifted page address). (64 bits PAE)*/ +#define X86_PDPT_MASK_AMD64 0x1ff + +/** @} */ + + +/** @name Page Map Level-4 Entry (Long Mode PAE) + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PML4E_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit. */ +#define X86_PML4E_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. */ +#define X86_PML4E_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PML4E_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PML4E_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit. */ +#define X86_PML4E_A RT_BIT_32(5) +/** Bits 9-11 - - Available for use to system software. */ +#define X86_PML4E_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bits 12-51 - - PAE - Physical Page number of the next level. */ +#define X86_PML4E_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bits 8, 7 - - MBZ bits when NX is active. */ +#define X86_PML4E_MBZ_MASK_NX UINT64_C(0x0000000000000080) +/** Bits 63, 7 - - MBZ bits when no NX. */ +#define X86_PML4E_MBZ_MASK_NO_NX UINT64_C(0x8000000000000080) +/** Bits 63 - NX - PAE - No execution flag. */ +#define X86_PML4E_NX RT_BIT_64(63) + +/** + * Page Map Level-4 Entry + */ +typedef struct X86PML4EBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Chunk of reserved bits. */ + uint32_t u3Reserved : 3; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use! */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PML4EBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PML4EBITS, 8); +#endif +/** Pointer to a page map level-4 entry. */ +typedef X86PML4EBITS *PX86PML4EBITS; +/** Pointer to a const page map level-4 entry. */ +typedef const X86PML4EBITS *PCX86PML4EBITS; + +/** + * Page Map Level-4 Entry. + */ +typedef union X86PML4E +{ + /** Unsigned integer view. */ + X86PGPAEUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + X86PML4EBITS n; +#endif + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} X86PML4E; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PML4E, 8); +#endif +/** Pointer to a page map level-4 entry. */ +typedef X86PML4E *PX86PML4E; +/** Pointer to a const page map level-4 entry. */ +typedef const X86PML4E *PCX86PML4E; + + +/** + * Page Map Level-4. + */ +typedef struct X86PML4 +{ + /** PDE Array. */ + X86PML4E a[X86_PG_PAE_ENTRIES]; +} X86PML4; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PML4, 4096); +#endif +/** Pointer to a page map level-4. */ +typedef X86PML4 *PX86PML4; +/** Pointer to a const page map level-4. */ +typedef const X86PML4 *PCX86PML4; + +/** The page shift to get the PML4 index. */ +#define X86_PML4_SHIFT 39 +/** The PML4 index mask (apply to a shifted page address). */ +#define X86_PML4_MASK 0x1ff + +/** @} */ + +/** @} */ + +/** + * Intel PCID invalidation types. + */ +/** Individual address invalidation. */ +#define X86_INVPCID_TYPE_INDV_ADDR 0 +/** Single-context invalidation. */ +#define X86_INVPCID_TYPE_SINGLE_CONTEXT 1 +/** All-context including globals invalidation. */ +#define X86_INVPCID_TYPE_ALL_CONTEXT_INCL_GLOBAL 2 +/** All-context excluding globals invalidation. */ +#define X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL 3 +/** The maximum valid invalidation type value. */ +#define X86_INVPCID_TYPE_MAX_VALID X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL + + +/** @name Special FPU integer values. + * @{ */ +#define X86_FPU_INT64_INDEFINITE INT64_MIN +#define X86_FPU_INT32_INDEFINITE INT32_MIN +#define X86_FPU_INT16_INDEFINITE INT16_MIN +/** @} */ + +/** + * 32-bit protected mode FSTENV image. + */ +typedef struct X86FSTENV32P +{ + uint16_t FCW; /**< 0x00 */ + uint16_t padding1; /**< 0x02 */ + uint16_t FSW; /**< 0x04 */ + uint16_t padding2; /**< 0x06 */ + uint16_t FTW; /**< 0x08 */ + uint16_t padding3; /**< 0x0a */ + uint32_t FPUIP; /**< 0x0c */ + uint16_t FPUCS; /**< 0x10 */ + uint16_t FOP; /**< 0x12 */ + uint32_t FPUDP; /**< 0x14 */ + uint16_t FPUDS; /**< 0x18 */ + uint16_t padding4; /**< 0x1a */ +} X86FSTENV32P; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FSTENV32P, 0x1c); +#endif +/** Pointer to a 32-bit protected mode FSTENV image. */ +typedef X86FSTENV32P *PX86FSTENV32P; +/** Pointer to a const 32-bit protected mode FSTENV image. */ +typedef X86FSTENV32P const *PCX86FSTENV32P; + + +/** + * 80-bit MMX/FPU register type. + */ +typedef struct X86FPUMMX +{ + uint8_t reg[10]; +} X86FPUMMX; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FPUMMX, 10); +#endif +/** Pointer to a 80-bit MMX/FPU register type. */ +typedef X86FPUMMX *PX86FPUMMX; +/** Pointer to a const 80-bit MMX/FPU register type. */ +typedef const X86FPUMMX *PCX86FPUMMX; + +/** FPU (x87) register. */ +typedef union X86FPUREG +{ + /** MMX view. */ + uint64_t mmx; + /** FPU view - todo. */ + X86FPUMMX fpu; + /** Extended precision floating point view. */ + RTFLOAT80U r80; + /** Extended precision floating point view v2 */ + RTFLOAT80U2 r80Ex; + /** 8-bit view. */ + uint8_t au8[16]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 64-bit view. */ + uint64_t au64[2]; + /** 128-bit view. (yeah, very helpful) */ + uint128_t au128[1]; +} X86FPUREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FPUREG, 16); +#endif +/** Pointer to a FPU register. */ +typedef X86FPUREG *PX86FPUREG; +/** Pointer to a const FPU register. */ +typedef X86FPUREG const *PCX86FPUREG; + +/** FPU (x87) register - v2 with correct size. */ +#pragma pack(1) +typedef union X86FPUREG2 +{ + /** MMX view. */ + uint64_t mmx; + /** FPU view - todo. */ + X86FPUMMX fpu; + /** Extended precision floating point view. */ + RTFLOAT80U r80; + /** 8-bit view. */ + uint8_t au8[10]; + /** 16-bit view. */ + uint16_t au16[5]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 64-bit view. */ + uint64_t au64[1]; +} X86FPUREG2; +#pragma pack() +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FPUREG2, 10); +#endif +/** Pointer to a FPU register - v2. */ +typedef X86FPUREG2 *PX86FPUREG2; +/** Pointer to a const FPU register - v2. */ +typedef X86FPUREG2 const *PCX86FPUREG2; + +/** + * XMM register union. + */ +typedef union X86XMMREG +{ + /** XMM Register view. */ + uint128_t xmm; + /** 8-bit view. */ + uint8_t au8[16]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 64-bit view. */ + uint64_t au64[2]; + /** Signed 8-bit view. */ + int8_t ai8[16]; + /** Signed 16-bit view. */ + int16_t ai16[8]; + /** Signed 32-bit view. */ + int32_t ai32[4]; + /** Signed 64-bit view. */ + int64_t ai64[2]; + /** 128-bit view. (yeah, very helpful) */ + uint128_t au128[1]; + /** Single precision floating point view. */ + RTFLOAT32U ar32[4]; + /** Double precision floating point view. */ + RTFLOAT64U ar64[2]; +#ifndef VBOX_FOR_DTRACE_LIB + /** Confusing nested 128-bit union view (this is what xmm should've been). */ + RTUINT128U uXmm; +#endif +} X86XMMREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XMMREG, 16); +#endif +/** Pointer to an XMM register state. */ +typedef X86XMMREG *PX86XMMREG; +/** Pointer to a const XMM register state. */ +typedef X86XMMREG const *PCX86XMMREG; + +/** + * YMM register union. + */ +typedef union X86YMMREG +{ + /** YMM register view. */ + RTUINT256U ymm; + /** 8-bit view. */ + uint8_t au8[32]; + /** 16-bit view. */ + uint16_t au16[16]; + /** 32-bit view. */ + uint32_t au32[8]; + /** 64-bit view. */ + uint64_t au64[4]; + /** 128-bit view. (yeah, very helpful) */ + uint128_t au128[2]; + /** Single precision floating point view. */ + RTFLOAT32U ar32[8]; + /** Double precision floating point view. */ + RTFLOAT64U ar64[4]; + /** XMM sub register view. */ + X86XMMREG aXmm[2]; +} X86YMMREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86YMMREG, 32); +#endif +/** Pointer to an YMM register state. */ +typedef X86YMMREG *PX86YMMREG; +/** Pointer to a const YMM register state. */ +typedef X86YMMREG const *PCX86YMMREG; + +/** + * ZMM register union. + */ +typedef union X86ZMMREG +{ + /** 8-bit view. */ + uint8_t au8[64]; + /** 16-bit view. */ + uint16_t au16[32]; + /** 32-bit view. */ + uint32_t au32[16]; + /** 64-bit view. */ + uint64_t au64[8]; + /** 128-bit view. (yeah, very helpful) */ + uint128_t au128[4]; + /** Single precision floating point view. */ + RTFLOAT32U ar32[16]; + /** Double precision floating point view. */ + RTFLOAT64U ar64[8]; + /** XMM sub register view. */ + X86XMMREG aXmm[4]; + /** YMM sub register view. */ + X86YMMREG aYmm[2]; +} X86ZMMREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86ZMMREG, 64); +#endif +/** Pointer to an ZMM register state. */ +typedef X86ZMMREG *PX86ZMMREG; +/** Pointer to a const ZMM register state. */ +typedef X86ZMMREG const *PCX86ZMMREG; + + +/** + * 32-bit FPU state (aka FSAVE/FRSTOR Memory Region). + */ +#pragma pack(1) +typedef struct X86FPUSTATE +{ + /** 0x00 - Control word. */ + uint16_t FCW; + /** 0x02 - Alignment word */ + uint16_t Dummy1; + /** 0x04 - Status word. */ + uint16_t FSW; + /** 0x06 - Alignment word */ + uint16_t Dummy2; + /** 0x08 - Tag word */ + uint16_t FTW; + /** 0x0a - Alignment word */ + uint16_t Dummy3; + + /** 0x0c - Instruction pointer. */ + uint32_t FPUIP; + /** 0x10 - Code selector. */ + uint16_t CS; + /** 0x12 - Opcode. */ + uint16_t FOP; + /** 0x14 - Data pointer. */ + uint32_t FPUOO; + /** 0x18 - FOS. */ + uint16_t FPUOS; + /** 0x0a - Alignment word */ + uint16_t Dummy4; + /** 0x1c - FPU register. */ + X86FPUREG2 regs[8]; +} X86FPUSTATE; +#pragma pack() +AssertCompileSize(X86FPUSTATE, 108); +/** Pointer to a FPU state. */ +typedef X86FPUSTATE *PX86FPUSTATE; +/** Pointer to a const FPU state. */ +typedef const X86FPUSTATE *PCX86FPUSTATE; + +/** + * FPU Extended state (aka FXSAVE/FXRSTORE Memory Region). + */ +#pragma pack(1) +typedef struct X86FXSTATE +{ + /** 0x00 - Control word. */ + uint16_t FCW; + /** 0x02 - Status word. */ + uint16_t FSW; + /** 0x04 - Tag word. (The upper byte is always zero.) */ + uint16_t FTW; + /** 0x06 - Opcode. */ + uint16_t FOP; + /** 0x08 - Instruction pointer. */ + uint32_t FPUIP; + /** 0x0c - Code selector. */ + uint16_t CS; + uint16_t Rsrvd1; + /** 0x10 - Data pointer. */ + uint32_t FPUDP; + /** 0x14 - Data segment */ + uint16_t DS; + /** 0x16 */ + uint16_t Rsrvd2; + /** 0x18 */ + uint32_t MXCSR; + /** 0x1c */ + uint32_t MXCSR_MASK; + /** 0x20 - FPU registers. */ + X86FPUREG aRegs[8]; + /** 0xA0 - XMM registers - 8 registers in 32 bits mode, 16 in long mode. */ + X86XMMREG aXMM[16]; + /* - offset 416 - */ + uint32_t au32RsrvdRest[(464 - 416) / sizeof(uint32_t)]; + /* - offset 464 - Software usable reserved bits. */ + uint32_t au32RsrvdForSoftware[(512 - 464) / sizeof(uint32_t)]; +} X86FXSTATE; +#pragma pack() +/** Pointer to a FPU Extended state. */ +typedef X86FXSTATE *PX86FXSTATE; +/** Pointer to a const FPU Extended state. */ +typedef const X86FXSTATE *PCX86FXSTATE; + +/** Offset for software usable reserved bits (464:511) where we store a 32-bit + * magic. Don't forget to update x86.mac if you change this! */ +#define X86_OFF_FXSTATE_RSVD 0x1d0 +/** The 32-bit magic used to recognize if this a 32-bit FPU state. Don't + * forget to update x86.mac if you change this! + * @todo r=bird: This has nothing what-so-ever to do here.... */ +#define X86_FXSTATE_RSVD_32BIT_MAGIC 0x32b3232b +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FXSTATE, 512); +AssertCompileMemberOffset(X86FXSTATE, au32RsrvdForSoftware, X86_OFF_FXSTATE_RSVD); +#endif + +/** @name FPU status word flags. + * @{ */ +/** Exception Flag: Invalid operation. */ +#define X86_FSW_IE RT_BIT_32(0) +#define X86_FSW_IE_BIT 0 +/** Exception Flag: Denormalized operand. */ +#define X86_FSW_DE RT_BIT_32(1) +#define X86_FSW_DE_BIT 1 +/** Exception Flag: Zero divide. */ +#define X86_FSW_ZE RT_BIT_32(2) +#define X86_FSW_ZE_BIT 2 +/** Exception Flag: Overflow. */ +#define X86_FSW_OE RT_BIT_32(3) +#define X86_FSW_OE_BIT 3 +/** Exception Flag: Underflow. */ +#define X86_FSW_UE RT_BIT_32(4) +#define X86_FSW_UE_BIT 4 +/** Exception Flag: Precision. */ +#define X86_FSW_PE RT_BIT_32(5) +#define X86_FSW_PE_BIT 5 +/** Stack fault. */ +#define X86_FSW_SF RT_BIT_32(6) +#define X86_FSW_SF_BIT 6 +/** Error summary status. */ +#define X86_FSW_ES RT_BIT_32(7) +#define X86_FSW_ES_BIT 7 +/** Mask of exceptions flags, excluding the summary bit. */ +#define X86_FSW_XCPT_MASK UINT16_C(0x007f) +/** Mask of exceptions flags, including the summary bit. */ +#define X86_FSW_XCPT_ES_MASK UINT16_C(0x00ff) +/** Condition code 0. */ +#define X86_FSW_C0 RT_BIT_32(X86_FSW_C0_BIT) +#define X86_FSW_C0_BIT 8 +/** Condition code 1. */ +#define X86_FSW_C1 RT_BIT_32(X86_FSW_C1_BIT) +#define X86_FSW_C1_BIT 9 +/** Condition code 2. */ +#define X86_FSW_C2 RT_BIT_32(X86_FSW_C2_BIT) +#define X86_FSW_C2_BIT 10 +/** Top of the stack mask. */ +#define X86_FSW_TOP_MASK UINT16_C(0x3800) +/** TOP shift value. */ +#define X86_FSW_TOP_SHIFT 11 +/** Mask for getting TOP value after shifting it right. */ +#define X86_FSW_TOP_SMASK UINT16_C(0x0007) +/** Get the TOP value. */ +#define X86_FSW_TOP_GET(a_uFsw) (((a_uFsw) >> X86_FSW_TOP_SHIFT) & X86_FSW_TOP_SMASK) +/** Get the TOP value offsetted by a_iSt (0-7). */ +#define X86_FSW_TOP_GET_ST(a_uFsw, a_iSt) ((((a_uFsw) >> X86_FSW_TOP_SHIFT) + (a_iSt)) & X86_FSW_TOP_SMASK) +/** Condition code 3. */ +#define X86_FSW_C3 RT_BIT_32(X86_FSW_C3_BIT) +#define X86_FSW_C3_BIT 14 +/** Mask of exceptions flags, including the summary bit. */ +#define X86_FSW_C_MASK UINT16_C(0x4700) +/** FPU busy. */ +#define X86_FSW_B RT_BIT_32(15) +/** For use with FPREM and FPREM1. */ +#define X86_FSW_CX_TO_QUOTIENT(a_fFsw) \ + ( (((a_fFsw) & X86_FSW_C1) >> (X86_FSW_C1_BIT - 0)) \ + | (((a_fFsw) & X86_FSW_C3) >> (X86_FSW_C3_BIT - 1)) \ + | (((a_fFsw) & X86_FSW_C0) >> (X86_FSW_C0_BIT - 2)) ) +/** For use with FPREM and FPREM1. */ +#define X86_FSW_CX_FROM_QUOTIENT(a_uQuotient) \ + ( ((uint16_t)((a_uQuotient) & 1) << (X86_FSW_C1_BIT - 0)) \ + | ((uint16_t)((a_uQuotient) & 2) << (X86_FSW_C3_BIT - 1)) \ + | ((uint16_t)((a_uQuotient) & 4) << (X86_FSW_C0_BIT - 2)) ) +/** @} */ + + +/** @name FPU control word flags. + * @{ */ +/** Exception Mask: Invalid operation. */ +#define X86_FCW_IM RT_BIT_32(0) +#define X86_FCW_IM_BIT 0 +/** Exception Mask: Denormalized operand. */ +#define X86_FCW_DM RT_BIT_32(1) +#define X86_FCW_DM_BIT 1 +/** Exception Mask: Zero divide. */ +#define X86_FCW_ZM RT_BIT_32(2) +#define X86_FCW_ZM_BIT 2 +/** Exception Mask: Overflow. */ +#define X86_FCW_OM RT_BIT_32(3) +#define X86_FCW_OM_BIT 3 +/** Exception Mask: Underflow. */ +#define X86_FCW_UM RT_BIT_32(4) +#define X86_FCW_UM_BIT 4 +/** Exception Mask: Precision. */ +#define X86_FCW_PM RT_BIT_32(5) +#define X86_FCW_PM_BIT 5 +/** Mask all exceptions, the value typically loaded (by for instance fninit). + * @remarks This includes reserved bit 6. */ +#define X86_FCW_MASK_ALL UINT16_C(0x007f) +/** Mask all exceptions. Same as X86_FSW_XCPT_MASK. */ +#define X86_FCW_XCPT_MASK UINT16_C(0x003f) +/** Precision control mask. */ +#define X86_FCW_PC_MASK UINT16_C(0x0300) +/** Precision control shift. */ +#define X86_FCW_PC_SHIFT 8 +/** Precision control: 24-bit. */ +#define X86_FCW_PC_24 UINT16_C(0x0000) +/** Precision control: Reserved. */ +#define X86_FCW_PC_RSVD UINT16_C(0x0100) +/** Precision control: 53-bit. */ +#define X86_FCW_PC_53 UINT16_C(0x0200) +/** Precision control: 64-bit. */ +#define X86_FCW_PC_64 UINT16_C(0x0300) +/** Rounding control mask. */ +#define X86_FCW_RC_MASK UINT16_C(0x0c00) +/** Rounding control shift. */ +#define X86_FCW_RC_SHIFT 10 +/** Rounding control: To nearest. */ +#define X86_FCW_RC_NEAREST UINT16_C(0x0000) +/** Rounding control: Down. */ +#define X86_FCW_RC_DOWN UINT16_C(0x0400) +/** Rounding control: Up. */ +#define X86_FCW_RC_UP UINT16_C(0x0800) +/** Rounding control: Towards zero. */ +#define X86_FCW_RC_ZERO UINT16_C(0x0c00) +/** Infinity control mask - obsolete, 8087 & 287 only. */ +#define X86_FCW_IC_MASK UINT16_C(0x1000) +/** Infinity control: Affine - positive infinity is distictly different from + * negative infinity. + * @note 8087, 287 only */ +#define X86_FCW_IC_AFFINE UINT16_C(0x1000) +/** Infinity control: Projective - positive and negative infinity are the + * same (sign ignored). + * @note 8087, 287 only */ +#define X86_FCW_IC_PROJECTIVE UINT16_C(0x0000) +/** Bits which should be zero, apparently. */ +#define X86_FCW_ZERO_MASK UINT16_C(0xf080) +/** @} */ + +/** @name SSE MXCSR + * @{ */ +/** Exception Flag: Invalid operation. */ +#define X86_MXCSR_IE RT_BIT_32(0) +/** Exception Flag: Denormalized operand. */ +#define X86_MXCSR_DE RT_BIT_32(1) +/** Exception Flag: Zero divide. */ +#define X86_MXCSR_ZE RT_BIT_32(2) +/** Exception Flag: Overflow. */ +#define X86_MXCSR_OE RT_BIT_32(3) +/** Exception Flag: Underflow. */ +#define X86_MXCSR_UE RT_BIT_32(4) +/** Exception Flag: Precision. */ +#define X86_MXCSR_PE RT_BIT_32(5) +/** Exception Flags: mask */ +#define X86_MXCSR_XCPT_FLAGS UINT32_C(0x003f) + +/** Denormals are zero. */ +#define X86_MXCSR_DAZ RT_BIT_32(6) + +/** Exception Mask: Invalid operation. */ +#define X86_MXCSR_IM RT_BIT_32(7) +/** Exception Mask: Denormalized operand. */ +#define X86_MXCSR_DM RT_BIT_32(8) +/** Exception Mask: Zero divide. */ +#define X86_MXCSR_ZM RT_BIT_32(9) +/** Exception Mask: Overflow. */ +#define X86_MXCSR_OM RT_BIT_32(10) +/** Exception Mask: Underflow. */ +#define X86_MXCSR_UM RT_BIT_32(11) +/** Exception Mask: Precision. */ +#define X86_MXCSR_PM RT_BIT_32(12) +/** Exception Mask: mask. */ +#define X86_MXCSR_XCPT_MASK UINT32_C(0x1f80) +/** Exception Mask: shift. */ +#define X86_MXCSR_XCPT_MASK_SHIFT 7 + +/** Rounding control mask. */ +#define X86_MXCSR_RC_MASK UINT32_C(0x6000) +/** Rounding control shift. */ +#define X86_MXCSR_RC_SHIFT 13 +/** Rounding control: To nearest. */ +#define X86_MXCSR_RC_NEAREST UINT32_C(0x0000) +/** Rounding control: Down. */ +#define X86_MXCSR_RC_DOWN UINT32_C(0x2000) +/** Rounding control: Up. */ +#define X86_MXCSR_RC_UP UINT32_C(0x4000) +/** Rounding control: Towards zero. */ +#define X86_MXCSR_RC_ZERO UINT32_C(0x6000) + +/** Flush-to-zero for masked underflow. */ +#define X86_MXCSR_FZ RT_BIT_32(15) + +/** Misaligned Exception Mask (AMD MISALIGNSSE). */ +#define X86_MXCSR_MM RT_BIT_32(17) +/** Bits which should be zero, apparently. */ +#define X86_MXCSR_ZERO_MASK UINT32_C(0xfffd0000) +/** @} */ + +/** + * XSAVE header. + */ +typedef struct X86XSAVEHDR +{ + /** XTATE_BV - Bitmap indicating whether a component is in the state. */ + uint64_t bmXState; + /** XCOMP_BC - Bitmap used by instructions applying structure compaction. */ + uint64_t bmXComp; + /** Reserved for furture extensions, probably MBZ. */ + uint64_t au64Reserved[6]; +} X86XSAVEHDR; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEHDR, 64); +#endif +/** Pointer to an XSAVE header. */ +typedef X86XSAVEHDR *PX86XSAVEHDR; +/** Pointer to a const XSAVE header. */ +typedef X86XSAVEHDR const *PCX86XSAVEHDR; + + +/** + * The high 128-bit YMM register state (XSAVE_C_YMM). + * (The lower 128-bits being in X86FXSTATE.) + */ +typedef struct X86XSAVEYMMHI +{ + /** 16 registers in 64-bit mode, 8 in 32-bit mode. */ + X86XMMREG aYmmHi[16]; +} X86XSAVEYMMHI; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEYMMHI, 256); +#endif +/** Pointer to a high 128-bit YMM register state. */ +typedef X86XSAVEYMMHI *PX86XSAVEYMMHI; +/** Pointer to a const high 128-bit YMM register state. */ +typedef X86XSAVEYMMHI const *PCX86XSAVEYMMHI; + +/** + * Intel MPX bound registers state (XSAVE_C_BNDREGS). + */ +typedef struct X86XSAVEBNDREGS +{ + /** Array of registers (BND0...BND3). */ + struct + { + /** Lower bound. */ + uint64_t uLowerBound; + /** Upper bound. */ + uint64_t uUpperBound; + } aRegs[4]; +} X86XSAVEBNDREGS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEBNDREGS, 64); +#endif +/** Pointer to a MPX bound register state. */ +typedef X86XSAVEBNDREGS *PX86XSAVEBNDREGS; +/** Pointer to a const MPX bound register state. */ +typedef X86XSAVEBNDREGS const *PCX86XSAVEBNDREGS; + +/** + * Intel MPX bound config and status register state (XSAVE_C_BNDCSR). + */ +typedef struct X86XSAVEBNDCFG +{ + uint64_t fConfig; + uint64_t fStatus; +} X86XSAVEBNDCFG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEBNDCFG, 16); +#endif +/** Pointer to a MPX bound config and status register state. */ +typedef X86XSAVEBNDCFG *PX86XSAVEBNDCFG; +/** Pointer to a const MPX bound config and status register state. */ +typedef X86XSAVEBNDCFG *PCX86XSAVEBNDCFG; + +/** + * AVX-512 opmask state (XSAVE_C_OPMASK). + */ +typedef struct X86XSAVEOPMASK +{ + /** The K0..K7 values. */ + uint64_t aKRegs[8]; +} X86XSAVEOPMASK; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEOPMASK, 64); +#endif +/** Pointer to a AVX-512 opmask state. */ +typedef X86XSAVEOPMASK *PX86XSAVEOPMASK; +/** Pointer to a const AVX-512 opmask state. */ +typedef X86XSAVEOPMASK const *PCX86XSAVEOPMASK; + +/** + * ZMM0-15 upper 256 bits introduced in AVX-512 (XSAVE_C_ZMM_HI256). + */ +typedef struct X86XSAVEZMMHI256 +{ + /** Upper 256-bits of ZMM0-15. */ + X86YMMREG aHi256Regs[16]; +} X86XSAVEZMMHI256; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEZMMHI256, 512); +#endif +/** Pointer to a state comprising the upper 256-bits of ZMM0-15. */ +typedef X86XSAVEZMMHI256 *PX86XSAVEZMMHI256; +/** Pointer to a const state comprising the upper 256-bits of ZMM0-15. */ +typedef X86XSAVEZMMHI256 const *PCX86XSAVEZMMHI256; + +/** + * ZMM16-31 register state introduced in AVX-512 (XSAVE_C_ZMM_16HI). + */ +typedef struct X86XSAVEZMM16HI +{ + /** ZMM16 thru ZMM31. */ + X86ZMMREG aRegs[16]; +} X86XSAVEZMM16HI; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEZMM16HI, 1024); +#endif +/** Pointer to a state comprising ZMM16-32. */ +typedef X86XSAVEZMM16HI *PX86XSAVEZMM16HI; +/** Pointer to a const state comprising ZMM16-32. */ +typedef X86XSAVEZMM16HI const *PCX86XSAVEZMM16HI; + +/** + * AMD Light weight profiling state (XSAVE_C_LWP). + * + * We probably won't play with this as AMD seems to be dropping from their "zen" + * processor micro architecture. + */ +typedef struct X86XSAVELWP +{ + /** Details when needed. */ + uint64_t auLater[128/8]; +} X86XSAVELWP; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVELWP, 128); +#endif + + +/** + * x86 FPU/SSE/AVX/XXXX state. + * + * Please bump DBGFCORE_FMT_VERSION by 1 in dbgfcorefmt.h if you make any + * changes to this structure. + */ +typedef struct X86XSAVEAREA +{ + /** The x87 and SSE region (or legacy region if you like). */ + X86FXSTATE x87; + /** The XSAVE header. */ + X86XSAVEHDR Hdr; + /** Beyond the header, there isn't really a fixed layout, but we can + generally assume the YMM (AVX) register extensions are present and + follows immediately. */ + union + { + /** The high 128-bit AVX registers for easy access by IEM. + * @note This ASSUMES they will always be here... */ + X86XSAVEYMMHI YmmHi; + + /** This is a typical layout on intel CPUs (good for debuggers). */ + struct + { + X86XSAVEYMMHI YmmHi; + X86XSAVEBNDREGS BndRegs; + X86XSAVEBNDCFG BndCfg; + uint8_t abFudgeToMatchDocs[0xB0]; + X86XSAVEOPMASK Opmask; + X86XSAVEZMMHI256 ZmmHi256; + X86XSAVEZMM16HI Zmm16Hi; + } Intel; + + /** This is a typical layout on AMD Bulldozer type CPUs (good for debuggers). */ + struct + { + X86XSAVEYMMHI YmmHi; + X86XSAVELWP Lwp; + } AmdBd; + + /** To enbling static deployments that have a reasonable chance of working for + * the next 3-6 CPU generations without running short on space, we allocate a + * lot of extra space here, making the structure a round 8KB in size. This + * leaves us 7616 bytes for extended state. The skylake xeons are likely to use + * 2112 of these, leaving us with 5504 bytes for future Intel generations. */ + uint8_t ab[8192 - 512 - 64]; + } u; +} X86XSAVEAREA; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEAREA, 8192); +AssertCompileMemberSize(X86XSAVEAREA, u.Intel, 0x840 /*2112 => total 0xa80 (2688) */); +AssertCompileMemberOffset(X86XSAVEAREA, Hdr, 0x200); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.YmmHi, 0x240); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.BndRegs, 0x340); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.BndCfg, 0x380); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.Opmask, 0x440 /* 1088 */); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.ZmmHi256, 0x480 /* 1152 */); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.Zmm16Hi, 0x680 /* 1664 */); +#endif +/** Pointer to a XSAVE area. */ +typedef X86XSAVEAREA *PX86XSAVEAREA; +/** Pointer to a const XSAVE area. */ +typedef X86XSAVEAREA const *PCX86XSAVEAREA; + + +/** @name XSAVE_C_XXX - XSAVE State Components Bits (XCR0). + * @{ */ +/** Bit 0 - x87 - Legacy FPU state (bit number) */ +#define XSAVE_C_X87_BIT 0 +/** Bit 0 - x87 - Legacy FPU state. */ +#define XSAVE_C_X87 RT_BIT_64(XSAVE_C_X87_BIT) +/** Bit 1 - SSE - 128-bit SSE state (bit number). */ +#define XSAVE_C_SSE_BIT 1 +/** Bit 1 - SSE - 128-bit SSE state. */ +#define XSAVE_C_SSE RT_BIT_64(XSAVE_C_SSE_BIT) +/** Bit 2 - YMM_Hi128 - Upper 128 bits of YMM0-15 (AVX) (bit number). */ +#define XSAVE_C_YMM_BIT 2 +/** Bit 2 - YMM_Hi128 - Upper 128 bits of YMM0-15 (AVX). */ +#define XSAVE_C_YMM RT_BIT_64(XSAVE_C_YMM_BIT) +/** Bit 3 - BNDREGS - MPX bound register state (bit number). */ +#define XSAVE_C_BNDREGS_BIT 3 +/** Bit 3 - BNDREGS - MPX bound register state. */ +#define XSAVE_C_BNDREGS RT_BIT_64(XSAVE_C_BNDREGS_BIT) +/** Bit 4 - BNDCSR - MPX bound config and status state (bit number). */ +#define XSAVE_C_BNDCSR_BIT 4 +/** Bit 4 - BNDCSR - MPX bound config and status state. */ +#define XSAVE_C_BNDCSR RT_BIT_64(XSAVE_C_BNDCSR_BIT) +/** Bit 5 - Opmask - opmask state (bit number). */ +#define XSAVE_C_OPMASK_BIT 5 +/** Bit 5 - Opmask - opmask state. */ +#define XSAVE_C_OPMASK RT_BIT_64(XSAVE_C_OPMASK_BIT) +/** Bit 6 - ZMM_Hi256 - Upper 256 bits of ZMM0-15 (AVX-512) (bit number). */ +#define XSAVE_C_ZMM_HI256_BIT 6 +/** Bit 6 - ZMM_Hi256 - Upper 256 bits of ZMM0-15 (AVX-512). */ +#define XSAVE_C_ZMM_HI256 RT_BIT_64(XSAVE_C_ZMM_HI256_BIT) +/** Bit 7 - Hi16_ZMM - 512-bits ZMM16-31 state (AVX-512) (bit number). */ +#define XSAVE_C_ZMM_16HI_BIT 7 +/** Bit 7 - Hi16_ZMM - 512-bits ZMM16-31 state (AVX-512). */ +#define XSAVE_C_ZMM_16HI RT_BIT_64(XSAVE_C_ZMM_16HI_BIT) +/** Bit 9 - PKRU - Protection-key state (bit number). */ +#define XSAVE_C_PKRU_BIT 9 +/** Bit 9 - PKRU - Protection-key state. */ +#define XSAVE_C_PKRU RT_BIT_64(XSAVE_C_PKRU_BIT) +/** Bit 62 - LWP - Lightweight Profiling (AMD) (bit number). */ +#define XSAVE_C_LWP_BIT 62 +/** Bit 62 - LWP - Lightweight Profiling (AMD). */ +#define XSAVE_C_LWP RT_BIT_64(XSAVE_C_LWP_BIT) +/** Bit 63 - X - Reserved (MBZ) for extending XCR0 (bit number). */ +#define XSAVE_C_X_BIT 63 +/** Bit 63 - X - Reserved (MBZ) for extending XCR0 (AMD). */ +#define XSAVE_C_X RT_BIT_64(XSAVE_C_X_BIT) +/** @} */ + + + +/** @name Selector Descriptor + * @{ + */ + +#ifndef VBOX_FOR_DTRACE_LIB +/** + * Descriptor attributes (as seen by VT-x). + */ +typedef struct X86DESCATTRBITS +{ + /** 00 - Segment Type. */ + unsigned u4Type : 4; + /** 04 - Descriptor Type. System(=0) or code/data selector */ + unsigned u1DescType : 1; + /** 05 - Descriptor Privilege level. */ + unsigned u2Dpl : 2; + /** 07 - Flags selector present(=1) or not. */ + unsigned u1Present : 1; + /** 08 - Segment limit 16-19. */ + unsigned u4LimitHigh : 4; + /** 0c - Available for system software. */ + unsigned u1Available : 1; + /** 0d - 32 bits mode: Reserved - 0, long mode: Long Attribute Bit. */ + unsigned u1Long : 1; + /** 0e - This flags meaning depends on the segment type. Try make sense out + * of the intel manual yourself. */ + unsigned u1DefBig : 1; + /** 0f - Granularity of the limit. If set 4KB granularity is used, if + * clear byte. */ + unsigned u1Granularity : 1; + /** 10 - "Unusable" selector, special Intel (VT-x only?) bit. */ + unsigned u1Unusable : 1; +} X86DESCATTRBITS; +#endif /* !VBOX_FOR_DTRACE_LIB */ + +/** @name X86DESCATTR masks + * @{ */ +#define X86DESCATTR_TYPE UINT32_C(0x0000000f) +#define X86DESCATTR_DT UINT32_C(0x00000010) +#define X86DESCATTR_DPL UINT32_C(0x00000060) +#define X86DESCATTR_DPL_SHIFT 5 /**< Shift count for the DPL value. */ +#define X86DESCATTR_P UINT32_C(0x00000080) +#define X86DESCATTR_LIMIT_HIGH UINT32_C(0x00000f00) +#define X86DESCATTR_AVL UINT32_C(0x00001000) +#define X86DESCATTR_L UINT32_C(0x00002000) +#define X86DESCATTR_D UINT32_C(0x00004000) +#define X86DESCATTR_G UINT32_C(0x00008000) +#define X86DESCATTR_UNUSABLE UINT32_C(0x00010000) +/** @} */ + +#pragma pack(1) +typedef union X86DESCATTR +{ + /** Unsigned integer view. */ + uint32_t u; +#ifndef VBOX_FOR_DTRACE_LIB + /** Normal view. */ + X86DESCATTRBITS n; +#endif +} X86DESCATTR; +#pragma pack() +/** Pointer to descriptor attributes. */ +typedef X86DESCATTR *PX86DESCATTR; +/** Pointer to const descriptor attributes. */ +typedef const X86DESCATTR *PCX86DESCATTR; + +#ifndef VBOX_FOR_DTRACE_LIB + +/** + * Generic descriptor table entry + */ +#pragma pack(1) +typedef struct X86DESCGENERIC +{ + /** 00 - Limit - Low word. */ + unsigned u16LimitLow : 16; + /** 10 - Base address - low word. + * Don't try set this to 24 because MSC is doing stupid things then. */ + unsigned u16BaseLow : 16; + /** 20 - Base address - first 8 bits of high word. */ + unsigned u8BaseHigh1 : 8; + /** 28 - Segment Type. */ + unsigned u4Type : 4; + /** 2c - Descriptor Type. System(=0) or code/data selector */ + unsigned u1DescType : 1; + /** 2d - Descriptor Privilege level. */ + unsigned u2Dpl : 2; + /** 2f - Flags selector present(=1) or not. */ + unsigned u1Present : 1; + /** 30 - Segment limit 16-19. */ + unsigned u4LimitHigh : 4; + /** 34 - Available for system software. */ + unsigned u1Available : 1; + /** 35 - 32 bits mode: Reserved - 0, long mode: Long Attribute Bit. */ + unsigned u1Long : 1; + /** 36 - This flags meaning depends on the segment type. Try make sense out + * of the intel manual yourself. */ + unsigned u1DefBig : 1; + /** 37 - Granularity of the limit. If set 4KB granularity is used, if + * clear byte. */ + unsigned u1Granularity : 1; + /** 38 - Base address - highest 8 bits. */ + unsigned u8BaseHigh2 : 8; +} X86DESCGENERIC; +#pragma pack() +/** Pointer to a generic descriptor entry. */ +typedef X86DESCGENERIC *PX86DESCGENERIC; +/** Pointer to a const generic descriptor entry. */ +typedef const X86DESCGENERIC *PCX86DESCGENERIC; + +/** @name Bit offsets of X86DESCGENERIC members. + * @{*/ +#define X86DESCGENERIC_BIT_OFF_LIMIT_LOW (0) /**< Bit offset of X86DESCGENERIC::u16LimitLow. */ +#define X86DESCGENERIC_BIT_OFF_BASE_LOW (16) /**< Bit offset of X86DESCGENERIC::u16BaseLow. */ +#define X86DESCGENERIC_BIT_OFF_BASE_HIGH1 (32) /**< Bit offset of X86DESCGENERIC::u8BaseHigh1. */ +#define X86DESCGENERIC_BIT_OFF_TYPE (40) /**< Bit offset of X86DESCGENERIC::u4Type. */ +#define X86DESCGENERIC_BIT_OFF_DESC_TYPE (44) /**< Bit offset of X86DESCGENERIC::u1DescType. */ +#define X86DESCGENERIC_BIT_OFF_DPL (45) /**< Bit offset of X86DESCGENERIC::u2Dpl. */ +#define X86DESCGENERIC_BIT_OFF_PRESENT (47) /**< Bit offset of X86DESCGENERIC::uu1Present. */ +#define X86DESCGENERIC_BIT_OFF_LIMIT_HIGH (48) /**< Bit offset of X86DESCGENERIC::u4LimitHigh. */ +#define X86DESCGENERIC_BIT_OFF_AVAILABLE (52) /**< Bit offset of X86DESCGENERIC::u1Available. */ +#define X86DESCGENERIC_BIT_OFF_LONG (53) /**< Bit offset of X86DESCGENERIC::u1Long. */ +#define X86DESCGENERIC_BIT_OFF_DEF_BIG (54) /**< Bit offset of X86DESCGENERIC::u1DefBig. */ +#define X86DESCGENERIC_BIT_OFF_GRANULARITY (55) /**< Bit offset of X86DESCGENERIC::u1Granularity. */ +#define X86DESCGENERIC_BIT_OFF_BASE_HIGH2 (56) /**< Bit offset of X86DESCGENERIC::u8BaseHigh2. */ +/** @} */ + + +/** @name LAR mask + * @{ */ +#define X86LAR_F_TYPE UINT16_C( 0x0f00) +#define X86LAR_F_DT UINT16_C( 0x1000) +#define X86LAR_F_DPL UINT16_C( 0x6000) +#define X86LAR_F_DPL_SHIFT 13 /**< Shift count for the DPL value. */ +#define X86LAR_F_P UINT16_C( 0x8000) +#define X86LAR_F_AVL UINT32_C(0x00100000) +#define X86LAR_F_L UINT32_C(0x00200000) +#define X86LAR_F_D UINT32_C(0x00400000) +#define X86LAR_F_G UINT32_C(0x00800000) +/** @} */ + + +/** + * Call-, Interrupt-, Trap- or Task-gate descriptor (legacy). + */ +typedef struct X86DESCGATE +{ + /** 00 - Target code segment offset - Low word. + * Ignored if task-gate. */ + unsigned u16OffsetLow : 16; + /** 10 - Target code segment selector for call-, interrupt- and trap-gates, + * TSS selector if task-gate. */ + unsigned u16Sel : 16; + /** 20 - Number of parameters for a call-gate. + * Ignored if interrupt-, trap- or task-gate. */ + unsigned u5ParmCount : 5; + /** 25 - Reserved / ignored. */ + unsigned u3Reserved : 3; + /** 28 - Segment Type. */ + unsigned u4Type : 4; + /** 2c - Descriptor Type (0 = system). */ + unsigned u1DescType : 1; + /** 2d - Descriptor Privilege level. */ + unsigned u2Dpl : 2; + /** 2f - Flags selector present(=1) or not. */ + unsigned u1Present : 1; + /** 30 - Target code segment offset - High word. + * Ignored if task-gate. */ + unsigned u16OffsetHigh : 16; +} X86DESCGATE; +/** Pointer to a Call-, Interrupt-, Trap- or Task-gate descriptor entry. */ +typedef X86DESCGATE *PX86DESCGATE; +/** Pointer to a const Call-, Interrupt-, Trap- or Task-gate descriptor entry. */ +typedef const X86DESCGATE *PCX86DESCGATE; + +#endif /* VBOX_FOR_DTRACE_LIB */ + +/** + * Descriptor table entry. + */ +#pragma pack(1) +typedef union X86DESC +{ +#ifndef VBOX_FOR_DTRACE_LIB + /** Generic descriptor view. */ + X86DESCGENERIC Gen; + /** Gate descriptor view. */ + X86DESCGATE Gate; +#endif + + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** Unsigned integer view. */ + uint64_t u; +} X86DESC; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86DESC, 8); +#endif +#pragma pack() +/** Pointer to descriptor table entry. */ +typedef X86DESC *PX86DESC; +/** Pointer to const descriptor table entry. */ +typedef const X86DESC *PCX86DESC; + +/** @def X86DESC_BASE + * Return the base address of a descriptor. + */ +#define X86DESC_BASE(a_pDesc) /*ASM-NOINC*/ \ + ( ((uint32_t)((a_pDesc)->Gen.u8BaseHigh2) << 24) \ + | ( (a_pDesc)->Gen.u8BaseHigh1 << 16) \ + | ( (a_pDesc)->Gen.u16BaseLow ) ) + +/** @def X86DESC_LIMIT + * Return the limit of a descriptor. + */ +#define X86DESC_LIMIT(a_pDesc) /*ASM-NOINC*/ \ + ( ((uint32_t)((a_pDesc)->Gen.u4LimitHigh) << 16) \ + | ( (a_pDesc)->Gen.u16LimitLow ) ) + +/** @def X86DESC_LIMIT_G + * Return the limit of a descriptor with the granularity bit taken into account. + * @returns Selector limit (uint32_t). + * @param a_pDesc Pointer to the descriptor. + */ +#define X86DESC_LIMIT_G(a_pDesc) /*ASM-NOINC*/ \ + ( (a_pDesc)->Gen.u1Granularity \ + ? ( ( ((uint32_t)(a_pDesc)->Gen.u4LimitHigh << 16) | (a_pDesc)->Gen.u16LimitLow ) << 12 ) | UINT32_C(0xfff) \ + : ((uint32_t)(a_pDesc)->Gen.u4LimitHigh << 16) | (a_pDesc)->Gen.u16LimitLow \ + ) + +/** @def X86DESC_GET_HID_ATTR + * Get the descriptor attributes for the hidden register. + */ +#define X86DESC_GET_HID_ATTR(a_pDesc) /*ASM-NOINC*/ \ + ( ((a_pDesc)->u >> (16+16+8)) & UINT32_C(0xf0ff) ) /** @todo do we have a define for 0xf0ff? */ + +#ifndef VBOX_FOR_DTRACE_LIB + +/** + * 64 bits generic descriptor table entry + * Note: most of these bits have no meaning in long mode. + */ +#pragma pack(1) +typedef struct X86DESC64GENERIC +{ + /** Limit - Low word - *IGNORED*. */ + uint32_t u16LimitLow : 16; + /** Base address - low word. - *IGNORED* + * Don't try set this to 24 because MSC is doing stupid things then. */ + uint32_t u16BaseLow : 16; + /** Base address - first 8 bits of high word. - *IGNORED* */ + uint32_t u8BaseHigh1 : 8; + /** Segment Type. */ + uint32_t u4Type : 4; + /** Descriptor Type. System(=0) or code/data selector */ + uint32_t u1DescType : 1; + /** Descriptor Privilege level. */ + uint32_t u2Dpl : 2; + /** Flags selector present(=1) or not. */ + uint32_t u1Present : 1; + /** Segment limit 16-19. - *IGNORED* */ + uint32_t u4LimitHigh : 4; + /** Available for system software. - *IGNORED* */ + uint32_t u1Available : 1; + /** Long mode flag. */ + uint32_t u1Long : 1; + /** This flags meaning depends on the segment type. Try make sense out + * of the intel manual yourself. */ + uint32_t u1DefBig : 1; + /** Granularity of the limit. If set 4KB granularity is used, if + * clear byte. - *IGNORED* */ + uint32_t u1Granularity : 1; + /** Base address - highest 8 bits. - *IGNORED* */ + uint32_t u8BaseHigh2 : 8; + /** Base address - bits 63-32. */ + uint32_t u32BaseHigh3 : 32; + uint32_t u8Reserved : 8; + uint32_t u5Zeros : 5; + uint32_t u19Reserved : 19; +} X86DESC64GENERIC; +#pragma pack() +/** Pointer to a generic descriptor entry. */ +typedef X86DESC64GENERIC *PX86DESC64GENERIC; +/** Pointer to a const generic descriptor entry. */ +typedef const X86DESC64GENERIC *PCX86DESC64GENERIC; + +/** + * System descriptor table entry (64 bits) + * + * @remarks This is, save a couple of comments, identical to X86DESC64GENERIC... + */ +#pragma pack(1) +typedef struct X86DESC64SYSTEM +{ + /** Limit - Low word. */ + uint32_t u16LimitLow : 16; + /** Base address - low word. + * Don't try set this to 24 because MSC is doing stupid things then. */ + uint32_t u16BaseLow : 16; + /** Base address - first 8 bits of high word. */ + uint32_t u8BaseHigh1 : 8; + /** Segment Type. */ + uint32_t u4Type : 4; + /** Descriptor Type. System(=0) or code/data selector */ + uint32_t u1DescType : 1; + /** Descriptor Privilege level. */ + uint32_t u2Dpl : 2; + /** Flags selector present(=1) or not. */ + uint32_t u1Present : 1; + /** Segment limit 16-19. */ + uint32_t u4LimitHigh : 4; + /** Available for system software. */ + uint32_t u1Available : 1; + /** Reserved - 0. */ + uint32_t u1Reserved : 1; + /** This flags meaning depends on the segment type. Try make sense out + * of the intel manual yourself. */ + uint32_t u1DefBig : 1; + /** Granularity of the limit. If set 4KB granularity is used, if + * clear byte. */ + uint32_t u1Granularity : 1; + /** Base address - bits 31-24. */ + uint32_t u8BaseHigh2 : 8; + /** Base address - bits 63-32. */ + uint32_t u32BaseHigh3 : 32; + uint32_t u8Reserved : 8; + uint32_t u5Zeros : 5; + uint32_t u19Reserved : 19; +} X86DESC64SYSTEM; +#pragma pack() +/** Pointer to a system descriptor entry. */ +typedef X86DESC64SYSTEM *PX86DESC64SYSTEM; +/** Pointer to a const system descriptor entry. */ +typedef const X86DESC64SYSTEM *PCX86DESC64SYSTEM; + +/** + * Call-, Interrupt-, Trap- or Task-gate descriptor (64-bit). + */ +typedef struct X86DESC64GATE +{ + /** Target code segment offset - Low word. */ + uint32_t u16OffsetLow : 16; + /** Target code segment selector. */ + uint32_t u16Sel : 16; + /** Interrupt stack table for interrupt- and trap-gates. + * Ignored by call-gates. */ + uint32_t u3IST : 3; + /** Reserved / ignored. */ + uint32_t u5Reserved : 5; + /** Segment Type. */ + uint32_t u4Type : 4; + /** Descriptor Type (0 = system). */ + uint32_t u1DescType : 1; + /** Descriptor Privilege level. */ + uint32_t u2Dpl : 2; + /** Flags selector present(=1) or not. */ + uint32_t u1Present : 1; + /** Target code segment offset - High word. + * Ignored if task-gate. */ + uint32_t u16OffsetHigh : 16; + /** Target code segment offset - Top dword. + * Ignored if task-gate. */ + uint32_t u32OffsetTop : 32; + /** Reserved / ignored / must be zero. + * For call-gates bits 8 thru 12 must be zero, the other gates ignores this. */ + uint32_t u32Reserved : 32; +} X86DESC64GATE; +AssertCompileSize(X86DESC64GATE, 16); +/** Pointer to a Call-, Interrupt-, Trap- or Task-gate descriptor entry. */ +typedef X86DESC64GATE *PX86DESC64GATE; +/** Pointer to a const Call-, Interrupt-, Trap- or Task-gate descriptor entry. */ +typedef const X86DESC64GATE *PCX86DESC64GATE; + +#endif /* VBOX_FOR_DTRACE_LIB */ + +/** + * Descriptor table entry. + */ +#pragma pack(1) +typedef union X86DESC64 +{ +#ifndef VBOX_FOR_DTRACE_LIB + /** Generic descriptor view. */ + X86DESC64GENERIC Gen; + /** System descriptor view. */ + X86DESC64SYSTEM System; + /** Gate descriptor view. */ + X86DESC64GATE Gate; +#endif + + /** 8 bit unsigned integer view. */ + uint8_t au8[16]; + /** 16 bit unsigned integer view. */ + uint16_t au16[8]; + /** 32 bit unsigned integer view. */ + uint32_t au32[4]; + /** 64 bit unsigned integer view. */ + uint64_t au64[2]; +} X86DESC64; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86DESC64, 16); +#endif +#pragma pack() +/** Pointer to descriptor table entry. */ +typedef X86DESC64 *PX86DESC64; +/** Pointer to const descriptor table entry. */ +typedef const X86DESC64 *PCX86DESC64; + +/** @def X86DESC64_BASE + * Return the base of a 64-bit descriptor. + */ +#define X86DESC64_BASE(a_pDesc) /*ASM-NOINC*/ \ + ( ((uint64_t)((a_pDesc)->Gen.u32BaseHigh3) << 32) \ + | ((uint32_t)((a_pDesc)->Gen.u8BaseHigh2) << 24) \ + | ( (a_pDesc)->Gen.u8BaseHigh1 << 16) \ + | ( (a_pDesc)->Gen.u16BaseLow ) ) + + + +/** @name Host system descriptor table entry - Use with care! + * @{ */ +/** Host system descriptor table entry. */ +#if HC_ARCH_BITS == 64 +typedef X86DESC64 X86DESCHC; +#else +typedef X86DESC X86DESCHC; +#endif +/** Pointer to a host system descriptor table entry. */ +#if HC_ARCH_BITS == 64 +typedef PX86DESC64 PX86DESCHC; +#else +typedef PX86DESC PX86DESCHC; +#endif +/** Pointer to a const host system descriptor table entry. */ +#if HC_ARCH_BITS == 64 +typedef PCX86DESC64 PCX86DESCHC; +#else +typedef PCX86DESC PCX86DESCHC; +#endif +/** @} */ + + +/** @name Selector Descriptor Types. + * @{ + */ + +/** @name Non-System Selector Types. + * @{ */ +/** Code(=set)/Data(=clear) bit. */ +#define X86_SEL_TYPE_CODE 8 +/** Memory(=set)/System(=clear) bit. */ +#define X86_SEL_TYPE_MEMORY RT_BIT_32(4) +/** Accessed bit. */ +#define X86_SEL_TYPE_ACCESSED 1 +/** Expand down bit (for data selectors only). */ +#define X86_SEL_TYPE_DOWN 4 +/** Conforming bit (for code selectors only). */ +#define X86_SEL_TYPE_CONF 4 +/** Write bit (for data selectors only). */ +#define X86_SEL_TYPE_WRITE 2 +/** Read bit (for code selectors only). */ +#define X86_SEL_TYPE_READ 2 +/** The bit number of the code segment read bit (relative to u4Type). */ +#define X86_SEL_TYPE_READ_BIT 1 + +/** Read only selector type. */ +#define X86_SEL_TYPE_RO 0 +/** Accessed read only selector type. */ +#define X86_SEL_TYPE_RO_ACC (0 | X86_SEL_TYPE_ACCESSED) +/** Read write selector type. */ +#define X86_SEL_TYPE_RW 2 +/** Accessed read write selector type. */ +#define X86_SEL_TYPE_RW_ACC (2 | X86_SEL_TYPE_ACCESSED) +/** Expand down read only selector type. */ +#define X86_SEL_TYPE_RO_DOWN 4 +/** Accessed expand down read only selector type. */ +#define X86_SEL_TYPE_RO_DOWN_ACC (4 | X86_SEL_TYPE_ACCESSED) +/** Expand down read write selector type. */ +#define X86_SEL_TYPE_RW_DOWN 6 +/** Accessed expand down read write selector type. */ +#define X86_SEL_TYPE_RW_DOWN_ACC (6 | X86_SEL_TYPE_ACCESSED) +/** Execute only selector type. */ +#define X86_SEL_TYPE_EO (0 | X86_SEL_TYPE_CODE) +/** Accessed execute only selector type. */ +#define X86_SEL_TYPE_EO_ACC (0 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +/** Execute and read selector type. */ +#define X86_SEL_TYPE_ER (2 | X86_SEL_TYPE_CODE) +/** Accessed execute and read selector type. */ +#define X86_SEL_TYPE_ER_ACC (2 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +/** Conforming execute only selector type. */ +#define X86_SEL_TYPE_EO_CONF (4 | X86_SEL_TYPE_CODE) +/** Accessed Conforming execute only selector type. */ +#define X86_SEL_TYPE_EO_CONF_ACC (4 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +/** Conforming execute and write selector type. */ +#define X86_SEL_TYPE_ER_CONF (6 | X86_SEL_TYPE_CODE) +/** Accessed Conforming execute and write selector type. */ +#define X86_SEL_TYPE_ER_CONF_ACC (6 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +/** @} */ + + +/** @name System Selector Types. + * @{ */ +/** The TSS busy bit mask. */ +#define X86_SEL_TYPE_SYS_TSS_BUSY_MASK 2 + +/** Undefined system selector type. */ +#define X86_SEL_TYPE_SYS_UNDEFINED 0 +/** 286 TSS selector. */ +#define X86_SEL_TYPE_SYS_286_TSS_AVAIL 1 +/** LDT selector. */ +#define X86_SEL_TYPE_SYS_LDT 2 +/** 286 TSS selector - Busy. */ +#define X86_SEL_TYPE_SYS_286_TSS_BUSY 3 +/** 286 Callgate selector. */ +#define X86_SEL_TYPE_SYS_286_CALL_GATE 4 +/** Taskgate selector. */ +#define X86_SEL_TYPE_SYS_TASK_GATE 5 +/** 286 Interrupt gate selector. */ +#define X86_SEL_TYPE_SYS_286_INT_GATE 6 +/** 286 Trapgate selector. */ +#define X86_SEL_TYPE_SYS_286_TRAP_GATE 7 +/** Undefined system selector. */ +#define X86_SEL_TYPE_SYS_UNDEFINED2 8 +/** 386 TSS selector. */ +#define X86_SEL_TYPE_SYS_386_TSS_AVAIL 9 +/** Undefined system selector. */ +#define X86_SEL_TYPE_SYS_UNDEFINED3 0xA +/** 386 TSS selector - Busy. */ +#define X86_SEL_TYPE_SYS_386_TSS_BUSY 0xB +/** 386 Callgate selector. */ +#define X86_SEL_TYPE_SYS_386_CALL_GATE 0xC +/** Undefined system selector. */ +#define X86_SEL_TYPE_SYS_UNDEFINED4 0xD +/** 386 Interruptgate selector. */ +#define X86_SEL_TYPE_SYS_386_INT_GATE 0xE +/** 386 Trapgate selector. */ +#define X86_SEL_TYPE_SYS_386_TRAP_GATE 0xF +/** @} */ + +/** @name AMD64 System Selector Types. + * @{ */ +/** LDT selector. */ +#define AMD64_SEL_TYPE_SYS_LDT 2 +/** TSS selector - Busy. */ +#define AMD64_SEL_TYPE_SYS_TSS_AVAIL 9 +/** TSS selector - Busy. */ +#define AMD64_SEL_TYPE_SYS_TSS_BUSY 0xB +/** Callgate selector. */ +#define AMD64_SEL_TYPE_SYS_CALL_GATE 0xC +/** Interruptgate selector. */ +#define AMD64_SEL_TYPE_SYS_INT_GATE 0xE +/** Trapgate selector. */ +#define AMD64_SEL_TYPE_SYS_TRAP_GATE 0xF +/** @} */ + +/** @} */ + + +/** @name Descriptor Table Entry Flag Masks. + * These are for the 2nd 32-bit word of a descriptor. + * @{ */ +/** Bits 8-11 - TYPE - Descriptor type mask. */ +#define X86_DESC_TYPE_MASK (RT_BIT_32(8) | RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bit 12 - S - System (=0) or Code/Data (=1). */ +#define X86_DESC_S RT_BIT_32(12) +/** Bits 13-14 - DPL - Descriptor Privilege Level. */ +#define X86_DESC_DPL (RT_BIT_32(13) | RT_BIT_32(14)) +/** Bit 15 - P - Present. */ +#define X86_DESC_P RT_BIT_32(15) +/** Bit 20 - AVL - Available for system software. */ +#define X86_DESC_AVL RT_BIT_32(20) +/** Bit 22 - DB - Default operation size. 0 = 16 bit, 1 = 32 bit. */ +#define X86_DESC_DB RT_BIT_32(22) +/** Bit 23 - G - Granularity of the limit. If set 4KB granularity is + * used, if clear byte. */ +#define X86_DESC_G RT_BIT_32(23) +/** @} */ + +/** @} */ + + +/** @name Task Segments. + * @{ + */ + +/** + * The minimum TSS descriptor limit for 286 tasks. + */ +#define X86_SEL_TYPE_SYS_286_TSS_LIMIT_MIN 0x2b + +/** + * The minimum TSS descriptor segment limit for 386 tasks. + */ +#define X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN 0x67 + +/** + * 16-bit Task Segment (TSS). + */ +#pragma pack(1) +typedef struct X86TSS16 +{ + /** Back link to previous task. (static) */ + RTSEL selPrev; + /** Ring-0 stack pointer. (static) */ + uint16_t sp0; + /** Ring-0 stack segment. (static) */ + RTSEL ss0; + /** Ring-1 stack pointer. (static) */ + uint16_t sp1; + /** Ring-1 stack segment. (static) */ + RTSEL ss1; + /** Ring-2 stack pointer. (static) */ + uint16_t sp2; + /** Ring-2 stack segment. (static) */ + RTSEL ss2; + /** IP before task switch. */ + uint16_t ip; + /** FLAGS before task switch. */ + uint16_t flags; + /** AX before task switch. */ + uint16_t ax; + /** CX before task switch. */ + uint16_t cx; + /** DX before task switch. */ + uint16_t dx; + /** BX before task switch. */ + uint16_t bx; + /** SP before task switch. */ + uint16_t sp; + /** BP before task switch. */ + uint16_t bp; + /** SI before task switch. */ + uint16_t si; + /** DI before task switch. */ + uint16_t di; + /** ES before task switch. */ + RTSEL es; + /** CS before task switch. */ + RTSEL cs; + /** SS before task switch. */ + RTSEL ss; + /** DS before task switch. */ + RTSEL ds; + /** LDTR before task switch. */ + RTSEL selLdt; +} X86TSS16; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86TSS16, X86_SEL_TYPE_SYS_286_TSS_LIMIT_MIN + 1); +#endif +#pragma pack() +/** Pointer to a 16-bit task segment. */ +typedef X86TSS16 *PX86TSS16; +/** Pointer to a const 16-bit task segment. */ +typedef const X86TSS16 *PCX86TSS16; + + +/** + * 32-bit Task Segment (TSS). + */ +#pragma pack(1) +typedef struct X86TSS32 +{ + /** Back link to previous task. (static) */ + RTSEL selPrev; + uint16_t padding1; + /** Ring-0 stack pointer. (static) */ + uint32_t esp0; + /** Ring-0 stack segment. (static) */ + RTSEL ss0; + uint16_t padding_ss0; + /** Ring-1 stack pointer. (static) */ + uint32_t esp1; + /** Ring-1 stack segment. (static) */ + RTSEL ss1; + uint16_t padding_ss1; + /** Ring-2 stack pointer. (static) */ + uint32_t esp2; + /** Ring-2 stack segment. (static) */ + RTSEL ss2; + uint16_t padding_ss2; + /** Page directory for the task. (static) */ + uint32_t cr3; + /** EIP before task switch. */ + uint32_t eip; + /** EFLAGS before task switch. */ + uint32_t eflags; + /** EAX before task switch. */ + uint32_t eax; + /** ECX before task switch. */ + uint32_t ecx; + /** EDX before task switch. */ + uint32_t edx; + /** EBX before task switch. */ + uint32_t ebx; + /** ESP before task switch. */ + uint32_t esp; + /** EBP before task switch. */ + uint32_t ebp; + /** ESI before task switch. */ + uint32_t esi; + /** EDI before task switch. */ + uint32_t edi; + /** ES before task switch. */ + RTSEL es; + uint16_t padding_es; + /** CS before task switch. */ + RTSEL cs; + uint16_t padding_cs; + /** SS before task switch. */ + RTSEL ss; + uint16_t padding_ss; + /** DS before task switch. */ + RTSEL ds; + uint16_t padding_ds; + /** FS before task switch. */ + RTSEL fs; + uint16_t padding_fs; + /** GS before task switch. */ + RTSEL gs; + uint16_t padding_gs; + /** LDTR before task switch. */ + RTSEL selLdt; + uint16_t padding_ldt; + /** Debug trap flag */ + uint16_t fDebugTrap; + /** Offset relative to the TSS of the start of the I/O Bitmap + * and the end of the interrupt redirection bitmap. */ + uint16_t offIoBitmap; +} X86TSS32; +#pragma pack() +/** Pointer to task segment. */ +typedef X86TSS32 *PX86TSS32; +/** Pointer to const task segment. */ +typedef const X86TSS32 *PCX86TSS32; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86TSS32, X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN + 1); +AssertCompileMemberOffset(X86TSS32, cr3, 28); +AssertCompileMemberOffset(X86TSS32, offIoBitmap, 102); +#endif + +/** + * 64-bit Task segment. + */ +#pragma pack(1) +typedef struct X86TSS64 +{ + /** Reserved. */ + uint32_t u32Reserved; + /** Ring-0 stack pointer. (static) */ + uint64_t rsp0; + /** Ring-1 stack pointer. (static) */ + uint64_t rsp1; + /** Ring-2 stack pointer. (static) */ + uint64_t rsp2; + /** Reserved. */ + uint32_t u32Reserved2[2]; + /* IST */ + uint64_t ist1; + uint64_t ist2; + uint64_t ist3; + uint64_t ist4; + uint64_t ist5; + uint64_t ist6; + uint64_t ist7; + /* Reserved. */ + uint16_t u16Reserved[5]; + /** Offset relative to the TSS of the start of the I/O Bitmap + * and the end of the interrupt redirection bitmap. */ + uint16_t offIoBitmap; +} X86TSS64; +#pragma pack() +/** Pointer to a 64-bit task segment. */ +typedef X86TSS64 *PX86TSS64; +/** Pointer to a const 64-bit task segment. */ +typedef const X86TSS64 *PCX86TSS64; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86TSS64, X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN + 1); +#endif + +/** @} */ + + +/** @name Selectors. + * @{ + */ + +/** + * The shift used to convert a selector from and to index an index (C). + */ +#define X86_SEL_SHIFT 3 + +/** + * The mask used to mask off the table indicator and RPL of an selector. + */ +#define X86_SEL_MASK 0xfff8U + +/** + * The mask used to mask off the RPL of an selector. + * This is suitable for checking for NULL selectors. + */ +#define X86_SEL_MASK_OFF_RPL 0xfffcU + +/** + * The bit indicating that a selector is in the LDT and not in the GDT. + */ +#define X86_SEL_LDT 0x0004U + +/** + * The bit mask for getting the RPL of a selector. + */ +#define X86_SEL_RPL 0x0003U + +/** + * The mask covering both RPL and LDT. + * This is incidentally the same as sizeof(X86DESC) - 1, so good for limit + * checks. + */ +#define X86_SEL_RPL_LDT 0x0007U + +/** @} */ + + +/** + * x86 Exceptions/Faults/Traps. + */ +typedef enum X86XCPT +{ + /** \#DE - Divide error. */ + X86_XCPT_DE = 0x00, + /** \#DB - Debug event (single step, DRx, ..) */ + X86_XCPT_DB = 0x01, + /** NMI - Non-Maskable Interrupt */ + X86_XCPT_NMI = 0x02, + /** \#BP - Breakpoint (INT3). */ + X86_XCPT_BP = 0x03, + /** \#OF - Overflow (INTO). */ + X86_XCPT_OF = 0x04, + /** \#BR - Bound range exceeded (BOUND). */ + X86_XCPT_BR = 0x05, + /** \#UD - Undefined opcode. */ + X86_XCPT_UD = 0x06, + /** \#NM - Device not available (math coprocessor device). */ + X86_XCPT_NM = 0x07, + /** \#DF - Double fault. */ + X86_XCPT_DF = 0x08, + /** ??? - Coprocessor segment overrun (obsolete). */ + X86_XCPT_CO_SEG_OVERRUN = 0x09, + /** \#TS - Taskswitch (TSS). */ + X86_XCPT_TS = 0x0a, + /** \#NP - Segment no present. */ + X86_XCPT_NP = 0x0b, + /** \#SS - Stack segment fault. */ + X86_XCPT_SS = 0x0c, + /** \#GP - General protection fault. */ + X86_XCPT_GP = 0x0d, + /** \#PF - Page fault. */ + X86_XCPT_PF = 0x0e, + /* 0x0f is reserved (to avoid conflict with spurious interrupts in BIOS setup). */ + /** \#MF - Math fault (FPU). */ + X86_XCPT_MF = 0x10, + /** \#AC - Alignment check. */ + X86_XCPT_AC = 0x11, + /** \#MC - Machine check. */ + X86_XCPT_MC = 0x12, + /** \#XF - SIMD Floating-Point Exception. */ + X86_XCPT_XF = 0x13, + /** \#VE - Virtualization Exception (Intel only). */ + X86_XCPT_VE = 0x14, + /** \#CP - Control Protection Exception (Intel only). */ + X86_XCPT_CP = 0x15, + /** \#VC - VMM Communication Exception (AMD only). */ + X86_XCPT_VC = 0x1d, + /** \#SX - Security Exception (AMD only). */ + X86_XCPT_SX = 0x1e +} X86XCPT; +/** Pointer to a x86 exception code. */ +typedef X86XCPT *PX86XCPT; +/** Pointer to a const x86 exception code. */ +typedef const X86XCPT *PCX86XCPT; +/** The last valid (currently reserved) exception value. */ +#define X86_XCPT_LAST 0x1f + + +/** @name Trap Error Codes + * @{ + */ +/** External indicator. */ +#define X86_TRAP_ERR_EXTERNAL 1 +/** IDT indicator. */ +#define X86_TRAP_ERR_IDT 2 +/** Descriptor table indicator - If set LDT, if clear GDT. */ +#define X86_TRAP_ERR_TI 4 +/** Mask for getting the selector. */ +#define X86_TRAP_ERR_SEL_MASK 0xfff8 +/** Shift for getting the selector table index (C type index). */ +#define X86_TRAP_ERR_SEL_SHIFT 3 +/** @} */ + + +/** @name \#PF Trap Error Codes + * @{ + */ +/** Bit 0 - P - Not present (clear) or page level protection (set) fault. */ +#define X86_TRAP_PF_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) or write (set) access. */ +#define X86_TRAP_PF_RW RT_BIT_32(1) +/** Bit 2 - U/S - CPU executing in user mode (set) or supervisor mode (clear). */ +#define X86_TRAP_PF_US RT_BIT_32(2) +/** Bit 3 - RSVD- Reserved bit violation (set), i.e. reserved bit was set to 1. */ +#define X86_TRAP_PF_RSVD RT_BIT_32(3) +/** Bit 4 - I/D - Instruction fetch (set) / Data access (clear) - PAE + NXE. */ +#define X86_TRAP_PF_ID RT_BIT_32(4) +/** Bit 5 - PK - Protection-key violation (AMD64 mode only). */ +#define X86_TRAP_PF_PK RT_BIT_32(5) +/** @} */ + +#pragma pack(1) +/** + * 16-bit IDTR. + */ +typedef struct X86IDTR16 +{ + /** Offset. */ + uint16_t offSel; + /** Selector. */ + uint16_t uSel; +} X86IDTR16, *PX86IDTR16; +#pragma pack() + +#pragma pack(1) +/** + * 32-bit IDTR/GDTR. + */ +typedef struct X86XDTR32 +{ + /** Size of the descriptor table. */ + uint16_t cb; + /** Address of the descriptor table. */ +#ifndef VBOX_FOR_DTRACE_LIB + uint32_t uAddr; +#else + uint16_t au16Addr[2]; +#endif +} X86XDTR32, *PX86XDTR32; +#pragma pack() + +#pragma pack(1) +/** + * 64-bit IDTR/GDTR. + */ +typedef struct X86XDTR64 +{ + /** Size of the descriptor table. */ + uint16_t cb; + /** Address of the descriptor table. */ +#ifndef VBOX_FOR_DTRACE_LIB + uint64_t uAddr; +#else + uint16_t au16Addr[4]; +#endif +} X86XDTR64, *PX86XDTR64; +#pragma pack() + + +/** @name ModR/M + * @{ */ +#define X86_MODRM_RM_MASK UINT8_C(0x07) +#define X86_MODRM_REG_MASK UINT8_C(0x38) +#define X86_MODRM_REG_SMASK UINT8_C(0x07) +#define X86_MODRM_REG_SHIFT 3 +#define X86_MODRM_MOD_MASK UINT8_C(0xc0) +#define X86_MODRM_MOD_SMASK UINT8_C(0x03) +#define X86_MODRM_MOD_SHIFT 6 +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompile((X86_MODRM_RM_MASK | X86_MODRM_REG_MASK | X86_MODRM_MOD_MASK) == 0xff); +AssertCompile((X86_MODRM_REG_MASK >> X86_MODRM_REG_SHIFT) == X86_MODRM_REG_SMASK); +AssertCompile((X86_MODRM_MOD_MASK >> X86_MODRM_MOD_SHIFT) == X86_MODRM_MOD_SMASK); +/** @def X86_MODRM_MAKE + * @param a_Mod The mod value (0..3). + * @param a_Reg The register value (0..7). + * @param a_RegMem The register or memory value (0..7). */ +# define X86_MODRM_MAKE(a_Mod, a_Reg, a_RegMem) (((a_Mod) << X86_MODRM_MOD_SHIFT) | ((a_Reg) << X86_MODRM_REG_SHIFT) | (a_RegMem)) +#endif +/** @} */ + +/** @name SIB + * @{ */ +#define X86_SIB_BASE_MASK UINT8_C(0x07) +#define X86_SIB_INDEX_MASK UINT8_C(0x38) +#define X86_SIB_INDEX_SMASK UINT8_C(0x07) +#define X86_SIB_INDEX_SHIFT 3 +#define X86_SIB_SCALE_MASK UINT8_C(0xc0) +#define X86_SIB_SCALE_SMASK UINT8_C(0x03) +#define X86_SIB_SCALE_SHIFT 6 +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompile((X86_SIB_BASE_MASK | X86_SIB_INDEX_MASK | X86_SIB_SCALE_MASK) == 0xff); +AssertCompile((X86_SIB_INDEX_MASK >> X86_SIB_INDEX_SHIFT) == X86_SIB_INDEX_SMASK); +AssertCompile((X86_SIB_SCALE_MASK >> X86_SIB_SCALE_SHIFT) == X86_SIB_SCALE_SMASK); +#endif +/** @} */ + +/** @name General register indexes. + * @{ */ +#define X86_GREG_xAX 0 +#define X86_GREG_xCX 1 +#define X86_GREG_xDX 2 +#define X86_GREG_xBX 3 +#define X86_GREG_xSP 4 +#define X86_GREG_xBP 5 +#define X86_GREG_xSI 6 +#define X86_GREG_xDI 7 +#define X86_GREG_x8 8 +#define X86_GREG_x9 9 +#define X86_GREG_x10 10 +#define X86_GREG_x11 11 +#define X86_GREG_x12 12 +#define X86_GREG_x13 13 +#define X86_GREG_x14 14 +#define X86_GREG_x15 15 +/** @} */ +/** General register count. */ +#define X86_GREG_COUNT 16 + +/** @name X86_SREG_XXX - Segment register indexes. + * @{ */ +#define X86_SREG_ES 0 +#define X86_SREG_CS 1 +#define X86_SREG_SS 2 +#define X86_SREG_DS 3 +#define X86_SREG_FS 4 +#define X86_SREG_GS 5 +/** @} */ +/** Segment register count. */ +#define X86_SREG_COUNT 6 + + +/** @name X86_OP_XXX - Prefixes + * @{ */ +#define X86_OP_PRF_CS UINT8_C(0x2e) +#define X86_OP_PRF_SS UINT8_C(0x36) +#define X86_OP_PRF_DS UINT8_C(0x3e) +#define X86_OP_PRF_ES UINT8_C(0x26) +#define X86_OP_PRF_FS UINT8_C(0x64) +#define X86_OP_PRF_GS UINT8_C(0x65) +#define X86_OP_PRF_SIZE_OP UINT8_C(0x66) +#define X86_OP_PRF_SIZE_ADDR UINT8_C(0x67) +#define X86_OP_PRF_LOCK UINT8_C(0xf0) +#define X86_OP_PRF_REPZ UINT8_C(0xf3) +#define X86_OP_PRF_REPNZ UINT8_C(0xf2) +#define X86_OP_REX_B UINT8_C(0x41) +#define X86_OP_REX_X UINT8_C(0x42) +#define X86_OP_REX_R UINT8_C(0x44) +#define X86_OP_REX_W UINT8_C(0x48) +/** @} */ + + +/** @} */ + +#endif /* !IPRT_INCLUDED_x86_h */ + diff --git a/include/iprt/x86.mac b/include/iprt/x86.mac new file mode 100644 index 00000000..cd1b545a --- /dev/null +++ b/include/iprt/x86.mac @@ -0,0 +1,1409 @@ +;; @file +; IPRT - X86 and AMD64 Structures and Definitions. +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef IPRT_INCLUDED_x86_h +%define IPRT_INCLUDED_x86_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%ifdef RT_OS_SOLARIS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_EFL_CF RT_BIT_32(0) +%define X86_EFL_CF_BIT 0 +%define X86_EFL_1 RT_BIT_32(1) +%define X86_EFL_PF RT_BIT_32(2) +%define X86_EFL_PF_BIT 2 +%define X86_EFL_AF RT_BIT_32(4) +%define X86_EFL_AF_BIT 4 +%define X86_EFL_ZF RT_BIT_32(6) +%define X86_EFL_ZF_BIT 6 +%define X86_EFL_SF RT_BIT_32(7) +%define X86_EFL_SF_BIT 7 +%define X86_EFL_TF RT_BIT_32(8) +%define X86_EFL_TF_BIT 8 +%define X86_EFL_IF RT_BIT_32(9) +%define X86_EFL_IF_BIT 9 +%define X86_EFL_DF RT_BIT_32(10) +%define X86_EFL_DF_BIT 10 +%define X86_EFL_OF RT_BIT_32(11) +%define X86_EFL_OF_BIT 11 +%define X86_EFL_IOPL (RT_BIT_32(12) | RT_BIT_32(13)) +%define X86_EFL_NT RT_BIT_32(14) +%define X86_EFL_NT_BIT 14 +%define X86_EFL_RF RT_BIT_32(16) +%define X86_EFL_RF_BIT 16 +%define X86_EFL_VM RT_BIT_32(17) +%define X86_EFL_VM_BIT 17 +%define X86_EFL_AC RT_BIT_32(18) +%define X86_EFL_AC_BIT 18 +%define X86_EFL_VIF RT_BIT_32(19) +%define X86_EFL_VIF_BIT 19 +%define X86_EFL_VIP RT_BIT_32(20) +%define X86_EFL_VIP_BIT 20 +%define X86_EFL_ID RT_BIT_32(21) +%define X86_EFL_ID_BIT 21 +%define X86_EFL_LIVE_MASK 0x003f7fd5 +%define X86_EFL_RA1_MASK RT_BIT_32(1) +%define X86_EFL_IOPL_SHIFT 12 +%define X86_EFL_GET_IOPL(efl) (((efl) >> X86_EFL_IOPL_SHIFT) & 3) +%define X86_EFL_POPF_BITS ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF \ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_AC | X86_EFL_ID ) +%define X86_EFL_POPF_BITS_386 ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF \ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT ) +%define X86_EFL_STATUS_BITS ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF ) +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%define X86_CPUID_VENDOR_INTEL_EBX 0x756e6547 +%define X86_CPUID_VENDOR_INTEL_ECX 0x6c65746e +%define X86_CPUID_VENDOR_INTEL_EDX 0x49656e69 +%define X86_CPUID_VENDOR_AMD_EBX 0x68747541 +%define X86_CPUID_VENDOR_AMD_ECX 0x444d4163 +%define X86_CPUID_VENDOR_AMD_EDX 0x69746e65 +%define X86_CPUID_VENDOR_VIA_EBX 0x746e6543 +%define X86_CPUID_VENDOR_VIA_ECX 0x736c7561 +%define X86_CPUID_VENDOR_VIA_EDX 0x48727561 +%define X86_CPUID_VENDOR_SHANGHAI_EBX 0x68532020 +%define X86_CPUID_VENDOR_SHANGHAI_ECX 0x20206961 +%define X86_CPUID_VENDOR_SHANGHAI_EDX 0x68676e61 +%define X86_CPUID_VENDOR_HYGON_EBX 0x6f677948 +%define X86_CPUID_VENDOR_HYGON_ECX 0x656e6975 +%define X86_CPUID_VENDOR_HYGON_EDX 0x6e65476e +%define X86_CPUID_FEATURE_ECX_SSE3 RT_BIT_32(0) +%define X86_CPUID_FEATURE_ECX_PCLMUL RT_BIT_32(1) +%define X86_CPUID_FEATURE_ECX_DTES64 RT_BIT_32(2) +%define X86_CPUID_FEATURE_ECX_MONITOR RT_BIT_32(3) +%define X86_CPUID_FEATURE_ECX_CPLDS RT_BIT_32(4) +%define X86_CPUID_FEATURE_ECX_VMX RT_BIT_32(5) +%define X86_CPUID_FEATURE_ECX_SMX RT_BIT_32(6) +%define X86_CPUID_FEATURE_ECX_EST RT_BIT_32(7) +%define X86_CPUID_FEATURE_ECX_TM2 RT_BIT_32(8) +%define X86_CPUID_FEATURE_ECX_SSSE3 RT_BIT_32(9) +%define X86_CPUID_FEATURE_ECX_CNTXID RT_BIT_32(10) +%define X86_CPUID_FEATURE_ECX_SDBG RT_BIT_32(11) +%define X86_CPUID_FEATURE_ECX_FMA RT_BIT_32(12) +%define X86_CPUID_FEATURE_ECX_CX16 RT_BIT_32(13) +%define X86_CPUID_FEATURE_ECX_TPRUPDATE RT_BIT_32(14) +%define X86_CPUID_FEATURE_ECX_PDCM RT_BIT_32(15) +%define X86_CPUID_FEATURE_ECX_PCID RT_BIT_32(17) +%define X86_CPUID_FEATURE_ECX_DCA RT_BIT_32(18) +%define X86_CPUID_FEATURE_ECX_SSE4_1 RT_BIT_32(19) +%define X86_CPUID_FEATURE_ECX_SSE4_2 RT_BIT_32(20) +%define X86_CPUID_FEATURE_ECX_X2APIC RT_BIT_32(21) +%define X86_CPUID_FEATURE_ECX_MOVBE RT_BIT_32(22) +%define X86_CPUID_FEATURE_ECX_POPCNT RT_BIT_32(23) +%define X86_CPUID_FEATURE_ECX_TSCDEADL RT_BIT_32(24) +%define X86_CPUID_FEATURE_ECX_AES RT_BIT_32(25) +%define X86_CPUID_FEATURE_ECX_XSAVE RT_BIT_32(26) +%define X86_CPUID_FEATURE_ECX_OSXSAVE RT_BIT_32(27) +%define X86_CPUID_FEATURE_ECX_AVX RT_BIT_32(28) +%define X86_CPUID_FEATURE_ECX_F16C RT_BIT_32(29) +%define X86_CPUID_FEATURE_ECX_RDRAND RT_BIT_32(30) +%define X86_CPUID_FEATURE_ECX_HVP RT_BIT_32(31) +%define X86_CPUID_FEATURE_EDX_FPU RT_BIT_32(0) +%define X86_CPUID_FEATURE_EDX_VME RT_BIT_32(1) +%define X86_CPUID_FEATURE_EDX_DE RT_BIT_32(2) +%define X86_CPUID_FEATURE_EDX_PSE RT_BIT_32(3) +%define X86_CPUID_FEATURE_EDX_PSE_BIT 3 +%define X86_CPUID_FEATURE_EDX_TSC RT_BIT_32(4) +%define X86_CPUID_FEATURE_EDX_MSR RT_BIT_32(5) +%define X86_CPUID_FEATURE_EDX_PAE RT_BIT_32(6) +%define X86_CPUID_FEATURE_EDX_PAE_BIT 6 +%define X86_CPUID_FEATURE_EDX_MCE RT_BIT_32(7) +%define X86_CPUID_FEATURE_EDX_CX8 RT_BIT_32(8) +%define X86_CPUID_FEATURE_EDX_APIC RT_BIT_32(9) +%define X86_CPUID_FEATURE_EDX_SEP RT_BIT_32(11) +%define X86_CPUID_FEATURE_EDX_MTRR RT_BIT_32(12) +%define X86_CPUID_FEATURE_EDX_PGE RT_BIT_32(13) +%define X86_CPUID_FEATURE_EDX_MCA RT_BIT_32(14) +%define X86_CPUID_FEATURE_EDX_CMOV RT_BIT_32(15) +%define X86_CPUID_FEATURE_EDX_PAT RT_BIT_32(16) +%define X86_CPUID_FEATURE_EDX_PSE36 RT_BIT_32(17) +%define X86_CPUID_FEATURE_EDX_PSN RT_BIT_32(18) +%define X86_CPUID_FEATURE_EDX_CLFSH RT_BIT_32(19) +%define X86_CPUID_FEATURE_EDX_DS RT_BIT_32(21) +%define X86_CPUID_FEATURE_EDX_ACPI RT_BIT_32(22) +%define X86_CPUID_FEATURE_EDX_MMX RT_BIT_32(23) +%define X86_CPUID_FEATURE_EDX_FXSR RT_BIT_32(24) +%define X86_CPUID_FEATURE_EDX_SSE RT_BIT_32(25) +%define X86_CPUID_FEATURE_EDX_SSE2 RT_BIT_32(26) +%define X86_CPUID_FEATURE_EDX_SS RT_BIT_32(27) +%define X86_CPUID_FEATURE_EDX_HTT RT_BIT_32(28) +%define X86_CPUID_FEATURE_EDX_TM RT_BIT_32(29) +%define X86_CPUID_FEATURE_EDX_PBE RT_BIT_32(31) +%define X86_CPUID_MWAIT_ECX_EXT RT_BIT_32(0) +%define X86_CPUID_MWAIT_ECX_BREAKIRQIF0 RT_BIT_32(1) +%define X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE RT_BIT_32(0) +%define X86_CPUID_STEXT_FEATURE_EBX_TSC_ADJUST RT_BIT_32(1) +%define X86_CPUID_STEXT_FEATURE_EBX_SGX RT_BIT_32(2) +%define X86_CPUID_STEXT_FEATURE_EBX_BMI1 RT_BIT_32(3) +%define X86_CPUID_STEXT_FEATURE_EBX_HLE RT_BIT_32(4) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX2 RT_BIT_32(5) +%define X86_CPUID_STEXT_FEATURE_EBX_FDP_EXCPTN_ONLY RT_BIT_32(6) +%define X86_CPUID_STEXT_FEATURE_EBX_SMEP RT_BIT_32(7) +%define X86_CPUID_STEXT_FEATURE_EBX_BMI2 RT_BIT_32(8) +%define X86_CPUID_STEXT_FEATURE_EBX_ERMS RT_BIT_32(9) +%define X86_CPUID_STEXT_FEATURE_EBX_INVPCID RT_BIT_32(10) +%define X86_CPUID_STEXT_FEATURE_EBX_RTM RT_BIT_32(11) +%define X86_CPUID_STEXT_FEATURE_EBX_PQM RT_BIT_32(12) +%define X86_CPUID_STEXT_FEATURE_EBX_DEPR_FPU_CS_DS RT_BIT_32(13) +%define X86_CPUID_STEXT_FEATURE_EBX_MPE RT_BIT_32(14) +%define X86_CPUID_STEXT_FEATURE_EBX_PQE RT_BIT_32(15) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX512F RT_BIT_32(16) +%define X86_CPUID_STEXT_FEATURE_EBX_RDSEED RT_BIT_32(18) +%define X86_CPUID_STEXT_FEATURE_EBX_ADX RT_BIT_32(19) +%define X86_CPUID_STEXT_FEATURE_EBX_SMAP RT_BIT_32(20) +%define X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT RT_BIT_32(23) +%define X86_CPUID_STEXT_FEATURE_EBX_INTEL_PT RT_BIT_32(25) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX512PF RT_BIT_32(26) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX512ER RT_BIT_32(27) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX512CD RT_BIT_32(28) +%define X86_CPUID_STEXT_FEATURE_EBX_SHA RT_BIT_32(29) +%define X86_CPUID_STEXT_FEATURE_ECX_PREFETCHWT1 RT_BIT_32(0) +%define X86_CPUID_STEXT_FEATURE_ECX_UMIP RT_BIT_32(2) +%define X86_CPUID_STEXT_FEATURE_ECX_PKU RT_BIT_32(3) +%define X86_CPUID_STEXT_FEATURE_ECX_OSPKE RT_BIT_32(4) +%define X86_CPUID_STEXT_FEATURE_ECX_MAWAU 0x003e0000 +%define X86_CPUID_STEXT_FEATURE_ECX_RDPID RT_BIT_32(2) +%define X86_CPUID_STEXT_FEATURE_ECX_SGX_LC RT_BIT_32(30) +%define X86_CPUID_STEXT_FEATURE_EDX_MD_CLEAR RT_BIT_32(10) +%define X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB RT_BIT_32(26) +%define X86_CPUID_STEXT_FEATURE_EDX_STIBP RT_BIT_32(27) +%define X86_CPUID_STEXT_FEATURE_EDX_FLUSH_CMD RT_BIT_32(28) +%define X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP RT_BIT_32(29) +%define X86_CPUID_STEXT_FEATURE_EDX_SSBD RT_BIT_32(31) +%define X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF RT_BIT_32(0) +%define X86_CPUID_EXT_FEATURE_EDX_SYSCALL RT_BIT_32(11) +%define X86_CPUID_EXT_FEATURE_EDX_NX RT_BIT_32(20) +%define X86_CPUID_EXT_FEATURE_EDX_PAGE1GB RT_BIT_32(26) +%define X86_CPUID_EXT_FEATURE_EDX_RDTSCP RT_BIT_32(27) +%define X86_CPUID_EXT_FEATURE_EDX_LONG_MODE RT_BIT_32(29) +%define X86_CPUID_AMD_FEATURE_EDX_FPU RT_BIT_32(0) +%define X86_CPUID_AMD_FEATURE_EDX_VME RT_BIT_32(1) +%define X86_CPUID_AMD_FEATURE_EDX_DE RT_BIT_32(2) +%define X86_CPUID_AMD_FEATURE_EDX_PSE RT_BIT_32(3) +%define X86_CPUID_AMD_FEATURE_EDX_TSC RT_BIT_32(4) +%define X86_CPUID_AMD_FEATURE_EDX_MSR RT_BIT_32(5) +%define X86_CPUID_AMD_FEATURE_EDX_PAE RT_BIT_32(6) +%define X86_CPUID_AMD_FEATURE_EDX_MCE RT_BIT_32(7) +%define X86_CPUID_AMD_FEATURE_EDX_CX8 RT_BIT_32(8) +%define X86_CPUID_AMD_FEATURE_EDX_APIC RT_BIT_32(9) +%define X86_CPUID_AMD_FEATURE_EDX_MTRR RT_BIT_32(12) +%define X86_CPUID_AMD_FEATURE_EDX_PGE RT_BIT_32(13) +%define X86_CPUID_AMD_FEATURE_EDX_MCA RT_BIT_32(14) +%define X86_CPUID_AMD_FEATURE_EDX_CMOV RT_BIT_32(15) +%define X86_CPUID_AMD_FEATURE_EDX_PAT RT_BIT_32(16) +%define X86_CPUID_AMD_FEATURE_EDX_PSE36 RT_BIT_32(17) +%define X86_CPUID_AMD_FEATURE_EDX_AXMMX RT_BIT_32(22) +%define X86_CPUID_AMD_FEATURE_EDX_MMX RT_BIT_32(23) +%define X86_CPUID_AMD_FEATURE_EDX_FXSR RT_BIT_32(24) +%define X86_CPUID_AMD_FEATURE_EDX_FFXSR RT_BIT_32(25) +%define X86_CPUID_AMD_FEATURE_EDX_3DNOW_EX RT_BIT_32(30) +%define X86_CPUID_AMD_FEATURE_EDX_3DNOW RT_BIT_32(31) +%define X86_CPUID_AMD_FEATURE_ECX_CMPL RT_BIT_32(1) +%define X86_CPUID_AMD_FEATURE_ECX_SVM RT_BIT_32(2) +%define X86_CPUID_AMD_FEATURE_ECX_EXT_APIC RT_BIT_32(3) +%define X86_CPUID_AMD_FEATURE_ECX_CR8L RT_BIT_32(4) +%define X86_CPUID_AMD_FEATURE_ECX_ABM RT_BIT_32(5) +%define X86_CPUID_AMD_FEATURE_ECX_SSE4A RT_BIT_32(6) +%define X86_CPUID_AMD_FEATURE_ECX_MISALNSSE RT_BIT_32(7) +%define X86_CPUID_AMD_FEATURE_ECX_3DNOWPRF RT_BIT_32(8) +%define X86_CPUID_AMD_FEATURE_ECX_OSVW RT_BIT_32(9) +%define X86_CPUID_AMD_FEATURE_ECX_IBS RT_BIT_32(10) +%define X86_CPUID_AMD_FEATURE_ECX_XOP RT_BIT_32(11) +%define X86_CPUID_AMD_FEATURE_ECX_SKINIT RT_BIT_32(12) +%define X86_CPUID_AMD_FEATURE_ECX_WDT RT_BIT_32(13) +%define X86_CPUID_AMD_FEATURE_ECX_LWP RT_BIT_32(15) +%define X86_CPUID_AMD_FEATURE_ECX_FMA4 RT_BIT_32(16) +%define X86_CPUID_AMD_FEATURE_ECX_NODEID RT_BIT_32(19) +%define X86_CPUID_AMD_FEATURE_ECX_TBM RT_BIT_32(21) +%define X86_CPUID_AMD_FEATURE_ECX_TOPOEXT RT_BIT_32(22) +%define X86_CPUID_AMD_ADVPOWER_EDX_TS RT_BIT_32(0) +%define X86_CPUID_AMD_ADVPOWER_EDX_FID RT_BIT_32(1) +%define X86_CPUID_AMD_ADVPOWER_EDX_VID RT_BIT_32(2) +%define X86_CPUID_AMD_ADVPOWER_EDX_TTP RT_BIT_32(3) +%define X86_CPUID_AMD_ADVPOWER_EDX_TM RT_BIT_32(4) +%define X86_CPUID_AMD_ADVPOWER_EDX_STC RT_BIT_32(5) +%define X86_CPUID_AMD_ADVPOWER_EDX_MC RT_BIT_32(6) +%define X86_CPUID_AMD_ADVPOWER_EDX_HWPSTATE RT_BIT_32(7) +%define X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR RT_BIT_32(8) +%define X86_CPUID_AMD_ADVPOWER_EDX_CPB RT_BIT_32(9) +%define X86_CPUID_AMD_ADVPOWER_EDX_EFRO RT_BIT_32(10) +%define X86_CPUID_AMD_ADVPOWER_EDX_PFI RT_BIT_32(11) +%define X86_CPUID_AMD_ADVPOWER_EDX_PA RT_BIT_32(12) +%define X86_CPUID_AMD_EFEID_EBX_CLZERO RT_BIT_32(0) +%define X86_CPUID_AMD_EFEID_EBX_IRPERF RT_BIT_32(1) +%define X86_CPUID_AMD_EFEID_EBX_XSAVE_ER_PTR RT_BIT_32(2) +%define X86_CPUID_AMD_EFEID_EBX_RDPRU RT_BIT_32(4) +%define X86_CPUID_AMD_EFEID_EBX_MCOMMIT RT_BIT_32(8) +%define X86_CPUID_AMD_EFEID_EBX_IBPB RT_BIT_32(12) +%define X86_CPUID_AMD_EFEID_EBX_IBRS RT_BIT_32(14) +%define X86_CPUID_AMD_EFEID_EBX_STIBP RT_BIT_32(15) +%define X86_CPUID_AMD_EFEID_EBX_IBRS_ALWAYS_ON RT_BIT_32(16) +%define X86_CPUID_AMD_EFEID_EBX_STIBP_ALWAYS_ON RT_BIT_32(17) +%define X86_CPUID_AMD_EFEID_EBX_IBRS_PREFERRED RT_BIT_32(18) +%define X86_CPUID_AMD_EFEID_EBX_SPEC_CTRL_SSBD RT_BIT_32(24) +%define X86_CPUID_AMD_EFEID_EBX_VIRT_SPEC_CTRL_SSBD RT_BIT_32(25) +%define X86_CPUID_AMD_EFEID_EBX_NO_SSBD_REQUIRED RT_BIT_32(26) +%define X86_CPUID_SVM_FEATURE_EDX_NESTED_PAGING RT_BIT(0) +%define X86_CPUID_SVM_FEATURE_EDX_LBR_VIRT RT_BIT(1) +%define X86_CPUID_SVM_FEATURE_EDX_SVM_LOCK RT_BIT(2) +%define X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE RT_BIT(3) +%define X86_CPUID_SVM_FEATURE_EDX_TSC_RATE_MSR RT_BIT(4) +%define X86_CPUID_SVM_FEATURE_EDX_VMCB_CLEAN RT_BIT(5) +%define X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID RT_BIT(6) +%define X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSISTS RT_BIT(7) +%define X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER RT_BIT(10) +%define X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER_THRESHOLD RT_BIT(12) +%define X86_CPUID_SVM_FEATURE_EDX_AVIC RT_BIT(13) +%define X86_CPUID_SVM_FEATURE_EDX_VIRT_VMSAVE_VMLOAD RT_BIT(15) +%define X86_CPUID_SVM_FEATURE_EDX_VGIF RT_BIT(16) +%define X86_CPUID_SVM_FEATURE_EDX_GMET RT_BIT(17) +%define X86_CPUID_SVM_FEATURE_EDX_SSSCHECK RT_BIT(19) +%define X86_CPUID_SVM_FEATURE_EDX_SPEC_CTRL RT_BIT(20) +%define X86_CPUID_SVM_FEATURE_EDX_HOST_MCE_OVERRIDE RT_BIT(23) +%define X86_CPUID_SVM_FEATURE_EDX_TLBICTL RT_BIT(24) +%define X86_CR0_PE RT_BIT_32(0) +%define X86_CR0_PROTECTION_ENABLE RT_BIT_32(0) +%define X86_CR0_MP RT_BIT_32(1) +%define X86_CR0_MONITOR_COPROCESSOR RT_BIT_32(1) +%define X86_CR0_EM RT_BIT_32(2) +%define X86_CR0_EMULATE_FPU RT_BIT_32(2) +%define X86_CR0_TS RT_BIT_32(3) +%define X86_CR0_TASK_SWITCH RT_BIT_32(3) +%define X86_CR0_ET RT_BIT_32(4) +%define X86_CR0_EXTENSION_TYPE RT_BIT_32(4) +%define X86_CR0_NE RT_BIT_32(5) +%define X86_CR0_NUMERIC_ERROR RT_BIT_32(5) +%define X86_CR0_WP RT_BIT_32(16) +%define X86_CR0_WRITE_PROTECT RT_BIT_32(16) +%define X86_CR0_AM RT_BIT_32(18) +%define X86_CR0_ALIGMENT_MASK RT_BIT_32(18) +%define X86_CR0_NW RT_BIT_32(29) +%define X86_CR0_NOT_WRITE_THROUGH RT_BIT_32(29) +%define X86_CR0_CD RT_BIT_32(30) +%define X86_CR0_CACHE_DISABLE RT_BIT_32(30) +%define X86_CR0_PG RT_BIT_32(31) +%define X86_CR0_PAGING RT_BIT_32(31) +%define X86_CR0_BIT_PG 31 +%define X86_CR3_PWT RT_BIT_32(3) +%define X86_CR3_PCD RT_BIT_32(4) +%define X86_CR3_PAGE_MASK (0xfffff000) +%define X86_CR3_PAE_PAGE_MASK (0xffffffe0) +%define X86_CR3_AMD64_PAGE_MASK 0x000ffffffffff000 +%define X86_CR3_EPT_PAGE_MASK 0x0000fffffffff000 +%define X86_CR4_VME RT_BIT_32(0) +%define X86_CR4_PVI RT_BIT_32(1) +%define X86_CR4_TSD RT_BIT_32(2) +%define X86_CR4_DE RT_BIT_32(3) +%define X86_CR4_PSE RT_BIT_32(4) +%define X86_CR4_PAE RT_BIT_32(5) +%define X86_CR4_MCE RT_BIT_32(6) +%define X86_CR4_PGE RT_BIT_32(7) +%define X86_CR4_PCE RT_BIT_32(8) +%define X86_CR4_OSFXSR RT_BIT_32(9) +%define X86_CR4_OSXMMEEXCPT RT_BIT_32(10) +%define X86_CR4_UMIP RT_BIT_32(11) +%define X86_CR4_VMXE RT_BIT_32(13) +%define X86_CR4_SMXE RT_BIT_32(14) +%define X86_CR4_FSGSBASE RT_BIT_32(16) +%define X86_CR4_PCIDE RT_BIT_32(17) +%define X86_CR4_OSXSAVE RT_BIT_32(18) +%define X86_CR4_SMEP RT_BIT_32(20) +%define X86_CR4_SMAP RT_BIT_32(21) +%define X86_CR4_PKE RT_BIT_32(22) +%define X86_CR4_CET RT_BIT_32(23) +%define X86_DR6_B0 RT_BIT_32(0) +%define X86_DR6_B1 RT_BIT_32(1) +%define X86_DR6_B2 RT_BIT_32(2) +%define X86_DR6_B3 RT_BIT_32(3) +%define X86_DR6_B_MASK 0x0000000f +%define X86_DR6_BD RT_BIT_32(13) +%define X86_DR6_BS RT_BIT_32(14) +%define X86_DR6_BT RT_BIT_32(15) +%define X86_DR6_RTM RT_BIT_32(16) +%define X86_DR6_INIT_VAL 0xffff0ff0 +%define X86_DR6_RA1_MASK 0xffff0ff0 +%define X86_DR6_RA1_MASK_RTM 0xfffe0ff0 +%define X86_DR6_RAZ_MASK RT_BIT_64(12) +%define X86_DR6_MBZ_MASK 0xffffffff00000000 +%define X86_DR6_B(iBp) RT_BIT_64(iBp) +%define X86_DR7_L0 RT_BIT_32(0) +%define X86_DR7_G0 RT_BIT_32(1) +%define X86_DR7_L1 RT_BIT_32(2) +%define X86_DR7_G1 RT_BIT_32(3) +%define X86_DR7_L2 RT_BIT_32(4) +%define X86_DR7_G2 RT_BIT_32(5) +%define X86_DR7_L3 RT_BIT_32(6) +%define X86_DR7_G3 RT_BIT_32(7) +%define X86_DR7_LE RT_BIT_32(8) +%define X86_DR7_GE RT_BIT_32(9) +%define X86_DR7_LE_ALL 0x0000000000000055 +%define X86_DR7_GE_ALL 0x00000000000000aa +%define X86_DR7_RTM RT_BIT_32(11) +%define X86_DR7_ICE_IR RT_BIT_32(12) +%define X86_DR7_GD RT_BIT_32(13) +%define X86_DR7_ICE_TR1 RT_BIT_32(14) +%define X86_DR7_ICE_TR2 RT_BIT_32(15) +%define X86_DR7_RW0_MASK (3 << 16) +%define X86_DR7_LEN0_MASK (3 << 18) +%define X86_DR7_RW1_MASK (3 << 20) +%define X86_DR7_LEN1_MASK (3 << 22) +%define X86_DR7_RW2_MASK (3 << 24) +%define X86_DR7_LEN2_MASK (3 << 26) +%define X86_DR7_RW3_MASK (3 << 28) +%define X86_DR7_LEN3_MASK (3 << 30) +%define X86_DR7_RA1_MASK RT_BIT_32(10) +%define X86_DR7_RAZ_MASK 0x0000d800 +%define X86_DR7_MBZ_MASK 0xffffffff00000000 +%define X86_DR7_L(iBp) ( 1 << (iBp * 2) ) +%define X86_DR7_G(iBp) ( 1 << (iBp * 2 + 1) ) +%define X86_DR7_L_G(iBp) ( 3 << (iBp * 2) ) +%define X86_DR7_RW_EO 0 +%define X86_DR7_RW_WO 1 +%define X86_DR7_RW_IO 2 +%define X86_DR7_RW_RW 3 +%define X86_DR7_RW(iBp, fRw) ( (fRw) << ((iBp) * 4 + 16) ) +%define X86_DR7_GET_RW(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 16) ) & 3 ) +%define X86_DR7_RW_ALL_MASKS 0x33330000 +%ifndef VBOX_FOR_DTRACE_LIB + %define X86_DR7_ANY_RW_IO(uDR7) \ + ( ( 0x22220000 & (uDR7) ) +%endif +%define X86_DR7_LEN_BYTE 0 +%define X86_DR7_LEN_WORD 1 +%define X86_DR7_LEN_QWORD 2 +%define X86_DR7_LEN_DWORD 3 +%define X86_DR7_LEN(iBp, cb) ( (cb) << ((iBp) * 4 + 18) ) +%define X86_DR7_GET_LEN(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 18) ) & 0x3 ) +%define X86_DR7_ENABLED_MASK 0x000000ff +%define X86_DR7_LEN_ALL_MASKS 0xcccc0000 +%define X86_DR7_RW_LEN_ALL_MASKS 0xffff0000 +%define X86_DR7_INIT_VAL 0x400 +%define MSR_P5_MC_ADDR 0x00000000 +%define MSR_P5_MC_TYPE 0x00000001 +%define MSR_IA32_TSC 0x10 +%define MSR_IA32_CESR 0x00000011 +%define MSR_IA32_CTR0 0x00000012 +%define MSR_IA32_CTR1 0x00000013 +%define MSR_IA32_PLATFORM_ID 0x17 +%ifndef MSR_IA32_APICBASE + %define MSR_IA32_APICBASE 0x1b + %define MSR_IA32_APICBASE_EN RT_BIT_64(11) + %define MSR_IA32_APICBASE_EXTD RT_BIT_64(10) + %define MSR_IA32_APICBASE_BSP RT_BIT_64(8) + %define MSR_IA32_APICBASE_BASE_MIN 0x0000000ffffff000 + %define MSR_IA32_APICBASE_ADDR 0x00000000fee00000 + %define MSR_IA32_APICBASE_GET_ADDR(a_Msr) ((a_Msr) & X86_PAGE_4K_BASE_MASK) +%endif +%define MSR_CORE_THREAD_COUNT 0x35 +%define MSR_IA32_FEATURE_CONTROL 0x3A +%define MSR_IA32_FEATURE_CONTROL_LOCK RT_BIT_64(0) +%define MSR_IA32_FEATURE_CONTROL_SMX_VMXON RT_BIT_64(1) +%define MSR_IA32_FEATURE_CONTROL_VMXON RT_BIT_64(2) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_0 RT_BIT_64(8) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_1 RT_BIT_64(9) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_2 RT_BIT_64(10) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_3 RT_BIT_64(11) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_4 RT_BIT_64(12) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_5 RT_BIT_64(13) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_6 RT_BIT_64(14) +%define MSR_IA32_FEATURE_CONTROL_SENTER_GLOBAL_EN RT_BIT_64(15) +%define MSR_IA32_FEATURE_CONTROL_SGX_LAUNCH_EN RT_BIT_64(17) +%define MSR_IA32_FEATURE_CONTROL_SGX_GLOBAL_EN RT_BIT_64(18) +%define MSR_IA32_FEATURE_CONTROL_LMCE RT_BIT_64(20) +%define MSR_IA32_TSC_ADJUST 0x3B +%define MSR_IA32_SPEC_CTRL 0x48 +%define MSR_IA32_SPEC_CTRL_F_IBRS RT_BIT_32(0) +%define MSR_IA32_SPEC_CTRL_F_STIBP RT_BIT_32(1) +%define MSR_IA32_SPEC_CTRL_F_SSBD RT_BIT_32(2) +%define MSR_IA32_PRED_CMD 0x49 +%define MSR_IA32_PRED_CMD_F_IBPB RT_BIT_32(0) +%define MSR_IA32_BIOS_UPDT_TRIG 0x79 +%define MSR_IA32_BIOS_SIGN_ID 0x8B +%define MSR_IA32_SMM_MONITOR_CTL 0x9B +%define MSR_IA32_SMM_MONITOR_VALID RT_BIT_64(0) +%define MSR_IA32_SMM_MONITOR_VMXOFF_UNBLOCK_SMI RT_BIT_64(2) +%define MSR_IA32_SMM_MONITOR_MSGEG_PHYSADDR(a) (((a) >> 12) & 0xfffff) +%define MSR_IA32_SMBASE 0x9E +%define MSR_IA32_PMC0 0xC1 +%define MSR_IA32_PMC1 0xC2 +%define MSR_IA32_PMC2 0xC3 +%define MSR_IA32_PMC3 0xC4 +%define MSR_IA32_PMC4 0xC5 +%define MSR_IA32_PMC5 0xC6 +%define MSR_IA32_PMC6 0xC7 +%define MSR_IA32_PMC7 0xC8 +%define MSR_IA32_PLATFORM_INFO 0xCE +%define MSR_IA32_FSB_CLOCK_STS 0xCD +%define MSR_PKG_CST_CONFIG_CONTROL 0x000000e2 +%define MSR_IA32_MPERF 0xE7 +%define MSR_IA32_APERF 0xE8 +%define MSR_IA32_MTRR_CAP 0xFE +%define MSR_IA32_ARCH_CAPABILITIES 0x10a +%define MSR_IA32_ARCH_CAP_F_RDCL_NO RT_BIT_32(0) +%define MSR_IA32_ARCH_CAP_F_IBRS_ALL RT_BIT_32(1) +%define MSR_IA32_ARCH_CAP_F_RSBO RT_BIT_32(2) +%define MSR_IA32_ARCH_CAP_F_VMM_NEED_NOT_FLUSH_L1D RT_BIT_32(3) +%define MSR_IA32_ARCH_CAP_F_MDS_NO RT_BIT_32(4) +%define MSR_IA32_FLUSH_CMD 0x10b +%define MSR_IA32_FLUSH_CMD_F_L1D RT_BIT_32(0) +%define MSR_BBL_CR_CTL3 0x11e +%ifndef MSR_IA32_SYSENTER_CS +%define MSR_IA32_SYSENTER_CS 0x174 +%define MSR_IA32_SYSENTER_ESP 0x175 +%define MSR_IA32_SYSENTER_EIP 0x176 +%endif +%define MSR_IA32_MCG_CAP 0x179 +%define MSR_IA32_MCG_STATUS 0x17A +%define MSR_IA32_MCG_CTRL 0x17B +%define MSR_IA32_CR_PAT 0x277 +%define MSR_IA32_CR_PAT_INIT_VAL 0x0007040600070406 +%define MSR_IA32_PERFEVTSEL0 0x186 +%define MSR_IA32_PERFEVTSEL1 0x187 +%define MSR_IA32_PERFEVTSEL2 0x188 +%define MSR_IA32_PERFEVTSEL3 0x189 +%define MSR_FLEX_RATIO 0x194 +%define MSR_IA32_PERF_STATUS 0x198 +%define MSR_IA32_PERF_CTL 0x199 +%define MSR_IA32_THERM_STATUS 0x19c +%define MSR_OFFCORE_RSP_0 0x1a6 +%define MSR_OFFCORE_RSP_1 0x1a7 +%define MSR_IA32_MISC_ENABLE 0x1A0 +%define MSR_IA32_MISC_ENABLE_FAST_STRINGS RT_BIT_64(0) +%define MSR_IA32_MISC_ENABLE_TCC RT_BIT_64(3) +%define MSR_IA32_MISC_ENABLE_PERF_MON RT_BIT_64(7) +%define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL RT_BIT_64(11) +%define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL RT_BIT_64(12) +%define MSR_IA32_MISC_ENABLE_SST_ENABLE RT_BIT_64(16) +%define MSR_IA32_MISC_ENABLE_MONITOR RT_BIT_64(18) +%define MSR_IA32_MISC_ENABLE_LIMIT_CPUID RT_BIT_64(22) +%define MSR_IA32_MISC_ENABLE_XTPR_MSG_DISABLE RT_BIT_64(23) +%define MSR_IA32_MISC_ENABLE_XD_DISABLE RT_BIT_64(34) +%define MSR_IA32_DEBUGCTL 0x000001d9 +%define MSR_IA32_DEBUGCTL_LBR RT_BIT_64(0) +%define MSR_IA32_DEBUGCTL_BTF RT_BIT_64(1) +%define MSR_IA32_DEBUGCTL_PB0 RT_BIT_64(2) +%define MSR_IA32_DEBUGCTL_PB1 RT_BIT_64(3) +%define MSR_IA32_DEBUGCTL_PB2 RT_BIT_64(4) +%define MSR_IA32_DEBUGCTL_PB3 RT_BIT_64(5) +%define MSR_IA32_DEBUGCTL_TR RT_BIT_64(6) +%define MSR_IA32_DEBUGCTL_BTS RT_BIT_64(7) +%define MSR_IA32_DEBUGCTL_BTINT RT_BIT_64(8) +%define MSR_IA32_DEBUGCTL_BTS_OFF_OS RT_BIT_64(9) +%define MSR_IA32_DEBUGCTL_BTS_OFF_USER RT_BIT_64(10) +%define MSR_IA32_DEBUGCTL_FREEZE_LBR_ON_PMI RT_BIT_64(11) +%define MSR_IA32_DEBUGCTL_FREEZE_PERFMON_ON_PMI RT_BIT_64(12) +%define MSR_IA32_DEBUGCTL_FREEZE_WHILE_SMM_EM RT_BIT_64(14) +%define MSR_IA32_DEBUGCTL_RTM RT_BIT_64(15) +%define MSR_IA32_DEBUGCTL_VALID_MASK_INTEL ( MSR_IA32_DEBUGCTL_LBR | MSR_IA32_DEBUGCTL_BTF | MSR_IA32_DEBUGCTL_TR \ + | MSR_IA32_DEBUGCTL_BTS | MSR_IA32_DEBUGCTL_BTINT | MSR_IA32_DEBUGCTL_BTS_OFF_OS \ + | MSR_IA32_DEBUGCTL_BTS_OFF_USER | MSR_IA32_DEBUGCTL_FREEZE_LBR_ON_PMI \ + | MSR_IA32_DEBUGCTL_FREEZE_PERFMON_ON_PMI | MSR_IA32_DEBUGCTL_FREEZE_WHILE_SMM_EM \ + | MSR_IA32_DEBUGCTL_RTM) +%define MSR_P4_LASTBRANCH_0 0x1db +%define MSR_P4_LASTBRANCH_1 0x1dc +%define MSR_P4_LASTBRANCH_2 0x1dd +%define MSR_P4_LASTBRANCH_3 0x1de +%define MSR_P4_LASTBRANCH_TOS 0x1da +%define MSR_CORE2_LASTBRANCH_0_FROM_IP 0x40 +%define MSR_CORE2_LASTBRANCH_1_FROM_IP 0x41 +%define MSR_CORE2_LASTBRANCH_2_FROM_IP 0x42 +%define MSR_CORE2_LASTBRANCH_3_FROM_IP 0x43 +%define MSR_CORE2_LASTBRANCH_0_TO_IP 0x60 +%define MSR_CORE2_LASTBRANCH_1_TO_IP 0x61 +%define MSR_CORE2_LASTBRANCH_2_TO_IP 0x62 +%define MSR_CORE2_LASTBRANCH_3_TO_IP 0x63 +%define MSR_CORE2_LASTBRANCH_TOS 0x1c9 +%define MSR_LASTBRANCH_0_FROM_IP 0x680 +%define MSR_LASTBRANCH_1_FROM_IP 0x681 +%define MSR_LASTBRANCH_2_FROM_IP 0x682 +%define MSR_LASTBRANCH_3_FROM_IP 0x683 +%define MSR_LASTBRANCH_4_FROM_IP 0x684 +%define MSR_LASTBRANCH_5_FROM_IP 0x685 +%define MSR_LASTBRANCH_6_FROM_IP 0x686 +%define MSR_LASTBRANCH_7_FROM_IP 0x687 +%define MSR_LASTBRANCH_8_FROM_IP 0x688 +%define MSR_LASTBRANCH_9_FROM_IP 0x689 +%define MSR_LASTBRANCH_10_FROM_IP 0x68a +%define MSR_LASTBRANCH_11_FROM_IP 0x68b +%define MSR_LASTBRANCH_12_FROM_IP 0x68c +%define MSR_LASTBRANCH_13_FROM_IP 0x68d +%define MSR_LASTBRANCH_14_FROM_IP 0x68e +%define MSR_LASTBRANCH_15_FROM_IP 0x68f +%define MSR_LASTBRANCH_16_FROM_IP 0x690 +%define MSR_LASTBRANCH_17_FROM_IP 0x691 +%define MSR_LASTBRANCH_18_FROM_IP 0x692 +%define MSR_LASTBRANCH_19_FROM_IP 0x693 +%define MSR_LASTBRANCH_20_FROM_IP 0x694 +%define MSR_LASTBRANCH_21_FROM_IP 0x695 +%define MSR_LASTBRANCH_22_FROM_IP 0x696 +%define MSR_LASTBRANCH_23_FROM_IP 0x697 +%define MSR_LASTBRANCH_24_FROM_IP 0x698 +%define MSR_LASTBRANCH_25_FROM_IP 0x699 +%define MSR_LASTBRANCH_26_FROM_IP 0x69a +%define MSR_LASTBRANCH_27_FROM_IP 0x69b +%define MSR_LASTBRANCH_28_FROM_IP 0x69c +%define MSR_LASTBRANCH_29_FROM_IP 0x69d +%define MSR_LASTBRANCH_30_FROM_IP 0x69e +%define MSR_LASTBRANCH_31_FROM_IP 0x69f +%define MSR_LASTBRANCH_0_TO_IP 0x6c0 +%define MSR_LASTBRANCH_1_TO_IP 0x6c1 +%define MSR_LASTBRANCH_2_TO_IP 0x6c2 +%define MSR_LASTBRANCH_3_TO_IP 0x6c3 +%define MSR_LASTBRANCH_4_TO_IP 0x6c4 +%define MSR_LASTBRANCH_5_TO_IP 0x6c5 +%define MSR_LASTBRANCH_6_TO_IP 0x6c6 +%define MSR_LASTBRANCH_7_TO_IP 0x6c7 +%define MSR_LASTBRANCH_8_TO_IP 0x6c8 +%define MSR_LASTBRANCH_9_TO_IP 0x6c9 +%define MSR_LASTBRANCH_10_TO_IP 0x6ca +%define MSR_LASTBRANCH_11_TO_IP 0x6cb +%define MSR_LASTBRANCH_12_TO_IP 0x6cc +%define MSR_LASTBRANCH_13_TO_IP 0x6cd +%define MSR_LASTBRANCH_14_TO_IP 0x6ce +%define MSR_LASTBRANCH_15_TO_IP 0x6cf +%define MSR_LASTBRANCH_16_TO_IP 0x6d0 +%define MSR_LASTBRANCH_17_TO_IP 0x6d1 +%define MSR_LASTBRANCH_18_TO_IP 0x6d2 +%define MSR_LASTBRANCH_19_TO_IP 0x6d3 +%define MSR_LASTBRANCH_20_TO_IP 0x6d4 +%define MSR_LASTBRANCH_21_TO_IP 0x6d5 +%define MSR_LASTBRANCH_22_TO_IP 0x6d6 +%define MSR_LASTBRANCH_23_TO_IP 0x6d7 +%define MSR_LASTBRANCH_24_TO_IP 0x6d8 +%define MSR_LASTBRANCH_25_TO_IP 0x6d9 +%define MSR_LASTBRANCH_26_TO_IP 0x6da +%define MSR_LASTBRANCH_27_TO_IP 0x6db +%define MSR_LASTBRANCH_28_TO_IP 0x6dc +%define MSR_LASTBRANCH_29_TO_IP 0x6dd +%define MSR_LASTBRANCH_30_TO_IP 0x6de +%define MSR_LASTBRANCH_31_TO_IP 0x6df +%define MSR_LASTBRANCH_0_INFO 0xdc0 +%define MSR_LASTBRANCH_1_INFO 0xdc1 +%define MSR_LASTBRANCH_2_INFO 0xdc2 +%define MSR_LASTBRANCH_3_INFO 0xdc3 +%define MSR_LASTBRANCH_4_INFO 0xdc4 +%define MSR_LASTBRANCH_5_INFO 0xdc5 +%define MSR_LASTBRANCH_6_INFO 0xdc6 +%define MSR_LASTBRANCH_7_INFO 0xdc7 +%define MSR_LASTBRANCH_8_INFO 0xdc8 +%define MSR_LASTBRANCH_9_INFO 0xdc9 +%define MSR_LASTBRANCH_10_INFO 0xdca +%define MSR_LASTBRANCH_11_INFO 0xdcb +%define MSR_LASTBRANCH_12_INFO 0xdcc +%define MSR_LASTBRANCH_13_INFO 0xdcd +%define MSR_LASTBRANCH_14_INFO 0xdce +%define MSR_LASTBRANCH_15_INFO 0xdcf +%define MSR_LASTBRANCH_16_INFO 0xdd0 +%define MSR_LASTBRANCH_17_INFO 0xdd1 +%define MSR_LASTBRANCH_18_INFO 0xdd2 +%define MSR_LASTBRANCH_19_INFO 0xdd3 +%define MSR_LASTBRANCH_20_INFO 0xdd4 +%define MSR_LASTBRANCH_21_INFO 0xdd5 +%define MSR_LASTBRANCH_22_INFO 0xdd6 +%define MSR_LASTBRANCH_23_INFO 0xdd7 +%define MSR_LASTBRANCH_24_INFO 0xdd8 +%define MSR_LASTBRANCH_25_INFO 0xdd9 +%define MSR_LASTBRANCH_26_INFO 0xdda +%define MSR_LASTBRANCH_27_INFO 0xddb +%define MSR_LASTBRANCH_28_INFO 0xddc +%define MSR_LASTBRANCH_29_INFO 0xddd +%define MSR_LASTBRANCH_30_INFO 0xdde +%define MSR_LASTBRANCH_31_INFO 0xddf +%define MSR_LASTBRANCH_SELECT 0x1c8 +%define MSR_LASTBRANCH_TOS 0x1c9 +%define MSR_LER_FROM_IP 0x1dd +%define MSR_LER_TO_IP 0x1de +%define MSR_IA32_TSX_CTRL 0x122 +%define MSR_IA32_MTRR_PHYSBASE0 0x200 +%define MSR_IA32_MTRR_PHYSMASK0 0x201 +%define MSR_IA32_MTRR_PHYSBASE1 0x202 +%define MSR_IA32_MTRR_PHYSMASK1 0x203 +%define MSR_IA32_MTRR_PHYSBASE2 0x204 +%define MSR_IA32_MTRR_PHYSMASK2 0x205 +%define MSR_IA32_MTRR_PHYSBASE3 0x206 +%define MSR_IA32_MTRR_PHYSMASK3 0x207 +%define MSR_IA32_MTRR_PHYSBASE4 0x208 +%define MSR_IA32_MTRR_PHYSMASK4 0x209 +%define MSR_IA32_MTRR_PHYSBASE5 0x20a +%define MSR_IA32_MTRR_PHYSMASK5 0x20b +%define MSR_IA32_MTRR_PHYSBASE6 0x20c +%define MSR_IA32_MTRR_PHYSMASK6 0x20d +%define MSR_IA32_MTRR_PHYSBASE7 0x20e +%define MSR_IA32_MTRR_PHYSMASK7 0x20f +%define MSR_IA32_MTRR_PHYSBASE8 0x210 +%define MSR_IA32_MTRR_PHYSMASK8 0x211 +%define MSR_IA32_MTRR_PHYSBASE9 0x212 +%define MSR_IA32_MTRR_PHYSMASK9 0x213 +%define MSR_IA32_MTRR_FIX64K_00000 0x250 +%define MSR_IA32_MTRR_FIX16K_80000 0x258 +%define MSR_IA32_MTRR_FIX16K_A0000 0x259 +%define MSR_IA32_MTRR_FIX4K_C0000 0x268 +%define MSR_IA32_MTRR_FIX4K_C8000 0x269 +%define MSR_IA32_MTRR_FIX4K_D0000 0x26a +%define MSR_IA32_MTRR_FIX4K_D8000 0x26b +%define MSR_IA32_MTRR_FIX4K_E0000 0x26c +%define MSR_IA32_MTRR_FIX4K_E8000 0x26d +%define MSR_IA32_MTRR_FIX4K_F0000 0x26e +%define MSR_IA32_MTRR_FIX4K_F8000 0x26f +%define MSR_IA32_MTRR_DEF_TYPE 0x2FF +%define MSR_IA32_PERF_GLOBAL_STATUS 0x38E +%define MSR_IA32_PERF_GLOBAL_CTRL 0x38F +%define MSR_IA32_PERF_GLOBAL_OVF_CTRL 0x390 +%define MSR_IA32_PEBS_ENABLE 0x3F1 +%define MSR_IA32_MC0_CTL 0x400 +%define MSR_IA32_MC0_STATUS 0x401 +%define MSR_IA32_VMX_BASIC 0x480 +%define MSR_IA32_VMX_PINBASED_CTLS 0x481 +%define MSR_IA32_VMX_PROCBASED_CTLS 0x482 +%define MSR_IA32_VMX_EXIT_CTLS 0x483 +%define MSR_IA32_VMX_ENTRY_CTLS 0x484 +%define MSR_IA32_VMX_MISC 0x485 +%define MSR_IA32_VMX_CR0_FIXED0 0x486 +%define MSR_IA32_VMX_CR0_FIXED1 0x487 +%define MSR_IA32_VMX_CR4_FIXED0 0x488 +%define MSR_IA32_VMX_CR4_FIXED1 0x489 +%define MSR_IA32_VMX_VMCS_ENUM 0x48A +%define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B +%define MSR_IA32_VMX_EPT_VPID_CAP 0x48C +%define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x48D +%define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x48E +%define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x48F +%define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x490 +%define MSR_IA32_VMX_VMFUNC 0x491 +%define MSR_IA32_VMX_PROCBASED_CTLS3 0x492 +%define MSR_IA32_RTIT_CTL 0x570 +%define MSR_IA32_DS_AREA 0x600 +%define MSR_RAPL_POWER_UNIT 0x606 +%define MSR_PKGC3_IRTL 0x60a +%define MSR_PKGC_IRTL1 0x60b +%define MSR_PKGC_IRTL2 0x60c +%define MSR_PKG_C2_RESIDENCY 0x60d +%define MSR_PKG_POWER_LIMIT 0x610 +%define MSR_PKG_ENERGY_STATUS 0x611 +%define MSR_PKG_PERF_STATUS 0x613 +%define MSR_PKG_POWER_INFO 0x614 +%define MSR_DRAM_POWER_LIMIT 0x618 +%define MSR_DRAM_ENERGY_STATUS 0x619 +%define MSR_DRAM_PERF_STATUS 0x61b +%define MSR_DRAM_POWER_INFO 0x61c +%define MSR_PKG_C10_RESIDENCY 0x632 +%define MSR_PP0_ENERGY_STATUS 0x639 +%define MSR_PP1_ENERGY_STATUS 0x641 +%define MSR_TURBO_ACTIVATION_RATIO 0x64c +%define MSR_CORE_PERF_LIMIT_REASONS 0x64f +%define MSR_IA32_X2APIC_START 0x800 +%define MSR_IA32_X2APIC_ID 0x802 +%define MSR_IA32_X2APIC_VERSION 0x803 +%define MSR_IA32_X2APIC_TPR 0x808 +%define MSR_IA32_X2APIC_PPR 0x80A +%define MSR_IA32_X2APIC_EOI 0x80B +%define MSR_IA32_X2APIC_LDR 0x80D +%define MSR_IA32_X2APIC_SVR 0x80F +%define MSR_IA32_X2APIC_ISR0 0x810 +%define MSR_IA32_X2APIC_ISR1 0x811 +%define MSR_IA32_X2APIC_ISR2 0x812 +%define MSR_IA32_X2APIC_ISR3 0x813 +%define MSR_IA32_X2APIC_ISR4 0x814 +%define MSR_IA32_X2APIC_ISR5 0x815 +%define MSR_IA32_X2APIC_ISR6 0x816 +%define MSR_IA32_X2APIC_ISR7 0x817 +%define MSR_IA32_X2APIC_TMR0 0x818 +%define MSR_IA32_X2APIC_TMR1 0x819 +%define MSR_IA32_X2APIC_TMR2 0x81A +%define MSR_IA32_X2APIC_TMR3 0x81B +%define MSR_IA32_X2APIC_TMR4 0x81C +%define MSR_IA32_X2APIC_TMR5 0x81D +%define MSR_IA32_X2APIC_TMR6 0x81E +%define MSR_IA32_X2APIC_TMR7 0x81F +%define MSR_IA32_X2APIC_IRR0 0x820 +%define MSR_IA32_X2APIC_IRR1 0x821 +%define MSR_IA32_X2APIC_IRR2 0x822 +%define MSR_IA32_X2APIC_IRR3 0x823 +%define MSR_IA32_X2APIC_IRR4 0x824 +%define MSR_IA32_X2APIC_IRR5 0x825 +%define MSR_IA32_X2APIC_IRR6 0x826 +%define MSR_IA32_X2APIC_IRR7 0x827 +%define MSR_IA32_X2APIC_ESR 0x828 +%define MSR_IA32_X2APIC_LVT_CMCI 0x82F +%define MSR_IA32_X2APIC_ICR 0x830 +%define MSR_IA32_X2APIC_LVT_TIMER 0x832 +%define MSR_IA32_X2APIC_LVT_THERMAL 0x833 +%define MSR_IA32_X2APIC_LVT_PERF 0x834 +%define MSR_IA32_X2APIC_LVT_LINT0 0x835 +%define MSR_IA32_X2APIC_LVT_LINT1 0x836 +%define MSR_IA32_X2APIC_LVT_ERROR 0x837 +%define MSR_IA32_X2APIC_TIMER_ICR 0x838 +%define MSR_IA32_X2APIC_TIMER_CCR 0x839 +%define MSR_IA32_X2APIC_TIMER_DCR 0x83E +%define MSR_IA32_X2APIC_SELF_IPI 0x83F +%define MSR_IA32_X2APIC_END 0x8FF +%define MSR_IA32_X2APIC_LVT_START MSR_IA32_X2APIC_LVT_TIMER +%define MSR_IA32_X2APIC_LVT_END MSR_IA32_X2APIC_LVT_ERROR +%define MSR_K6_EFER 0xc0000080 +%define MSR_K6_EFER_SCE RT_BIT_32(0) +%define MSR_K6_EFER_LME RT_BIT_32(8) +%define MSR_K6_EFER_BIT_LME 8 +%define MSR_K6_EFER_LMA RT_BIT_32(10) +%define MSR_K6_EFER_BIT_LMA 10 +%define MSR_K6_EFER_NXE RT_BIT_32(11) +%define MSR_K6_EFER_BIT_NXE 11 +%define MSR_K6_EFER_SVME RT_BIT_32(12) +%define MSR_K6_EFER_LMSLE RT_BIT_32(13) +%define MSR_K6_EFER_FFXSR RT_BIT_32(14) +%define MSR_K6_EFER_TCE RT_BIT_32(15) +%define MSR_K6_EFER_MCOMMIT RT_BIT_32(17) +%define MSR_K6_STAR 0xc0000081 +%define MSR_K6_STAR_SYSRET_CS_SS_SHIFT 48 +%define MSR_K6_STAR_SYSCALL_CS_SS_SHIFT 32 +%define MSR_K6_STAR_SEL_MASK 0xffff +%define MSR_K6_STAR_SYSCALL_EIP_MASK 0xffffffff +%define MSR_K6_WHCR 0xc0000082 +%define MSR_K6_UWCCR 0xc0000085 +%define MSR_K6_PSOR 0xc0000087 +%define MSR_K6_PFIR 0xc0000088 +%define MSR_K7_EVNTSEL0 0xc0010000 +%define MSR_K7_EVNTSEL1 0xc0010001 +%define MSR_K7_EVNTSEL2 0xc0010002 +%define MSR_K7_EVNTSEL3 0xc0010003 +%define MSR_K7_PERFCTR0 0xc0010004 +%define MSR_K7_PERFCTR1 0xc0010005 +%define MSR_K7_PERFCTR2 0xc0010006 +%define MSR_K7_PERFCTR3 0xc0010007 +%define MSR_K8_LSTAR 0xc0000082 +%define MSR_K8_CSTAR 0xc0000083 +%define MSR_K8_SF_MASK 0xc0000084 +%define MSR_K8_FS_BASE 0xc0000100 +%define MSR_K8_GS_BASE 0xc0000101 +%define MSR_K8_KERNEL_GS_BASE 0xc0000102 +%define MSR_K8_TSC_AUX 0xc0000103 +%define MSR_K8_SYSCFG 0xc0010010 +%define MSR_K8_HWCR 0xc0010015 +%define MSR_K8_IORRBASE0 0xc0010016 +%define MSR_K8_IORRMASK0 0xc0010017 +%define MSR_K8_IORRBASE1 0xc0010018 +%define MSR_K8_IORRMASK1 0xc0010019 +%define MSR_K8_TOP_MEM1 0xc001001a +%define MSR_K8_TOP_MEM2 0xc001001d +%define MSR_K7_SMBASE 0xc0010111 +%define MSR_K7_SMM_ADDR 0xc0010112 +%define MSR_K7_SMM_MASK 0xc0010113 +%define MSR_K8_NB_CFG 0xc001001f +%define MSR_K8_INT_PENDING 0xc0010055 +%define MSR_K8_VM_CR 0xc0010114 +%define MSR_K8_VM_CR_DPD RT_BIT_32(0) +%define MSR_K8_VM_CR_R_INIT RT_BIT_32(1) +%define MSR_K8_VM_CR_DIS_A20M RT_BIT_32(2) +%define MSR_K8_VM_CR_LOCK RT_BIT_32(3) +%define MSR_K8_VM_CR_SVM_DISABLE RT_BIT_32(4) +%define MSR_K8_IGNNE 0xc0010115 +%define MSR_K8_SMM_CTL 0xc0010116 +%define MSR_K8_VM_HSAVE_PA 0xc0010117 +%define MSR_AMD_VIRT_SPEC_CTL 0xc001011f + %define MSR_AMD_VIRT_SPEC_CTL_F_SSBD RT_BIT(2) +%define X86_PG_ENTRIES 1024 +%define X86_PG_PAE_ENTRIES 512 +%define X86_PG_PAE_PDPE_ENTRIES 4 +%define X86_PG_AMD64_ENTRIES X86_PG_PAE_ENTRIES +%define X86_PG_AMD64_PDPE_ENTRIES X86_PG_AMD64_ENTRIES +%define X86_PAGE_SIZE X86_PAGE_4K_SIZE +%define X86_PAGE_SHIFT X86_PAGE_4K_SHIFT +%define X86_PAGE_OFFSET_MASK X86_PAGE_4K_OFFSET_MASK +%define X86_PAGE_BASE_MASK X86_PAGE_4K_BASE_MASK +%define X86_PAGE_BASE_MASK_32 X86_PAGE_4K_BASE_MASK_32 +%define X86_PAGE_4K_SIZE _4K +%define X86_PAGE_4K_SHIFT 12 +%define X86_PAGE_4K_OFFSET_MASK 0xfff +%define X86_PAGE_4K_BASE_MASK 0xfffffffffffff000 +%define X86_PAGE_4K_BASE_MASK_32 0xfffff000 +%define X86_PAGE_2M_SIZE _2M +%define X86_PAGE_2M_SHIFT 21 +%define X86_PAGE_2M_OFFSET_MASK 0x001fffff +%define X86_PAGE_2M_BASE_MASK 0xffffffffffe00000 +%define X86_PAGE_2M_BASE_MASK_32 0xffe00000 +%define X86_PAGE_4M_SIZE _4M +%define X86_PAGE_4M_SHIFT 22 +%define X86_PAGE_4M_OFFSET_MASK 0x003fffff +%define X86_PAGE_4M_BASE_MASK 0xffffffffffc00000 +%define X86_PAGE_4M_BASE_MASK_32 0xffc00000 +%define X86_PAGE_1G_SIZE _1G +%define X86_PAGE_1G_SHIFT 30 +%define X86_PAGE_1G_OFFSET_MASK 0x3fffffff +%define X86_PAGE_1G_BASE_MASK 0xffffffffc0000000 +%define X86_IS_CANONICAL(a_u64Addr) ((uint64_t)(a_u64Addr) + 0x800000000000 < UINT64_C(0x1000000000000)) +%define X86_GET_PAGE_BASE_MASK(a_cShift) (0xffffffffffffffff << (a_cShift)) +%define X86_GET_PAGE_OFFSET_MASK(a_cShift) (~X86_GET_PAGE_BASE_MASK(a_cShift)) +%define X86_PTE_BIT_P 0 +%define X86_PTE_BIT_RW 1 +%define X86_PTE_BIT_US 2 +%define X86_PTE_BIT_PWT 3 +%define X86_PTE_BIT_PCD 4 +%define X86_PTE_BIT_A 5 +%define X86_PTE_BIT_D 6 +%define X86_PTE_BIT_PAT 7 +%define X86_PTE_BIT_G 8 +%define X86_PTE_PAE_BIT_NX 63 +%define X86_PTE_P RT_BIT_32(0) +%define X86_PTE_RW RT_BIT_32(1) +%define X86_PTE_US RT_BIT_32(2) +%define X86_PTE_PWT RT_BIT_32(3) +%define X86_PTE_PCD RT_BIT_32(4) +%define X86_PTE_A RT_BIT_32(5) +%define X86_PTE_D RT_BIT_32(6) +%define X86_PTE_PAT RT_BIT_32(7) +%define X86_PTE_G RT_BIT_32(8) +%define X86_PTE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PTE_PG_MASK ( 0xfffff000 ) +%define X86_PTE_PAE_PG_MASK 0x000ffffffffff000 +%define X86_PTE_PAE_NX RT_BIT_64(63) +%define X86_PTE_PAE_MBZ_MASK_NX 0x7ff0000000000000 +%define X86_PTE_PAE_MBZ_MASK_NO_NX 0xfff0000000000000 +%define X86_PTE_LM_MBZ_MASK_NX 0x0000000000000000 +%define X86_PTE_LM_MBZ_MASK_NO_NX 0x8000000000000000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PT_SHIFT 12 +%define X86_PT_MASK 0x3ff +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PT_PAE_SHIFT 12 +%define X86_PT_PAE_MASK 0x1ff +%define X86_PDE_P RT_BIT_32(0) +%define X86_PDE_RW RT_BIT_32(1) +%define X86_PDE_US RT_BIT_32(2) +%define X86_PDE_PWT RT_BIT_32(3) +%define X86_PDE_PCD RT_BIT_32(4) +%define X86_PDE_A RT_BIT_32(5) +%define X86_PDE_PS RT_BIT_32(7) +%define X86_PDE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PDE_PG_MASK ( 0xfffff000 ) +%define X86_PDE_PAE_PG_MASK 0x000ffffffffff000 +%define X86_PDE_PAE_NX RT_BIT_64(63) +%define X86_PDE_PAE_MBZ_MASK_NX 0x7ff0000000000080 +%define X86_PDE_PAE_MBZ_MASK_NO_NX 0xfff0000000000080 +%define X86_PDE_LM_MBZ_MASK_NX 0x0000000000000080 +%define X86_PDE_LM_MBZ_MASK_NO_NX 0x8000000000000080 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PDE4M_P RT_BIT_32(0) +%define X86_PDE4M_RW RT_BIT_32(1) +%define X86_PDE4M_US RT_BIT_32(2) +%define X86_PDE4M_PWT RT_BIT_32(3) +%define X86_PDE4M_PCD RT_BIT_32(4) +%define X86_PDE4M_A RT_BIT_32(5) +%define X86_PDE4M_D RT_BIT_32(6) +%define X86_PDE4M_PS RT_BIT_32(7) +%define X86_PDE4M_G RT_BIT_32(8) +%define X86_PDE4M_AVL (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PDE4M_PAT RT_BIT_32(12) +%define X86_PDE4M_PAT_SHIFT (12 - 7) +%define X86_PDE4M_PG_MASK ( 0xffc00000 ) +%define X86_PDE4M_PG_HIGH_MASK ( 0x001fe000 ) +%define X86_PDE4M_PG_HIGH_SHIFT 19 +%define X86_PDE4M_MBZ_MASK RT_BIT_32(21) +%define X86_PDE2M_PAE_PG_MASK 0x000fffffffe00000 +%define X86_PDE2M_PAE_NX RT_BIT_64(63) +%define X86_PDE2M_PAE_MBZ_MASK_NX 0x7ff00000001fe000 +%define X86_PDE2M_PAE_MBZ_MASK_NO_NX 0xfff00000001fe000 +%define X86_PDE2M_LM_MBZ_MASK_NX 0x00000000001fe000 +%define X86_PDE2M_LM_MBZ_MASK_NO_NX 0x80000000001fe000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PD_SHIFT 22 +%define X86_PD_MASK 0x3ff +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PD_PAE_SHIFT 21 +%define X86_PD_PAE_MASK 0x1ff +%define X86_PDPE_P RT_BIT_32(0) +%define X86_PDPE_RW RT_BIT_32(1) +%define X86_PDPE_US RT_BIT_32(2) +%define X86_PDPE_PWT RT_BIT_32(3) +%define X86_PDPE_PCD RT_BIT_32(4) +%define X86_PDPE_A RT_BIT_32(5) +%define X86_PDPE_LM_PS RT_BIT_32(7) +%define X86_PDPE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PDPE_PG_MASK 0x000ffffffffff000 +%define X86_PDPE1G_PG_MASK 0x000fffffc0000000 +%define X86_PDPE_PAE_MBZ_MASK 0xfff00000000001e6 +%define X86_PDPE_LM_NX RT_BIT_64(63) +%define X86_PDPE_LM_MBZ_MASK_NX 0x0000000000000180 +%define X86_PDPE_LM_MBZ_MASK_NO_NX 0x8000000000000180 +%define X86_PDPE1G_LM_MBZ_MASK_NX 0x000000003fffe000 +%define X86_PDPE1G_LM_MBZ_MASK_NO_NX 0x800000003fffe000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PDPT_SHIFT 30 +%define X86_PDPT_MASK_PAE 0x3 +%define X86_PDPT_MASK_AMD64 0x1ff +%define X86_PML4E_P RT_BIT_32(0) +%define X86_PML4E_RW RT_BIT_32(1) +%define X86_PML4E_US RT_BIT_32(2) +%define X86_PML4E_PWT RT_BIT_32(3) +%define X86_PML4E_PCD RT_BIT_32(4) +%define X86_PML4E_A RT_BIT_32(5) +%define X86_PML4E_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PML4E_PG_MASK 0x000ffffffffff000 +%define X86_PML4E_MBZ_MASK_NX 0x0000000000000080 +%define X86_PML4E_MBZ_MASK_NO_NX 0x8000000000000080 +%define X86_PML4E_NX RT_BIT_64(63) +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PML4_SHIFT 39 +%define X86_PML4_MASK 0x1ff +%define X86_INVPCID_TYPE_INDV_ADDR 0 +%define X86_INVPCID_TYPE_SINGLE_CONTEXT 1 +%define X86_INVPCID_TYPE_ALL_CONTEXT_INCL_GLOBAL 2 +%define X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL 3 +%define X86_INVPCID_TYPE_MAX_VALID X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL +%define X86_FPU_INT64_INDEFINITE INT64_MIN +%define X86_FPU_INT32_INDEFINITE INT32_MIN +%define X86_FPU_INT16_INDEFINITE INT16_MIN +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_OFF_FXSTATE_RSVD 0x1d0 +%define X86_FXSTATE_RSVD_32BIT_MAGIC 0x32b3232b +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_FSW_IE RT_BIT_32(0) +%define X86_FSW_IE_BIT 0 +%define X86_FSW_DE RT_BIT_32(1) +%define X86_FSW_DE_BIT 1 +%define X86_FSW_ZE RT_BIT_32(2) +%define X86_FSW_ZE_BIT 2 +%define X86_FSW_OE RT_BIT_32(3) +%define X86_FSW_OE_BIT 3 +%define X86_FSW_UE RT_BIT_32(4) +%define X86_FSW_UE_BIT 4 +%define X86_FSW_PE RT_BIT_32(5) +%define X86_FSW_PE_BIT 5 +%define X86_FSW_SF RT_BIT_32(6) +%define X86_FSW_SF_BIT 6 +%define X86_FSW_ES RT_BIT_32(7) +%define X86_FSW_ES_BIT 7 +%define X86_FSW_XCPT_MASK 0x007f +%define X86_FSW_XCPT_ES_MASK 0x00ff +%define X86_FSW_C0 RT_BIT_32(X86_FSW_C0_BIT) +%define X86_FSW_C0_BIT 8 +%define X86_FSW_C1 RT_BIT_32(X86_FSW_C1_BIT) +%define X86_FSW_C1_BIT 9 +%define X86_FSW_C2 RT_BIT_32(X86_FSW_C2_BIT) +%define X86_FSW_C2_BIT 10 +%define X86_FSW_TOP_MASK 0x3800 +%define X86_FSW_TOP_SHIFT 11 +%define X86_FSW_TOP_SMASK 0x0007 +%define X86_FSW_TOP_GET(a_uFsw) (((a_uFsw) >> X86_FSW_TOP_SHIFT) & X86_FSW_TOP_SMASK) +%define X86_FSW_TOP_GET_ST(a_uFsw, a_iSt) ((((a_uFsw) >> X86_FSW_TOP_SHIFT) + (a_iSt)) & X86_FSW_TOP_SMASK) +%define X86_FSW_C3 RT_BIT_32(X86_FSW_C3_BIT) +%define X86_FSW_C3_BIT 14 +%define X86_FSW_C_MASK 0x4700 +%define X86_FSW_B RT_BIT_32(15) +%define X86_FSW_CX_TO_QUOTIENT(a_fFsw) \ + ( (((a_fFsw) & X86_FSW_C1) >> (X86_FSW_C1_BIT - 0)) \ + | (((a_fFsw) & X86_FSW_C3) >> (X86_FSW_C3_BIT - 1)) \ + | (((a_fFsw) & X86_FSW_C0) >> (X86_FSW_C0_BIT - 2)) ) +%define X86_FSW_CX_FROM_QUOTIENT(a_uQuotient) \ + ( ((uint16_t)((a_uQuotient) & 1) << (X86_FSW_C1_BIT - 0)) \ + | ((uint16_t)((a_uQuotient) & 2) << (X86_FSW_C3_BIT - 1)) \ + | ((uint16_t)((a_uQuotient) & 4) << (X86_FSW_C0_BIT - 2)) ) +%define X86_FCW_IM RT_BIT_32(0) +%define X86_FCW_IM_BIT 0 +%define X86_FCW_DM RT_BIT_32(1) +%define X86_FCW_DM_BIT 1 +%define X86_FCW_ZM RT_BIT_32(2) +%define X86_FCW_ZM_BIT 2 +%define X86_FCW_OM RT_BIT_32(3) +%define X86_FCW_OM_BIT 3 +%define X86_FCW_UM RT_BIT_32(4) +%define X86_FCW_UM_BIT 4 +%define X86_FCW_PM RT_BIT_32(5) +%define X86_FCW_PM_BIT 5 +%define X86_FCW_MASK_ALL 0x007f +%define X86_FCW_XCPT_MASK 0x003f +%define X86_FCW_PC_MASK 0x0300 +%define X86_FCW_PC_SHIFT 8 +%define X86_FCW_PC_24 0x0000 +%define X86_FCW_PC_RSVD 0x0100 +%define X86_FCW_PC_53 0x0200 +%define X86_FCW_PC_64 0x0300 +%define X86_FCW_RC_MASK 0x0c00 +%define X86_FCW_RC_SHIFT 10 +%define X86_FCW_RC_NEAREST 0x0000 +%define X86_FCW_RC_DOWN 0x0400 +%define X86_FCW_RC_UP 0x0800 +%define X86_FCW_RC_ZERO 0x0c00 +%define X86_FCW_IC_MASK 0x1000 +%define X86_FCW_IC_AFFINE 0x1000 +%define X86_FCW_IC_PROJECTIVE 0x0000 +%define X86_FCW_ZERO_MASK 0xf080 +%define X86_MXCSR_IE RT_BIT_32(0) +%define X86_MXCSR_DE RT_BIT_32(1) +%define X86_MXCSR_ZE RT_BIT_32(2) +%define X86_MXCSR_OE RT_BIT_32(3) +%define X86_MXCSR_UE RT_BIT_32(4) +%define X86_MXCSR_PE RT_BIT_32(5) +%define X86_MXCSR_XCPT_FLAGS 0x003f +%define X86_MXCSR_DAZ RT_BIT_32(6) +%define X86_MXCSR_IM RT_BIT_32(7) +%define X86_MXCSR_DM RT_BIT_32(8) +%define X86_MXCSR_ZM RT_BIT_32(9) +%define X86_MXCSR_OM RT_BIT_32(10) +%define X86_MXCSR_UM RT_BIT_32(11) +%define X86_MXCSR_PM RT_BIT_32(12) +%define X86_MXCSR_XCPT_MASK 0x1f80 +%define X86_MXCSR_XCPT_MASK_SHIFT 7 +%define X86_MXCSR_RC_MASK 0x6000 +%define X86_MXCSR_RC_SHIFT 13 +%define X86_MXCSR_RC_NEAREST 0x0000 +%define X86_MXCSR_RC_DOWN 0x2000 +%define X86_MXCSR_RC_UP 0x4000 +%define X86_MXCSR_RC_ZERO 0x6000 +%define X86_MXCSR_FZ RT_BIT_32(15) +%define X86_MXCSR_MM RT_BIT_32(17) +%define X86_MXCSR_ZERO_MASK 0xfffd0000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define XSAVE_C_X87_BIT 0 +%define XSAVE_C_X87 RT_BIT_64(XSAVE_C_X87_BIT) +%define XSAVE_C_SSE_BIT 1 +%define XSAVE_C_SSE RT_BIT_64(XSAVE_C_SSE_BIT) +%define XSAVE_C_YMM_BIT 2 +%define XSAVE_C_YMM RT_BIT_64(XSAVE_C_YMM_BIT) +%define XSAVE_C_BNDREGS_BIT 3 +%define XSAVE_C_BNDREGS RT_BIT_64(XSAVE_C_BNDREGS_BIT) +%define XSAVE_C_BNDCSR_BIT 4 +%define XSAVE_C_BNDCSR RT_BIT_64(XSAVE_C_BNDCSR_BIT) +%define XSAVE_C_OPMASK_BIT 5 +%define XSAVE_C_OPMASK RT_BIT_64(XSAVE_C_OPMASK_BIT) +%define XSAVE_C_ZMM_HI256_BIT 6 +%define XSAVE_C_ZMM_HI256 RT_BIT_64(XSAVE_C_ZMM_HI256_BIT) +%define XSAVE_C_ZMM_16HI_BIT 7 +%define XSAVE_C_ZMM_16HI RT_BIT_64(XSAVE_C_ZMM_16HI_BIT) +%define XSAVE_C_PKRU_BIT 9 +%define XSAVE_C_PKRU RT_BIT_64(XSAVE_C_PKRU_BIT) +%define XSAVE_C_LWP_BIT 62 +%define XSAVE_C_LWP RT_BIT_64(XSAVE_C_LWP_BIT) +%define XSAVE_C_X_BIT 63 +%define XSAVE_C_X RT_BIT_64(XSAVE_C_X_BIT) +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86DESCATTR_TYPE 0x0000000f +%define X86DESCATTR_DT 0x00000010 +%define X86DESCATTR_DPL 0x00000060 +%define X86DESCATTR_DPL_SHIFT 5 +%define X86DESCATTR_P 0x00000080 +%define X86DESCATTR_LIMIT_HIGH 0x00000f00 +%define X86DESCATTR_AVL 0x00001000 +%define X86DESCATTR_L 0x00002000 +%define X86DESCATTR_D 0x00004000 +%define X86DESCATTR_G 0x00008000 +%define X86DESCATTR_UNUSABLE 0x00010000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%define X86DESCGENERIC_BIT_OFF_LIMIT_LOW (0) +%define X86DESCGENERIC_BIT_OFF_BASE_LOW (16) +%define X86DESCGENERIC_BIT_OFF_BASE_HIGH1 (32) +%define X86DESCGENERIC_BIT_OFF_TYPE (40) +%define X86DESCGENERIC_BIT_OFF_DESC_TYPE (44) +%define X86DESCGENERIC_BIT_OFF_DPL (45) +%define X86DESCGENERIC_BIT_OFF_PRESENT (47) +%define X86DESCGENERIC_BIT_OFF_LIMIT_HIGH (48) +%define X86DESCGENERIC_BIT_OFF_AVAILABLE (52) +%define X86DESCGENERIC_BIT_OFF_LONG (53) +%define X86DESCGENERIC_BIT_OFF_DEF_BIG (54) +%define X86DESCGENERIC_BIT_OFF_GRANULARITY (55) +%define X86DESCGENERIC_BIT_OFF_BASE_HIGH2 (56) +%define X86LAR_F_TYPE 0x0f00 +%define X86LAR_F_DT 0x1000 +%define X86LAR_F_DPL 0x6000 +%define X86LAR_F_DPL_SHIFT 13 +%define X86LAR_F_P 0x8000 +%define X86LAR_F_AVL 0x00100000 +%define X86LAR_F_L 0x00200000 +%define X86LAR_F_D 0x00400000 +%define X86LAR_F_G 0x00800000 +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%if HC_ARCH_BITS == 64 +%else +%endif +%if HC_ARCH_BITS == 64 +%else +%endif +%if HC_ARCH_BITS == 64 +%else +%endif +%define X86_SEL_TYPE_CODE 8 +%define X86_SEL_TYPE_MEMORY RT_BIT_32(4) +%define X86_SEL_TYPE_ACCESSED 1 +%define X86_SEL_TYPE_DOWN 4 +%define X86_SEL_TYPE_CONF 4 +%define X86_SEL_TYPE_WRITE 2 +%define X86_SEL_TYPE_READ 2 +%define X86_SEL_TYPE_READ_BIT 1 +%define X86_SEL_TYPE_RO 0 +%define X86_SEL_TYPE_RO_ACC (0 | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_RW 2 +%define X86_SEL_TYPE_RW_ACC (2 | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_RO_DOWN 4 +%define X86_SEL_TYPE_RO_DOWN_ACC (4 | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_RW_DOWN 6 +%define X86_SEL_TYPE_RW_DOWN_ACC (6 | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_EO (0 | X86_SEL_TYPE_CODE) +%define X86_SEL_TYPE_EO_ACC (0 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_ER (2 | X86_SEL_TYPE_CODE) +%define X86_SEL_TYPE_ER_ACC (2 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_EO_CONF (4 | X86_SEL_TYPE_CODE) +%define X86_SEL_TYPE_EO_CONF_ACC (4 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_ER_CONF (6 | X86_SEL_TYPE_CODE) +%define X86_SEL_TYPE_ER_CONF_ACC (6 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_SYS_TSS_BUSY_MASK 2 +%define X86_SEL_TYPE_SYS_UNDEFINED 0 +%define X86_SEL_TYPE_SYS_286_TSS_AVAIL 1 +%define X86_SEL_TYPE_SYS_LDT 2 +%define X86_SEL_TYPE_SYS_286_TSS_BUSY 3 +%define X86_SEL_TYPE_SYS_286_CALL_GATE 4 +%define X86_SEL_TYPE_SYS_TASK_GATE 5 +%define X86_SEL_TYPE_SYS_286_INT_GATE 6 +%define X86_SEL_TYPE_SYS_286_TRAP_GATE 7 +%define X86_SEL_TYPE_SYS_UNDEFINED2 8 +%define X86_SEL_TYPE_SYS_386_TSS_AVAIL 9 +%define X86_SEL_TYPE_SYS_UNDEFINED3 0xA +%define X86_SEL_TYPE_SYS_386_TSS_BUSY 0xB +%define X86_SEL_TYPE_SYS_386_CALL_GATE 0xC +%define X86_SEL_TYPE_SYS_UNDEFINED4 0xD +%define X86_SEL_TYPE_SYS_386_INT_GATE 0xE +%define X86_SEL_TYPE_SYS_386_TRAP_GATE 0xF +%define AMD64_SEL_TYPE_SYS_LDT 2 +%define AMD64_SEL_TYPE_SYS_TSS_AVAIL 9 +%define AMD64_SEL_TYPE_SYS_TSS_BUSY 0xB +%define AMD64_SEL_TYPE_SYS_CALL_GATE 0xC +%define AMD64_SEL_TYPE_SYS_INT_GATE 0xE +%define AMD64_SEL_TYPE_SYS_TRAP_GATE 0xF +%define X86_DESC_TYPE_MASK (RT_BIT_32(8) | RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_DESC_S RT_BIT_32(12) +%define X86_DESC_DPL (RT_BIT_32(13) | RT_BIT_32(14)) +%define X86_DESC_P RT_BIT_32(15) +%define X86_DESC_AVL RT_BIT_32(20) +%define X86_DESC_DB RT_BIT_32(22) +%define X86_DESC_G RT_BIT_32(23) +%define X86_SEL_TYPE_SYS_286_TSS_LIMIT_MIN 0x2b +%define X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN 0x67 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_SEL_SHIFT 3 +%define X86_SEL_MASK 0xfff8 +%define X86_SEL_MASK_OFF_RPL 0xfffc +%define X86_SEL_LDT 0x0004 +%define X86_SEL_RPL 0x0003 +%define X86_SEL_RPL_LDT 0x0007 +%define X86_XCPT_LAST 0x1f +%define X86_TRAP_ERR_EXTERNAL 1 +%define X86_TRAP_ERR_IDT 2 +%define X86_TRAP_ERR_TI 4 +%define X86_TRAP_ERR_SEL_MASK 0xfff8 +%define X86_TRAP_ERR_SEL_SHIFT 3 +%define X86_TRAP_PF_P RT_BIT_32(0) +%define X86_TRAP_PF_RW RT_BIT_32(1) +%define X86_TRAP_PF_US RT_BIT_32(2) +%define X86_TRAP_PF_RSVD RT_BIT_32(3) +%define X86_TRAP_PF_ID RT_BIT_32(4) +%define X86_TRAP_PF_PK RT_BIT_32(5) +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%define X86_MODRM_RM_MASK 0x07 +%define X86_MODRM_REG_MASK 0x38 +%define X86_MODRM_REG_SMASK 0x07 +%define X86_MODRM_REG_SHIFT 3 +%define X86_MODRM_MOD_MASK 0xc0 +%define X86_MODRM_MOD_SMASK 0x03 +%define X86_MODRM_MOD_SHIFT 6 +%ifndef VBOX_FOR_DTRACE_LIB + %define X86_MODRM_MAKE(a_Mod, a_Reg, a_RegMem) (((a_Mod) << X86_MODRM_MOD_SHIFT) | ((a_Reg) << X86_MODRM_REG_SHIFT) | (a_RegMem)) +%endif +%define X86_SIB_BASE_MASK 0x07 +%define X86_SIB_INDEX_MASK 0x38 +%define X86_SIB_INDEX_SMASK 0x07 +%define X86_SIB_INDEX_SHIFT 3 +%define X86_SIB_SCALE_MASK 0xc0 +%define X86_SIB_SCALE_SMASK 0x03 +%define X86_SIB_SCALE_SHIFT 6 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_GREG_xAX 0 +%define X86_GREG_xCX 1 +%define X86_GREG_xDX 2 +%define X86_GREG_xBX 3 +%define X86_GREG_xSP 4 +%define X86_GREG_xBP 5 +%define X86_GREG_xSI 6 +%define X86_GREG_xDI 7 +%define X86_GREG_x8 8 +%define X86_GREG_x9 9 +%define X86_GREG_x10 10 +%define X86_GREG_x11 11 +%define X86_GREG_x12 12 +%define X86_GREG_x13 13 +%define X86_GREG_x14 14 +%define X86_GREG_x15 15 +%define X86_GREG_COUNT 16 +%define X86_SREG_ES 0 +%define X86_SREG_CS 1 +%define X86_SREG_SS 2 +%define X86_SREG_DS 3 +%define X86_SREG_FS 4 +%define X86_SREG_GS 5 +%define X86_SREG_COUNT 6 +%define X86_OP_PRF_CS 0x2e +%define X86_OP_PRF_SS 0x36 +%define X86_OP_PRF_DS 0x3e +%define X86_OP_PRF_ES 0x26 +%define X86_OP_PRF_FS 0x64 +%define X86_OP_PRF_GS 0x65 +%define X86_OP_PRF_SIZE_OP 0x66 +%define X86_OP_PRF_SIZE_ADDR 0x67 +%define X86_OP_PRF_LOCK 0xf0 +%define X86_OP_PRF_REPZ 0xf3 +%define X86_OP_PRF_REPNZ 0xf2 +%define X86_OP_REX_B 0x41 +%define X86_OP_REX_X 0x42 +%define X86_OP_REX_R 0x44 +%define X86_OP_REX_W 0x48 +%endif +%include "iprt/x86extra.mac" diff --git a/include/iprt/x86extra.mac b/include/iprt/x86extra.mac new file mode 100644 index 00000000..44986e95 --- /dev/null +++ b/include/iprt/x86extra.mac @@ -0,0 +1,225 @@ +;; @file +; IPRT - X86 and AMD64 Structures and Definitions that are not automatically +; converted from the C header file. +; + +; +; Copyright (C) 2012-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_x86extra_mac +%define ___iprt_x86extra_mac + + +%define X86_XCPT_DE 0x00 +%define X86_XCPT_DB 0x01 +%define X86_XCPT_NMI 0x02 +%define X86_XCPT_BP 0x03 +%define X86_XCPT_OF 0x04 +%define X86_XCPT_BR 0x05 +%define X86_XCPT_UD 0x06 +%define X86_XCPT_NM 0x07 +%define X86_XCPT_DF 0x08 +%define X86_XCPT_CO_SEG_OVERRUN 0x09 +%define X86_XCPT_TS 0x0a +%define X86_XCPT_NP 0x0b +%define X86_XCPT_SS 0x0c +%define X86_XCPT_GP 0x0d +%define X86_XCPT_PF 0x0e +%define X86_XCPT_MF 0x10 +%define X86_XCPT_AC 0x11 +%define X86_XCPT_MC 0x12 +%define X86_XCPT_XF 0x13 +%define X86_XCPT_VE 0x14 +%define X86_XCPT_SX 0x1f + +%define PAGE_SIZE 0x1000 + +;; Same a ~(X86_CR0_PE | X86_CR0_PG) except it won't cause assembler warnings. +%define X86_CR0_NO_PE_NO_PG 0x7ffffffe + + + +;; +; 32-bit protected mode fstenv image. +; +struc X86FSTENV32P + .FCW resw 1 + .padding1 resw 1 + .FSW resw 1 + .padding2 resw 1 + .FTW resw 1 + .padding3 resw 1 + .FPUIP resd 1 + .FPUCS resw 1 + .FOP resw 1 + .FPUDP resd 1 + .FPUDS resw 1 + .padding4 resw 1 +endstruc + + +;; +; The image saved by FXSAVE. +; +struc X86FXSTATE + .FCW resw 1 + .FSW resw 1 + .FTW resw 1 + .FOP resw 1 + .FPUIP resd 1 + .FPUCS resw 1 + .Rsrvd1 resw 1 + .FPUDP resd 1 + .FPUDS resw 1 + .Rsrvd2 resw 1 + .MXCSR resd 1 + .MXCSR_MASK resd 1 + .st0 resd 4 + .st1 resd 4 + .st2 resd 4 + .st3 resd 4 + .st4 resd 4 + .st5 resd 4 + .st6 resd 4 + .st7 resd 4 + .xmm0 resd 4 + .xmm1 resd 4 + .xmm2 resd 4 + .xmm3 resd 4 + .xmm4 resd 4 + .xmm5 resd 4 + .xmm6 resd 4 + .xmm7 resd 4 + .xmm8 resd 4 + .xmm9 resd 4 + .xmm10 resd 4 + .xmm11 resd 4 + .xmm12 resd 4 + .xmm13 resd 4 + .xmm14 resd 4 + .xmm15 resd 4 + .au32RsrvdRest resd 24 +endstruc + + +struc X86TSS16 + .selPrev resw 1 + .sp0 resw 1 + .ss0 resw 1 + .sp1 resw 1 + .ss1 resw 1 + .sp2 resw 1 + .ss2 resw 1 + .ip resw 1 + .flags resw 1 + .ax resw 1 + .cx resw 1 + .dx resw 1 + .bx resw 1 + .sp resw 1 + .bp resw 1 + .si resw 1 + .di resw 1 + .es resw 1 + .cs resw 1 + .ss resw 1 + .ds resw 1 + .selLdt resw 1 +endstruc +AssertCompileSize(X86TSS16, 44) + + +struc X86TSS32 + .selPrev resw 1 + .padding1 resw 1 + .esp0 resd 1 + .ss0 resw 1 + .padding_ss0 resw 1 + .esp1 resd 1 + .ss1 resw 1 + .padding_ss1 resw 1 + .esp2 resd 1 + .ss2 resw 1 + .padding_ss2 resw 1 + .cr3 resd 1 + .eip resd 1 + .eflags resd 1 + .eax resd 1 + .ecx resd 1 + .edx resd 1 + .ebx resd 1 + .esp resd 1 + .ebp resd 1 + .esi resd 1 + .edi resd 1 + .es resw 1 + .padding_es resw 1 + .cs resw 1 + .padding_cs resw 1 + .ss resw 1 + .padding_ss resw 1 + .ds resw 1 + .padding_ds resw 1 + .fs resw 1 + .padding_fs resw 1 + .gs resw 1 + .padding_gs resw 1 + .selLdt resw 1 + .padding_ldt resw 1 + .fDebugTrap resw 1 + .offIoBitmap resw 1 + ;.IntRedirBitmap resb 32 - this is optional. +endstruc +AssertCompileSize(X86TSS32,104) + + +struc X86TSS64 + .u32Reserved resd 1 + .rsp0 resq 1 + .rsp1 resq 1 + .rsp2 resq 1 + .u32Reserved2 resd 2 + .ist1 resq 1 + .ist2 resq 1 + .ist3 resq 1 + .ist4 resq 1 + .ist5 resq 1 + .ist6 resq 1 + .ist7 resq 1 + .u16Reserved resw 5 + .offIoBitmap resw 1 + ;.IntRedirBitmap resb 32 - this isn't really there!! VBox addition for x86TSS32 structure compatibility in x86.h. +endstruc +AssertCompileSize(X86TSS64, 104) + + +%endif + diff --git a/include/iprt/zero.h b/include/iprt/zero.h new file mode 100644 index 00000000..75dd3041 --- /dev/null +++ b/include/iprt/zero.h @@ -0,0 +1,67 @@ +/** @file + * IPRT - Zero Memory. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_zero_h +#define IPRT_INCLUDED_zero_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_zero RTZero - Zeroed Memory Objects + * @ingroup grp_rt + * @{ + */ + +extern RTDATADECL(uint8_t const) g_abRTZeroPage[PAGE_SIZE]; +extern RTDATADECL(uint8_t const) g_abRTZero4K[_4K]; +extern RTDATADECL(uint8_t const) g_abRTZero8K[_8K]; +extern RTDATADECL(uint8_t const) g_abRTZero16K[_16K]; +extern RTDATADECL(uint8_t const) g_abRTZero32K[_32K]; +extern RTDATADECL(uint8_t const) g_abRTZero64K[_64K]; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_zero_h */ + diff --git a/include/iprt/zip.h b/include/iprt/zip.h new file mode 100644 index 00000000..4dc1ee19 --- /dev/null +++ b/include/iprt/zip.h @@ -0,0 +1,533 @@ +/** @file + * IPRT - Compression. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_zip_h +#define IPRT_INCLUDED_zip_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_zip RTZip - Compression + * @ingroup grp_rt + * @{ + */ + + + +/** + * Callback function for consuming compressed data during compression. + * + * @returns iprt status code. + * @param pvUser User argument. + * @param pvBuf Compressed data. + * @param cbBuf Size of the compressed data. + */ +typedef DECLCALLBACKTYPE(int, FNRTZIPOUT,(void *pvUser, const void *pvBuf, size_t cbBuf)); +/** Pointer to FNRTZIPOUT() function. */ +typedef FNRTZIPOUT *PFNRTZIPOUT; + +/** + * Callback function for supplying compressed data during decompression. + * + * @returns iprt status code. + * @param pvUser User argument. + * @param pvBuf Where to store the compressed data. + * @param cbBuf Size of the buffer. + * @param pcbBuf Number of bytes actually stored in the buffer. + */ +typedef DECLCALLBACKTYPE(int, FNRTZIPIN,(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbBuf)); +/** Pointer to FNRTZIPIN() function. */ +typedef FNRTZIPIN *PFNRTZIPIN; + +/** + * Compression type. + * (Be careful with these they are stored in files!) + */ +typedef enum RTZIPTYPE +{ + /** Invalid. */ + RTZIPTYPE_INVALID = 0, + /** Choose best fitting one. */ + RTZIPTYPE_AUTO, + /** Store the data. */ + RTZIPTYPE_STORE, + /** Zlib compression the data. */ + RTZIPTYPE_ZLIB, + /** BZlib compress. */ + RTZIPTYPE_BZLIB, + /** libLZF compress. */ + RTZIPTYPE_LZF, + /** Lempel-Ziv-Jeff-Bonwick compression. */ + RTZIPTYPE_LZJB, + /** Lempel-Ziv-Oberhumer compression. */ + RTZIPTYPE_LZO, + /* Zlib compression the data without zlib header. */ + RTZIPTYPE_ZLIB_NO_HEADER, + /** End of valid the valid compression types. */ + RTZIPTYPE_END +} RTZIPTYPE; + +/** + * Compression level. + */ +typedef enum RTZIPLEVEL +{ + /** Store, don't compress. */ + RTZIPLEVEL_STORE = 0, + /** Fast compression. */ + RTZIPLEVEL_FAST, + /** Default compression. */ + RTZIPLEVEL_DEFAULT, + /** Maximal compression. */ + RTZIPLEVEL_MAX +} RTZIPLEVEL; + + +/** + * Create a stream compressor instance. + * + * @returns iprt status code. + * @param ppZip Where to store the instance handle. + * @param pvUser User argument which will be passed on to pfnOut and pfnIn. + * @param pfnOut Callback for consuming output of compression. + * @param enmType Type of compressor to create. + * @param enmLevel Compression level. + */ +RTDECL(int) RTZipCompCreate(PRTZIPCOMP *ppZip, void *pvUser, PFNRTZIPOUT pfnOut, RTZIPTYPE enmType, RTZIPLEVEL enmLevel); + +/** + * Compresses a chunk of memory. + * + * @returns iprt status code. + * @param pZip The compressor instance. + * @param pvBuf Pointer to buffer containing the bits to compress. + * @param cbBuf Number of bytes to compress. + */ +RTDECL(int) RTZipCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf); + +/** + * Finishes the compression. + * This will flush all data and terminate the compression data stream. + * + * @returns iprt status code. + * @param pZip The stream compressor instance. + */ +RTDECL(int) RTZipCompFinish(PRTZIPCOMP pZip); + +/** + * Destroys the stream compressor instance. + * + * @returns iprt status code. + * @param pZip The compressor instance. + */ +RTDECL(int) RTZipCompDestroy(PRTZIPCOMP pZip); + + +/** + * Create a stream decompressor instance. + * + * @returns iprt status code. + * @param ppZip Where to store the instance handle. + * @param pvUser User argument which will be passed on to pfnOut and pfnIn. + * @param pfnIn Callback for producing input for decompression. + */ +RTDECL(int) RTZipDecompCreate(PRTZIPDECOMP *ppZip, void *pvUser, PFNRTZIPIN pfnIn); + +/** + * Decompresses a chunk of memory. + * + * @returns iprt status code. + * @param pZip The stream decompressor instance. + * @param pvBuf Where to store the decompressed data. + * @param cbBuf Number of bytes to produce. If pcbWritten is set + * any number of bytes up to cbBuf might be returned. + * @param pcbWritten Number of bytes actually written to the buffer. If NULL + * cbBuf number of bytes must be written. + */ +RTDECL(int) RTZipDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten); + +/** + * Destroys the stream decompressor instance. + * + * @returns iprt status code. + * @param pZip The decompressor instance. + */ +RTDECL(int) RTZipDecompDestroy(PRTZIPDECOMP pZip); + + +/** + * Compress a chunk of memory into a block. + * + * @returns IPRT status code. + * + * @param enmType The compression type. + * @param enmLevel The compression level. + * @param fFlags Flags reserved for future extensions, MBZ. + * @param pvSrc Pointer to the input block. + * @param cbSrc Size of the input block. + * @param pvDst Pointer to the output buffer. + * @param cbDst The size of the output buffer. + * @param pcbDstActual Where to return the compressed size. + */ +RTDECL(int) RTZipBlockCompress(RTZIPTYPE enmType, RTZIPLEVEL enmLevel, uint32_t fFlags, + void const *pvSrc, size_t cbSrc, + void *pvDst, size_t cbDst, size_t *pcbDstActual) RT_NO_THROW_PROTO; + + +/** + * Decompress a block. + * + * @returns IPRT status code. + * + * @param enmType The compression type. + * @param fFlags Flags reserved for future extensions, MBZ. + * @param pvSrc Pointer to the input block. + * @param cbSrc Size of the input block. + * @param pcbSrcActual Where to return the compressed size. + * @param pvDst Pointer to the output buffer. + * @param cbDst The size of the output buffer. + * @param pcbDstActual Where to return the decompressed size. + */ +RTDECL(int) RTZipBlockDecompress(RTZIPTYPE enmType, uint32_t fFlags, + void const *pvSrc, size_t cbSrc, size_t *pcbSrcActual, + void *pvDst, size_t cbDst, size_t *pcbDstActual) RT_NO_THROW_PROTO; + + +/** + * Opens a gzip decompression I/O stream. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The compressed input stream (must be readable). + * The reference is not consumed, instead another + * one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsIosGunzip Where to return the handle to the gunzipped I/O + * stream (read). + */ +RTDECL(int) RTZipGzipDecompressIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSIOSTREAM phVfsIosGunzip); + +/** @name RTZipGzipDecompressIoStream flags. + * @{ */ +/** Allow the smaller ZLIB header as well as the regular GZIP header. */ +#define RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR RT_BIT(0) +/** @} */ + + +/** + * Opens a gzip decompression I/O stream. + * + * @returns IPRT status code. + * + * @param hVfsIosDst The compressed output stream (must be writable). + * The reference is not consumed, instead another + * one is retained. + * @param fFlags Flags, MBZ. + * @param uLevel The gzip compression level, 1 thru 9. + * @param phVfsIosGzip Where to return the gzip input I/O stream handle + * (you write to this). + */ +RTDECL(int) RTZipGzipCompressIoStream(RTVFSIOSTREAM hVfsIosDst, uint32_t fFlags, uint8_t uLevel, PRTVFSIOSTREAM phVfsIosGzip); + +/** + * A mini GZIP program. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTDECL(RTEXITCODE) RTZipGzipCmd(unsigned cArgs, char **papszArgs); + +/** + * Opens a TAR filesystem stream. + * + * This is used to extract, list or check a TAR archive. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The input stream. The reference is not + * consumed, instead another one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsFss Where to return the handle to the TAR + * filesystem stream. + */ +RTDECL(int) RTZipTarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** TAR format type. */ +typedef enum RTZIPTARFORMAT +{ + /** Customary invalid zero value. */ + RTZIPTARFORMAT_INVALID = 0, + /** Default format (GNU). */ + RTZIPTARFORMAT_DEFAULT, + /** The GNU format. */ + RTZIPTARFORMAT_GNU, + /** USTAR format from POSIX.1-1988. */ + RTZIPTARFORMAT_USTAR, + /** PAX format from POSIX.1-2001. */ + RTZIPTARFORMAT_PAX, + /** End of valid formats. */ + RTZIPTARFORMAT_END, + /** Make sure the type is at least 32 bits wide. */ + RTZIPTARFORMAT_32BIT_HACK = 0x7fffffff +} RTZIPTARFORMAT; + +/** + * Opens a TAR filesystem stream for the purpose of create a new TAR archive. + * + * @returns IPRT status code. + * + * @param hVfsIosOut The output stream, i.e. where the tar stuff is + * written. The reference is not consumed, instead + * another one is retained. + * @param enmFormat The desired output format. + * @param fFlags RTZIPTAR_C_XXX, except RTZIPTAR_C_UPDATE. + * @param phVfsFss Where to return the handle to the TAR + * filesystem stream. + */ +RTDECL(int) RTZipTarFsStreamToIoStream(RTVFSIOSTREAM hVfsIosOut, RTZIPTARFORMAT enmFormat, + uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** @name RTZIPTAR_C_XXX - TAR creation flags (RTZipTarFsStreamToIoStream). + * @{ */ +/** Check for sparse files. + * @note Only supported when adding file objects. The files will be read + * twice. */ +#define RTZIPTAR_C_SPARSE RT_BIT_32(0) +/** Set if opening for updating. */ +#define RTZIPTAR_C_UPDATE RT_BIT_32(1) +/** Valid bits. */ +#define RTZIPTAR_C_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Opens a TAR filesystem stream for the purpose of create a new TAR archive or + * updating an existing one. + * + * @returns IPRT status code. + * + * @param hVfsFile The TAR file handle, i.e. where the tar stuff is + * written and optionally read/update. The + * reference is not consumed, instead another one + * is retained. + * @param enmFormat The desired output format. + * @param fFlags RTZIPTAR_C_XXX. + * @param phVfsFss Where to return the handle to the TAR + * filesystem stream. + */ +RTDECL(int) RTZipTarFsStreamForFile(RTVFSFILE hVfsFile, RTZIPTARFORMAT enmFormat, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** + * Set the owner to store the archive entries with. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param uid The UID value to set. Passing NIL_RTUID makes + * it use the value found in RTFSOBJINFO. + * @param pszOwner The owner name to store. Passing NULL makes it + * use the value found in RTFSOBJINFO. + */ +RTDECL(int) RTZipTarFsStreamSetOwner(RTVFSFSSTREAM hVfsFss, RTUID uid, const char *pszOwner); + +/** + * Set the group to store the archive entries with. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param gid The GID value to set. Passing NIL_RTUID makes + * it use the value found in RTFSOBJINFO. + * @param pszGroup The group name to store. Passing NULL makes it + * use the value found in RTFSOBJINFO. + */ +RTDECL(int) RTZipTarFsStreamSetGroup(RTVFSFSSTREAM hVfsFss, RTGID gid, const char *pszGroup); + +/** + * Set path prefix to store the archive entries with. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param pszPrefix The path prefix to join the names with. Pass + * NULL for no prefix. + */ +RTDECL(int) RTZipTarFsStreamSetPrefix(RTVFSFSSTREAM hVfsFss, const char *pszPrefix); + +/** + * Set the AND and OR masks to apply to file (non-dir) modes in the archive. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param fAndMode The bits to keep + * @param fOrMode The bits to set. + */ +RTDECL(int) RTZipTarFsStreamSetFileMode(RTVFSFSSTREAM hVfsFss, RTFMODE fAndMode, RTFMODE fOrMode); + +/** + * Set the AND and OR masks to apply to directory modes in the archive. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param fAndMode The bits to keep + * @param fOrMode The bits to set. + */ +RTDECL(int) RTZipTarFsStreamSetDirMode(RTVFSFSSTREAM hVfsFss, RTFMODE fAndMode, RTFMODE fOrMode); + +/** + * Set the modification time to store the archive entires with. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param pModificationTime The modification time to use. Pass NULL to use + * the value found in RTFSOBJINFO. + */ +RTDECL(int) RTZipTarFsStreamSetMTime(RTVFSFSSTREAM hVfsFss, PCRTTIMESPEC pModificationTime); + +/** + * Truncates a TAR creator stream in update mode. + * + * Use RTVfsFsStrmNext to examine the TAR stream and locate the cut-off point. + * + * After performing this call, the stream will be in write mode and + * RTVfsFsStrmNext will stop working (VERR_WRONG_ORDER). The RTVfsFsStrmAdd() + * and RTVfsFsStrmPushFile() can be used to add new object to the TAR file, + * starting at the trunction point. RTVfsFsStrmEnd() is used to finish the TAR + * file (this performs the actual file trunction). + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator in update mode. + * @param hVfsObj Object returned by RTVfsFsStrmNext that the + * trunction is relative to. This doesn't have to + * be the current stream object, it can be an + * earlier one too. + * @param fAfter If set, @a hVfsObj will remain in the update TAR + * file. If clear, @a hVfsObj will not be + * included. + */ +RTDECL(int) RTZipTarFsStreamTruncate(RTVFSFSSTREAM hVfsFss, RTVFSOBJ hVfsObj, bool fAfter); + +/** + * A mini TAR program. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs); + +/** + * Opens a ZIP filesystem stream. + * + * This is used to extract, list or check a ZIP archive. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The compressed input stream. The reference is + * not consumed, instead another one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsFss Where to return the handle to the TAR + * filesystem stream. + */ +RTDECL(int) RTZipPkzipFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** + * A mini UNZIP program. + * + * @returns Program exit code. + * @ + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTDECL(RTEXITCODE) RTZipUnzipCmd(unsigned cArgs, char **papszArgs); + +/** + * Helper for decompressing files of a ZIP file located in memory. + * + * @returns IPRT status code. + * + * @param ppvDst Where to store the pointer to the allocated + * buffer. To be freed with RTMemFree(). + * @param pcbDst Where to store the pointer to the size of the + * allocated buffer. + * @param pvSrc Pointer to the buffer containing the .zip file. + * @param cbSrc Size of the buffer containing the .zip file. + * @param pszObject Name of the object to extract. + */ +RTDECL(int) RTZipPkzipMemDecompress(void **ppvDst, size_t *pcbDst, const void *pvSrc, size_t cbSrc, const char *pszObject); + +/** + * Opens a XAR filesystem stream. + * + * This is used to extract, list or check a XAR archive. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The compressed input stream. The reference is + * not consumed, instead another one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsFss Where to return the handle to the XAR filesystem + * stream. + */ +RTDECL(int) RTZipXarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** + * Opens a CPIO filesystem stream. + * + * This is used to extract, list or check a CPIO archive. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The input stream. The reference is not + * consumed, instead another one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsFss Where to return the handle to the CPIO + * filesystem stream. + */ +RTDECL(int) RTZipCpioFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_zip_h */ + -- cgit v1.2.3