summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Runtime
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-master.tar.gz
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Runtime')
-rw-r--r--src/VBox/Runtime/.scm-settings2
-rw-r--r--src/VBox/Runtime/Makefile.kmk466
-rw-r--r--src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp2
-rw-r--r--src/VBox/Runtime/VBox/VBoxRTDeps.cpp4
-rw-r--r--src/VBox/Runtime/VBox/VBoxRTImp.def37
-rw-r--r--src/VBox/Runtime/VBox/dbus.cpp2
-rw-r--r--src/VBox/Runtime/VBox/errmsgvboxcom.xsl2
-rw-r--r--src/VBox/Runtime/VBox/log-vbox.cpp36
-rw-r--r--src/VBox/Runtime/VBox/logbackdoor.cpp2
-rw-r--r--src/VBox/Runtime/common/alloc/alloc.cpp2
-rw-r--r--src/VBox/Runtime/common/alloc/heapoffset.cpp2
-rw-r--r--src/VBox/Runtime/common/alloc/heapsimple.cpp2
-rw-r--r--src/VBox/Runtime/common/alloc/memcache.cpp28
-rw-r--r--src/VBox/Runtime/common/asm/ASMAtomicCmpXchgExU64.asm8
-rw-r--r--src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU64.asm4
-rw-r--r--src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU8.asm2
-rw-r--r--src/VBox/Runtime/common/asm/ASMAtomicReadU64.asm2
-rw-r--r--src/VBox/Runtime/common/asm/ASMAtomicUoAndU32.asm58
-rw-r--r--src/VBox/Runtime/common/asm/ASMAtomicUoAndU64.asm77
-rw-r--r--src/VBox/Runtime/common/asm/ASMAtomicUoOrU32.asm57
-rw-r--r--src/VBox/Runtime/common/asm/ASMAtomicUoOrU64.asm76
-rw-r--r--src/VBox/Runtime/common/asm/ASMCpuIdExSlow.asm137
-rw-r--r--src/VBox/Runtime/common/asm/ASMCpuId_Idx_ECX.asm116
-rw-r--r--src/VBox/Runtime/common/asm/ASMGetGDTR.asm52
-rw-r--r--src/VBox/Runtime/common/asm/ASMGetIDTR.asm (renamed from src/VBox/Runtime/win/amd64/ASMGetIDTR.asm)18
-rw-r--r--src/VBox/Runtime/common/asm/ASMGetLDTR.asm (renamed from src/VBox/Runtime/win/amd64/ASMGetGDTR.asm)18
-rw-r--r--src/VBox/Runtime/common/asm/ASMGetSegAttr.asm61
-rw-r--r--src/VBox/Runtime/common/asm/ASMGetTR.asm (renamed from src/VBox/Runtime/win/amd64/ASMGetTR.asm)3
-rw-r--r--src/VBox/Runtime/common/asm/ASMMultU64ByU32DivByU32.asm2
-rw-r--r--src/VBox/Runtime/common/asm/ASMNopPause.asm2
-rw-r--r--src/VBox/Runtime/common/asm/ASMRdMsrEx.asm84
-rw-r--r--src/VBox/Runtime/common/asm/ASMWrMsrEx.asm79
-rw-r--r--src/VBox/Runtime/common/asm/asm-fake.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/RTSha256Digest.cpp201
-rw-r--r--src/VBox/Runtime/common/checksum/adler32.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/crc32-zlib.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/crc32.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/crc64.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/ipv4.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/ipv6.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/manifest.cpp107
-rw-r--r--src/VBox/Runtime/common/checksum/manifest2.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/manifest3.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/md5.cpp8
-rw-r--r--src/VBox/Runtime/common/checksum/md5str.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/sha1.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/sha1str.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/sha256.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/sha256str.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/sha512.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/sha512str.cpp2
-rw-r--r--src/VBox/Runtime/common/dbg/dbg.cpp2
-rw-r--r--src/VBox/Runtime/common/dbg/dbgas.cpp180
-rw-r--r--src/VBox/Runtime/common/dbg/dbgcfg.cpp2172
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmod.cpp1276
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp2786
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmodcontainer.cpp186
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmoddbghelp.cpp502
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmoddeferred.cpp642
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp1647
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmodexports.cpp164
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmodldr.cpp102
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmodnm.cpp6
-rw-r--r--src/VBox/Runtime/common/dvm/dvm.cpp2
-rw-r--r--src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp2
-rw-r--r--src/VBox/Runtime/common/dvm/dvmgpt.cpp2
-rw-r--r--src/VBox/Runtime/common/dvm/dvmmbr.cpp2
-rw-r--r--src/VBox/Runtime/common/err/RTErrConvertFromErrno.cpp2
-rw-r--r--src/VBox/Runtime/common/err/RTErrConvertToErrno.cpp2
-rw-r--r--src/VBox/Runtime/common/err/errinfo.cpp2
-rw-r--r--src/VBox/Runtime/common/err/errmsg.cpp2
-rw-r--r--src/VBox/Runtime/common/err/errmsg.sed35
-rw-r--r--src/VBox/Runtime/common/err/errmsgcom.sed2
-rw-r--r--src/VBox/Runtime/common/err/errmsgxpcom.cpp2
-rw-r--r--src/VBox/Runtime/common/filesystem/filesystem.cpp1
-rw-r--r--src/VBox/Runtime/common/filesystem/filesystemext.cpp2
-rw-r--r--src/VBox/Runtime/common/ldr/ldr.cpp81
-rw-r--r--src/VBox/Runtime/common/ldr/ldrELF.cpp6
-rw-r--r--src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h837
-rw-r--r--src/VBox/Runtime/common/ldr/ldrEx.cpp42
-rw-r--r--src/VBox/Runtime/common/ldr/ldrFile.cpp5
-rw-r--r--src/VBox/Runtime/common/ldr/ldrMemory.cpp324
-rw-r--r--src/VBox/Runtime/common/ldr/ldrNative.cpp88
-rw-r--r--src/VBox/Runtime/common/ldr/ldrPE.cpp806
-rw-r--r--src/VBox/Runtime/common/ldr/ldrkStuff.cpp151
-rw-r--r--src/VBox/Runtime/common/log/log.cpp29
-rw-r--r--src/VBox/Runtime/common/log/logcom.cpp2
-rw-r--r--src/VBox/Runtime/common/log/logellipsis.cpp2
-rw-r--r--src/VBox/Runtime/common/log/logformat.cpp2
-rw-r--r--src/VBox/Runtime/common/log/logrel.cpp2
-rw-r--r--src/VBox/Runtime/common/log/logrelellipsis.cpp2
-rw-r--r--src/VBox/Runtime/common/math/ceill.asm4
-rw-r--r--src/VBox/Runtime/common/math/cosl.asm6
-rw-r--r--src/VBox/Runtime/common/math/fabs.asm4
-rw-r--r--src/VBox/Runtime/common/math/fabsf.asm4
-rw-r--r--src/VBox/Runtime/common/math/fabsl.asm6
-rw-r--r--src/VBox/Runtime/common/math/floor.asm4
-rw-r--r--src/VBox/Runtime/common/math/floorf.asm4
-rw-r--r--src/VBox/Runtime/common/math/floorl.asm4
-rw-r--r--src/VBox/Runtime/common/math/ldexpl.asm8
-rw-r--r--src/VBox/Runtime/common/math/llrint.asm2
-rw-r--r--src/VBox/Runtime/common/math/llrintf.asm2
-rw-r--r--src/VBox/Runtime/common/math/llrintl.asm6
-rw-r--r--src/VBox/Runtime/common/math/logl.asm6
-rw-r--r--src/VBox/Runtime/common/math/lrint.asm2
-rw-r--r--src/VBox/Runtime/common/math/lrintf.asm2
-rw-r--r--src/VBox/Runtime/common/math/lrintl.asm6
-rw-r--r--src/VBox/Runtime/common/math/remainder.asm2
-rw-r--r--src/VBox/Runtime/common/math/remainderf.asm2
-rw-r--r--src/VBox/Runtime/common/math/remainderl.asm2
-rw-r--r--src/VBox/Runtime/common/math/sinl.asm6
-rw-r--r--src/VBox/Runtime/common/math/tanl.asm6
-rw-r--r--src/VBox/Runtime/common/math/trunc.asm4
-rw-r--r--src/VBox/Runtime/common/math/truncf.asm4
-rw-r--r--src/VBox/Runtime/common/math/truncl.asm4
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp337
-rw-r--r--src/VBox/Runtime/common/misc/RTFileOpenF.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTFileOpenV.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/aiomgr.cpp1314
-rw-r--r--src/VBox/Runtime/common/misc/assert.cpp6
-rw-r--r--src/VBox/Runtime/common/misc/buildconfig.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/cidr.cpp8
-rw-r--r--src/VBox/Runtime/common/misc/getopt.cpp89
-rw-r--r--src/VBox/Runtime/common/misc/getoptargv.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/handletable.cpp12
-rw-r--r--src/VBox/Runtime/common/misc/handletable.h4
-rw-r--r--src/VBox/Runtime/common/misc/handletablectx.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/handletablesimple.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/http.cpp550
-rw-r--r--src/VBox/Runtime/common/misc/lockvalidator.cpp39
-rw-r--r--src/VBox/Runtime/common/misc/message.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/once.cpp135
-rw-r--r--src/VBox/Runtime/common/misc/req.cpp4
-rw-r--r--src/VBox/Runtime/common/misc/reqpool.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/reqqueue.cpp12
-rw-r--r--src/VBox/Runtime/common/misc/sanity-c.c2
-rw-r--r--src/VBox/Runtime/common/misc/sanity-cpp.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/sanity.h2
-rw-r--r--src/VBox/Runtime/common/misc/semspingpong.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/setjmp.asm2
-rw-r--r--src/VBox/Runtime/common/misc/sg.cpp58
-rw-r--r--src/VBox/Runtime/common/misc/term.cpp12
-rw-r--r--src/VBox/Runtime/common/misc/thread.cpp16
-rw-r--r--src/VBox/Runtime/common/net/macstr.cpp91
-rw-r--r--src/VBox/Runtime/common/net/netaddrstr.cpp10
-rw-r--r--src/VBox/Runtime/common/net/netaddrstr2.cpp72
-rw-r--r--src/VBox/Runtime/common/path/RTPathAbsDup.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathAbsEx.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathAbsExDup.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathAppend.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathAppendEx.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathCalcRelative.cpp130
-rw-r--r--src/VBox/Runtime/common/path/RTPathExt.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathFilename.cpp76
-rw-r--r--src/VBox/Runtime/common/path/RTPathParse.cpp109
-rw-r--r--src/VBox/Runtime/common/path/RTPathParse.cpp.h250
-rw-r--r--src/VBox/Runtime/common/path/RTPathParseSimple.cpp118
-rw-r--r--src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp122
-rw-r--r--src/VBox/Runtime/common/path/RTPathRealDup.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathRmCmd.cpp648
-rw-r--r--src/VBox/Runtime/common/path/RTPathSplit.cpp133
-rw-r--r--src/VBox/Runtime/common/path/RTPathSplitA.cpp91
-rw-r--r--src/VBox/Runtime/common/path/RTPathSplitReassemble.cpp120
-rw-r--r--src/VBox/Runtime/common/path/RTPathStripExt.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathStripFilename.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathTraverseList.cpp2
-rw-r--r--src/VBox/Runtime/common/path/comparepaths.cpp2
-rw-r--r--src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp4
-rw-r--r--src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp2
-rw-r--r--src/VBox/Runtime/common/path/rtpath-expand-template.cpp.h82
-rw-r--r--src/VBox/Runtime/common/rand/rand.cpp28
-rw-r--r--src/VBox/Runtime/common/rand/randadv.cpp2
-rw-r--r--src/VBox/Runtime/common/rand/randparkmiller.cpp2
-rw-r--r--src/VBox/Runtime/common/string/RTStrCmp.cpp2
-rw-r--r--src/VBox/Runtime/common/string/RTStrNCmp.cpp17
-rw-r--r--src/VBox/Runtime/common/string/RTStrNLen.cpp2
-rw-r--r--src/VBox/Runtime/common/string/RTStrNLenEx.cpp2
-rw-r--r--src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp2
-rw-r--r--src/VBox/Runtime/common/string/RTStrStr.cpp2
-rw-r--r--src/VBox/Runtime/common/string/base64.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memchr.asm2
-rw-r--r--src/VBox/Runtime/common/string/memchr.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memchr_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/memcmp.asm2
-rw-r--r--src/VBox/Runtime/common/string/memcmp.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memcmp_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/memcpy.asm2
-rw-r--r--src/VBox/Runtime/common/string/memcpy.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memcpy_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/memmove.asm2
-rw-r--r--src/VBox/Runtime/common/string/memmove_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/mempcpy.asm2
-rw-r--r--src/VBox/Runtime/common/string/memset.asm2
-rw-r--r--src/VBox/Runtime/common/string/memset.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memset_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/simplepattern.cpp2
-rw-r--r--src/VBox/Runtime/common/string/straprintf.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strcache.cpp1163
-rw-r--r--src/VBox/Runtime/common/string/strchr.asm2
-rw-r--r--src/VBox/Runtime/common/string/strchr_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/strcmp.asm2
-rw-r--r--src/VBox/Runtime/common/string/strcmp_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/strcpy.asm2
-rw-r--r--src/VBox/Runtime/common/string/strcpy.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strcpy_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/strformat.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strformatnum.cpp4
-rw-r--r--src/VBox/Runtime/common/string/strformatrt.cpp189
-rw-r--r--src/VBox/Runtime/common/string/strformattype.cpp6
-rw-r--r--src/VBox/Runtime/common/string/strlen.asm2
-rw-r--r--src/VBox/Runtime/common/string/strlen.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strlen_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/strncmp.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strpbrk.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strprintf.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strspace.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strstrip.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strtonum.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strversion.cpp2
-rw-r--r--src/VBox/Runtime/common/string/uni.cpp2
-rw-r--r--src/VBox/Runtime/common/string/unidata.cpp2
-rw-r--r--src/VBox/Runtime/common/string/uniread.cpp4
-rw-r--r--src/VBox/Runtime/common/string/utf-16.cpp2
-rw-r--r--src/VBox/Runtime/common/string/utf-8-case.cpp79
-rw-r--r--src/VBox/Runtime/common/string/utf-8.cpp2
-rw-r--r--src/VBox/Runtime/common/table/avl_Base.cpp.h2
-rw-r--r--src/VBox/Runtime/common/table/avl_Destroy.cpp.h10
-rw-r--r--src/VBox/Runtime/common/table/avl_DoWithAll.cpp.h14
-rw-r--r--src/VBox/Runtime/common/table/avl_Enum.cpp.h2
-rw-r--r--src/VBox/Runtime/common/table/avl_Get.cpp.h2
-rw-r--r--src/VBox/Runtime/common/table/avl_GetBestFit.cpp.h2
-rw-r--r--src/VBox/Runtime/common/table/avl_Range.cpp.h2
-rw-r--r--src/VBox/Runtime/common/table/avl_RemoveBestFit.cpp.h2
-rw-r--r--src/VBox/Runtime/common/table/avl_RemoveNode.cpp.h3
-rw-r--r--src/VBox/Runtime/common/table/avlgcphys.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlgcptr.cpp4
-rw-r--r--src/VBox/Runtime/common/table/avlhcphys.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avllu32.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlogcphys.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlogcptr.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlohcphys.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avloioport.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlou32.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlpv.cpp4
-rw-r--r--src/VBox/Runtime/common/table/avlrfoff.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlrgcptr.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlrogcphys.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlrogcptr.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlroioport.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlroogcptr.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlrpv.cpp4
-rw-r--r--src/VBox/Runtime/common/table/avlru64.cpp4
-rw-r--r--src/VBox/Runtime/common/table/avlruintptr.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlu32.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avluintptr.cpp3
-rw-r--r--src/VBox/Runtime/common/table/avlul.cpp3
-rw-r--r--src/VBox/Runtime/common/table/table.cpp2
-rw-r--r--src/VBox/Runtime/common/time/time.cpp164
-rw-r--r--src/VBox/Runtime/common/time/timeprog.cpp2
-rw-r--r--src/VBox/Runtime/common/time/timesup.cpp2
-rw-r--r--src/VBox/Runtime/common/time/timesupA.asm2
-rw-r--r--src/VBox/Runtime/common/time/timesupA.mac2
-rw-r--r--src/VBox/Runtime/common/time/timesupref.h2
-rw-r--r--src/VBox/Runtime/common/time/timesysalias.cpp2
-rw-r--r--src/VBox/Runtime/common/vfs/vfsbase.cpp2
-rw-r--r--src/VBox/Runtime/common/vfs/vfschain.cpp12
-rw-r--r--src/VBox/Runtime/common/vfs/vfsmisc.cpp2
-rw-r--r--src/VBox/Runtime/common/vfs/vfsstdfile.cpp71
-rw-r--r--src/VBox/Runtime/common/zip/gzipvfs.cpp348
-rw-r--r--src/VBox/Runtime/common/zip/tar.cpp170
-rw-r--r--src/VBox/Runtime/common/zip/tarcmd.cpp745
-rw-r--r--src/VBox/Runtime/common/zip/tarvfs.cpp2
-rw-r--r--src/VBox/Runtime/common/zip/xarvfs.cpp2111
-rw-r--r--src/VBox/Runtime/common/zip/zip.cpp45
-rw-r--r--src/VBox/Runtime/darwin/RTErrConvertFromDarwin.cpp2
-rw-r--r--src/VBox/Runtime/darwin/RTErrConvertFromDarwinCOM.cpp2
-rw-r--r--src/VBox/Runtime/darwin/RTErrConvertFromDarwinIO.cpp2
-rw-r--r--src/VBox/Runtime/darwin/RTErrConvertFromDarwinKern.cpp2
-rw-r--r--src/VBox/Runtime/gc/initterm-gc.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTAssertShouldPanic-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTDirExists-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTDirQueryInfo-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTDirSetTimes-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTFileCopy-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTFileExists-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTFileMove-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTFileQuerySize-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTFileReadAll-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTFileReadAllByHandle-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTFileReadAllByHandleEx-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTFileReadAllEx-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTFileReadAllFree-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTLogDefaultInit-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTLogWriteDebugger-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTLogWriteStdErr-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTLogWriteStdErr-stub-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTLogWriteStdOut-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTLogWriteStdOut-stub-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTLogWriteUser-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpCpuId-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpCpuIdFromSetIndex-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpCpuIdToSetIndex-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpGetCoreCount-generic.cpp40
-rw-r--r--src/VBox/Runtime/generic/RTMpGetCount-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpGetCurFrequency-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpGetDescription-generic-stub.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpGetDescription-generic.cpp9
-rw-r--r--src/VBox/Runtime/generic/RTMpGetMaxCpuId-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpGetMaxFrequency-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpGetOnlineCoreCount-generic.cpp40
-rw-r--r--src/VBox/Runtime/generic/RTMpGetOnlineCount-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpGetOnlineSet-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpGetSet-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpIsCpuOnline-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTMpIsCpuPossible-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTPathIsSame-generic.cpp93
-rw-r--r--src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp5
-rw-r--r--src/VBox/Runtime/generic/RTProcIsRunningByName-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTProcessQueryUsernameA-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTRandAdvCreateSystemFaster-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTRandAdvCreateSystemTruer-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTSemEventMultiWait-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTSemEventWait-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTSemMutexRequest-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTSemMutexRequestDebug-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTSystemQueryOSInfo-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTTimeLocalDeltaNano-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTTimeLocalExplode-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTTimeLocalNow-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTTimerLRCreate-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/RTUuidCreate-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/cdrom-generic.cpp1
-rw-r--r--src/VBox/Runtime/generic/createtemp-generic.cpp4
-rw-r--r--src/VBox/Runtime/generic/critsect-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/critsectrw-generic.cpp917
-rw-r--r--src/VBox/Runtime/generic/env-generic.cpp103
-rw-r--r--src/VBox/Runtime/generic/fs-stubs-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/mempool-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/mppresent-generic.cpp9
-rw-r--r--src/VBox/Runtime/generic/sched-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/semfastmutex-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/semrw-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/semrw-lockless-generic.cpp19
-rw-r--r--src/VBox/Runtime/generic/semxroads-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/strcache-stubs-generic.cpp39
-rw-r--r--src/VBox/Runtime/generic/timer-generic.cpp13
-rw-r--r--src/VBox/Runtime/generic/timerlr-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/tls-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/utf16locale-generic.cpp2
-rw-r--r--src/VBox/Runtime/generic/uuid-generic.cpp2
-rw-r--r--src/VBox/Runtime/include/internal/alignmentchecks.h2
-rw-r--r--src/VBox/Runtime/include/internal/assert.h2
-rw-r--r--src/VBox/Runtime/include/internal/dbgmod.h170
-rw-r--r--src/VBox/Runtime/include/internal/dir.h54
-rw-r--r--src/VBox/Runtime/include/internal/dvm.h2
-rw-r--r--src/VBox/Runtime/include/internal/file.h2
-rw-r--r--src/VBox/Runtime/include/internal/fileaio.h2
-rw-r--r--src/VBox/Runtime/include/internal/fs.h2
-rw-r--r--src/VBox/Runtime/include/internal/initterm.h2
-rw-r--r--src/VBox/Runtime/include/internal/iprt.h2
-rw-r--r--src/VBox/Runtime/include/internal/ldr.h57
-rw-r--r--src/VBox/Runtime/include/internal/ldrELF.h2
-rw-r--r--src/VBox/Runtime/include/internal/ldrELF32.h2
-rw-r--r--src/VBox/Runtime/include/internal/ldrELF64.h2
-rw-r--r--src/VBox/Runtime/include/internal/ldrMZ.h2
-rw-r--r--src/VBox/Runtime/include/internal/ldrMach-O.h625
-rw-r--r--src/VBox/Runtime/include/internal/ldrPE.h565
-rw-r--r--src/VBox/Runtime/include/internal/lockvalidator.h2
-rw-r--r--src/VBox/Runtime/include/internal/magics.h16
-rw-r--r--src/VBox/Runtime/include/internal/path.h2
-rw-r--r--src/VBox/Runtime/include/internal/pipe.h53
-rw-r--r--src/VBox/Runtime/include/internal/process.h2
-rw-r--r--src/VBox/Runtime/include/internal/rand.h2
-rw-r--r--src/VBox/Runtime/include/internal/sched.h2
-rw-r--r--src/VBox/Runtime/include/internal/socket.h6
-rw-r--r--src/VBox/Runtime/include/internal/strhash.h2
-rw-r--r--src/VBox/Runtime/include/internal/strict.h9
-rw-r--r--src/VBox/Runtime/include/internal/thread.h15
-rw-r--r--src/VBox/Runtime/nt/NtProcessStartup-stub.cpp2
-rw-r--r--src/VBox/Runtime/nt/RTErrConvertFromNtStatus.cpp31
-rw-r--r--src/VBox/Runtime/os2/RTErrConvertFromOS2.cpp2
-rw-r--r--src/VBox/Runtime/os2/rtSemWaitOs2ConvertTimeout.cpp10
-rw-r--r--src/VBox/Runtime/os2/sys0.asm2
-rw-r--r--src/VBox/Runtime/r0drv/alloc-r0drv.cpp6
-rw-r--r--src/VBox/Runtime/r0drv/alloc-r0drv.h2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/RTLogWriteDebugger-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp8
-rw-r--r--src/VBox/Runtime/r0drv/darwin/memuserkernel-r0drv-darwin.cpp3
-rw-r--r--src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/process-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h8
-rw-r--r--src/VBox/Runtime/r0drv/darwin/thread-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/darwin/threadpreempt-r0drv-darwin.cpp6
-rw-r--r--src/VBox/Runtime/r0drv/darwin/time-r0drv-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c5
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c63
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/memuserkernel-r0drv-freebsd.c3
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c7
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c2
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h6
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h4
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/thread-r0drv-freebsd.c2
-rw-r--r--src/VBox/Runtime/r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/generic/RTMpPokeCpu-r0drv-generic.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/generic/RTThreadPreemptDisable-r0drv-generic.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsEnabled-r0drv-generic.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPending-r0drv-generic.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPendingTrusty-r0drv-generic.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/generic/RTThreadPreemptRestore-r0drv-generic.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c2
-rw-r--r--src/VBox/Runtime/r0drv/generic/threadctxhooks-r0drv-generic.cpp84
-rw-r--r--src/VBox/Runtime/r0drv/haiku/RTLogWriteDebugger-r0drv-haiku.c42
-rw-r--r--src/VBox/Runtime/r0drv/haiku/RTLogWriteStdOut-r0drv-haiku.c41
-rw-r--r--src/VBox/Runtime/r0drv/haiku/alloc-r0drv-haiku.c124
-rw-r--r--src/VBox/Runtime/r0drv/haiku/assert-r0drv-haiku.c68
-rw-r--r--src/VBox/Runtime/r0drv/haiku/initterm-r0drv-haiku.c48
-rw-r--r--src/VBox/Runtime/r0drv/haiku/memobj-r0drv-haiku.c663
-rw-r--r--src/VBox/Runtime/r0drv/haiku/mp-r0drv-haiku.c218
-rw-r--r--src/VBox/Runtime/r0drv/haiku/process-r0drv-haiku.c46
-rw-r--r--src/VBox/Runtime/r0drv/haiku/semevent-r0drv-haiku.c264
-rw-r--r--src/VBox/Runtime/r0drv/haiku/semeventmulti-r0drv-haiku.c291
-rw-r--r--src/VBox/Runtime/r0drv/haiku/semfastmutex-r0drv-haiku.c120
-rw-r--r--src/VBox/Runtime/r0drv/haiku/semmutex-r0drv-haiku.c233
-rw-r--r--src/VBox/Runtime/r0drv/haiku/spinlock-r0drv-haiku.c146
-rw-r--r--src/VBox/Runtime/r0drv/haiku/the-haiku-kernel.h114
-rw-r--r--src/VBox/Runtime/r0drv/haiku/thread-r0drv-haiku.c127
-rw-r--r--src/VBox/Runtime/r0drv/haiku/thread2-r0drv-haiku.c131
-rw-r--r--src/VBox/Runtime/r0drv/haiku/time-r0drv-haiku.c79
-rw-r--r--src/VBox/Runtime/r0drv/initterm-r0drv.cpp17
-rw-r--r--src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c10
-rw-r--r--src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c33
-rw-r--r--src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/process-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c15
-rw-r--r--src/VBox/Runtime/r0drv/linux/string.h2
-rw-r--r--src/VBox/Runtime/r0drv/linux/the-linux-kernel.h14
-rw-r--r--src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c6
-rw-r--r--src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c330
-rw-r--r--src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c2
-rw-r--r--src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c4
-rw-r--r--src/VBox/Runtime/r0drv/memobj-r0drv.cpp10
-rw-r--r--src/VBox/Runtime/r0drv/mp-r0drv.h2
-rw-r--r--src/VBox/Runtime/r0drv/mpnotification-r0drv.c4
-rw-r--r--src/VBox/Runtime/r0drv/nt/RTLogWriteDebugger-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/alloc-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/assert-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp349
-rw-r--r--src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h4
-rw-r--r--src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/memuserkernel-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/mpnotification-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp1203
-rw-r--r--src/VBox/Runtime/r0drv/nt/process-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/semevent-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/semeventmulti-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/semfastmutex-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/semmutex-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/spinlock-r0drv-nt.cpp8
-rw-r--r--src/VBox/Runtime/r0drv/nt/symdb.h85
-rw-r--r--src/VBox/Runtime/r0drv/nt/symdbdata.h2920
-rw-r--r--src/VBox/Runtime/r0drv/nt/the-nt-kernel.h2
-rw-r--r--src/VBox/Runtime/r0drv/nt/thread-r0drv-nt.cpp7
-rw-r--r--src/VBox/Runtime/r0drv/nt/thread2-r0drv-nt.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/nt/time-r0drv-nt.cpp26
-rw-r--r--src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp17
-rw-r--r--src/VBox/Runtime/r0drv/os2/memuserkernel-r0drv-os2.cpp2
-rw-r--r--src/VBox/Runtime/r0drv/os2/semevent-r0drv-os2.cpp4
-rw-r--r--src/VBox/Runtime/r0drv/os2/semeventmulti-r0drv-os2.cpp4
-rw-r--r--src/VBox/Runtime/r0drv/os2/spinlock-r0drv-os2.cpp3
-rw-r--r--src/VBox/Runtime/r0drv/power-r0drv.h2
-rw-r--r--src/VBox/Runtime/r0drv/powernotification-r0drv.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/RTLogWriteDebugger-r0drv-solaris.c11
-rw-r--r--src/VBox/Runtime/r0drv/solaris/RTMpPokeCpu-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/alloc-r0drv-solaris.c4
-rw-r--r--src/VBox/Runtime/r0drv/solaris/assert-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/initterm-r0drv-solaris.c28
-rw-r--r--src/VBox/Runtime/r0drv/solaris/memobj-r0drv-solaris.c6
-rw-r--r--src/VBox/Runtime/r0drv/solaris/memuserkernel-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/mp-r0drv-solaris.c8
-rw-r--r--src/VBox/Runtime/r0drv/solaris/mpnotification-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/process-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/semevent-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/semeventwait-r0drv-solaris.h2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/semfastmutex-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/semmutex-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/spinlock-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/the-solaris-kernel.h49
-rw-r--r--src/VBox/Runtime/r0drv/solaris/thread-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/thread2-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/threadctxhooks-r0drv-solaris.c337
-rw-r--r--src/VBox/Runtime/r0drv/solaris/time-r0drv-solaris.c2
-rw-r--r--src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c73
-rw-r--r--src/VBox/Runtime/r3/alloc-ef-cpp.cpp2
-rw-r--r--src/VBox/Runtime/r3/alloc-ef.cpp2
-rw-r--r--src/VBox/Runtime/r3/alloc.cpp6
-rw-r--r--src/VBox/Runtime/r3/allocex.cpp126
-rw-r--r--src/VBox/Runtime/r3/allocex.h84
-rw-r--r--src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp65
-rw-r--r--src/VBox/Runtime/r3/darwin/mp-darwin.cpp83
-rw-r--r--src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp13
-rw-r--r--src/VBox/Runtime/r3/darwin/sched-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r3/darwin/time-darwin.cpp2
-rw-r--r--src/VBox/Runtime/r3/dir.cpp106
-rw-r--r--src/VBox/Runtime/r3/dir2.cpp2
-rw-r--r--src/VBox/Runtime/r3/fileio.cpp88
-rw-r--r--src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp12
-rw-r--r--src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp2
-rw-r--r--src/VBox/Runtime/r3/freebsd/rtProcInitExePath-freebsd.cpp2
-rw-r--r--src/VBox/Runtime/r3/fs.cpp3
-rw-r--r--src/VBox/Runtime/r3/generic/allocex-r3-generic.cpp (renamed from src/VBox/Runtime/r3/os2/poll-os2.cpp)52
-rw-r--r--src/VBox/Runtime/r3/generic/semspinmutex-r3-generic.cpp2
-rw-r--r--src/VBox/Runtime/r3/haiku/rtProcInitExePath-haiku.cpp60
-rw-r--r--src/VBox/Runtime/r3/haiku/time-haiku.cpp84
-rw-r--r--src/VBox/Runtime/r3/init.cpp157
-rw-r--r--src/VBox/Runtime/r3/init.h38
-rw-r--r--src/VBox/Runtime/r3/isofs.cpp2
-rw-r--r--src/VBox/Runtime/r3/linux/RTProcIsRunningByName-linux.cpp2
-rw-r--r--src/VBox/Runtime/r3/linux/RTSystemShutdown-linux.cpp13
-rw-r--r--src/VBox/Runtime/r3/linux/fileaio-linux.cpp12
-rw-r--r--src/VBox/Runtime/r3/linux/mp-linux.cpp70
-rw-r--r--src/VBox/Runtime/r3/linux/rtProcInitExePath-linux.cpp2
-rw-r--r--src/VBox/Runtime/r3/linux/sched-linux.cpp2
-rw-r--r--src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp2
-rw-r--r--src/VBox/Runtime/r3/linux/semmutex-linux.cpp2
-rw-r--r--src/VBox/Runtime/r3/linux/sysfs.cpp166
-rw-r--r--src/VBox/Runtime/r3/linux/systemmem-linux.cpp42
-rw-r--r--src/VBox/Runtime/r3/linux/time-linux.cpp2
-rw-r--r--src/VBox/Runtime/r3/nt/Makefile.kup0
-rw-r--r--src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp697
-rw-r--r--src/VBox/Runtime/r3/nt/fs-nt.cpp284
-rw-r--r--src/VBox/Runtime/r3/nt/internal-r3-nt.h140
-rw-r--r--src/VBox/Runtime/r3/nt/pathint-nt.cpp356
-rw-r--r--src/VBox/Runtime/r3/os2/filelock-os2.cpp2
-rw-r--r--src/VBox/Runtime/r3/os2/mp-os2.cpp2
-rw-r--r--src/VBox/Runtime/r3/os2/pipe-os2.cpp956
-rw-r--r--src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp2
-rw-r--r--src/VBox/Runtime/r3/os2/sched-os2.cpp2
-rw-r--r--src/VBox/Runtime/r3/os2/sems-os2.cpp2
-rw-r--r--src/VBox/Runtime/r3/os2/systemmem-os2.cpp70
-rw-r--r--src/VBox/Runtime/r3/os2/thread-os2.cpp25
-rw-r--r--src/VBox/Runtime/r3/path.cpp2
-rw-r--r--src/VBox/Runtime/r3/poll.cpp1109
-rw-r--r--src/VBox/Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/RTHandleGetStandard-posix.cpp3
-rw-r--r--src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/allocex-r3-posix.cpp109
-rw-r--r--src/VBox/Runtime/r3/posix/dir-posix.cpp31
-rw-r--r--src/VBox/Runtime/r3/posix/env-posix.cpp41
-rw-r--r--src/VBox/Runtime/r3/posix/fileaio-posix.cpp10
-rw-r--r--src/VBox/Runtime/r3/posix/fileio-posix.cpp16
-rw-r--r--src/VBox/Runtime/r3/posix/fileio2-posix.cpp36
-rw-r--r--src/VBox/Runtime/r3/posix/filelock-posix.cpp3
-rw-r--r--src/VBox/Runtime/r3/posix/fs-posix.cpp4
-rw-r--r--src/VBox/Runtime/r3/posix/fs2-posix.cpp5
-rw-r--r--src/VBox/Runtime/r3/posix/ldrNative-posix.cpp12
-rw-r--r--src/VBox/Runtime/r3/posix/path-posix.cpp7
-rw-r--r--src/VBox/Runtime/r3/posix/path2-posix.cpp4
-rw-r--r--src/VBox/Runtime/r3/posix/pathhost-posix.cpp14
-rw-r--r--src/VBox/Runtime/r3/posix/pipe-posix.cpp19
-rw-r--r--src/VBox/Runtime/r3/posix/poll-posix.cpp519
-rw-r--r--src/VBox/Runtime/r3/posix/process-creation-posix.cpp71
-rw-r--r--src/VBox/Runtime/r3/posix/process-posix.cpp3
-rw-r--r--src/VBox/Runtime/r3/posix/rand-posix.cpp8
-rw-r--r--src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp19
-rw-r--r--src/VBox/Runtime/r3/posix/sched-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/semevent-posix.cpp6
-rw-r--r--src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp4
-rw-r--r--src/VBox/Runtime/r3/posix/semmutex-posix.cpp59
-rw-r--r--src/VBox/Runtime/r3/posix/semrw-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/symlink-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/thread-posix.cpp148
-rw-r--r--src/VBox/Runtime/r3/posix/thread2-posix.cpp8
-rw-r--r--src/VBox/Runtime/r3/posix/time-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/timelocal-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/timer-posix.cpp20
-rw-r--r--src/VBox/Runtime/r3/posix/tls-posix.cpp2
-rw-r--r--src/VBox/Runtime/r3/posix/utf8-posix.cpp26
-rw-r--r--src/VBox/Runtime/r3/process.cpp2
-rw-r--r--src/VBox/Runtime/r3/socket.cpp119
-rw-r--r--src/VBox/Runtime/r3/solaris/Makefile.kup0
-rw-r--r--src/VBox/Runtime/r3/solaris/RTSystemShutdown-solaris.cpp102
-rw-r--r--src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp56
-rw-r--r--src/VBox/Runtime/r3/solaris/coredumper-solaris.h2
-rw-r--r--src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp14
-rw-r--r--src/VBox/Runtime/r3/solaris/mp-solaris.cpp182
-rw-r--r--src/VBox/Runtime/r3/solaris/rtProcInitExePath-solaris.cpp2
-rw-r--r--src/VBox/Runtime/r3/solaris/systemmem-solaris.cpp172
-rw-r--r--src/VBox/Runtime/r3/stream.cpp3
-rw-r--r--src/VBox/Runtime/r3/tcp.cpp48
-rw-r--r--src/VBox/Runtime/r3/test.cpp350
-rw-r--r--src/VBox/Runtime/r3/testi.cpp2
-rw-r--r--src/VBox/Runtime/r3/udp.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/RTHandleGetStandard-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/RTSystemQueryDmiString-win.cpp10
-rw-r--r--src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp228
-rw-r--r--src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp12
-rw-r--r--src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def22
-rw-r--r--src/VBox/Runtime/r3/win/VBoxRT-openssl.def12
-rw-r--r--src/VBox/Runtime/r3/win/VBoxRT-win32.def2
-rw-r--r--src/VBox/Runtime/r3/win/VBoxRT-win64.def2
-rw-r--r--src/VBox/Runtime/r3/win/alloc-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/allocex-win.cpp120
-rw-r--r--src/VBox/Runtime/r3/win/dir-win.cpp342
-rw-r--r--src/VBox/Runtime/r3/win/direnum-win.cpp389
-rw-r--r--src/VBox/Runtime/r3/win/dllmain-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/env-win.cpp268
-rw-r--r--src/VBox/Runtime/r3/win/fileaio-win.cpp14
-rw-r--r--src/VBox/Runtime/r3/win/fs-win.cpp5
-rw-r--r--src/VBox/Runtime/r3/win/init-win.cpp273
-rw-r--r--src/VBox/Runtime/r3/win/internal-r3-win.h72
-rw-r--r--src/VBox/Runtime/r3/win/ldrNative-win.cpp54
-rw-r--r--src/VBox/Runtime/r3/win/localipc-win.cpp782
-rw-r--r--src/VBox/Runtime/r3/win/mp-win.cpp69
-rw-r--r--src/VBox/Runtime/r3/win/ntdll-mini-implib.c111
-rw-r--r--src/VBox/Runtime/r3/win/ntdll-mini-implib.def9
-rw-r--r--src/VBox/Runtime/r3/win/path-win.cpp4
-rw-r--r--src/VBox/Runtime/r3/win/pipe-win.cpp22
-rw-r--r--src/VBox/Runtime/r3/win/poll-win.cpp586
-rw-r--r--src/VBox/Runtime/r3/win/process-win.cpp283
-rw-r--r--src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/sched-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/semmutex-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/symlink-win.cpp15
-rw-r--r--src/VBox/Runtime/r3/win/thread-win.cpp10
-rw-r--r--src/VBox/Runtime/r3/win/time-win.cpp25
-rw-r--r--src/VBox/Runtime/r3/win/timer-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/tls-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/utf16locale-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/win/uuid-win.cpp2
-rw-r--r--src/VBox/Runtime/r3/xml.cpp975
-rw-r--r--src/VBox/Runtime/testcase/Makefile.kmk40
-rw-r--r--src/VBox/Runtime/testcase/ioctl.h48
-rw-r--r--src/VBox/Runtime/testcase/ntGetTimerResolution.cpp2
-rw-r--r--src/VBox/Runtime/testcase/soundcard.h1300
-rw-r--r--src/VBox/Runtime/testcase/tstDir-2.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstDir-3.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstDir.cpp167
-rw-r--r--src/VBox/Runtime/testcase/tstEnv.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstFile.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstFileAppendWin-1.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstFileLock.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstFork.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstHandleTable.cpp8
-rw-r--r--src/VBox/Runtime/testcase/tstIoCtl.cpp119
-rw-r--r--src/VBox/Runtime/testcase/tstIprtList.cpp190
-rw-r--r--src/VBox/Runtime/testcase/tstLdr-2.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstLdr-3.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstLdr-4.cpp4
-rw-r--r--src/VBox/Runtime/testcase/tstLdr-4Imp-os2.def2
-rw-r--r--src/VBox/Runtime/testcase/tstLdr-4Imp-win.def2
-rw-r--r--src/VBox/Runtime/testcase/tstLdr.cpp4
-rw-r--r--src/VBox/Runtime/testcase/tstLdrDisasmTest.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstLdrLoad.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstLdrObj.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstLdrObjR0.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstLog.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstMemAutoPtr.cpp6
-rw-r--r--src/VBox/Runtime/testcase/tstMove.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstMp-1.cpp285
-rw-r--r--src/VBox/Runtime/testcase/tstNoCrt-1.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstOnce.cpp20
-rw-r--r--src/VBox/Runtime/testcase/tstPrfRT.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp284
-rw-r--r--src/VBox/Runtime/testcase/tstR0ThreadPreemption.h6
-rw-r--r--src/VBox/Runtime/testcase/tstR0ThreadPreemptionDriver.cpp112
-rw-r--r--src/VBox/Runtime/testcase/tstRTAssertCompile.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTAvl.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTBase64.cpp14
-rw-r--r--src/VBox/Runtime/testcase/tstRTBitOperations.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTCidr.cpp12
-rw-r--r--src/VBox/Runtime/testcase/tstRTCircBuf.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTCritSect.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTCritSectRw.cpp491
-rw-r--r--src/VBox/Runtime/testcase/tstRTDigest.cpp12
-rw-r--r--src/VBox/Runtime/testcase/tstRTDirCreateUniqueNumbered.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTDvm.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTFileAio.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTFileGetSize-1.cpp18
-rw-r--r--src/VBox/Runtime/testcase/tstRTFileModeStringToFlags.cpp222
-rw-r--r--src/VBox/Runtime/testcase/tstRTFsQueries.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTHeapOffset.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTHeapSimple.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTHttp.cpp253
-rw-r--r--src/VBox/Runtime/testcase/tstRTInlineAsm.cpp82
-rw-r--r--src/VBox/Runtime/testcase/tstRTList.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTLocalIpc.cpp644
-rw-r--r--src/VBox/Runtime/testcase/tstRTLockValidator.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTManifest.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTMemEf.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTMemPool.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTMp-1.cpp241
-rw-r--r--src/VBox/Runtime/testcase/tstRTPath.cpp223
-rw-r--r--src/VBox/Runtime/testcase/tstRTPipe.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp12
-rw-r--r--src/VBox/Runtime/testcase/tstRTProcCreatePrf.cpp3
-rw-r--r--src/VBox/Runtime/testcase/tstRTProcIsRunningByName.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTProcWait.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0Common.h47
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0CommonDriver.h9
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0DbgKrnlInfoDriver.cpp6
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0MemUserKernel.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0MemUserKernel.h2
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0MemUserKernelDriver.cpp6
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0SemMutex.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0SemMutexDriver.cpp6
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0Timer.cpp172
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0Timer.h3
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp76
-rw-r--r--src/VBox/Runtime/testcase/tstRTS3.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTSemRW.cpp19
-rw-r--r--src/VBox/Runtime/testcase/tstRTSemXRoads.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTStrAlloc.cpp6
-rw-r--r--src/VBox/Runtime/testcase/tstRTStrCache.cpp144
-rw-r--r--src/VBox/Runtime/testcase/tstRTStrFormat.cpp110
-rw-r--r--src/VBox/Runtime/testcase/tstRTSymlink.cpp4
-rw-r--r--src/VBox/Runtime/testcase/tstRTSystemQueryOsInfo.cpp12
-rw-r--r--src/VBox/Runtime/testcase/tstRTTcp-1.cpp18
-rw-r--r--src/VBox/Runtime/testcase/tstRTTemp.cpp4
-rw-r--r--src/VBox/Runtime/testcase/tstRTTime.cpp (renamed from src/VBox/Runtime/testcase/tstTime.cpp)70
-rw-r--r--src/VBox/Runtime/testcase/tstRTTimeSpec.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRTUri.cpp83
-rw-r--r--src/VBox/Runtime/testcase/tstRTUuid.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstRand.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstSemMutex.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstSemPingPong.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstStrSimplePattern.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstStrToNum.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstTSC.cpp4
-rw-r--r--src/VBox/Runtime/testcase/tstTermCallbacks.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstThread-1.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstTime-2.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstTime-3.cpp8
-rw-r--r--src/VBox/Runtime/testcase/tstTime-4.cpp9
-rw-r--r--src/VBox/Runtime/testcase/tstTimer.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstTimerLR.cpp2
-rw-r--r--src/VBox/Runtime/testcase/tstUtf8.cpp22
-rw-r--r--src/VBox/Runtime/tools/Makefile.kmk12
-rw-r--r--src/VBox/Runtime/tools/RTGzip.cpp566
-rw-r--r--src/VBox/Runtime/tools/RTLdrFlt.cpp78
-rw-r--r--src/VBox/Runtime/tools/RTManifest.cpp2
-rw-r--r--src/VBox/Runtime/tools/RTNtDbgHelp.cpp380
-rw-r--r--src/VBox/Runtime/tools/RTRm.cpp45
-rw-r--r--src/VBox/Runtime/tools/RTTar.cpp2
-rw-r--r--src/VBox/Runtime/win/RTErrConvertFromWin32.cpp3
-rw-r--r--src/VBox/Runtime/win/amd64/ASMAtomicBitClear.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMAtomicBitTestAndToggle.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMAtomicBitToggle.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMAtomicReadU64.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMAtomicXchgU16.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMAtomicXchgU8.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMBitFirstClear.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMBitFirstSet.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetCS.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetDR0.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetDR1.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetDR2.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetDR3.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetDR6.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetDR7.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetDS.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetES.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetFS.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetFlags.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetGS.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMGetSS.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMProbeReadByte.asm2
-rw-r--r--src/VBox/Runtime/win/amd64/ASMSetFlags.asm2
806 files changed, 46019 insertions, 8727 deletions
diff --git a/src/VBox/Runtime/.scm-settings b/src/VBox/Runtime/.scm-settings
index cc03358c..84ef39a9 100644
--- a/src/VBox/Runtime/.scm-settings
+++ b/src/VBox/Runtime/.scm-settings
@@ -4,7 +4,7 @@
#
#
-# Copyright (C) 2010 Oracle Corporation
+# Copyright (C) 2010-2012 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/Makefile.kmk b/src/VBox/Runtime/Makefile.kmk
index 131a8675..eb7e12a6 100644
--- a/src/VBox/Runtime/Makefile.kmk
+++ b/src/VBox/Runtime/Makefile.kmk
@@ -1,10 +1,10 @@
# $Id: Makefile.kmk $
## @file
-# Sub-Makefile for the IPRT (IPRT).
+# Sub-Makefile for the IPRT.
#
#
-# Copyright (C) 2006-2012 Oracle Corporation
+# Copyright (C) 2006-2013 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
@@ -46,6 +46,7 @@ else ifdef VBOX_ONLY_TESTSUITE
LIBRARIES += RuntimeGuestR3 RuntimeGuestR3Shared RuntimeR3 RuntimeR0
LIBRARIES.solaris += RuntimeR0Stub
LIBRARIES.win += RuntimeR0Stub
+ LIBRARIES.win.x86 += RuntimeR3VccTricks
else ifdef VBOX_ONLY_DOCS
#
@@ -92,8 +93,11 @@ else # !VBOX_ONLY_ADDITIONS && !VBOX_ONLY_TESTSUITE && !VBOX_ONLY_DOCS
#LIBRARIES.os2 += RuntimeGuestR0OS2Warp3
LIBRARIES.win.x86 += RuntimeGuestR0NT4
endif # VBOX_WITH_ADDITIONS
- LIBRARIES.l4 += RuntimeR3L4 RuntimeLnxHostR3
+ LIBRARIES.win.x86 += RuntimeR3VccTricks
DLLS += VBoxRT
+ ifdef VBOX_WITH_32_ON_64_MAIN_API
+ DLLS += VBoxRT-x86
+ endif
endif
@@ -165,9 +169,6 @@ RuntimeWin64ASM_SOURCES = \
win/amd64/ASMGetFlags.asm \
win/amd64/ASMGetFS.asm \
win/amd64/ASMGetGS.asm \
- win/amd64/ASMGetIDTR.asm \
- win/amd64/ASMGetGDTR.asm \
- win/amd64/ASMGetTR.asm \
win/amd64/ASMGetSS.asm \
win/amd64/ASMProbeReadByte.asm \
win/amd64/ASMSetFlags.asm \
@@ -179,14 +180,22 @@ RuntimeWin64ASM_SOURCES = \
win/amd64/ASMGetDR7.asm \
common/asm/ASMAtomicCmpXchgU8.asm \
common/asm/ASMMultU64ByU32DivByU32.asm \
- common/asm/ASMNopPause.asm
+ common/asm/ASMCpuId_Idx_ECX.asm \
+ common/asm/ASMNopPause.asm \
+ common/asm/ASMGetIDTR.asm \
+ common/asm/ASMGetGDTR.asm \
+ common/asm/ASMGetLDTR.asm \
+ common/asm/ASMGetSegAttr.asm \
+ common/asm/ASMGetTR.asm
#
# Win32 assembly sources.
#
RuntimeWin32ASM_SOURCES = \
common/asm/ASMAtomicCmpXchgU8.asm \
- common/asm/ASMMultU64ByU32DivByU32.asm
+ common/asm/ASMMultU64ByU32DivByU32.asm \
+ common/asm/ASMCpuId_Idx_ECX.asm \
+ common/asm/ASMGetSegAttr.asm
#
# NoCRT sources (minus math stuff).
@@ -212,7 +221,7 @@ endif
# RuntimeR3 - Static Runtime for Ring-3 executables.
#
RuntimeR3_TEMPLATE = VBoxR3Static
-RuntimeR3_SDKS = VBOX_LIBXML2 VBOX_OPENSSL VBOX_BOOST ## @todo why is BOOST and XML2 here? r3/xml.cpp is not in this lib...
+RuntimeR3_SDKS = VBOX_OPENSSL VBOX_LIBXML2
RuntimeR3_SDKS.win = $(VBOX_WINPSDK) $(VBOX_WINDDK)
RuntimeR3_DEFS = IN_RT_R3 IN_SUP_R3 LDR_WITH_NATIVE LDR_WITH_ELF32 LDR_WITH_PE RT_WITH_VBOX RT_NO_GIP
#RuntimeR3_DEFS += RTMEM_WRAP_TO_EF_APIS
@@ -240,8 +249,6 @@ ifdef IPRT_WITH_KSTUFF
RuntimeR3_INCS += \
$(PATH_ROOT)/src/libs/kStuff/kStuff/include
endif
-RuntimeR3_INCS.l4 = \
- $(L4_INCDIR)
# RuntimeR3_INCS.solaris = \
# /usr/include
@@ -264,6 +271,7 @@ RuntimeR3_SOURCES = \
common/checksum/manifest3.cpp \
common/checksum/manifest-file.cpp \
common/checksum/RTSha1Digest.cpp \
+ common/checksum/RTSha256Digest.cpp \
common/checksum/sha1.cpp \
common/checksum/sha1str.cpp \
common/checksum/sha256.cpp \
@@ -272,10 +280,14 @@ RuntimeR3_SOURCES = \
common/checksum/sha512str.cpp \
common/dbg/dbg.cpp \
common/dbg/dbgas.cpp \
+ common/dbg/dbgcfg.cpp \
common/dbg/dbgmod.cpp \
+ common/dbg/dbgmodldr.cpp \
common/dbg/dbgmodcontainer.cpp \
+ common/dbg/dbgmoddeferred.cpp \
+ common/dbg/dbgmodexports.cpp \
+ common/dbg/dbgmodcodeview.cpp \
common/dbg/dbgmoddwarf.cpp \
- common/dbg/dbgmodldr.cpp \
common/dbg/dbgmodnm.cpp \
common/dvm/dvm.cpp \
common/dvm/dvmbsdlabel.cpp \
@@ -292,6 +304,7 @@ RuntimeR3_SOURCES = \
common/ldr/ldrELF.cpp \
common/ldr/ldrEx.cpp \
common/ldr/ldrFile.cpp \
+ common/ldr/ldrMemory.cpp \
common/ldr/ldrNative.cpp \
common/ldr/ldrPE.cpp \
common/log/log.cpp \
@@ -309,6 +322,7 @@ RuntimeR3_SOURCES = \
common/misc/RTAssertMsg2AddWeakV.cpp \
common/misc/RTAssertMsg2Weak.cpp \
common/misc/RTAssertMsg2WeakV.cpp \
+ common/misc/RTFileModeToFlags.cpp \
common/misc/RTFileOpenF.cpp \
common/misc/RTFileOpenV.cpp \
common/misc/RTMemWipeThoroughly.cpp \
@@ -336,6 +350,8 @@ RuntimeR3_SOURCES = \
common/misc/term.cpp \
common/misc/uri.cpp \
common/net/netaddrstr.cpp \
+ common/net/netaddrstr2.cpp \
+ common/net/macstr.cpp \
common/path/rtPathRootSpecLen.cpp \
common/path/rtPathVolumeSpecLen.cpp \
common/path/RTPathAbsDup.cpp \
@@ -343,6 +359,7 @@ RuntimeR3_SOURCES = \
common/path/RTPathAbsExDup.cpp \
common/path/RTPathAppend.cpp \
common/path/RTPathAppendEx.cpp \
+ common/path/RTPathCalcRelative.cpp \
common/path/RTPathChangeToDosSlashes.cpp \
common/path/RTPathChangeToUnixSlashes.cpp \
common/path/RTPathCopyComponents.cpp \
@@ -355,7 +372,13 @@ RuntimeR3_SOURCES = \
common/path/RTPathJoinA.cpp \
common/path/RTPathJoinEx.cpp \
common/path/RTPathParse.cpp \
+ common/path/RTPathParsedReassemble.cpp \
+ common/path/RTPathParseSimple.cpp \
common/path/RTPathRealDup.cpp \
+ common/path/RTPathRmCmd.cpp \
+ common/path/RTPathSplit.cpp \
+ common/path/RTPathSplitA.cpp \
+ common/path/RTPathSplitReassemble.cpp \
common/path/RTPathStartsWithRoot.cpp \
common/path/RTPathStripExt.cpp \
common/path/RTPathStripFilename.cpp \
@@ -392,6 +415,7 @@ RuntimeR3_SOURCES = \
common/string/strhash1.cpp \
common/string/stringalloc.cpp \
common/string/strprintf.cpp \
+ common/string/strcache.cpp \
common/string/strspace.cpp \
common/string/strstrip.cpp \
common/string/strtonum.cpp \
@@ -441,6 +465,7 @@ RuntimeR3_SOURCES = \
common/zip/zip.cpp \
generic/createtemp-generic.cpp \
generic/critsect-generic.cpp \
+ generic/critsectrw-generic.cpp \
generic/env-generic.cpp \
generic/RTDirCreateUniqueNumbered-generic.cpp \
generic/RTEnvDupEx-generic.cpp \
@@ -454,16 +479,17 @@ RuntimeR3_SOURCES = \
generic/RTLogWriteStdErr-generic.cpp \
generic/RTLogWriteStdOut-generic.cpp \
generic/RTLogWriteUser-generic.cpp \
+ generic/RTPathIsSame-generic.cpp \
generic/RTProcessQueryUsernameA-generic.cpp \
generic/RTTimerLRCreate-generic.cpp \
generic/mempool-generic.cpp \
generic/semfastmutex-generic.cpp \
generic/semxroads-generic.cpp \
generic/spinlock-generic.cpp \
- generic/strcache-stubs-generic.cpp \
generic/timerlr-generic.cpp \
r3/alloc-ef.cpp \
r3/alloc.cpp \
+ r3/allocex.cpp \
r3/dir.cpp \
r3/dir2.cpp \
r3/fileio.cpp \
@@ -471,6 +497,7 @@ RuntimeR3_SOURCES = \
r3/init.cpp \
r3/isofs.cpp \
r3/path.cpp \
+ r3/poll.cpp \
r3/process.cpp \
r3/socket.cpp \
r3/stream.cpp \
@@ -478,7 +505,10 @@ RuntimeR3_SOURCES = \
r3/testi.cpp \
r3/tcp.cpp \
r3/udp.cpp \
- r3/generic/semspinmutex-r3-generic.cpp
+ r3/generic/semspinmutex-r3-generic.cpp \
+ r3/xml.cpp \
+ common/zip/xarvfs.cpp
+
#if1of ($(KBUILD_TARGET_ARCH),amd64 x86)
# RuntimeR3_SOURCES += common/time/timesupA.asm
@@ -501,6 +531,24 @@ ifdef IPRT_WITH_LZJB
RuntimeR3_SOURCES += common/misc/lzjb.c
endif
+# AMD64 / x86 assembly code.
+RuntimeR3_SOURCES.x86 += \
+ common/asm/ASMCpuIdExSlow.asm \
+ common/asm/ASMAtomicUoAndU64.asm \
+ common/asm/ASMAtomicUoAndU32.asm \
+ common/asm/ASMAtomicUoOrU64.asm \
+ common/asm/ASMAtomicUoOrU32.asm \
+ common/asm/ASMRdMsrEx.asm \
+ common/asm/ASMWrMsrEx.asm
+RuntimeR3_SOURCES.amd64 += \
+ common/asm/ASMCpuIdExSlow.asm \
+ common/asm/ASMAtomicUoAndU64.asm \
+ common/asm/ASMAtomicUoAndU32.asm \
+ common/asm/ASMAtomicUoOrU64.asm \
+ common/asm/ASMAtomicUoOrU32.asm \
+ common/asm/ASMRdMsrEx.asm \
+ common/asm/ASMWrMsrEx.asm
+
# Some versions of GCC might require this.
RuntimeR3_SOURCES.x86 += \
common/asm/ASMAtomicXchgU64.asm \
@@ -509,6 +557,7 @@ RuntimeR3_SOURCES.x86 += \
common/asm/ASMAtomicReadU64.asm \
common/asm/ASMAtomicUoReadU64.asm
+
ifdef IPRT_WITH_KSTUFF
RuntimeR3_SOURCES += \
common/ldr/ldrkStuff.cpp
@@ -528,6 +577,7 @@ RuntimeR3_SOURCES += \
endif
RuntimeR3_SOURCES.win = \
+ common/dbg/dbgmoddbghelp.cpp \
generic/cdrom-generic.cpp \
generic/RTDirExists-generic.cpp \
generic/RTDirQueryInfo-generic.cpp \
@@ -550,23 +600,26 @@ RuntimeR3_SOURCES.win = \
generic/RTProcIsRunningByName-generic.cpp \
generic/RTThreadGetNativeState-generic.cpp \
nt/RTErrConvertFromNtStatus.cpp \
- r3/posix/env-posix.cpp \
+ r3/nt/fs-nt.cpp \
+ r3/nt/pathint-nt.cpp \
+ r3/win/env-win.cpp \
r3/win/RTHandleGetStandard-win.cpp \
r3/win/RTSystemQueryOSInfo-win.cpp \
r3/win/RTSystemShutdown-win.cpp \
r3/win/RTSystemQueryDmiString-win.cpp \
r3/win/RTSystemQueryTotalRam-win.cpp \
r3/win/alloc-win.cpp \
+ r3/win/allocex-win.cpp \
r3/win/dir-win.cpp \
+ $(if-expr defined(VBOX_WITH_NT_DIRENUM),r3/nt/direnum-r3-nt.cpp,r3/win/direnum-win.cpp) \
r3/win/errvars-win.cpp \
r3/win/fileio-win.cpp \
- r3/win/fs-win.cpp \
+ r3/win/init-win.cpp \
r3/win/ldrNative-win.cpp \
r3/win/localipc-win.cpp \
r3/win/mp-win.cpp \
r3/win/path-win.cpp \
r3/win/pipe-win.cpp \
- r3/win/poll-win.cpp \
r3/win/process-win.cpp \
r3/win/RTLogWriteDebugger-win.cpp \
r3/win/rtProcInitExePath-win.cpp \
@@ -587,8 +640,8 @@ RuntimeR3_SOURCES.win = \
win/errmsgwin.cpp \
win/RTErrConvertFromWin32.cpp
-RuntimeR3_SOURCES.win.amd64 = $(RuntimeWin64ASM_SOURCES)
-RuntimeR3_SOURCES.win.x86 = $(RuntimeWin32ASM_SOURCES)
+RuntimeR3_SOURCES.win.amd64 := $(RuntimeWin64ASM_SOURCES)
+RuntimeR3_SOURCES.win.x86 := $(RuntimeWin32ASM_SOURCES)
RuntimeR3_SOURCES.linux = \
generic/cdrom-generic.cpp \
@@ -606,6 +659,7 @@ RuntimeR3_SOURCES.linux = \
generic/mppresent-generic.cpp \
generic/utf16locale-generic.cpp \
generic/uuid-generic.cpp \
+ r3/posix/allocex-r3-posix.cpp \
r3/linux/RTThreadGetNativeState-linux.cpp \
r3/linux/mp-linux.cpp \
r3/linux/rtProcInitExePath-linux.cpp \
@@ -640,7 +694,6 @@ RuntimeR3_SOURCES.linux = \
r3/posix/pathhost-posix.cpp \
r3/posix/RTPathUserDocuments-posix.cpp \
r3/posix/pipe-posix.cpp \
- r3/posix/poll-posix.cpp \
r3/posix/process-posix.cpp \
r3/posix/process-creation-posix.cpp \
r3/posix/rand-posix.cpp \
@@ -698,18 +751,21 @@ RuntimeR3_SOURCES.os2 = \
generic/timer-generic.cpp \
generic/utf16locale-generic.cpp \
generic/uuid-generic.cpp \
+ generic/RTMpGetCoreCount-generic.cpp \
+ generic/RTMpGetOnlineCoreCount-generic.cpp \
generic/RTMpGetCurFrequency-generic.cpp \
generic/RTMpGetMaxFrequency-generic.cpp \
generic/RTProcIsRunningByName-generic.cpp \
generic/RTThreadGetNativeState-generic.cpp \
os2/RTErrConvertFromOS2.cpp \
+ r3/generic/allocex-r3-generic.cpp \
r3/os2/filelock-os2.cpp \
r3/os2/mp-os2.cpp \
r3/os2/pipe-os2.cpp \
- r3/os2/poll-os2.cpp \
r3/os2/rtProcInitExePath-os2.cpp \
r3/os2/sched-os2.cpp \
r3/os2/sems-os2.cpp \
+ r3/os2/systemmem-os2.cpp \
r3/os2/thread-os2.cpp \
r3/os2/time-os2.cpp \
r3/posix/RTFileQueryFsSizes-posix.cpp \
@@ -757,6 +813,7 @@ RuntimeR3_SOURCES.darwin = \
generic/RTTimerCreate-generic.cpp \
generic/RTUuidCreate-generic.cpp \
generic/mppresent-generic.cpp \
+ generic/RTMpGetOnlineCoreCount-generic.cpp \
generic/RTSemEventMultiWait-2-ex-generic.cpp \
generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
generic/semrw-$(if-expr defined(VBOX_WITH_LOCKLESS_SEMRW),lockless-,)generic.cpp \
@@ -775,6 +832,7 @@ RuntimeR3_SOURCES.darwin = \
r3/darwin/systemmem-darwin.cpp \
r3/darwin/time-darwin.cpp \
r3/darwin/RTPathUserDocuments-darwin.cpp \
+ r3/generic/allocex-r3-generic.cpp \
r3/posix/RTFileQueryFsSizes-posix.cpp \
r3/posix/RTHandleGetStandard-posix.cpp \
r3/posix/RTMemProtect-posix.cpp \
@@ -794,7 +852,6 @@ RuntimeR3_SOURCES.darwin = \
r3/posix/path-posix.cpp \
r3/posix/path2-posix.cpp \
r3/posix/pipe-posix.cpp \
- r3/posix/poll-posix.cpp \
r3/posix/process-posix.cpp \
r3/posix/process-creation-posix.cpp \
r3/posix/rand-posix.cpp \
@@ -830,11 +887,14 @@ RuntimeR3_SOURCES.freebsd = \
generic/utf16locale-generic.cpp \
generic/uuid-generic.cpp \
generic/RTMpCpuId-generic.cpp \
+ generic/RTMpGetCoreCount-generic.cpp \
+ generic/RTMpGetOnlineCoreCount-generic.cpp \
generic/RTProcDaemonize-generic.cpp \
generic/RTProcIsRunningByName-generic.cpp \
generic/RTThreadGetNativeState-generic.cpp \
r3/freebsd/mp-freebsd.cpp \
r3/freebsd/rtProcInitExePath-freebsd.cpp \
+ r3/generic/allocex-r3-generic.cpp \
r3/posix/RTFileQueryFsSizes-posix.cpp \
r3/posix/RTHandleGetStandard-posix.cpp \
r3/posix/RTMemProtect-posix.cpp \
@@ -859,7 +919,6 @@ RuntimeR3_SOURCES.freebsd = \
r3/posix/pathhost-posix.cpp \
r3/posix/RTPathUserDocuments-posix.cpp \
r3/posix/pipe-posix.cpp \
- r3/posix/poll-posix.cpp \
r3/posix/process-posix.cpp \
r3/posix/process-creation-posix.cpp \
r3/posix/rand-posix.cpp \
@@ -886,7 +945,6 @@ RuntimeR3_SOURCES.solaris = \
generic/RTProcIsRunningByName-generic.cpp \
generic/RTSemEventMultiWait-2-ex-generic.cpp \
generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
- generic/RTSystemShutdown-generic.cpp \
generic/RTThreadSetAffinityToCpu-generic.cpp \
generic/RTTimeLocalNow-generic.cpp \
generic/RTTimerCreate-generic.cpp \
@@ -895,12 +953,12 @@ RuntimeR3_SOURCES.solaris = \
generic/utf16locale-generic.cpp \
generic/uuid-generic.cpp \
generic/RTThreadGetNativeState-generic.cpp \
+ r3/generic/allocex-r3-generic.cpp \
r3/posix/RTFileQueryFsSizes-posix.cpp \
r3/posix/RTHandleGetStandard-posix.cpp \
r3/posix/RTMemProtect-posix.cpp \
r3/posix/RTPathUserHome-posix.cpp \
r3/posix/RTSystemQueryOSInfo-posix.cpp \
- r3/posix/RTSystemQueryTotalRam-posix.cpp \
r3/posix/RTTimeNow-posix.cpp \
r3/posix/RTTimeSet-posix.cpp \
r3/posix/dir-posix.cpp \
@@ -919,7 +977,6 @@ RuntimeR3_SOURCES.solaris = \
r3/posix/pathhost-posix.cpp \
r3/posix/RTPathUserDocuments-posix.cpp \
r3/posix/pipe-posix.cpp \
- r3/posix/poll-posix.cpp \
r3/posix/process-posix.cpp \
r3/posix/process-creation-posix.cpp \
r3/posix/rand-posix.cpp \
@@ -935,8 +992,10 @@ RuntimeR3_SOURCES.solaris = \
r3/posix/timer-posix.cpp \
r3/posix/tls-posix.cpp \
r3/posix/utf8-posix.cpp \
+ r3/solaris/systemmem-solaris.cpp \
r3/solaris/mp-solaris.cpp \
r3/solaris/rtProcInitExePath-solaris.cpp \
+ r3/solaris/RTSystemShutdown-solaris.cpp \
r3/solaris/thread-affinity-solaris.cpp
RuntimeR3_SOURCES.solaris.amd64 = \
r3/solaris/coredumper-solaris.cpp \
@@ -949,75 +1008,66 @@ RuntimeR3_SOURCES.solaris.sparc32 = \
RuntimeR3_SOURCES.solaris.sparc64 = \
generic/RTSystemQueryDmiString-generic.cpp
-## PORTME: Porters add their selection of platform specific files for Ring-3 here.
-
-
-#
-# L4 RuntimeR3 subtarget since L4 headers won't work with VBOXR3.
-#
-RuntimeR3L4_TEMPLATE = VBOXR3NP
-RuntimeR3L4_DEFS = IN_RT_R3 IN_SUP_R3 LDR_WITH_NATIVE LDR_WITH_ELF LDR_WITH_PE
-ifneq ($(KBUILD_TARGET_ARCH),amd64)
-RuntimeR3L4_DEFS += __PIC__
-endif
-RuntimeR3L4_INCS = \
- include \
- $(L4_INCDIR)
-
-RuntimeR3L4_SOURCES = \
- generic/cdrom-generic.cpp \
- generic/errvars-generic.cpp \
- generic/fs-stubs-generic.cpp \
- generic/pathhost-generic.cpp \
+RuntimeR3_SOURCES.haiku = \
generic/RTDirQueryInfo-generic.cpp \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
generic/RTLogWriteDebugger-generic.cpp \
generic/RTProcDaemonize-generic.cpp \
- generic/RTSystemQueryOSInfo-generic.cpp \
- generic/RTSystemQueryDmiString-generic.cpp \
- generic/RTSystemShutdown-generic.cpp \
- generic/RTThreadGetAffinity-stub-generic.cpp \
- generic/RTThreadSetAffinity-stub-generic.cpp \
- generic/RTThreadSetAffinityToCpu-generic.cpp \
generic/RTTimeLocalNow-generic.cpp \
+ generic/RTTimerCreate-generic.cpp \
generic/RTUuidCreate-generic.cpp \
generic/mppresent-generic.cpp \
+ generic/RTSemEventMultiWait-2-ex-generic.cpp \
+ generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
generic/sched-generic.cpp \
- generic/RTSemEventWait-generic.cpp \
- generic/RTSemEventMultiWait-generic.cpp \
- generic/RTSemMutexRequest-generic.cpp \
- generic/RTSemMutexRequestDebug-generic.cpp \
- generic/semrw-$(if-expr defined(VBOX_WITH_LOCKLESS_SEMRW),lockless-,)generic.cpp \
+ generic/semrw-$(if-expr defined(VBOX_WITH_LOCKLESS_SEMRW),ockless-,)generic.cpp \
+ generic/timer-generic.cpp \
generic/utf16locale-generic.cpp \
- generic/uuid-generic.cpp \
+ generic/uuid-generic.cpp\
generic/RTProcIsRunningByName-generic.cpp \
generic/RTThreadGetNativeState-generic.cpp \
- l4/l4-errno.cpp \
- l4/rtProcInitExePath-l4.cpp \
- l4/process-l4env.cpp \
- l4/sems-l4env.cpp \
- l4/thread-l4env.cpp \
- l4/timer-l4env.cpp \
- l4/utf8-l4env.cpp \
+ generic/RTMpGetCoreCount-generic.cpp \
+ generic/RTMpGetOnlineCoreCount-generic.cpp \
+ r3/haiku/rtProcInitExePath-haiku.cpp \
+ r3/haiku/time-haiku.cpp \
+ r3/generic/allocex-r3-generic.cpp \
r3/posix/RTFileQueryFsSizes-posix.cpp \
+ r3/posix/RTHandleGetStandard-posix.cpp \
r3/posix/RTMemProtect-posix.cpp \
- r3/posix/rtmempage-exec-mmap-heap-posix.cpp \
r3/posix/RTPathUserHome-posix.cpp \
+ r3/posix/RTSystemQueryOSInfo-posix.cpp \
+ r3/posix/RTSystemQueryTotalRam-posix.cpp \
r3/posix/RTTimeNow-posix.cpp \
- r3/posix/RTTimeSet-posix.cpp \
r3/posix/dir-posix.cpp \
r3/posix/env-posix.cpp \
+ r3/posix/errvars-posix.cpp \
r3/posix/fileio-posix.cpp \
r3/posix/fileio2-posix.cpp \
r3/posix/filelock-posix.cpp \
+ r3/posix/fs-posix.cpp \
+ r3/posix/fs2-posix.cpp \
+ r3/posix/fs3-posix.cpp \
r3/posix/ldrNative-posix.cpp \
+ r3/posix/rtmempage-exec-mmap-heap-posix.cpp \
r3/posix/path-posix.cpp \
r3/posix/path2-posix.cpp \
- r3/posix/RTPathUserDocuments-posix.cpp \
+ r3/posix/pathhost-posix.cpp \
+ r3/posix/pipe-posix.cpp \
+ r3/posix/process-posix.cpp \
+ r3/posix/process-creation-posix.cpp \
r3/posix/rand-posix.cpp \
- r3/posix/time-posix.cpp \
- r3/posix/timelocal-posix.cpp
+ r3/posix/semevent-posix.cpp \
+ r3/posix/semeventmulti-posix.cpp \
+ r3/posix/semmutex-posix.cpp \
+ r3/posix/symlink-posix.cpp \
+ r3/posix/thread-posix.cpp \
+ r3/posix/thread2-posix.cpp \
+ r3/posix/timelocal-posix.cpp \
+ r3/posix/tls-posix.cpp \
+ r3/posix/utf8-posix.cpp
+
+## PORTME: Porters add their selection of platform specific files for Ring-3 here.
#
@@ -1031,11 +1081,16 @@ RuntimeBldProg_EXTENDS := RuntimeR3
RuntimeBldProg_BLD_TRG := $(KBUILD_HOST)
RuntimeBldProg_BLD_TRG_ARCH := $(KBUILD_HOST_ARCH)
RuntimeBldProg_BLD_TRG_CPU := $(KBUILD_HOST_CPU)
+RuntimeBldProg_SOURCES = $(filter-out \
+ r3/xml.cpp \
+ common/zip/xarvfs.cpp \
+ , $(RuntimeR3_SOURCES))
+
#
# RuntimeGuestR3 - Guest Additions Runtime (static/exe).
-# (The KBUILD_HOST inheritance here is for l4 cross building the linux
+# (The KBUILD_HOST inheritance here is for cross building the linux
# additions, while .x86 is for cross building x86 while targeting amd64.)
#
RuntimeGuestR3_TEMPLATE := VBoxGuestR3Lib
@@ -1043,7 +1098,7 @@ RuntimeGuestR3_TEMPLATE := VBoxGuestR3Lib
RuntimeGuestR3_SDKS.win := $(RuntimeR3_SDKS.win)
RuntimeGuestR3_DEFS := $(filter-out RTCRITSECT_STRICT RT_NO_GIP, $(RuntimeR3_DEFS))
RuntimeGuestR3_DEFS.$(KBUILD_TARGET) := $(RuntimeR3_DEFS.$(KBUILD_TARGET))
-RuntimeGuestR3_DEFS.$(KBUILD_HOST) := $(RuntimeR3_DEFS.$(KBUILD_HOST))
+RuntimeGuestR3_DEFS.$(KBUILD_HOST) := $(RuntimeR3_DEFS.$(KBUILD_HOST))
RuntimeGuestR3_INCS := $(RuntimeR3_INCS)
RuntimeGuestR3_INCS.$(KBUILD_TARGET) := $(RuntimeR3_INCS.$(KBUILD_TARGET))
RuntimeGuestR3_INCS.$(KBUILD_HOST) := $(RuntimeR3_INCS.$(KBUILD_HOST))
@@ -1052,8 +1107,11 @@ RuntimeGuestR3_SOURCES := $(filter-out \
common/time/timesupA.asm \
common/time/timesup.cpp \
common/checksum/RTSha1Digest.cpp \
+ common/checksum/RTSha256Digest.cpp \
common/checksum/sha% \
generic/RTLogWriteUser-generic.cpp \
+ r3/xml.cpp \
+ common/zip/xarvfs.cpp \
, $(RuntimeR3_SOURCES))
RuntimeGuestR3_SOURCES += \
common/time/timesysalias.cpp \
@@ -1126,6 +1184,7 @@ RuntimeGuestR3Mini_SOURCES = \
common/misc/buildconfig.cpp \
common/misc/sanity-c.c \
common/misc/sanity-cpp.cpp \
+ common/misc/sg.cpp \
common/path/rtPathVolumeSpecLen.cpp \
common/path/RTPathAbsDup.cpp \
common/path/RTPathAbsEx.cpp \
@@ -1138,7 +1197,7 @@ RuntimeGuestR3Mini_SOURCES = \
common/path/RTPathHasPath.cpp \
common/path/RTPathJoin.cpp \
common/path/RTPathJoinA.cpp \
- common/path/RTPathParse.cpp \
+ common/path/RTPathParseSimple.cpp \
common/path/RTPathRealDup.cpp \
common/path/RTPathStripExt.cpp \
common/path/RTPathStripFilename.cpp \
@@ -1229,49 +1288,42 @@ RuntimeGuestR3Mini_SOURCES += \
#
-# RuntimeLnxHostR3 Linux host program runtime
-# (Only used when building L4.)
-#
-RuntimeLnxHostR3_TEMPLATE = VBOXLNXHOSTR3LIB
-RuntimeLnxHostR3_DEFS = IN_RT_R3 IN_SUP_R3 RT_WITH_VBOX RT_NO_GIP
-RuntimeLnxHostR3_SOURCES = \
- $(RuntimeR3_SOURCES.linux.$(KBUILD_TARGET_ARCH)) \
- $(RuntimeR3_SOURCES.linux) \
- $(RuntimeR3_SOURCES)
-RuntimeLnxHostR3_INCS = \
- $(RuntimeR3_INCS.linux.$(KBUILD_TARGET_ARCH)) \
- $(RuntimeR3_INCS.linux) \
- $(RuntimeR3_INCS)
-
-
-#
# VBoxRT - Shared Object / DLL version.
#
VBoxRT_TEMPLATE = VBoxR3DllNoPic
-VBoxRT_SDKS = VBOX_OPENSSL VBOX_LIBXML2 VBOX_BOOST
+VBoxRT_SDKS = VBOX_LIBXML2
ifdef VBOX_WITH_LIBCURL
VBoxRT_SDKS += VBOX_LIBCURL
endif
+VBoxRT_SDKS += VBOX_OPENSSL
VBoxRT_SDKS.win = $(VBOX_WINPSDK) $(VBOX_WINDDK) VBOX_NTDLL
if1of ($(KBUILD_TARGET)$(VBOX_WITH_HARDENING), darwin win)
VBoxRT_INST = $(INST_DLL) $(INST_TESTCASE)
endif
-VBoxRT_DEFS = $(filter-out RT_NO_GIP,$(RuntimeR3_DEFS)) IN_SUP_R3 IN_SUP_R3
+VBoxRT_DEFS := $(filter-out RT_NO_GIP,$(RuntimeR3_DEFS)) IN_SUP_R3 IN_SUP_R3 IPRT_WITH_XAR
ifn1of ($(KBUILD_TARGET_ARCH), amd64 x86)
VBoxRT_DEFS += RT_NO_GIP
endif
-VBoxRT_DEFS.$(KBUILD_TYPE) = $(RuntimeR3_DEFS.$(KBUILD_TYPE))
-VBoxRT_SOURCES = \
+ifdef VBOX_WITH_LIBCURL
+ VBoxRT_DEFS += IPRT_WITH_HTTP
+endif
+VBoxRT_DEFS.$(KBUILD_TYPE) := $(RuntimeR3_DEFS.$(KBUILD_TYPE))
+VBoxRT_SOURCES := \
VBox/VBoxRTDeps.cpp \
- r3/xml.cpp \
$(filter-out common/checksum/crc32.cpp, $(RuntimeR3_SOURCES)) \
- common/checksum/crc32-zlib.cpp
+ common/checksum/crc32-zlib.cpp \
+ common/misc/aiomgr.cpp
ifdef VBOX_WITH_LIBCURL
VBoxRT_SOURCES += common/misc/s3.cpp
+ VBoxRT_SOURCES += common/misc/http.cpp
endif
VBoxRT_SOURCES.$(KBUILD_TARGET) = $(RuntimeR3_SOURCES.$(KBUILD_TARGET))
-VBoxRT_SOURCES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH) = $(RuntimeR3_SOURCES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))
-VBoxRT_SOURCES.$(KBUILD_TARGET_ARCH) = $(RuntimeR3_SOURCES.$(KBUILD_TARGET_ARCH))
+VBoxRT_SOURCES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH) := $(RuntimeR3_SOURCES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))
+VBoxRT_SOURCES.$(KBUILD_TARGET).x86 := $(RuntimeR3_SOURCES.$(KBUILD_TARGET).x86)
+VBoxRT_SOURCES.$(KBUILD_TARGET).amd64 := $(RuntimeR3_SOURCES.$(KBUILD_TARGET).amd64)
+VBoxRT_SOURCES.$(KBUILD_TARGET_ARCH) := $(RuntimeR3_SOURCES.$(KBUILD_TARGET_ARCH))
+VBoxRT_SOURCES.x86 := $(RuntimeR3_SOURCES.x86)
+VBoxRT_SOURCES.amd64 := $(RuntimeR3_SOURCES.amd64)
VBoxRT_SOURCES.win += \
r3/win/dllmain-win.cpp \
r3/win/fileaio-win.cpp \
@@ -1284,9 +1336,9 @@ VBoxRT_SOURCES.darwin += \
r3/posix/fileaio-posix.cpp
VBoxRT_SOURCES.freebsd += \
r3/freebsd/fileaio-freebsd.cpp
-VBoxRT_INCS = $(RuntimeR3_INCS)
-VBoxRT_INCS.$(KBUILD_TARGET) = $(RuntimeR3_INCS.$(KBUILD_TARGET))
-VBoxRT_INCS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH) = $(RuntimeR3_INCS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))
+VBoxRT_INCS := $(RuntimeR3_INCS)
+VBoxRT_INCS.$(KBUILD_TARGET) := $(RuntimeR3_INCS.$(KBUILD_TARGET))
+VBoxRT_INCS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH) := $(RuntimeR3_INCS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))
VBoxRT_LIBS = \
$(PATH_STAGE_LIB)/VBox-liblzf$(VBOX_SUFF_LIB)
if1of ($(KBUILD_TARGET_ARCH), amd64 x86)
@@ -1318,6 +1370,8 @@ VBoxRT_LIBS.darwin = \
VBoxRT_LIBS.freebsd = \
iconv \
rt
+VBoxRT_LIBS.haiku = \
+ iconv
VBoxRT_LIBS.solaris = \
kstat \
contract
@@ -1330,17 +1384,6 @@ VBoxRT_LIBS.win = \
$(PATH_SDK_$(VBOX_WINDDK)_LIB)/wbemuuid.lib
VBoxRT_LDFLAGS.darwin = -framework IOKit -framework CoreFoundation -framework CoreServices -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxRT.dylib
VBoxRT_LDFLAGS.win = /MANIFEST
-VBoxRT_LDFLAGS.l4 = \
- -Wl,-whole-archive \
- $(PATH_STAGE_LIB)/RuntimeR3L4$(VBOX_SUFF_LIB) \
- -Wl,-no-whole-archive
-ifeq ($(KBUILD_TARGET),l4)
-VBoxRT_LIBS += \
- $(L4_LIBDIR)/libl4sys.a \
- $(L4_LIBDIR)/libl4sys.p.a
-endif
-VBoxRT_LIBS.l4 = \
- $(PATH_STAGE_LIB)/RuntimeR3L4$(VBOX_SUFF_LIB)
if1of ($(DLLS), VBoxRT)
$$(VBoxRT_0_OUTDIR)/VBoxRT.def: \
@@ -1380,6 +1423,71 @@ endif # linux
#
+# VBoxRT-x86 - 32-bit version of VBoxRT
+#
+VBoxRT-x86_EXTENDS = VBoxRT
+VBoxRT-x86_TEMPLATE = VBoxR3Dll-x86
+VBoxRT-x86_SDKS = VBOX_LIBXML2
+ifdef VBOX_WITH_LIBCURL
+ VBoxRT-x86_SDKS += VBOX_LIBCURL-x86
+endif
+VBoxRT-x86_SDKS += VBOX_OPENSSL-x86
+
+VBoxRT-x86_LIBS = \
+ $(PATH_STAGE_LIB)/VBox-liblzf-x86$(VBOX_SUFF_LIB)
+if1of ($(KBUILD_TARGET_ARCH), amd64 x86)
+VBoxRT-x86_LIBS += \
+ $(PATH_STAGE_LIB)/SUPR3-x86$(VBOX_SUFF_LIB)
+endif
+ifdef IPRT_WITH_KSTUFF
+ VBoxRT-x86_LIBS += \
+ $(PATH_STAGE_LIB)/VBox-kStuff-x86$(VBOX_SUFF_LIB)
+endif
+ifndef SDK_VBOX_LIBXML2_LIBS
+ VBoxRT-x86_LIBS += \
+ $(PATH_STAGE_LIB)/VBox-libxml2-x86$(VBOX_SUFF_LIB)
+endif
+VBoxRT-x86_LIBS += \
+ $(SDK_VBOX_ZLIB_LIBS-x86)
+ifndef SDK_VBOX_OPENSSL_LIBS
+ VBoxRT-x86_LIBS += \
+ $(PATH_STAGE_LIB)/VBox-libcrypto-x86$(VBOX_SUFF_LIB) \
+ $(PATH_STAGE_LIB)/VBox-libssl-x86$(VBOX_SUFF_LIB)
+endif
+ifdef IPRT_WITH_LZO
+ VBoxRT-x86_LIBS += lzo2
+endif
+VBoxRT-x86_LIBS.linux = \
+ crypt
+VBoxRT-x86_LIBS.darwin = \
+ iconv
+VBoxRT-x86_LIBS.freebsd = \
+ iconv \
+ rt
+VBoxRT-x86_LIBS.haiku = \
+ iconv
+VBoxRT-x86_LIBS.solaris = \
+ kstat \
+ contract
+ifn1of ($(KBUILD_TARGET_ARCH), sparc32 sparc64)
+ # SMBIOS not available on Solaris SPARC.
+ VBoxRT-x86_LIBS.solaris += smbios
+endif
+VBoxRT-x86_LIBS.win = \
+ $(PATH_SDK_$(VBOX_WINDDK)_LIB.x86)/vccomsup.lib \
+ $(PATH_SDK_$(VBOX_WINDDK)_LIB.x86)/wbemuuid.lib
+
+VBoxRT-x86_SOURCES.win = $(filter-out %.def,$(VBoxRT_SOURCES.win)) \
+ $(VBoxRT-x86_0_OUTDIR)/VBoxRT-x86.def
+if1of ($(DLLS), VBoxRT-x86)
+$$(VBoxRT-x86_0_OUTDIR)/VBoxRT-x86.def: \
+ $(PATH_SUB_CURRENT)/r3/win/VBoxRT-win32.def \
+ $(PATH_SUB_CURRENT)/r3/win/$(if $(VBOX_OSE),VBoxRT-openssl-ose.def,VBoxRT-openssl.def)
+ $(RM) -f -- $@
+ $(REDIRECT) -wto $@ -- $(CAT_EXT) $^
+endif
+
+#
# VBoxRTImp - Import library/hack.
#
ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),win.amd64)
@@ -1401,8 +1509,8 @@ RuntimeR3NoCRTGCC_LIBSUFF = $(VBOX_SUFF_LIB)
ifn1of ($(KBUILD_TARGET_ARCH), amd64 x86)
RuntimeR3NoCRTGCC_DEFS += RT_NO_GIP
endif
-RuntimeR3NoCRTGCC_INCS = include
-RuntimeR3NoCRTGCC_SOURCES = \
+RuntimeR3NoCRTGCC_INCS = include
+RuntimeR3NoCRTGCC_SOURCES := \
common/misc/sanity-cpp.cpp \
common/misc/sanity-c.c \
\
@@ -1479,7 +1587,7 @@ ifn1of ($(KBUILD_TARGET_ARCH), amd64 x86)
RuntimeR0_DEFS += RT_NO_GIP
endif
RuntimeR0_INCS = include
-RuntimeR0_SOURCES = \
+RuntimeR0_SOURCES := \
common/log/logellipsis.cpp \
common/log/logrelellipsis.cpp \
common/log/logcom.cpp \
@@ -1554,14 +1662,31 @@ RuntimeR0_SOURCES += \
common/math/gcc/xordi3.c
endif
+RuntimeR0_SOURCES.x86 += \
+ common/asm/ASMCpuIdExSlow.asm \
+ common/asm/ASMAtomicUoAndU64.asm \
+ common/asm/ASMAtomicUoAndU32.asm \
+ common/asm/ASMAtomicUoOrU64.asm \
+ common/asm/ASMAtomicUoOrU32.asm \
+ common/asm/ASMRdMsrEx.asm \
+ common/asm/ASMWrMsrEx.asm
+RuntimeR0_SOURCES.amd64 += \
+ common/asm/ASMCpuIdExSlow.asm \
+ common/asm/ASMAtomicUoAndU64.asm \
+ common/asm/ASMAtomicUoAndU32.asm \
+ common/asm/ASMAtomicUoOrU64.asm \
+ common/asm/ASMAtomicUoOrU32.asm \
+ common/asm/ASMRdMsrEx.asm \
+ common/asm/ASMWrMsrEx.asm
+
#if1of ($(KBUILD_TARGET_ARCH),amd64 x86)
# RuntimeR0_SOURCES += common/time/timesupA.asm
#else
RuntimeR0_SOURCES += common/time/timesupref.cpp
#endif
-RuntimeR0_SOURCES.win.amd64 = $(RuntimeWin64ASM_SOURCES)
-RuntimeR0_SOURCES.win.x86 = $(RuntimeWin32ASM_SOURCES)
+RuntimeR0_SOURCES.win.amd64 := $(RuntimeWin64ASM_SOURCES)
+RuntimeR0_SOURCES.win.x86 := $(RuntimeWin32ASM_SOURCES)
RuntimeR0_SOURCES.win = \
nt/NtProcessStartup-stub.cpp
@@ -1642,7 +1767,7 @@ RuntimeR0Drv_SOURCES = \
common/path/RTPathFilename.cpp \
common/path/RTPathHasExt.cpp \
common/path/RTPathHasPath.cpp \
- common/path/RTPathParse.cpp \
+ common/path/RTPathParseSimple.cpp \
common/path/RTPathRealDup.cpp \
common/path/RTPathStripExt.cpp \
common/path/RTPathStripFilename.cpp \
@@ -1690,11 +1815,20 @@ RuntimeR0Drv_SOURCES = \
r0drv/generic/semspinmutex-r0drv-generic.c \
VBox/log-vbox.cpp \
+RuntimeR0Drv_SOURCES.amd64 = \
+ common/asm/ASMRdMsrEx.asm \
+ common/asm/ASMWrMsrEx.asm
+RuntimeR0Drv_SOURCES.x86 = \
+ common/asm/ASMRdMsrEx.asm \
+ common/asm/ASMWrMsrEx.asm
+
+
RuntimeR0Drv_SOURCES.linux = \
common/misc/thread.cpp \
common/string/strpbrk.cpp \
generic/RTAssertShouldPanic-generic.cpp \
generic/RTLogWriteStdOut-stub-generic.cpp \
+ generic/RTMpGetCoreCount-generic.cpp \
generic/mppresent-generic.cpp \
r0drv/linux/alloc-r0drv-linux.c \
r0drv/linux/assert-r0drv-linux.c \
@@ -1712,6 +1846,7 @@ RuntimeR0Drv_SOURCES.linux = \
r0drv/linux/spinlock-r0drv-linux.c \
r0drv/linux/thread-r0drv-linux.c \
r0drv/linux/thread2-r0drv-linux.c \
+ r0drv/linux/threadctxhooks-r0drv-linux.c \
r0drv/linux/time-r0drv-linux.c \
r0drv/linux/timer-r0drv-linux.c \
r0drv/memobj-r0drv.cpp \
@@ -1732,7 +1867,9 @@ RuntimeR0Drv_SOURCES.win = \
generic/RTLogWriteStdOut-stub-generic.cpp \
generic/RTTimerCreate-generic.cpp \
generic/mppresent-generic.cpp \
+ generic/RTMpGetCoreCount-generic.cpp \
nt/RTErrConvertFromNtStatus.cpp \
+ r0drv/generic/threadctxhooks-r0drv-generic.cpp \
r0drv/memobj-r0drv.cpp \
r0drv/mpnotification-r0drv.c \
r0drv/powernotification-r0drv.c \
@@ -1756,8 +1893,8 @@ RuntimeR0Drv_SOURCES.win = \
r0drv/nt/timer-r0drv-nt.cpp \
r0drv/nt/RTTimerGetSystemGranularity-r0drv-nt.cpp
-RuntimeR0Drv_SOURCES.win.amd64 = $(RuntimeWin64ASM_SOURCES)
-RuntimeR0Drv_SOURCES.win.x86 = $(RuntimeWin32ASM_SOURCES)
+RuntimeR0Drv_SOURCES.win.amd64 := $(RuntimeWin64ASM_SOURCES)
+RuntimeR0Drv_SOURCES.win.x86 := $(RuntimeWin32ASM_SOURCES)
RuntimeR0Drv_SOURCES.darwin = \
common/misc/thread.cpp \
@@ -1768,9 +1905,11 @@ RuntimeR0Drv_SOURCES.darwin = \
darwin/RTErrConvertFromDarwinKern.cpp \
generic/RTAssertShouldPanic-generic.cpp \
generic/RTTimerCreate-generic.cpp \
+ generic/RTMpGetCoreCount-generic.cpp \
generic/mppresent-generic.cpp \
generic/timer-generic.cpp \
r0drv/generic/mpnotification-r0drv-generic.cpp \
+ r0drv/generic/threadctxhooks-r0drv-generic.cpp \
r0drv/darwin/alloc-r0drv-darwin.cpp \
r0drv/darwin/assert-r0drv-darwin.cpp \
r0drv/darwin/initterm-r0drv-darwin.cpp \
@@ -1830,6 +1969,7 @@ RuntimeR0Drv_SOURCES.os2 = \
r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp \
r0drv/generic/RTMpOn-r0drv-generic.cpp \
r0drv/generic/mpnotification-r0drv-generic.cpp \
+ r0drv/generic/threadctxhooks-r0drv-generic.cpp \
r0drv/memobj-r0drv.cpp \
r0drv/powernotification-r0drv.c \
r0drv/os2/alloc-r0drv-os2.cpp \
@@ -1867,6 +2007,7 @@ RuntimeR0Drv_SOURCES.freebsd = \
generic/mppresent-generic.cpp \
r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp \
r0drv/generic/mpnotification-r0drv-generic.cpp \
+ r0drv/generic/threadctxhooks-r0drv-generic.cpp \
r0drv/freebsd/alloc-r0drv-freebsd.c \
r0drv/freebsd/assert-r0drv-freebsd.c \
r0drv/freebsd/initterm-r0drv-freebsd.c \
@@ -1891,6 +2032,7 @@ RuntimeR0Drv_SOURCES.solaris = \
common/string/memchr.asm \
generic/RTAssertShouldPanic-generic.cpp \
generic/RTLogWriteStdOut-stub-generic.cpp \
+ generic/RTMpGetCoreCount-generic.cpp \
generic/RTTimerCreate-generic.cpp \
generic/mppresent-generic.cpp \
r0drv/memobj-r0drv.cpp \
@@ -1914,9 +2056,42 @@ RuntimeR0Drv_SOURCES.solaris = \
r0drv/solaris/spinlock-r0drv-solaris.c \
r0drv/solaris/thread-r0drv-solaris.c \
r0drv/solaris/thread2-r0drv-solaris.c \
+ r0drv/solaris/threadctxhooks-r0drv-solaris.c \
r0drv/solaris/time-r0drv-solaris.c \
r0drv/solaris/timer-r0drv-solaris.c
+RuntimeR0Drv_SOURCES.haiku = \
+ common/misc/thread.cpp \
+ common/string/memchr.asm \
+ common/string/memmove.asm \
+ common/string/strpbrk.cpp \
+ common/string/memcmp.asm \
+ common/string/strchr.asm \
+ generic/RTAssertShouldPanic-generic.cpp \
+ generic/RTTimerCreate-generic.cpp \
+ generic/mppresent-generic.cpp \
+ r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp \
+ r0drv/generic/mpnotification-r0drv-generic.cpp \
+ r0drv/generic/threadctxhooks-r0drv-generic.cpp \
+ r0drv/haiku/alloc-r0drv-haiku.c \
+ r0drv/haiku/assert-r0drv-haiku.c \
+ r0drv/haiku/initterm-r0drv-haiku.c \
+ r0drv/haiku/memobj-r0drv-haiku.c \
+ r0drv/haiku/mp-r0drv-haiku.c \
+ r0drv/haiku/process-r0drv-haiku.c \
+ r0drv/haiku/RTLogWriteDebugger-r0drv-haiku.c \
+ r0drv/haiku/RTLogWriteStdOut-r0drv-haiku.c \
+ r0drv/haiku/semevent-r0drv-haiku.c \
+ r0drv/haiku/semeventmulti-r0drv-haiku.c \
+ r0drv/haiku/semfastmutex-r0drv-haiku.c \
+ r0drv/haiku/semmutex-r0drv-haiku.c \
+ r0drv/haiku/spinlock-r0drv-haiku.c \
+ r0drv/haiku/thread-r0drv-haiku.c \
+ r0drv/haiku/thread2-r0drv-haiku.c \
+ r0drv/haiku/time-r0drv-haiku.c \
+ generic/timer-generic.cpp \
+ r0drv/memobj-r0drv.cpp \
+ r0drv/powernotification-r0drv.c
## PORTME: Porters create and add their selection of platform specific Ring-0 Driver files here.
@@ -1953,7 +2128,7 @@ ifdef VBOX_WITH_RAW_MODE
RuntimeRC_TEMPLATE = VBoxRc
RuntimeRC_DEFS = IN_RT_RC RT_WITH_VBOX
RuntimeRC_INCS = include
- RuntimeRC_SOURCES = \
+ RuntimeRC_SOURCES := \
common/checksum/crc32.cpp \
common/checksum/crc64.cpp \
common/checksum/md5.cpp \
@@ -2055,14 +2230,14 @@ endif # VBOX_WITH_RAW_MODE
#
# Static library for new & delete for the electric fence.
#
-RuntimeEFCPP_TEMPLATE = $(VBoxRT_TEMPLATE)
-RuntimeEFCPP_SDKS = $(RuntimeR3_SDKS)
-RuntimeEFCPP_SDKS.$(KBUILD_TARGET) = $(RuntimeR3_SDKS.$(KBUILD_TARGET))
-RuntimeEFCPP_DEFS = $(RuntimeR3_DEFS)
-RuntimeEFCPP_DEFS.$(KBUILD_TARGET) = $(RuntimeR3_DEFS.$(KBUILD_TARGET))
-RuntimeEFCPP_INCS = $(RuntimeR3_INCS)
-RuntimeEFCPP_INCS.$(KBUILD_TARGET) = $(RuntimeR3_INCS.$(KBUILD_TARGET))
-RuntimeEFCPP_SOURCES = r3/alloc-ef-cpp.cpp
+RuntimeEFCPP_TEMPLATE := $(VBoxRT_TEMPLATE)
+RuntimeEFCPP_SDKS := $(RuntimeR3_SDKS)
+RuntimeEFCPP_SDKS.$(KBUILD_TARGET) := $(RuntimeR3_SDKS.$(KBUILD_TARGET))
+RuntimeEFCPP_DEFS := $(RuntimeR3_DEFS)
+RuntimeEFCPP_DEFS.$(KBUILD_TARGET) := $(RuntimeR3_DEFS.$(KBUILD_TARGET))
+RuntimeEFCPP_INCS := $(RuntimeR3_INCS)
+RuntimeEFCPP_INCS.$(KBUILD_TARGET) := $(RuntimeR3_INCS.$(KBUILD_TARGET))
+RuntimeEFCPP_SOURCES := r3/alloc-ef-cpp.cpp
@@ -2090,6 +2265,16 @@ RuntimeR3NtDll-x86_ARFLAGS = /NODEFAULTLIB /MACHINE:x86
#
+# Bag of tricks required for making VCC100 output binaries work on NT4, W2K
+# early XP and early W2K3.
+#
+RuntimeR3VccTricks_TEMPLATE = VBoxR3Dll
+RuntimeR3VccTricks_SOURCES = \
+ r3/win/vcc100-kernel32-fakes.cpp \
+ r3/win/vcc100-kernel32-fakesA.asm
+
+
+#
# errmsg.cpp depends on a generated header.
#
common/err/errmsg.cpp_DEPS = $(IPRT_OUT_DIR)/errmsgdata.h
@@ -2104,7 +2289,7 @@ define def_errmsgwin_deps
$(lib)_common/err/errmsgxpcom.cpp_INCS = $(IPRT_OUT_DIR)
$(lib)_common/err/errmsgxpcom.cpp_DEPS = $(IPRT_OUT_DIR)/errmsgvboxcomdata.h
endef
-$(foreach lib,RuntimeR3 RuntimeBldProg VBoxRT RuntimeLnxHostR3,$(eval $(def_errmsgwin_deps)))
+$(foreach lib,RuntimeR3 RuntimeBldProg VBoxRT VBoxRT-x86,$(eval $(def_errmsgwin_deps)))
#
@@ -2216,10 +2401,11 @@ IPRT_DOXYFILE_INPUT_DIRS = \
$(foreach dir, $(VBOX_PATH_RUNTIME_SRC) $(VBOX_PATH_RUNTIME_SRC)/r3 $(VBOX_PATH_RUNTIME_SRC)/r0drv,\
$(dir) \
$(dir)/darwin \
- $(dir)/l4 \
+ $(dir)/haiku \
$(dir)/linux \
$(dir)/nt \
$(dir)/os2 \
+ $(dir)/solaris \
$(dir)/win \
$(dir)/win32 \
$(dir)/win64 \
@@ -2350,10 +2536,19 @@ if1of ($(LIBRARIES),RuntimeR3 RuntimeR0 RuntimeR0Drv RuntimeRC)
-e '/^strncpy/d' \
-e '/^strlen/d' \
-e '/^_Z[[:alpha:]]*[[:digit:]]\+RTC/d' \
- \
+ -e '/^_Z[[:alpha:]]*[[:digit:]]\+RTC/d' \
+ \
+ -e '/^_ZnwjPv/d' \
+ -e '/^_ZnwmPv/d' \
-e '/^_ZNSt9bad_allocC1Ev/d' \
-e '/^_ZNSt9exceptionC2Ev/d' \
+ -e '/^_ZNSt9exceptionC[12]ERKS_/d' \
\
+ -e '/^_ZN[a-zA-Z]*St[[:digit:]]*_*[lL]ist/d' \
+ -e '/^_ZN[a-zA-Z]*[[:digit:]]*__gnu_cxx/d' \
+ -e '/^_ZNSa.*ElementNode.*/d' \
+ -e '/^_ZSt.*ElementNode.*/d' \
+ \
-e '/^_Z[[:digit:]]\+dbus/d' \
-e '/^_Z13RTDBusLoadLibv/d' \
\
@@ -2388,6 +2583,15 @@ if1of ($(LIBRARIES),RuntimeR3 RuntimeR0 RuntimeR0Drv RuntimeRC)
endif
$(QUIET)$(APPEND) -t $@
+if !defined(VBOX_ONLY_ADDITIONS) && !defined(VBOX_ONLY_TESTSUITE) && !defined(VBOX_ONLY_DOCS)
+#
+# Windows build tool.
+#
+BLDPROGS.win += ntBldSymDb
+ntBldSymDb_TEMPLATE = VBoxAdvBldProg
+ntBldSymDb_INCS = .
+ntBldSymDb_SOURCES = r0drv/nt/ntBldSymDb.cpp
+endif
#
# Generate the rules (we're the to sub-makefile).
diff --git a/src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp b/src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp
index a0d6476e..d6712e29 100644
--- a/src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp
+++ b/src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/VBox/VBoxRTDeps.cpp b/src/VBox/Runtime/VBox/VBoxRTDeps.cpp
index f88e8fee..61e86d9f 100644
--- a/src/VBox/Runtime/VBox/VBoxRTDeps.cpp
+++ b/src/VBox/Runtime/VBox/VBoxRTDeps.cpp
@@ -35,7 +35,7 @@
#include <iprt/buildconfig.h>
#include <iprt/system.h>
-#include <libxml/xmlmodule.h>
+#include <libxml/catalog.h>
#include <libxml/globals.h>
#include <openssl/md5.h>
#include <openssl/rc4.h>
@@ -57,7 +57,7 @@ PFNRT g_VBoxRTDeps[] =
(PFNRT)SUPSemEventCreate,
(PFNRT)SUPTracerFireProbe,
#endif
- (PFNRT)xmlModuleOpen,
+ (PFNRT)xmlLoadCatalogs,
(PFNRT)MD5_Init,
(PFNRT)RC4,
(PFNRT)RC4_set_key,
diff --git a/src/VBox/Runtime/VBox/VBoxRTImp.def b/src/VBox/Runtime/VBox/VBoxRTImp.def
index 70637b43..d7c1c0d8 100644
--- a/src/VBox/Runtime/VBox/VBoxRTImp.def
+++ b/src/VBox/Runtime/VBox/VBoxRTImp.def
@@ -3,7 +3,7 @@
; VirtualBox Runtime DLL - Stable Interface Definition file.
;
-; Copyright (C) 2010 Oracle Corporation
+; Copyright (C) 2010-2012 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -663,6 +663,7 @@ EXPORTS
RTManifestVerify
RTManifestVerifyFiles
RTManifestVerifyFilesBuf
+ RTManifestVerifyDigestType
RTManifestWriteFiles
RTManifestWriteFilesBuf
RTManifestWriteStandard
@@ -802,7 +803,7 @@ EXPORTS
RTPathJoin
RTPathJoinA
RTPathJoinEx
- RTPathParse
+ RTPathParseSimple
RTPathQueryInfo
RTPathQueryInfoEx
RTPathReal
@@ -887,17 +888,19 @@ EXPORTS
RTRandU32Ex
RTRandU64
RTRandU64Ex
- RTReqAlloc
- RTReqCall
- RTReqCallEx
- RTReqCallV
- RTReqCallVoid
- RTReqCreateQueue
- RTReqDestroyQueue
- RTReqFree
- RTReqIsBusy
- RTReqProcess
- RTReqQueue
+ RTReqQueueAlloc
+ RTReqQueueCall
+ RTReqQueueCallEx
+ RTReqQueueCallV
+ RTReqQueueCallVoid
+ RTReqQueueCreate
+ RTReqQueueDestroy
+ RTReqQueueIsBusy
+ RTReqQueueProcess
+ RTReqGetStatus
+ RTReqRelease
+ RTReqRetain
+ RTReqSubmit
RTReqWait
RTS3BucketsDestroy
RTS3Create
@@ -1007,6 +1010,8 @@ EXPORTS
RTSha256Init
RTSha256ToString
RTSha256Update
+ RTSha256Digest
+ RTSha256DigestFromFile
RTSha512
RTSha512Final
RTSha512FromString
@@ -1473,3 +1478,9 @@ EXPORTS
RTZipTarCmd
RTZipTarFsStreamFromIoStream
+ ; Support library
+ SUPR3HardenedLdrLoad
+ SUPR3HardenedLdrLoadAppPriv
+ SUPR3HardenedLdrLoadPlugIn
+ SUPR3QueryVTxSupported
+ SUPR3QueryVTCaps
diff --git a/src/VBox/Runtime/VBox/dbus.cpp b/src/VBox/Runtime/VBox/dbus.cpp
index 1e8ce844..70e6374e 100644
--- a/src/VBox/Runtime/VBox/dbus.cpp
+++ b/src/VBox/Runtime/VBox/dbus.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/VBox/errmsgvboxcom.xsl b/src/VBox/Runtime/VBox/errmsgvboxcom.xsl
index 71854521..03dea8bf 100644
--- a/src/VBox/Runtime/VBox/errmsgvboxcom.xsl
+++ b/src/VBox/Runtime/VBox/errmsgvboxcom.xsl
@@ -6,7 +6,7 @@
* %Rhrc format specifier) as they are defined in the VirtualBox interface
* definition file (src/VBox/Main/idl/VirtualBox.xidl).
- Copyright (C) 2006-2008 Oracle Corporation
+ Copyright (C) 2006-2012 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/VBox/log-vbox.cpp b/src/VBox/Runtime/VBox/log-vbox.cpp
index 4403648d..390a9a53 100644
--- a/src/VBox/Runtime/VBox/log-vbox.cpp
+++ b/src/VBox/Runtime/VBox/log-vbox.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -137,13 +137,13 @@
# include <sys/user.h>
# include <stdlib.h>
# include <unistd.h>
+# elif defined(RT_OS_HAIKU)
+# include <OS.h>
# elif defined(RT_OS_SOLARIS)
# define _STRUCTURED_PROC 1
# undef _FILE_OFFSET_BITS /* procfs doesn't like this */
# include <sys/procfs.h>
# include <unistd.h>
-# elif defined(RT_OS_L4)
-# include <l4/vboxserver/vboxserver.h>
# elif defined(RT_OS_OS2)
# include <stdlib.h>
# endif
@@ -162,6 +162,10 @@
# include <iprt/mem.h>
# include <stdio.h>
#endif
+#if defined(IN_RING0) && defined(RT_OS_DARWIN)
+# include <iprt/asm-amd64-x86.h>
+# include <iprt/thread.h>
+#endif
/*******************************************************************************
@@ -251,8 +255,9 @@ RTDECL(PRTLOGGER) RTLogDefaultInit(void)
ASSERT_LOG_GROUP(EM);
ASSERT_LOG_GROUP(GUI);
ASSERT_LOG_GROUP(HGCM);
- ASSERT_LOG_GROUP(HWACCM);
+ ASSERT_LOG_GROUP(HM);
ASSERT_LOG_GROUP(IOM);
+ ASSERT_LOG_GROUP(LWIP);
ASSERT_LOG_GROUP(MAIN);
ASSERT_LOG_GROUP(MM);
ASSERT_LOG_GROUP(MM_HEAP);
@@ -368,6 +373,14 @@ RTDECL(PRTLOGGER) RTLogDefaultInit(void)
fclose(pFile);
}
+# elif defined(RT_OS_HAIKU)
+ team_info info;
+ if (get_team_info(0, &info) == B_OK)
+ {
+ /* there is an info.argc, but no way to know arg boundaries */
+ RTLogLoggerEx(pLogger, 0, ~0U, "Commandline: %.64s\n", info.args);
+ }
+
# elif defined(RT_OS_FREEBSD)
/* Retrieve the required length first */
int aiName[4];
@@ -402,7 +415,7 @@ RTDECL(PRTLOGGER) RTLogDefaultInit(void)
}
}
-# elif defined(RT_OS_L4) || defined(RT_OS_OS2) || defined(RT_OS_DARWIN)
+# elif defined(RT_OS_OS2) || defined(RT_OS_DARWIN)
/* commandline? */
# else
# error needs porting.
@@ -415,6 +428,15 @@ RTDECL(PRTLOGGER) RTLogDefaultInit(void)
# endif /* IN_GUEST */
#else /* IN_RING0 */
+
+ /* Some platforms has trouble allocating memory with interrupts and/or
+ preemption disabled. Check and fail before we panic. */
+# if defined(RT_OS_DARWIN)
+ if ( !ASMIntAreEnabled()
+ || !RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+ return NULL;
+# endif
+
# ifndef IN_GUEST
rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_FILE, "VBox-ring0.log");
# else /* IN_GUEST */
@@ -461,8 +483,8 @@ RTDECL(PRTLOGGER) RTLogDefaultInit(void)
RTLogFlags(pLogger, "enabled unbuffered");
pLogger->fDestFlags |= RTLOGDEST_DEBUGGER;
# endif
-# if defined(DEBUG_leo) /* Guest ring-0 as well */
- RTLogGroupSettings(pLogger, "+drv_mouse.e.l.f+drv_miniport.e.l.f+drv_display.e.l.f");
+# if defined(DEBUG_michael) && defined(IN_GUEST)
+ RTLogGroupSettings(pLogger, "+all.e.l.f");
RTLogFlags(pLogger, "enabled unbuffered");
pLogger->fDestFlags |= RTLOGDEST_DEBUGGER;
# endif
diff --git a/src/VBox/Runtime/VBox/logbackdoor.cpp b/src/VBox/Runtime/VBox/logbackdoor.cpp
index 99d4485d..956d8a49 100644
--- a/src/VBox/Runtime/VBox/logbackdoor.cpp
+++ b/src/VBox/Runtime/VBox/logbackdoor.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/alloc/alloc.cpp b/src/VBox/Runtime/common/alloc/alloc.cpp
index 585a22f6..d4709446 100644
--- a/src/VBox/Runtime/common/alloc/alloc.cpp
+++ b/src/VBox/Runtime/common/alloc/alloc.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/alloc/heapoffset.cpp b/src/VBox/Runtime/common/alloc/heapoffset.cpp
index 2cd8697a..f593b66f 100644
--- a/src/VBox/Runtime/common/alloc/heapoffset.cpp
+++ b/src/VBox/Runtime/common/alloc/heapoffset.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/alloc/heapsimple.cpp b/src/VBox/Runtime/common/alloc/heapsimple.cpp
index 7e680132..015be043 100644
--- a/src/VBox/Runtime/common/alloc/heapsimple.cpp
+++ b/src/VBox/Runtime/common/alloc/heapsimple.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/alloc/memcache.cpp b/src/VBox/Runtime/common/alloc/memcache.cpp
index 57282102..43285e67 100644
--- a/src/VBox/Runtime/common/alloc/memcache.cpp
+++ b/src/VBox/Runtime/common/alloc/memcache.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -122,6 +122,8 @@ typedef struct RTMEMCACHEINT
bool fUseFreeList;
/** Head of the page list. */
PRTMEMCACHEPAGE pPageHead;
+ /** Poiner to the insertion point in the page list. */
+ PRTMEMCACHEPAGE volatile *ppPageNext;
/** Constructor callback. */
PFNMEMCACHECTOR pfnCtor;
/** Destructor callback. */
@@ -141,8 +143,8 @@ typedef struct RTMEMCACHEINT
* These are marked as used in the allocation bitmaps.
*
* @todo This doesn't scale well when several threads are beating on the
- * cache. Also, it totally doesn't work when we've got a
- * constructor/destructor around or the objects are too small. */
+ * cache. Also, it totally doesn't work when the objects are too
+ * small. */
PRTMEMCACHEFREEOBJ volatile pFreeTop;
} RTMEMCACHEINT;
@@ -209,6 +211,7 @@ RTDECL(int) RTMemCacheCreate(PRTMEMCACHE phMemCache, size_t cbObject, size_t cbA
&& !pfnCtor
&& !pfnDtor;
pThis->pPageHead = NULL;
+ pThis->ppPageNext = &pThis->pPageHead;
pThis->pfnCtor = pfnCtor;
pThis->pfnDtor = pfnDtor;
pThis->pvUser = pvUser;
@@ -244,7 +247,8 @@ RTDECL(int) RTMemCacheDestroy(RTMEMCACHE hMemCache)
return VINF_SUCCESS;
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertReturn(pThis->u32Magic == RTMEMCACHE_MAGIC, VERR_INVALID_HANDLE);
-#ifdef RT_STRICT
+
+#if 0 /*def RT_STRICT - don't require eveything to be freed. Caches are very convenient for lazy cleanup. */
uint32_t cFree = pThis->cFree;
for (PRTMEMCACHEFREEOBJ pFree = pThis->pFreeTop; pFree && cFree < pThis->cTotal + 5; pFree = pFree->pNext)
cFree++;
@@ -332,16 +336,9 @@ static int rtMemCacheGrow(RTMEMCACHEINT *pThis)
/* Make it the hint. */
ASMAtomicWritePtr(&pThis->pPageHint, pPage);
- /* Link the page. */
- PRTMEMCACHEPAGE pPrevPage = pThis->pPageHead;
- if (!pPrevPage)
- ASMAtomicWritePtr(&pThis->pPageHead, pPage);
- else
- {
- while (pPrevPage->pNext)
- pPrevPage = pPrevPage->pNext;
- ASMAtomicWritePtr(&pPrevPage->pNext, pPage);
- }
+ /* Link the page in at the end of the list. */
+ ASMAtomicWritePtr(pThis->ppPageNext, pPage);
+ pThis->ppPageNext = &pPage->pNext;
/* Add it to the page counts. */
ASMAtomicAddS32(&pThis->cFree, cObjects);
@@ -547,8 +544,7 @@ RTDECL(void) RTMemCacheFree(RTMEMCACHE hMemCache, void *pvObj)
}
else
{
- /* Note: Do *NOT* attempt to poison the object if we have a constructor
- or/and destructor! */
+ /* Note: Do *NOT* attempt to poison the object! */
/*
* Find the cache page. The page structure is at the start of the page.
diff --git a/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgExU64.asm b/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgExU64.asm
index da71254e..f6963e1f 100644
--- a/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgExU64.asm
+++ b/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgExU64.asm
@@ -36,8 +36,8 @@ BEGINCODE
;
; @param pu64 x86:ebp+8 gcc:rdi msc:rcx
; @param u64New x86:ebp+c gcc:rsi msc:rdx
-; @param u64Old x86:ebp+14 gcc:rcx msc:r8
-; @param u64Old x86:ebp+1c gcc:rdx msc:r9
+; @param u64Old x86:ebp+14 gcc:rdx msc:r8
+; @param pu64Old x86:ebp+1c gcc:rcx msc:r9
;
; @returns bool result: true if successfully exchanged, false if not.
; x86:al
@@ -49,9 +49,9 @@ BEGINPROC_EXPORTED ASMAtomicCmpXchgExU64
lock cmpxchg [rcx], rdx
mov [r9], rax
%else
- mov rax, rcx
+ mov rax, rdx
lock cmpxchg [rdi], rsi
- mov [rdx], rax
+ mov [rcx], rax
%endif
setz al
movzx eax, al
diff --git a/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU64.asm b/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU64.asm
index d6ee4d69..0474644c 100644
--- a/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU64.asm
+++ b/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU64.asm
@@ -36,7 +36,7 @@ BEGINCODE
;
; @param pu64 x86:ebp+8 gcc:rdi msc:rcx
; @param u64New x86:ebp+c gcc:rsi msc:rdx
-; @param u64Old x86:ebp+14 gcc:rcx msc:r8
+; @param u64Old x86:ebp+14 gcc:rdx msc:r8
;
; @returns bool result: true if successfully exchanged, false if not.
; x86:al
@@ -47,7 +47,7 @@ BEGINPROC_EXPORTED ASMAtomicCmpXchgU64
mov rax, r8
lock cmpxchg [rcx], rdx
%else
- mov rax, rcx
+ mov rax, rdx
lock cmpxchg [rdi], rsi
%endif
setz al
diff --git a/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU8.asm b/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU8.asm
index 0c57b29d..55c92c8d 100644
--- a/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU8.asm
+++ b/src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU8.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2009 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/asm/ASMAtomicReadU64.asm b/src/VBox/Runtime/common/asm/ASMAtomicReadU64.asm
index 60d01e32..c7e86e8a 100644
--- a/src/VBox/Runtime/common/asm/ASMAtomicReadU64.asm
+++ b/src/VBox/Runtime/common/asm/ASMAtomicReadU64.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2009 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/asm/ASMAtomicUoAndU32.asm b/src/VBox/Runtime/common/asm/ASMAtomicUoAndU32.asm
new file mode 100644
index 00000000..1e4bb0b9
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMAtomicUoAndU32.asm
@@ -0,0 +1,58 @@
+; $Id: ASMAtomicUoAndU32.asm $
+;; @file
+; IPRT - ASMAtomicUoAndU32().
+;
+
+;
+; Copyright (C) 2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; Atomically OR an unsigned 32-bit value, unordered.
+;
+; @param pu32 x86:esp+4 gcc:rdi msc:rcx
+; @param u32Or x86:esp+8 gcc:rsi msc:rdx
+;
+; @returns void
+;
+BEGINPROC_EXPORTED ASMAtomicUoAndU32
+%ifdef RT_ARCH_AMD64
+ %ifdef ASM_CALL64_MSC
+ and [rcx], rdx
+ %else
+ and [rdi], rsi
+ %endif
+%elifdef RT_ARCH_X86
+ mov ecx, [esp + 04h]
+ mov edx, [esp + 08h]
+ and [ecx], edx
+%endif
+ ret
+ENDPROC ASMAtomicUoAndU32
+
+
+
diff --git a/src/VBox/Runtime/common/asm/ASMAtomicUoAndU64.asm b/src/VBox/Runtime/common/asm/ASMAtomicUoAndU64.asm
new file mode 100644
index 00000000..7f145c22
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMAtomicUoAndU64.asm
@@ -0,0 +1,77 @@
+; $Id: ASMAtomicUoAndU64.asm $
+;; @file
+; IPRT - ASMAtomicUoAndU64().
+;
+
+;
+; Copyright (C) 2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; Atomically AND an unsigned 64-bit value, unordered.
+;
+; @param pu64 x86:ebp+8 gcc:rdi msc:rcx
+; @param u64Or x86:ebp+c gcc:rsi msc:rdx
+;
+; @returns void
+;
+BEGINPROC_EXPORTED ASMAtomicUoAndU64
+%ifdef RT_ARCH_AMD64
+ %ifdef ASM_CALL64_MSC
+ and [rcx], rdx
+ %else
+ and [rdi], rsi
+ %endif
+%elifdef RT_ARCH_X86
+ push ebp
+ mov ebp, esp
+ push ebx
+ push edi
+
+ mov edi, [ebp + 08h]
+ mov ebx, [ebp + 0ch]
+ mov ecx, [ebp + 0ch + 4]
+ mov eax, ebx
+ mov edx, ecx
+.try_again:
+ cmpxchg8b [edi]
+ jz .done
+ mov ebx, eax
+ and ebx, [ebp + 0ch]
+ mov ecx, edx
+ and ecx, [ebp + 0ch + 4]
+ jmp .try_again
+
+.done:
+ pop edi
+ pop ebx
+ leave
+%endif
+ ret
+ENDPROC ASMAtomicUoAndU64
+
+
diff --git a/src/VBox/Runtime/common/asm/ASMAtomicUoOrU32.asm b/src/VBox/Runtime/common/asm/ASMAtomicUoOrU32.asm
new file mode 100644
index 00000000..efd63e54
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMAtomicUoOrU32.asm
@@ -0,0 +1,57 @@
+; $Id: ASMAtomicUoOrU32.asm $
+;; @file
+; IPRT - ASMAtomicUoOrU32().
+;
+
+;
+; Copyright (C) 2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; Atomically OR an unsigned 32-bit value, unordered.
+;
+; @param pu32 x86:esp+4 gcc:rdi msc:rcx
+; @param u32Or x86:esp+8 gcc:rsi msc:rdx
+;
+; @returns void
+;
+BEGINPROC_EXPORTED ASMAtomicUoOrU32
+%ifdef RT_ARCH_AMD64
+ %ifdef ASM_CALL64_MSC
+ or [rcx], rdx
+ %else
+ or [rdi], rsi
+ %endif
+%elifdef RT_ARCH_X86
+ mov ecx, [esp + 04h]
+ mov edx, [esp + 08h]
+ or [ecx], edx
+%endif
+ ret
+ENDPROC ASMAtomicUoOrU32
+
+
diff --git a/src/VBox/Runtime/common/asm/ASMAtomicUoOrU64.asm b/src/VBox/Runtime/common/asm/ASMAtomicUoOrU64.asm
new file mode 100644
index 00000000..729aba51
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMAtomicUoOrU64.asm
@@ -0,0 +1,76 @@
+; $Id: ASMAtomicUoOrU64.asm $
+;; @file
+; IPRT - ASMAtomicUoOrU64().
+;
+
+;
+; Copyright (C) 2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; Atomically OR an unsigned 64-bit value, unordered.
+;
+; @param pu64 x86:ebp+8 gcc:rdi msc:rcx
+; @param u64Or x86:ebp+c gcc:rsi msc:rdx
+;
+; @returns void
+;
+BEGINPROC_EXPORTED ASMAtomicUoOrU64
+%ifdef RT_ARCH_AMD64
+ %ifdef ASM_CALL64_MSC
+ or [rcx], rdx
+ %else
+ or [rdi], rsi
+ %endif
+%elifdef RT_ARCH_X86
+ push ebp
+ mov ebp, esp
+ push ebx
+ push edi
+
+ mov edi, [ebp + 08h]
+ mov ebx, [ebp + 0ch]
+ mov ecx, [ebp + 0ch + 4]
+ mov eax, ebx
+ mov edx, ecx
+.try_again:
+ cmpxchg8b [edi]
+ jz .done
+ mov ebx, eax
+ or ebx, [ebp + 0ch]
+ mov ecx, edx
+ or ecx, [ebp + 0ch + 4]
+ jmp .try_again
+
+.done:
+ pop edi
+ pop ebx
+ leave
+%endif
+ ret
+ENDPROC ASMAtomicUoOrU64
+
diff --git a/src/VBox/Runtime/common/asm/ASMCpuIdExSlow.asm b/src/VBox/Runtime/common/asm/ASMCpuIdExSlow.asm
new file mode 100644
index 00000000..772aee35
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMCpuIdExSlow.asm
@@ -0,0 +1,137 @@
+; $Id: ASMCpuIdExSlow.asm $
+;; @file
+; IPRT - ASMCpuIdExSlow().
+;
+
+;
+; Copyright (C) 2012-2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; CPUID with EAX and ECX inputs, returning ALL output registers.
+;
+; @param uOperator x86:ebp+8 gcc:rdi msc:rcx
+; @param uInitEBX x86:ebp+c gcc:rsi msc:rdx
+; @param uInitECX x86:ebp+10 gcc:rdx msc:r8
+; @param uInitEDX x86:ebp+14 gcc:rcx msc:r9
+; @param pvEAX x86:ebp+18 gcc:r8 msc:rbp+30h
+; @param pvEBX x86:ebp+1c gcc:r9 msc:rbp+38h
+; @param pvECX x86:ebp+20 gcc:rbp+10h msc:rbp+40h
+; @param pvEDX x86:ebp+24 gcc:rbp+18h msc:rbp+48h
+;
+; @returns EAX
+;
+BEGINPROC_EXPORTED ASMCpuIdExSlow
+ push xBP
+ mov xBP, xSP
+ push xBX
+%ifdef RT_ARCH_X86
+ push edi
+%endif
+
+%ifdef ASM_CALL64_MSC
+ mov eax, ecx
+ mov ebx, edx
+ mov ecx, r8d
+ mov edx, r9d
+ mov r8, [rbp + 30h]
+ mov r9, [rbp + 38h]
+ mov r10, [rbp + 40h]
+ mov r11, [rbp + 48h]
+%elifdef ASM_CALL64_GCC
+ mov eax, edi
+ mov ebx, esi
+ xchg ecx, edx
+ mov r10, [rbp + 10h]
+ mov r11, [rbp + 18h]
+%elifdef RT_ARCH_X86
+ mov eax, [ebp + 08h]
+ mov ebx, [ebp + 0ch]
+ mov ecx, [ebp + 10h]
+ mov edx, [ebp + 14h]
+ mov edi, [ebp + 18h]
+%else
+ %error unsupported arch
+%endif
+
+ cpuid
+
+%ifdef RT_ARCH_AMD64
+ test r8, r8
+ jz .store_ebx
+ mov [r8], eax
+%else
+ test edi, edi
+ jz .store_ebx
+ mov [edi], eax
+%endif
+.store_ebx:
+
+%ifdef RT_ARCH_AMD64
+ test r9, r9
+ jz .store_ecx
+ mov [r9], ebx
+%else
+ mov edi, [ebp + 1ch]
+ test edi, edi
+ jz .store_ecx
+ mov [edi], ebx
+%endif
+.store_ecx:
+
+%ifdef RT_ARCH_AMD64
+ test r10, r10
+ jz .store_edx
+ mov [r10], ecx
+%else
+ mov edi, [ebp + 20h]
+ test edi, edi
+ jz .store_edx
+ mov [edi], ecx
+%endif
+.store_edx:
+
+%ifdef RT_ARCH_AMD64
+ test r11, r11
+ jz .done
+ mov [r11], edx
+%else
+ mov edi, [ebp + 24h]
+ test edi, edi
+ jz .done
+ mov [edi], edx
+%endif
+.done:
+
+%ifdef RT_ARCH_X86
+ pop edi
+%endif
+ pop xBX
+ leave
+ ret
+ENDPROC ASMCpuIdExSlow
+
diff --git a/src/VBox/Runtime/common/asm/ASMCpuId_Idx_ECX.asm b/src/VBox/Runtime/common/asm/ASMCpuId_Idx_ECX.asm
new file mode 100644
index 00000000..9992fb22
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMCpuId_Idx_ECX.asm
@@ -0,0 +1,116 @@
+; $Id: ASMCpuId_Idx_ECX.asm $
+;; @file
+; IPRT - ASMCpuId_Idx_ECX().
+;
+
+;
+; Copyright (C) 2012-2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; CPUID with EAX and ECX inputs, returning ALL output registers.
+;
+; @param uOperator x86:ebp+8 gcc:rdi msc:rcx
+; @param uIdxECX x86:ebp+c gcc:rsi msc:rdx
+; @param pvEAX x86:ebp+10 gcc:rdx msc:r8
+; @param pvEBX x86:ebp+14 gcc:rcx msc:r9
+; @param pvECX x86:ebp+18 gcc:r8 msc:rsp+28h
+; @param pvEDX x86:ebp+1c gcc:r9 msc:rsp+30h
+;
+; @returns void
+;
+BEGINPROC_EXPORTED ASMCpuId_Idx_ECX
+%ifdef RT_ARCH_AMD64
+ mov r10, rbx
+
+ %ifdef ASM_CALL64_MSC
+
+ mov eax, ecx
+ mov ecx, edx
+ xor ebx, ebx
+ xor edx, edx
+
+ cpuid
+
+ mov [r8], eax
+ mov [r9], ebx
+ mov rax, [rsp + 28h]
+ mov rbx, [rsp + 30h]
+ mov [rax], ecx
+ mov [rbx], edx
+
+ %else
+ mov rsi, rdx
+ mov r11, rcx
+ mov eax, edi
+ mov ecx, esi
+ xor ebx, ebx
+ xor edx, edx
+
+ cpuid
+
+ mov [rsi], eax
+ mov [r11], ebx
+ mov [r8], ecx
+ mov [r9], edx
+
+ %endif
+
+ mov rbx, r10
+ ret
+
+%elifdef RT_ARCH_X86
+ push ebp
+ mov ebp, esp
+ push ebx
+ push edi
+
+ xor edx, edx
+ xor ebx, ebx
+ mov eax, [ebp + 08h]
+ mov ecx, [ebp + 0ch]
+
+ cpuid
+
+ mov edi, [ebp + 10h]
+ mov [edi], eax
+ mov edi, [ebp + 14h]
+ mov [edi], ebx
+ mov edi, [ebp + 18h]
+ mov [edi], ecx
+ mov edi, [ebp + 1ch]
+ mov [edi], edx
+
+ pop edi
+ pop ebx
+ leave
+ ret
+%else
+ %error unsupported arch
+%endif
+ENDPROC ASMCpuId_Idx_ECX
+
diff --git a/src/VBox/Runtime/common/asm/ASMGetGDTR.asm b/src/VBox/Runtime/common/asm/ASMGetGDTR.asm
new file mode 100644
index 00000000..3d827e4e
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMGetGDTR.asm
@@ -0,0 +1,52 @@
+; $Id: ASMGetGDTR.asm $
+;; @file
+; IPRT - ASMGetGDTR().
+;
+
+;
+; Copyright (C) 2006-2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; Gets the content of the GDTR CPU register.
+; @param pGdtr Where to store the GDTR contents.
+; msc=rcx, gcc=rdi, x86=[esp+4]
+;
+BEGINPROC_EXPORTED ASMGetGDTR
+%ifdef ASM_CALL64_MSC
+ mov rax, rcx
+%elifdef ASM_CALL64_GCC
+ mov rax, rdi
+%elifdef RT_ARCH_X86
+ mov eax, [esp + 4]
+%else
+ %error "Undefined arch?"
+%endif
+ sgdt [xAX]
+ ret
+ENDPROC ASMGetGDTR
+
diff --git a/src/VBox/Runtime/win/amd64/ASMGetIDTR.asm b/src/VBox/Runtime/common/asm/ASMGetIDTR.asm
index 7f098fe4..558a6d7b 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetIDTR.asm
+++ b/src/VBox/Runtime/common/asm/ASMGetIDTR.asm
@@ -1,9 +1,10 @@
+; $Id: ASMGetIDTR.asm $
;; @file
; IPRT - ASMGetIDTR().
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2013 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -32,11 +33,20 @@ BEGINCODE
;;
; Gets the content of the IDTR CPU register.
-; @param rcx pIdtr Where to store the IDTR contents.
+; @param pIdtr Where to store the IDTR contents.
+; msc=rcx, gcc=rdi, x86=[esp+4]
;
BEGINPROC_EXPORTED ASMGetIDTR
- sidt [rcx]
+%ifdef ASM_CALL64_MSC
+ mov rax, rcx
+%elifdef ASM_CALL64_GCC
+ mov rax, rdi
+%elifdef RT_ARCH_X86
+ mov eax, [esp + 4]
+%else
+ %error "Undefined arch?"
+%endif
+ sidt [xAX]
ret
ENDPROC ASMGetIDTR
-
diff --git a/src/VBox/Runtime/win/amd64/ASMGetGDTR.asm b/src/VBox/Runtime/common/asm/ASMGetLDTR.asm
index 0356e3c5..f7adf829 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetGDTR.asm
+++ b/src/VBox/Runtime/common/asm/ASMGetLDTR.asm
@@ -1,9 +1,10 @@
+; $Id: ASMGetLDTR.asm $
;; @file
-; IPRT - ASMGetGDTR().
+; IPRT - ASMGetLDTR().
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2013 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -31,11 +32,12 @@
BEGINCODE
;;
-; Gets the content of the GDTR CPU register.
-; @param rcx pGdtr Where to store the GDTR contents.
-;
-BEGINPROC_EXPORTED ASMGetGDTR
- sgdt [rcx]
+; Get the LDTR register.
+; @returns LDTR.
+;
+BEGINPROC_EXPORTED ASMGetLDTR
+ sldt ax
+ movzx eax, ax
ret
-ENDPROC ASMGetGDTR
+ENDPROC ASMGetLDTR
diff --git a/src/VBox/Runtime/common/asm/ASMGetSegAttr.asm b/src/VBox/Runtime/common/asm/ASMGetSegAttr.asm
new file mode 100644
index 00000000..a9f493e7
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMGetSegAttr.asm
@@ -0,0 +1,61 @@
+; $Id: ASMGetSegAttr.asm $
+;; @file
+; IPRT - ASMGetSegAttr().
+;
+
+;
+; Copyright (C) 2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; Get the segment attributes for a selector.
+;
+; @param uSel x86: [ebp + 08h] msc: ecx gcc: edi The selector value.
+; @returns Segment attributes on success or ~0U on failure.
+;
+; @remarks Using ~0U for failure is chosen because valid access rights always
+; have bits 0:7 as 0 (on both Intel & AMD).
+;
+BEGINPROC_EXPORTED ASMGetSegAttr
+%ifdef ASM_CALL64_MSC
+ and ecx, 0ffffh
+ lar eax, ecx
+%elifdef ASM_CALL64_GCC
+ and edi, 0ffffh
+ lar eax, edi
+%elifdef RT_ARCH_X86
+ movzx edx, word [esp + 4]
+ lar eax, edx
+%else
+ %error "Which arch is this?"
+%endif
+ jz .return
+ mov eax, 0ffffffffh
+.return:
+ ret
+ENDPROC ASMGetSegAttr
+
diff --git a/src/VBox/Runtime/win/amd64/ASMGetTR.asm b/src/VBox/Runtime/common/asm/ASMGetTR.asm
index 8a3f5ce8..3d6fc68e 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetTR.asm
+++ b/src/VBox/Runtime/common/asm/ASMGetTR.asm
@@ -1,9 +1,10 @@
+; $Id: ASMGetTR.asm $
;; @file
; IPRT - ASMGetTR().
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2013 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/asm/ASMMultU64ByU32DivByU32.asm b/src/VBox/Runtime/common/asm/ASMMultU64ByU32DivByU32.asm
index 6155e869..4308631a 100644
--- a/src/VBox/Runtime/common/asm/ASMMultU64ByU32DivByU32.asm
+++ b/src/VBox/Runtime/common/asm/ASMMultU64ByU32DivByU32.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/asm/ASMNopPause.asm b/src/VBox/Runtime/common/asm/ASMNopPause.asm
index 455bd14d..8447a87f 100644
--- a/src/VBox/Runtime/common/asm/ASMNopPause.asm
+++ b/src/VBox/Runtime/common/asm/ASMNopPause.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2009 Oracle Corporation
+; Copyright (C) 2009-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/asm/ASMRdMsrEx.asm b/src/VBox/Runtime/common/asm/ASMRdMsrEx.asm
new file mode 100644
index 00000000..69135620
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMRdMsrEx.asm
@@ -0,0 +1,84 @@
+; $Id: ASMRdMsrEx.asm $
+;; @file
+; IPRT - ASMRdMsrEx().
+;
+
+;
+; Copyright (C) 2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; Special version of ASMRdMsr that allow specifying the rdi value.
+;
+; @param uMsr msc=rcx, gcc=rdi, x86=[ebp+8] The MSR to read.
+; @param uEdi msc=rdx, gcc=rsi, x86=[ebp+12] The EDI/RDI value.
+; @returns MSR value in rax on amd64 and edx:eax on x86.
+;
+BEGINPROC_EXPORTED ASMRdMsrEx
+%ifdef ASM_CALL64_MSC
+proc_frame ASMRdMsrEx_DupWarningHack
+ push rdi
+ [pushreg rdi]
+[endprolog]
+ and ecx, ecx ; serious paranoia
+ mov rdi, rdx
+ xor eax, eax
+ xor edx, edx
+ rdmsr
+ pop rdi
+ and eax, eax ; paranoia
+ shl rdx, 32
+ or rax, rdx
+ ret
+endproc_frame
+%elifdef ASM_CALL64_GCC
+ mov ecx, edi
+ mov rdi, rsi
+ xor eax, eax
+ xor edx, edx
+ rdmsr
+ and eax, eax ; paranoia
+ shl rdx, 32
+ or rax, rdx
+ ret
+%elifdef RT_ARCH_X86
+ push ebp
+ mov ebp, esp
+ push edi
+ xor eax, eax
+ xor edx, edx
+ mov ecx, [ebp + 8]
+ mov edi, [esp + 12]
+ rdmsr
+ pop edi
+ leave
+ ret
+%else
+ %error "Undefined arch?"
+%endif
+ENDPROC ASMRdMsrEx
+
diff --git a/src/VBox/Runtime/common/asm/ASMWrMsrEx.asm b/src/VBox/Runtime/common/asm/ASMWrMsrEx.asm
new file mode 100644
index 00000000..4feeaa9a
--- /dev/null
+++ b/src/VBox/Runtime/common/asm/ASMWrMsrEx.asm
@@ -0,0 +1,79 @@
+; $Id: ASMWrMsrEx.asm $
+;; @file
+; IPRT - ASMWrMsrEx().
+;
+
+;
+; Copyright (C) 2013 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; Special version of ASMRdMsr that allow specifying the rdi value.
+;
+; @param uMsr msc=rcx, gcc=rdi, x86=[ebp+8] The MSR to read.
+; @param uXDI msc=rdx, gcc=rsi, x86=[ebp+12] The EDI/RDI value.
+; @param uValue msc=r8, gcc=rdx, x86=[ebp+16] The 64-bit value to write.
+;
+BEGINPROC_EXPORTED ASMWrMsrEx
+%ifdef ASM_CALL64_MSC
+proc_frame ASMWrMsrEx_DupWarningHack
+ push rdi
+ [pushreg rdi]
+[endprolog]
+ and ecx, ecx ; serious paranoia
+ mov rdi, rdx
+ mov eax, r8d
+ mov rdx, r8
+ shr rdx, 32
+ wrmsr
+ pop rdi
+ ret
+endproc_frame
+%elifdef ASM_CALL64_GCC
+ mov ecx, edi
+ mov rdi, rsi
+ mov eax, edx
+ shr edx, 32
+ wrmsr
+ ret
+%elifdef RT_ARCH_X86
+ push ebp
+ mov ebp, esp
+ push edi
+ mov ecx, [ebp + 8]
+ mov edi, [esp + 12]
+ mov eax, [esp + 16]
+ mov edx, [esp + 20]
+ wrmsr
+ pop edi
+ leave
+ ret
+%else
+ %error "Undefined arch?"
+%endif
+ENDPROC ASMWrMsrEx
+
diff --git a/src/VBox/Runtime/common/asm/asm-fake.cpp b/src/VBox/Runtime/common/asm/asm-fake.cpp
index c2edb702..b737ffe3 100644
--- a/src/VBox/Runtime/common/asm/asm-fake.cpp
+++ b/src/VBox/Runtime/common/asm/asm-fake.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/RTSha256Digest.cpp b/src/VBox/Runtime/common/checksum/RTSha256Digest.cpp
new file mode 100644
index 00000000..5b8679c4
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/RTSha256Digest.cpp
@@ -0,0 +1,201 @@
+/** @file
+ * IPRT - SHA256 digest creation
+ */
+
+/*
+ * Copyright (C) 2009-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/alloca.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/file.h>
+
+#include <openssl/sha.h>
+
+
+RTR3DECL(int) RTSha256Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
+{
+ /* Validate input */
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER);
+
+ int rc = VINF_SUCCESS;
+ *ppszDigest = NULL;
+
+ /* Initialize OpenSSL. */
+ SHA256_CTX ctx;
+ if (!SHA256_Init(&ctx))
+ return VERR_INTERNAL_ERROR;
+
+ /* Buffer size for progress callback */
+ double rdMulti = 100.0 / cbBuf;
+
+ /* Working buffer */
+ char *pvTmp = (char*)pvBuf;
+
+ /* Process the memory in blocks */
+ size_t cbRead;
+ size_t cbReadTotal = 0;
+ for (;;)
+ {
+ cbRead = RT_MIN(cbBuf - cbReadTotal, _1M);
+ if(!SHA256_Update(&ctx, pvTmp, cbRead))
+ {
+ rc = VERR_INTERNAL_ERROR;
+ break;
+ }
+ cbReadTotal += cbRead;
+ pvTmp += cbRead;
+
+ /* Call the progress callback if one is defined */
+ if (pfnProgressCallback)
+ {
+ rc = pfnProgressCallback((unsigned)(cbReadTotal * rdMulti), pvUser);
+ if (RT_FAILURE(rc))
+ break; /* canceled */
+ }
+ /* Finished? */
+ if (cbReadTotal == cbBuf)
+ break;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ /* Finally calculate & format the SHA256 sum */
+ unsigned char auchDig[RTSHA256_HASH_SIZE];
+ if (!SHA256_Final(auchDig, &ctx))
+ return VERR_INTERNAL_ERROR;
+
+ char *pszDigest;
+ rc = RTStrAllocEx(&pszDigest, RTSHA256_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSha256ToString(auchDig, pszDigest, RTSHA256_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ *ppszDigest = pszDigest;
+ else
+ RTStrFree(pszDigest);
+ }
+ }
+
+ return rc;
+}
+
+RTR3DECL(int) RTSha256DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
+{
+ /* Validate input */
+ AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER);
+
+ *ppszDigest = NULL;
+
+ /* Initialize OpenSSL. */
+ SHA256_CTX ctx;
+ if (!SHA256_Init(&ctx))
+ return VERR_INTERNAL_ERROR;
+
+ /* Open the file to calculate a SHA256 sum of */
+ RTFILE hFile;
+ int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Fetch the file size. Only needed if there is a progress callback. */
+ double rdMulti = 0;
+ if (pfnProgressCallback)
+ {
+ uint64_t cbFile;
+ rc = RTFileGetSize(hFile, &cbFile);
+ if (RT_FAILURE(rc))
+ {
+ RTFileClose(hFile);
+ return rc;
+ }
+ rdMulti = 100.0 / cbFile;
+ }
+
+ /* Allocate a reasonably large buffer, fall back on a tiny one. */
+ void *pvBufFree;
+ size_t cbBuf = _1M;
+ void *pvBuf = pvBufFree = RTMemTmpAlloc(cbBuf);
+ if (!pvBuf)
+ {
+ cbBuf = 0x1000;
+ pvBuf = alloca(cbBuf);
+ }
+
+ /* Read that file in blocks */
+ size_t cbRead;
+ size_t cbReadTotal = 0;
+ for (;;)
+ {
+ rc = RTFileRead(hFile, pvBuf, cbBuf, &cbRead);
+ if (RT_FAILURE(rc) || !cbRead)
+ break;
+ if(!SHA256_Update(&ctx, pvBuf, cbRead))
+ {
+ rc = VERR_INTERNAL_ERROR;
+ break;
+ }
+ cbReadTotal += cbRead;
+
+ /* Call the progress callback if one is defined */
+ if (pfnProgressCallback)
+ {
+ rc = pfnProgressCallback((unsigned)(cbReadTotal * rdMulti), pvUser);
+ if (RT_FAILURE(rc))
+ break; /* canceled */
+ }
+ }
+ RTMemTmpFree(pvBufFree);
+ RTFileClose(hFile);
+
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Finally calculate & format the SHA256 sum */
+ unsigned char auchDig[RTSHA256_HASH_SIZE];
+ if (!SHA256_Final(auchDig, &ctx))
+ return VERR_INTERNAL_ERROR;
+
+ char *pszDigest;
+ rc = RTStrAllocEx(&pszDigest, RTSHA256_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSha256ToString(auchDig, pszDigest, RTSHA256_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ *ppszDigest = pszDigest;
+ else
+ RTStrFree(pszDigest);
+ }
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/checksum/adler32.cpp b/src/VBox/Runtime/common/checksum/adler32.cpp
index d9e54985..5ab8a55f 100644
--- a/src/VBox/Runtime/common/checksum/adler32.cpp
+++ b/src/VBox/Runtime/common/checksum/adler32.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/crc32-zlib.cpp b/src/VBox/Runtime/common/checksum/crc32-zlib.cpp
index 650a959b..0ba474b3 100644
--- a/src/VBox/Runtime/common/checksum/crc32-zlib.cpp
+++ b/src/VBox/Runtime/common/checksum/crc32-zlib.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/crc32.cpp b/src/VBox/Runtime/common/checksum/crc32.cpp
index c43b2cbb..0ea4f092 100644
--- a/src/VBox/Runtime/common/checksum/crc32.cpp
+++ b/src/VBox/Runtime/common/checksum/crc32.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/crc64.cpp b/src/VBox/Runtime/common/checksum/crc64.cpp
index 74c60070..0904031f 100644
--- a/src/VBox/Runtime/common/checksum/crc64.cpp
+++ b/src/VBox/Runtime/common/checksum/crc64.cpp
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/ipv4.cpp b/src/VBox/Runtime/common/checksum/ipv4.cpp
index c757be21..0200e744 100644
--- a/src/VBox/Runtime/common/checksum/ipv4.cpp
+++ b/src/VBox/Runtime/common/checksum/ipv4.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/ipv6.cpp b/src/VBox/Runtime/common/checksum/ipv6.cpp
index d33438a0..3364d19f 100644
--- a/src/VBox/Runtime/common/checksum/ipv6.cpp
+++ b/src/VBox/Runtime/common/checksum/ipv6.cpp
@@ -60,7 +60,7 @@ DECLINLINE(uint32_t) rtNetIPv6PseudoChecksumBits(PCRTNETADDRIPV6 pSrcAddr, PCRTN
+ RT_H2BE_U16(RT_HIWORD(cbPkt))
+ RT_H2BE_U16(RT_LOWORD(cbPkt))
+ 0
- + RT_H2BE_U16(RT_MAKE_U16(0, bProtocol));
+ + RT_H2BE_U16(RT_MAKE_U16(bProtocol, 0));
return u32Sum;
}
diff --git a/src/VBox/Runtime/common/checksum/manifest.cpp b/src/VBox/Runtime/common/checksum/manifest.cpp
index b16a8f6a..77d4d039 100644
--- a/src/VBox/Runtime/common/checksum/manifest.cpp
+++ b/src/VBox/Runtime/common/checksum/manifest.cpp
@@ -1,10 +1,10 @@
/* $Id: manifest.cpp $ */
/** @file
- * IPRT - Manifest file handling.
+ * IPRT - Manifest file handling, old style - deprecated.
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -66,6 +66,7 @@ typedef struct RTMANIFESTCALLBACKDATA
} RTMANIFESTCALLBACKDATA;
typedef RTMANIFESTCALLBACKDATA* PRTMANIFESTCALLBACKDATA;
+
/*******************************************************************************
* Private functions
*******************************************************************************/
@@ -96,6 +97,7 @@ int rtSHAProgressCallback(unsigned uPercent, void *pvUser)
pData->pvUser);
}
+
/*******************************************************************************
* Public functions
*******************************************************************************/
@@ -252,10 +254,13 @@ RTR3DECL(int) RTManifestWriteFiles(const char *pszManifestFile, RTDIGESTTYPE enm
/* Cleanup */
if (pvBuf)
RTMemFree(pvBuf);
- for (size_t i = 0; i < cFiles; ++i)
- if (paFiles[i].pszTestDigest)
- RTStrFree((char*)paFiles[i].pszTestDigest);
- RTMemFree(paFiles);
+ if (paFiles)
+ {
+ for (size_t i = 0; i < cFiles; ++i)
+ if (paFiles[i].pszTestDigest)
+ RTStrFree((char*)paFiles[i].pszTestDigest);
+ RTMemFree(paFiles);
+ }
/* Delete the manifest file on failure */
if (RT_FAILURE(rc))
@@ -264,6 +269,67 @@ RTR3DECL(int) RTManifestWriteFiles(const char *pszManifestFile, RTDIGESTTYPE enm
return rc;
}
+
+RTR3DECL(int) RTManifestVerifyDigestType(void const *pvBuf, size_t cbSize, RTDIGESTTYPE *penmDigestType)
+{
+ /* Validate input */
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertReturn(cbSize > 0, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(penmDigestType, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+
+ char const *pcBuf = (char *)pvBuf;
+ size_t cbRead = 0;
+ /* Parse the manifest file line by line */
+ for (;;)
+ {
+ if (cbRead >= cbSize)
+ return VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE;
+
+ size_t cch = rtManifestIndexOfCharInBuf(pcBuf, cbSize - cbRead, '\n') + 1;
+
+ /* Skip empty lines (UNIX/DOS format) */
+ if ( ( cch == 1
+ && pcBuf[0] == '\n')
+ || ( cch == 2
+ && pcBuf[0] == '\r'
+ && pcBuf[1] == '\n'))
+ {
+ pcBuf += cch;
+ cbRead += cch;
+ continue;
+ }
+
+/** @todo r=bird: Missing space check here. */
+ /* Check for the digest algorithm */
+ if ( pcBuf[0] == 'S'
+ && pcBuf[1] == 'H'
+ && pcBuf[2] == 'A'
+ && pcBuf[3] == '1')
+ {
+ *penmDigestType = RTDIGESTTYPE_SHA1;
+ break;
+ }
+ if ( pcBuf[0] == 'S'
+ && pcBuf[1] == 'H'
+ && pcBuf[2] == 'A'
+ && pcBuf[3] == '2'
+ && pcBuf[4] == '5'
+ && pcBuf[5] == '6')
+ {
+ *penmDigestType = RTDIGESTTYPE_SHA256;
+ break;
+ }
+
+ pcBuf += cch;
+ cbRead += cch;
+ }
+
+ return rc;
+}
+
+
RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed)
{
/* Validate input */
@@ -307,7 +373,7 @@ RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTE
/** @todo r=bird:
* -# Better deal with this EOF line platform dependency
- * -# The SHA1 test should probably include a blank space check.
+ * -# The SHA1 and SHA256 tests should probably include a blank space check.
* -# If there is a specific order to the elements in the string, it would be
* good if the delimiter searching checked for it.
* -# Deal with filenames containing delimiter characters.
@@ -315,10 +381,19 @@ RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTE
/* Check for the digest algorithm */
if ( cch < 4
- || !( pcBuf[0] == 'S'
- && pcBuf[1] == 'H'
- && pcBuf[2] == 'A'
- && pcBuf[3] == '1'))
+ || ( !( pcBuf[0] == 'S'
+ && pcBuf[1] == 'H'
+ && pcBuf[2] == 'A'
+ && pcBuf[3] == '1')
+ &&
+ !( pcBuf[0] == 'S'
+ && pcBuf[1] == 'H'
+ && pcBuf[2] == 'A'
+ && pcBuf[3] == '2'
+ && pcBuf[4] == '5'
+ && pcBuf[5] == '6')
+ )
+ )
{
/* Digest unsupported */
rc = VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE;
@@ -363,6 +438,7 @@ RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTE
pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\n');
if (!pszDigestEnd)
{
+ RTMemTmpFree(pszName);
rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
break;
}
@@ -371,6 +447,7 @@ RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTE
char *pszDigest = (char *)RTMemTmpAlloc(cchDigest + 1);
if (!pszDigest)
{
+ RTMemTmpFree(pszName);
rc = VERR_NO_MEMORY;
break;
}
@@ -381,7 +458,8 @@ RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTE
bool fFound = false;
for (size_t i = 0; i < cTests; ++i)
{
- if (!RTStrCmp(RTPathFilename(paFiles[i].pTestPattern->pszTestFile), RTStrStrip(pszName)))
+ /** @todo r=bird: Using RTStrStr here looks bogus. */
+ if (RTStrStr(paFiles[i].pTestPattern->pszTestFile, RTStrStrip(pszName)) != NULL)
{
/* Add the data of the manifest file to the file list */
paFiles[i].pszManifestFile = RTStrDup(RTStrStrip(pszName));
@@ -418,7 +496,7 @@ RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTE
break;
}
- /* Do the manifest SHA1 digest match against the actual digest? */
+ /* Do the manifest SHA digest match against the actual digest? */
if (RTStrICmp(paFiles[i].pszManifestDigest, paFiles[i].pTestPattern->pszTestDigest))
{
if (piFailed)
@@ -439,7 +517,6 @@ RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTE
}
RTMemTmpFree(paFiles);
- RTPrintf("rc = %Rrc\n", rc);
return rc;
}
@@ -468,7 +545,7 @@ RTR3DECL(int) RTManifestWriteFilesBuf(void **ppvBuf, size_t *pcbSize, RTDIGESTTY
for (size_t i = 0; i < cFiles; ++i)
{
size_t cbTmp = strlen(RTPathFilename(paFiles[i].pszTestFile))
- + strlen(paFiles[i].pszTestDigest)
+ + strlen(paFiles[i].pszTestDigest)
+ strlen(pcszDigestType)
+ 6;
cbMaxSize = RT_MAX(cbMaxSize, cbTmp);
diff --git a/src/VBox/Runtime/common/checksum/manifest2.cpp b/src/VBox/Runtime/common/checksum/manifest2.cpp
index a6450627..84cdb039 100644
--- a/src/VBox/Runtime/common/checksum/manifest2.cpp
+++ b/src/VBox/Runtime/common/checksum/manifest2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/manifest3.cpp b/src/VBox/Runtime/common/checksum/manifest3.cpp
index c0b5e855..9ff67f23 100644
--- a/src/VBox/Runtime/common/checksum/manifest3.cpp
+++ b/src/VBox/Runtime/common/checksum/manifest3.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/md5.cpp b/src/VBox/Runtime/common/checksum/md5.cpp
index 0bd8afb6..05aff4a0 100644
--- a/src/VBox/Runtime/common/checksum/md5.cpp
+++ b/src/VBox/Runtime/common/checksum/md5.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,7 +30,7 @@
/*
* This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest. This code was
+ * The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
@@ -51,7 +51,7 @@
#include <iprt/md5.h>
#include "internal/iprt.h"
-#include <iprt/string.h> /* for memcpy() */
+#include <iprt/string.h> /* for memcpy() */
#if defined(RT_BIG_ENDIAN)
# include <iprt/asm.h> /* RT_LE2H_U32 uses ASMByteSwapU32. */
#endif
@@ -239,7 +239,7 @@ RTDECL(void) RTMd5Update(PRTMD5CONTEXT ctx, const void *pvBuf, size_t len)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += (uint32_t)(len >> 29);
- t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t)
diff --git a/src/VBox/Runtime/common/checksum/md5str.cpp b/src/VBox/Runtime/common/checksum/md5str.cpp
index 40dbb8ba..288d6eb7 100644
--- a/src/VBox/Runtime/common/checksum/md5str.cpp
+++ b/src/VBox/Runtime/common/checksum/md5str.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/sha1.cpp b/src/VBox/Runtime/common/checksum/sha1.cpp
index e448a479..9db75a2b 100644
--- a/src/VBox/Runtime/common/checksum/sha1.cpp
+++ b/src/VBox/Runtime/common/checksum/sha1.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/sha1str.cpp b/src/VBox/Runtime/common/checksum/sha1str.cpp
index 730d0bee..22261034 100644
--- a/src/VBox/Runtime/common/checksum/sha1str.cpp
+++ b/src/VBox/Runtime/common/checksum/sha1str.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/sha256.cpp b/src/VBox/Runtime/common/checksum/sha256.cpp
index c78e22e2..da2a70ed 100644
--- a/src/VBox/Runtime/common/checksum/sha256.cpp
+++ b/src/VBox/Runtime/common/checksum/sha256.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/sha256str.cpp b/src/VBox/Runtime/common/checksum/sha256str.cpp
index 43e668e1..4ca92a2e 100644
--- a/src/VBox/Runtime/common/checksum/sha256str.cpp
+++ b/src/VBox/Runtime/common/checksum/sha256str.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/sha512.cpp b/src/VBox/Runtime/common/checksum/sha512.cpp
index ee38f368..570c0a7e 100644
--- a/src/VBox/Runtime/common/checksum/sha512.cpp
+++ b/src/VBox/Runtime/common/checksum/sha512.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/checksum/sha512str.cpp b/src/VBox/Runtime/common/checksum/sha512str.cpp
index 13373421..5329f4d2 100644
--- a/src/VBox/Runtime/common/checksum/sha512str.cpp
+++ b/src/VBox/Runtime/common/checksum/sha512str.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/dbg/dbg.cpp b/src/VBox/Runtime/common/dbg/dbg.cpp
index 4198ddaf..b5ae1d9f 100644
--- a/src/VBox/Runtime/common/dbg/dbg.cpp
+++ b/src/VBox/Runtime/common/dbg/dbg.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/dbg/dbgas.cpp b/src/VBox/Runtime/common/dbg/dbgas.cpp
index 947fffaa..445cc492 100644
--- a/src/VBox/Runtime/common/dbg/dbgas.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgas.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -396,6 +396,26 @@ RTDECL(uint32_t) RTDbgAsRelease(RTDBGAS hDbgAs)
RT_EXPORT_SYMBOL(RTDbgAsRelease);
+RTDECL(int) RTDbgAsLockExcl(RTDBGAS hDbgAs)
+{
+ PRTDBGASINT pDbgAs = hDbgAs;
+ RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
+ RTDBGAS_LOCK_WRITE(pDbgAs);
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTDbgAsLockExcl);
+
+
+RTDECL(int) RTDbgAsUnlockExcl(RTDBGAS hDbgAs)
+{
+ PRTDBGASINT pDbgAs = hDbgAs;
+ RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
+ RTDBGAS_UNLOCK_WRITE(pDbgAs);
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTDbgAsUnlockExcl);
+
+
/**
* Gets the name of an address space.
*
@@ -900,7 +920,7 @@ RTDECL(int) RTDbgAsModuleUnlinkByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr)
RTDBGAS_LOCK_WRITE(pDbgAs);
PRTDBGASMAP pMap = (PRTDBGASMAP)RTAvlrUIntPtrRangeGet(&pDbgAs->MapTree, Addr);
- if (pMap)
+ if (!pMap)
{
RTDBGAS_UNLOCK_WRITE(pDbgAs);
return VERR_NOT_FOUND;
@@ -1283,6 +1303,37 @@ RT_EXPORT_SYMBOL(RTDbgAsSymbolAdd);
/**
+ * Creates a snapshot of the module table on the temporary heap.
+ *
+ * The caller must release all the module handles before freeing the table
+ * using RTMemTmpFree.
+ *
+ * @returns Module table snaphot.
+ * @param pDbgAs The address space instance data.
+ * @param pcModules Where to return the number of modules.
+ */
+static PRTDBGMOD rtDbgAsSnapshotModuleTable(PRTDBGASINT pDbgAs, uint32_t *pcModules)
+{
+ RTDBGAS_LOCK_READ(pDbgAs);
+
+ uint32_t iMod = *pcModules = pDbgAs->cModules;
+ PRTDBGMOD pahModules = (PRTDBGMOD)RTMemTmpAlloc(sizeof(pahModules[0]) * RT_MAX(iMod, 1));
+ if (pahModules)
+ {
+ while (iMod-- > 0)
+ {
+ RTDBGMOD hMod = (RTDBGMOD)pDbgAs->papModules[iMod]->Core.Key;
+ pahModules[iMod] = hMod;
+ RTDbgModRetain(hMod);
+ }
+ }
+
+ RTDBGAS_UNLOCK_READ(pDbgAs);
+ return pahModules;
+}
+
+
+/**
* Query a symbol by address.
*
* @returns IPRT status code. See RTDbgModSymbolAddr for more specific ones.
@@ -1306,6 +1357,8 @@ RTDECL(int) RTDbgAsSymbolByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, uint32_t fFlags,
*/
PRTDBGASINT pDbgAs = hDbgAs;
RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
+ if (phMod)
+ *phMod = NIL_RTDBGMOD;
RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
RTUINTPTR offSeg = 0;
@@ -1313,9 +1366,46 @@ RTDECL(int) RTDbgAsSymbolByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, uint32_t fFlags,
RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
if (hMod == NIL_RTDBGMOD)
{
- if (phMod)
- *phMod = NIL_RTDBGMOD;
- return VERR_NOT_FOUND;
+ /*
+ * Check for absolute symbols. Requires iterating all modules.
+ */
+ uint32_t cModules;
+ PRTDBGMOD pahModules = rtDbgAsSnapshotModuleTable(pDbgAs, &cModules);
+ if (!pahModules)
+ return VERR_NO_TMP_MEMORY;
+
+ int rc;
+ RTINTPTR offBestDisp = RTINTPTR_MAX;
+ uint32_t iBest = UINT32_MAX;
+ for (uint32_t i = 0; i < cModules; i++)
+ {
+ RTINTPTR offDisp;
+ rc = RTDbgModSymbolByAddr(pahModules[i], RTDBGSEGIDX_ABS, Addr, fFlags, &offDisp, pSymbol);
+ if (RT_SUCCESS(rc) && RT_ABS(offDisp) < offBestDisp)
+ {
+ offBestDisp = RT_ABS(offDisp);
+ iBest = i;
+ }
+ }
+
+ if (iBest == UINT32_MAX)
+ rc = VERR_NOT_FOUND;
+ else
+ {
+ hMod = pahModules[iBest];
+ rc = RTDbgModSymbolByAddr(hMod, RTDBGSEGIDX_ABS, Addr, fFlags, poffDisp, pSymbol);
+ if (RT_SUCCESS(rc))
+ {
+ rtDbgAsAdjustSymbolValue(pSymbol, hMod, MapAddr, iSeg);
+ if (phMod)
+ RTDbgModRetain(*phMod = hMod);
+ }
+ }
+
+ for (uint32_t i = 0; i < cModules; i++)
+ RTDbgModRelease(pahModules[i]);
+ RTMemTmpFree(pahModules);
+ return rc;
}
/*
@@ -1386,37 +1476,6 @@ RT_EXPORT_SYMBOL(RTDbgAsSymbolByAddrA);
/**
- * Creates a snapshot of the module table on the temporary heap.
- *
- * The caller must release all the module handles before freeing the table
- * using RTMemTmpFree.
- *
- * @returns Module table snaphot.
- * @param pDbgAs The address space instance data.
- * @param pcModules Where to return the number of modules.
- */
-DECLINLINE(PRTDBGMOD) rtDbgAsSnapshotModuleTable(PRTDBGASINT pDbgAs, uint32_t *pcModules)
-{
- RTDBGAS_LOCK_READ(pDbgAs);
-
- uint32_t iMod = *pcModules = pDbgAs->cModules;
- PRTDBGMOD pahModules = (PRTDBGMOD)RTMemTmpAlloc(sizeof(pahModules[0]) * RT_MAX(iMod, 1));
- if (pahModules)
- {
- while (iMod-- > 0)
- {
- RTDBGMOD hMod = (RTDBGMOD)pDbgAs->papModules[iMod]->Core.Key;
- pahModules[iMod] = hMod;
- RTDbgModRetain(hMod);
- }
- }
-
- RTDBGAS_UNLOCK_READ(pDbgAs);
- return pahModules;
-}
-
-
-/**
* Attempts to find a mapping of the specified symbol/module and
* adjust it's Value field accordingly.
*
@@ -1675,20 +1734,7 @@ RTDECL(int) RTDbgAsLineAdd(RTDBGAS hDbgAs, const char *pszFile, uint32_t uLineNo
RT_EXPORT_SYMBOL(RTDbgAsLineAdd);
-/**
- * Query a line number 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.
- *
- * @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.
- */
-RTDECL(int) RTDbgAsLineByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE pLine)
+RTDECL(int) RTDbgAsLineByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod)
{
/*
* Validate input and resolve the address.
@@ -1708,28 +1754,21 @@ RTDECL(int) RTDbgAsLineByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp
*/
int rc = RTDbgModLineByAddr(hMod, iSeg, offSeg, poffDisp, pLine);
if (RT_SUCCESS(rc))
+ {
rtDbgAsAdjustLineAddress(pLine, hMod, MapAddr, iSeg);
- RTDbgModRelease(hMod);
+ if (phMod)
+ *phMod = hMod;
+ else
+ RTDbgModRelease(hMod);
+ }
+ else
+ RTDbgModRelease(hMod);
return rc;
}
RT_EXPORT_SYMBOL(RTDbgAsLineByAddr);
-/**
- * Query a line number 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.
- *
- * @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.
- */
-RTDECL(int) RTDbgAsLineByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE *ppLine)
+RTDECL(int) RTDbgAsLineByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE *ppLine, PRTDBGMOD phMod)
{
/*
* Validate input and resolve the address.
@@ -1749,8 +1788,15 @@ RTDECL(int) RTDbgAsLineByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDis
*/
int rc = RTDbgModLineByAddrA(hMod, iSeg, offSeg, poffDisp, ppLine);
if (RT_SUCCESS(rc))
+ {
rtDbgAsAdjustLineAddress(*ppLine, hMod, MapAddr, iSeg);
- RTDbgModRelease(hMod);
+ if (phMod)
+ *phMod = hMod;
+ else
+ RTDbgModRelease(hMod);
+ }
+ else
+ RTDbgModRelease(hMod);
return rc;
}
RT_EXPORT_SYMBOL(RTDbgAsLineByAddrA);
diff --git a/src/VBox/Runtime/common/dbg/dbgcfg.cpp b/src/VBox/Runtime/common/dbg/dbgcfg.cpp
new file mode 100644
index 00000000..77555180
--- /dev/null
+++ b/src/VBox/Runtime/common/dbg/dbgcfg.cpp
@@ -0,0 +1,2172 @@
+/* $Id: dbgcfg.cpp $ */
+/** @file
+ * IPRT - Debugging Configuration.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DBG
+#include <iprt/dbg.h>
+#include "internal/iprt.h"
+
+#include <iprt/alloca.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/ctype.h>
+#include <iprt/dir.h>
+#include <iprt/err.h>
+#include <iprt/env.h>
+#include <iprt/file.h>
+#ifdef IPRT_WITH_HTTP
+# include <iprt/http.h>
+#endif
+#include <iprt/list.h>
+#include <iprt/log.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/process.h>
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+#include <iprt/uuid.h>
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * String list entry.
+ */
+typedef struct RTDBGCFGSTR
+{
+ /** List entry. */
+ RTLISTNODE ListEntry;
+ /** Domain specific flags. */
+ uint16_t fFlags;
+ /** The length of the string. */
+ uint16_t cch;
+ /** The string. */
+ char sz[1];
+} RTDBGCFGSTR;
+/** Pointer to a string list entry. */
+typedef RTDBGCFGSTR *PRTDBGCFGSTR;
+
+
+/**
+ * Configuration instance.
+ */
+typedef struct RTDBGCFGINT
+{
+ /** The magic value (RTDBGCFG_MAGIC). */
+ uint32_t u32Magic;
+ /** Reference counter. */
+ uint32_t volatile cRefs;
+ /** Flags, see RTDBGCFG_FLAGS_XXX. */
+ uint64_t fFlags;
+
+ /** List of paths to search for debug files and executable images. */
+ RTLISTANCHOR PathList;
+ /** List of debug file suffixes. */
+ RTLISTANCHOR SuffixList;
+ /** List of paths to search for source files. */
+ RTLISTANCHOR SrcPathList;
+
+#ifdef RT_OS_WINDOWS
+ /** The _NT_ALT_SYMBOL_PATH and _NT_SYMBOL_PATH combined. */
+ RTLISTANCHOR NtSymbolPathList;
+ /** The _NT_EXECUTABLE_PATH. */
+ RTLISTANCHOR NtExecutablePathList;
+ /** The _NT_SOURCE_PATH. */
+ RTLISTANCHOR NtSourcePath;
+#endif
+
+ /** Log callback function. */
+ PFNRTDBGCFGLOG pfnLogCallback;
+ /** User argument to pass to the log callback. */
+ void *pvLogUser;
+
+ /** Critical section protecting the instance data. */
+ RTCRITSECTRW CritSect;
+} *PRTDBGCFGINT;
+
+/**
+ * Mnemonics map entry for a 64-bit unsigned property value.
+ */
+typedef struct RTDBGCFGU64MNEMONIC
+{
+ /** The flags to set or clear. */
+ uint64_t fFlags;
+ /** The mnemonic. */
+ const char *pszMnemonic;
+ /** The length of the mnemonic. */
+ uint8_t cchMnemonic;
+ /** If @c true, the bits in fFlags will be set, if @c false they will be
+ * cleared. */
+ bool fSet;
+} RTDBGCFGU64MNEMONIC;
+/** Pointer to a read only mnemonic map entry for a uint64_t property. */
+typedef RTDBGCFGU64MNEMONIC const *PCRTDBGCFGU64MNEMONIC;
+
+
+/** @name Open flags.
+ * @{ */
+/** The operative system mask. The values are RT_OPSYS_XXX. */
+#define RTDBGCFG_O_OPSYS_MASK UINT32_C(0x000000ff)
+/** 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)
+/** @} */
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** Validates a debug module handle and returns rc if not valid. */
+#define RTDBGCFG_VALID_RETURN_RC(pThis, rc) \
+ do { \
+ AssertPtrReturn((pThis), (rc)); \
+ AssertReturn((pThis)->u32Magic == RTDBGCFG_MAGIC, (rc)); \
+ AssertReturn((pThis)->cRefs > 0, (rc)); \
+ } while (0)
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** Mnemonics map for RTDBGCFGPROP_FLAGS. */
+static const RTDBGCFGU64MNEMONIC g_aDbgCfgFlags[] =
+{
+ { RTDBGCFG_FLAGS_DEFERRED, RT_STR_TUPLE("deferred"), true },
+ { RTDBGCFG_FLAGS_DEFERRED, RT_STR_TUPLE("nodeferred"), false },
+ { RTDBGCFG_FLAGS_NO_SYM_SRV, RT_STR_TUPLE("symsrv"), false },
+ { RTDBGCFG_FLAGS_NO_SYM_SRV, RT_STR_TUPLE("nosymsrv"), true },
+ { RTDBGCFG_FLAGS_NO_SYSTEM_PATHS, RT_STR_TUPLE("syspaths"), false },
+ { RTDBGCFG_FLAGS_NO_SYSTEM_PATHS, RT_STR_TUPLE("nosyspaths"), true },
+ { RTDBGCFG_FLAGS_NO_RECURSIV_SEARCH, RT_STR_TUPLE("rec"), false },
+ { RTDBGCFG_FLAGS_NO_RECURSIV_SEARCH, RT_STR_TUPLE("norec"), true },
+ { RTDBGCFG_FLAGS_NO_RECURSIV_SRC_SEARCH, RT_STR_TUPLE("recsrc"), false },
+ { RTDBGCFG_FLAGS_NO_RECURSIV_SRC_SEARCH, RT_STR_TUPLE("norecsrc"), true },
+ { 0, NULL, 0, false }
+};
+
+
+
+/**
+ * Runtime logging, level 1.
+ *
+ * @param pThis The debug config instance data.
+ * @param pszFormat The message format string.
+ * @param ... Arguments references in the format string.
+ */
+static void rtDbgCfgLog1(PRTDBGCFGINT pThis, const char *pszFormat, ...)
+{
+ if (LogIsEnabled() || (pThis && pThis->pfnLogCallback))
+ {
+ va_list va;
+ va_start(va, pszFormat);
+ char *pszMsg = RTStrAPrintf2V(pszFormat, va);
+ va_end(va);
+
+ Log(("RTDbgCfg: %s", pszMsg));
+ if (pThis && pThis->pfnLogCallback)
+ pThis->pfnLogCallback(pThis, 1, pszMsg, pThis->pvLogUser);
+ RTStrFree(pszMsg);
+ }
+}
+
+
+/**
+ * Runtime logging, level 2.
+ *
+ * @param pThis The debug config instance data.
+ * @param pszFormat The message format string.
+ * @param ... Arguments references in the format string.
+ */
+static void rtDbgCfgLog2(PRTDBGCFGINT pThis, const char *pszFormat, ...)
+{
+ if (LogIs2Enabled() || (pThis && pThis->pfnLogCallback))
+ {
+ va_list va;
+ va_start(va, pszFormat);
+ char *pszMsg = RTStrAPrintf2V(pszFormat, va);
+ va_end(va);
+
+ Log(("RTDbgCfg: %s", pszMsg));
+ if (pThis && pThis->pfnLogCallback)
+ pThis->pfnLogCallback(pThis, 2, pszMsg, pThis->pvLogUser);
+ RTStrFree(pszMsg);
+ }
+}
+
+
+/**
+ * Checks if the file system at the given path is case insensitive or not.
+ *
+ * @returns true / false
+ * @param pszPath The path to query about.
+ */
+static int rtDbgCfgIsFsCaseInsensitive(const char *pszPath)
+{
+ RTFSPROPERTIES Props;
+ int rc = RTFsQueryProperties(pszPath, &Props);
+ if (RT_FAILURE(rc))
+ return RT_OPSYS == RT_OPSYS_DARWIN
+ || RT_OPSYS == RT_OPSYS_DOS
+ || RT_OPSYS == RT_OPSYS_OS2
+ || RT_OPSYS == RT_OPSYS_NT
+ || RT_OPSYS == RT_OPSYS_WINDOWS;
+ return !Props.fCaseSensitive;
+}
+
+
+/**
+ * Worker that does case sensitive file/dir searching.
+ *
+ * @returns true / false.
+ * @param pszPath The path buffer containing an existing directory.
+ * RTPATH_MAX in size. On success, this will contain
+ * the combined path with @a pszName case correct.
+ * @param offLastComp The offset of the last component (for chopping it
+ * off).
+ * @param pszName What we're looking for.
+ * @param enmType What kind of thing we're looking for.
+ */
+static bool rtDbgCfgIsXxxxAndFixCaseWorker(char *pszPath, size_t offLastComp, const char *pszName,
+ RTDIRENTRYTYPE enmType)
+{
+ /** @todo IPRT should generalize this so we can use host specific tricks to
+ * speed it up. */
+
+ /* Return straight away if the name isn't case foldable. */
+ if (!RTStrIsCaseFoldable(pszName))
+ return false;
+
+ /*
+ * Try some simple case folding games.
+ */
+ RTStrToLower(&pszPath[offLastComp]);
+ if (RTFileExists(pszPath))
+ return true;
+
+ RTStrToUpper(&pszPath[offLastComp]);
+ if (RTFileExists(pszPath))
+ return true;
+
+ /*
+ * Open the directory and check each entry in it.
+ */
+ pszPath[offLastComp] = '\0';
+ PRTDIR pDir;
+ int rc = RTDirOpen(&pDir, pszPath);
+ if (RT_FAILURE(rc))
+ return false;
+
+ for (;;)
+ {
+ /* Read the next entry. */
+ union
+ {
+ RTDIRENTRY Entry;
+ uint8_t ab[_4K];
+ } u;
+ size_t cbBuf = sizeof(u);
+ rc = RTDirRead(pDir, &u.Entry, &cbBuf);
+ if (RT_FAILURE(rc))
+ break;
+
+ if ( !RTStrICmp(pszName, u.Entry.szName)
+ && ( u.Entry.enmType == enmType
+ || u.Entry.enmType == RTDIRENTRYTYPE_UNKNOWN
+ || u.Entry.enmType == RTDIRENTRYTYPE_SYMLINK) )
+ {
+ pszPath[offLastComp] = '\0';
+ rc = RTPathAppend(pszPath, RTPATH_MAX, u.Entry.szName);
+ if ( u.Entry.enmType != enmType
+ && RT_SUCCESS(rc))
+ RTDirQueryUnknownType(pszPath, true /*fFollowSymlinks*/, &u.Entry.enmType);
+
+ if ( u.Entry.enmType == enmType
+ || RT_FAILURE(rc))
+ {
+ RTDirClose(pDir);
+ if (RT_FAILURE(rc))
+ {
+ pszPath[offLastComp] = '\0';
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ RTDirClose(pDir);
+ pszPath[offLastComp] = '\0';
+
+ return false;
+}
+
+
+/**
+ * Appends @a pszSubDir to @a pszPath and check whether it exists and is a
+ * directory.
+ *
+ * If @a fCaseInsensitive is set, we will do a case insensitive search for a
+ * matching sub directory.
+ *
+ * @returns true / false
+ * @param pszPath The path buffer containing an existing
+ * directory. RTPATH_MAX in size.
+ * @param pszSubDir The sub directory to append.
+ * @param fCaseInsensitive Whether case insensitive searching is required.
+ */
+static bool rtDbgCfgIsDirAndFixCase(char *pszPath, const char *pszSubDir, bool fCaseInsensitive)
+{
+ /* Save the length of the input path so we can restore it in the case
+ insensitive branch further down. */
+ size_t const cchPath = strlen(pszPath);
+
+ /*
+ * Append the sub directory and check if we got a hit.
+ */
+ int rc = RTPathAppend(pszPath, RTPATH_MAX, pszSubDir);
+ if (RT_FAILURE(rc))
+ return false;
+
+ if (RTDirExists(pszPath))
+ return true;
+
+ /*
+ * Do case insensitive lookup if requested.
+ */
+ if (fCaseInsensitive)
+ return rtDbgCfgIsXxxxAndFixCaseWorker(pszPath, cchPath, pszSubDir, RTDIRENTRYTYPE_DIRECTORY);
+
+ pszPath[cchPath] = '\0';
+ return false;
+}
+
+
+/**
+ * Appends @a pszFilename to @a pszPath and check whether it exists and is a
+ * directory.
+ *
+ * If @a fCaseInsensitive is set, we will do a case insensitive search for a
+ * matching filename.
+ *
+ * @returns true / false
+ * @param pszPath The path buffer containing an existing
+ * directory. RTPATH_MAX in size.
+ * @param pszFilename The file name to append.
+ * @param fCaseInsensitive Whether case insensitive searching is required.
+ * @param fMsCompressed Whether to look for the MS compressed file name
+ * variant.
+ * @param pfProbablyCompressed This is set to true if a MS compressed
+ * filename variant is returned. Optional.
+ */
+static bool rtDbgCfgIsFileAndFixCase(char *pszPath, const char *pszFilename, bool fCaseInsensitive,
+ bool fMsCompressed, bool *pfProbablyCompressed)
+{
+ /* Save the length of the input path so we can restore it in the case
+ insensitive branch further down. */
+ size_t cchPath = strlen(pszPath);
+ if (pfProbablyCompressed)
+ *pfProbablyCompressed = false;
+
+ /*
+ * Append the filename and check if we got a hit.
+ */
+ int rc = RTPathAppend(pszPath, RTPATH_MAX, pszFilename);
+ if (RT_FAILURE(rc))
+ return false;
+
+ if (RTFileExists(pszPath))
+ return true;
+
+ /*
+ * Do case insensitive file lookup if requested.
+ */
+ if (fCaseInsensitive)
+ {
+ if (rtDbgCfgIsXxxxAndFixCaseWorker(pszPath, cchPath, pszFilename, RTDIRENTRYTYPE_FILE))
+ return true;
+ }
+
+ /*
+ * Look for MS compressed file if requested.
+ */
+ if ( fMsCompressed
+ && (unsigned char)pszFilename[strlen(pszFilename) - 1] < 0x7f)
+ {
+ pszPath[cchPath] = '\0';
+ rc = RTPathAppend(pszPath, RTPATH_MAX, pszFilename);
+ AssertRCReturn(rc, false);
+ pszPath[strlen(pszPath) - 1] = '_';
+
+ if (pfProbablyCompressed)
+ *pfProbablyCompressed = true;
+
+ if (RTFileExists(pszPath))
+ return true;
+
+ if (fCaseInsensitive)
+ {
+ /* Note! Ugly hack here, the pszName parameter points into pszPath! */
+ if (rtDbgCfgIsXxxxAndFixCaseWorker(pszPath, cchPath, RTPathFilename(pszPath), RTDIRENTRYTYPE_FILE))
+ return true;
+ }
+
+ if (pfProbablyCompressed)
+ *pfProbablyCompressed = false;
+ }
+
+ pszPath[cchPath] = '\0';
+ return false;
+}
+
+
+static int rtDbgCfgTryOpenDir(PRTDBGCFGINT pThis, char *pszPath, PRTPATHSPLIT pSplitFn, uint32_t fFlags,
+ PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ int rcRet = VWRN_NOT_FOUND;
+ int rc2;
+
+ /* If the directory doesn't exist, just quit immediately.
+ Note! Our case insensitivity doesn't extend to the search dirs themselfs,
+ only to the bits under neath them. */
+ if (!RTDirExists(pszPath))
+ {
+ rtDbgCfgLog2(pThis, "Dir does not exist: '%s'\n", pszPath);
+ return rcRet;
+ }
+
+ /* Figure out whether we have to do a case sensitive search or not.
+ Note! As a simplification, we don't ask for case settings in each
+ directory under the user specified path, we assume the file
+ systems that mounted there have compatible settings. Faster
+ that way. */
+ bool const fCaseInsensitive = (fFlags & RTDBGCFG_O_CASE_INSENSITIVE)
+ && !rtDbgCfgIsFsCaseInsensitive(pszPath);
+
+ size_t const cchPath = strlen(pszPath);
+
+ /*
+ * Look for the file with less and less of the original path given.
+ */
+ for (unsigned i = RTPATH_PROP_HAS_ROOT_SPEC(pSplitFn->fProps); i < pSplitFn->cComps; i++)
+ {
+ pszPath[cchPath] = '\0';
+
+ rc2 = VINF_SUCCESS;
+ for (unsigned j = i; j < pSplitFn->cComps - 1U && RT_SUCCESS(rc2); j++)
+ if (!rtDbgCfgIsDirAndFixCase(pszPath, pSplitFn->apszComps[i], fCaseInsensitive))
+ rc2 = VERR_FILE_NOT_FOUND;
+
+ if (RT_SUCCESS(rc2))
+ {
+ if (rtDbgCfgIsFileAndFixCase(pszPath, pSplitFn->apszComps[pSplitFn->cComps - 1], fCaseInsensitive, false, NULL))
+ {
+ rtDbgCfgLog1(pThis, "Trying '%s'...\n", pszPath);
+ rc2 = pfnCallback(pThis, pszPath, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ {
+ if (rc2 == VINF_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Found '%s'.\n", pszPath);
+ else
+ rtDbgCfgLog1(pThis, "Error opening '%s'.\n", pszPath);
+ return rc2;
+ }
+ rtDbgCfgLog1(pThis, "Error %Rrc opening '%s'.\n", rc2, pszPath);
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+ }
+ }
+ }
+
+ /*
+ * Do a recursive search if requested.
+ */
+ if ( (fFlags & RTDBGCFG_O_RECURSIVE)
+ && !(pThis->fFlags & RTDBGCFG_FLAGS_NO_RECURSIV_SEARCH) )
+ {
+ /** @todo Recursive searching will be done later. */
+ }
+
+ return rcRet;
+}
+
+static int rtDbgCfgUnpackMsCacheFile(PRTDBGCFGINT pThis, char *pszPath, const char *pszFilename)
+{
+ rtDbgCfgLog2(pThis, "Unpacking '%s'...\n", pszPath);
+
+ /*
+ * Duplicate the source file path, just for simplicity and restore the
+ * final character in the orignal. We cheerfully ignorining any
+ * possibility of multibyte UTF-8 sequences just like the caller did when
+ * setting it to '_'.
+ */
+ char *pszSrcArchive = RTStrDup(pszPath);
+ if (!pszSrcArchive)
+ return VERR_NO_STR_MEMORY;
+
+ pszPath[strlen(pszPath) - 1] = RT_C_TO_LOWER(pszFilename[strlen(pszFilename) - 1]);
+
+
+ /*
+ * Figuring out the argument list for the platform specific unpack util.
+ */
+#ifdef RT_OS_WINDOWS
+ const char *papszArgs[] =
+ {
+ "expand.exe",
+ pszSrcArchive,
+ pszPath,
+ NULL
+ };
+
+#else
+ char szExtractDir[RTPATH_MAX];
+ strcpy(szExtractDir, pszPath);
+ RTPathStripFilename(szExtractDir);
+
+ const char *papszArgs[] =
+ {
+ "cabextract",
+ "-L", /* Lower case extracted files. */
+ "-d", szExtractDir, /* Extraction path */
+ pszSrcArchive,
+ NULL
+ };
+#endif
+
+ /*
+ * Do the unpacking.
+ */
+ RTPROCESS hChild;
+ int rc = RTProcCreate(papszArgs[0], papszArgs, RTENV_DEFAULT,
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ RTPROC_FLAGS_NO_WINDOW | RTPROC_FLAGS_HIDDEN | RTPROC_FLAGS_SEARCH_PATH,
+#else
+ RTPROC_FLAGS_SEARCH_PATH,
+#endif
+ &hChild);
+ if (RT_SUCCESS(rc))
+ {
+ RTPROCSTATUS ProcStatus;
+ rc = RTProcWait(hChild, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus);
+ if (RT_SUCCESS(rc))
+ {
+ if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
+ && ProcStatus.iStatus == 0)
+ {
+ if (RTPathExists(pszPath))
+ {
+ rtDbgCfgLog1(pThis, "Successfully unpacked '%s' to '%s'.\n", pszSrcArchive, pszPath);
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+ rtDbgCfgLog1(pThis, "Successfully ran unpacker on '%s', but '%s' is missing!\n", pszSrcArchive, pszPath);
+ rc = VERR_ZIP_ERROR;
+ }
+ }
+ else
+ {
+ rtDbgCfgLog2(pThis, "Unpacking '%s' failed: iStatus=%d enmReason=%d\n",
+ pszSrcArchive, ProcStatus.iStatus, ProcStatus.enmReason);
+ rc = VERR_ZIP_CORRUPTED;
+ }
+ }
+ else
+ rtDbgCfgLog1(pThis, "Error waiting for process: %Rrc\n", rc);
+
+ }
+ else
+ rtDbgCfgLog1(pThis, "Error starting unpack process '%s': %Rrc\n", papszArgs[0], rc);
+
+ return rc;
+}
+
+static int rtDbgCfgTryDownloadAndOpen(PRTDBGCFGINT pThis, const char *pszServer,
+ char *pszPath, const char *pszCacheSubDir, PRTPATHSPLIT pSplitFn,
+ uint32_t fFlags, PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+#ifdef IPRT_WITH_HTTP
+ if (pThis->fFlags & RTDBGCFG_FLAGS_NO_SYM_SRV)
+ return VWRN_NOT_FOUND;
+ if (!pszCacheSubDir || !*pszCacheSubDir)
+ return VWRN_NOT_FOUND;
+
+ /*
+ * Create the path.
+ */
+ size_t cchTmp = strlen(pszPath);
+
+ int rc = RTDirCreateFullPath(pszPath, 0766);
+ if (!RTDirExists(pszPath))
+ {
+ Log(("Error creating cache dir '%s': %Rrc\n", pszPath, rc));
+ return rc;
+ }
+
+ const char *pszFilename = pSplitFn->apszComps[pSplitFn->cComps - 1];
+ rc = RTPathAppend(pszPath, RTPATH_MAX, pszFilename);
+ if (RT_FAILURE(rc))
+ return rc;
+ RTStrToLower(&pszPath[cchTmp]);
+ if (!RTDirExists(pszPath))
+ {
+ rc = RTDirCreate(pszPath, 0766, 0);
+ if (RT_FAILURE(rc))
+ {
+ Log(("RTDirCreate(%s) -> %Rrc\n", pszPath, rc));
+ }
+ }
+
+ rc = RTPathAppend(pszPath, RTPATH_MAX, pszCacheSubDir);
+ if (RT_FAILURE(rc))
+ return rc;
+ if (!RTDirExists(pszPath))
+ {
+ rc = RTDirCreate(pszPath, 0766, 0);
+ if (RT_FAILURE(rc))
+ {
+ Log(("RTDirCreate(%s) -> %Rrc\n", pszPath, rc));
+ }
+ }
+
+ /* Prepare the destination file name while we're here. */
+ cchTmp = strlen(pszPath);
+ RTStrToLower(&pszPath[cchTmp]);
+ rc = RTPathAppend(pszPath, RTPATH_MAX, pszFilename);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Download the file.
+ */
+ RTHTTP hHttp;
+ rc = RTHttpCreate(&hHttp);
+ if (RT_FAILURE(rc))
+ return rc;
+ RTHttpUseSystemProxySettings(hHttp);
+
+ static const char * const s_apszHeaders[] =
+ {
+ "User-Agent: Microsoft-Symbol-Server/6.6.0999.9",
+ "Pragma: no-cache",
+ };
+
+ rc = RTHttpSetHeaders(hHttp, RT_ELEMENTS(s_apszHeaders), s_apszHeaders);
+ if (RT_SUCCESS(rc))
+ {
+ char szUrl[_2K];
+ RTStrPrintf(szUrl, sizeof(szUrl), "%s/%s/%s/%s", pszServer, pszFilename, pszCacheSubDir, pszFilename);
+
+ /** @todo Use some temporary file name and rename it after the operation
+ * since not all systems support read-deny file sharing
+ * settings. */
+ rtDbgCfgLog2(pThis, "Downloading '%s' to '%s'...\n", szUrl, pszPath);
+ rc = RTHttpGetFile(hHttp, szUrl, pszPath);
+ if (RT_FAILURE(rc))
+ {
+ RTFileDelete(pszPath);
+ rtDbgCfgLog1(pThis, "%Rrc on URL '%s'\n", rc, pszPath);
+ }
+ if (rc == VERR_HTTP_NOT_FOUND)
+ {
+ /* Try the compressed version of the file. */
+ pszPath[strlen(pszPath) - 1] = '_';
+ szUrl[strlen(szUrl) - 1] = '_';
+ rtDbgCfgLog2(pThis, "Downloading '%s' to '%s'...\n", szUrl, pszPath);
+ rc = RTHttpGetFile(hHttp, szUrl, pszPath);
+ if (RT_SUCCESS(rc))
+ rc = rtDbgCfgUnpackMsCacheFile(pThis, pszPath, pszFilename);
+ else
+ {
+ rtDbgCfgLog1(pThis, "%Rrc on URL '%s'\n", rc, pszPath);
+ RTFileDelete(pszPath);
+ }
+ }
+ }
+
+ RTHttpDestroy(hHttp);
+
+ /*
+ * If we succeeded, give it a try.
+ */
+ if (RT_SUCCESS(rc))
+ {
+ Assert(RTFileExists(pszPath));
+ rtDbgCfgLog1(pThis, "Trying '%s'...\n", pszPath);
+ rc = pfnCallback(pThis, pszPath, pvUser1, pvUser2);
+ if (rc == VINF_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Found '%s'.\n", pszPath);
+ else if (rc == VERR_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Error opening '%s'.\n", pszPath);
+ else
+ rtDbgCfgLog1(pThis, "Error %Rrc opening '%s'.\n", rc, pszPath);
+ }
+
+ return rc;
+
+#else /* !IPRT_WITH_HTTP */
+ return VWRN_NOT_FOUND;
+#endif /* !IPRT_WITH_HTTP */
+}
+
+
+static int rtDbgCfgCopyFileToCache(PRTDBGCFGINT pThis, char const *pszSrc, const char *pchCache, size_t cchCache,
+ const char *pszCacheSubDir, PRTPATHSPLIT pSplitFn)
+{
+ if (!pszCacheSubDir || !*pszCacheSubDir)
+ return VINF_SUCCESS;
+
+ /** @todo copy to cache */
+ return VINF_SUCCESS;
+}
+
+
+static int rtDbgCfgTryOpenCache(PRTDBGCFGINT pThis, char *pszPath, const char *pszCacheSubDir, PRTPATHSPLIT pSplitFn,
+ uint32_t fFlags, PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ /*
+ * If the cache doesn't exist, fail right away.
+ */
+ if (!pszCacheSubDir || !*pszCacheSubDir)
+ return VWRN_NOT_FOUND;
+ if (!RTDirExists(pszPath))
+ {
+ rtDbgCfgLog2(pThis, "Cache does not exist: '%s'\n", pszPath);
+ return VWRN_NOT_FOUND;
+ }
+
+ size_t cchPath = strlen(pszPath);
+
+ /*
+ * Carefully construct the cache path with case insensitivity in mind.
+ */
+ bool const fCaseInsensitive = (fFlags & RTDBGCFG_O_CASE_INSENSITIVE)
+ && !rtDbgCfgIsFsCaseInsensitive(pszPath);
+ const char *pszFilename = pSplitFn->apszComps[pSplitFn->cComps - 1];
+
+ if (!rtDbgCfgIsDirAndFixCase(pszPath, pszFilename, fCaseInsensitive))
+ return VWRN_NOT_FOUND;
+
+ if (!rtDbgCfgIsDirAndFixCase(pszPath, pszCacheSubDir, fCaseInsensitive))
+ return VWRN_NOT_FOUND;
+
+ bool fProbablyCompressed = false;
+ if (!rtDbgCfgIsFileAndFixCase(pszPath, pszFilename, fCaseInsensitive,
+ RT_BOOL(fFlags & RTDBGCFG_O_MAYBE_COMPRESSED_MS), &fProbablyCompressed))
+ return VWRN_NOT_FOUND;
+ if (fProbablyCompressed)
+ {
+ int rc = rtDbgCfgUnpackMsCacheFile(pThis, pszPath, pszFilename);
+ if (RT_FAILURE(rc))
+ return VWRN_NOT_FOUND;
+ }
+
+ rtDbgCfgLog1(pThis, "Trying '%s'...\n", pszPath);
+ int rc2 = pfnCallback(pThis, pszPath, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Found '%s'.\n", pszPath);
+ else if (rc2 == VERR_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Error opening '%s'.\n", pszPath);
+ else
+ rtDbgCfgLog1(pThis, "Error %Rrc opening '%s'.\n", rc2, pszPath);
+ return rc2;
+}
+
+
+static int rtDbgCfgTryOpenList(PRTDBGCFGINT pThis, PRTLISTANCHOR pList, PRTPATHSPLIT pSplitFn, const char *pszCacheSubDir,
+ uint32_t fFlags, char *pszPath, PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ int rcRet = VWRN_NOT_FOUND;
+ int rc2;
+
+ const char *pchCache = NULL;
+ size_t cchCache = 0;
+ int rcCache = VWRN_NOT_FOUND;
+
+ PRTDBGCFGSTR pCur;
+ RTListForEach(pList, pCur, RTDBGCFGSTR, ListEntry)
+ {
+ size_t cchDir = pCur->cch;
+ const char *pszDir = pCur->sz;
+ rtDbgCfgLog2(pThis, "Path list entry: '%s'\n", pszDir);
+
+ /* This is very simplistic, but we have a unreasonably large path
+ buffer, so it'll work just fine and simplify things greatly below. */
+ if (cchDir >= RTPATH_MAX - 8U)
+ {
+ if (RT_SUCCESS_NP(rcRet))
+ rcRet = VERR_FILENAME_TOO_LONG;
+ continue;
+ }
+
+ /*
+ * Process the path according to it's type.
+ */
+ if (!strncmp(pszDir, RT_STR_TUPLE("srv*")))
+ {
+ /*
+ * Symbol server.
+ */
+ pszDir += sizeof("srv*") - 1;
+ cchDir -= sizeof("srv*") - 1;
+ bool fSearchCache = false;
+ const char *pszServer = (const char *)memchr(pszDir, '*', cchDir);
+ if (!pszServer)
+ pszServer = pszDir;
+ else if (pszServer == pszDir)
+ continue;
+ {
+ fSearchCache = true;
+ pchCache = pszDir;
+ cchCache = pszServer - pszDir;
+ pszServer++;
+ }
+
+ /* We don't have any default cache directory, so skip if the cache is missing. */
+ if (cchCache == 0)
+ continue;
+
+ /* Search the cache first (if we haven't already done so). */
+ if (fSearchCache)
+ {
+ memcpy(pszPath, pchCache, cchCache);
+ pszPath[cchCache] = '\0';
+ RTPathChangeToUnixSlashes(pszPath, false);
+
+ rcCache = rc2 = rtDbgCfgTryOpenCache(pThis, pszPath, pszCacheSubDir, pSplitFn, fFlags,
+ pfnCallback, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ return rc2;
+ }
+
+ /* Try downloading the file. */
+ if (rcCache == VWRN_NOT_FOUND)
+ {
+ memcpy(pszPath, pchCache, cchCache);
+ pszPath[cchCache] = '\0';
+ RTPathChangeToUnixSlashes(pszPath, false);
+
+ rc2 = rtDbgCfgTryDownloadAndOpen(pThis, pszServer, pszPath, pszCacheSubDir, pSplitFn, fFlags,
+ pfnCallback, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ return rc2;
+ }
+ }
+ else if (!strncmp(pszDir, RT_STR_TUPLE("cache*")))
+ {
+ /*
+ * Cache directory.
+ */
+ pszDir += sizeof("cache*") - 1;
+ cchDir -= sizeof("cache*") - 1;
+ if (!cchDir)
+ continue;
+ pchCache = pszDir;
+ cchCache = cchDir;
+
+ memcpy(pszPath, pchCache, cchCache);
+ pszPath[cchCache] = '\0';
+ RTPathChangeToUnixSlashes(pszPath, false);
+
+ rcCache = rc2 = rtDbgCfgTryOpenCache(pThis, pszPath, pszCacheSubDir, pSplitFn, fFlags,
+ pfnCallback, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ return rc2;
+ }
+ else
+ {
+ /*
+ * Normal directory. Check for our own 'rec*' and 'norec*' prefix
+ * flags governing recursive searching.
+ */
+ uint32_t fFlagsDir = fFlags;
+ if (!strncmp(pszDir, RT_STR_TUPLE("rec*")))
+ {
+ pszDir += sizeof("rec*") - 1;
+ cchDir -= sizeof("rec*") - 1;
+ fFlagsDir |= RTDBGCFG_O_RECURSIVE;
+ }
+ else if (!strncmp(pszDir, RT_STR_TUPLE("norec*")))
+ {
+ pszDir += sizeof("norec*") - 1;
+ cchDir -= sizeof("norec*") - 1;
+ fFlagsDir &= ~RTDBGCFG_O_RECURSIVE;
+ }
+
+ /* Copy the path into the buffer and do the searching. */
+ memcpy(pszPath, pszDir, cchDir);
+ pszPath[cchDir] = '\0';
+ RTPathChangeToUnixSlashes(pszPath, false);
+
+ rc2 = rtDbgCfgTryOpenDir(pThis, pszPath, pSplitFn, fFlagsDir, pfnCallback, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ {
+ if ( rc2 == VINF_CALLBACK_RETURN
+ && cchCache > 0)
+ rtDbgCfgCopyFileToCache(pThis, pszPath, pchCache, cchCache, pszCacheSubDir, pSplitFn);
+ return rc2;
+ }
+ }
+
+ /* Propagate errors. */
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+ }
+
+ return rcRet;
+}
+
+
+/**
+ * Common worker routine for Image and debug info opening.
+ *
+ * This will not search using for suffixes.
+ *
+ * @returns IPRT status code.
+ * @param hDbgCfg The debugging configuration handle. NIL_RTDBGCFG is
+ * accepted, but the result is that no paths will be
+ * searched beyond the given and the current directory.
+ * @param pszFilename The filename to search for. This may or may not
+ * include a full or partial path.
+ * @param pszCacheSubDir The cache subdirectory to look in.
+ * @param fFlags Flags and hints.
+ * @param pfnCallback The open callback routine.
+ * @param pvUser1 User parameter 1.
+ * @param pvUser2 User parameter 2.
+ */
+static int rtDbgCfgOpenWithSubDir(RTDBGCFG hDbgCfg, const char *pszFilename, const char *pszCacheSubDir,
+ uint32_t fFlags, PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ int rcRet = VINF_SUCCESS;
+ int rc2;
+
+ /*
+ * Do a little validating first.
+ */
+ PRTDBGCFGINT pThis = hDbgCfg;
+ if (pThis != NIL_RTDBGCFG)
+ RTDBGCFG_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+ else
+ pThis = NULL;
+ AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszCacheSubDir, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
+
+ /*
+ * Do some guessing as to the way we should parse the filename and whether
+ * it's case exact or not.
+ */
+ bool fDosPath = strchr(pszFilename, ':') != NULL
+ || strchr(pszFilename, '\\') != NULL
+ || RT_OPSYS_USES_DOS_PATHS(fFlags & RTDBGCFG_O_OPSYS_MASK)
+ || (fFlags & RTDBGCFG_O_CASE_INSENSITIVE);
+ if (fDosPath)
+ fFlags |= RTDBGCFG_O_CASE_INSENSITIVE;
+
+ rtDbgCfgLog2(pThis, "Looking for '%s' w/ cache subdir '%s' and %#x flags...\n", pszFilename, pszCacheSubDir, fFlags);
+
+ PRTPATHSPLIT pSplitFn;
+ rc2 = RTPathSplitA(pszFilename, &pSplitFn, fDosPath ? RTPATH_STR_F_STYLE_DOS : RTPATH_STR_F_STYLE_UNIX);
+ if (RT_FAILURE(rc2))
+ return rc2;
+ AssertReturnStmt(pSplitFn->fProps & RTPATH_PROP_FILENAME, RTPathSplitFree(pSplitFn), VERR_IS_A_DIRECTORY);
+
+ /*
+ * Try the stored file name first if it has a kind of absolute path.
+ */
+ char szPath[RTPATH_MAX];
+ if (RTPATH_PROP_HAS_ROOT_SPEC(pSplitFn->fProps))
+ {
+ rc2 = RTPathSplitReassemble(pSplitFn, RTPATH_STR_F_STYLE_HOST, szPath, sizeof(szPath));
+ if (RT_SUCCESS(rc2) && RTFileExists(szPath))
+ {
+ RTPathChangeToUnixSlashes(szPath, false);
+ rtDbgCfgLog1(pThis, "Trying '%s'...\n", szPath);
+ rc2 = pfnCallback(pThis, szPath, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Found '%s'.\n", szPath);
+ else if (rc2 == VERR_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Error opening '%s'.\n", szPath);
+ else
+ rtDbgCfgLog1(pThis, "Error %Rrc opening '%s'.\n", rc2, szPath);
+ }
+ }
+ if ( rc2 != VINF_CALLBACK_RETURN
+ && rc2 != VERR_CALLBACK_RETURN)
+ {
+ /*
+ * Try the current directory (will take cover relative paths
+ * skipped above).
+ */
+ rc2 = RTPathGetCurrent(szPath, sizeof(szPath));
+ if (RT_FAILURE(rc2))
+ strcpy(szPath, ".");
+ RTPathChangeToUnixSlashes(szPath, false);
+
+ rc2 = rtDbgCfgTryOpenDir(pThis, szPath, pSplitFn, fFlags, pfnCallback, pvUser1, pvUser2);
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+
+ if ( rc2 != VINF_CALLBACK_RETURN
+ && rc2 != VERR_CALLBACK_RETURN
+ && pThis)
+ {
+ rc2 = RTCritSectRwEnterShared(&pThis->CritSect);
+ if (RT_SUCCESS(rc2))
+ {
+ /*
+ * Run the applicable lists.
+ */
+ rc2 = rtDbgCfgTryOpenList(pThis, &pThis->PathList, pSplitFn, pszCacheSubDir, fFlags, szPath,
+ pfnCallback, pvUser1, pvUser2);
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+
+#ifdef RT_OS_WINDOWS
+ if ( rc2 != VINF_CALLBACK_RETURN
+ && rc2 != VERR_CALLBACK_RETURN
+ && (fFlags & RTDBGCFG_O_EXECUTABLE_IMAGE)
+ && !(pThis->fFlags & RTDBGCFG_FLAGS_NO_SYSTEM_PATHS) )
+ {
+ rc2 = rtDbgCfgTryOpenList(pThis, &pThis->NtExecutablePathList, pSplitFn, pszCacheSubDir, fFlags, szPath,
+ pfnCallback, pvUser1, pvUser2);
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+ }
+
+ if ( rc2 != VINF_CALLBACK_RETURN
+ && rc2 != VERR_CALLBACK_RETURN
+ && !(pThis->fFlags & RTDBGCFG_FLAGS_NO_SYSTEM_PATHS) )
+ {
+ rc2 = rtDbgCfgTryOpenList(pThis, &pThis->NtSymbolPathList, pSplitFn, pszCacheSubDir, fFlags, szPath,
+ pfnCallback, pvUser1, pvUser2);
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+ }
+#endif
+ RTCritSectRwLeaveShared(&pThis->CritSect);
+ }
+ else if (RT_SUCCESS(rcRet))
+ rcRet = rc2;
+ }
+ }
+
+ RTPathSplitFree(pSplitFn);
+ if ( rc2 == VINF_CALLBACK_RETURN
+ || rc2 == VERR_CALLBACK_RETURN)
+ rcRet = rc2;
+ else if (RT_SUCCESS(rcRet))
+ rcRet = VERR_NOT_FOUND;
+ return rcRet;
+}
+
+
+RTDECL(int) RTDbgCfgOpenPeImage(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp,
+ PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ char szSubDir[32];
+ RTStrPrintf(szSubDir, sizeof(szSubDir), "%08X%x", uTimestamp, cbImage);
+ return rtDbgCfgOpenWithSubDir(hDbgCfg, pszFilename, szSubDir,
+ RT_OPSYS_WINDOWS /* approx */ | RTDBGCFG_O_SYMSRV | RTDBGCFG_O_CASE_INSENSITIVE
+ | RTDBGCFG_O_MAYBE_COMPRESSED_MS | RTDBGCFG_O_EXECUTABLE_IMAGE,
+ pfnCallback, pvUser1, pvUser2);
+}
+
+
+RTDECL(int) RTDbgCfgOpenPdb70(RTDBGCFG hDbgCfg, const char *pszFilename, PCRTUUID pUuid, uint32_t uAge,
+ PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ char szSubDir[64];
+ if (!pUuid)
+ szSubDir[0] = '\0';
+ else
+ {
+ /* Stringify the UUID and remove the dashes. */
+ int rc2 = RTUuidToStr(pUuid, szSubDir, sizeof(szSubDir));
+ AssertRCReturn(rc2, rc2);
+
+ char *pszSrc = szSubDir;
+ char *pszDst = szSubDir;
+ char ch;
+ while ((ch = *pszSrc++))
+ if (ch != '-')
+ *pszDst++ = RT_C_TO_UPPER(ch);
+
+ RTStrPrintf(pszDst, &szSubDir[sizeof(szSubDir)] - pszDst, "%X", uAge);
+ }
+
+ return rtDbgCfgOpenWithSubDir(hDbgCfg, pszFilename, szSubDir,
+ RT_OPSYS_WINDOWS /* approx */ | RTDBGCFG_O_SYMSRV | RTDBGCFG_O_CASE_INSENSITIVE
+ | RTDBGCFG_O_MAYBE_COMPRESSED_MS | RTDBGCFG_O_EXT_DEBUG_FILE,
+ pfnCallback, pvUser1, pvUser2);
+}
+
+
+RTDECL(int) RTDbgCfgOpenPdb20(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp, uint32_t uAge,
+ PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ /** @todo test this! */
+ char szSubDir[32];
+ RTStrPrintf(szSubDir, sizeof(szSubDir), "%08X%x", uTimestamp, uAge);
+ return rtDbgCfgOpenWithSubDir(hDbgCfg, pszFilename, szSubDir,
+ RT_OPSYS_WINDOWS /* approx */ | RTDBGCFG_O_SYMSRV | RTDBGCFG_O_CASE_INSENSITIVE
+ | RTDBGCFG_O_MAYBE_COMPRESSED_MS | RTDBGCFG_O_EXT_DEBUG_FILE,
+ pfnCallback, pvUser1, pvUser2);
+}
+
+
+RTDECL(int) RTDbgCfgOpenDbg(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp,
+ PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ char szSubDir[32];
+ RTStrPrintf(szSubDir, sizeof(szSubDir), "%08X%x", uTimestamp, cbImage);
+ return rtDbgCfgOpenWithSubDir(hDbgCfg, pszFilename, szSubDir,
+ RT_OPSYS_WINDOWS /* approx */ | RTDBGCFG_O_SYMSRV | RTDBGCFG_O_CASE_INSENSITIVE
+ | RTDBGCFG_O_MAYBE_COMPRESSED_MS | RTDBGCFG_O_EXT_DEBUG_FILE,
+ pfnCallback, pvUser1, pvUser2);
+}
+
+
+RTDECL(int) RTDbgCfgOpenDwo(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t uCrc32,
+ PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ char szSubDir[32];
+ RTStrPrintf(szSubDir, sizeof(szSubDir), "%08x", uCrc32);
+ return rtDbgCfgOpenWithSubDir(hDbgCfg, pszFilename, szSubDir,
+ RT_OPSYS_UNKNOWN | RTDBGCFG_O_EXT_DEBUG_FILE,
+ pfnCallback, pvUser1, pvUser2);
+}
+
+
+
+/*
+ *
+ * D a r w i n . d S Y M b u n d l e s
+ * D a r w i n . d S Y M b u n d l e s
+ * D a r w i n . d S Y M b u n d l e s
+ *
+ */
+
+/**
+ * Very similar to rtDbgCfgTryOpenDir.
+ */
+static int rtDbgCfgTryOpenDsymBundleInDir(PRTDBGCFGINT pThis, char *pszPath, PRTPATHSPLIT pSplitFn, const char *pszDsymName,
+ uint32_t fFlags, PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ int rcRet = VWRN_NOT_FOUND;
+ int rc2;
+
+ /* If the directory doesn't exist, just quit immediately.
+ Note! Our case insensitivity doesn't extend to the search dirs themselfs,
+ only to the bits under neath them. */
+ if (!RTDirExists(pszPath))
+ {
+ rtDbgCfgLog2(pThis, "Dir does not exist: '%s'\n", pszPath);
+ return rcRet;
+ }
+
+ /* Figure out whether we have to do a case sensitive search or not.
+ Note! As a simplification, we don't ask for case settings in each
+ directory under the user specified path, we assume the file
+ systems that mounted there have compatible settings. Faster
+ that way. */
+ bool const fCaseInsensitive = (fFlags & RTDBGCFG_O_CASE_INSENSITIVE)
+ && !rtDbgCfgIsFsCaseInsensitive(pszPath);
+
+ size_t const cchPath = strlen(pszPath);
+
+ /*
+ * Look for the file with less and less of the original path given.
+ */
+ for (unsigned i = RTPATH_PROP_HAS_ROOT_SPEC(pSplitFn->fProps); i < pSplitFn->cComps; i++)
+ {
+ pszPath[cchPath] = '\0';
+
+ rc2 = VINF_SUCCESS;
+ for (unsigned j = i; j < pSplitFn->cComps - 1U && RT_SUCCESS(rc2); j++)
+ if (!rtDbgCfgIsDirAndFixCase(pszPath, pSplitFn->apszComps[i], fCaseInsensitive))
+ rc2 = VERR_FILE_NOT_FOUND;
+ if ( RT_SUCCESS(rc2)
+ && !rtDbgCfgIsDirAndFixCase(pszPath, pszDsymName, fCaseInsensitive)
+ && !rtDbgCfgIsDirAndFixCase(pszPath, "Contents", fCaseInsensitive)
+ && !rtDbgCfgIsDirAndFixCase(pszPath, "Resources", fCaseInsensitive)
+ && !rtDbgCfgIsDirAndFixCase(pszPath, "DWARF", fCaseInsensitive))
+ {
+ if (rtDbgCfgIsFileAndFixCase(pszPath, pSplitFn->apszComps[pSplitFn->cComps - 1], fCaseInsensitive, false, NULL))
+ {
+ rtDbgCfgLog1(pThis, "Trying '%s'...\n", pszPath);
+ rc2 = pfnCallback(pThis, pszPath, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ {
+ if (rc2 == VINF_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Found '%s'.\n", pszPath);
+ else
+ rtDbgCfgLog1(pThis, "Error opening '%s'.\n", pszPath);
+ return rc2;
+ }
+ rtDbgCfgLog1(pThis, "Error %Rrc opening '%s'.\n", rc2, pszPath);
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+ }
+ }
+ rc2 = VERR_FILE_NOT_FOUND;
+ }
+
+ /*
+ * Do a recursive search if requested.
+ */
+ if ( (fFlags & RTDBGCFG_O_RECURSIVE)
+ && !(pThis->fFlags & RTDBGCFG_FLAGS_NO_RECURSIV_SEARCH) )
+ {
+ /** @todo Recursive searching will be done later. */
+ }
+
+ return rcRet;
+}
+
+
+/**
+ * Very similar to rtDbgCfgTryOpenList.
+ */
+static int rtDbgCfgTryOpenDsumBundleInList(PRTDBGCFGINT pThis, PRTLISTANCHOR pList, PRTPATHSPLIT pSplitFn,
+ const char *pszDsymName, const char *pszCacheSubDir, uint32_t fFlags, char *pszPath,
+ PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ int rcRet = VWRN_NOT_FOUND;
+ int rc2;
+
+ const char *pchCache = NULL;
+ size_t cchCache = 0;
+ int rcCache = VWRN_NOT_FOUND;
+
+ PRTDBGCFGSTR pCur;
+ RTListForEach(pList, pCur, RTDBGCFGSTR, ListEntry)
+ {
+ size_t cchDir = pCur->cch;
+ const char *pszDir = pCur->sz;
+ rtDbgCfgLog2(pThis, "Path list entry: '%s'\n", pszDir);
+
+ /* This is very simplistic, but we have a unreasonably large path
+ buffer, so it'll work just fine and simplify things greatly below. */
+ if (cchDir >= RTPATH_MAX - 8U)
+ {
+ if (RT_SUCCESS_NP(rcRet))
+ rcRet = VERR_FILENAME_TOO_LONG;
+ continue;
+ }
+
+ /*
+ * Process the path according to it's type.
+ */
+ if (!strncmp(pszDir, RT_STR_TUPLE("srv*")))
+ {
+ /*
+ * Symbol server.
+ */
+ pszDir += sizeof("srv*") - 1;
+ cchDir -= sizeof("srv*") - 1;
+ bool fSearchCache = false;
+ const char *pszServer = (const char *)memchr(pszDir, '*', cchDir);
+ if (!pszServer)
+ pszServer = pszDir;
+ else if (pszServer == pszDir)
+ continue;
+ {
+ fSearchCache = true;
+ pchCache = pszDir;
+ cchCache = pszServer - pszDir;
+ pszServer++;
+ }
+
+ /* We don't have any default cache directory, so skip if the cache is missing. */
+ if (cchCache == 0)
+ continue;
+
+ /* Search the cache first (if we haven't already done so). */
+ if (fSearchCache)
+ {
+ memcpy(pszPath, pchCache, cchCache);
+ pszPath[cchCache] = '\0';
+ RTPathChangeToUnixSlashes(pszPath, false);
+
+ rcCache = rc2 = rtDbgCfgTryOpenCache(pThis, pszPath, pszCacheSubDir, pSplitFn, fFlags,
+ pfnCallback, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ return rc2;
+ }
+
+ /* Try downloading the file. */
+ if (rcCache == VWRN_NOT_FOUND)
+ {
+ memcpy(pszPath, pchCache, cchCache);
+ pszPath[cchCache] = '\0';
+ RTPathChangeToUnixSlashes(pszPath, false);
+
+ rc2 = rtDbgCfgTryDownloadAndOpen(pThis, pszServer, pszPath, pszCacheSubDir, pSplitFn, fFlags,
+ pfnCallback, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ return rc2;
+ }
+ }
+ else if (!strncmp(pszDir, RT_STR_TUPLE("cache*")))
+ {
+ /*
+ * Cache directory.
+ */
+ pszDir += sizeof("cache*") - 1;
+ cchDir -= sizeof("cache*") - 1;
+ if (!cchDir)
+ continue;
+ pchCache = pszDir;
+ cchCache = cchDir;
+
+ memcpy(pszPath, pchCache, cchCache);
+ pszPath[cchCache] = '\0';
+ RTPathChangeToUnixSlashes(pszPath, false);
+
+ rcCache = rc2 = rtDbgCfgTryOpenCache(pThis, pszPath, pszCacheSubDir, pSplitFn, fFlags,
+ pfnCallback, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ return rc2;
+ }
+ else
+ {
+ /*
+ * Normal directory. Check for our own 'rec*' and 'norec*' prefix
+ * flags governing recursive searching.
+ */
+ uint32_t fFlagsDir = fFlags;
+ if (!strncmp(pszDir, RT_STR_TUPLE("rec*")))
+ {
+ pszDir += sizeof("rec*") - 1;
+ cchDir -= sizeof("rec*") - 1;
+ fFlagsDir |= RTDBGCFG_O_RECURSIVE;
+ }
+ else if (!strncmp(pszDir, RT_STR_TUPLE("norec*")))
+ {
+ pszDir += sizeof("norec*") - 1;
+ cchDir -= sizeof("norec*") - 1;
+ fFlagsDir &= ~RTDBGCFG_O_RECURSIVE;
+ }
+
+ /* Copy the path into the buffer and do the searching. */
+ memcpy(pszPath, pszDir, cchDir);
+ pszPath[cchDir] = '\0';
+ RTPathChangeToUnixSlashes(pszPath, false);
+
+ rc2 = rtDbgCfgTryOpenDsymBundleInDir(pThis, pszPath, pSplitFn, pszDsymName, fFlagsDir,
+ pfnCallback, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+ {
+ if ( rc2 == VINF_CALLBACK_RETURN
+ && cchCache > 0)
+ rtDbgCfgCopyFileToCache(pThis, pszPath, pchCache, cchCache, pszCacheSubDir, pSplitFn);
+ return rc2;
+ }
+ }
+
+ /* Propagate errors. */
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+ }
+
+ return rcRet;
+}
+
+
+RTDECL(int) RTDbgCfgOpenDsymBundle(RTDBGCFG hDbgCfg, const char *pszImage, PCRTUUID pUuid,
+ PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+ /*
+ * Bundles are directories, means we can forget about sharing code much
+ * with the other RTDbgCfgOpenXXX methods. Thus we're duplicating a lot of
+ * code from rtDbgCfgOpenWithSubDir with .dSYM related adjustments, so, a bug
+ * found here or there probably means the other version needs updating.
+ */
+ int rcRet = VINF_SUCCESS;
+ int rc2;
+
+ //RTStrPrintf(szFile, sizeof(szFile), "%s.dSYM/Contents/Resources/DWARF/%s", pszFilename, pszFilename);
+
+ /*
+ * Do a little validating first.
+ */
+ PRTDBGCFGINT pThis = hDbgCfg;
+ if (pThis != NIL_RTDBGCFG)
+ RTDBGCFG_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+ else
+ pThis = NULL;
+ AssertPtrReturn(pszImage, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
+
+ /*
+ * Set up rtDbgCfgOpenWithSubDir parameters.
+ */
+ uint32_t fFlags = RTDBGCFG_O_EXT_DEBUG_FILE | RT_OPSYS_DARWIN;
+ const char *pszCacheSubDir = NULL;
+ char szCacheSubDir[RTUUID_STR_LENGTH];
+ if (pUuid)
+ {
+ RTUuidToStr(pUuid, szCacheSubDir, sizeof(szCacheSubDir));
+ pszCacheSubDir = szCacheSubDir;
+ }
+
+ /*
+ * Do some guessing as to the way we should parse the filename and whether
+ * it's case exact or not.
+ */
+ bool fDosPath = strchr(pszImage, ':') != NULL
+ || strchr(pszImage, '\\') != NULL
+ || RT_OPSYS_USES_DOS_PATHS(fFlags & RTDBGCFG_O_OPSYS_MASK)
+ || (fFlags & RTDBGCFG_O_CASE_INSENSITIVE);
+ if (fDosPath)
+ fFlags |= RTDBGCFG_O_CASE_INSENSITIVE;
+
+ rtDbgCfgLog2(pThis, "Looking for '%s' with %#x flags...\n", pszImage, fFlags);
+
+ PRTPATHSPLIT pSplitFn;
+ rc2 = RTPathSplitA(pszImage, &pSplitFn, fDosPath ? RTPATH_STR_F_STYLE_DOS : RTPATH_STR_F_STYLE_UNIX);
+ if (RT_FAILURE(rc2))
+ return rc2;
+ AssertReturnStmt(pSplitFn->fProps & RTPATH_PROP_FILENAME, RTPathSplitFree(pSplitFn), VERR_IS_A_DIRECTORY);
+
+ /*
+ * Try the image directory first.
+ */
+ char szPath[RTPATH_MAX];
+ if (pSplitFn->cComps > 0)
+ {
+ rc2 = RTPathSplitReassemble(pSplitFn, RTPATH_STR_F_STYLE_HOST, szPath, sizeof(szPath));
+ if (RT_SUCCESS(rc2))
+ rc2 = RTStrCat(szPath, sizeof(szPath),
+ ".dSYM" RTPATH_SLASH_STR "Contents" RTPATH_SLASH_STR "Resources" RTPATH_SLASH_STR "DWARF");
+ if (RT_SUCCESS(rc2))
+ rc2 = RTPathAppend(szPath, sizeof(szPath), pSplitFn->apszComps[pSplitFn->cComps - 1]);
+ if (RT_SUCCESS(rc2))
+ {
+ RTPathChangeToUnixSlashes(szPath, false);
+ rtDbgCfgLog1(pThis, "Trying '%s'...\n", szPath);
+ rc2 = pfnCallback(pThis, szPath, pvUser1, pvUser2);
+ if (rc2 == VINF_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Found '%s'.\n", szPath);
+ else if (rc2 == VERR_CALLBACK_RETURN)
+ rtDbgCfgLog1(pThis, "Error opening '%s'.\n", szPath);
+ else
+ rtDbgCfgLog1(pThis, "Error %Rrc opening '%s'.\n", rc2, szPath);
+ }
+ }
+ if ( rc2 != VINF_CALLBACK_RETURN
+ && rc2 != VERR_CALLBACK_RETURN)
+ {
+ char *pszDsymName = (char *)alloca(strlen(pSplitFn->apszComps[pSplitFn->cComps - 1]) + sizeof(".dSYM"));
+ strcat(strcpy(pszDsymName, pSplitFn->apszComps[pSplitFn->cComps - 1]), ".dSYM");
+
+ /*
+ * Try the current directory (will take cover relative paths
+ * skipped above).
+ */
+ rc2 = RTPathGetCurrent(szPath, sizeof(szPath));
+ if (RT_FAILURE(rc2))
+ strcpy(szPath, ".");
+ RTPathChangeToUnixSlashes(szPath, false);
+
+ rc2 = rtDbgCfgTryOpenDsymBundleInDir(pThis, szPath, pSplitFn, pszDsymName, fFlags, pfnCallback, pvUser1, pvUser2);
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+
+ if ( rc2 != VINF_CALLBACK_RETURN
+ && rc2 != VERR_CALLBACK_RETURN
+ && pThis)
+ {
+ rc2 = RTCritSectRwEnterShared(&pThis->CritSect);
+ if (RT_SUCCESS(rc2))
+ {
+ /*
+ * Run the applicable lists.
+ */
+ rc2 = rtDbgCfgTryOpenDsumBundleInList(pThis, &pThis->PathList, pSplitFn, pszDsymName,
+ pszCacheSubDir, fFlags, szPath,
+ pfnCallback, pvUser1, pvUser2);
+ if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+ rcRet = rc2;
+
+ RTCritSectRwLeaveShared(&pThis->CritSect);
+ }
+ else if (RT_SUCCESS(rcRet))
+ rcRet = rc2;
+ }
+ }
+
+ RTPathSplitFree(pSplitFn);
+ if ( rc2 == VINF_CALLBACK_RETURN
+ || rc2 == VERR_CALLBACK_RETURN)
+ rcRet = rc2;
+ else if (RT_SUCCESS(rcRet))
+ rcRet = VERR_NOT_FOUND;
+ return rcRet;
+
+
+}
+
+
+
+RTDECL(int) RTDbgCfgSetLogCallback(RTDBGCFG hDbgCfg, PFNRTDBGCFGLOG pfnCallback, void *pvUser)
+{
+ PRTDBGCFGINT pThis = hDbgCfg;
+ RTDBGCFG_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+ AssertPtrNullReturn(pfnCallback, VERR_INVALID_POINTER);
+
+ int rc = RTCritSectRwEnterExcl(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ if ( pThis->pfnLogCallback == NULL
+ || pfnCallback == NULL
+ || pfnCallback == pThis->pfnLogCallback)
+ {
+ pThis->pfnLogCallback = NULL;
+ pThis->pvLogUser = NULL;
+ ASMCompilerBarrier(); /* paranoia */
+ pThis->pvLogUser = pvUser;
+ pThis->pfnLogCallback = pfnCallback;
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_ACCESS_DENIED;
+ RTCritSectRwLeaveExcl(&pThis->CritSect);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Frees a string list.
+ *
+ * @param pList The list to free.
+ */
+static void rtDbgCfgFreeStrList(PRTLISTANCHOR pList)
+{
+ PRTDBGCFGSTR pCur;
+ PRTDBGCFGSTR pNext;
+ RTListForEachSafe(pList, pCur, pNext, RTDBGCFGSTR, ListEntry)
+ {
+ RTListNodeRemove(&pCur->ListEntry);
+ RTMemFree(pCur);
+ }
+}
+
+
+/**
+ * Make changes to a string list, given a semicolon separated input string.
+ *
+ * @returns VINF_SUCCESS, VERR_FILENAME_TOO_LONG, VERR_NO_MEMORY
+ * @param pThis The config instance.
+ * @param enmOp The change operation.
+ * @param pszValue The input strings separated by semicolon.
+ * @param fPaths Indicates that this is a path list and that we
+ * should look for srv and cache prefixes.
+ * @param pList The string list anchor.
+ */
+static int rtDbgCfgChangeStringList(PRTDBGCFGINT pThis, RTDBGCFGOP enmOp, const char *pszValue, bool fPaths,
+ PRTLISTANCHOR pList)
+{
+ if (enmOp == RTDBGCFGOP_SET)
+ rtDbgCfgFreeStrList(pList);
+
+ while (*pszValue)
+ {
+ /* Skip separators. */
+ while (*pszValue == ';')
+ pszValue++;
+ if (!*pszValue)
+ break;
+
+ /* Find the end of this path. */
+ const char *pchPath = pszValue++;
+ char ch;
+ while ((ch = *pszValue) && ch != ';')
+ pszValue++;
+ size_t cchPath = pszValue - pchPath;
+ if (cchPath >= UINT16_MAX)
+ return VERR_FILENAME_TOO_LONG;
+
+ if (enmOp == RTDBGCFGOP_REMOVE)
+ {
+ /*
+ * Remove all occurences.
+ */
+ PRTDBGCFGSTR pCur;
+ PRTDBGCFGSTR pNext;
+ RTListForEachSafe(pList, pCur, pNext, RTDBGCFGSTR, ListEntry)
+ {
+ if ( pCur->cch == cchPath
+ && !memcmp(pCur->sz, pchPath, cchPath))
+ {
+ RTListNodeRemove(&pCur->ListEntry);
+ RTMemFree(pCur);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * We're adding a new one.
+ */
+ PRTDBGCFGSTR pNew = (PRTDBGCFGSTR)RTMemAlloc(RT_OFFSETOF(RTDBGCFGSTR, sz[cchPath + 1]));
+ if (!pNew)
+ return VERR_NO_MEMORY;
+ pNew->cch = (uint16_t)cchPath;
+ pNew->fFlags = 0;
+ memcpy(pNew->sz, pchPath, cchPath);
+ pNew->sz[cchPath] = '\0';
+
+ if (enmOp == RTDBGCFGOP_PREPEND)
+ RTListPrepend(pList, &pNew->ListEntry);
+ else
+ RTListAppend(pList, &pNew->ListEntry);
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Make changes to a 64-bit value
+ *
+ * @returns VINF_SUCCESS, VERR_DBG_CFG_INVALID_VALUE.
+ * @param pThis The config instance.
+ * @param enmOp The change operation.
+ * @param pszValue The input value.
+ * @param pszMnemonics The mnemonics map for this value.
+ * @param puValue The value to change.
+ */
+static int rtDbgCfgChangeStringU64(PRTDBGCFGINT pThis, RTDBGCFGOP enmOp, const char *pszValue,
+ PCRTDBGCFGU64MNEMONIC paMnemonics, uint64_t *puValue)
+{
+ uint64_t uNew = enmOp == RTDBGCFGOP_SET ? 0 : *puValue;
+
+ char ch;
+ while ((ch = *pszValue))
+ {
+ /* skip whitespace and separators */
+ while (RT_C_IS_SPACE(ch) || RT_C_IS_CNTRL(ch) || ch == ';' || ch == ':')
+ ch = *++pszValue;
+ if (!ch)
+ break;
+
+ if (RT_C_IS_DIGIT(ch))
+ {
+ uint64_t uTmp;
+ int rc = RTStrToUInt64Ex(pszValue, (char **)&pszValue, 0, &uTmp);
+ if (RT_FAILURE(rc) || rc == VWRN_NUMBER_TOO_BIG)
+ return VERR_DBG_CFG_INVALID_VALUE;
+
+ if (enmOp != RTDBGCFGOP_REMOVE)
+ uNew |= uTmp;
+ else
+ uNew &= ~uTmp;
+ }
+ else
+ {
+ /* A mnemonic, find the end of it. */
+ const char *pszMnemonic = pszValue - 1;
+ do
+ ch = *++pszValue;
+ while (ch && !RT_C_IS_SPACE(ch) && !RT_C_IS_CNTRL(ch) && ch != ';' && ch != ':');
+ size_t cchMnemonic = pszValue - pszMnemonic;
+
+ /* Look it up in the map and apply it. */
+ unsigned i = 0;
+ while (paMnemonics[i].pszMnemonic)
+ {
+ if ( cchMnemonic == paMnemonics[i].cchMnemonic
+ && !memcmp(pszMnemonic, paMnemonics[i].pszMnemonic, cchMnemonic))
+ {
+ if (paMnemonics[i].fSet ? enmOp != RTDBGCFGOP_REMOVE : enmOp == RTDBGCFGOP_REMOVE)
+ uNew |= paMnemonics[i].fFlags;
+ else
+ uNew &= ~paMnemonics[i].fFlags;
+ break;
+ }
+ i++;
+ }
+
+ if (!paMnemonics[i].pszMnemonic)
+ return VERR_DBG_CFG_INVALID_VALUE;
+ }
+ }
+
+ *puValue = uNew;
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTDbgCfgChangeString(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, RTDBGCFGOP enmOp, const char *pszValue)
+{
+ PRTDBGCFGINT pThis = hDbgCfg;
+ RTDBGCFG_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(enmProp > RTDBGCFGPROP_INVALID && enmProp < RTDBGCFGPROP_END, VERR_INVALID_PARAMETER);
+ AssertReturn(enmOp > RTDBGCFGOP_INVALID && enmOp < RTDBGCFGOP_END, VERR_INVALID_PARAMETER);
+ if (!pszValue)
+ pszValue = "";
+ else
+ AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
+
+ int rc = RTCritSectRwEnterExcl(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ switch (enmProp)
+ {
+ case RTDBGCFGPROP_FLAGS:
+ rc = rtDbgCfgChangeStringU64(pThis, enmOp, pszValue, g_aDbgCfgFlags, &pThis->fFlags);
+ break;
+ case RTDBGCFGPROP_PATH:
+ rc = rtDbgCfgChangeStringList(pThis, enmOp, pszValue, true, &pThis->PathList);
+ break;
+ case RTDBGCFGPROP_SUFFIXES:
+ rc = rtDbgCfgChangeStringList(pThis, enmOp, pszValue, false, &pThis->SuffixList);
+ break;
+ case RTDBGCFGPROP_SRC_PATH:
+ rc = rtDbgCfgChangeStringList(pThis, enmOp, pszValue, true, &pThis->SrcPathList);
+ break;
+ default:
+ AssertFailed();
+ rc = VERR_INTERNAL_ERROR_3;
+ }
+
+ RTCritSectRwLeaveExcl(&pThis->CritSect);
+ }
+
+ return rc;
+}
+
+
+RTDECL(int) RTDbgCfgChangeUInt(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, RTDBGCFGOP enmOp, uint64_t uValue)
+{
+ PRTDBGCFGINT pThis = hDbgCfg;
+ RTDBGCFG_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(enmProp > RTDBGCFGPROP_INVALID && enmProp < RTDBGCFGPROP_END, VERR_INVALID_PARAMETER);
+ AssertReturn(enmOp > RTDBGCFGOP_INVALID && enmOp < RTDBGCFGOP_END, VERR_INVALID_PARAMETER);
+
+ int rc = RTCritSectRwEnterExcl(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ uint64_t *puValue = NULL;
+ switch (enmProp)
+ {
+ case RTDBGCFGPROP_FLAGS:
+ puValue = &pThis->fFlags;
+ break;
+ default:
+ rc = VERR_DBG_CFG_NOT_UINT_PROP;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ switch (enmOp)
+ {
+ case RTDBGCFGOP_SET:
+ *puValue = uValue;
+ break;
+ case RTDBGCFGOP_APPEND:
+ case RTDBGCFGOP_PREPEND:
+ *puValue |= uValue;
+ break;
+ case RTDBGCFGOP_REMOVE:
+ *puValue &= ~uValue;
+ break;
+ default:
+ AssertFailed();
+ rc = VERR_INTERNAL_ERROR_2;
+ }
+ }
+
+ RTCritSectRwLeaveExcl(&pThis->CritSect);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Querys a string list as a single string (semicolon separators).
+ *
+ * @returns VINF_SUCCESS, VERR_BUFFER_OVERFLOW.
+ * @param pThis The config instance.
+ * @param pList The string list anchor.
+ * @param pszValue The output buffer.
+ * @param cbValue The size of the output buffer.
+ */
+static int rtDbgCfgQueryStringList(RTDBGCFG hDbgCfg, PRTLISTANCHOR pList,
+ char *pszValue, size_t cbValue)
+{
+ /*
+ * Check the length first.
+ */
+ size_t cbReq = 1;
+ PRTDBGCFGSTR pCur;
+ RTListForEach(pList, pCur, RTDBGCFGSTR, ListEntry)
+ cbReq += pCur->cch + 1;
+ if (cbReq > cbValue)
+ return VERR_BUFFER_OVERFLOW;
+
+ /*
+ * Construct the string list in the buffer.
+ */
+ char *psz = pszValue;
+ RTListForEach(pList, pCur, RTDBGCFGSTR, ListEntry)
+ {
+ if (psz != pszValue)
+ *psz++ = ';';
+ memcpy(psz, pCur->sz, pCur->cch);
+ psz += pCur->cch;
+ }
+ *psz = '\0';
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Querys the string value of a 64-bit unsigned int.
+ *
+ * @returns VINF_SUCCESS, VERR_BUFFER_OVERFLOW.
+ * @param pThis The config instance.
+ * @param uValue The value to query.
+ * @param pszMnemonics The mnemonics map for this value.
+ * @param pszValue The output buffer.
+ * @param cbValue The size of the output buffer.
+ */
+static int rtDbgCfgQueryStringU64(RTDBGCFG hDbgCfg, uint64_t uValue, PCRTDBGCFGU64MNEMONIC paMnemonics,
+ char *pszValue, size_t cbValue)
+{
+ /*
+ * If no mnemonics, just return the hex value.
+ */
+ if (!paMnemonics || paMnemonics[0].pszMnemonic)
+ {
+ char szTmp[64];
+ size_t cch = RTStrPrintf(szTmp, sizeof(szTmp), "%#x", uValue);
+ if (cch + 1 > cbValue)
+ return VERR_BUFFER_OVERFLOW;
+ memcpy(pszValue, szTmp, cbValue);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Check that there is sufficient buffer space first.
+ */
+ size_t cbReq = 1;
+ for (unsigned i = 0; paMnemonics[i].pszMnemonic; i++)
+ if ( paMnemonics[i].fSet
+ ? (paMnemonics[i].fFlags & uValue)
+ : !(paMnemonics[i].fFlags & uValue))
+ cbReq += (cbReq != 1) + paMnemonics[i].cchMnemonic;
+ if (cbReq > cbValue)
+ return VERR_BUFFER_OVERFLOW;
+
+ /*
+ * Construct the string.
+ */
+ char *psz = pszValue;
+ for (unsigned i = 0; paMnemonics[i].pszMnemonic; i++)
+ if ( paMnemonics[i].fSet
+ ? (paMnemonics[i].fFlags & uValue)
+ : !(paMnemonics[i].fFlags & uValue))
+ {
+ if (psz != pszValue)
+ *psz++ = ' ';
+ memcpy(psz, paMnemonics[i].pszMnemonic, paMnemonics[i].cchMnemonic);
+ psz += paMnemonics[i].cchMnemonic;
+ }
+ *psz = '\0';
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTDbgCfgQueryString(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, char *pszValue, size_t cbValue)
+{
+ PRTDBGCFGINT pThis = hDbgCfg;
+ RTDBGCFG_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(enmProp > RTDBGCFGPROP_INVALID && enmProp < RTDBGCFGPROP_END, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
+
+ int rc = RTCritSectRwEnterShared(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ switch (enmProp)
+ {
+ case RTDBGCFGPROP_FLAGS:
+ rc = rtDbgCfgQueryStringU64(pThis, pThis->fFlags, g_aDbgCfgFlags, pszValue, cbValue);
+ break;
+ case RTDBGCFGPROP_PATH:
+ rc = rtDbgCfgQueryStringList(pThis, &pThis->PathList, pszValue, cbValue);
+ break;
+ case RTDBGCFGPROP_SUFFIXES:
+ rc = rtDbgCfgQueryStringList(pThis, &pThis->SuffixList, pszValue, cbValue);
+ break;
+ case RTDBGCFGPROP_SRC_PATH:
+ rc = rtDbgCfgQueryStringList(pThis, &pThis->SrcPathList, pszValue, cbValue);
+ break;
+ default:
+ AssertFailed();
+ rc = VERR_INTERNAL_ERROR_3;
+ }
+
+ RTCritSectRwLeaveShared(&pThis->CritSect);
+ }
+
+ return rc;
+}
+
+
+RTDECL(int) RTDbgCfgQueryUInt(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, uint64_t *puValue)
+{
+ PRTDBGCFGINT pThis = hDbgCfg;
+ RTDBGCFG_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(enmProp > RTDBGCFGPROP_INVALID && enmProp < RTDBGCFGPROP_END, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(puValue, VERR_INVALID_POINTER);
+
+ int rc = RTCritSectRwEnterShared(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ switch (enmProp)
+ {
+ case RTDBGCFGPROP_FLAGS:
+ *puValue = pThis->fFlags;
+ break;
+ default:
+ rc = VERR_DBG_CFG_NOT_UINT_PROP;
+ }
+
+ RTCritSectRwLeaveShared(&pThis->CritSect);
+ }
+
+ return rc;
+}
+
+RTDECL(uint32_t) RTDbgCfgRetain(RTDBGCFG hDbgCfg)
+{
+ PRTDBGCFGINT pThis = hDbgCfg;
+ RTDBGCFG_VALID_RETURN_RC(pThis, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs < UINT32_MAX / 2);
+ return cRefs;
+}
+
+
+RTDECL(uint32_t) RTDbgCfgRelease(RTDBGCFG hDbgCfg)
+{
+ if (hDbgCfg == NIL_RTDBGCFG)
+ return 0;
+
+ PRTDBGCFGINT pThis = hDbgCfg;
+ RTDBGCFG_VALID_RETURN_RC(pThis, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+ if (!cRefs)
+ {
+ /*
+ * Last reference - free all memory.
+ */
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTDBGCFG_MAGIC);
+ rtDbgCfgFreeStrList(&pThis->PathList);
+ rtDbgCfgFreeStrList(&pThis->SuffixList);
+ rtDbgCfgFreeStrList(&pThis->SrcPathList);
+#ifdef RT_OS_WINDOWS
+ rtDbgCfgFreeStrList(&pThis->NtSymbolPathList);
+ rtDbgCfgFreeStrList(&pThis->NtExecutablePathList);
+ rtDbgCfgFreeStrList(&pThis->NtSourcePath);
+#endif
+ RTCritSectRwDelete(&pThis->CritSect);
+ RTMemFree(pThis);
+ }
+ else
+ Assert(cRefs < UINT32_MAX / 2);
+ return cRefs;
+}
+
+
+RTDECL(int) RTDbgCfgCreate(PRTDBGCFG phDbgCfg, const char *pszEnvVarPrefix, bool fNativePaths)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(phDbgCfg, VERR_INVALID_POINTER);
+ if (pszEnvVarPrefix)
+ {
+ AssertPtrReturn(pszEnvVarPrefix, VERR_INVALID_POINTER);
+ AssertReturn(*pszEnvVarPrefix, VERR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Allocate and initialize a new instance.
+ */
+ PRTDBGCFGINT pThis = (PRTDBGCFGINT)RTMemAllocZ(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ pThis->u32Magic = RTDBGCFG_MAGIC;
+ pThis->cRefs = 1;
+ RTListInit(&pThis->PathList);
+ RTListInit(&pThis->SuffixList);
+ RTListInit(&pThis->SrcPathList);
+#ifdef RT_OS_WINDOWS
+ RTListInit(&pThis->NtSymbolPathList);
+ RTListInit(&pThis->NtExecutablePathList);
+ RTListInit(&pThis->NtSourcePath);
+#endif
+
+ int rc = RTCritSectRwInit(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree(pThis);
+ return rc;
+ }
+
+ /*
+ * Read configurtion from the environment if requested to do so.
+ */
+ if (pszEnvVarPrefix || fNativePaths)
+ {
+ const size_t cbEnvVar = 256;
+ const size_t cbEnvVal = 65536 - cbEnvVar;
+ char *pszEnvVar = (char *)RTMemTmpAlloc(cbEnvVar + cbEnvVal);
+ if (pszEnvVar)
+ {
+ char *pszEnvVal = pszEnvVar + cbEnvVar;
+
+ if (pszEnvVarPrefix)
+ {
+ static struct
+ {
+ RTDBGCFGPROP enmProp;
+ const char *pszVar;
+ } const s_aProps[] =
+ {
+ { RTDBGCFGPROP_FLAGS, "FLAGS" },
+ { RTDBGCFGPROP_PATH, "PATH" },
+ { RTDBGCFGPROP_SUFFIXES, "SUFFIXES" },
+ { RTDBGCFGPROP_SRC_PATH, "SRC_PATH" },
+ };
+
+ for (unsigned i = 0; i < RT_ELEMENTS(s_aProps); i++)
+ {
+ size_t cchEnvVar = RTStrPrintf(pszEnvVar, cbEnvVar, "%s_%s", pszEnvVarPrefix, s_aProps[i].pszVar);
+ if (cchEnvVar >= cbEnvVar - 1)
+ {
+ rc = VERR_BUFFER_OVERFLOW;
+ break;
+ }
+
+ rc = RTEnvGetEx(RTENV_DEFAULT, pszEnvVar, pszEnvVal, cbEnvVal, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTDbgCfgChangeString(pThis, s_aProps[i].enmProp, RTDBGCFGOP_SET, pszEnvVal);
+ if (RT_FAILURE(rc))
+ break;
+ }
+ else if (rc != VERR_ENV_VAR_NOT_FOUND)
+ break;
+ else
+ rc = VINF_SUCCESS;
+ }
+ }
+
+ /*
+ * Pick up system specific search paths.
+ */
+ if (RT_SUCCESS(rc) && fNativePaths)
+ {
+ struct
+ {
+ PRTLISTANCHOR pList;
+ const char *pszVar;
+ char chSep;
+ } aNativePaths[] =
+ {
+#ifdef RT_OS_WINDOWS
+ { &pThis->NtExecutablePathList, "_NT_EXECUTABLE_PATH", ';' },
+ { &pThis->NtSymbolPathList, "_NT_ALT_SYMBOL_PATH", ';' },
+ { &pThis->NtSymbolPathList, "_NT_SYMBOL_PATH", ';' },
+ { &pThis->NtSourcePath, "_NT_SOURCE_PATH", ';' },
+#endif
+ { NULL, NULL, 0 }
+ };
+ for (unsigned i = 0; aNativePaths[i].pList; i++)
+ {
+ Assert(aNativePaths[i].chSep == ';'); /* fix when needed */
+ rc = RTEnvGetEx(RTENV_DEFAULT, aNativePaths[i].pszVar, pszEnvVal, cbEnvVal, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtDbgCfgChangeStringList(pThis, RTDBGCFGOP_APPEND, pszEnvVal, true, aNativePaths[i].pList);
+ if (RT_FAILURE(rc))
+ break;
+ }
+ else if (rc != VERR_ENV_VAR_NOT_FOUND)
+ break;
+ else
+ rc = VINF_SUCCESS;
+ }
+ }
+ RTMemTmpFree(pszEnvVar);
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+ if (RT_FAILURE(rc))
+ {
+ /*
+ * Error, bail out.
+ */
+ RTDbgCfgRelease(pThis);
+ return rc;
+ }
+ }
+
+ /*
+ * Returns successfully.
+ */
+ *phDbgCfg = pThis;
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/common/dbg/dbgmod.cpp b/src/VBox/Runtime/common/dbg/dbgmod.cpp
index 13c677fa..7e627fd9 100644
--- a/src/VBox/Runtime/common/dbg/dbgmod.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgmod.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,14 +28,17 @@
/*******************************************************************************
* Header Files *
*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DBG
#include <iprt/dbg.h>
#include "internal/iprt.h"
+#include <iprt/alloca.h>
#include <iprt/asm.h>
#include <iprt/assert.h>
#include <iprt/avl.h>
#include <iprt/err.h>
#include <iprt/initterm.h>
+#include <iprt/log.h>
#include <iprt/mem.h>
#include <iprt/once.h>
#include <iprt/param.h>
@@ -119,6 +122,8 @@ DECLHIDDEN(RTSTRCACHE) g_hDbgModStrCache = NIL_RTSTRCACHE;
+
+
/**
* Cleanup debug info interpreter globals.
*
@@ -253,12 +258,11 @@ static int rtDbgModImageInterpreterRegister(PCRTDBGMODVTIMG pVt)
* the built-in interpreters.
*
* @returns IPRT status code.
- * @param pvUser1 NULL.
- * @param pvUser2 NULL.
+ * @param pvUser NULL.
*/
-static DECLCALLBACK(int) rtDbgModInitOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int) rtDbgModInitOnce(void *pvUser)
{
- NOREF(pvUser1); NOREF(pvUser2);
+ NOREF(pvUser);
/*
* Create the semaphore and string cache.
@@ -276,6 +280,12 @@ static DECLCALLBACK(int) rtDbgModInitOnce(void *pvUser1, void *pvUser2)
if (RT_SUCCESS(rc))
rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDwarf);
if (RT_SUCCESS(rc))
+ rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgCodeView);
+#ifdef RT_OS_WINDOWS
+ if (RT_SUCCESS(rc))
+ rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDbgHelp);
+#endif
+ if (RT_SUCCESS(rc))
rc = rtDbgModImageInterpreterRegister(&g_rtDbgModVtImgLdr);
if (RT_SUCCESS(rc))
{
@@ -296,28 +306,16 @@ static DECLCALLBACK(int) rtDbgModInitOnce(void *pvUser1, void *pvUser2)
}
+/**
+ * Performs lazy init of our global variables.
+ * @returns IPRT status code.
+ */
DECLINLINE(int) rtDbgModLazyInit(void)
{
- return RTOnce(&g_rtDbgModOnce, rtDbgModInitOnce, NULL, NULL);
+ return RTOnce(&g_rtDbgModOnce, rtDbgModInitOnce, NULL);
}
-/**
- * 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)
{
/*
@@ -344,7 +342,8 @@ RTDECL(int) RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cb
rc = RTCritSectInit(&pDbgMod->CritSect);
if (RT_SUCCESS(rc))
{
- pDbgMod->pszName = RTStrCacheEnter(g_hDbgModStrCache, pszName);
+ pDbgMod->pszImgFileSpecified = RTStrCacheEnter(g_hDbgModStrCache, pszName);
+ pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, RTPathFilenameEx(pszName, RTPATH_STR_F_STYLE_DOS));
if (pDbgMod->pszName)
{
rc = rtDbgModContainerCreate(pDbgMod, cbSeg);
@@ -353,6 +352,7 @@ RTDECL(int) RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cb
*phDbgMod = pDbgMod;
return rc;
}
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
}
RTCritSectDelete(&pDbgMod->CritSect);
@@ -364,16 +364,419 @@ RTDECL(int) RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cb
RT_EXPORT_SYMBOL(RTDbgModCreate);
-RTDECL(int) RTDbgModCreateDeferred(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
- RTUINTPTR cb, uint32_t fFlags)
+RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
+ RTUINTPTR uSubtrahend, RTDBGCFG hDbgCfg)
+{
+ /*
+ * Input validation and lazy initialization.
+ */
+ AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
+ *phDbgMod = NIL_RTDBGMOD;
+ AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
+ AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
+ AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
+ AssertReturn(uSubtrahend == 0, VERR_NOT_IMPLEMENTED); /** @todo implement uSubtrahend. */
+
+ int rc = rtDbgModLazyInit();
+ if (RT_FAILURE(rc))
+ return rc;
+
+ if (!pszName)
+ pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
+
+ /*
+ * Allocate a new module instance.
+ */
+ PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
+ if (!pDbgMod)
+ return VERR_NO_MEMORY;
+ pDbgMod->u32Magic = RTDBGMOD_MAGIC;
+ pDbgMod->cRefs = 1;
+ rc = RTCritSectInit(&pDbgMod->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
+ if (pDbgMod->pszName)
+ {
+ pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
+ if (pDbgMod->pszDbgFile)
+ {
+ /*
+ * Try the map file readers.
+ */
+ rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VERR_DBG_NO_MATCHING_INTERPRETER;
+ for (PRTDBGMODREGDBG pCur = g_pDbgHead; pCur; pCur = pCur->pNext)
+ {
+ if (pCur->pVt->fSupports & RT_DBGTYPE_MAP)
+ {
+ pDbgMod->pDbgVt = pCur->pVt;
+ pDbgMod->pvDbgPriv = NULL;
+ rc = pCur->pVt->pfnTryOpen(pDbgMod, RTLDRARCH_WHATEVER);
+ if (RT_SUCCESS(rc))
+ {
+ ASMAtomicIncU32(&pCur->cUsers);
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+
+ *phDbgMod = pDbgMod;
+ return rc;
+ }
+ }
+ }
+
+ /* bail out */
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+ }
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
+ }
+ else
+ rc = VERR_NO_STR_MEMORY;
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
+ }
+ else
+ rc = VERR_NO_STR_MEMORY;
+ RTCritSectDelete(&pDbgMod->CritSect);
+ }
+
+ RTMemFree(pDbgMod);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTDbgModCreateFromMap);
+
+
+
+/*
+ *
+ * E x e c u t a b l e I m a g e F i l e s
+ * E x e c u t a b l e I m a g e F i l e s
+ * E x e c u t a b l e I m a g e F i l e s
+ *
+ */
+
+
+/**
+ * Opens debug information for an image.
+ *
+ * @returns IPRT status code
+ * @param pDbgMod The debug module structure.
+ *
+ * @note This will generally not look for debug info stored in external
+ * files. rtDbgModFromPeImageExtDbgInfoCallback can help with that.
+ */
+static int rtDbgModOpenDebugInfoInsideImage(PRTDBGMODINT pDbgMod)
+{
+ AssertReturn(!pDbgMod->pDbgVt, VERR_DBG_MOD_IPE);
+ AssertReturn(pDbgMod->pImgVt, VERR_DBG_MOD_IPE);
+
+ int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
+ {
+ pDbgMod->pDbgVt = pDbg->pVt;
+ pDbgMod->pvDbgPriv = NULL;
+ rc = pDbg->pVt->pfnTryOpen(pDbgMod, pDbgMod->pImgVt->pfnGetArch(pDbgMod));
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * That's it!
+ */
+ ASMAtomicIncU32(&pDbg->cUsers);
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+ return VINF_SUCCESS;
+ }
+
+ pDbgMod->pDbgVt = NULL;
+ Assert(pDbgMod->pvDbgPriv == NULL);
+ }
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+ }
+
+ return VERR_DBG_NO_MATCHING_INTERPRETER;
+}
+
+
+/** @callback_method_impl{FNRTDBGCFGOPEN} */
+static DECLCALLBACK(int) rtDbgModExtDbgInfoOpenCallback(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
+{
+ PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser1;
+ PCRTLDRDBGINFO pDbgInfo = (PCRTLDRDBGINFO)pvUser2;
+ NOREF(pDbgInfo); /** @todo consider a more direct search for a interpreter. */
+
+ Assert(!pDbgMod->pDbgVt);
+ Assert(!pDbgMod->pvDbgPriv);
+ Assert(!pDbgMod->pszDbgFile);
+ Assert(pDbgMod->pImgVt);
+
+ /*
+ * Set the debug file name and try possible interpreters.
+ */
+ pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
+
+ int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
+ {
+ pDbgMod->pDbgVt = pDbg->pVt;
+ pDbgMod->pvDbgPriv = NULL;
+ rc = pDbg->pVt->pfnTryOpen(pDbgMod, pDbgMod->pImgVt->pfnGetArch(pDbgMod));
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Got it!
+ */
+ ASMAtomicIncU32(&pDbg->cUsers);
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+ return VINF_CALLBACK_RETURN;
+ }
+
+ pDbgMod->pDbgVt = NULL;
+ Assert(pDbgMod->pvDbgPriv == NULL);
+ }
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+ }
+
+ /* No joy. */
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
+ pDbgMod->pszDbgFile = NULL;
+ return rc;
+}
+
+
+/**
+ * Argument package used by rtDbgModOpenDebugInfoExternalToImage.
+ */
+typedef struct RTDBGMODOPENDIETI
+{
+ PRTDBGMODINT pDbgMod;
+ RTDBGCFG hDbgCfg;
+} RTDBGMODOPENDIETI;
+
+
+/** @callback_method_impl{FNRTLDRENUMDBG} */
+static DECLCALLBACK(int)
+rtDbgModOpenDebugInfoExternalToImageCallback(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)
+{
+ RTDBGMODOPENDIETI *pArgs = (RTDBGMODOPENDIETI *)pvUser;
+
+ Assert(pDbgInfo->enmType > RTLDRDBGINFOTYPE_INVALID && pDbgInfo->enmType < RTLDRDBGINFOTYPE_END);
+ const char *pszExtFile = pDbgInfo->pszExtFile;
+ if (!pszExtFile)
+ {
+ /*
+ * If a external debug type comes without a file name, calculate a
+ * likely debug filename for it. (Hack for NT4 drivers.)
+ */
+ const char *pszExt = NULL;
+ if (pDbgInfo->enmType == RTLDRDBGINFOTYPE_CODEVIEW_DBG)
+ pszExt = ".dbg";
+ else if ( pDbgInfo->enmType == RTLDRDBGINFOTYPE_CODEVIEW_PDB20
+ || pDbgInfo->enmType == RTLDRDBGINFOTYPE_CODEVIEW_PDB70)
+ pszExt = ".pdb";
+ if (pszExt && pArgs->pDbgMod->pszName)
+ {
+ size_t cchName = strlen(pArgs->pDbgMod->pszName);
+ char *psz = (char *)alloca(cchName + strlen(pszExt) + 1);
+ if (psz)
+ {
+ memcpy(psz, pArgs->pDbgMod->pszName, cchName + 1);
+ RTPathStripExt(psz);
+ pszExtFile = strcat(psz, pszExt);
+ }
+ }
+
+ if (!pszExtFile)
+ {
+ Log2(("rtDbgModOpenDebugInfoExternalToImageCallback: enmType=%d\n", pDbgInfo->enmType));
+ return VINF_SUCCESS;
+ }
+ }
+
+ /*
+ * Switch on type and call the appropriate search function.
+ */
+ int rc;
+ switch (pDbgInfo->enmType)
+ {
+ case RTLDRDBGINFOTYPE_CODEVIEW_PDB70:
+ rc = RTDbgCfgOpenPdb70(pArgs->hDbgCfg, pszExtFile,
+ &pDbgInfo->u.Pdb70.Uuid,
+ pDbgInfo->u.Pdb70.uAge,
+ rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
+ break;
+
+ case RTLDRDBGINFOTYPE_CODEVIEW_PDB20:
+ rc = RTDbgCfgOpenPdb20(pArgs->hDbgCfg, pszExtFile,
+ pDbgInfo->u.Pdb20.cbImage,
+ pDbgInfo->u.Pdb20.uTimestamp,
+ pDbgInfo->u.Pdb20.uAge,
+ rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
+ break;
+
+ case RTLDRDBGINFOTYPE_CODEVIEW_DBG:
+ rc = RTDbgCfgOpenDbg(pArgs->hDbgCfg, pszExtFile,
+ pDbgInfo->u.Dbg.cbImage,
+ pDbgInfo->u.Dbg.uTimestamp,
+ rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
+ break;
+
+ case RTLDRDBGINFOTYPE_DWARF_DWO:
+ rc = RTDbgCfgOpenDwo(pArgs->hDbgCfg, pszExtFile,
+ pDbgInfo->u.Dwo.uCrc32,
+ rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
+ break;
+
+ default:
+ Log(("rtDbgModOpenDebugInfoExternalToImageCallback: Don't know how to handle enmType=%d and pszFileExt=%s\n",
+ pDbgInfo->enmType, pszExtFile));
+ return VERR_DBG_TODO;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ LogFlow(("RTDbgMod: Successfully opened external debug info '%s' for '%s'\n",
+ pArgs->pDbgMod->pszDbgFile, pArgs->pDbgMod->pszImgFile));
+ return VINF_CALLBACK_RETURN;
+ }
+ Log(("rtDbgModOpenDebugInfoExternalToImageCallback: '%s' (enmType=%d) for '%s' -> %Rrc\n",
+ pszExtFile, pDbgInfo->enmType, pArgs->pDbgMod->pszImgFile, rc));
+ return rc;
+}
+
+
+/**
+ * Opens debug info listed in the image that is stored in a separate file.
+ *
+ * @returns IPRT status code
+ * @param pDbgMod The debug module.
+ * @param hDbgCfg The debug config. Can be NIL.
+ */
+static int rtDbgModOpenDebugInfoExternalToImage(PRTDBGMODINT pDbgMod, RTDBGCFG hDbgCfg)
{
- NOREF(phDbgMod); NOREF(pszFilename); NOREF(pszName); NOREF(cb); NOREF(fFlags);
- return VERR_NOT_IMPLEMENTED;
+ Assert(!pDbgMod->pDbgVt);
+
+ RTDBGMODOPENDIETI Args;
+ Args.pDbgMod = pDbgMod;
+ Args.hDbgCfg = hDbgCfg;
+ int rc = pDbgMod->pImgVt->pfnEnumDbgInfo(pDbgMod, rtDbgModOpenDebugInfoExternalToImageCallback, &Args);
+ if (RT_SUCCESS(rc) && pDbgMod->pDbgVt)
+ return VINF_SUCCESS;
+
+ LogFlow(("rtDbgModOpenDebugInfoExternalToImage: rc=%Rrc\n", rc));
+ return VERR_NOT_FOUND;
}
-RT_EXPORT_SYMBOL(RTDbgModCreateDeferred);
-RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t fFlags)
+/** @callback_method_impl{FNRTDBGCFGOPEN} */
+static DECLCALLBACK(int) rtDbgModExtDbgInfoOpenCallback2(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
+{
+ PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser1;
+ NOREF(pvUser2); /** @todo image matching string or smth. */
+
+ Assert(!pDbgMod->pDbgVt);
+ Assert(!pDbgMod->pvDbgPriv);
+ Assert(!pDbgMod->pszDbgFile);
+ Assert(pDbgMod->pImgVt);
+
+ /*
+ * Set the debug file name and try possible interpreters.
+ */
+ pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
+
+ int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
+ {
+ pDbgMod->pDbgVt = pDbg->pVt;
+ pDbgMod->pvDbgPriv = NULL;
+ rc = pDbg->pVt->pfnTryOpen(pDbgMod, pDbgMod->pImgVt->pfnGetArch(pDbgMod));
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Got it!
+ */
+ ASMAtomicIncU32(&pDbg->cUsers);
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+ return VINF_CALLBACK_RETURN;
+ }
+ pDbgMod->pDbgVt = NULL;
+ Assert(pDbgMod->pvDbgPriv == NULL);
+ }
+ }
+
+ /* No joy. */
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
+ pDbgMod->pszDbgFile = NULL;
+ return rc;
+}
+
+
+/**
+ * Opens external debug info that is not listed in the image.
+ *
+ * @returns IPRT status code
+ * @param pDbgMod The debug module.
+ * @param hDbgCfg The debug config. Can be NIL.
+ */
+static int rtDbgModOpenDebugInfoExternalToImage2(PRTDBGMODINT pDbgMod, RTDBGCFG hDbgCfg)
+{
+ int rc;
+ Assert(!pDbgMod->pDbgVt);
+ Assert(pDbgMod->pImgVt);
+
+ /*
+ * Figure out what to search for based on the image format.
+ */
+ const char *pszzExts = NULL;
+ RTLDRFMT enmFmt = pDbgMod->pImgVt->pfnGetFormat(pDbgMod);
+ switch (enmFmt)
+ {
+ case RTLDRFMT_MACHO:
+ {
+ rc = RTDbgCfgOpenDsymBundle(hDbgCfg, pDbgMod->pszImgFile, NULL /**@todo pUuid*/,
+ rtDbgModExtDbgInfoOpenCallback2, pDbgMod, NULL /*pvUser2*/);
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+ break;
+ }
+
+#if 0 /* Will be links in the image if these apply. .map readers for PE or ELF we don't have. */
+ case RTLDRFMT_ELF:
+ pszzExts = ".debug\0.dwo\0";
+ break;
+ case RTLDRFMT_PE:
+ pszzExts = ".map\0";
+ break;
+#endif
+#if 0 /* Haven't implemented .sym or .map file readers for OS/2 yet. */
+ case RTLDRFMT_LX:
+ pszzExts = ".sym\0.map\0";
+ break;
+#endif
+ default:
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ NOREF(pszzExts);
+#if 0 /* Later */
+ if (pszzExts)
+ {
+
+ }
+#endif
+
+ LogFlow(("rtDbgModOpenDebugInfoExternalToImage2: rc=%Rrc\n", rc));
+ return VERR_NOT_FOUND;
+}
+
+
+RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
+ RTLDRARCH enmArch, RTDBGCFG hDbgCfg)
{
/*
* Input validation and lazy initialization.
@@ -383,14 +786,14 @@ RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename,
AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
- AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
+ AssertReturn(enmArch > RTLDRARCH_INVALID && enmArch < RTLDRARCH_END, VERR_INVALID_PARAMETER);
int rc = rtDbgModLazyInit();
if (RT_FAILURE(rc))
return rc;
if (!pszName)
- pszName = RTPathFilename(pszFilename);
+ pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
/*
* Allocate a new module instance.
@@ -403,12 +806,15 @@ RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename,
rc = RTCritSectInit(&pDbgMod->CritSect);
if (RT_SUCCESS(rc))
{
- pDbgMod->pszName = RTStrCacheEnter(g_hDbgModStrCache, pszName);
+ pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
if (pDbgMod->pszName)
{
pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
if (pDbgMod->pszImgFile)
{
+ RTStrCacheRetain(pDbgMod->pszImgFile);
+ pDbgMod->pszImgFileSpecified = pDbgMod->pszImgFile;
+
/*
* Find an image reader which groks the file.
*/
@@ -421,38 +827,40 @@ RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename,
{
pDbgMod->pImgVt = pImg->pVt;
pDbgMod->pvImgPriv = NULL;
- rc = pImg->pVt->pfnTryOpen(pDbgMod);
+ /** @todo need to specify some arch stuff here. */
+ rc = pImg->pVt->pfnTryOpen(pDbgMod, enmArch);
if (RT_SUCCESS(rc))
{
/*
- * Find a debug info interpreter.
+ * Image detected, but found no debug info we were
+ * able to understand.
*/
- rc = VERR_DBG_NO_MATCHING_INTERPRETER;
- for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
+ /** @todo some generic way of matching image and debug info, flexible signature
+ * of some kind. Apple uses UUIDs, microsoft uses a UUID+age or a
+ * size+timestamp, and GNU a CRC32 (last time I checked). */
+ rc = rtDbgModOpenDebugInfoExternalToImage(pDbgMod, hDbgCfg);
+ if (RT_FAILURE(rc))
+ rc = rtDbgModOpenDebugInfoInsideImage(pDbgMod);
+ if (RT_FAILURE(rc))
+ rc = rtDbgModOpenDebugInfoExternalToImage2(pDbgMod, hDbgCfg);
+ if (RT_FAILURE(rc))
+ rc = rtDbgModCreateForExports(pDbgMod);
+ if (RT_SUCCESS(rc))
{
- pDbgMod->pDbgVt = pDbg->pVt;
- pDbgMod->pvDbgPriv = NULL;
- rc = pDbg->pVt->pfnTryOpen(pDbgMod);
- if (RT_SUCCESS(rc))
- {
- /*
- * That's it!
- */
- ASMAtomicIncU32(&pDbg->cUsers);
- ASMAtomicIncU32(&pImg->cUsers);
- RTSemRWReleaseRead(g_hDbgModRWSem);
-
- *phDbgMod = pDbgMod;
- return rc;
- }
+ /*
+ * We're done!
+ */
+ ASMAtomicIncU32(&pImg->cUsers);
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+
+ *phDbgMod = pDbgMod;
+ return VINF_SUCCESS;
}
- /*
- * Image detected, but found no debug info we were
- * able to understand.
- */
- /** @todo Fall back on exported symbols! */
+ /* Failed, close up the shop. */
pDbgMod->pImgVt->pfnClose(pDbgMod);
+ pDbgMod->pImgVt = NULL;
+ pDbgMod->pvImgPriv = NULL;
break;
}
}
@@ -471,7 +879,7 @@ RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename,
{
pDbgMod->pDbgVt = pDbg->pVt;
pDbgMod->pvDbgPriv = NULL;
- rc = pDbg->pVt->pfnTryOpen(pDbgMod);
+ rc = pDbg->pVt->pfnTryOpen(pDbgMod, enmArch);
if (RT_SUCCESS(rc))
{
/*
@@ -492,10 +900,15 @@ RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename,
/* bail out */
RTSemRWReleaseRead(g_hDbgModRWSem);
}
- RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
}
- RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
+ else
+ rc = VERR_NO_STR_MEMORY;
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
}
+ else
+ rc = VERR_NO_STR_MEMORY;
RTCritSectDelete(&pDbgMod->CritSect);
}
@@ -505,8 +918,150 @@ RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename,
RT_EXPORT_SYMBOL(RTDbgModCreateFromImage);
-RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
- RTUINTPTR uSubtrahend, uint32_t fFlags)
+
+
+
+/*
+ *
+ * P E I M A G E
+ * P E I M A G E
+ * P E I M A G E
+ *
+ */
+
+
+
+/** @callback_method_impl{FNRTDBGCFGOPEN} */
+static DECLCALLBACK(int) rtDbgModFromPeImageOpenCallback(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
+{
+ PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser1;
+ PRTDBGMODDEFERRED pDeferred = (PRTDBGMODDEFERRED)pvUser2;
+ LogFlow(("rtDbgModFromPeImageOpenCallback: %s\n", pszFilename));
+
+ Assert(pDbgMod->pImgVt == NULL);
+ Assert(pDbgMod->pvImgPriv == NULL);
+ Assert(pDbgMod->pDbgVt == NULL);
+ Assert(pDbgMod->pvDbgPriv == NULL);
+
+ /*
+ * Replace the image file name while probing it.
+ */
+ const char *pszNewImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
+ if (!pszNewImgFile)
+ return VERR_NO_STR_MEMORY;
+ const char *pszOldImgFile = pDbgMod->pszImgFile;
+ pDbgMod->pszImgFile = pszNewImgFile;
+
+ /*
+ * Find an image reader which groks the file.
+ */
+ int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VERR_DBG_NO_MATCHING_INTERPRETER;
+ PRTDBGMODREGIMG pImg;
+ for (pImg = g_pImgHead; pImg; pImg = pImg->pNext)
+ {
+ pDbgMod->pImgVt = pImg->pVt;
+ pDbgMod->pvImgPriv = NULL;
+ rc = pImg->pVt->pfnTryOpen(pDbgMod, RTLDRARCH_WHATEVER);
+ if (RT_SUCCESS(rc))
+ break;
+ pDbgMod->pImgVt = NULL;
+ Assert(pDbgMod->pvImgPriv == NULL);
+ }
+ RTSemRWReleaseRead(g_hDbgModRWSem);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Check the deferred info.
+ */
+ RTUINTPTR cbImage = pDbgMod->pImgVt->pfnImageSize(pDbgMod);
+ if ( pDeferred->cbImage == 0
+ || pDeferred->cbImage == cbImage)
+ {
+ uint32_t uTimestamp = pDeferred->u.PeImage.uTimestamp; /** @todo add method for getting the timestamp. */
+ if ( pDeferred->u.PeImage.uTimestamp == 0
+ || pDeferred->u.PeImage.uTimestamp == uTimestamp)
+ {
+ Log(("RTDbgMod: Found matching PE image '%s'\n", pszFilename));
+
+ /*
+ * We found the executable image we need, now go find any
+ * debug info associated with it. For PE images, this is
+ * generally found in an external file, so we do a sweep
+ * for that first.
+ *
+ * Then try open debug inside the module, and finally
+ * falling back on exports.
+ */
+ rc = rtDbgModOpenDebugInfoExternalToImage(pDbgMod, pDeferred->hDbgCfg);
+ if (RT_FAILURE(rc))
+ rc = rtDbgModOpenDebugInfoInsideImage(pDbgMod);
+ if (RT_FAILURE(rc))
+ rc = rtDbgModCreateForExports(pDbgMod);
+ if (RT_SUCCESS(rc))
+ {
+ RTStrCacheRelease(g_hDbgModStrCache, pszOldImgFile);
+ return VINF_CALLBACK_RETURN;
+ }
+
+ /* Something bad happened, just give up. */
+ Log(("rtDbgModFromPeImageOpenCallback: rtDbgModCreateForExports failed: %Rrc\n", rc));
+ }
+ else
+ {
+ LogFlow(("rtDbgModFromPeImageOpenCallback: uTimestamp mismatch (found %#x, expected %#x) - %s\n",
+ uTimestamp, pDeferred->u.PeImage.uTimestamp, pszFilename));
+ rc = VERR_DBG_FILE_MISMATCH;
+ }
+ }
+ else
+ {
+ LogFlow(("rtDbgModFromPeImageOpenCallback: cbImage mismatch (found %#x, expected %#x) - %s\n",
+ cbImage, pDeferred->cbImage, pszFilename));
+ rc = VERR_DBG_FILE_MISMATCH;
+ }
+
+ pDbgMod->pImgVt->pfnClose(pDbgMod);
+ pDbgMod->pImgVt = NULL;
+ pDbgMod->pvImgPriv = NULL;
+ }
+ else
+ LogFlow(("rtDbgModFromPeImageOpenCallback: Failed %Rrc - %s\n", rc, pszFilename));
+ }
+
+ /* Restore image name. */
+ pDbgMod->pszImgFile = pszOldImgFile;
+ RTStrCacheRelease(g_hDbgModStrCache, pszNewImgFile);
+ return rc;
+}
+
+
+/** @callback_method_impl{FNRTDBGMODDEFERRED} */
+static DECLCALLBACK(int) rtDbgModFromPeImageDeferredCallback(PRTDBGMODINT pDbgMod, PRTDBGMODDEFERRED pDeferred)
+{
+ int rc;
+
+ Assert(pDbgMod->pszImgFile);
+ if (!pDbgMod->pImgVt)
+ rc = RTDbgCfgOpenPeImage(pDeferred->hDbgCfg, pDbgMod->pszImgFile,
+ pDeferred->cbImage, pDeferred->u.PeImage.uTimestamp,
+ rtDbgModFromPeImageOpenCallback, pDbgMod, pDeferred);
+ else
+ {
+ rc = rtDbgModOpenDebugInfoExternalToImage(pDbgMod, pDeferred->hDbgCfg);
+ if (RT_FAILURE(rc))
+ rc = rtDbgModOpenDebugInfoInsideImage(pDbgMod);
+ if (RT_FAILURE(rc))
+ rc = rtDbgModCreateForExports(pDbgMod);
+ }
+ return rc;
+}
+
+
+RTDECL(int) RTDbgModCreateFromPeImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTLDRMOD hLdrMod,
+ uint32_t cbImage, uint32_t uTimestamp, RTDBGCFG hDbgCfg)
{
/*
* Input validation and lazy initialization.
@@ -515,16 +1070,21 @@ RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, c
*phDbgMod = NIL_RTDBGMOD;
AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
- AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
- AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
- AssertReturn(uSubtrahend == 0, VERR_NOT_IMPLEMENTED); /** @todo implement uSubtrahend. */
+ if (!pszName)
+ pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertReturn(hLdrMod == NIL_RTLDRMOD || RTLdrSize(hLdrMod) != ~(size_t)0, VERR_INVALID_HANDLE);
int rc = rtDbgModLazyInit();
if (RT_FAILURE(rc))
return rc;
- if (!pszName)
- pszName = RTPathFilename(pszFilename);
+ uint64_t fDbgCfg = 0;
+ if (hDbgCfg)
+ {
+ rc = RTDbgCfgQueryUInt(hDbgCfg, RTDBGCFGPROP_FLAGS, &fDbgCfg);
+ AssertRCReturn(rc, rc);
+ }
/*
* Allocate a new module instance.
@@ -537,51 +1097,76 @@ RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, c
rc = RTCritSectInit(&pDbgMod->CritSect);
if (RT_SUCCESS(rc))
{
- pDbgMod->pszName = RTStrCacheEnter(g_hDbgModStrCache, pszName);
+ pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
if (pDbgMod->pszName)
{
- pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
- if (pDbgMod->pszDbgFile)
+ pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
+ if (pDbgMod->pszImgFile)
{
+ RTStrCacheRetain(pDbgMod->pszImgFile);
+ pDbgMod->pszImgFileSpecified = pDbgMod->pszImgFile;
+
/*
- * Try the map file readers.
+ * If we have a loader module, we must instantiate the loader
+ * side of things regardless of the deferred setting.
*/
- rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
+ if (hLdrMod != NIL_RTLDRMOD)
+ {
+ if (!cbImage)
+ cbImage = (uint32_t)RTLdrSize(hLdrMod);
+ pDbgMod->pImgVt = &g_rtDbgModVtImgLdr;
+
+ rc = rtDbgModLdrOpenFromHandle(pDbgMod, hLdrMod);
+ }
if (RT_SUCCESS(rc))
{
- rc = VERR_DBG_NO_MATCHING_INTERPRETER;
- for (PRTDBGMODREGDBG pCur = g_pDbgHead; pCur; pCur = pCur->pNext)
+ /*
+ * Do it now or procrastinate?
+ */
+ if (!(fDbgCfg & RTDBGCFG_FLAGS_DEFERRED) || !cbImage)
{
- if (pCur->pVt->fSupports & RT_DBGTYPE_MAP)
- {
- pDbgMod->pDbgVt = pCur->pVt;
- pDbgMod->pvDbgPriv = NULL;
- rc = pCur->pVt->pfnTryOpen(pDbgMod);
- if (RT_SUCCESS(rc))
- {
- ASMAtomicIncU32(&pCur->cUsers);
- RTSemRWReleaseRead(g_hDbgModRWSem);
-
- *phDbgMod = pDbgMod;
- return rc;
- }
- }
+ RTDBGMODDEFERRED Deferred;
+ Deferred.cbImage = cbImage;
+ Deferred.hDbgCfg = hDbgCfg;
+ Deferred.u.PeImage.uTimestamp = uTimestamp;
+ rc = rtDbgModFromPeImageDeferredCallback(pDbgMod, &Deferred);
+ }
+ else
+ {
+ PRTDBGMODDEFERRED pDeferred;
+ rc = rtDbgModDeferredCreate(pDbgMod, rtDbgModFromPeImageDeferredCallback, cbImage, hDbgCfg, &pDeferred);
+ if (RT_SUCCESS(rc))
+ pDeferred->u.PeImage.uTimestamp = uTimestamp;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ *phDbgMod = pDbgMod;
+ return VINF_SUCCESS;
}
- /* bail out */
- RTSemRWReleaseRead(g_hDbgModRWSem);
+ /* Failed, bail out. */
+ if (hLdrMod != NIL_RTLDRMOD)
+ {
+ Assert(pDbgMod->pImgVt);
+ pDbgMod->pImgVt->pfnClose(pDbgMod);
+ }
}
RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
}
- RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
+ else
+ rc = VERR_NO_STR_MEMORY;
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
}
+ else
+ rc = VERR_NO_STR_MEMORY;
RTCritSectDelete(&pDbgMod->CritSect);
}
RTMemFree(pDbgMod);
return rc;
}
-RT_EXPORT_SYMBOL(RTDbgModCreateFromMap);
+RT_EXPORT_SYMBOL(RTDbgModCreateFromPeImage);
/**
@@ -616,6 +1201,7 @@ static void rtDbgModDestroy(PRTDBGMODINT pDbgMod)
ASMAtomicWriteU32(&pDbgMod->u32Magic, ~RTDBGMOD_MAGIC);
RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
RTCritSectLeave(&pDbgMod->CritSect); /* paranoia */
RTCritSectDelete(&pDbgMod->CritSect);
@@ -623,15 +1209,6 @@ static void rtDbgModDestroy(PRTDBGMODINT pDbgMod)
}
-/**
- * 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)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -641,18 +1218,6 @@ RTDECL(uint32_t) RTDbgModRetain(RTDBGMOD hDbgMod)
RT_EXPORT_SYMBOL(RTDbgModRetain);
-/**
- * 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)
{
if (hDbgMod == NIL_RTDBGMOD)
@@ -668,13 +1233,6 @@ RTDECL(uint32_t) RTDbgModRelease(RTDBGMOD hDbgMod)
RT_EXPORT_SYMBOL(RTDbgModRelease);
-/**
- * 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)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -684,17 +1242,79 @@ RTDECL(const char *) RTDbgModName(RTDBGMOD hDbgMod)
RT_EXPORT_SYMBOL(RTDbgModName);
-/**
- * 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(const char *) RTDbgModDebugFile(RTDBGMOD hDbgMod)
+{
+ PRTDBGMODINT pDbgMod = hDbgMod;
+ RTDBGMOD_VALID_RETURN_RC(pDbgMod, NULL);
+ if (pDbgMod->fDeferred || pDbgMod->fExports)
+ return NULL;
+ return pDbgMod->pszDbgFile;
+}
+RT_EXPORT_SYMBOL(RTDbgModDebugFile);
+
+
+RTDECL(const char *) RTDbgModImageFile(RTDBGMOD hDbgMod)
+{
+ PRTDBGMODINT pDbgMod = hDbgMod;
+ RTDBGMOD_VALID_RETURN_RC(pDbgMod, NULL);
+ return pDbgMod->pszImgFileSpecified;
+}
+RT_EXPORT_SYMBOL(RTDbgModImageFile);
+
+
+RTDECL(const char *) RTDbgModImageFileUsed(RTDBGMOD hDbgMod)
+{
+ PRTDBGMODINT pDbgMod = hDbgMod;
+ RTDBGMOD_VALID_RETURN_RC(pDbgMod, NULL);
+ return pDbgMod->pszImgFile == pDbgMod->pszImgFileSpecified ? NULL : pDbgMod->pszImgFile;
+}
+RT_EXPORT_SYMBOL(RTDbgModImageFileUsed);
+
+
+RTDECL(bool) RTDbgModIsDeferred(RTDBGMOD hDbgMod)
+{
+ PRTDBGMODINT pDbgMod = hDbgMod;
+ RTDBGMOD_VALID_RETURN_RC(pDbgMod, false);
+ return pDbgMod->fDeferred;
+}
+
+
+RTDECL(bool) RTDbgModIsExports(RTDBGMOD hDbgMod)
+{
+ PRTDBGMODINT pDbgMod = hDbgMod;
+ RTDBGMOD_VALID_RETURN_RC(pDbgMod, false);
+ return pDbgMod->fExports;
+}
+
+
+RTDECL(int) RTDbgModRemoveAll(RTDBGMOD hDbgMod, bool fLeaveSegments)
+{
+ PRTDBGMODINT pDbgMod = hDbgMod;
+ RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
+
+ RTDBGMOD_LOCK(pDbgMod);
+
+ /* Only possible on container modules. */
+ int rc = VINF_SUCCESS;
+ if (pDbgMod->pDbgVt != &g_rtDbgModVtDbgContainer)
+ {
+ if (fLeaveSegments)
+ {
+ rc = rtDbgModContainer_LineRemoveAll(pDbgMod);
+ if (RT_SUCCESS(rc))
+ rc = rtDbgModContainer_SymbolRemoveAll(pDbgMod);
+ }
+ else
+ rc = rtDbgModContainer_RemoveAll(pDbgMod);
+ }
+ else
+ rc = VERR_ACCESS_DENIED;
+
+ RTDBGMOD_UNLOCK(pDbgMod);
+ return rc;
+}
+
+
RTDECL(RTDBGSEGIDX) RTDbgModRvaToSegOff(RTDBGMOD hDbgMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -709,17 +1329,6 @@ RTDECL(RTDBGSEGIDX) RTDbgModRvaToSegOff(RTDBGMOD hDbgMod, RTUINTPTR uRva, PRTUIN
RT_EXPORT_SYMBOL(RTDbgModRvaToSegOff);
-/**
- * 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)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -734,13 +1343,6 @@ RTDECL(RTUINTPTR) RTDbgModImageSize(RTDBGMOD hDbgMod)
RT_EXPORT_SYMBOL(RTDbgModImageSize);
-/**
- * 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)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -750,19 +1352,6 @@ RTDECL(uint64_t) RTDbgModGetTag(RTDBGMOD hDbgMod)
RT_EXPORT_SYMBOL(RTDbgModGetTag);
-/**
- * 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)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -777,35 +1366,6 @@ RTDECL(int) RTDbgModSetTag(RTDBGMOD hDbgMod, uint64_t uTag)
RT_EXPORT_SYMBOL(RTDbgModSetTag);
-/**
- * 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)
{
@@ -836,17 +1396,6 @@ RTDECL(int) RTDbgModSegmentAdd(RTDBGMOD hDbgMod, RTUINTPTR uRva, RTUINTPTR cb, c
RT_EXPORT_SYMBOL(RTDbgModSegmentAdd);
-/**
- * Gets the number of segments in the module.
- *
- * This is can be used to determine the range which can be passed to
- * RTDbgModSegmentByIndex and derivatives.
- *
- * @returns The segment relative address.
- * NIL_RTDBGSEGIDX if the handle is invalid.
- *
- * @param hDbgMod The module handle.
- */
RTDECL(RTDBGSEGIDX) RTDbgModSegmentCount(RTDBGMOD hDbgMod)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -861,23 +1410,6 @@ RTDECL(RTDBGSEGIDX) RTDbgModSegmentCount(RTDBGMOD hDbgMod)
RT_EXPORT_SYMBOL(RTDbgModSegmentCount);
-/**
- * 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)
{
AssertMsgReturn(iSeg <= RTDBGSEGIDX_LAST, ("%#x\n", iSeg), VERR_DBG_SPECIAL_SEGMENT);
@@ -893,20 +1425,6 @@ RTDECL(int) RTDbgModSegmentByIndex(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, PRTDBGSEG
RT_EXPORT_SYMBOL(RTDbgModSegmentByIndex);
-/**
- * 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)
{
if (iSeg == RTDBGSEGIDX_RVA)
@@ -918,19 +1436,6 @@ RTDECL(RTUINTPTR) RTDbgModSegmentSize(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg)
RT_EXPORT_SYMBOL(RTDbgModSegmentSize);
-/**
- * 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)
{
RTDBGSEGMENT SegInfo;
@@ -940,34 +1445,6 @@ RTDECL(RTUINTPTR) RTDbgModSegmentRva(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg)
RT_EXPORT_SYMBOL(RTDbgModSegmentRva);
-/**
- * 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.
- *
- * @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. Reserved for the future, MBZ.
- * @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)
{
@@ -1014,18 +1491,6 @@ RTDECL(int) RTDbgModSymbolAdd(RTDBGMOD hDbgMod, const char *pszSymbol, RTDBGSEGI
RT_EXPORT_SYMBOL(RTDbgModSymbolAdd);
-/**
- * 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)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -1040,20 +1505,6 @@ RTDECL(uint32_t) RTDbgModSymbolCount(RTDBGMOD hDbgMod)
RT_EXPORT_SYMBOL(RTDbgModSymbolCount);
-/**
- * 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)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -1068,22 +1519,6 @@ RTDECL(int) RTDbgModSymbolByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGS
RT_EXPORT_SYMBOL(RTDbgModSymbolByOrdinal);
-/**
- * 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)
{
AssertPtr(ppSymInfo);
@@ -1104,33 +1539,6 @@ RTDECL(int) RTDbgModSymbolByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBG
RT_EXPORT_SYMBOL(RTDbgModSymbolByOrdinalA);
-/**
- * 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)
{
@@ -1169,35 +1577,6 @@ RTDECL(int) RTDbgModSymbolByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR o
RT_EXPORT_SYMBOL(RTDbgModSymbolByAddr);
-/**
- * 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)
{
@@ -1219,19 +1598,6 @@ RTDECL(int) RTDbgModSymbolByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR
RT_EXPORT_SYMBOL(RTDbgModSymbolByAddrA);
-/**
- * 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)
{
/*
@@ -1257,22 +1623,6 @@ RTDECL(int) RTDbgModSymbolByName(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBG
RT_EXPORT_SYMBOL(RTDbgModSymbolByName);
-/**
- * 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)
{
AssertPtr(ppSymInfo);
@@ -1293,31 +1643,6 @@ RTDECL(int) RTDbgModSymbolByNameA(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDB
RT_EXPORT_SYMBOL(RTDbgModSymbolByNameA);
-/**
- * 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)
{
@@ -1362,18 +1687,6 @@ RTDECL(int) RTDbgModLineAdd(RTDBGMOD hDbgMod, const char *pszFile, uint32_t uLin
RT_EXPORT_SYMBOL(RTDbgModLineAdd);
-/**
- * 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)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -1388,23 +1701,6 @@ RTDECL(uint32_t) RTDbgModLineCount(RTDBGMOD hDbgMod)
RT_EXPORT_SYMBOL(RTDbgModLineCount);
-/**
- * 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)
{
PRTDBGMODINT pDbgMod = hDbgMod;
@@ -1419,25 +1715,6 @@ RTDECL(int) RTDbgModLineByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLIN
RT_EXPORT_SYMBOL(RTDbgModLineByOrdinal);
-/**
- * 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)
{
AssertPtr(ppLineInfo);
@@ -1458,31 +1735,6 @@ RTDECL(int) RTDbgModLineByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLI
RT_EXPORT_SYMBOL(RTDbgModLineByOrdinalA);
-/**
- * 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)
{
/*
@@ -1516,34 +1768,6 @@ RTDECL(int) RTDbgModLineByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off
RT_EXPORT_SYMBOL(RTDbgModLineByAddr);
-/**
- * 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)
{
AssertPtr(ppLineInfo);
diff --git a/src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp b/src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp
new file mode 100644
index 00000000..55d41fbd
--- /dev/null
+++ b/src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp
@@ -0,0 +1,2786 @@
+/* $Id: dbgmodcodeview.cpp $ */
+/** @file
+ * IPRT - Debug Module Reader For Microsoft CodeView and COFF.
+ *
+ * Based on the following documentation (plus guess work and googling):
+ *
+ * - "Tools Interface Standard (TIS) Formats Specification for Windows",
+ * dated February 1993, version 1.0.
+ *
+ * - "Visual C++ 5.0 Symbolic Debug Information Specification" chapter of
+ * SPECS.CHM from MSDN Library October 2001.
+ *
+ * - "High Level Languages Debug Table Documentation", aka HLLDBG.HTML, aka
+ * IBMHLL.HTML, last changed 1996-07-08.
+ *
+ * Testcases using RTLdrFlt:
+ * - VBoxPcBios.sym at 0xf0000.
+ * - NT4 kernel PE image (coff syms).
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DBG
+#include <iprt/dbg.h>
+#include "internal/iprt.h"
+
+#include <iprt/alloca.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/log.h>
+#include <iprt/mem.h>
+#include <iprt/param.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/strcache.h>
+#include "internal/dbgmod.h"
+#include "internal/ldrPE.h"
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * 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;
+
+
+/**
+ * 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,
+ kCvSymType_DataRef,
+ kCvSymType_Align
+ /** @} */
+} RTCVSYMTYPE;
+typedef RTCVSYMTYPE *PRTCVSYMTYPE;
+typedef RTCVSYMTYPE const *PCRTCVSYMTYPE;
+
+
+/** The $$SYMBOL table signature for CV4. */
+#define RTCVSYMBOLS_SIGNATURE_CV4 UINT32_C(0x00000001)
+
+
+/**
+ * Directory sorting order.
+ */
+typedef enum RTCVDIRORDER
+{
+ RTCVDIRORDER_INVALID = 0,
+ /** Ordered by module. */
+ RTCVDIRORDER_BY_MOD,
+ /** Ordered by module, but 0 modules at the end. */
+ RTCVDIRORDER_BY_MOD_0,
+ /** Ordered by section, with global modules at the end. */
+ RTCVDIRORDER_BY_SST_MOD
+} RTCVDIRORDER;
+
+
+/**
+ * File type.
+ */
+typedef enum RTCVFILETYPE
+{
+ RTCVFILETYPE_INVALID = 0,
+ /** Executable image. */
+ RTCVFILETYPE_IMAGE,
+ /** A DBG-file with a IMAGE_SEPARATE_DEBUG_HEADER. */
+ RTCVFILETYPE_DBG,
+ /** A PDB file. */
+ RTCVFILETYPE_PDB,
+ /** Some other kind of file with CV at the end. */
+ RTCVFILETYPE_OTHER_AT_END,
+ /** The end of the valid values. */
+ RTCVFILETYPE_END,
+ /** Type blowup. */
+ RTCVFILETYPE_32BIT_HACK = 0x7fffffff
+} RTCVFILETYPE;
+
+
+/**
+ * CodeView debug info reader instance.
+ */
+typedef struct RTDBGMODCV
+{
+ /** Using a container for managing the debug info. */
+ RTDBGMOD hCnt;
+
+ /** @name Codeview details
+ * @{ */
+ /** The code view magic (used as format indicator). */
+ uint32_t u32CvMagic;
+ /** The offset of the CV debug info in the file. */
+ uint32_t offBase;
+ /** The size of the CV debug info. */
+ uint32_t cbDbgInfo;
+ /** The offset of the subsection directory (relative to offBase). */
+ uint32_t offDir;
+ /** The directory order. */
+ RTCVDIRORDER enmDirOrder;
+ /** @} */
+
+ /** @name COFF details.
+ * @{ */
+ /** Offset of the COFF header. */
+ uint32_t offCoffDbgInfo;
+ /** The size of the COFF debug info. */
+ uint32_t cbCoffDbgInfo;
+ /** The COFF debug info header. */
+ IMAGE_COFF_SYMBOLS_HEADER CoffHdr;
+ /** @} */
+
+ /** The file type. */
+ RTCVFILETYPE enmType;
+ /** The file handle (if external). */
+ RTFILE hFile;
+ /** Pointer to the module (no reference retained). */
+ PRTDBGMODINT pMod;
+
+ /** The image size, if we know it. This is 0 if we don't know it. */
+ uint32_t cbImage;
+
+ /** Indicates that we've loaded segments intot he container already. */
+ bool fHaveLoadedSegments;
+ /** Alternative address translation method for DOS frames. */
+ bool fHaveDosFrames;
+
+ /** @name Codeview Parsing state.
+ * @{ */
+ /** Number of directory entries. */
+ uint32_t cDirEnts;
+ /** The directory (converted to 32-bit). */
+ PRTCVDIRENT32 paDirEnts;
+ /** Current debugging style when parsing modules. */
+ uint16_t uCurStyle;
+ /** Current debugging style version (HLL only). */
+ uint16_t uCurStyleVer;
+
+ /** The segment map (if present). */
+ PRTCVSEGMAP pSegMap;
+ /** Segment names. */
+ char *pszzSegNames;
+ /** The size of the segment names. */
+ uint32_t cbSegNames;
+
+ /** @} */
+
+} RTDBGMODCV;
+/** Pointer to a codeview debug info reader instance. */
+typedef RTDBGMODCV *PRTDBGMODCV;
+/** Pointer to a const codeview debug info reader instance. */
+typedef RTDBGMODCV *PCRTDBGMODCV;
+
+
+
+/**
+ * Subsection callback.
+ *
+ * @returns IPRT status code.
+ * @param pThis The CodeView debug info reader instance.
+ * @param pvSubSect Pointer to the subsection data.
+ * @param cbSubSect The size of the subsection data.
+ * @param pDirEnt The directory entry.
+ */
+typedef DECLCALLBACK(int) FNDBGMODCVSUBSECTCALLBACK(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect,
+ PCRTCVDIRENT32 pDirEnt);
+/** Pointer to a subsection callback. */
+typedef FNDBGMODCVSUBSECTCALLBACK *PFNDBGMODCVSUBSECTCALLBACK;
+
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** Light weight assert + return w/ fixed status code. */
+#define RTDBGMODCV_CHECK_RET_BF(a_Expr, a_LogArgs) \
+ do { \
+ if (!(a_Expr)) \
+ { \
+ Log(("RTDbgCv: Check failed on line %d: " #a_Expr "\n", __LINE__)); \
+ Log(a_LogArgs); \
+ /*return VERR_CV_BAD_FORMAT;*/ \
+ } \
+ } while (0)
+
+
+/** Light weight assert + return w/ fixed status code. */
+#define RTDBGMODCV_CHECK_NOMSG_RET_BF(a_Expr) \
+ do { \
+ if (!(a_Expr)) \
+ { \
+ Log(("RTDbgCv: Check failed on line %d: " #a_Expr "\n", __LINE__)); \
+ /*return VERR_CV_BAD_FORMAT;*/ \
+ } \
+ } while (0)
+
+
+
+
+
+/**
+ * Reads CodeView information.
+ *
+ * @returns IPRT status.
+ * @param pThis The CodeView reader instance.
+ * @param off The offset to start reading at, relative to the
+ * CodeView base header.
+ * @param pvBuf The buffer to read into.
+ * @param cb How many bytes to read.
+ */
+static int rtDbgModCvReadAt(PRTDBGMODCV pThis, uint32_t off, void *pvBuf, size_t cb)
+{
+ int rc;
+ if (pThis->hFile == NIL_RTFILE)
+ rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off + pThis->offBase, pvBuf, cb);
+ else
+ rc = RTFileReadAt(pThis->hFile, off + pThis->offBase, pvBuf, cb, NULL);
+ return rc;
+}
+
+
+/**
+ * Reads CodeView information into an allocated buffer.
+ *
+ * @returns IPRT status.
+ * @param pThis The CodeView reader instance.
+ * @param off The offset to start reading at, relative to the
+ * CodeView base header.
+ * @param ppvBuf Where to return the allocated buffer on success.
+ * @param cb How many bytes to read.
+ */
+static int rtDbgModCvReadAtAlloc(PRTDBGMODCV pThis, uint32_t off, void **ppvBuf, size_t cb)
+{
+ int rc;
+ void *pvBuf = *ppvBuf = RTMemAlloc(cb);
+ if (pvBuf)
+ {
+ if (pThis->hFile == NIL_RTFILE)
+ rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off + pThis->offBase, pvBuf, cb);
+ else
+ rc = RTFileReadAt(pThis->hFile, off + pThis->offBase, pvBuf, cb, NULL);
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+
+ RTMemFree(pvBuf);
+ *ppvBuf = NULL;
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ return rc;
+}
+
+
+/**
+ * Gets a name string for a subsection type.
+ *
+ * @returns Section name (read only).
+ * @param uSubSectType The subsection type.
+ */
+static const char *rtDbgModCvGetSubSectionName(uint16_t uSubSectType)
+{
+ switch (uSubSectType)
+ {
+ case kCvSst_OldModule: return "sstOldModule";
+ case kCvSst_OldPublic: return "sstOldPublic";
+ case kCvSst_OldTypes: return "sstOldTypes";
+ case kCvSst_OldSymbols: return "sstOldSymbols";
+ case kCvSst_OldSrcLines: return "sstOldSrcLines";
+ case kCvSst_OldLibraries: return "sstOldLibraries";
+ case kCvSst_OldImports: return "sstOldImports";
+ case kCvSst_OldCompacted: return "sstOldCompacted";
+ case kCvSst_OldSrcLnSeg: return "sstOldSrcLnSeg";
+ case kCvSst_OldSrcLines3: return "sstOldSrcLines3";
+
+ case kCvSst_Module: return "sstModule";
+ case kCvSst_Types: return "sstTypes";
+ case kCvSst_Public: return "sstPublic";
+ case kCvSst_PublicSym: return "sstPublicSym";
+ case kCvSst_Symbols: return "sstSymbols";
+ case kCvSst_AlignSym: return "sstAlignSym";
+ case kCvSst_SrcLnSeg: return "sstSrcLnSeg";
+ case kCvSst_SrcModule: return "sstSrcModule";
+ case kCvSst_Libraries: return "sstLibraries";
+ case kCvSst_GlobalSym: return "sstGlobalSym";
+ case kCvSst_GlobalPub: return "sstGlobalPub";
+ case kCvSst_GlobalTypes: return "sstGlobalTypes";
+ case kCvSst_MPC: return "sstMPC";
+ case kCvSst_SegMap: return "sstSegMap";
+ case kCvSst_SegName: return "sstSegName";
+ case kCvSst_PreComp: return "sstPreComp";
+ case kCvSst_PreCompMap: return "sstPreCompMap";
+ case kCvSst_OffsetMap16: return "sstOffsetMap16";
+ case kCvSst_OffsetMap32: return "sstOffsetMap32";
+ case kCvSst_FileIndex: return "sstFileIndex";
+ case kCvSst_StaticSym: return "sstStaticSym";
+ }
+ static char s_sz[32];
+ RTStrPrintf(s_sz, sizeof(s_sz), "Unknown%#x", uSubSectType);
+ return s_sz;
+}
+
+
+/**
+ * Adds a symbol to the container.
+ *
+ * @returns IPRT status code
+ * @param pThis The CodeView debug info reader instance.
+ * @param iSeg Segment number.
+ * @param off Offset into the segment
+ * @param pchName The symbol name (not necessarily terminated).
+ * @param cchName The symbol name length.
+ * @param fFlags Flags reserved for future exploits, MBZ.
+ */
+static int rtDbgModCvAddSymbol(PRTDBGMODCV pThis, uint32_t iSeg, uint64_t off, const char *pchName,
+ uint8_t cchName, uint32_t fFlags)
+{
+ const char *pszName = RTStrCacheEnterN(g_hDbgModStrCache, pchName, cchName);
+ if (!pszName)
+ return VERR_NO_STR_MEMORY;
+#if 1
+ Log2(("CV Sym: %04x:%08x %.*s\n", iSeg, off, cchName, pchName));
+ if (iSeg == 0)
+ iSeg = RTDBGSEGIDX_ABS;
+ else if (pThis->pSegMap)
+ {
+ if (pThis->fHaveDosFrames)
+ {
+ if ( iSeg > pThis->pSegMap->Hdr.cSegs
+ || iSeg == 0)
+ {
+ Log(("Invalid segment index/offset %#06x:%08x for symbol %.*s\n", iSeg, off, cchName, pchName));
+ return VERR_CV_BAD_FORMAT;
+ }
+ if (off <= pThis->pSegMap->aDescs[iSeg - 1].cb + pThis->pSegMap->aDescs[iSeg - 1].off)
+ off -= pThis->pSegMap->aDescs[iSeg - 1].off;
+ else
+ {
+ /* Workaround for VGABIOS where _DATA symbols like vgafont8 are
+ reported in the VGAROM segment. */
+ uint64_t uAddrSym = off + ((uint32_t)pThis->pSegMap->aDescs[iSeg - 1].iFrame << 4);
+ uint16_t j = pThis->pSegMap->Hdr.cSegs;
+ while (j-- > 0)
+ {
+ uint64_t uAddrFirst = (uint64_t)pThis->pSegMap->aDescs[j].off
+ + ((uint32_t)pThis->pSegMap->aDescs[j].iFrame << 4);
+ if (uAddrSym - uAddrFirst < pThis->pSegMap->aDescs[j].cb)
+ {
+ Log(("CV addr fix: %04x:%08x -> %04x:%08x\n", iSeg, off, j + 1, uAddrSym - uAddrFirst));
+ off = uAddrSym - uAddrFirst;
+ iSeg = j + 1;
+ break;
+ }
+ }
+ if (j == UINT16_MAX)
+ {
+ Log(("Invalid segment index/offset %#06x:%08x for symbol %.*s [2]\n", iSeg, off, cchName, pchName));
+ return VERR_CV_BAD_FORMAT;
+ }
+ }
+ }
+ else
+ {
+ if ( iSeg > pThis->pSegMap->Hdr.cSegs
+ || iSeg == 0
+ || off > pThis->pSegMap->aDescs[iSeg - 1].cb)
+ {
+ Log(("Invalid segment index/offset %#06x:%08x for symbol %.*s\n", iSeg, off, cchName, pchName));
+ return VERR_CV_BAD_FORMAT;
+ }
+ off += pThis->pSegMap->aDescs[iSeg - 1].off;
+ }
+ if (pThis->pSegMap->aDescs[iSeg - 1].fFlags & RTCVSEGMAPDESC_F_ABS)
+ iSeg = RTDBGSEGIDX_ABS;
+ else
+ iSeg = pThis->pSegMap->aDescs[iSeg - 1].iGroup;
+ }
+
+ int rc = RTDbgModSymbolAdd(pThis->hCnt, pszName, iSeg, off, 0, 0 /*fFlags*/, NULL);
+ Log(("Symbol: %04x:%08x %.*s [%Rrc]\n", iSeg, off, cchName, pchName, rc));
+ if (rc == VERR_DBG_ADDRESS_CONFLICT || rc == VERR_DBG_DUPLICATE_SYMBOL)
+ rc = VINF_SUCCESS;
+ RTStrCacheRelease(g_hDbgModStrCache, pszName);
+ return rc;
+#else
+ Log(("Symbol: %04x:%08x %.*s\n", iSeg, off, cchName, pchName));
+ return VINF_SUCCESS;
+#endif
+}
+
+
+/**
+ * Parses a CV4 symbol table, adding symbols to the container.
+ *
+ * @returns IPRT status code
+ * @param pThis The CodeView debug info reader instance.
+ * @param pbSymTab The symbol table.
+ * @param cbSymTab The size of the symbol table.
+ * @param fFlags Flags reserved for future exploits, MBZ.
+ */
+static int rtDbgModCvSsProcessV4SymTab(PRTDBGMODCV pThis, void const *pvSymTab, size_t cbSymTab, uint32_t fFlags)
+{
+ int rc = VINF_SUCCESS;
+ RTCPTRUNION uCursor;
+ uCursor.pv = pvSymTab;
+
+ while (cbSymTab > 0 && RT_SUCCESS(rc))
+ {
+ uint8_t const * const pbRecStart = uCursor.pu8;
+ uint16_t cbRec = *uCursor.pu16++;
+ if (cbRec >= 2)
+ {
+ uint16_t uSymType = *uCursor.pu16++;
+
+ Log3((" %p: uSymType=%#06x LB %#x\n", pbRecStart - (uint8_t *)pvSymTab, uSymType, cbRec));
+ RTDBGMODCV_CHECK_RET_BF(cbRec >= 2 && cbRec <= cbSymTab, ("cbRec=%#x cbSymTab=%#x\n", cbRec, cbSymTab));
+
+ switch (uSymType)
+ {
+ case kCvSymType_LData16:
+ case kCvSymType_GData16:
+ case kCvSymType_Pub16:
+ {
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec > 2 + 2+2+2+1);
+ uint16_t off = *uCursor.pu16++;
+ uint16_t iSeg = *uCursor.pu16++;
+ /*uint16_t iType =*/ *uCursor.pu16++;
+ uint8_t cchName = *uCursor.pu8++;
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cchName > 0);
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec >= 2 + 2+2+2+1 + cchName);
+
+ rc = rtDbgModCvAddSymbol(pThis, iSeg, off, uCursor.pch, cchName, 0);
+ break;
+ }
+
+ case kCvSymType_LData32:
+ case kCvSymType_GData32:
+ case kCvSymType_Pub32:
+ {
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec > 2 + 4+2+2+1);
+ uint32_t off = *uCursor.pu32++;
+ uint16_t iSeg = *uCursor.pu16++;
+ /*uint16_t iType =*/ *uCursor.pu16++;
+ uint8_t cchName = *uCursor.pu8++;
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cchName > 0);
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec >= 2 + 4+2+2+1 + cchName);
+
+ rc = rtDbgModCvAddSymbol(pThis, iSeg, off, uCursor.pch, cchName, 0);
+ break;
+ }
+
+ /** @todo add GProc and LProc so we can gather sizes as well as just symbols. */
+ }
+ }
+ /*else: shorter records can be used for alignment, I guess. */
+
+ /* next */
+ uCursor.pu8 = pbRecStart + cbRec + 2;
+ cbSymTab -= cbRec + 2;
+ }
+ return rc;
+}
+
+
+/** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK,
+ * Parses kCvSst_GlobalPub, kCvSst_GlobalSym and kCvSst_StaticSym subsections,
+ * adding symbols it finds to the container.} */
+static DECLCALLBACK(int)
+rtDbgModCvSs_GlobalPub_GlobalSym_StaticSym(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt)
+{
+ PCRTCVGLOBALSYMTABHDR pHdr = (PCRTCVGLOBALSYMTABHDR)pvSubSect;
+
+ /*
+ * Quick data validation.
+ */
+ Log2(("RTDbgModCv: %s: uSymHash=%#x uAddrHash=%#x cbSymbols=%#x cbSymHash=%#x cbAddrHash=%#x\n",
+ rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pHdr->uSymHash,
+ pHdr->uAddrHash, pHdr->cbSymbols, pHdr->cbSymHash, pHdr->cbAddrHash));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= sizeof(RTCVGLOBALSYMTABHDR));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF((uint64_t)pHdr->cbSymbols + pHdr->cbSymHash + pHdr->cbAddrHash <= cbSubSect - sizeof(*pHdr));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->uSymHash < 0x20);
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->uAddrHash < 0x20);
+ if (!pHdr->cbSymbols)
+ return VINF_SUCCESS;
+
+ /*
+ * Parse the symbols.
+ */
+ return rtDbgModCvSsProcessV4SymTab(pThis, pHdr + 1, pHdr->cbSymbols, 0);
+}
+
+
+/** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK,
+ * Parses kCvSst_Module subsection, storing the debugging style in pThis.} */
+static DECLCALLBACK(int)
+rtDbgModCvSs_Module(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt)
+{
+ RTCPTRUNION uCursor;
+ uCursor.pv = pvSubSect;
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 2 + 2 + 2 + 2 + 0 + 1);
+ uint16_t iOverlay = *uCursor.pu16++;
+ uint16_t iLib = *uCursor.pu16++;
+ uint16_t cSegs = *uCursor.pu16++;
+ pThis->uCurStyle = *uCursor.pu16++;
+ if (pThis->uCurStyle == 0)
+ pThis->uCurStyle = RT_MAKE_U16('C', 'V');
+ pThis->uCurStyleVer = 0;
+ uint8_t cchName = uCursor.pu8[cSegs * 12];
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 2 + 2 + 2 + 2 + cSegs * 12U + 1 + cchName);
+
+ const char *pchName = (const char *)&uCursor.pu8[cSegs * 12 + 1];
+ Log2(("RTDbgModCv: Module: iOverlay=%#x iLib=%#x cSegs=%#x Style=%c%c (%#x) %.*s\n", iOverlay, iLib, cSegs,
+ RT_BYTE1(pThis->uCurStyle), RT_BYTE2(pThis->uCurStyle), pThis->uCurStyle, cchName, pchName));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(pThis->uCurStyle == RT_MAKE_U16('C', 'V'));
+
+ PCRTCVMODSEGINFO32 paSegs = (PCRTCVMODSEGINFO32)uCursor.pv;
+ for (uint16_t iSeg = 0; iSeg < cSegs; iSeg++)
+ Log2((" #%02u: %04x:%08x LB %08x\n", iSeg, paSegs[iSeg].iSeg, paSegs[iSeg].off, paSegs[iSeg].cb));
+
+ return VINF_SUCCESS;
+}
+
+
+/** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK,
+ * Parses kCvSst_Symbols, kCvSst_PublicSym and kCvSst_AlignSym subsections,
+ * adding symbols it finds to the container.} */
+static DECLCALLBACK(int)
+rtDbgModCvSs_Symbols_PublicSym_AlignSym(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt)
+{
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(pThis->uCurStyle == RT_MAKE_U16('C', 'V'));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 8);
+
+ uint32_t u32Signature = *(uint32_t const *)pvSubSect;
+ RTDBGMODCV_CHECK_RET_BF(u32Signature == RTCVSYMBOLS_SIGNATURE_CV4,
+ ("%#x, expected %#x\n", u32Signature, RTCVSYMBOLS_SIGNATURE_CV4));
+
+ return rtDbgModCvSsProcessV4SymTab(pThis, (uint8_t const *)pvSubSect + 4, cbSubSect - 4, 0);
+}
+
+
+static int rtDbgModCvLoadSegmentMap(PRTDBGMODCV pThis)
+{
+ /*
+ * Search for the segment map and segment names. They will be at the end of the directory.
+ */
+ uint32_t iSegMap = UINT32_MAX;
+ uint32_t iSegNames = UINT32_MAX;
+ uint32_t i = pThis->cDirEnts;
+ while (i-- > 0)
+ {
+ if ( pThis->paDirEnts[i].iMod != 0xffff
+ && pThis->paDirEnts[i].iMod != 0x0000)
+ break;
+ if (pThis->paDirEnts[i].uSubSectType == kCvSst_SegMap)
+ iSegMap = i;
+ else if (pThis->paDirEnts[i].uSubSectType == kCvSst_SegName)
+ iSegNames = i;
+ }
+ if (iSegMap == UINT32_MAX)
+ {
+ Log(("RTDbgModCv: No segment map present, using segment indexes as is then...\n"));
+ return VINF_SUCCESS;
+ }
+ RTDBGMODCV_CHECK_RET_BF(pThis->paDirEnts[iSegMap].cb >= sizeof(RTCVSEGMAPHDR),
+ ("Bad sstSegMap entry: cb=%#x\n", pThis->paDirEnts[iSegMap].cb));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(iSegNames == UINT32_MAX || pThis->paDirEnts[iSegNames].cb > 0);
+
+ /*
+ * Read them into memory.
+ */
+ int rc = rtDbgModCvReadAtAlloc(pThis, pThis->paDirEnts[iSegMap].off, (void **)&pThis->pSegMap,
+ pThis->paDirEnts[iSegMap].cb);
+ if (iSegNames != UINT32_MAX && RT_SUCCESS(rc))
+ {
+ pThis->cbSegNames = pThis->paDirEnts[iSegNames].cb;
+ rc = rtDbgModCvReadAtAlloc(pThis, pThis->paDirEnts[iSegNames].off, (void **)&pThis->pszzSegNames,
+ pThis->paDirEnts[iSegNames].cb);
+ }
+ if (RT_FAILURE(rc))
+ return rc;
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(!pThis->pszzSegNames || !pThis->pszzSegNames[pThis->cbSegNames - 1]); /* must be terminated */
+
+ /* Use local pointers to avoid lots of indirection and typing. */
+ PCRTCVSEGMAPHDR pHdr = &pThis->pSegMap->Hdr;
+ PRTCVSEGMAPDESC paDescs = &pThis->pSegMap->aDescs[0];
+
+ /*
+ * If there are only logical segments, assume a direct mapping.
+ * PE images, like the NT4 kernel, does it like this.
+ */
+ bool const fNoGroups = pHdr->cSegs == pHdr->cLogSegs;
+
+ /*
+ * The PE image has an extra section/segment for the headers, the others
+ * doesn't. PE images doesn't have DOS frames. So, figure the image type now.
+ */
+ RTLDRFMT enmImgFmt = RTLDRFMT_INVALID;
+ if (pThis->pMod->pImgVt)
+ enmImgFmt = pThis->pMod->pImgVt->pfnGetFormat(pThis->pMod);
+
+ /*
+ * Validate and display it all.
+ */
+ Log2(("RTDbgModCv: SegMap: cSegs=%#x cLogSegs=%#x (cbSegNames=%#x)\n", pHdr->cSegs, pHdr->cLogSegs, pThis->cbSegNames));
+ RTDBGMODCV_CHECK_RET_BF(pThis->paDirEnts[iSegMap].cb >= sizeof(*pHdr) + pHdr->cSegs * sizeof(paDescs[0]),
+ ("SegMap is out of bounds: cbSubSect=%#x cSegs=%#x\n", pThis->paDirEnts[iSegMap].cb, pHdr->cSegs));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->cSegs >= pHdr->cLogSegs);
+
+ Log2(("Logical segment descriptors: %u\n", pHdr->cLogSegs));
+
+ bool fHaveDosFrames = false;
+ for (i = 0; i < pHdr->cSegs; i++)
+ {
+ if (i == pHdr->cLogSegs)
+ Log2(("Group/Physical descriptors: %u\n", pHdr->cSegs - pHdr->cLogSegs));
+ uint16_t idx = i < pHdr->cLogSegs ? i : i - pHdr->cLogSegs;
+ char szFlags[16];
+ memset(szFlags, '-', sizeof(szFlags));
+ if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_READ)
+ szFlags[0] = 'R';
+ if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_WRITE)
+ szFlags[1] = 'W';
+ if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_EXECUTE)
+ szFlags[2] = 'X';
+ if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_32BIT)
+ szFlags[3] = '3', szFlags[4] = '2';
+ if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_SEL)
+ szFlags[5] = 'S';
+ if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS)
+ szFlags[6] = 'A';
+ if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP)
+ szFlags[7] = 'G';
+ szFlags[8] = '\0';
+ if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_RESERVED)
+ szFlags[8] = '!', szFlags[9] = '\0';
+ Log2((" #%02u: %#010x LB %#010x flags=%#06x ovl=%#06x group=%#06x frame=%#06x iSegName=%#06x iClassName=%#06x %s\n",
+ idx, paDescs[i].off, paDescs[i].cb, paDescs[i].fFlags, paDescs[i].iOverlay, paDescs[i].iGroup,
+ paDescs[i].iFrame, paDescs[i].offSegName, paDescs[i].offClassName, szFlags));
+
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].offSegName == UINT16_MAX || paDescs[i].offSegName < pThis->cbSegNames);
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].offClassName == UINT16_MAX || paDescs[i].offClassName < pThis->cbSegNames);
+ const char *pszName = paDescs[i].offSegName != UINT16_MAX
+ ? pThis->pszzSegNames + paDescs[i].offSegName
+ : NULL;
+ const char *pszClass = paDescs[i].offClassName != UINT16_MAX
+ ? pThis->pszzSegNames + paDescs[i].offClassName
+ : NULL;
+ if (pszName || pszClass)
+ Log2((" pszName=%s pszClass=%s\n", pszName, pszClass));
+
+ /* Validate the group link. */
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iGroup == 0 || !(paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF( paDescs[i].iGroup == 0
+ || ( paDescs[i].iGroup >= pHdr->cLogSegs
+ && paDescs[i].iGroup < pHdr->cSegs));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF( paDescs[i].iGroup == 0
+ || (paDescs[paDescs[i].iGroup].fFlags & RTCVSEGMAPDESC_F_GROUP));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(!(paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || paDescs[i].off == 0); /* assumed below */
+
+ if (fNoGroups)
+ {
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iGroup == 0);
+ if ( !fHaveDosFrames
+ && paDescs[i].iFrame != 0
+ && (paDescs[i].fFlags & (RTCVSEGMAPDESC_F_SEL | RTCVSEGMAPDESC_F_ABS))
+ && paDescs[i].iOverlay == 0
+ && enmImgFmt != RTLDRFMT_PE
+ && pThis->enmType != RTCVFILETYPE_DBG)
+ fHaveDosFrames = true; /* BIOS, only groups with frames. */
+ }
+ }
+
+ /*
+ * Further valiations based on fHaveDosFrames or not.
+ */
+ if (fNoGroups)
+ {
+ if (fHaveDosFrames)
+ for (i = 0; i < pHdr->cSegs; i++)
+ {
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iOverlay == 0);
+ RTDBGMODCV_CHECK_NOMSG_RET_BF( (paDescs[i].fFlags & (RTCVSEGMAPDESC_F_SEL | RTCVSEGMAPDESC_F_ABS))
+ == RTCVSEGMAPDESC_F_SEL
+ || (paDescs[i].fFlags & (RTCVSEGMAPDESC_F_SEL | RTCVSEGMAPDESC_F_ABS))
+ == RTCVSEGMAPDESC_F_ABS);
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(!(paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS));
+ }
+ else
+ for (i = 0; i < pHdr->cSegs; i++)
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].off == 0);
+ }
+
+ /*
+ * Modify the groups index to be the loader segment index instead, also
+ * add the segments to the container if we haven't done that already.
+ */
+
+ /* Guess work: Group can be implicit if used. Observed Visual C++ v1.5,
+ omitting the CODE group. */
+ const char *pszGroup0 = NULL;
+ uint64_t cbGroup0 = 0;
+ if (!fNoGroups && !fHaveDosFrames)
+ {
+ for (i = 0; i < pHdr->cSegs; i++)
+ if ( !(paDescs[i].fFlags & (RTCVSEGMAPDESC_F_GROUP | RTCVSEGMAPDESC_F_ABS))
+ && paDescs[i].iGroup == 0)
+ {
+ if (pszGroup0 == NULL && paDescs[i].offClassName != UINT16_MAX)
+ pszGroup0 = pThis->pszzSegNames + paDescs[i].offClassName;
+ uint64_t offEnd = (uint64_t)paDescs[i].off + paDescs[i].cb;
+ if (offEnd > cbGroup0)
+ cbGroup0 = offEnd;
+ }
+ }
+
+ /* Add the segments.
+ Note! The RVAs derived from this exercise are all wrong. :-/
+ Note! We don't have an image loader, so we cannot add any fake sections. */
+ /** @todo Try see if we can figure something out from the frame value later. */
+ if (!pThis->fHaveLoadedSegments)
+ {
+ uint16_t iSeg = 0;
+ if (!fHaveDosFrames)
+ {
+ Assert(!pThis->pMod->pImgVt); Assert(pThis->enmType != RTCVFILETYPE_DBG);
+ uint64_t uRva = 0;
+ if (cbGroup0 && !fNoGroups)
+ {
+ rc = RTDbgModSegmentAdd(pThis->hCnt, 0, cbGroup0, pszGroup0 ? pszGroup0 : "Seg00", 0 /*fFlags*/, NULL);
+ uRva += cbGroup0;
+ iSeg++;
+ }
+
+ for (i = 0; RT_SUCCESS(rc) && i < pHdr->cSegs; i++)
+ if ((paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || fNoGroups)
+ {
+ char szName[16];
+ char *pszName = szName;
+ if (paDescs[i].offSegName != UINT16_MAX)
+ pszName = pThis->pszzSegNames + paDescs[i].offSegName;
+ else
+ RTStrPrintf(szName, sizeof(szName), "Seg%02u", iSeg);
+ rc = RTDbgModSegmentAdd(pThis->hCnt, uRva, paDescs[i].cb, pszName, 0 /*fFlags*/, NULL);
+ uRva += paDescs[i].cb;
+ iSeg++;
+ }
+ }
+ else
+ {
+ /* The map is not sorted by RVA, very annoying, but I'm countering
+ by being lazy and slow about it. :-) Btw. this is the BIOS case. */
+ Assert(fNoGroups);
+#if 1 /** @todo need more inputs */
+
+ /* Figure image base address. */
+ uint64_t uImageBase = UINT64_MAX;
+ for (i = 0; RT_SUCCESS(rc) && i < pHdr->cSegs; i++)
+ {
+ uint64_t uAddr = (uint64_t)paDescs[i].off + ((uint32_t)paDescs[i].iFrame << 4);
+ if (uAddr < uImageBase)
+ uImageBase = uAddr;
+ }
+
+ /* Add the segments. */
+ uint64_t uMinAddr = uImageBase;
+ for (i = 0; RT_SUCCESS(rc) && i < pHdr->cSegs; i++)
+ {
+ /* Figure out the next one. */
+ uint16_t cOverlaps = 0;
+ uint16_t iBest = UINT16_MAX;
+ uint64_t uBestAddr = UINT64_MAX;
+ for (uint16_t j = 0; j < pHdr->cSegs; j++)
+ {
+ uint64_t uAddr = (uint64_t)paDescs[j].off + ((uint32_t)paDescs[j].iFrame << 4);
+ if (uAddr >= uMinAddr && uAddr < uBestAddr)
+ {
+ uBestAddr = uAddr;
+ iBest = j;
+ }
+ else if (uAddr == uBestAddr)
+ {
+ cOverlaps++;
+ if (paDescs[j].cb > paDescs[iBest].cb)
+ {
+ uBestAddr = uAddr;
+ iBest = j;
+ }
+ }
+ }
+ if (iBest == UINT16_MAX && RT_SUCCESS(rc))
+ {
+ rc = VERR_CV_IPE;
+ break;
+ }
+
+ /* Add it. */
+ char szName[16];
+ char *pszName = szName;
+ if (paDescs[iBest].offSegName != UINT16_MAX)
+ pszName = pThis->pszzSegNames + paDescs[iBest].offSegName;
+ else
+ RTStrPrintf(szName, sizeof(szName), "Seg%02u", iSeg);
+ Log(("CV: %#010x LB %#010x %s uRVA=%#010x iBest=%u cOverlaps=%u\n",
+ uBestAddr, paDescs[iBest].cb, szName, uBestAddr - uImageBase, iBest, cOverlaps));
+ rc = RTDbgModSegmentAdd(pThis->hCnt, uBestAddr - uImageBase, paDescs[iBest].cb, pszName, 0 /*fFlags*/, NULL);
+
+ /* Update translations. */
+ paDescs[iBest].iGroup = iSeg;
+ if (cOverlaps > 0)
+ {
+ for (uint16_t j = 0; j < pHdr->cSegs; j++)
+ if ((uint64_t)paDescs[j].off + ((uint32_t)paDescs[j].iFrame << 4) == uBestAddr)
+ paDescs[iBest].iGroup = iSeg;
+ i += cOverlaps;
+ }
+
+ /* Advance. */
+ uMinAddr = uBestAddr + 1;
+ iSeg++;
+ }
+
+ pThis->fHaveDosFrames = true;
+#else
+ uint32_t iFrameFirst = UINT32_MAX;
+ uint16_t iSeg = 0;
+ uint32_t iFrameMin = 0;
+ do
+ {
+ /* Find next frame. */
+ uint32_t iFrame = UINT32_MAX;
+ for (uint16_t j = 0; j < pHdr->cSegs; j++)
+ if (paDescs[j].iFrame >= iFrameMin && paDescs[j].iFrame < iFrame)
+ iFrame = paDescs[j].iFrame;
+ if (iFrame == UINT32_MAX)
+ break;
+
+ /* Figure the frame span. */
+ uint32_t offFirst = UINT32_MAX;
+ uint64_t offEnd = 0;
+ for (uint16_t j = 0; j < pHdr->cSegs; j++)
+ if (paDescs[j].iFrame == iFrame)
+ {
+ uint64_t offThisEnd = paDescs[j].off + paDescs[j].cb;
+ if (offThisEnd > offEnd)
+ offEnd = offThisEnd;
+ if (paDescs[j].off < offFirst)
+ offFirst = paDescs[j].off;
+ }
+
+ if (offFirst < offEnd)
+ {
+ /* Add it. */
+ char szName[16];
+ RTStrPrintf(szName, sizeof(szName), "Frame_%04x", iFrame);
+ Log(("CV: %s offEnd=%#x offFirst=%#x\n", szName, offEnd, offFirst));
+ if (iFrameFirst == UINT32_MAX)
+ iFrameFirst = iFrame;
+ rc = RTDbgModSegmentAdd(pThis->hCnt, (iFrame - iFrameFirst) << 4, offEnd, szName, 0 /*fFlags*/, NULL);
+
+ /* Translation updates. */
+ for (uint16_t j = 0; j < pHdr->cSegs; j++)
+ if (paDescs[j].iFrame == iFrame)
+ {
+ paDescs[j].iGroup = iSeg;
+ paDescs[j].off = 0;
+ paDescs[j].cb = offEnd > UINT32_MAX ? UINT32_MAX : (uint32_t)offEnd;
+ }
+
+ iSeg++;
+ }
+
+ iFrameMin = iFrame + 1;
+ } while (RT_SUCCESS(rc));
+#endif
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ Log(("RTDbgModCv: %Rrc while adding segments from SegMap\n", rc));
+ return rc;
+ }
+
+ pThis->fHaveLoadedSegments = true;
+
+ /* Skip the stuff below if we have DOS frames since we did it all above. */
+ if (fHaveDosFrames)
+ return VINF_SUCCESS;
+ }
+
+ /* Pass one: Fixate the group segment indexes. */
+ uint16_t iSeg0 = enmImgFmt == RTLDRFMT_PE || pThis->enmType == RTCVFILETYPE_DBG ? 1 : 0;
+ uint16_t iSeg = iSeg0 + (cbGroup0 > 0); /** @todo probably wrong... */
+ for (i = 0; i < pHdr->cSegs; i++)
+ if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS)
+ paDescs[i].iGroup = (uint16_t)RTDBGSEGIDX_ABS;
+ else if ((paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || fNoGroups)
+ paDescs[i].iGroup = iSeg++;
+
+ /* Pass two: Resolve group references in to segment indexes. */
+ Log2(("Mapped segments (both kinds):\n"));
+ for (i = 0; i < pHdr->cSegs; i++)
+ {
+ if (!fNoGroups && !(paDescs[i].fFlags & (RTCVSEGMAPDESC_F_GROUP | RTCVSEGMAPDESC_F_ABS)))
+ paDescs[i].iGroup = paDescs[i].iGroup == 0 ? iSeg0 : paDescs[paDescs[i].iGroup].iGroup;
+
+ Log2((" #%02u: %#010x LB %#010x -> %#06x (flags=%#06x ovl=%#06x frame=%#06x)\n",
+ i, paDescs[i].off, paDescs[i].cb, paDescs[i].iGroup,
+ paDescs[i].fFlags, paDescs[i].iOverlay, paDescs[i].iFrame));
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Loads the directory into memory (RTDBGMODCV::paDirEnts and
+ * RTDBGMODCV::cDirEnts).
+ *
+ * Converting old format version into the newer format to simplifying the code
+ * using the directory.
+ *
+ *
+ * @returns IPRT status code. (May leave with paDirEnts allocated on failure.)
+ * @param pThis The CV reader instance.
+ */
+static int rtDbgModCvLoadDirectory(PRTDBGMODCV pThis)
+{
+ /*
+ * Read in the CV directory.
+ */
+ int rc;
+ if ( pThis->u32CvMagic == RTCVHDR_MAGIC_NB00
+ || pThis->u32CvMagic == RTCVHDR_MAGIC_NB02)
+ {
+ /*
+ * 16-bit type.
+ */
+ RTCVDIRHDR16 DirHdr;
+ rc = rtDbgModCvReadAt(pThis, pThis->offDir, &DirHdr, sizeof(DirHdr));
+ if (RT_SUCCESS(rc))
+ {
+ if (DirHdr.cEntries > 2 && DirHdr.cEntries < _64K - 32U)
+ {
+ pThis->cDirEnts = DirHdr.cEntries;
+ pThis->paDirEnts = (PRTCVDIRENT32)RTMemAlloc(DirHdr.cEntries * sizeof(pThis->paDirEnts[0]));
+ if (pThis->paDirEnts)
+ {
+ rc = rtDbgModCvReadAt(pThis, pThis->offDir + sizeof(DirHdr),
+ pThis->paDirEnts, DirHdr.cEntries * sizeof(RTCVDIRENT16));
+ if (RT_SUCCESS(rc))
+ {
+ /* Convert the entries (from the end). */
+ uint32_t cLeft = DirHdr.cEntries;
+ RTCVDIRENT32 volatile *pDst = pThis->paDirEnts + cLeft;
+ RTCVDIRENT16 volatile *pSrc = (RTCVDIRENT16 volatile *)pThis->paDirEnts + cLeft;
+ while (cLeft--)
+ {
+ pDst--;
+ pSrc--;
+
+ pDst->cb = pSrc->cb;
+ pDst->off = RT_MAKE_U32(pSrc->offLow, pSrc->offHigh);
+ pDst->iMod = pSrc->iMod;
+ pDst->uSubSectType = pSrc->uSubSectType;
+ }
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ {
+ Log(("Old CV directory count is out of considered valid range: %#x\n", DirHdr.cEntries));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * 32-bit type (reading too much for NB04 is no problem).
+ */
+ RTCVDIRHDR32EX DirHdr;
+ rc = rtDbgModCvReadAt(pThis, pThis->offDir, &DirHdr, sizeof(DirHdr));
+ if (RT_SUCCESS(rc))
+ {
+ if ( DirHdr.Core.cbHdr != sizeof(DirHdr.Core)
+ && DirHdr.Core.cbHdr != sizeof(DirHdr))
+ {
+ Log(("Unexpected CV directory size: %#x\n", DirHdr.Core.cbHdr));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if ( DirHdr.Core.cbHdr == sizeof(DirHdr)
+ && ( DirHdr.offNextDir != 0
+ || DirHdr.fFlags != 0) )
+ {
+ Log(("Extended CV directory headers fields are not zero: fFlags=%#x offNextDir=%#x\n",
+ DirHdr.fFlags, DirHdr.offNextDir));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if (DirHdr.Core.cbEntry != sizeof(RTCVDIRENT32))
+ {
+ Log(("Unexpected CV directory entry size: %#x (expected %#x)\n", DirHdr.Core.cbEntry, sizeof(RTCVDIRENT32)));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if (DirHdr.Core.cEntries < 2 || DirHdr.Core.cEntries >= _512K)
+ {
+ Log(("CV directory count is out of considered valid range: %#x\n", DirHdr.Core.cEntries));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ pThis->cDirEnts = DirHdr.Core.cEntries;
+ pThis->paDirEnts = (PRTCVDIRENT32)RTMemAlloc(DirHdr.Core.cEntries * sizeof(pThis->paDirEnts[0]));
+ if (pThis->paDirEnts)
+ rc = rtDbgModCvReadAt(pThis, pThis->offDir + DirHdr.Core.cbHdr,
+ pThis->paDirEnts, DirHdr.Core.cEntries * sizeof(RTCVDIRENT32));
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ }
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Basic info validation and determining the directory ordering.
+ */
+ bool fWatcom = 0;
+ uint16_t cGlobalMods = 0;
+ uint16_t cNormalMods = 0;
+ uint16_t iModLast = 0;
+ uint32_t const cbDbgInfo = pThis->cbDbgInfo;
+ uint32_t const cDirEnts = pThis->cDirEnts;
+ Log2(("RTDbgModCv: %u (%#x) directory entries:\n", cDirEnts, cDirEnts));
+ for (uint32_t i = 0; i < cDirEnts; i++)
+ {
+ PCRTCVDIRENT32 pDirEnt = &pThis->paDirEnts[i];
+ Log2((" #%04u mod=%#06x sst=%#06x at %#010x LB %#07x %s\n",
+ i, pDirEnt->iMod, pDirEnt->uSubSectType, pDirEnt->off, pDirEnt->cb,
+ rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType)));
+
+ if ( pDirEnt->off >= cbDbgInfo
+ || pDirEnt->cb >= cbDbgInfo
+ || pDirEnt->off + pDirEnt->cb > cbDbgInfo)
+ {
+ Log(("CV directory entry #%u is out of bounds: %#x LB %#x, max %#x\n", i, pDirEnt->off, pDirEnt->cb, cbDbgInfo));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if ( pDirEnt->iMod == 0
+ && pThis->u32CvMagic != RTCVHDR_MAGIC_NB04
+ && pThis->u32CvMagic != RTCVHDR_MAGIC_NB02
+ && pThis->u32CvMagic != RTCVHDR_MAGIC_NB00)
+ {
+ Log(("CV directory entry #%u uses module index 0 (uSubSectType=%#x)\n", i, pDirEnt->iMod, pDirEnt->uSubSectType));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if (pDirEnt->iMod == 0 || pDirEnt->iMod == 0xffff)
+ cGlobalMods++;
+ else
+ {
+ if (pDirEnt->iMod > iModLast)
+ {
+ if ( pDirEnt->uSubSectType != kCvSst_Module
+ && pDirEnt->uSubSectType != kCvSst_OldModule)
+ {
+ Log(("CV directory entry #%u: expected module subsection first, found %s (%#x)\n",
+ i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pDirEnt->uSubSectType));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if (pDirEnt->iMod != iModLast + 1)
+ {
+ Log(("CV directory entry #%u: skips from mod %#x to %#x modules\n", iModLast, pDirEnt->iMod));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ iModLast = pDirEnt->iMod;
+ }
+ else if (pDirEnt->iMod < iModLast)
+ fWatcom = true;
+ cNormalMods++;
+ }
+ }
+ if (cGlobalMods == 0)
+ {
+ Log(("CV directory contains no global modules\n"));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ if (fWatcom)
+ pThis->enmDirOrder = RTCVDIRORDER_BY_SST_MOD;
+ else if (pThis->paDirEnts[0].iMod == 0)
+ pThis->enmDirOrder = RTCVDIRORDER_BY_MOD_0;
+ else
+ pThis->enmDirOrder = RTCVDIRORDER_BY_MOD;
+ Log(("CV dir stats: %u total, %u normal, %u special, iModLast=%#x (%u), enmDirOrder=%d\n",
+ cDirEnts, cNormalMods, cGlobalMods, iModLast, iModLast, pThis->enmDirOrder));
+
+
+ /*
+ * Validate the directory ordering.
+ */
+ uint16_t i = 0;
+
+ /* Old style with special modules up front. */
+ if (pThis->enmDirOrder == RTCVDIRORDER_BY_MOD_0)
+ while (i < cGlobalMods)
+ {
+ if (pThis->paDirEnts[i].iMod != 0)
+ {
+ Log(("CV directory entry #%u: Expected iMod=%x instead of %x\n", i, 0, pThis->paDirEnts[i].iMod));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ i++;
+ }
+
+ /* Normal modules. */
+ if (pThis->enmDirOrder != RTCVDIRORDER_BY_SST_MOD)
+ {
+ uint16_t iEndNormalMods = cNormalMods + (pThis->enmDirOrder == RTCVDIRORDER_BY_MOD_0 ? cGlobalMods : 0);
+ while (i < iEndNormalMods)
+ {
+ if (pThis->paDirEnts[i].iMod == 0 || pThis->paDirEnts[i].iMod == 0xffff)
+ {
+ Log(("CV directory entry #%u: Unexpected global module entry.\n", i));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ i++;
+ }
+ }
+ else
+ {
+ uint32_t fSeen = RT_BIT_32(kCvSst_Module - kCvSst_Module)
+ | RT_BIT_32(kCvSst_Libraries - kCvSst_Module)
+ | RT_BIT_32(kCvSst_GlobalSym - kCvSst_Module)
+ | RT_BIT_32(kCvSst_GlobalPub - kCvSst_Module)
+ | RT_BIT_32(kCvSst_GlobalTypes - kCvSst_Module)
+ | RT_BIT_32(kCvSst_SegName - kCvSst_Module)
+ | RT_BIT_32(kCvSst_SegMap - kCvSst_Module)
+ | RT_BIT_32(kCvSst_StaticSym - kCvSst_Module)
+ | RT_BIT_32(kCvSst_FileIndex - kCvSst_Module)
+ | RT_BIT_32(kCvSst_MPC - kCvSst_Module);
+ uint16_t iMod = 0;
+ uint16_t uSst = kCvSst_Module;
+ while (i < cNormalMods)
+ {
+ PCRTCVDIRENT32 pDirEnt = &pThis->paDirEnts[i];
+ if (pDirEnt->iMod > iMod)
+ {
+ if (pDirEnt->uSubSectType != uSst)
+ {
+ Log(("CV directory entry #%u: Expected %s (%#x), found %s (%#x).\n",
+ i, rtDbgModCvGetSubSectionName(uSst), uSst,
+ rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pDirEnt->uSubSectType));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ }
+ else
+ {
+ uint32_t iBit = pDirEnt->uSubSectType - kCvSst_Module;
+ if (iBit >= 32U || (fSeen & RT_BIT_32(iBit)))
+ {
+ Log(("CV directory entry #%u: SST %s (%#x) has already been seen or is for globals.\n",
+ i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pDirEnt->uSubSectType));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ fSeen |= RT_BIT_32(iBit);
+ }
+
+ uSst = pDirEnt->uSubSectType;
+ iMod = pDirEnt->iMod;
+ i++;
+ }
+ }
+
+ /* New style with special modules at the end. */
+ if (pThis->enmDirOrder != RTCVDIRORDER_BY_MOD_0)
+ while (i < cDirEnts)
+ {
+ if (pThis->paDirEnts[i].iMod != 0 && pThis->paDirEnts[i].iMod != 0xffff)
+ {
+ Log(("CV directory entry #%u: Expected global module entry, not %#x.\n", i,
+ pThis->paDirEnts[i].iMod));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ i++;
+ }
+ }
+
+ }
+
+ return rc;
+}
+
+
+static int rtDbgModCvLoadCodeViewInfo(PRTDBGMODCV pThis)
+{
+ /*
+ * Load the directory, the segment map (if any) and then scan for segments
+ * if necessary.
+ */
+ int rc = rtDbgModCvLoadDirectory(pThis);
+ if (RT_SUCCESS(rc))
+ rc = rtDbgModCvLoadSegmentMap(pThis);
+ if (RT_SUCCESS(rc) && !pThis->fHaveLoadedSegments)
+ {
+ rc = VERR_CV_TODO; /** @todo Scan anything containing address, in particular sstSegMap and sstModule,
+ * and reconstruct the segments from that information. */
+ pThis->cbImage = 0x1000;
+ rc = VINF_SUCCESS;
+ }
+
+ /*
+ * Process the directory.
+ */
+ for (uint32_t i = 0; RT_SUCCESS(rc) && i < pThis->cDirEnts; i++)
+ {
+ PCRTCVDIRENT32 pDirEnt = &pThis->paDirEnts[i];
+ Log3(("Processing subsection %#u %s\n", i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType)));
+ PFNDBGMODCVSUBSECTCALLBACK pfnCallback = NULL;
+ switch (pDirEnt->uSubSectType)
+ {
+ case kCvSst_GlobalPub:
+ case kCvSst_GlobalSym:
+ case kCvSst_StaticSym:
+ pfnCallback = rtDbgModCvSs_GlobalPub_GlobalSym_StaticSym;
+ break;
+ case kCvSst_Module:
+ pfnCallback = rtDbgModCvSs_Module;
+ break;
+ case kCvSst_PublicSym:
+ case kCvSst_Symbols:
+ case kCvSst_AlignSym:
+ pfnCallback = rtDbgModCvSs_Symbols_PublicSym_AlignSym;
+ break;
+
+ case kCvSst_OldModule:
+ case kCvSst_OldPublic:
+ case kCvSst_OldTypes:
+ case kCvSst_OldSymbols:
+ case kCvSst_OldSrcLines:
+ case kCvSst_OldLibraries:
+ case kCvSst_OldImports:
+ case kCvSst_OldCompacted:
+ case kCvSst_OldSrcLnSeg:
+ case kCvSst_OldSrcLines3:
+
+ case kCvSst_Types:
+ case kCvSst_Public:
+ case kCvSst_SrcLnSeg:
+ case kCvSst_SrcModule:
+ case kCvSst_Libraries:
+ case kCvSst_GlobalTypes:
+ case kCvSst_MPC:
+ case kCvSst_PreComp:
+ case kCvSst_PreCompMap:
+ case kCvSst_OffsetMap16:
+ case kCvSst_OffsetMap32:
+ case kCvSst_FileIndex:
+
+ default:
+ /** @todo implement more. */
+ break;
+
+ /* Skip because we've already processed them: */
+ case kCvSst_SegMap:
+ case kCvSst_SegName:
+ pfnCallback = NULL;
+ break;
+ }
+
+ if (pfnCallback)
+ {
+ void *pvSubSect;
+ rc = rtDbgModCvReadAtAlloc(pThis, pDirEnt->off, &pvSubSect, pDirEnt->cb);
+ if (RT_SUCCESS(rc))
+ {
+ rc = pfnCallback(pThis, pvSubSect, pDirEnt->cb, pDirEnt);
+ RTMemFree(pvSubSect);
+ }
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ *
+ * COFF Debug Info Parsing.
+ * COFF Debug Info Parsing.
+ * COFF Debug Info Parsing.
+ *
+ */
+
+static const char *rtDbgModCvGetCoffStorageClassName(uint8_t bStorageClass)
+{
+ switch (bStorageClass)
+ {
+ case IMAGE_SYM_CLASS_END_OF_FUNCTION: return "END_OF_FUNCTION";
+ case IMAGE_SYM_CLASS_NULL: return "NULL";
+ case IMAGE_SYM_CLASS_AUTOMATIC: return "AUTOMATIC";
+ case IMAGE_SYM_CLASS_EXTERNAL: return "EXTERNAL";
+ case IMAGE_SYM_CLASS_STATIC: return "STATIC";
+ case IMAGE_SYM_CLASS_REGISTER: return "REGISTER";
+ case IMAGE_SYM_CLASS_EXTERNAL_DEF: return "EXTERNAL_DEF";
+ case IMAGE_SYM_CLASS_LABEL: return "LABEL";
+ case IMAGE_SYM_CLASS_UNDEFINED_LABEL: return "UNDEFINED_LABEL";
+ case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT: return "MEMBER_OF_STRUCT";
+ case IMAGE_SYM_CLASS_ARGUMENT: return "ARGUMENT";
+ case IMAGE_SYM_CLASS_STRUCT_TAG: return "STRUCT_TAG";
+ case IMAGE_SYM_CLASS_MEMBER_OF_UNION: return "MEMBER_OF_UNION";
+ case IMAGE_SYM_CLASS_UNION_TAG: return "UNION_TAG";
+ case IMAGE_SYM_CLASS_TYPE_DEFINITION: return "TYPE_DEFINITION";
+ case IMAGE_SYM_CLASS_UNDEFINED_STATIC: return "UNDEFINED_STATIC";
+ case IMAGE_SYM_CLASS_ENUM_TAG: return "ENUM_TAG";
+ case IMAGE_SYM_CLASS_MEMBER_OF_ENUM: return "MEMBER_OF_ENUM";
+ case IMAGE_SYM_CLASS_REGISTER_PARAM: return "REGISTER_PARAM";
+ case IMAGE_SYM_CLASS_BIT_FIELD: return "BIT_FIELD";
+ case IMAGE_SYM_CLASS_FAR_EXTERNAL: return "FAR_EXTERNAL";
+ case IMAGE_SYM_CLASS_BLOCK: return "BLOCK";
+ case IMAGE_SYM_CLASS_FUNCTION: return "FUNCTION";
+ case IMAGE_SYM_CLASS_END_OF_STRUCT: return "END_OF_STRUCT";
+ case IMAGE_SYM_CLASS_FILE: return "FILE";
+ case IMAGE_SYM_CLASS_SECTION: return "SECTION";
+ case IMAGE_SYM_CLASS_WEAK_EXTERNAL: return "WEAK_EXTERNAL";
+ case IMAGE_SYM_CLASS_CLR_TOKEN: return "CLR_TOKEN";
+ }
+
+ static char s_szName[32];
+ RTStrPrintf(s_szName, sizeof(s_szName), "Unknown%#04x", bStorageClass);
+ return s_szName;
+}
+
+
+/**
+ * Adds a chunk of COFF line numbers.
+ *
+ * @param pThis The COFF/CodeView reader instance.
+ * @param pszFile The source file name.
+ * @param iSection The section number.
+ * @param paLines Pointer to the first line number table entry.
+ * @param cLines The number of line number table entries to add.
+ */
+static void rtDbgModCvAddCoffLineNumbers(PRTDBGMODCV pThis, const char *pszFile, uint32_t iSection,
+ PCIMAGE_LINENUMBER paLines, uint32_t cLines)
+{
+ Log4(("Adding %u line numbers in section #%u for %s\n", cLines, iSection, pszFile));
+ PCIMAGE_LINENUMBER pCur = paLines;
+ while (cLines-- > 0)
+ {
+ if (pCur->Linenumber)
+ {
+ int rc = RTDbgModLineAdd(pThis->hCnt, pszFile, pCur->Linenumber, RTDBGSEGIDX_RVA, pCur->Type.VirtualAddress, NULL);
+ Log4((" %#010x: %u [%Rrc]\n", pCur->Type.VirtualAddress, pCur->Linenumber, rc));
+ }
+ pCur++;
+ }
+}
+
+
+/**
+ * Adds a COFF symbol.
+ *
+ * @returns IPRT status (ignored)
+ * @param pThis The COFF/CodeView reader instance.
+ * @param idxSeg IPRT RVA or ABS segment index indicator.
+ * @param uValue The symbol value.
+ * @param pszName The symbol name.
+ */
+static int rtDbgModCvAddCoffSymbol(PRTDBGMODCV pThis, uint32_t idxSeg, uint32_t uValue, const char *pszName)
+{
+ int rc = RTDbgModSymbolAdd(pThis->hCnt, pszName, idxSeg, uValue, 0, 0 /*fFlags*/, NULL);
+ Log(("Symbol: %s:%08x %s [%Rrc]\n", idxSeg == RTDBGSEGIDX_RVA ? "rva" : "abs", uValue, pszName, rc));
+ if (rc == VERR_DBG_ADDRESS_CONFLICT || rc == VERR_DBG_DUPLICATE_SYMBOL)
+ rc = VINF_SUCCESS;
+ return rc;
+}
+
+
+/**
+ * Processes the COFF symbol table.
+ *
+ * @returns IPRT status code
+ * @param pThis The COFF/CodeView reader instance.
+ * @param paSymbols Pointer to the symbol table.
+ * @param cSymbols The number of entries in the symbol table.
+ * @param paLines Pointer to the line number table.
+ * @param cLines The number of entires in the line number table.
+ * @param pszzStrTab Pointer to the string table.
+ * @param cbStrTab Size of the string table.
+ */
+static int rtDbgModCvProcessCoffSymbolTable(PRTDBGMODCV pThis,
+ PCIMAGE_SYMBOL paSymbols, uint32_t cSymbols,
+ PCIMAGE_LINENUMBER paLines, uint32_t cLines,
+ const char *pszzStrTab, uint32_t cbStrTab)
+{
+ Log3(("Processing COFF symbol table with %#x symbols\n", cSymbols));
+
+ /*
+ * Making some bold assumption that the line numbers for the section in
+ * the file are allocated sequentially, we do multiple passes until we've
+ * gathered them all.
+ */
+ int rc = VINF_SUCCESS;
+ uint32_t cSections = 1;
+ uint32_t iLineSect = 1;
+ uint32_t iLine = 0;
+ do
+ {
+ /*
+ * Process the symbols.
+ */
+ char szShort[9];
+ char szFile[RTPATH_MAX];
+ uint32_t iSymbol = 0;
+ szFile[0] = '\0';
+ szShort[8] = '\0'; /* avoid having to terminate it all the time. */
+
+ while (iSymbol < cSymbols && RT_SUCCESS(rc))
+ {
+ /* Copy the symbol in and hope it works around the misalignment
+ issues everywhere. */
+ IMAGE_SYMBOL Sym;
+ memcpy(&Sym, &paSymbols[iSymbol], sizeof(Sym));
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(Sym.NumberOfAuxSymbols < cSymbols);
+
+ /* Calc a zero terminated symbol name. */
+ const char *pszName;
+ if (Sym.N.Name.Short)
+ pszName = (const char *)memcpy(szShort, &Sym.N, 8);
+ else
+ {
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(Sym.N.Name.Long < cbStrTab);
+ pszName = pszzStrTab + Sym.N.Name.Long;
+ }
+
+ /* Only log stuff and count sections the in the first pass.*/
+ if (iLineSect == 1)
+ {
+ Log3(("%04x: s=%#06x v=%#010x t=%#06x a=%#04x c=%#04x (%s) name='%s'\n",
+ iSymbol, Sym.SectionNumber, Sym.Value, Sym.Type, Sym.NumberOfAuxSymbols,
+ Sym.StorageClass, rtDbgModCvGetCoffStorageClassName(Sym.StorageClass), pszName));
+ if ((int16_t)cSections <= Sym.SectionNumber && Sym.SectionNumber > 0)
+ cSections = Sym.SectionNumber + 1;
+ }
+
+ /*
+ * Use storage class to pick what we need (which isn't much because,
+ * MS only provides a very restricted set of symbols).
+ */
+ IMAGE_AUX_SYMBOL Aux;
+ switch (Sym.StorageClass)
+ {
+ case IMAGE_SYM_CLASS_NULL:
+ /* a NOP */
+ break;
+
+ case IMAGE_SYM_CLASS_FILE:
+ {
+ /* Change the current file name (for line numbers). Pretend
+ ANSI and ISO-8859-1 are similar enough for out purposes... */
+ RTDBGMODCV_CHECK_NOMSG_RET_BF(Sym.NumberOfAuxSymbols > 0);
+ const char *pszFile = (const char *)&paSymbols[iSymbol + 1];
+ char *pszDst = szFile;
+ rc = RTLatin1ToUtf8Ex(pszFile, Sym.NumberOfAuxSymbols * sizeof(IMAGE_SYMBOL), &pszDst, sizeof(szFile), NULL);
+ if (RT_FAILURE(rc))
+ Log(("Error converting COFF filename: %Rrc\n", rc));
+ else if (iLineSect == 1)
+ Log3((" filename='%s'\n", szFile));
+ break;
+ }
+
+ case IMAGE_SYM_CLASS_STATIC:
+ if ( Sym.NumberOfAuxSymbols == 1
+ && ( iLineSect == 1
+ || Sym.SectionNumber == (int32_t)iLineSect) )
+ {
+ memcpy(&Aux, &paSymbols[iSymbol + 1], sizeof(Aux));
+ if (iLineSect == 1)
+ Log3((" section: cb=%#010x #relocs=%#06x #lines=%#06x csum=%#x num=%#x sel=%x rvd=%u\n",
+ Aux.Section.Length, Aux.Section.NumberOfRelocations,
+ Aux.Section.NumberOfLinenumbers,
+ Aux.Section.CheckSum,
+ RT_MAKE_U32(Aux.Section.Number, Aux.Section.HighNumber),
+ Aux.Section.Selection,
+ Aux.Section.bReserved));
+ if ( Sym.SectionNumber == (int32_t)iLineSect
+ && Aux.Section.NumberOfLinenumbers > 0)
+ {
+ uint32_t cLinesToAdd = RT_MIN(Aux.Section.NumberOfLinenumbers, cLines - iLine);
+ if (iLine < cLines && szFile[0])
+ rtDbgModCvAddCoffLineNumbers(pThis, szFile, iLineSect, &paLines[iLine], cLinesToAdd);
+ iLine += cLinesToAdd;
+ }
+ }
+ /* Not so sure about the quality here, but might be useful. */
+ else if ( iLineSect == 1
+ && Sym.NumberOfAuxSymbols == 0
+ && Sym.SectionNumber != IMAGE_SYM_UNDEFINED
+ && Sym.SectionNumber != IMAGE_SYM_ABSOLUTE
+ && Sym.SectionNumber != IMAGE_SYM_DEBUG
+ && Sym.Value > 0
+ && *pszName)
+ rtDbgModCvAddCoffSymbol(pThis, RTDBGSEGIDX_RVA, Sym.Value, pszName);
+ break;
+
+ case IMAGE_SYM_CLASS_EXTERNAL:
+ /* Add functions (first pass only). */
+ if ( iLineSect == 1
+ && (ISFCN(Sym.Type) || Sym.Type == 0)
+ && Sym.NumberOfAuxSymbols == 0
+ && *pszName )
+ {
+ if (Sym.SectionNumber == IMAGE_SYM_ABSOLUTE)
+ rtDbgModCvAddCoffSymbol(pThis, RTDBGSEGIDX_ABS, Sym.Value, pszName);
+ else if ( Sym.SectionNumber != IMAGE_SYM_UNDEFINED
+ && Sym.SectionNumber != IMAGE_SYM_DEBUG)
+ rtDbgModCvAddCoffSymbol(pThis, RTDBGSEGIDX_RVA, Sym.Value, pszName);
+ }
+ break;
+
+ case IMAGE_SYM_CLASS_FUNCTION:
+ /* Not sure this is really used. */
+ break;
+
+ case IMAGE_SYM_CLASS_END_OF_FUNCTION:
+ case IMAGE_SYM_CLASS_AUTOMATIC:
+ case IMAGE_SYM_CLASS_REGISTER:
+ case IMAGE_SYM_CLASS_EXTERNAL_DEF:
+ case IMAGE_SYM_CLASS_LABEL:
+ case IMAGE_SYM_CLASS_UNDEFINED_LABEL:
+ case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:
+ case IMAGE_SYM_CLASS_ARGUMENT:
+ case IMAGE_SYM_CLASS_STRUCT_TAG:
+ case IMAGE_SYM_CLASS_MEMBER_OF_UNION:
+ case IMAGE_SYM_CLASS_UNION_TAG:
+ case IMAGE_SYM_CLASS_TYPE_DEFINITION:
+ case IMAGE_SYM_CLASS_UNDEFINED_STATIC:
+ case IMAGE_SYM_CLASS_ENUM_TAG:
+ case IMAGE_SYM_CLASS_MEMBER_OF_ENUM:
+ case IMAGE_SYM_CLASS_REGISTER_PARAM:
+ case IMAGE_SYM_CLASS_BIT_FIELD:
+ case IMAGE_SYM_CLASS_FAR_EXTERNAL:
+ case IMAGE_SYM_CLASS_BLOCK:
+ case IMAGE_SYM_CLASS_END_OF_STRUCT:
+ case IMAGE_SYM_CLASS_SECTION:
+ case IMAGE_SYM_CLASS_WEAK_EXTERNAL:
+ case IMAGE_SYM_CLASS_CLR_TOKEN:
+ /* Not used by MS, I think. */
+ break;
+
+ default:
+ Log(("RTDbgCv: Unexpected COFF storage class %#x (%u)\n", Sym.StorageClass, Sym.StorageClass));
+ break;
+ }
+
+ /* next symbol */
+ iSymbol += 1 + Sym.NumberOfAuxSymbols;
+ }
+
+ /* Next section with line numbers. */
+ iLineSect++;
+ } while (iLine < cLines && iLineSect < cSections && RT_SUCCESS(rc));
+
+ return rc;
+}
+
+
+/**
+ * Loads COFF debug information into the container.
+ *
+ * @returns IPRT status code.
+ * @param pThis The COFF/CodeView debug reader instance.
+ */
+static int rtDbgModCvLoadCoffInfo(PRTDBGMODCV pThis)
+{
+ /*
+ * Read the whole section into memory.
+ * Note! Cannot use rtDbgModCvReadAt or rtDbgModCvReadAtAlloc here.
+ */
+ int rc;
+ uint8_t *pbDbgSect = (uint8_t *)RTMemAlloc(pThis->cbCoffDbgInfo);
+ if (pbDbgSect)
+ {
+ if (pThis->hFile == NIL_RTFILE)
+ rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, pThis->offCoffDbgInfo, pbDbgSect, pThis->cbCoffDbgInfo);
+ else
+ rc = RTFileReadAt(pThis->hFile, pThis->offCoffDbgInfo, pbDbgSect, pThis->cbCoffDbgInfo, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /* The string table follows after the symbol table. */
+ const char *pszzStrTab = (const char *)( pbDbgSect
+ + pThis->CoffHdr.LvaToFirstSymbol
+ + pThis->CoffHdr.NumberOfSymbols * sizeof(IMAGE_SYMBOL));
+ uint32_t cbStrTab = (uint32_t)((uintptr_t)(pbDbgSect + pThis->cbCoffDbgInfo) - (uintptr_t)pszzStrTab);
+ /** @todo The symbol table starts with a size. Read it and checking. Also verify
+ * that the symtab ends with a terminator character. */
+
+ rc = rtDbgModCvProcessCoffSymbolTable(pThis,
+ (PCIMAGE_SYMBOL)(pbDbgSect + pThis->CoffHdr.LvaToFirstSymbol),
+ pThis->CoffHdr.NumberOfSymbols,
+ (PCIMAGE_LINENUMBER)(pbDbgSect + pThis->CoffHdr.LvaToFirstLinenumber),
+ pThis->CoffHdr.NumberOfLinenumbers,
+ pszzStrTab, cbStrTab);
+ }
+ RTMemFree(pbDbgSect);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ return rc;
+}
+
+
+
+
+
+
+/*
+ *
+ * CodeView Debug module implementation.
+ * CodeView Debug module implementation.
+ * CodeView Debug module implementation.
+ *
+ */
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
+static DECLCALLBACK(int) rtDbgModCv_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
+ PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ return RTDbgModLineByAddr(pThis->hCnt, iSeg, off, poffDisp, pLineInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
+static DECLCALLBACK(int) rtDbgModCv_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ return RTDbgModLineByOrdinal(pThis->hCnt, iOrdinal, pLineInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
+static DECLCALLBACK(uint32_t) rtDbgModCv_LineCount(PRTDBGMODINT pMod)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ return RTDbgModLineCount(pThis->hCnt);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
+static DECLCALLBACK(int) rtDbgModCv_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
+ uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ Assert(!pszFile[cchFile]); NOREF(cchFile);
+ return RTDbgModLineAdd(pThis->hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
+static DECLCALLBACK(int) rtDbgModCv_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
+ PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ return RTDbgModSymbolByAddr(pThis->hCnt, iSeg, off, fFlags, poffDisp, pSymInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
+static DECLCALLBACK(int) rtDbgModCv_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
+ PRTDBGSYMBOL pSymInfo)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ Assert(!pszSymbol[cchSymbol]);
+ return RTDbgModSymbolByName(pThis->hCnt, pszSymbol/*, cchSymbol*/, pSymInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
+static DECLCALLBACK(int) rtDbgModCv_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ return RTDbgModSymbolByOrdinal(pThis->hCnt, iOrdinal, pSymInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
+static DECLCALLBACK(uint32_t) rtDbgModCv_SymbolCount(PRTDBGMODINT pMod)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ return RTDbgModSymbolCount(pThis->hCnt);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
+static DECLCALLBACK(int) rtDbgModCv_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
+ RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
+ uint32_t *piOrdinal)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
+ return RTDbgModSymbolAdd(pThis->hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
+static DECLCALLBACK(int) rtDbgModCv_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ return RTDbgModSegmentByIndex(pThis->hCnt, iSeg, pSegInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
+static DECLCALLBACK(RTDBGSEGIDX) rtDbgModCv_SegmentCount(PRTDBGMODINT pMod)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ return RTDbgModSegmentCount(pThis->hCnt);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
+static DECLCALLBACK(int) rtDbgModCv_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
+ uint32_t fFlags, PRTDBGSEGIDX piSeg)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ Assert(!pszName[cchName]); NOREF(cchName);
+ return RTDbgModSegmentAdd(pThis->hCnt, uRva, cb, pszName, fFlags, piSeg);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
+static DECLCALLBACK(RTUINTPTR) rtDbgModCv_ImageSize(PRTDBGMODINT pMod)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ if (pThis->cbImage)
+ return pThis->cbImage;
+ return RTDbgModImageSize(pThis->hCnt);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
+static DECLCALLBACK(RTDBGSEGIDX) rtDbgModCv_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ return RTDbgModRvaToSegOff(pThis->hCnt, uRva, poffSeg);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
+static DECLCALLBACK(int) rtDbgModCv_Close(PRTDBGMODINT pMod)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+
+ RTDbgModRelease(pThis->hCnt);
+ if (pThis->hFile != NIL_RTFILE)
+ RTFileClose(pThis->hFile);
+ RTMemFree(pThis->paDirEnts);
+ RTMemFree(pThis);
+
+ pMod->pvDbgPriv = NULL; /* for internal use */
+ return VINF_SUCCESS;
+}
+
+
+/*
+ *
+ * Probing code used by rtDbgModCv_TryOpen.
+ * Probing code used by rtDbgModCv_TryOpen.
+ *
+ */
+
+
+
+/** @callback_method_impl{FNRTLDRENUMSEGS,
+ * Used to add segments from the image.} */
+static DECLCALLBACK(int) rtDbgModCvAddSegmentsCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
+{
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pvUser;
+ Log(("Segment %s: LinkAddress=%#llx RVA=%#llx cb=%#llx\n",
+ pSeg->pszName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
+ NOREF(hLdrMod);
+
+ /* If the segment doesn't have a mapping, just add a dummy so the indexing
+ works out correctly (same as for the image). */
+ if (pSeg->RVA == NIL_RTLDRADDR)
+ return RTDbgModSegmentAdd(pThis->hCnt, 0, 0, pSeg->pszName, 0 /*fFlags*/, NULL);
+
+ RTLDRADDR cb = RT_MAX(pSeg->cb, pSeg->cbMapped);
+ return RTDbgModSegmentAdd(pThis->hCnt, pSeg->RVA, cb, pSeg->pszName, 0 /*fFlags*/, NULL);
+}
+
+
+/**
+ * Copies the sections over from the DBG file.
+ *
+ * Called if we don't have an associated executable image.
+ *
+ * @returns IPRT status code.
+ * @param pThis The CV module instance.
+ * @param pDbgHdr The DBG file header.
+ * @param pszFilename The filename (for logging).
+ */
+static int rtDbgModCvAddSegmentsFromDbg(PRTDBGMODCV pThis, PCIMAGE_SEPARATE_DEBUG_HEADER pDbgHdr, const char *pszFilename)
+{
+ /*
+ * Validate the header fields a little.
+ */
+ if ( pDbgHdr->NumberOfSections < 1
+ || pDbgHdr->NumberOfSections > 4096)
+ {
+ Log(("RTDbgModCv: Bad NumberOfSections: %d\n", pDbgHdr->NumberOfSections));
+ return VERR_CV_BAD_FORMAT;
+ }
+ if (!RT_IS_POWER_OF_TWO(pDbgHdr->SectionAlignment))
+ {
+ Log(("RTDbgModCv: Bad SectionAlignment: %#x\n", pDbgHdr->SectionAlignment));
+ return VERR_CV_BAD_FORMAT;
+ }
+
+ /*
+ * Read the section table.
+ */
+ size_t cbShs = pDbgHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
+ PIMAGE_SECTION_HEADER paShs = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbShs);
+ if (!paShs)
+ return VERR_NO_MEMORY;
+ int rc = RTFileReadAt(pThis->hFile, sizeof(*pDbgHdr), paShs, cbShs, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Do some basic validation.
+ */
+ uint32_t cbHeaders = 0;
+ uint32_t uRvaPrev = 0;
+ for (uint32_t i = 0; i < pDbgHdr->NumberOfSections; i++)
+ {
+ Log3(("RTDbgModCv: Section #%02u %#010x LB %#010x %.*s\n",
+ i, paShs[i].VirtualAddress, paShs[i].Misc.VirtualSize, sizeof(paShs[i].Name), paShs[i].Name));
+
+ if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
+ continue;
+
+ if (paShs[i].VirtualAddress < uRvaPrev)
+ {
+ Log(("RTDbgModCv: %s: Overlap or soring error, VirtualAddress=%#x uRvaPrev=%#x - section #%d '%.*s'!!!\n",
+ pszFilename, paShs[i].VirtualAddress, uRvaPrev, i, sizeof(paShs[i].Name), paShs[i].Name));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ else if ( paShs[i].VirtualAddress > pDbgHdr->SizeOfImage
+ || paShs[i].Misc.VirtualSize > pDbgHdr->SizeOfImage
+ || paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize > pDbgHdr->SizeOfImage)
+ {
+ Log(("RTDbgModCv: %s: VirtualAddress=%#x VirtualSize=%#x (total %x) - beyond image size (%#x) - section #%d '%.*s'!!!\n",
+ pszFilename, paShs[i].VirtualAddress, paShs[i].Misc.VirtualSize,
+ paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize,
+ pThis->cbImage, i, sizeof(paShs[i].Name), paShs[i].Name));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ else if (paShs[i].VirtualAddress & (pDbgHdr->SectionAlignment - 1))
+ {
+ Log(("RTDbgModCv: %s: VirtualAddress=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
+ pszFilename, paShs[i].VirtualAddress, pDbgHdr->SectionAlignment, i, sizeof(paShs[i].Name), paShs[i].Name));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ else
+ {
+ if (uRvaPrev == 0)
+ cbHeaders = paShs[i].VirtualAddress;
+ uRvaPrev = paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize;
+ continue;
+ }
+ }
+ if (RT_SUCCESS(rc) && uRvaPrev == 0)
+ {
+ Log(("RTDbgModCv: %s: No loadable sections.\n", pszFilename));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if (RT_SUCCESS(rc) && cbHeaders == 0)
+ {
+ Log(("RTDbgModCv: %s: No space for PE headers.\n", pszFilename));
+ rc = VERR_CV_BAD_FORMAT;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Add sections.
+ */
+ rc = RTDbgModSegmentAdd(pThis->hCnt, 0, cbHeaders, "NtHdrs", 0 /*fFlags*/, NULL);
+ for (uint32_t i = 0; RT_SUCCESS(rc) && i < pDbgHdr->NumberOfSections; i++)
+ {
+ char szName[sizeof(paShs[i].Name) + 1];
+ memcpy(szName, paShs[i].Name, sizeof(paShs[i].Name));
+ szName[sizeof(szName) - 1] = '\0';
+
+ if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
+ rc = RTDbgModSegmentAdd(pThis->hCnt, 0, 0, szName, 0 /*fFlags*/, NULL);
+ else
+ rc = RTDbgModSegmentAdd(pThis->hCnt, paShs[i].VirtualAddress, paShs[i].Misc.VirtualSize, szName,
+ 0 /*fFlags*/, NULL);
+ }
+ if (RT_SUCCESS(rc))
+ pThis->fHaveLoadedSegments = true;
+ }
+ }
+
+ RTMemFree(paShs);
+ return rc;
+}
+
+
+/**
+ * Instantiates the CV/COFF reader.
+ *
+ * @returns IPRT status code
+ * @param pDbgMod The debug module instance.
+ * @param enmFileType The type of input file.
+ * @param hFile The file handle, NIL_RTFILE of image.
+ * @param ppThis Where to return the reader instance.
+ */
+static int rtDbgModCvCreateInstance(PRTDBGMODINT pDbgMod, RTCVFILETYPE enmFileType, RTFILE hFile, PRTDBGMODCV *ppThis)
+{
+ /*
+ * Do we already have an instance? Happens if we find multiple debug
+ * formats we support.
+ */
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pDbgMod->pvDbgPriv;
+ if (pThis)
+ {
+ Assert(pThis->enmType == enmFileType);
+ Assert(pThis->hFile == hFile);
+ Assert(pThis->pMod == pDbgMod);
+ *ppThis = pThis;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Create a new instance.
+ */
+ pThis = (PRTDBGMODCV)RTMemAllocZ(sizeof(RTDBGMODCV));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+ int rc = RTDbgModCreate(&pThis->hCnt, pDbgMod->pszName, 0 /*cbSeg*/, 0 /*fFlags*/);
+ if (RT_SUCCESS(rc))
+ {
+ pDbgMod->pvDbgPriv = pThis;
+ pThis->enmType = enmFileType;
+ pThis->hFile = hFile;
+ pThis->pMod = pDbgMod;
+ pThis->offBase = UINT32_MAX;
+ pThis->offCoffDbgInfo = UINT32_MAX;
+ *ppThis = pThis;
+ return VINF_SUCCESS;
+ }
+ RTMemFree(pThis);
+ return rc;
+}
+
+
+/**
+ * Common part of the COFF probing.
+ *
+ * @returns status code.
+ * @param pDbgMod The debug module instance. On success pvDbgPriv
+ * will point to a valid RTDBGMODCV.
+ * @param hFile The file with debug info in it.
+ * @param off The offset where to expect CV debug info.
+ * @param cb The number of bytes of debug info.
+ * @param enmArch The desired image architecture.
+ * @param pszFilename The path to the file (for logging).
+ */
+static int rtDbgModCvProbeCoff(PRTDBGMODINT pDbgMod, RTCVFILETYPE enmFileType, RTFILE hFile,
+ uint32_t off, uint32_t cb, const char *pszFilename)
+{
+ /*
+ * Check that there is sufficient data for a header, then read it.
+ */
+ if (cb < sizeof(IMAGE_COFF_SYMBOLS_HEADER))
+ {
+ Log(("RTDbgModCv: Not enough room for COFF header.\n"));
+ return VERR_BAD_EXE_FORMAT;
+ }
+ if (cb >= UINT32_C(128) * _1M)
+ {
+ Log(("RTDbgModCv: COFF debug information is to large (%'u bytes), max is 128MB\n", cb));
+ return VERR_BAD_EXE_FORMAT;
+ }
+
+ int rc;
+ IMAGE_COFF_SYMBOLS_HEADER Hdr;
+ if (hFile == NIL_RTFILE)
+ rc = pDbgMod->pImgVt->pfnReadAt(pDbgMod, UINT32_MAX, off, &Hdr, sizeof(Hdr));
+ else
+ rc = RTFileReadAt(hFile, off, &Hdr, sizeof(Hdr), NULL);
+ if (RT_FAILURE(rc))
+ {
+ Log(("RTDbgModCv: Error reading COFF header: %Rrc\n", rc));
+ return rc;
+ }
+
+ Log2(("RTDbgModCv: Found COFF debug info header at %#x (LB %#x) in %s\n", off, cb, pszFilename));
+ Log2((" NumberOfSymbols = %#010x\n", Hdr.NumberOfSymbols));
+ Log2((" LvaToFirstSymbol = %#010x\n", Hdr.LvaToFirstSymbol));
+ Log2((" NumberOfLinenumbers = %#010x\n", Hdr.NumberOfLinenumbers));
+ Log2((" LvaToFirstLinenumber = %#010x\n", Hdr.LvaToFirstLinenumber));
+ Log2((" RvaToFirstByteOfCode = %#010x\n", Hdr.RvaToFirstByteOfCode));
+ Log2((" RvaToLastByteOfCode = %#010x\n", Hdr.RvaToLastByteOfCode));
+ Log2((" RvaToFirstByteOfData = %#010x\n", Hdr.RvaToFirstByteOfData));
+ Log2((" RvaToLastByteOfData = %#010x\n", Hdr.RvaToLastByteOfData));
+
+ /*
+ * Validate the COFF header.
+ */
+ if ( (uint64_t)Hdr.LvaToFirstSymbol + (uint64_t)Hdr.NumberOfSymbols * sizeof(IMAGE_SYMBOL) > cb
+ || (Hdr.LvaToFirstSymbol < sizeof(Hdr) && Hdr.NumberOfSymbols > 0))
+ {
+ Log(("RTDbgModCv: Bad COFF symbol count or/and offset: LvaToFirstSymbol=%#x, NumberOfSymbols=%#x cbCoff=%#x\n",
+ Hdr.LvaToFirstSymbol, Hdr.NumberOfSymbols, cb));
+ return VERR_BAD_EXE_FORMAT;
+ }
+ if ( (uint64_t)Hdr.LvaToFirstLinenumber + (uint64_t)Hdr.NumberOfLinenumbers * sizeof(IMAGE_LINENUMBER) > cb
+ || (Hdr.LvaToFirstLinenumber < sizeof(Hdr) && Hdr.NumberOfLinenumbers > 0))
+ {
+ Log(("RTDbgModCv: Bad COFF symbol count or/and offset: LvaToFirstSymbol=%#x, NumberOfSymbols=%#x cbCoff=%#x\n",
+ Hdr.LvaToFirstSymbol, Hdr.NumberOfSymbols, cb));
+ return VERR_BAD_EXE_FORMAT;
+ }
+ if (Hdr.NumberOfSymbols < 2)
+ {
+ Log(("RTDbgModCv: The COFF symbol table is too short to be of any worth... (%u syms)\n", Hdr.NumberOfSymbols));
+ return VERR_NO_DATA;
+ }
+
+ /*
+ * What we care about looks fine, use it.
+ */
+ PRTDBGMODCV pThis;
+ rc = rtDbgModCvCreateInstance(pDbgMod, enmFileType, hFile, &pThis);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->offCoffDbgInfo = off;
+ pThis->cbCoffDbgInfo = cb;
+ pThis->CoffHdr = Hdr;
+ }
+
+ return rc;
+}
+
+
+/**
+ * Common part of the CodeView probing.
+ *
+ * @returns status code.
+ * @param pDbgMod The debug module instance. On success pvDbgPriv
+ * will point to a valid RTDBGMODCV.
+ * @param pCvHdr The CodeView base header.
+ * @param enmFileType The kind of file this is we're probing.
+ * @param hFile The file with debug info in it.
+ * @param off The offset where to expect CV debug info.
+ * @param cb The number of bytes of debug info.
+ * @param pszFilename The path to the file (for logging).
+ */
+static int rtDbgModCvProbeCommon(PRTDBGMODINT pDbgMod, PRTCVHDR pCvHdr, RTCVFILETYPE enmFileType, RTFILE hFile,
+ uint32_t off, uint32_t cb, RTLDRARCH enmArch, const char *pszFilename)
+{
+ int rc = VERR_DBG_NO_MATCHING_INTERPRETER;
+
+ /* Is a codeview format we (wish to) support? */
+ if ( pCvHdr->u32Magic == RTCVHDR_MAGIC_NB11
+ || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB09
+ || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB08
+ || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB05
+ || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB04
+ || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB02
+ || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB00
+ )
+ {
+ /* We're assuming it's a base header, so the offset must be within
+ the area defined by the debug info we got from the loader. */
+ if (pCvHdr->off < cb && pCvHdr->off >= sizeof(*pCvHdr))
+ {
+ Log(("RTDbgModCv: Found %c%c%c%c at %#RTfoff - size %#x, directory at %#x. file type %d\n",
+ RT_BYTE1(pCvHdr->u32Magic), RT_BYTE2(pCvHdr->u32Magic), RT_BYTE3(pCvHdr->u32Magic), RT_BYTE4(pCvHdr->u32Magic),
+ off, cb, pCvHdr->off, enmFileType));
+
+ /*
+ * Create a module instance, if not already done.
+ */
+ PRTDBGMODCV pThis;
+ rc = rtDbgModCvCreateInstance(pDbgMod, enmFileType, hFile, &pThis);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->u32CvMagic = pCvHdr->u32Magic;
+ pThis->offBase = off;
+ pThis->cbDbgInfo = cb;
+ pThis->offDir = pCvHdr->off;
+ return VINF_SUCCESS;
+ }
+ }
+ }
+
+ return rc;
+}
+
+
+/** @callback_method_impl{FNRTLDRENUMDBG} */
+static DECLCALLBACK(int) rtDbgModCvEnumCallback(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)
+{
+ PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser;
+ Assert(!pDbgMod->pvDbgPriv);
+
+ /* Skip external files, RTDbgMod will deal with those
+ via RTDBGMODINT::pszDbgFile. */
+ if (pDbgInfo->pszExtFile)
+ return VINF_SUCCESS;
+
+ /* We only handle the codeview sections. */
+ if (pDbgInfo->enmType == RTLDRDBGINFOTYPE_CODEVIEW)
+ {
+ /* Read the specified header and check if we like it. */
+ RTCVHDR CvHdr;
+ int rc = pDbgMod->pImgVt->pfnReadAt(pDbgMod, pDbgInfo->iDbgInfo, pDbgInfo->offFile, &CvHdr, sizeof(CvHdr));
+ if (RT_SUCCESS(rc))
+ rc = rtDbgModCvProbeCommon(pDbgMod, &CvHdr, RTCVFILETYPE_IMAGE, NIL_RTFILE, pDbgInfo->offFile, pDbgInfo->cb,
+ pDbgMod->pImgVt->pfnGetArch(pDbgMod), pDbgMod->pszImgFile);
+ }
+ else if (pDbgInfo->enmType == RTLDRDBGINFOTYPE_COFF)
+ {
+ /* Join paths with the DBG code. */
+ rtDbgModCvProbeCoff(pDbgMod, RTCVFILETYPE_IMAGE, NIL_RTFILE, pDbgInfo->offFile, pDbgInfo->cb, pDbgMod->pszImgFile);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Part two of the external file probing.
+ *
+ * @returns status code.
+ * @param pDbgMod The debug module instance. On success pvDbgPriv
+ * will point to a valid RTDBGMODCV.
+ * @param enmFileType The kind of file this is we're probing.
+ * @param hFile The file with debug info in it.
+ * @param off The offset where to expect CV debug info.
+ * @param cb The number of bytes of debug info.
+ * @param enmArch The desired image architecture.
+ * @param pszFilename The path to the file (for logging).
+ */
+static int rtDbgModCvProbeFile2(PRTDBGMODINT pThis, RTCVFILETYPE enmFileType, RTFILE hFile, uint32_t off, uint32_t cb,
+ RTLDRARCH enmArch, const char *pszFilename)
+{
+ RTCVHDR CvHdr;
+ int rc = RTFileReadAt(hFile, off, &CvHdr, sizeof(CvHdr), NULL);
+ if (RT_SUCCESS(rc))
+ rc = rtDbgModCvProbeCommon(pThis, &CvHdr, enmFileType, hFile, off, cb, enmArch, pszFilename);
+ return rc;
+}
+
+
+/**
+ * Probes an external file for CodeView information.
+ *
+ * @returns status code.
+ * @param pDbgMod The debug module instance. On success pvDbgPriv
+ * will point to a valid RTDBGMODCV.
+ * @param pszFilename The path to the file to probe.
+ * @param enmArch The desired image architecture.
+ */
+static int rtDbgModCvProbeFile(PRTDBGMODINT pDbgMod, const char *pszFilename, RTLDRARCH enmArch)
+{
+ RTFILE hFile;
+ int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Check for .DBG file
+ */
+ IMAGE_SEPARATE_DEBUG_HEADER DbgHdr;
+ rc = RTFileReadAt(hFile, 0, &DbgHdr, sizeof(DbgHdr), NULL);
+ if ( RT_SUCCESS(rc)
+ && DbgHdr.Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
+ {
+ Log2(("RTDbgModCv: Found separate debug header in %s:\n", pszFilename));
+ Log2((" Flags = %#x\n", DbgHdr.Flags));
+ Log2((" Machine = %#x\n", DbgHdr.Machine));
+ Log2((" Characteristics = %#x\n", DbgHdr.Characteristics));
+ Log2((" TimeDateStamp = %#x\n", DbgHdr.TimeDateStamp));
+ Log2((" CheckSum = %#x\n", DbgHdr.CheckSum));
+ Log2((" ImageBase = %#x\n", DbgHdr.ImageBase));
+ Log2((" SizeOfImage = %#x\n", DbgHdr.SizeOfImage));
+ Log2((" NumberOfSections = %#x\n", DbgHdr.NumberOfSections));
+ Log2((" ExportedNamesSize = %#x\n", DbgHdr.ExportedNamesSize));
+ Log2((" DebugDirectorySize = %#x\n", DbgHdr.DebugDirectorySize));
+ Log2((" SectionAlignment = %#x\n", DbgHdr.SectionAlignment));
+
+ /*
+ * Match up the architecture if specified.
+ */
+ switch (enmArch)
+ {
+ case RTLDRARCH_X86_32:
+ if (DbgHdr.Machine != IMAGE_FILE_MACHINE_I386)
+ rc = VERR_LDR_ARCH_MISMATCH;
+ break;
+ case RTLDRARCH_AMD64:
+ if (DbgHdr.Machine != IMAGE_FILE_MACHINE_AMD64)
+ rc = VERR_LDR_ARCH_MISMATCH;
+ break;
+
+ default:
+ case RTLDRARCH_HOST:
+ AssertFailed();
+ case RTLDRARCH_WHATEVER:
+ break;
+ }
+ if (RT_FAILURE(rc))
+ {
+ RTFileClose(hFile);
+ return rc;
+ }
+
+ /*
+ * Probe for readable debug info in the debug directory.
+ */
+ uint32_t offDbgDir = sizeof(DbgHdr)
+ + DbgHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
+ + DbgHdr.ExportedNamesSize;
+
+ uint32_t cEntries = DbgHdr.DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
+ for (uint32_t i = 0; i < cEntries; i++, offDbgDir += sizeof(IMAGE_DEBUG_DIRECTORY))
+ {
+ IMAGE_DEBUG_DIRECTORY DbgDir;
+ rc = RTFileReadAt(hFile, offDbgDir, &DbgDir, sizeof(DbgDir), NULL);
+ if (RT_FAILURE(rc))
+ break;
+ if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
+ rc = rtDbgModCvProbeFile2(pDbgMod, RTCVFILETYPE_DBG, hFile,
+ DbgDir.PointerToRawData, DbgDir.SizeOfData,
+ enmArch, pszFilename);
+ else if (DbgDir.Type == IMAGE_DEBUG_TYPE_COFF)
+ rc = rtDbgModCvProbeCoff(pDbgMod, RTCVFILETYPE_DBG, hFile,
+ DbgDir.PointerToRawData, DbgDir.SizeOfData, pszFilename);
+ }
+
+ /*
+ * If we get down here with an instance, it prooves that we've found
+ * something, regardless of any errors. Add the sections and such.
+ */
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pDbgMod->pvDbgPriv;
+ if (pThis)
+ {
+ pThis->cbImage = DbgHdr.SizeOfImage;
+ if (pDbgMod->pImgVt)
+ rc = VINF_SUCCESS;
+ else
+ {
+ rc = rtDbgModCvAddSegmentsFromDbg(pThis, &DbgHdr, pszFilename);
+ if (RT_FAILURE(rc))
+ rtDbgModCv_Close(pDbgMod);
+ }
+ return rc;
+ }
+
+ /* Failed to find CV or smth, look at the end of the file just to be sure... */
+ }
+
+ /*
+ * Look for CV tail header.
+ */
+ uint64_t cbFile;
+ rc = RTFileSeek(hFile, -(RTFOFF)sizeof(RTCVHDR), RTFILE_SEEK_END, &cbFile);
+ if (RT_SUCCESS(rc))
+ {
+ cbFile += sizeof(RTCVHDR);
+ RTCVHDR CvHdr;
+ rc = RTFileRead(hFile, &CvHdr, sizeof(CvHdr), NULL);
+ if (RT_SUCCESS(rc))
+ rc = rtDbgModCvProbeFile2(pDbgMod, RTCVFILETYPE_OTHER_AT_END, hFile,
+ cbFile - CvHdr.off, CvHdr.off, enmArch, pszFilename);
+ }
+
+ if (RT_FAILURE(rc))
+ RTFileClose(hFile);
+ return rc;
+}
+
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
+static DECLCALLBACK(int) rtDbgModCv_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
+{
+ /*
+ * Look for debug info.
+ */
+ int rc = VERR_DBG_NO_MATCHING_INTERPRETER;
+ if (pMod->pszDbgFile)
+ rc = rtDbgModCvProbeFile(pMod, pMod->pszDbgFile, enmArch);
+
+ if (!pMod->pvDbgPriv && pMod->pImgVt)
+ {
+ int rc2 = pMod->pImgVt->pfnEnumDbgInfo(pMod, rtDbgModCvEnumCallback, pMod);
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+
+ if (!pMod->pvDbgPriv)
+ {
+ /* Try the executable in case it has a NBxx tail header. */
+ rc2 = rtDbgModCvProbeFile(pMod, pMod->pszImgFile, enmArch);
+ if (RT_FAILURE(rc2) && (RT_SUCCESS(rc) || VERR_DBG_NO_MATCHING_INTERPRETER))
+ rc = rc2;
+ }
+ }
+
+ PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
+ if (!pThis)
+ return RT_SUCCESS_NP(rc) ? VERR_DBG_NO_MATCHING_INTERPRETER : rc;
+ Assert(pThis->offBase != UINT32_MAX || pThis->offCoffDbgInfo != UINT32_MAX);
+
+ /*
+ * Load the debug info.
+ */
+ if (pMod->pImgVt)
+ {
+ rc = pMod->pImgVt->pfnEnumSegments(pMod, rtDbgModCvAddSegmentsCallback, pThis);
+ pThis->fHaveLoadedSegments = true;
+ }
+ if (RT_SUCCESS(rc) && pThis->offBase != UINT32_MAX)
+ rc = rtDbgModCvLoadCodeViewInfo(pThis);
+ if (RT_SUCCESS(rc) && pThis->offCoffDbgInfo != UINT32_MAX)
+ rc = rtDbgModCvLoadCoffInfo(pThis);
+ if (RT_SUCCESS(rc))
+ {
+ Log(("RTDbgCv: Successfully loaded debug info\n"));
+ return VINF_SUCCESS;
+ }
+
+ Log(("RTDbgCv: Debug info load error %Rrc\n", rc));
+ rtDbgModCv_Close(pMod);
+ return rc;
+}
+
+
+
+
+
+/** Virtual function table for the CodeView debug info reader. */
+DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgCodeView =
+{
+ /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
+ /*.fSupports = */ RT_DBGTYPE_CODEVIEW,
+ /*.pszName = */ "codeview",
+ /*.pfnTryOpen = */ rtDbgModCv_TryOpen,
+ /*.pfnClose = */ rtDbgModCv_Close,
+
+ /*.pfnRvaToSegOff = */ rtDbgModCv_RvaToSegOff,
+ /*.pfnImageSize = */ rtDbgModCv_ImageSize,
+
+ /*.pfnSegmentAdd = */ rtDbgModCv_SegmentAdd,
+ /*.pfnSegmentCount = */ rtDbgModCv_SegmentCount,
+ /*.pfnSegmentByIndex = */ rtDbgModCv_SegmentByIndex,
+
+ /*.pfnSymbolAdd = */ rtDbgModCv_SymbolAdd,
+ /*.pfnSymbolCount = */ rtDbgModCv_SymbolCount,
+ /*.pfnSymbolByOrdinal = */ rtDbgModCv_SymbolByOrdinal,
+ /*.pfnSymbolByName = */ rtDbgModCv_SymbolByName,
+ /*.pfnSymbolByAddr = */ rtDbgModCv_SymbolByAddr,
+
+ /*.pfnLineAdd = */ rtDbgModCv_LineAdd,
+ /*.pfnLineCount = */ rtDbgModCv_LineCount,
+ /*.pfnLineByOrdinal = */ rtDbgModCv_LineByOrdinal,
+ /*.pfnLineByAddr = */ rtDbgModCv_LineByAddr,
+
+ /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
+};
+
diff --git a/src/VBox/Runtime/common/dbg/dbgmodcontainer.cpp b/src/VBox/Runtime/common/dbg/dbgmodcontainer.cpp
index 23325698..1e36e77b 100644
--- a/src/VBox/Runtime/common/dbg/dbgmodcontainer.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgmodcontainer.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -34,6 +34,10 @@
#include <iprt/avl.h>
#include <iprt/err.h>
#include <iprt/mem.h>
+#define RTDBGMODCNT_WITH_MEM_CACHE
+#ifdef RTDBGMODCNT_WITH_MEM_CACHE
+# include <iprt/memcache.h>
+#endif
#include <iprt/string.h>
#include <iprt/strcache.h>
#include "internal/dbgmod.h"
@@ -134,6 +138,12 @@ typedef struct RTDBGMODCTN
uint32_t iNextSymbolOrdinal;
/** The next line number ordinal. */
uint32_t iNextLineOrdinal;
+#ifdef RTDBGMODCNT_WITH_MEM_CACHE
+ /** Line number allocator.
+ * Using a cache is a bit overkill since we normally won't free them, but
+ * it's a construct that exists and does the job relatively efficiently. */
+ RTMEMCACHE hLineNumAllocator;
+#endif
} RTDBGMODCTN;
/** Pointer to instance data for the debug info container. */
typedef RTDBGMODCTN *PRTDBGMODCTN;
@@ -250,7 +260,11 @@ static DECLCALLBACK(int) rtDbgModContainer_LineAdd(PRTDBGMODINT pMod, const char
/*
* Create a new entry.
*/
+#ifdef RTDBGMODCNT_WITH_MEM_CACHE
+ PRTDBGMODCTNLINE pLine = (PRTDBGMODCTNLINE)RTMemCacheAlloc(pThis->hLineNumAllocator);
+#else
PRTDBGMODCTNLINE pLine = (PRTDBGMODCTNLINE)RTMemAllocZ(sizeof(*pLine));
+#endif
if (!pLine)
return VERR_NO_MEMORY;
pLine->AddrCore.Key = off;
@@ -281,7 +295,11 @@ static DECLCALLBACK(int) rtDbgModContainer_LineAdd(PRTDBGMODINT pMod, const char
}
else
rc = VERR_NO_MEMORY;
+#ifdef RTDBGMODCNT_WITH_MEM_CACHE
+ RTMemCacheFree(pThis->hLineNumAllocator, pLine);
+#else
RTMemFree(pLine);
+#endif
return rc;
}
@@ -382,10 +400,18 @@ static DECLCALLBACK(int) rtDbgModContainer_SymbolAdd(PRTDBGMODINT pMod, const ch
("iSeg=%#x cSegs=%#x\n", pThis->cSegs),
VERR_DBG_INVALID_SEGMENT_INDEX);
AssertMsgReturn( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
- || off + cb <= pThis->paSegs[iSeg].cb,
+ || off <= pThis->paSegs[iSeg].cb,
("off=%RTptr cb=%RTptr cbSeg=%RTptr\n", off, cb, pThis->paSegs[iSeg].cb),
VERR_DBG_INVALID_SEGMENT_OFFSET);
+ /* Be a little relaxed wrt to the symbol size. */
+ int rc = VINF_SUCCESS;
+ if (iSeg != RTDBGSEGIDX_ABS && off + cb > pThis->paSegs[iSeg].cb)
+ {
+ cb = pThis->paSegs[iSeg].cb - off;
+ rc = VINF_DBG_ADJUSTED_SYM_SIZE;
+ }
+
/*
* Create a new entry.
*/
@@ -400,7 +426,6 @@ static DECLCALLBACK(int) rtDbgModContainer_SymbolAdd(PRTDBGMODINT pMod, const ch
pSymbol->cb = cb;
pSymbol->fFlags = fFlags;
pSymbol->NameCore.pszString = RTStrCacheEnterN(g_hDbgModStrCache, pszSymbol, cchSymbol);
- int rc;
if (pSymbol->NameCore.pszString)
{
if (RTStrSpaceInsert(&pThis->Names, &pSymbol->NameCore))
@@ -415,7 +440,7 @@ static DECLCALLBACK(int) rtDbgModContainer_SymbolAdd(PRTDBGMODINT pMod, const ch
if (piOrdinal)
*piOrdinal = pThis->iNextSymbolOrdinal;
pThis->iNextSymbolOrdinal++;
- return VINF_SUCCESS;
+ return rc;
}
/* bail out */
@@ -480,7 +505,16 @@ static DECLCALLBACK(int) rtDbgModContainer_SegmentAdd(PRTDBGMODINT pMod, RTUINTP
RTUINTPTR uCurRvaLast = uCurRva + RT_MAX(pThis->paSegs[iSeg].cb, 1) - 1;
if ( uRva <= uCurRvaLast
&& uRvaLast >= uCurRva
- && (cb != 0 || pThis->paSegs[iSeg].cb != 0)) /* HACK ALERT! Allow empty segments to share space (bios/watcom). */
+ && ( /* HACK ALERT! Allow empty segments to share space (bios/watcom, elf). */
+ (cb != 0 && pThis->paSegs[iSeg].cb != 0)
+ || ( cb == 0
+ && uRva != uCurRva
+ && uRva != uCurRvaLast)
+ || ( pThis->paSegs[iSeg].cb == 0
+ && uCurRva != uRva
+ && uCurRva != uRvaLast)
+ )
+ )
AssertMsgFailedReturn(("uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\";\n"
"uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\" iSeg=%#x\n",
uRva, uRvaLast, cb, pszName,
@@ -540,7 +574,9 @@ static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_RvaToSegOff(PRTDBGMODINT pMod
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
PCRTDBGMODCTNSEGMENT paSeg = pThis->paSegs;
uint32_t const cSegs = pThis->cSegs;
+#if 0
if (cSegs <= 7)
+#endif
{
/*
* Linear search.
@@ -556,6 +592,7 @@ static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_RvaToSegOff(PRTDBGMODINT pMod
}
}
}
+#if 0 /** @todo binary search doesn't work if we've got empty segments in the list */
else
{
/*
@@ -592,19 +629,36 @@ static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_RvaToSegOff(PRTDBGMODINT pMod
}
else
{
- /* between iSeg and iLast. */
+ /* between iSeg and iLast. paSeg[iSeg].cb == 0 ends up here too. */
if (iSeg == iLast)
break;
iFirst = iSeg + 1;
}
}
}
+#endif
/* Invalid. */
return NIL_RTDBGSEGIDX;
}
+/** Destroy a line number node. */
+static DECLCALLBACK(int) rtDbgModContainer_DestroyTreeLineNode(PAVLU32NODECORE pNode, void *pvUser)
+{
+ PRTDBGMODCTN pThis = (PRTDBGMODCTN)pvUser;
+ PRTDBGMODCTNLINE pLine = RT_FROM_MEMBER(pNode, RTDBGMODCTNLINE, OrdinalCore);
+ RTStrCacheRelease(g_hDbgModStrCache, pLine->pszFile);
+ pLine->pszFile = NULL;
+#ifdef RTDBGMODCNT_WITH_MEM_CACHE
+ RTMemCacheFree(pThis->hLineNumAllocator, pLine);
+#else
+ RTMemFree(pLine); NOREF(pThis);
+#endif
+ return 0;
+}
+
+
/** Destroy a symbol node. */
static DECLCALLBACK(int) rtDbgModContainer_DestroyTreeNode(PAVLRUINTPTRNODECORE pNode, void *pvUser)
{
@@ -635,6 +689,13 @@ static DECLCALLBACK(int) rtDbgModContainer_Close(PRTDBGMODINT pMod)
RTAvlrUIntPtrDestroy(&pThis->AbsAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
pThis->Names = NULL;
+#ifdef RTDBGMODCNT_WITH_MEM_CACHE
+ RTMemCacheDestroy(pThis->hLineNumAllocator);
+ pThis->hLineNumAllocator = NIL_RTMEMCACHE;
+#else
+ RTAvlU32Destroy(&pThis->LineOrdinalTree, rtDbgModContainer_DestroyTreeLineNode, pThis);
+#endif
+
RTMemFree(pThis->paSegs);
pThis->paSegs = NULL;
@@ -645,16 +706,16 @@ static DECLCALLBACK(int) rtDbgModContainer_Close(PRTDBGMODINT pMod)
/** @copydoc RTDBGMODVTDBG::pfnTryOpen */
-static DECLCALLBACK(int) rtDbgModContainer_TryOpen(PRTDBGMODINT pMod)
+static DECLCALLBACK(int) rtDbgModContainer_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
{
- NOREF(pMod);
+ NOREF(pMod); NOREF(enmArch);
return VERR_INTERNAL_ERROR_5;
}
/** Virtual function table for the debug info container. */
-static RTDBGMODVTDBG const g_rtDbgModVtDbgContainer =
+DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgContainer =
{
/*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
/*.fSupports = */ 0, /* (Don't call my TryOpen, please.) */
@@ -686,6 +747,80 @@ static RTDBGMODVTDBG const g_rtDbgModVtDbgContainer =
/**
+ * Special container operation for removing all symbols.
+ *
+ * @returns IPRT status code.
+ * @param pMod The module instance.
+ */
+DECLHIDDEN(int) rtDbgModContainer_SymbolRemoveAll(PRTDBGMODINT pMod)
+{
+ PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
+
+ for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
+ {
+ RTAvlrUIntPtrDestroy(&pThis->paSegs[iSeg].SymAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
+ Assert(pThis->paSegs[iSeg].SymAddrTree == NULL);
+ }
+
+ RTAvlrUIntPtrDestroy(&pThis->AbsAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
+ Assert(pThis->AbsAddrTree == NULL);
+
+ pThis->Names = NULL;
+ pThis->iNextSymbolOrdinal = 0;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Special container operation for removing all line numbers.
+ *
+ * @returns IPRT status code.
+ * @param pMod The module instance.
+ */
+DECLHIDDEN(int) rtDbgModContainer_LineRemoveAll(PRTDBGMODINT pMod)
+{
+ PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
+
+ for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
+ pThis->paSegs[iSeg].LineAddrTree = NULL;
+
+ RTAvlU32Destroy(&pThis->LineOrdinalTree, rtDbgModContainer_DestroyTreeLineNode, pThis);
+ Assert(pThis->LineOrdinalTree == NULL);
+
+ pThis->iNextLineOrdinal = 0;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Special container operation for removing everything.
+ *
+ * @returns IPRT status code.
+ * @param pMod The module instance.
+ */
+DECLHIDDEN(int) rtDbgModContainer_RemoveAll(PRTDBGMODINT pMod)
+{
+ PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
+
+ rtDbgModContainer_LineRemoveAll(pMod);
+ rtDbgModContainer_SymbolRemoveAll(pMod);
+
+ for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
+ {
+ RTStrCacheRelease(g_hDbgModStrCache, pThis->paSegs[iSeg].pszName);
+ pThis->paSegs[iSeg].pszName = NULL;
+ }
+
+ pThis->cSegs = 0;
+ pThis->cb = 0;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
* Creates a generic debug info container and associates it with the module.
*
* @returns IPRT status code.
@@ -712,21 +847,30 @@ int rtDbgModContainerCreate(PRTDBGMODINT pMod, RTUINTPTR cbSeg)
pMod->pDbgVt = &g_rtDbgModVtDbgContainer;
pMod->pvDbgPriv = pThis;
- /*
- * Add the initial segment.
- */
- if (cbSeg)
+#ifdef RTDBGMODCNT_WITH_MEM_CACHE
+ int rc = RTMemCacheCreate(&pThis->hLineNumAllocator, sizeof(RTDBGMODCTNLINE), sizeof(void *), UINT32_MAX,
+ NULL /*pfnCtor*/, NULL /*pfnDtor*/, NULL /*pvUser*/, 0 /*fFlags*/);
+#else
+ int rc = VINF_SUCCESS;
+#endif
+ if (RT_SUCCESS(rc))
{
- int rc = rtDbgModContainer_SegmentAdd(pMod, 0, cbSeg, "default", sizeof("default") - 1, 0, NULL);
- if (RT_FAILURE(rc))
- {
- RTMemFree(pThis);
- pMod->pDbgVt = NULL;
- pMod->pvDbgPriv = NULL;
+ /*
+ * Add the initial segment.
+ */
+ if (cbSeg)
+ rc = rtDbgModContainer_SegmentAdd(pMod, 0, cbSeg, "default", sizeof("default") - 1, 0, NULL);
+ if (RT_SUCCESS(rc))
return rc;
- }
+
+#ifdef RTDBGMODCNT_WITH_MEM_CACHE
+ RTMemCacheDestroy(pThis->hLineNumAllocator);
+#endif
}
- return VINF_SUCCESS;
+ RTMemFree(pThis);
+ pMod->pDbgVt = NULL;
+ pMod->pvDbgPriv = NULL;
+ return rc;
}
diff --git a/src/VBox/Runtime/common/dbg/dbgmoddbghelp.cpp b/src/VBox/Runtime/common/dbg/dbgmoddbghelp.cpp
new file mode 100644
index 00000000..96419771
--- /dev/null
+++ b/src/VBox/Runtime/common/dbg/dbgmoddbghelp.cpp
@@ -0,0 +1,502 @@
+/* $Id: dbgmoddbghelp.cpp $ */
+/** @file
+ * IPRT - Debug Info Reader Using DbgHelp.dll if Present.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DBG
+#include <iprt/dbg.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/list.h>
+#include <iprt/log.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include "internal/dbgmod.h"
+
+#include <Windows.h>
+#include <Dbghelp.h>
+#include <iprt/win/lazy-dbghelp.h>
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/** For passing arguments to DbgHelp.dll callback. */
+typedef struct RTDBGMODBGHELPARGS
+{
+ RTDBGMOD hCnt;
+ PRTDBGMODINT pMod;
+ uint64_t uModAddr;
+
+ /** UTF-8 version of the previous file name. */
+ char *pszPrev;
+ /** Copy of the previous file name. */
+ PRTUTF16 pwszPrev;
+ /** Number of bytes pwszPrev points to. */
+ size_t cbPrevUtf16Alloc;
+} RTDBGMODBGHELPARGS;
+
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
+ PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ return RTDbgModLineByAddr(hCnt, iSeg, off, poffDisp, pLineInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ return RTDbgModLineByOrdinal(hCnt, iOrdinal, pLineInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
+static DECLCALLBACK(uint32_t) rtDbgModDbgHelp_LineCount(PRTDBGMODINT pMod)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ return RTDbgModLineCount(hCnt);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
+ uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ Assert(!pszFile[cchFile]); NOREF(cchFile);
+ return RTDbgModLineAdd(hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
+ PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ return RTDbgModSymbolByAddr(hCnt, iSeg, off, fFlags, poffDisp, pSymInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
+ PRTDBGSYMBOL pSymInfo)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ Assert(!pszSymbol[cchSymbol]);
+ return RTDbgModSymbolByName(hCnt, pszSymbol/*, cchSymbol*/, pSymInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ return RTDbgModSymbolByOrdinal(hCnt, iOrdinal, pSymInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
+static DECLCALLBACK(uint32_t) rtDbgModDbgHelp_SymbolCount(PRTDBGMODINT pMod)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ return RTDbgModSymbolCount(hCnt);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
+ RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
+ uint32_t *piOrdinal)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
+ return RTDbgModSymbolAdd(hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ return RTDbgModSegmentByIndex(hCnt, iSeg, pSegInfo);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
+static DECLCALLBACK(RTDBGSEGIDX) rtDbgModDbgHelp_SegmentCount(PRTDBGMODINT pMod)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ return RTDbgModSegmentCount(hCnt);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
+ uint32_t fFlags, PRTDBGSEGIDX piSeg)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ Assert(!pszName[cchName]); NOREF(cchName);
+ return RTDbgModSegmentAdd(hCnt, uRva, cb, pszName, fFlags, piSeg);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
+static DECLCALLBACK(RTUINTPTR) rtDbgModDbgHelp_ImageSize(PRTDBGMODINT pMod)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ RTUINTPTR cb1 = RTDbgModImageSize(hCnt);
+ RTUINTPTR cb2 = pMod->pImgVt->pfnImageSize(pMod);
+ return RT_MAX(cb1, cb2);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
+static DECLCALLBACK(RTDBGSEGIDX) rtDbgModDbgHelp_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
+ return RTDbgModRvaToSegOff(hCnt, uRva, poffSeg);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_Close(PRTDBGMODINT pMod)
+{
+ RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;;
+ RTDbgModRelease(hCnt);
+ pMod->pvDbgPriv = NULL;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * SymEnumLinesW callback that adds a line number to the container.
+ *
+ * @returns TRUE, FALSE if we're out of memory.
+ * @param pLineInfo Line number information.
+ * @param pvUser Pointer to a RTDBGMODBGHELPARGS structure.
+ */
+static BOOL CALLBACK rtDbgModDbgHelpCopyLineNumberCallback(PSRCCODEINFOW pLineInfo, PVOID pvUser)
+{
+ RTDBGMODBGHELPARGS *pArgs = (RTDBGMODBGHELPARGS *)pvUser;
+
+ if (pLineInfo->Address < pArgs->uModAddr)
+ {
+ Log((" %#018x %05u %s [SKIPPED - INVALID ADDRESS!]\n", pLineInfo->Address, pLineInfo->LineNumber));
+ return TRUE;
+ }
+
+ /*
+ * To save having to call RTUtf16ToUtf8 every time, we keep a copy of the
+ * previous file name both as UTF-8 and UTF-16.
+ */
+ /** @todo we could combine RTUtf16Len and memcmp... */
+ size_t cbLen = (RTUtf16Len(pLineInfo->FileName) + 1) * sizeof(RTUTF16);
+ if ( !pArgs->pwszPrev
+ || memcmp(pArgs->pwszPrev, pLineInfo->FileName, cbLen) )
+ {
+ if (pArgs->cbPrevUtf16Alloc >= cbLen)
+ memcpy(pArgs->pwszPrev, pLineInfo->FileName, cbLen);
+ else
+ {
+ RTMemFree(pArgs->pwszPrev);
+ pArgs->cbPrevUtf16Alloc = cbLen;
+ pArgs->pwszPrev = (PRTUTF16)RTMemDupEx(pLineInfo->FileName, cbLen, pArgs->cbPrevUtf16Alloc - cbLen);
+ if (!pArgs->pwszPrev)
+ pArgs->cbPrevUtf16Alloc = 0;
+ }
+
+ RTStrFree(pArgs->pszPrev);
+ pArgs->pszPrev = NULL;
+ int rc = RTUtf16ToUtf8(pLineInfo->FileName, &pArgs->pszPrev);
+ if (RT_FAILURE(rc))
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
+ Log(("rtDbgModDbgHelpCopyLineNumberCallback: Out of memory\n"));
+ return FALSE;
+ }
+ }
+
+ /*
+ * Add the line number to the container.
+ */
+ int rc = RTDbgModLineAdd(pArgs->hCnt, pArgs->pszPrev, pLineInfo->LineNumber,
+ RTDBGSEGIDX_RVA, pLineInfo->Address - pArgs->uModAddr, NULL);
+ Log((" %#018x %05u %s [%Rrc]\n", pLineInfo->Address, pLineInfo->LineNumber, rc));
+ NOREF(rc);
+
+ return TRUE;
+}
+
+
+/**
+ * Copies the line numbers into the container.
+ *
+ * @returns IPRT status code.
+ * @param pMod The debug module.
+ * @param hCnt The container that will keep the symbols.
+ * @param hFake The fake process handle.
+ * @param uModAddr The module load address.
+ */
+static int rtDbgModDbgHelpCopyLineNumbers(PRTDBGMODINT pMod, RTDBGMOD hCnt, HANDLE hFake, uint64_t uModAddr)
+{
+ RTDBGMODBGHELPARGS Args;
+ Args.hCnt = hCnt;
+ Args.pMod = pMod;
+ Args.uModAddr = uModAddr;
+ Args.pszPrev = NULL;
+ Args.pwszPrev = NULL;
+ Args.cbPrevUtf16Alloc = 0;
+
+ int rc;
+ if (SymEnumLinesW(hFake, uModAddr, NULL /*pszObj*/, NULL /*pszFile*/, rtDbgModDbgHelpCopyLineNumberCallback, &Args))
+ rc = VINF_SUCCESS;
+ else
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ Log(("Line number enum: %Rrc (%u)\n", rc, GetLastError()));
+ if (rc == VERR_NOT_SUPPORTED)
+ rc = VINF_SUCCESS;
+ }
+
+ RTStrFree(Args.pszPrev);
+ RTMemFree(Args.pwszPrev);
+ return rc;
+}
+
+
+/**
+ * SymEnumSymbols callback that adds a symbol to the container.
+ *
+ * @returns TRUE
+ * @param pSymInfo The symbol information.
+ * @param cbSymbol The symbol size (estimated).
+ * @param pvUser Pointer to a RTDBGMODBGHELPARGS structure.
+ */
+static BOOL CALLBACK rtDbgModDbgHelpCopySymbolsCallback(PSYMBOL_INFO pSymInfo, ULONG cbSymbol, PVOID pvUser)
+{
+ RTDBGMODBGHELPARGS *pArgs = (RTDBGMODBGHELPARGS *)pvUser;
+ if (pSymInfo->Address < pArgs->uModAddr) /* NT4 SP1 ntfs.dbg */
+ {
+ Log((" %#018x LB %#07x %s [SKIPPED - INVALID ADDRESS!]\n", pSymInfo->Address, cbSymbol, pSymInfo->Name));
+ return TRUE;
+ }
+ if (pSymInfo->NameLen >= RTDBG_SYMBOL_NAME_LENGTH)
+ {
+ Log((" %#018x LB %#07x %s [SKIPPED - TOO LONG (%u > %u)!]\n", pSymInfo->Address, cbSymbol, pSymInfo->Name,
+ pSymInfo->NameLen, RTDBG_SYMBOL_NAME_LENGTH));
+ return TRUE;
+ }
+
+ /* ASSUMES the symbol name is ASCII. */
+ int rc = RTDbgModSymbolAdd(pArgs->hCnt, pSymInfo->Name, RTDBGSEGIDX_RVA,
+ pSymInfo->Address - pArgs->uModAddr, cbSymbol, 0, NULL);
+ Log((" %#018x LB %#07x %s [%Rrc]\n", pSymInfo->Address, cbSymbol, pSymInfo->Name, rc));
+ NOREF(rc);
+
+ return TRUE;
+}
+
+
+/**
+ * Copies the symbols into the container.
+ *
+ * @returns IPRT status code.
+ * @param pMod The debug module.
+ * @param hCnt The container that will keep the symbols.
+ * @param hFake The fake process handle.
+ * @param uModAddr The module load address.
+ */
+static int rtDbgModDbgHelpCopySymbols(PRTDBGMODINT pMod, RTDBGMOD hCnt, HANDLE hFake, uint64_t uModAddr)
+{
+ RTDBGMODBGHELPARGS Args;
+ Args.hCnt = hCnt;
+ Args.pMod = pMod;
+ Args.uModAddr = uModAddr;
+ int rc;
+ if (SymEnumSymbols(hFake, uModAddr, NULL, rtDbgModDbgHelpCopySymbolsCallback, &Args))
+ rc = VINF_SUCCESS;
+ else
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ Log(("SymEnumSymbols: %Rrc (%u)\n", rc, GetLastError()));
+ }
+ return rc;
+}
+
+
+/** @callback_method_impl{FNRTLDRENUMSEGS, Copies the PE segments over into
+ * the container.} */
+static DECLCALLBACK(int) rtDbgModDbgHelpAddSegmentsCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
+{
+ RTDBGMODBGHELPARGS *pArgs = (RTDBGMODBGHELPARGS *)pvUser;
+
+ Log(("Segment %.*s: LinkAddress=%#llx RVA=%#llx cb=%#llx\n",
+ pSeg->cchName, pSeg->pszName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
+
+ Assert(pSeg->cchName > 0);
+ Assert(!pSeg->pszName[pSeg->cchName]);
+
+ if (!pSeg->RVA)
+ pArgs->uModAddr = pSeg->LinkAddress;
+
+ RTLDRADDR cb = RT_MAX(pSeg->cb, pSeg->cbMapped);
+ return RTDbgModSegmentAdd(pArgs->hCnt, pSeg->RVA, cb, pSeg->pszName, 0 /*fFlags*/, NULL);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
+static DECLCALLBACK(int) rtDbgModDbgHelp_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
+{
+ NOREF(enmArch);
+
+ /*
+ * Currently only support external files with a executable already present.
+ */
+ if (!pMod->pszDbgFile)
+ return VERR_DBG_NO_MATCHING_INTERPRETER;
+ if (!pMod->pImgVt)
+ return VERR_DBG_NO_MATCHING_INTERPRETER;
+
+ /*
+ * Create a container for copying the information into. We do this early
+ * so we can determine the image base address.
+ */
+ RTDBGMOD hCnt;
+ int rc = RTDbgModCreate(&hCnt, pMod->pszName, 0 /*cbSeg*/, 0 /*fFlags*/);
+ if (RT_SUCCESS(rc))
+ {
+ RTDBGMODBGHELPARGS Args;
+ RT_ZERO(Args);
+ Args.hCnt = hCnt;
+ rc = pMod->pImgVt->pfnEnumSegments(pMod, rtDbgModDbgHelpAddSegmentsCallback, &Args);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t cbImage = pMod->pImgVt->pfnImageSize(pMod);
+ uint64_t uImageBase = Args.uModAddr ? Args.uModAddr : 0x4000000;
+
+ /*
+ * Try load the module into an empty address space.
+ */
+ static uint32_t volatile s_uFakeHandle = 0x3940000;
+ HANDLE hFake;
+ do
+ hFake = (HANDLE)(uintptr_t)ASMAtomicIncU32(&s_uFakeHandle);
+ while (hFake == NULL || hFake == INVALID_HANDLE_VALUE);
+
+ LogFlow(("rtDbgModDbgHelp_TryOpen: \n"));
+ if (SymInitialize(hFake, NULL /*SearchPath*/, FALSE /*fInvalidProcess*/))
+ {
+ SymSetOptions(SYMOPT_LOAD_LINES | SymGetOptions());
+
+ PRTUTF16 pwszDbgFile;
+ rc = RTStrToUtf16(pMod->pszDbgFile, &pwszDbgFile);
+ if (RT_SUCCESS(rc))
+ {
+ uint64_t uModAddr = SymLoadModuleExW(hFake, NULL /*hFile*/, pwszDbgFile, NULL /*pszModName*/,
+ uImageBase, cbImage, NULL /*pModData*/, 0 /*fFlags*/);
+ if (uModAddr != 0)
+ {
+ rc = rtDbgModDbgHelpCopySymbols(pMod, hCnt, hFake, uModAddr);
+ if (RT_SUCCESS(rc))
+ rc = rtDbgModDbgHelpCopyLineNumbers(pMod, hCnt, hFake, uModAddr);
+ if (RT_SUCCESS(rc))
+ {
+ pMod->pvDbgPriv = hCnt;
+ pMod->pDbgVt = &g_rtDbgModVtDbgDbgHelp;
+ hCnt = NIL_RTDBGMOD;
+ LogFlow(("rtDbgModDbgHelp_TryOpen: Successfully loaded '%s' at %#llx\n",
+ pMod->pszDbgFile, (uint64_t)uImageBase));
+ }
+
+ SymUnloadModule64(hFake, uModAddr);
+ }
+ else
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ LogFlow(("rtDbgModDbgHelp_TryOpen: Error loading the module '%s' at %#llx: %Rrc (%u)\n",
+ pMod->pszDbgFile, (uint64_t)uImageBase, rc, GetLastError()));
+ }
+ RTUtf16Free(pwszDbgFile);
+ }
+ else
+ LogFlow(("rtDbgModDbgHelp_TryOpen: Unicode version issue: %Rrc\n", rc));
+
+ BOOL fRc2 = SymCleanup(hFake); Assert(fRc2); NOREF(fRc2);
+ }
+ else
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ LogFlow(("rtDbgModDbgHelp_TryOpen: SymInitialize failed: %Rrc (%u)\n", rc, GetLastError()));
+ }
+ }
+ RTDbgModRelease(hCnt);
+ }
+ return rc;
+}
+
+
+
+/** Virtual function table for the DBGHELP debug info reader. */
+DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgDbgHelp =
+{
+ /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
+ /*.fSupports = */ RT_DBGTYPE_CODEVIEW,
+ /*.pszName = */ "dbghelp",
+ /*.pfnTryOpen = */ rtDbgModDbgHelp_TryOpen,
+ /*.pfnClose = */ rtDbgModDbgHelp_Close,
+
+ /*.pfnRvaToSegOff = */ rtDbgModDbgHelp_RvaToSegOff,
+ /*.pfnImageSize = */ rtDbgModDbgHelp_ImageSize,
+
+ /*.pfnSegmentAdd = */ rtDbgModDbgHelp_SegmentAdd,
+ /*.pfnSegmentCount = */ rtDbgModDbgHelp_SegmentCount,
+ /*.pfnSegmentByIndex = */ rtDbgModDbgHelp_SegmentByIndex,
+
+ /*.pfnSymbolAdd = */ rtDbgModDbgHelp_SymbolAdd,
+ /*.pfnSymbolCount = */ rtDbgModDbgHelp_SymbolCount,
+ /*.pfnSymbolByOrdinal = */ rtDbgModDbgHelp_SymbolByOrdinal,
+ /*.pfnSymbolByName = */ rtDbgModDbgHelp_SymbolByName,
+ /*.pfnSymbolByAddr = */ rtDbgModDbgHelp_SymbolByAddr,
+
+ /*.pfnLineAdd = */ rtDbgModDbgHelp_LineAdd,
+ /*.pfnLineCount = */ rtDbgModDbgHelp_LineCount,
+ /*.pfnLineByOrdinal = */ rtDbgModDbgHelp_LineByOrdinal,
+ /*.pfnLineByAddr = */ rtDbgModDbgHelp_LineByAddr,
+
+ /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
+};
+
diff --git a/src/VBox/Runtime/common/dbg/dbgmoddeferred.cpp b/src/VBox/Runtime/common/dbg/dbgmoddeferred.cpp
new file mode 100644
index 00000000..1e2893e0
--- /dev/null
+++ b/src/VBox/Runtime/common/dbg/dbgmoddeferred.cpp
@@ -0,0 +1,642 @@
+/* $Id: dbgmoddeferred.cpp $ */
+/** @file
+ * IPRT - Debug Module Deferred Loading Stub.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/dbg.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/param.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include "internal/dbgmod.h"
+#include "internal/magics.h"
+
+
+
+/**
+ * Releases the instance data.
+ *
+ * @param pThis The instance data.
+ */
+static void rtDbgModDeferredReleaseInstanceData(PRTDBGMODDEFERRED pThis)
+{
+ AssertPtr(pThis);
+ uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); Assert(cRefs < 8);
+ if (!cRefs)
+ {
+ RTDbgCfgRelease(pThis->hDbgCfg);
+ pThis->hDbgCfg = NIL_RTDBGCFG;
+ RTMemFree(pThis);
+ }
+}
+
+
+/**
+ * Does the deferred loading of the real data (image and/or debug info).
+ *
+ * @returns VINF_SUCCESS or VERR_DBG_DEFERRED_LOAD_FAILED.
+ * @param pMod The generic module instance data.
+ * @param fForcedRetry Whether it's a forced retry by one of the
+ * pfnTryOpen methods.
+ */
+static int rtDbgModDeferredDoIt(PRTDBGMODINT pMod, bool fForcedRetry)
+{
+ RTCritSectEnter(&pMod->CritSect);
+
+ int rc;
+ if (!pMod->fDeferredFailed || fForcedRetry)
+ {
+ bool const fDbgVt = pMod->pDbgVt == &g_rtDbgModVtDbgDeferred;
+ bool const fImgVt = pMod->pImgVt == &g_rtDbgModVtImgDeferred;
+ AssertReturnStmt(fDbgVt || fImgVt, RTCritSectLeave(&pMod->CritSect), VERR_INTERNAL_ERROR_5);
+
+ PRTDBGMODDEFERRED pThis = (PRTDBGMODDEFERRED)(fDbgVt ? pMod->pvDbgPriv : pMod->pvImgPriv);
+
+ /* Reset the method tables and private data pointes so the deferred loading
+ procedure can figure out what to do and won't get confused. */
+ if (fDbgVt)
+ {
+ pMod->pvDbgPriv = NULL;
+ pMod->pDbgVt = NULL;
+ }
+
+ if (fImgVt)
+ {
+ pMod->pvImgPriv = NULL;
+ pMod->pImgVt = NULL;
+ }
+
+ /* Do the deferred loading. */
+ rc = pThis->pfnDeferred(pMod, pThis);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(!fDbgVt || pMod->pDbgVt != NULL);
+ Assert(!fImgVt || pMod->pImgVt != NULL);
+
+ pMod->fDeferred = false;
+ pMod->fDeferredFailed = false;
+
+ rtDbgModDeferredReleaseInstanceData(pThis);
+ if (fImgVt && fDbgVt)
+ rtDbgModDeferredReleaseInstanceData(pThis);
+ }
+ else
+ {
+ /* Failed, bail out and restore the deferred setup. */
+ pMod->fDeferredFailed = true;
+
+ if (fDbgVt)
+ {
+ Assert(!pMod->pDbgVt);
+ pMod->pDbgVt = &g_rtDbgModVtDbgDeferred;
+ pMod->pvDbgPriv = pThis;
+ }
+
+ if (fImgVt)
+ {
+ Assert(!pMod->pImgVt);
+ pMod->pImgVt = &g_rtDbgModVtImgDeferred;
+ pMod->pvImgPriv = pThis;
+ }
+ }
+ }
+ else
+ rc = VERR_DBG_DEFERRED_LOAD_FAILED;
+
+ RTCritSectLeave(&pMod->CritSect);
+ return rc;
+}
+
+
+
+
+/*
+ *
+ * D e b u g I n f o M e t h o d s
+ * D e b u g I n f o M e t h o d s
+ * D e b u g I n f o M e t h o d s
+ *
+ */
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
+ PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pDbgVt->pfnLineByAddr(pMod, iSeg, off, poffDisp, pLineInfo);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pDbgVt->pfnLineByOrdinal(pMod, iOrdinal, pLineInfo);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
+static DECLCALLBACK(uint32_t) rtDbgModDeferredDbg_LineCount(PRTDBGMODINT pMod)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ return pMod->pDbgVt->pfnLineCount(pMod);
+ return 0;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
+ uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pDbgVt->pfnLineAdd(pMod, pszFile, cchFile, uLineNo, iSeg, off, piOrdinal);
+ return rc;
+}
+
+
+/**
+ * Fill in symbol info for the fake start symbol.
+ *
+ * @returns VINF_SUCCESS
+ * @param pThis The deferred load data.
+ * @param pSymInfo The output structure.
+ */
+static int rtDbgModDeferredDbgSymInfo_Start(PRTDBGMODDEFERRED pThis, PRTDBGSYMBOL pSymInfo)
+{
+ pSymInfo->Value = 0;
+ pSymInfo->cb = pThis->cbImage;
+ pSymInfo->offSeg = 0;
+ pSymInfo->iSeg = 0;
+ pSymInfo->fFlags = 0;
+ pSymInfo->iOrdinal = 0;
+ strcpy(pSymInfo->szName, "DeferredStart");
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Fill in symbol info for the fake last symbol.
+ *
+ * @returns VINF_SUCCESS
+ * @param pThis The deferred load data.
+ * @param pSymInfo The output structure.
+ */
+static int rtDbgModDeferredDbgSymInfo_Last(PRTDBGMODDEFERRED pThis, PRTDBGSYMBOL pSymInfo)
+{
+ pSymInfo->Value = pThis->cbImage - 1;
+ pSymInfo->cb = 0;
+ pSymInfo->offSeg = pThis->cbImage - 1;
+ pSymInfo->iSeg = 0;
+ pSymInfo->fFlags = 0;
+ pSymInfo->iOrdinal = 1;
+ strcpy(pSymInfo->szName, "DeferredLast");
+ return VINF_SUCCESS;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
+ PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pDbgVt->pfnSymbolByAddr(pMod, iSeg, off, fFlags, poffDisp, pSymInfo);
+ else
+ {
+ PRTDBGMODDEFERRED pThis = (PRTDBGMODDEFERRED)pMod->pvDbgPriv;
+ if (off == 0)
+ rc = rtDbgModDeferredDbgSymInfo_Start(pThis, pSymInfo);
+ else if (off >= pThis->cbImage - 1 || (fFlags & RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL))
+ rc = rtDbgModDeferredDbgSymInfo_Last(pThis, pSymInfo);
+ else
+ rc = rtDbgModDeferredDbgSymInfo_Start(pThis, pSymInfo);
+ if (poffDisp)
+ *poffDisp = off - pSymInfo->offSeg;
+ }
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
+ PRTDBGSYMBOL pSymInfo)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pDbgVt->pfnSymbolByName(pMod, pszSymbol, cchSymbol, pSymInfo);
+ else
+ {
+ PRTDBGMODDEFERRED pThis = (PRTDBGMODDEFERRED)pMod->pvDbgPriv;
+ if ( cchSymbol == sizeof("DeferredStart") - 1
+ && !memcmp(pszSymbol, RT_STR_TUPLE("DeferredStart")))
+ rc = rtDbgModDeferredDbgSymInfo_Start(pThis, pSymInfo);
+ else if ( cchSymbol == sizeof("DeferredLast") - 1
+ && !memcmp(pszSymbol, RT_STR_TUPLE("DeferredLast")))
+ rc = rtDbgModDeferredDbgSymInfo_Last(pThis, pSymInfo);
+ else
+ rc = VERR_SYMBOL_NOT_FOUND;
+ }
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pDbgVt->pfnSymbolByOrdinal(pMod, iOrdinal, pSymInfo);
+ else
+ {
+ PRTDBGMODDEFERRED pThis = (PRTDBGMODDEFERRED)pMod->pvDbgPriv;
+ if (iOrdinal == 0)
+ rc = rtDbgModDeferredDbgSymInfo_Start(pThis, pSymInfo);
+ else if (iOrdinal == 1)
+ rc = rtDbgModDeferredDbgSymInfo_Last(pThis, pSymInfo);
+ else
+ rc = VERR_SYMBOL_NOT_FOUND;
+ }
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
+static DECLCALLBACK(uint32_t) rtDbgModDeferredDbg_SymbolCount(PRTDBGMODINT pMod)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ return pMod->pDbgVt->pfnSymbolCount(pMod);
+ return 2;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
+ RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
+ uint32_t *piOrdinal)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pDbgVt->pfnSymbolAdd(pMod, pszSymbol, cchSymbol, iSeg, off, cb, fFlags, piOrdinal);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pDbgVt->pfnSegmentByIndex(pMod, iSeg, pSegInfo);
+ else if (iSeg == 0)
+ {
+ PRTDBGMODDEFERRED pThis = (PRTDBGMODDEFERRED)pMod->pvDbgPriv;
+ pSegInfo->Address = 0;
+ pSegInfo->uRva = 0;
+ pSegInfo->cb = pThis->cbImage;
+ pSegInfo->fFlags = 0;
+ pSegInfo->iSeg = 0;
+ memcpy(pSegInfo->szName, RT_STR_TUPLE("LATER"));
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_DBG_INVALID_SEGMENT_INDEX;
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
+static DECLCALLBACK(RTDBGSEGIDX) rtDbgModDeferredDbg_SegmentCount(PRTDBGMODINT pMod)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ return pMod->pDbgVt->pfnSegmentCount(pMod);
+ return 1;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName,
+ size_t cchName, uint32_t fFlags, PRTDBGSEGIDX piSeg)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pDbgVt->pfnSegmentAdd(pMod, uRva, cb, pszName, cchName, fFlags, piSeg);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
+static DECLCALLBACK(RTUINTPTR) rtDbgModDeferredDbg_ImageSize(PRTDBGMODINT pMod)
+{
+ PRTDBGMODDEFERRED pThis = (PRTDBGMODDEFERRED)pMod->pvDbgPriv;
+ return pThis->cbImage;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
+static DECLCALLBACK(RTDBGSEGIDX) rtDbgModDeferredDbg_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ return pMod->pDbgVt->pfnRvaToSegOff(pMod, uRva, poffSeg);
+ return 0;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_Close(PRTDBGMODINT pMod)
+{
+ rtDbgModDeferredReleaseInstanceData((PRTDBGMODDEFERRED)pMod->pvImgPriv);
+ return VINF_SUCCESS;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
+static DECLCALLBACK(int) rtDbgModDeferredDbg_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
+{
+ NOREF(enmArch);
+ return rtDbgModDeferredDoIt(pMod, true /*fForceRetry*/);
+}
+
+
+
+/** Virtual function table for the deferred debug info reader. */
+DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgDeferred =
+{
+ /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
+ /*.fSupports = */ RT_DBGTYPE_MAP,
+ /*.pszName = */ "deferred",
+ /*.pfnTryOpen = */ rtDbgModDeferredDbg_TryOpen,
+ /*.pfnClose = */ rtDbgModDeferredDbg_Close,
+
+ /*.pfnRvaToSegOff = */ rtDbgModDeferredDbg_RvaToSegOff,
+ /*.pfnImageSize = */ rtDbgModDeferredDbg_ImageSize,
+
+ /*.pfnSegmentAdd = */ rtDbgModDeferredDbg_SegmentAdd,
+ /*.pfnSegmentCount = */ rtDbgModDeferredDbg_SegmentCount,
+ /*.pfnSegmentByIndex = */ rtDbgModDeferredDbg_SegmentByIndex,
+
+ /*.pfnSymbolAdd = */ rtDbgModDeferredDbg_SymbolAdd,
+ /*.pfnSymbolCount = */ rtDbgModDeferredDbg_SymbolCount,
+ /*.pfnSymbolByOrdinal = */ rtDbgModDeferredDbg_SymbolByOrdinal,
+ /*.pfnSymbolByName = */ rtDbgModDeferredDbg_SymbolByName,
+ /*.pfnSymbolByAddr = */ rtDbgModDeferredDbg_SymbolByAddr,
+
+ /*.pfnLineAdd = */ rtDbgModDeferredDbg_LineAdd,
+ /*.pfnLineCount = */ rtDbgModDeferredDbg_LineCount,
+ /*.pfnLineByOrdinal = */ rtDbgModDeferredDbg_LineByOrdinal,
+ /*.pfnLineByAddr = */ rtDbgModDeferredDbg_LineByAddr,
+
+ /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
+};
+
+
+
+
+/*
+ *
+ * I m a g e M e t h o d s
+ * I m a g e M e t h o d s
+ * I m a g e M e t h o d s
+ *
+ */
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnGetArch} */
+static DECLCALLBACK(RTLDRARCH) rtDbgModDeferredImg_GetArch(PRTDBGMODINT pMod)
+{
+ RTLDRARCH enmArch;
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ enmArch = pMod->pImgVt->pfnGetArch(pMod);
+ else
+ enmArch = RTLDRARCH_WHATEVER;
+ return enmArch;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnGetFormat} */
+static DECLCALLBACK(RTLDRFMT) rtDbgModDeferredImg_GetFormat(PRTDBGMODINT pMod)
+{
+ RTLDRFMT enmFmt;
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ enmFmt = pMod->pImgVt->pfnGetFormat(pMod);
+ else
+ enmFmt = RTLDRFMT_INVALID;
+ return enmFmt;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnReadAt} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_ReadAt(PRTDBGMODINT pMod, uint32_t iDbgInfoHint, RTFOFF off, void *pvBuf, size_t cb)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pImgVt->pfnReadAt(pMod, iDbgInfoHint, off, pvBuf, cb);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnUnmapPart} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_UnmapPart(PRTDBGMODINT pMod, size_t cb, void const **ppvMap)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pImgVt->pfnUnmapPart(pMod, cb, ppvMap);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnMapPart} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_MapPart(PRTDBGMODINT pMod, uint32_t iDbgInfo, RTFOFF off, size_t cb, void const **ppvMap)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pImgVt->pfnMapPart(pMod, iDbgInfo, off, cb, ppvMap);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnImageSize} */
+static DECLCALLBACK(RTUINTPTR) rtDbgModDeferredImg_ImageSize(PRTDBGMODINT pMod)
+{
+ PRTDBGMODDEFERRED pThis = (PRTDBGMODDEFERRED)pMod->pvImgPriv;
+ return pThis->cbImage;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnRvaToSegOffset} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_RvaToSegOffset(PRTDBGMODINT pMod, RTLDRADDR uRva,
+ PRTDBGSEGIDX piSeg, PRTLDRADDR poffSeg)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pImgVt->pfnRvaToSegOffset(pMod, uRva, piSeg, poffSeg);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnLinkAddressToSegOffset} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_LinkAddressToSegOffset(PRTDBGMODINT pMod, RTLDRADDR LinkAddress,
+ PRTDBGSEGIDX piSeg, PRTLDRADDR poffSeg)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pImgVt->pfnLinkAddressToSegOffset(pMod, LinkAddress, piSeg, poffSeg);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnEnumSymbols} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_EnumSymbols(PRTDBGMODINT pMod, uint32_t fFlags, RTLDRADDR BaseAddress,
+ PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pImgVt->pfnEnumSymbols(pMod, fFlags, BaseAddress, pfnCallback, pvUser);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnEnumSegments} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_EnumSegments(PRTDBGMODINT pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pImgVt->pfnEnumSegments(pMod, pfnCallback, pvUser);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnEnumDbgInfo} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_EnumDbgInfo(PRTDBGMODINT pMod, PFNRTLDRENUMDBG pfnCallback, void *pvUser)
+{
+ int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+ if (RT_SUCCESS(rc))
+ rc = pMod->pImgVt->pfnEnumDbgInfo(pMod, pfnCallback, pvUser);
+ return rc;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnClose} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_Close(PRTDBGMODINT pMod)
+{
+ rtDbgModDeferredReleaseInstanceData((PRTDBGMODDEFERRED)pMod->pvImgPriv);
+ return VINF_SUCCESS;
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnTryOpen} */
+static DECLCALLBACK(int) rtDbgModDeferredImg_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
+{
+ NOREF(enmArch);
+ return rtDbgModDeferredDoIt(pMod, true /*fForceRetry*/);
+}
+
+
+/** Virtual function table for the RTLdr based image reader. */
+DECL_HIDDEN_CONST(RTDBGMODVTIMG) const g_rtDbgModVtImgDeferred =
+{
+ /*.u32Magic = */ RTDBGMODVTIMG_MAGIC,
+ /*.fReserved = */ 0,
+ /*.pszName = */ "deferred",
+ /*.pfnTryOpen = */ rtDbgModDeferredImg_TryOpen,
+ /*.pfnClose = */ rtDbgModDeferredImg_Close,
+ /*.pfnEnumDbgInfo = */ rtDbgModDeferredImg_EnumDbgInfo,
+ /*.pfnEnumSegments = */ rtDbgModDeferredImg_EnumSegments,
+ /*.pfnEnumSymbols = */ rtDbgModDeferredImg_EnumSymbols,
+ /*.pfnGetLoadedSize = */ rtDbgModDeferredImg_ImageSize,
+ /*.pfnLinkAddressToSegOffset = */ rtDbgModDeferredImg_LinkAddressToSegOffset,
+ /*.pfnRvaToSegOffset = */ rtDbgModDeferredImg_RvaToSegOffset,
+ /*.pfnMapPart = */ rtDbgModDeferredImg_MapPart,
+ /*.pfnUnmapPart = */ rtDbgModDeferredImg_UnmapPart,
+ /*.pfnReadAt = */ rtDbgModDeferredImg_ReadAt,
+ /*.pfnGetFormat = */ rtDbgModDeferredImg_GetFormat,
+ /*.pfnGetArch = */ rtDbgModDeferredImg_GetArch,
+
+ /*.u32EndMagic = */ RTDBGMODVTIMG_MAGIC
+};
+
+
+/**
+ * Creates a deferred loading stub for both image and debug info.
+ *
+ * @returns IPRT status code.
+ * @param pDbgMod The debug module.
+ * @param pfnDeferred The callback that will try load the image and
+ * debug info.
+ * @param cbImage The size of the image.
+ * @param hDbgCfg The debug config handle. Can be NIL. A
+ * reference will be retained.
+ * @param ppDeferred Where to return the instance data. Can be NULL.
+ */
+DECLHIDDEN(int) rtDbgModDeferredCreate(PRTDBGMODINT pDbgMod, PFNRTDBGMODDEFERRED pfnDeferred, RTUINTPTR cbImage,
+ RTDBGCFG hDbgCfg, PRTDBGMODDEFERRED *ppDeferred)
+{
+ AssertReturn(!pDbgMod->pDbgVt, VERR_DBG_MOD_IPE);
+
+ PRTDBGMODDEFERRED pDeferred = (PRTDBGMODDEFERRED)RTMemAllocZ(sizeof(*pDeferred));
+ if (!pDeferred)
+ return VERR_NO_MEMORY;
+
+ pDeferred->cbImage = cbImage;
+ pDeferred->cRefs = 1 + (pDbgMod->pImgVt == NULL);
+ if (hDbgCfg != NIL_RTDBGCFG)
+ RTDbgCfgRetain(hDbgCfg);
+ pDeferred->hDbgCfg = hDbgCfg;
+ pDeferred->pfnDeferred = pfnDeferred;
+
+ pDbgMod->pDbgVt = &g_rtDbgModVtDbgDeferred;
+ pDbgMod->pvDbgPriv = pDeferred;
+ if (!pDbgMod->pImgVt)
+ {
+ pDbgMod->pImgVt = &g_rtDbgModVtImgDeferred;
+ pDbgMod->pvImgPriv = pDeferred;
+ }
+ pDbgMod->fDeferred = true;
+ pDbgMod->fDeferredFailed = false;
+
+ if (ppDeferred)
+ *ppDeferred = pDeferred;
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
index b1757877..6e11da29 100644
--- a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -38,8 +38,13 @@
#include <iprt/list.h>
#include <iprt/log.h>
#include <iprt/mem.h>
+#define RTDBGMODDWARF_WITH_MEM_CACHE
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+# include <iprt/memcache.h>
+#endif
#include <iprt/path.h>
#include <iprt/string.h>
+#include <iprt/strcache.h>
#include "internal/dbgmod.h"
@@ -136,6 +141,8 @@
#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_hi_user UINT16_C(0xffff)
/** @} */
@@ -235,6 +242,8 @@
#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_hi_user UINT16_C(0x3fff)
/** @} */
@@ -279,6 +288,68 @@
/** @} */
+/** @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. */
+/** @} */
+
+
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
@@ -318,20 +389,38 @@ typedef enum krtDbgModDwarfSect
*/
typedef struct RTDWARFABBREV
{
- /** Whether this entry is filled in or not. */
- bool fFilled;
/** Whether there are children or not. */
bool fChildren;
/** The tag. */
uint16_t uTag;
/** Offset into the abbrev section of the specification pairs. */
uint32_t offSpec;
+ /** The abbreviation table offset this is entry is valid for.
+ * UINT32_MAX if not valid. */
+ uint32_t offAbbrev;
} RTDWARFABBREV;
/** Pointer to an abbreviation cache entry. */
typedef RTDWARFABBREV *PRTDWARFABBREV;
/** Pointer to a const abbreviation cache entry. */
typedef RTDWARFABBREV const *PCRTDWARFABBREV;
+/**
+ * Structure for gathering segment info.
+ */
+typedef struct RTDBGDWARFSEG
+{
+ /** The highest offset in the segment. */
+ uint64_t offHighest;
+ /** Calculated base address. */
+ uint64_t uBaseAddr;
+ /** Estimated The segment size. */
+ uint64_t cbSegment;
+ /** Segment number (RTLDRSEG::Sel16bit). */
+ RTSEL uSegment;
+} RTDBGDWARFSEG;
+/** Pointer to segment info. */
+typedef RTDBGDWARFSEG *PRTDBGDWARFSEG;
+
/**
* The instance data of the DWARF reader.
@@ -340,8 +429,12 @@ typedef struct RTDBGMODDWARF
{
/** The debug container containing doing the real work. */
RTDBGMOD hCnt;
- /** Pointer to back to the debug info module (no reference ofc). */
- PRTDBGMODINT pMod;
+ /** The image module (no reference). */
+ PRTDBGMODINT pImgMod;
+ /** The debug info module (no reference). */
+ PRTDBGMODINT pDbgInfoMod;
+ /** Nested image module (with reference ofc). */
+ PRTDBGMODINT pNestedMod;
/** DWARF debug info sections. */
struct
@@ -354,14 +447,14 @@ typedef struct RTDBGMODDWARF
void const *pv;
/** Set if present. */
bool fPresent;
+ /** The debug info ordinal number in the image file. */
+ uint32_t iDbgInfo;
} aSections[krtDbgModDwarfSect_End];
/** The offset into the abbreviation section of the current cache. */
uint32_t offCachedAbbrev;
/** The number of cached abbreviations we've allocated space for. */
uint32_t cCachedAbbrevsAlloced;
- /** Used for range checking cache lookups. */
- uint32_t cCachedAbbrevs;
/** Array of cached abbreviations, indexed by code. */
PRTDWARFABBREV paCachedAbbrevs;
/** Used by rtDwarfAbbrev_Lookup when the result is uncachable. */
@@ -369,6 +462,34 @@ typedef struct RTDBGMODDWARF
/** The list of compilation units (RTDWARFDIE). */
RTLISTANCHOR CompileUnitList;
+
+ /** Set if we have to use link addresses because the module does not have
+ * fixups (mach_kernel). */
+ bool fUseLinkAddress;
+ /** This is set to -1 if we're doing everything in one pass.
+ * Otherwise it's 1 or 2:
+ * - In pass 1, we collect segment info.
+ * - In pass 2, we add debug info to the container.
+ * The two pass parsing is necessary for watcom generated symbol files as
+ * these contains no information about the code and data segments in the
+ * image. So we have to figure out some approximate stuff based on the
+ * segments and offsets we encounter in the debug info. */
+ int8_t iWatcomPass;
+ /** Segment index hint. */
+ uint16_t iSegHint;
+ /** The number of segments in paSegs.
+ * (During segment copying, this is abused to count useful segments.) */
+ uint32_t cSegs;
+ /** Pointer to segments if iWatcomPass isn't -1. */
+ PRTDBGDWARFSEG paSegs;
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ /** DIE allocators. */
+ struct
+ {
+ RTMEMCACHE hMemCache;
+ uint32_t cbMax;
+ } aDieAllocators[2];
+#endif
} RTDBGMODDWARF;
/** Pointer to instance data of the DWARF reader. */
typedef RTDBGMODDWARF *PRTDBGMODDWARF;
@@ -424,6 +545,7 @@ typedef struct RTDWARFLINESTATE
bool fEpilogueBegin;
uint32_t uIsa;
uint32_t uDiscriminator;
+ RTSEL uSegment;
} Regs;
/** @} */
@@ -481,11 +603,12 @@ typedef FNRTDWARFATTRDECODER *PFNRTDWARFATTRDECODER;
typedef struct RTDWARFATTRDESC
{
/** The attribute. */
- uint8_t uAttr;
- /** The data member size and initialization method. */
- uint8_t cbInit;
+ uint16_t uAttr;
/** The data member offset. */
uint16_t off;
+ /** The data member size and initialization method. */
+ uint8_t cbInit;
+ uint8_t bPadding[3]; /**< Alignment padding. */
/** The decoder function. */
PFNRTDWARFATTRDECODER pfnDecoder;
} RTDWARFATTRDESC;
@@ -494,8 +617,9 @@ typedef struct RTDWARFATTRDESC
#define ATTR_ENTRY(a_uAttr, a_Struct, a_Member, a_Init, a_pfnDecoder) \
{ \
a_uAttr, \
- a_Init | ((uint8_t)RT_SIZEOFMEMB(a_Struct, a_Member) & ATTR_SIZE_MASK), \
(uint16_t)RT_OFFSETOF(a_Struct, a_Member), \
+ a_Init | ((uint8_t)RT_SIZEOFMEMB(a_Struct, a_Member) & ATTR_SIZE_MASK), \
+ { 0, 0, 0 }, \
a_pfnDecoder\
}
@@ -541,7 +665,11 @@ typedef struct RTDWARFDIE
uint8_t cDecodedAttrs;
/** The number of unknown or otherwise unhandled attributes. */
uint8_t cUnhandledAttrs;
- /** The date tag, indicating which union structure to use. */
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ /** The allocator index. */
+ uint8_t iAllocator;
+#endif
+ /** The die tag, indicating which union structure to use. */
uint16_t uTag;
/** Offset of the abbreviation specification (within debug_abbrev). */
uint32_t offSpec;
@@ -571,6 +699,7 @@ typedef struct RTDWARFADDRRANGE
uint8_t cAttrs : 2;
uint8_t fHaveLowAddress : 1;
uint8_t fHaveHighAddress : 1;
+ uint8_t fHaveHighIsAddress : 1;
uint8_t fHaveRanges : 1;
} RTDWARFADDRRANGE;
typedef RTDWARFADDRRANGE *PRTDWARFADDRRANGE;
@@ -602,6 +731,22 @@ typedef RTDWARFREF *PRTDWARFREF;
typedef RTDWARFREF const *PCRTDWARFREF;
+/**
+ * DWARF Location state.
+ */
+typedef struct RTDWARFLOCST
+{
+ /** The input cursor. */
+ RTDWARFCURSOR Cursor;
+ /** Points to the current top of the stack. Initial value -1. */
+ int32_t iTop;
+ /** The value stack. */
+ uint64_t auStack[64];
+} RTDWARFLOCST;
+/** Pointer to location state. */
+typedef RTDWARFLOCST *PRTDWARFLOCST;
+
+
/*******************************************************************************
* Internal Functions *
@@ -614,6 +759,7 @@ static FNRTDWARFATTRDECODER rtDwarfDecode_Reference;
static FNRTDWARFATTRDECODER rtDwarfDecode_SectOff;
static FNRTDWARFATTRDECODER rtDwarfDecode_String;
static FNRTDWARFATTRDECODER rtDwarfDecode_UnsignedInt;
+static FNRTDWARFATTRDECODER rtDwarfDecode_SegmentLoc;
/*******************************************************************************
@@ -635,7 +781,7 @@ typedef struct RTDWARFDIECOMPILEUNIT
/** The address range of the code belonging to this unit. */
RTDWARFADDRRANGE PcRange;
/** The language name. */
- uint8_t uLanguage;
+ uint16_t uLanguage;
/** The identifier case. */
uint8_t uIdentifierCase;
/** String are UTF-8 encoded. If not set, the encoding is
@@ -708,6 +854,10 @@ typedef struct RTDWARFDIESUBPROGRAM
RTDWARFADDRRANGE PcRange;
/** The first instruction in the function. */
RTDWARFADDR EntryPc;
+ /** Segment number (watcom). */
+ RTSEL uSegment;
+ /** Reference to the specification. */
+ RTDWARFREF SpecRef;
} RTDWARFDIESUBPROGRAM;
/** Pointer to a DW_TAG_subprogram DIE. */
typedef RTDWARFDIESUBPROGRAM *PRTDWARFDIESUBPROGRAM;
@@ -720,16 +870,66 @@ static const RTDWARFATTRDESC g_aSubProgramAttrs[] =
{
ATTR_ENTRY(DW_AT_name, RTDWARFDIESUBPROGRAM, pszName, ATTR_INIT_ZERO, rtDwarfDecode_String),
ATTR_ENTRY(DW_AT_linkage_name, RTDWARFDIESUBPROGRAM, pszLinkageName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+ ATTR_ENTRY(DW_AT_MIPS_linkage_name, RTDWARFDIESUBPROGRAM, pszLinkageName, ATTR_INIT_ZERO, rtDwarfDecode_String),
ATTR_ENTRY(DW_AT_low_pc, RTDWARFDIESUBPROGRAM, PcRange, ATTR_INIT_ZERO, rtDwarfDecode_LowHighPc),
ATTR_ENTRY(DW_AT_high_pc, RTDWARFDIESUBPROGRAM, PcRange, ATTR_INIT_ZERO, rtDwarfDecode_LowHighPc),
ATTR_ENTRY(DW_AT_ranges, RTDWARFDIESUBPROGRAM, PcRange, ATTR_INIT_ZERO, rtDwarfDecode_Ranges),
ATTR_ENTRY(DW_AT_entry_pc, RTDWARFDIESUBPROGRAM, EntryPc, ATTR_INIT_ZERO, rtDwarfDecode_Address),
+ ATTR_ENTRY(DW_AT_segment, RTDWARFDIESUBPROGRAM, uSegment, ATTR_INIT_ZERO, rtDwarfDecode_SegmentLoc),
+ ATTR_ENTRY(DW_AT_specification, RTDWARFDIESUBPROGRAM, SpecRef, ATTR_INIT_ZERO, rtDwarfDecode_Reference)
};
/** RTDWARFDIESUBPROGRAM description. */
static const RTDWARFDIEDESC g_SubProgramDesc = DIE_DESC_INIT(RTDWARFDIESUBPROGRAM, g_aSubProgramAttrs);
+/** RTDWARFDIESUBPROGRAM attributes for the specification hack. */
+static const RTDWARFATTRDESC g_aSubProgramSpecHackAttrs[] =
+{
+ ATTR_ENTRY(DW_AT_name, RTDWARFDIESUBPROGRAM, pszName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+ ATTR_ENTRY(DW_AT_linkage_name, RTDWARFDIESUBPROGRAM, pszLinkageName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+ ATTR_ENTRY(DW_AT_MIPS_linkage_name, RTDWARFDIESUBPROGRAM, pszLinkageName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+};
+
+/** RTDWARFDIESUBPROGRAM description for the specification hack. */
+static const RTDWARFDIEDESC g_SubProgramSpecHackDesc = DIE_DESC_INIT(RTDWARFDIESUBPROGRAM, g_aSubProgramSpecHackAttrs);
+
+
+/**
+ * DW_TAG_label.
+ */
+typedef struct RTDWARFDIELABEL
+{
+ /** The DIE core structure. */
+ RTDWARFDIE Core;
+ /** The name. */
+ const char *pszName;
+ /** The address of the first instruction. */
+ RTDWARFADDR Address;
+ /** Segment number (watcom). */
+ RTSEL uSegment;
+ /** Externally visible? */
+ bool fExternal;
+} RTDWARFDIELABEL;
+/** Pointer to a DW_TAG_label DIE. */
+typedef RTDWARFDIELABEL *PRTDWARFDIELABEL;
+/** Pointer to a const DW_TAG_label DIE. */
+typedef RTDWARFDIELABEL const *PCRTDWARFDIELABEL;
+
+
+/** RTDWARFDIESUBPROGRAM attributes. */
+static const RTDWARFATTRDESC g_aLabelAttrs[] =
+{
+ ATTR_ENTRY(DW_AT_name, RTDWARFDIELABEL, pszName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+ ATTR_ENTRY(DW_AT_low_pc, RTDWARFDIELABEL, Address, ATTR_INIT_ZERO, rtDwarfDecode_Address),
+ ATTR_ENTRY(DW_AT_segment, RTDWARFDIELABEL, uSegment, ATTR_INIT_ZERO, rtDwarfDecode_SegmentLoc),
+ ATTR_ENTRY(DW_AT_external, RTDWARFDIELABEL, fExternal, ATTR_INIT_ZERO, rtDwarfDecode_Bool)
+};
+
+/** RTDWARFDIESUBPROGRAM description. */
+static const RTDWARFDIEDESC g_LabelDesc = DIE_DESC_INIT(RTDWARFDIELABEL, g_aLabelAttrs);
+
+
/**
* Tag names and descriptors.
*/
@@ -756,7 +956,7 @@ static const struct RTDWARFTAGDESC
TAGDESC_EMPTY(),
TAGDESC_CORE(TAG_imported_declaration), /* 0x08 */
TAGDESC_EMPTY(),
- TAGDESC_CORE(TAG_label),
+ TAGDESC(TAG_label, &g_LabelDesc),
TAGDESC_CORE(TAG_lexical_block),
TAGDESC_EMPTY(), /* 0x0c */
TAGDESC_CORE(TAG_member),
@@ -820,19 +1020,226 @@ static const struct RTDWARFTAGDESC
};
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int rtDwarfInfo_ParseDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie, PCRTDWARFDIEDESC pDieDesc,
+ PRTDWARFCURSOR pCursor, PCRTDWARFABBREV pAbbrev, bool fInitDie);
+
+
+
+#if defined(LOG_ENABLED) || defined(RT_STRICT)
+
+/**
+ * Turns a tag value into a string for logging purposes.
+ *
+ * @returns String name.
+ * @param uTag The tag.
+ */
+static const char *rtDwarfLog_GetTagName(uint32_t uTag)
+{
+ if (uTag < RT_ELEMENTS(g_aTagDescs))
+ {
+ const char *pszTag = g_aTagDescs[uTag].pszName;
+ if (pszTag)
+ return pszTag;
+ }
+
+ static char s_szStatic[32];
+ RTStrPrintf(s_szStatic, sizeof(s_szStatic),"DW_TAG_%#x", uTag);
+ return s_szStatic;
+}
+
+
+/**
+ * Turns an attributevalue into a string for logging purposes.
+ *
+ * @returns String name.
+ * @param uAttr The attribute.
+ */
+static const char *rtDwarfLog_AttrName(uint32_t uAttr)
+{
+ switch (uAttr)
+ {
+ RT_CASE_RET_STR(DW_AT_sibling);
+ RT_CASE_RET_STR(DW_AT_location);
+ RT_CASE_RET_STR(DW_AT_name);
+ RT_CASE_RET_STR(DW_AT_ordering);
+ RT_CASE_RET_STR(DW_AT_byte_size);
+ RT_CASE_RET_STR(DW_AT_bit_offset);
+ RT_CASE_RET_STR(DW_AT_bit_size);
+ RT_CASE_RET_STR(DW_AT_stmt_list);
+ RT_CASE_RET_STR(DW_AT_low_pc);
+ RT_CASE_RET_STR(DW_AT_high_pc);
+ RT_CASE_RET_STR(DW_AT_language);
+ RT_CASE_RET_STR(DW_AT_discr);
+ RT_CASE_RET_STR(DW_AT_discr_value);
+ RT_CASE_RET_STR(DW_AT_visibility);
+ RT_CASE_RET_STR(DW_AT_import);
+ RT_CASE_RET_STR(DW_AT_string_length);
+ RT_CASE_RET_STR(DW_AT_common_reference);
+ RT_CASE_RET_STR(DW_AT_comp_dir);
+ RT_CASE_RET_STR(DW_AT_const_value);
+ RT_CASE_RET_STR(DW_AT_containing_type);
+ RT_CASE_RET_STR(DW_AT_default_value);
+ RT_CASE_RET_STR(DW_AT_inline);
+ RT_CASE_RET_STR(DW_AT_is_optional);
+ RT_CASE_RET_STR(DW_AT_lower_bound);
+ RT_CASE_RET_STR(DW_AT_producer);
+ RT_CASE_RET_STR(DW_AT_prototyped);
+ RT_CASE_RET_STR(DW_AT_return_addr);
+ RT_CASE_RET_STR(DW_AT_start_scope);
+ RT_CASE_RET_STR(DW_AT_bit_stride);
+ RT_CASE_RET_STR(DW_AT_upper_bound);
+ RT_CASE_RET_STR(DW_AT_abstract_origin);
+ RT_CASE_RET_STR(DW_AT_accessibility);
+ RT_CASE_RET_STR(DW_AT_address_class);
+ RT_CASE_RET_STR(DW_AT_artificial);
+ RT_CASE_RET_STR(DW_AT_base_types);
+ RT_CASE_RET_STR(DW_AT_calling_convention);
+ RT_CASE_RET_STR(DW_AT_count);
+ RT_CASE_RET_STR(DW_AT_data_member_location);
+ RT_CASE_RET_STR(DW_AT_decl_column);
+ RT_CASE_RET_STR(DW_AT_decl_file);
+ RT_CASE_RET_STR(DW_AT_decl_line);
+ RT_CASE_RET_STR(DW_AT_declaration);
+ RT_CASE_RET_STR(DW_AT_discr_list);
+ RT_CASE_RET_STR(DW_AT_encoding);
+ RT_CASE_RET_STR(DW_AT_external);
+ RT_CASE_RET_STR(DW_AT_frame_base);
+ RT_CASE_RET_STR(DW_AT_friend);
+ RT_CASE_RET_STR(DW_AT_identifier_case);
+ RT_CASE_RET_STR(DW_AT_macro_info);
+ RT_CASE_RET_STR(DW_AT_namelist_item);
+ RT_CASE_RET_STR(DW_AT_priority);
+ RT_CASE_RET_STR(DW_AT_segment);
+ RT_CASE_RET_STR(DW_AT_specification);
+ RT_CASE_RET_STR(DW_AT_static_link);
+ RT_CASE_RET_STR(DW_AT_type);
+ RT_CASE_RET_STR(DW_AT_use_location);
+ RT_CASE_RET_STR(DW_AT_variable_parameter);
+ RT_CASE_RET_STR(DW_AT_virtuality);
+ RT_CASE_RET_STR(DW_AT_vtable_elem_location);
+ RT_CASE_RET_STR(DW_AT_allocated);
+ RT_CASE_RET_STR(DW_AT_associated);
+ RT_CASE_RET_STR(DW_AT_data_location);
+ RT_CASE_RET_STR(DW_AT_byte_stride);
+ RT_CASE_RET_STR(DW_AT_entry_pc);
+ RT_CASE_RET_STR(DW_AT_use_UTF8);
+ RT_CASE_RET_STR(DW_AT_extension);
+ RT_CASE_RET_STR(DW_AT_ranges);
+ RT_CASE_RET_STR(DW_AT_trampoline);
+ RT_CASE_RET_STR(DW_AT_call_column);
+ RT_CASE_RET_STR(DW_AT_call_file);
+ RT_CASE_RET_STR(DW_AT_call_line);
+ RT_CASE_RET_STR(DW_AT_description);
+ RT_CASE_RET_STR(DW_AT_binary_scale);
+ RT_CASE_RET_STR(DW_AT_decimal_scale);
+ RT_CASE_RET_STR(DW_AT_small);
+ RT_CASE_RET_STR(DW_AT_decimal_sign);
+ RT_CASE_RET_STR(DW_AT_digit_count);
+ RT_CASE_RET_STR(DW_AT_picture_string);
+ RT_CASE_RET_STR(DW_AT_mutable);
+ RT_CASE_RET_STR(DW_AT_threads_scaled);
+ RT_CASE_RET_STR(DW_AT_explicit);
+ RT_CASE_RET_STR(DW_AT_object_pointer);
+ RT_CASE_RET_STR(DW_AT_endianity);
+ RT_CASE_RET_STR(DW_AT_elemental);
+ RT_CASE_RET_STR(DW_AT_pure);
+ RT_CASE_RET_STR(DW_AT_recursive);
+ RT_CASE_RET_STR(DW_AT_signature);
+ RT_CASE_RET_STR(DW_AT_main_subprogram);
+ RT_CASE_RET_STR(DW_AT_data_bit_offset);
+ RT_CASE_RET_STR(DW_AT_const_expr);
+ RT_CASE_RET_STR(DW_AT_enum_class);
+ RT_CASE_RET_STR(DW_AT_linkage_name);
+ RT_CASE_RET_STR(DW_AT_MIPS_linkage_name);
+ }
+ static char s_szStatic[32];
+ RTStrPrintf(s_szStatic, sizeof(s_szStatic),"DW_AT_%#x", uAttr);
+ return s_szStatic;
+}
+
+
+/**
+ * Turns a form value into a string for logging purposes.
+ *
+ * @returns String name.
+ * @param uForm The form.
+ */
+static const char *rtDwarfLog_FormName(uint32_t uForm)
+{
+ switch (uForm)
+ {
+ RT_CASE_RET_STR(DW_FORM_addr);
+ RT_CASE_RET_STR(DW_FORM_block2);
+ RT_CASE_RET_STR(DW_FORM_block4);
+ RT_CASE_RET_STR(DW_FORM_data2);
+ RT_CASE_RET_STR(DW_FORM_data4);
+ RT_CASE_RET_STR(DW_FORM_data8);
+ RT_CASE_RET_STR(DW_FORM_string);
+ RT_CASE_RET_STR(DW_FORM_block);
+ RT_CASE_RET_STR(DW_FORM_block1);
+ RT_CASE_RET_STR(DW_FORM_data1);
+ RT_CASE_RET_STR(DW_FORM_flag);
+ RT_CASE_RET_STR(DW_FORM_sdata);
+ RT_CASE_RET_STR(DW_FORM_strp);
+ RT_CASE_RET_STR(DW_FORM_udata);
+ RT_CASE_RET_STR(DW_FORM_ref_addr);
+ RT_CASE_RET_STR(DW_FORM_ref1);
+ RT_CASE_RET_STR(DW_FORM_ref2);
+ RT_CASE_RET_STR(DW_FORM_ref4);
+ RT_CASE_RET_STR(DW_FORM_ref8);
+ RT_CASE_RET_STR(DW_FORM_ref_udata);
+ RT_CASE_RET_STR(DW_FORM_indirect);
+ RT_CASE_RET_STR(DW_FORM_sec_offset);
+ RT_CASE_RET_STR(DW_FORM_exprloc);
+ RT_CASE_RET_STR(DW_FORM_flag_present);
+ RT_CASE_RET_STR(DW_FORM_ref_sig8);
+ }
+ static char s_szStatic[32];
+ RTStrPrintf(s_szStatic, sizeof(s_szStatic),"DW_FORM_%#x", uForm);
+ return s_szStatic;
+}
+
+#endif /* LOG_ENABLED || RT_STRICT */
+
+
+
/** @callback_method_impl{FNRTLDRENUMSEGS} */
-static DECLCALLBACK(int) rtDbgModHlpAddSegmentCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
+static DECLCALLBACK(int) rtDbgModDwarfScanSegmentsCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
{
- PRTDBGMODINT pMod = (PRTDBGMODINT)pvUser;
+ PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pvUser;
Log(("Segment %.*s: LinkAddress=%#llx RVA=%#llx cb=%#llx\n",
- pSeg->cchName, pSeg->pchName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
+ pSeg->cchName, pSeg->pszName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
+ NOREF(hLdrMod);
+
+ /* Count relevant segments. */
+ if (pSeg->RVA != NIL_RTLDRADDR)
+ pThis->cSegs++;
+
+ return VINF_SUCCESS;
+}
+
+
+/** @callback_method_impl{FNRTLDRENUMSEGS} */
+static DECLCALLBACK(int) rtDbgModDwarfAddSegmentsCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
+{
+ PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pvUser;
+ Log(("Segment %.*s: LinkAddress=%#llx RVA=%#llx cb=%#llx cbMapped=%#llx\n",
+ pSeg->cchName, pSeg->pszName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb, pSeg->cbMapped));
NOREF(hLdrMod);
+ Assert(pSeg->cchName > 0);
+ Assert(!pSeg->pszName[pSeg->cchName]);
+
+ /* If the segment doesn't have a mapping, just add a dummy so the indexing
+ works out correctly (same as for the image). */
+ if (pSeg->RVA == NIL_RTLDRADDR)
+ return RTDbgModSegmentAdd(pThis->hCnt, 0, 0, pSeg->pszName, 0 /*fFlags*/, NULL);
+
+ /* The link address is 0 for all segments in a relocatable ELF image. */
RTLDRADDR cb = RT_MAX(pSeg->cb, pSeg->cbMapped);
-#if 1
- return pMod->pDbgVt->pfnSegmentAdd(pMod, pSeg->RVA, cb, pSeg->pchName, pSeg->cchName, 0 /*fFlags*/, NULL);
-#else
- return pMod->pDbgVt->pfnSegmentAdd(pMod, pSeg->LinkAddress, cb, pSeg->pchName, pSeg->cchName, 0 /*fFlags*/, NULL);
-#endif
+ return RTDbgModSegmentAdd(pThis->hCnt, pSeg->RVA, cb, pSeg->pszName, 0 /*fFlags*/, NULL);
}
@@ -840,15 +1247,158 @@ static DECLCALLBACK(int) rtDbgModHlpAddSegmentCallback(RTLDRMOD hLdrMod, PCRTLDR
* Calls pfnSegmentAdd for each segment in the executable image.
*
* @returns IPRT status code.
- * @param pMod The debug module.
+ * @param pThis The DWARF instance.
*/
-DECLHIDDEN(int) rtDbgModHlpAddSegmentsFromImage(PRTDBGMODINT pMod)
+static int rtDbgModDwarfAddSegmentsFromImage(PRTDBGMODDWARF pThis)
{
- AssertReturn(pMod->pImgVt, VERR_INTERNAL_ERROR_2);
- return pMod->pImgVt->pfnEnumSegments(pMod, rtDbgModHlpAddSegmentCallback, pMod);
+ AssertReturn(pThis->pImgMod && pThis->pImgMod->pImgVt, VERR_INTERNAL_ERROR_2);
+ Assert(!pThis->cSegs);
+ int rc = pThis->pImgMod->pImgVt->pfnEnumSegments(pThis->pImgMod, rtDbgModDwarfScanSegmentsCallback, pThis);
+ if (RT_SUCCESS(rc))
+ {
+ if (pThis->cSegs == 0)
+ pThis->iWatcomPass = 1;
+ else
+ {
+ pThis->cSegs = 0;
+ pThis->iWatcomPass = -1;
+ rc = pThis->pImgMod->pImgVt->pfnEnumSegments(pThis->pImgMod, rtDbgModDwarfAddSegmentsCallback, pThis);
+ }
+ }
+
+ return rc;
}
+/**
+ * Looks up a segment.
+ *
+ * @returns Pointer to the segment on success, NULL if not found.
+ * @param pThis The DWARF instance.
+ * @param uSeg The segment number / selector.
+ */
+static PRTDBGDWARFSEG rtDbgModDwarfFindSegment(PRTDBGMODDWARF pThis, RTSEL uSeg)
+{
+ uint32_t cSegs = pThis->cSegs;
+ uint32_t iSeg = pThis->iSegHint;
+ PRTDBGDWARFSEG paSegs = pThis->paSegs;
+ if ( iSeg < cSegs
+ && paSegs[iSeg].uSegment == uSeg)
+ return &paSegs[iSeg];
+
+ for (iSeg = 0; iSeg < cSegs; iSeg++)
+ if (uSeg == paSegs[iSeg].uSegment)
+ {
+ pThis->iSegHint = iSeg;
+ return &paSegs[iSeg];
+ }
+
+ AssertFailed();
+ return NULL;
+}
+
+
+/**
+ * Record a segment:offset during pass 1.
+ *
+ * @returns IPRT status code.
+ * @param pThis The DWARF instance.
+ * @param uSeg The segment number / selector.
+ * @param offSeg The segment offset.
+ */
+static int rtDbgModDwarfRecordSegOffset(PRTDBGMODDWARF pThis, RTSEL uSeg, uint64_t offSeg)
+{
+ /* Look up the segment. */
+ uint32_t cSegs = pThis->cSegs;
+ uint32_t iSeg = pThis->iSegHint;
+ PRTDBGDWARFSEG paSegs = pThis->paSegs;
+ if ( iSeg >= cSegs
+ || paSegs[iSeg].uSegment != uSeg)
+ {
+ for (iSeg = 0; iSeg < cSegs; iSeg++)
+ if (uSeg <= paSegs[iSeg].uSegment)
+ break;
+ if ( iSeg >= cSegs
+ || paSegs[iSeg].uSegment != uSeg)
+ {
+ /* Add */
+ void *pvNew = RTMemRealloc(paSegs, (pThis->cSegs + 1) * sizeof(paSegs[0]));
+ if (!pvNew)
+ return VERR_NO_MEMORY;
+ pThis->paSegs = paSegs = (PRTDBGDWARFSEG)pvNew;
+ if (iSeg != cSegs)
+ memmove(&paSegs[iSeg + 1], &paSegs[iSeg], (cSegs - iSeg) * sizeof(paSegs[0]));
+ paSegs[iSeg].offHighest = offSeg;
+ paSegs[iSeg].uBaseAddr = 0;
+ paSegs[iSeg].cbSegment = 0;
+ paSegs[iSeg].uSegment = uSeg;
+ pThis->cSegs++;
+ }
+
+ pThis->iSegHint = iSeg;
+ }
+
+ /* Increase it's range? */
+ if (paSegs[iSeg].offHighest < offSeg)
+ {
+ Log3(("rtDbgModDwarfRecordSegOffset: iSeg=%d uSeg=%#06x offSeg=%#llx\n", iSeg, uSeg, offSeg));
+ paSegs[iSeg].offHighest = offSeg;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Calls pfnSegmentAdd for each segment in the executable image.
+ *
+ * @returns IPRT status code.
+ * @param pThis The DWARF instance.
+ */
+static int rtDbgModDwarfAddSegmentsFromPass1(PRTDBGMODDWARF pThis)
+{
+ AssertReturn(pThis->cSegs, VERR_DWARF_BAD_INFO);
+ uint32_t const cSegs = pThis->cSegs;
+ PRTDBGDWARFSEG paSegs = pThis->paSegs;
+
+ /*
+ * Are the segments assigned more or less in numerical order?
+ */
+ if ( paSegs[0].uSegment < 16U
+ && paSegs[cSegs - 1].uSegment - paSegs[0].uSegment + 1U <= cSegs + 16U)
+ {
+ /** @todo heuristics, plase. */
+ AssertFailedReturn(VERR_DWARF_TODO);
+
+ }
+ /*
+ * Assume DOS segmentation.
+ */
+ else
+ {
+ for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
+ paSegs[iSeg].uBaseAddr = (uint32_t)paSegs[iSeg].uSegment << 16;
+ for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
+ paSegs[iSeg].cbSegment = paSegs[iSeg].offHighest;
+ }
+
+ /*
+ * Add them.
+ */
+ for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
+ {
+ Log3(("rtDbgModDwarfAddSegmentsFromPass1: Seg#%u: %#010llx LB %#llx uSegment=%#x\n",
+ iSeg, paSegs[iSeg].uBaseAddr, paSegs[iSeg].cbSegment, paSegs[iSeg].uSegment));
+ char szName[32];
+ RTStrPrintf(szName, sizeof(szName), "seg-%#04xh", paSegs[iSeg].uSegment);
+ int rc = RTDbgModSegmentAdd(pThis->hCnt, paSegs[iSeg].uBaseAddr, paSegs[iSeg].cbSegment,
+ szName, 0 /*fFlags*/, NULL);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
/**
@@ -887,8 +1437,11 @@ static int rtDbgModDwarfLoadSection(PRTDBGMODDWARF pThis, krtDbgModDwarfSect enm
/*
* Do the job.
*/
- return pThis->pMod->pImgVt->pfnMapPart(pThis->pMod, pThis->aSections[enmSect].offFile, pThis->aSections[enmSect].cb,
- &pThis->aSections[enmSect].pv);
+ return pThis->pDbgInfoMod->pImgVt->pfnMapPart(pThis->pDbgInfoMod,
+ pThis->aSections[enmSect].iDbgInfo,
+ pThis->aSections[enmSect].offFile,
+ pThis->aSections[enmSect].cb,
+ &pThis->aSections[enmSect].pv);
}
@@ -905,7 +1458,7 @@ static int rtDbgModDwarfUnloadSection(PRTDBGMODDWARF pThis, krtDbgModDwarfSect e
if (!pThis->aSections[enmSect].pv)
return VINF_SUCCESS;
- int rc = pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[enmSect].cb, &pThis->aSections[enmSect].pv);
+ int rc = pThis->pDbgInfoMod->pImgVt->pfnUnmapPart(pThis->pDbgInfoMod, pThis->aSections[enmSect].cb, &pThis->aSections[enmSect].pv);
AssertRC(rc);
return rc;
}
@@ -934,14 +1487,28 @@ static int rtDbgModDwarfStringToUtf8(PRTDBGMODDWARF pThis, char **ppsz)
*
* @returns IPRT status code.
* @param pThis The DWARF instance.
+ * @param uSegment The segment, 0 if not applicable.
* @param LinkAddress The address to convert..
* @param piSeg The segment index.
* @param poffSeg Where to return the segment offset.
*/
-static int rtDbgModDwarfLinkAddressToSegOffset(PRTDBGMODDWARF pThis, uint64_t LinkAddress,
+static int rtDbgModDwarfLinkAddressToSegOffset(PRTDBGMODDWARF pThis, RTSEL uSegment, uint64_t LinkAddress,
PRTDBGSEGIDX piSeg, PRTLDRADDR poffSeg)
{
- return pThis->pMod->pImgVt->pfnLinkAddressToSegOffset(pThis->pMod, LinkAddress, piSeg, poffSeg);
+ if (pThis->paSegs)
+ {
+ PRTDBGDWARFSEG pSeg = rtDbgModDwarfFindSegment(pThis, uSegment);
+ if (pSeg)
+ {
+ *piSeg = pSeg - pThis->paSegs;
+ *poffSeg = LinkAddress;
+ return VINF_SUCCESS;
+ }
+ }
+
+ if (pThis->fUseLinkAddress)
+ return pThis->pImgMod->pImgVt->pfnLinkAddressToSegOffset(pThis->pImgMod, LinkAddress, piSeg, poffSeg);
+ return pThis->pImgMod->pImgVt->pfnRvaToSegOffset(pThis->pImgMod, LinkAddress, piSeg, poffSeg);
}
@@ -1348,6 +1915,32 @@ static uint64_t rtDwarfCursor_GetVarSizedU(PRTDWARFCURSOR pCursor, size_t cbValu
}
+#if 0 /* unused */
+/**
+ * Gets the pointer to a variable size block and advances the cursor.
+ *
+ * @returns Pointer to the block at the current cursor location. On error
+ * RTDWARFCURSOR::rc is set and NULL returned.
+ * @param pCursor The cursor.
+ * @param cbBlock The block size.
+ */
+static const uint8_t *rtDwarfCursor_GetBlock(PRTDWARFCURSOR pCursor, uint32_t cbBlock)
+{
+ if (cbBlock > pCursor->cbUnitLeft)
+ {
+ pCursor->rc = VERR_DWARF_UNEXPECTED_END;
+ return NULL;
+ }
+
+ uint8_t const *pb = &pCursor->pb[0];
+ pCursor->pb += cbBlock;
+ pCursor->cbUnitLeft -= cbBlock;
+ pCursor->cbLeft -= cbBlock;
+ return pb;
+}
+#endif
+
+
/**
* Reads an unsigned DWARF half number.
*
@@ -1477,6 +2070,7 @@ static uint32_t rtDwarfCursor_CalcSectOffsetU32(PRTDWARFCURSOR pCursor)
uint32_t offRet = (uint32_t)off;
if (offRet != off)
{
+ AssertFailed();
pCursor->rc = VERR_OUT_OF_RANGE;
offRet = UINT32_MAX;
}
@@ -1644,6 +2238,39 @@ static int rtDwarfCursor_InitWithOffset(PRTDWARFCURSOR pCursor, PRTDBGMODDWARF p
/**
+ * Initialize a cursor for a block (subsection) retrieved from the given cursor.
+ *
+ * The parent cursor will be advanced past the block.
+ *
+ * @returns IPRT status code.
+ * @param pCursor The cursor.
+ * @param pParent The parent cursor. Will be moved by @a cbBlock.
+ * @param cbBlock The size of the block the new cursor should
+ * cover.
+ */
+static int rtDwarfCursor_InitForBlock(PRTDWARFCURSOR pCursor, PRTDWARFCURSOR pParent, uint32_t cbBlock)
+{
+ if (RT_FAILURE(pParent->rc))
+ return pParent->rc;
+ if (pParent->cbUnitLeft < cbBlock)
+ {
+ Log(("rtDwarfCursor_InitForBlock: cbUnitLeft=%#x < cbBlock=%#x \n", pParent->cbUnitLeft, cbBlock));
+ return VERR_DWARF_BAD_POS;
+ }
+
+ *pCursor = *pParent;
+ pCursor->cbLeft = cbBlock;
+ pCursor->cbUnitLeft = cbBlock;
+
+ pParent->pb += cbBlock;
+ pParent->cbLeft -= cbBlock;
+ pParent->cbUnitLeft -= cbBlock;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
* Deletes a section reader initialized by rtDwarfCursor_Init.
*
* @returns @a rcOther or RTDWARCURSOR::rc.
@@ -1730,22 +2357,32 @@ static int rtDwarfLine_DefineFileName(PRTDWARFLINESTATE pLnState, const char *ps
*/
static int rtDwarfLine_AddLine(PRTDWARFLINESTATE pLnState, uint32_t offOpCode)
{
- const char *pszFile = pLnState->Regs.iFile < pLnState->cFileNames
- ? pLnState->papszFileNames[pLnState->Regs.iFile]
- : "<bad file name index>";
- NOREF(offOpCode);
-
- RTDBGSEGIDX iSeg;
- RTUINTPTR offSeg;
- int rc = rtDbgModDwarfLinkAddressToSegOffset(pLnState->pDwarfMod, pLnState->Regs.uAddress, &iSeg, &offSeg);
- if (RT_SUCCESS(rc))
+ PRTDBGMODDWARF pThis = pLnState->pDwarfMod;
+ int rc;
+ if (pThis->iWatcomPass == 1)
+ rc = rtDbgModDwarfRecordSegOffset(pThis, pLnState->Regs.uSegment, pLnState->Regs.uAddress + 1);
+ else
{
- Log2(("rtDwarfLine_AddLine: %x:%08llx (%#llx) %s(%d) [offOpCode=%08x]\n", iSeg, offSeg, pLnState->Regs.uAddress, pszFile, pLnState->Regs.uLine, offOpCode));
- rc = RTDbgModLineAdd(pLnState->pDwarfMod->hCnt, pszFile, pLnState->Regs.uLine, iSeg, offSeg, NULL);
+ const char *pszFile = pLnState->Regs.iFile < pLnState->cFileNames
+ ? pLnState->papszFileNames[pLnState->Regs.iFile]
+ : "<bad file name index>";
+ NOREF(offOpCode);
+
+ RTDBGSEGIDX iSeg;
+ RTUINTPTR offSeg;
+ rc = rtDbgModDwarfLinkAddressToSegOffset(pLnState->pDwarfMod, pLnState->Regs.uSegment, pLnState->Regs.uAddress,
+ &iSeg, &offSeg); /*AssertRC(rc);*/
+ if (RT_SUCCESS(rc))
+ {
+ Log2(("rtDwarfLine_AddLine: %x:%08llx (%#llx) %s(%d) [offOpCode=%08x]\n", iSeg, offSeg, pLnState->Regs.uAddress, pszFile, pLnState->Regs.uLine, offOpCode));
+ rc = RTDbgModLineAdd(pLnState->pDwarfMod->hCnt, pszFile, pLnState->Regs.uLine, iSeg, offSeg, NULL);
- /* Ignore address conflicts for now. */
- if (rc == VERR_DBG_ADDRESS_CONFLICT)
- rc = VINF_SUCCESS;
+ /* Ignore address conflicts for now. */
+ if (rc == VERR_DBG_ADDRESS_CONFLICT)
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VINF_SUCCESS; /* ignore failure */
}
pLnState->Regs.fBasicBlock = false;
@@ -1775,6 +2412,7 @@ static void rtDwarfLine_ResetState(PRTDWARFLINESTATE pLnState)
pLnState->Regs.fEpilogueBegin = false;
pLnState->Regs.uIsa = 0;
pLnState->Regs.uDiscriminator = 0;
+ pLnState->Regs.uSegment = 0;
}
@@ -1811,7 +2449,7 @@ static int rtDwarfLine_RunProgram(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCu
int32_t const cLineDelta = bOpCode % pLnState->Hdr.u8LineRange + (int32_t)pLnState->Hdr.s8LineBase;
bOpCode /= pLnState->Hdr.u8LineRange;
- uint64_t uTmp = bOpCode + pLnState->Regs.idxOp + bOpCode;
+ uint64_t uTmp = bOpCode + pLnState->Regs.idxOp;
uint64_t const cAddressDelta = uTmp / pLnState->Hdr.cMaxOpsPerInstr * pLnState->Hdr.cbMinInstr;
uint64_t const cOpIndexDelta = uTmp % pLnState->Hdr.cMaxOpsPerInstr;
@@ -1954,6 +2592,7 @@ static int rtDwarfLine_RunProgram(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCu
rc = rtDwarfCursor_AdvanceToPos(pCursor, pbEndOfInstr);
if (RT_SUCCESS(rc))
rc = rtDwarfLine_DefineFileName(pLnState, pszFilename, idxInc);
+ break;
}
/*
@@ -1971,9 +2610,9 @@ static int rtDwarfLine_RunProgram(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCu
else
{
uint64_t uSeg = rtDwarfCursor_GetVarSizedU(pCursor, cbInstr - 1, UINT64_MAX);
- Log2(("%08x: DW_LNE_set_segment: %ll#x - Watcom Extension\n", offOpCode, uSeg));
- NOREF(uSeg);
- /** @todo make use of this? */
+ Log2(("%08x: DW_LNE_set_segment: %#llx, cbInstr=%#x - Watcom Extension\n", offOpCode, uSeg, cbInstr));
+ pLnState->Regs.uSegment = (RTSEL)uSeg;
+ AssertStmt(pLnState->Regs.uSegment == uSeg, rc = VERR_DWARF_BAD_INFO);
}
break;
@@ -2205,7 +2844,7 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
bool fFillCache = true;
if (pThis->cCachedAbbrevsAlloced < uCode)
{
- if (uCode > _64K)
+ if (uCode >= _64K)
fFillCache = false;
else
{
@@ -2215,8 +2854,11 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
fFillCache = false;
else
{
- pThis->cCachedAbbrevsAlloced = cNew;
+ Log(("rtDwarfAbbrev_LookupMiss: Growing from %u to %u...\n", pThis->cCachedAbbrevsAlloced, cNew));
pThis->paCachedAbbrevs = (PRTDWARFABBREV)pv;
+ for (uint32_t i = pThis->cCachedAbbrevsAlloced; i < cNew; i++)
+ pThis->paCachedAbbrevs[i].offAbbrev = UINT32_MAX;
+ pThis->cCachedAbbrevsAlloced = cNew;
}
}
}
@@ -2234,52 +2876,61 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
{
/*
* Search for the entry and fill the cache while doing so.
+ * We assume that abbreviation codes for a unit will stop when we see
+ * zero code or when the code value drops.
*/
+ uint32_t uPrevCode = 0;
for (;;)
{
- /* Read the 'header'. */
- uint32_t const uCurCode = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
- uint32_t const uCurTag = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
- uint8_t const uChildren = rtDwarfCursor_GetU8(&Cursor, 0);
- if (RT_FAILURE(Cursor.rc))
- break;
- if ( uCurTag > 0xffff
- || uChildren > 1)
+ /* Read the 'header'. Skipping zero code bytes. */
+ uint32_t const uCurCode = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
+ if (pRet && (uCurCode == 0 || uCurCode < uPrevCode))
+ break; /* probably end of unit. */
+ if (uCurCode != 0)
{
- Cursor.rc = VERR_DWARF_BAD_ABBREV;
- break;
- }
-
- /* Cache it? */
- if (uCurCode <= pThis->cCachedAbbrevsAlloced)
- {
- PRTDWARFABBREV pEntry = &pThis->paCachedAbbrevs[uCurCode - 1];
- while (pThis->cCachedAbbrevs < uCurCode)
+ uint32_t const uCurTag = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
+ uint8_t const uChildren = rtDwarfCursor_GetU8(&Cursor, 0);
+ if (RT_FAILURE(Cursor.rc))
+ break;
+ if ( uCurTag > 0xffff
+ || uChildren > 1)
{
- pThis->paCachedAbbrevs[pThis->cCachedAbbrevs].fFilled = false;
- pThis->cCachedAbbrevs++;
+ Cursor.rc = VERR_DWARF_BAD_ABBREV;
+ break;
}
- pEntry->fFilled = true;
- pEntry->fChildren = RT_BOOL(uChildren);
- pEntry->uTag = uCurTag;
- pEntry->offSpec = rtDwarfCursor_CalcSectOffsetU32(&Cursor);
-
- if (uCurCode == uCode)
+ /* Cache it? */
+ if (uCurCode <= pThis->cCachedAbbrevsAlloced)
{
- pRet = pEntry;
- if (uCurCode == pThis->cCachedAbbrevsAlloced)
- break;
+ PRTDWARFABBREV pEntry = &pThis->paCachedAbbrevs[uCurCode - 1];
+ if (pEntry->offAbbrev != pThis->offCachedAbbrev)
+ {
+ pEntry->offAbbrev = pThis->offCachedAbbrev;
+ pEntry->fChildren = RT_BOOL(uChildren);
+ pEntry->uTag = uCurTag;
+ pEntry->offSpec = rtDwarfCursor_CalcSectOffsetU32(&Cursor);
+
+ if (uCurCode == uCode)
+ {
+ Assert(!pRet);
+ pRet = pEntry;
+ if (uCurCode == pThis->cCachedAbbrevsAlloced)
+ break;
+ }
+ }
+ else if (pRet)
+ break; /* Next unit, don't cache more. */
+ /* else: We're growing the cache and re-reading old data. */
}
- }
- /* Skip the specification. */
- uint32_t uAttr, uForm;
- do
- {
- uAttr = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
- uForm = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
- } while (uAttr != 0);
+ /* Skip the specification. */
+ uint32_t uAttr, uForm;
+ do
+ {
+ uAttr = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
+ uForm = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
+ } while (uAttr != 0);
+ }
if (RT_FAILURE(Cursor.rc))
break;
@@ -2313,10 +2964,10 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
if (uCurCode == uCode)
{
pRet = &pThis->LookupAbbrev;
- pRet->fFilled = true;
pRet->fChildren = RT_BOOL(uChildren);
pRet->uTag = uCurTag;
pRet->offSpec = rtDwarfCursor_CalcSectOffsetU32(&Cursor);
+ pRet->offAbbrev = pThis->offCachedAbbrev;
break;
}
@@ -2347,8 +2998,8 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
*/
static PCRTDWARFABBREV rtDwarfAbbrev_Lookup(PRTDBGMODDWARF pThis, uint32_t uCode)
{
- if ( uCode - 1 >= pThis->cCachedAbbrevs
- || !pThis->paCachedAbbrevs[uCode - 1].fFilled)
+ if ( uCode - 1 >= pThis->cCachedAbbrevsAlloced
+ || pThis->paCachedAbbrevs[uCode - 1].offAbbrev != pThis->offCachedAbbrev)
return rtDwarfAbbrev_LookupMiss(pThis, uCode);
return &pThis->paCachedAbbrevs[uCode - 1];
}
@@ -2357,19 +3008,12 @@ static PCRTDWARFABBREV rtDwarfAbbrev_Lookup(PRTDBGMODDWARF pThis, uint32_t uCode
/**
* Sets the abbreviation offset of the current unit.
*
- * This will flush the cached abbreviation entries if the offset differs from
- * the previous unit.
- *
* @param pThis The DWARF instance.
* @param offAbbrev The offset into the abbreviation section.
*/
static void rtDwarfAbbrev_SetUnitOffset(PRTDBGMODDWARF pThis, uint32_t offAbbrev)
{
- if (pThis->offCachedAbbrev != offAbbrev)
- {
- pThis->offCachedAbbrev = offAbbrev;
- pThis->cCachedAbbrevs = 0;
- }
+ pThis->offCachedAbbrev = offAbbrev;
}
@@ -2408,7 +3052,7 @@ static PRTDWARFDIECOMPILEUNIT rtDwarfDie_GetCompileUnit(PRTDWARFDIE pDie)
* @param pszErrValue What to return on failure (@a
* pCursor->rc is set).
*/
-static const char *rtDwarfDecode_GetStrp(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, const char *pszErrValue)
+static const char *rtDwarfDecodeHlp_GetStrp(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, const char *pszErrValue)
{
uint64_t offDebugStr = rtDwarfCursor_GetUOff(pCursor, UINT64_MAX);
if (RT_FAILURE(pCursor->rc))
@@ -2453,7 +3097,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Address(PRTDWARFDIE pDie, uint8_t *pbMemb
case DW_FORM_data8: uAddr = rtDwarfCursor_GetU64(pCursor, 0); break;
case DW_FORM_udata: uAddr = rtDwarfCursor_GetULeb128(pCursor, 0); break;
default:
- AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
+ AssertMsgFailedReturn(("%#x (%s)\n", uForm, rtDwarfLog_FormName(uForm)), VERR_DWARF_UNEXPECTED_FORM);
}
if (RT_FAILURE(pCursor->rc))
return pCursor->rc;
@@ -2461,6 +3105,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Address(PRTDWARFDIE pDie, uint8_t *pbMemb
PRTDWARFADDR pAddr = (PRTDWARFADDR)pbMember;
pAddr->uAddress = uAddr;
+ Log4((" %-20s %#010llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), uAddr, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2479,7 +3124,10 @@ static DECLCALLBACK(int) rtDwarfDecode_Bool(PRTDWARFDIE pDie, uint8_t *pbMember,
{
uint8_t b = rtDwarfCursor_GetU8(pCursor, UINT8_MAX);
if (b > 1)
+ {
+ Log(("Unexpected boolean value %#x\n", b));
return RT_FAILURE(pCursor->rc) ? pCursor->rc : pCursor->rc = VERR_DWARF_BAD_INFO;
+ }
*pfMember = RT_BOOL(b);
break;
}
@@ -2492,6 +3140,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Bool(PRTDWARFDIE pDie, uint8_t *pbMember,
AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
}
+ Log4((" %-20s %RTbool [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), *pfMember, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2538,10 +3187,19 @@ static DECLCALLBACK(int) rtDwarfDecode_LowHighPc(PRTDWARFDIE pDie, uint8_t *pbMe
return pCursor->rc = VERR_DWARF_BAD_INFO;
}
pRange->fHaveHighAddress = true;
- pRange->uHighAddress = uAddr;
+ pRange->fHaveHighIsAddress = uForm == DW_FORM_addr;
+ if (!pRange->fHaveHighIsAddress && pRange->fHaveLowAddress)
+ {
+ pRange->fHaveHighIsAddress = true;
+ pRange->uHighAddress = uAddr + pRange->uLowAddress;
+ }
+ else
+ pRange->uHighAddress = uAddr;
+
}
pRange->cAttrs++;
+ Log4((" %-20s %#010llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), uAddr, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2551,16 +3209,17 @@ static DECLCALLBACK(int) rtDwarfDecode_Ranges(PRTDWARFDIE pDie, uint8_t *pbMembe
uint32_t uForm, PRTDWARFCURSOR pCursor)
{
AssertReturn(ATTR_GET_SIZE(pDesc) == sizeof(RTDWARFADDRRANGE), VERR_INTERNAL_ERROR_3);
- AssertReturn(pDesc->uAttr == DW_AT_low_pc || pDesc->uAttr == DW_AT_high_pc, VERR_INTERNAL_ERROR_3);
+ AssertReturn(pDesc->uAttr == DW_AT_ranges, VERR_INTERNAL_ERROR_3);
NOREF(pDie);
/* Decode it. */
uint64_t off;
switch (uForm)
{
- case DW_FORM_addr: off = rtDwarfCursor_GetNativeUOff(pCursor, 0); break;
- case DW_FORM_data4: off = rtDwarfCursor_GetU32(pCursor, 0); break;
- case DW_FORM_data8: off = rtDwarfCursor_GetU64(pCursor, 0); break;
+ case DW_FORM_addr: off = rtDwarfCursor_GetNativeUOff(pCursor, 0); break;
+ case DW_FORM_data4: off = rtDwarfCursor_GetU32(pCursor, 0); break;
+ case DW_FORM_data8: off = rtDwarfCursor_GetU64(pCursor, 0); break;
+ case DW_FORM_sec_offset: off = rtDwarfCursor_GetUOff(pCursor, 0); break;
default:
AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
}
@@ -2593,6 +3252,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Ranges(PRTDWARFDIE pDie, uint8_t *pbMembe
pRange->cAttrs++;
pRange->pbRanges = (uint8_t const *)pThis->aSections[krtDbgModDwarfSect_ranges].pv + (size_t)off;
+ Log4((" %-20s TODO [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2605,7 +3265,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Reference(PRTDWARFDIE pDie, uint8_t *pbMe
/* Decode it. */
uint64_t off;
- krtDwarfRef enmWrt = krtDwarfRef_InfoSection;
+ krtDwarfRef enmWrt = krtDwarfRef_SameUnit;
switch (uForm)
{
case DW_FORM_ref1: off = rtDwarfCursor_GetU8(pCursor, 0); break;
@@ -2657,6 +3317,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Reference(PRTDWARFDIE pDie, uint8_t *pbMe
pRef->enmWrt = enmWrt;
pRef->off = off;
+ Log4((" %-20s %d:%#010llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), enmWrt, off, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2675,7 +3336,7 @@ static DECLCALLBACK(int) rtDwarfDecode_SectOff(PRTDWARFDIE pDie, uint8_t *pbMemb
case DW_FORM_data8: off = rtDwarfCursor_GetU64(pCursor, 0); break;
case DW_FORM_sec_offset: off = rtDwarfCursor_GetUOff(pCursor, 0); break;
default:
- AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
+ AssertMsgFailedReturn(("%#x (%s)\n", uForm, rtDwarfLog_FormName(uForm)), VERR_DWARF_UNEXPECTED_FORM);
}
if (RT_FAILURE(pCursor->rc))
return pCursor->rc;
@@ -2687,18 +3348,24 @@ static DECLCALLBACK(int) rtDwarfDecode_SectOff(PRTDWARFDIE pDie, uint8_t *pbMemb
case DW_AT_stmt_list: enmSect = krtDbgModDwarfSect_line; enmWrt = krtDwarfRef_LineSection; break;
case DW_AT_macro_info: enmSect = krtDbgModDwarfSect_loc; enmWrt = krtDwarfRef_LocSection; break;
case DW_AT_ranges: enmSect = krtDbgModDwarfSect_ranges; enmWrt = krtDwarfRef_RangesSection; break;
- default: AssertMsgFailedReturn(("%u\n", pDesc->uAttr), VERR_INTERNAL_ERROR_4);
+ default:
+ AssertMsgFailedReturn(("%u (%s)\n", pDesc->uAttr, rtDwarfLog_AttrName(pDesc->uAttr)), VERR_INTERNAL_ERROR_4);
}
- if (off >= pCursor->pDwarfMod->aSections[enmSect].cb)
+ size_t cbSect = pCursor->pDwarfMod->aSections[enmSect].cb;
+ if (off >= cbSect)
{
- Log(("rtDwarfDecode_SectOff: bad off=%#llx, attr %#x\n", off, pDesc->uAttr));
- return pCursor->rc = VERR_DWARF_BAD_POS;
+ /* Watcom generates offset past the end of the section, increasing the
+ offset by one for each compile unit. So, just fudge it. */
+ Log(("rtDwarfDecode_SectOff: bad off=%#llx, attr %#x (%s), enmSect=%d cb=%#llx; Assuming watcom/gcc.\n", off,
+ pDesc->uAttr, rtDwarfLog_AttrName(pDesc->uAttr), enmSect, cbSect));
+ off = cbSect;
}
PRTDWARFREF pRef = (PRTDWARFREF)pbMember;
pRef->enmWrt = enmWrt;
pRef->off = off;
+ Log4((" %-20s %d:%#010llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), enmWrt, off, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2710,20 +3377,23 @@ static DECLCALLBACK(int) rtDwarfDecode_String(PRTDWARFDIE pDie, uint8_t *pbMembe
AssertReturn(ATTR_GET_SIZE(pDesc) == sizeof(const char *), VERR_INTERNAL_ERROR_3);
NOREF(pDie);
+ const char *psz;
switch (uForm)
{
case DW_FORM_string:
- *(const char **)pbMember = rtDwarfCursor_GetSZ(pCursor, NULL);
+ psz = rtDwarfCursor_GetSZ(pCursor, NULL);
break;
case DW_FORM_strp:
- *(const char **)pbMember = rtDwarfDecode_GetStrp(pCursor->pDwarfMod, pCursor, NULL);
+ psz = rtDwarfDecodeHlp_GetStrp(pCursor->pDwarfMod, pCursor, NULL);
break;
default:
AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
}
+ *(const char **)pbMember = psz;
+ Log4((" %-20s '%s' [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), psz, rtDwarfLog_FormName(uForm)));
return pCursor->rc;
}
@@ -2752,25 +3422,37 @@ static DECLCALLBACK(int) rtDwarfDecode_UnsignedInt(PRTDWARFDIE pDie, uint8_t *pb
case 1:
*pbMember = (uint8_t)u64Val;
if (*pbMember != u64Val)
+ {
+ AssertFailed();
return VERR_OUT_OF_RANGE;
+ }
break;
case 2:
*(uint16_t *)pbMember = (uint16_t)u64Val;
if (*(uint16_t *)pbMember != u64Val)
+ {
+ AssertFailed();
return VERR_OUT_OF_RANGE;
+ }
break;
case 4:
*(uint32_t *)pbMember = (uint32_t)u64Val;
if (*(uint32_t *)pbMember != u64Val)
+ {
+ AssertFailed();
return VERR_OUT_OF_RANGE;
+ }
break;
case 8:
*(uint64_t *)pbMember = (uint64_t)u64Val;
if (*(uint64_t *)pbMember != u64Val)
+ {
+ AssertFailed();
return VERR_OUT_OF_RANGE;
+ }
break;
default:
@@ -2780,6 +3462,256 @@ static DECLCALLBACK(int) rtDwarfDecode_UnsignedInt(PRTDWARFDIE pDie, uint8_t *pb
}
+/**
+ * Initialize location interpreter state from cursor & form.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_NOT_FOUND if no location information (i.e. there is source but
+ * it resulted in no byte code).
+ * @param pLoc The location state structure to initialize.
+ * @param pCursor The cursor to read from.
+ * @param uForm The attribute form.
+ */
+static int rtDwarfLoc_Init(PRTDWARFLOCST pLoc, PRTDWARFCURSOR pCursor, uint32_t uForm)
+{
+ uint32_t cbBlock;
+ switch (uForm)
+ {
+ case DW_FORM_block1:
+ cbBlock = rtDwarfCursor_GetU8(pCursor, 0);
+ break;
+
+ case DW_FORM_block2:
+ cbBlock = rtDwarfCursor_GetU16(pCursor, 0);
+ break;
+
+ case DW_FORM_block4:
+ cbBlock = rtDwarfCursor_GetU32(pCursor, 0);
+ break;
+
+ case DW_FORM_block:
+ cbBlock = rtDwarfCursor_GetULeb128(pCursor, 0);
+ break;
+
+ default:
+ AssertMsgFailedReturn(("uForm=%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
+ }
+ if (!cbBlock)
+ return VERR_NOT_FOUND;
+
+ int rc = rtDwarfCursor_InitForBlock(&pLoc->Cursor, pCursor, cbBlock);
+ if (RT_FAILURE(rc))
+ return rc;
+ pLoc->iTop = -1;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Pushes a value onto the stack.
+ *
+ * @returns VINF_SUCCESS or VERR_DWARF_STACK_OVERFLOW.
+ * @param pLoc The state.
+ * @param uValue The value to push.
+ */
+static int rtDwarfLoc_Push(PRTDWARFLOCST pLoc, uint64_t uValue)
+{
+ int iTop = pLoc->iTop + 1;
+ AssertReturn((unsigned)iTop < RT_ELEMENTS(pLoc->auStack), VERR_DWARF_STACK_OVERFLOW);
+ pLoc->auStack[iTop] = uValue;
+ pLoc->iTop = iTop;
+ return VINF_SUCCESS;
+}
+
+
+static int rtDwarfLoc_Evaluate(PRTDWARFLOCST pLoc, void *pvLater, void *pvUser)
+{
+ while (!rtDwarfCursor_IsAtEndOfUnit(&pLoc->Cursor))
+ {
+ /* Read the next opcode.*/
+ uint8_t const bOpcode = rtDwarfCursor_GetU8(&pLoc->Cursor, 0);
+
+ /* Get its operands. */
+ uint64_t uOperand1 = 0;
+ uint64_t uOperand2 = 0;
+ switch (bOpcode)
+ {
+ case DW_OP_addr:
+ uOperand1 = rtDwarfCursor_GetNativeUOff(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_pick:
+ case DW_OP_const1u:
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ uOperand1 = rtDwarfCursor_GetU8(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const1s:
+ uOperand1 = (int8_t)rtDwarfCursor_GetU8(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const2u:
+ uOperand1 = rtDwarfCursor_GetU16(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_skip:
+ case DW_OP_bra:
+ case DW_OP_const2s:
+ uOperand1 = (int16_t)rtDwarfCursor_GetU16(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const4u:
+ uOperand1 = rtDwarfCursor_GetU32(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const4s:
+ uOperand1 = (int32_t)rtDwarfCursor_GetU32(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const8u:
+ uOperand1 = rtDwarfCursor_GetU64(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const8s:
+ uOperand1 = rtDwarfCursor_GetU64(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_regx:
+ case DW_OP_piece:
+ case DW_OP_plus_uconst:
+ case DW_OP_constu:
+ uOperand1 = rtDwarfCursor_GetULeb128(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_consts:
+ case DW_OP_fbreg:
+ case DW_OP_breg0+0: case DW_OP_breg0+1: case DW_OP_breg0+2: case DW_OP_breg0+3:
+ case DW_OP_breg0+4: case DW_OP_breg0+5: case DW_OP_breg0+6: case DW_OP_breg0+7:
+ case DW_OP_breg0+8: case DW_OP_breg0+9: case DW_OP_breg0+10: case DW_OP_breg0+11:
+ case DW_OP_breg0+12: case DW_OP_breg0+13: case DW_OP_breg0+14: case DW_OP_breg0+15:
+ case DW_OP_breg0+16: case DW_OP_breg0+17: case DW_OP_breg0+18: case DW_OP_breg0+19:
+ case DW_OP_breg0+20: case DW_OP_breg0+21: case DW_OP_breg0+22: case DW_OP_breg0+23:
+ case DW_OP_breg0+24: case DW_OP_breg0+25: case DW_OP_breg0+26: case DW_OP_breg0+27:
+ case DW_OP_breg0+28: case DW_OP_breg0+29: case DW_OP_breg0+30: case DW_OP_breg0+31:
+ uOperand1 = rtDwarfCursor_GetSLeb128(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_bregx:
+ uOperand1 = rtDwarfCursor_GetULeb128(&pLoc->Cursor, 0);
+ uOperand2 = rtDwarfCursor_GetSLeb128(&pLoc->Cursor, 0);
+ break;
+ }
+ if (RT_FAILURE(pLoc->Cursor.rc))
+ break;
+
+ /* Interpret the opcode. */
+ int rc;
+ switch (bOpcode)
+ {
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ case DW_OP_constu:
+ case DW_OP_consts:
+ case DW_OP_addr:
+ rc = rtDwarfLoc_Push(pLoc, uOperand1);
+ break;
+ case DW_OP_lit0 + 0: case DW_OP_lit0 + 1: case DW_OP_lit0 + 2: case DW_OP_lit0 + 3:
+ case DW_OP_lit0 + 4: case DW_OP_lit0 + 5: case DW_OP_lit0 + 6: case DW_OP_lit0 + 7:
+ case DW_OP_lit0 + 8: case DW_OP_lit0 + 9: case DW_OP_lit0 + 10: case DW_OP_lit0 + 11:
+ case DW_OP_lit0 + 12: case DW_OP_lit0 + 13: case DW_OP_lit0 + 14: case DW_OP_lit0 + 15:
+ case DW_OP_lit0 + 16: case DW_OP_lit0 + 17: case DW_OP_lit0 + 18: case DW_OP_lit0 + 19:
+ case DW_OP_lit0 + 20: case DW_OP_lit0 + 21: case DW_OP_lit0 + 22: case DW_OP_lit0 + 23:
+ case DW_OP_lit0 + 24: case DW_OP_lit0 + 25: case DW_OP_lit0 + 26: case DW_OP_lit0 + 27:
+ case DW_OP_lit0 + 28: case DW_OP_lit0 + 29: case DW_OP_lit0 + 30: case DW_OP_lit0 + 31:
+ rc = rtDwarfLoc_Push(pLoc, bOpcode - DW_OP_lit0);
+ break;
+ case DW_OP_nop:
+ break;
+ case DW_OP_dup: /** @todo 0 operands. */
+ case DW_OP_drop: /** @todo 0 operands. */
+ case DW_OP_over: /** @todo 0 operands. */
+ case DW_OP_pick: /** @todo 1 operands, a 1-byte stack index. */
+ case DW_OP_swap: /** @todo 0 operands. */
+ case DW_OP_rot: /** @todo 0 operands. */
+ case DW_OP_abs: /** @todo 0 operands. */
+ case DW_OP_and: /** @todo 0 operands. */
+ case DW_OP_div: /** @todo 0 operands. */
+ case DW_OP_minus: /** @todo 0 operands. */
+ case DW_OP_mod: /** @todo 0 operands. */
+ case DW_OP_mul: /** @todo 0 operands. */
+ case DW_OP_neg: /** @todo 0 operands. */
+ case DW_OP_not: /** @todo 0 operands. */
+ case DW_OP_or: /** @todo 0 operands. */
+ case DW_OP_plus: /** @todo 0 operands. */
+ case DW_OP_plus_uconst: /** @todo 1 operands, a ULEB128 addend. */
+ case DW_OP_shl: /** @todo 0 operands. */
+ case DW_OP_shr: /** @todo 0 operands. */
+ case DW_OP_shra: /** @todo 0 operands. */
+ case DW_OP_xor: /** @todo 0 operands. */
+ case DW_OP_skip: /** @todo 1 signed 2-byte constant. */
+ case DW_OP_bra: /** @todo 1 signed 2-byte constant. */
+ case DW_OP_eq: /** @todo 0 operands. */
+ case DW_OP_ge: /** @todo 0 operands. */
+ case DW_OP_gt: /** @todo 0 operands. */
+ case DW_OP_le: /** @todo 0 operands. */
+ case DW_OP_lt: /** @todo 0 operands. */
+ case DW_OP_ne: /** @todo 0 operands. */
+ case DW_OP_reg0 + 0: case DW_OP_reg0 + 1: case DW_OP_reg0 + 2: case DW_OP_reg0 + 3: /** @todo 0 operands - reg 0..31. */
+ case DW_OP_reg0 + 4: case DW_OP_reg0 + 5: case DW_OP_reg0 + 6: case DW_OP_reg0 + 7:
+ case DW_OP_reg0 + 8: case DW_OP_reg0 + 9: case DW_OP_reg0 + 10: case DW_OP_reg0 + 11:
+ case DW_OP_reg0 + 12: case DW_OP_reg0 + 13: case DW_OP_reg0 + 14: case DW_OP_reg0 + 15:
+ case DW_OP_reg0 + 16: case DW_OP_reg0 + 17: case DW_OP_reg0 + 18: case DW_OP_reg0 + 19:
+ case DW_OP_reg0 + 20: case DW_OP_reg0 + 21: case DW_OP_reg0 + 22: case DW_OP_reg0 + 23:
+ case DW_OP_reg0 + 24: case DW_OP_reg0 + 25: case DW_OP_reg0 + 26: case DW_OP_reg0 + 27:
+ case DW_OP_reg0 + 28: case DW_OP_reg0 + 29: case DW_OP_reg0 + 30: case DW_OP_reg0 + 31:
+ case DW_OP_breg0+ 0: case DW_OP_breg0+ 1: case DW_OP_breg0+ 2: case DW_OP_breg0+ 3: /** @todo 1 operand, a SLEB128 offset. */
+ case DW_OP_breg0+ 4: case DW_OP_breg0+ 5: case DW_OP_breg0+ 6: case DW_OP_breg0+ 7:
+ case DW_OP_breg0+ 8: case DW_OP_breg0+ 9: case DW_OP_breg0+ 10: case DW_OP_breg0+ 11:
+ case DW_OP_breg0+ 12: case DW_OP_breg0+ 13: case DW_OP_breg0+ 14: case DW_OP_breg0+ 15:
+ case DW_OP_breg0+ 16: case DW_OP_breg0+ 17: case DW_OP_breg0+ 18: case DW_OP_breg0+ 19:
+ case DW_OP_breg0+ 20: case DW_OP_breg0+ 21: case DW_OP_breg0+ 22: case DW_OP_breg0+ 23:
+ case DW_OP_breg0+ 24: case DW_OP_breg0+ 25: case DW_OP_breg0+ 26: case DW_OP_breg0+ 27:
+ case DW_OP_breg0+ 28: case DW_OP_breg0+ 29: case DW_OP_breg0+ 30: case DW_OP_breg0+ 31:
+ case DW_OP_piece: /** @todo 1 operand, a ULEB128 size of piece addressed. */
+ case DW_OP_regx: /** @todo 1 operand, a ULEB128 register. */
+ case DW_OP_fbreg: /** @todo 1 operand, a SLEB128 offset. */
+ case DW_OP_bregx: /** @todo 2 operands, a ULEB128 register followed by a SLEB128 offset. */
+ case DW_OP_deref: /** @todo 0 operands. */
+ case DW_OP_deref_size: /** @todo 1 operand, a 1-byte size of data retrieved. */
+ case DW_OP_xderef: /** @todo 0 operands. */
+ case DW_OP_xderef_size: /** @todo 1 operand, a 1-byte size of data retrieved. */
+ AssertMsgFailedReturn(("bOpcode=%#x\n", bOpcode), VERR_DWARF_TODO);
+ default:
+ AssertMsgFailedReturn(("bOpcode=%#x\n", bOpcode), VERR_DWARF_UNKNOWN_LOC_OPCODE);
+ }
+ }
+
+ return pLoc->Cursor.rc;
+}
+
+
+/** @callback_method_impl{FNRTDWARFATTRDECODER} */
+static DECLCALLBACK(int) rtDwarfDecode_SegmentLoc(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
+ uint32_t uForm, PRTDWARFCURSOR pCursor)
+{
+ NOREF(pDie);
+ AssertReturn(ATTR_GET_SIZE(pDesc) == 2, VERR_DWARF_IPE);
+
+ RTDWARFLOCST LocSt;
+ int rc = rtDwarfLoc_Init(&LocSt, pCursor, uForm);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtDwarfLoc_Evaluate(&LocSt, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ if (LocSt.iTop >= 0)
+ {
+ *(uint16_t *)pbMember = LocSt.auStack[LocSt.iTop];
+ Log4((" %-20s %#06llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr),
+ LocSt.auStack[LocSt.iTop], rtDwarfLog_FormName(uForm)));
+ return VINF_SUCCESS;
+ }
+ rc = VERR_DWARF_STACK_UNDERFLOW;
+ }
+ }
+ return rc;
+}
/*
*
@@ -2791,6 +3723,87 @@ static DECLCALLBACK(int) rtDwarfDecode_UnsignedInt(PRTDWARFDIE pDie, uint8_t *pb
/**
+ * Special hack to get the name and/or linkage name for a subprogram via a
+ * specification reference.
+ *
+ * Since this is a hack, we ignore failure.
+ *
+ * If we want to really make use of DWARF info, we'll have to create some kind
+ * of lookup tree for handling this. But currently we don't, so a hack will
+ * suffice.
+ *
+ * @param pThis The DWARF instance.
+ * @param pSubProgram The subprogram which is short on names.
+ */
+static void rtDwarfInfo_TryGetSubProgramNameFromSpecRef(PRTDBGMODDWARF pThis, PRTDWARFDIESUBPROGRAM pSubProgram)
+{
+ /*
+ * Must have a spec ref, and it must be in the info section.
+ */
+ if (pSubProgram->SpecRef.enmWrt != krtDwarfRef_InfoSection)
+ return;
+
+ /*
+ * Create a cursor for reading the info and then the abbrivation code
+ * starting the off the DIE.
+ */
+ RTDWARFCURSOR InfoCursor;
+ int rc = rtDwarfCursor_InitWithOffset(&InfoCursor, pThis, krtDbgModDwarfSect_info, pSubProgram->SpecRef.off);
+ if (RT_FAILURE(rc))
+ return;
+
+ uint32_t uAbbrCode = rtDwarfCursor_GetULeb128AsU32(&InfoCursor, UINT32_MAX);
+ if (uAbbrCode)
+ {
+ /* Only references to subprogram tags are interesting here. */
+ PCRTDWARFABBREV pAbbrev = rtDwarfAbbrev_Lookup(pThis, uAbbrCode);
+ if ( pAbbrev
+ && pAbbrev->uTag == DW_TAG_subprogram)
+ {
+ /*
+ * Use rtDwarfInfo_ParseDie to do the parsing, but with a different
+ * attribute spec than usual.
+ */
+ rtDwarfInfo_ParseDie(pThis, &pSubProgram->Core, &g_SubProgramSpecHackDesc, &InfoCursor,
+ pAbbrev, false /*fInitDie*/);
+ }
+ }
+
+ rtDwarfCursor_Delete(&InfoCursor, VINF_SUCCESS);
+}
+
+
+/**
+ * Select which name to use.
+ *
+ * @returns One of the names.
+ * @param pszName The DWARF name, may exclude namespace and class.
+ * Can also be NULL.
+ * @param pszLinkageName The linkage name. Can be NULL.
+ */
+static const char *rtDwarfInfo_SelectName(const char *pszName, const char *pszLinkageName)
+{
+ if (!pszName || !pszLinkageName)
+ return pszName ? pszName : pszLinkageName;
+
+ /*
+ * Some heuristics for selecting the link name if the normal name is missing
+ * namespace or class prefixes.
+ */
+ size_t cchName = strlen(pszName);
+ size_t cchLinkageName = strlen(pszLinkageName);
+ if (cchLinkageName <= cchName + 1)
+ return pszName;
+
+ const char *psz = strstr(pszLinkageName, pszName);
+ if (!psz || psz - pszLinkageName < 4)
+ return pszName;
+
+ return pszLinkageName;
+}
+
+
+/**
* Parse the attributes of a DIE.
*
* @returns IPRT status code.
@@ -2804,7 +3817,13 @@ static int rtDwarfInfo_SnoopSymbols(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie)
{
case DW_TAG_subprogram:
{
- PCRTDWARFDIESUBPROGRAM pSubProgram = (PCRTDWARFDIESUBPROGRAM)pDie;
+ PRTDWARFDIESUBPROGRAM pSubProgram = (PRTDWARFDIESUBPROGRAM)pDie;
+
+ /* Obtain referenced specification there is only partial info. */
+ if ( pSubProgram->PcRange.cAttrs
+ && !pSubProgram->pszName)
+ rtDwarfInfo_TryGetSubProgramNameFromSpecRef(pThis, pSubProgram);
+
if (pSubProgram->PcRange.cAttrs)
{
if (pSubProgram->PcRange.fHaveRanges)
@@ -2814,19 +3833,50 @@ static int rtDwarfInfo_SnoopSymbols(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie)
Log5(("subprogram %s (%s) %#llx-%#llx%s\n", pSubProgram->pszName, pSubProgram->pszLinkageName,
pSubProgram->PcRange.uLowAddress, pSubProgram->PcRange.uHighAddress,
pSubProgram->PcRange.cAttrs == 2 ? "" : " !bad!"));
- if ( pSubProgram->pszName
+ if ( ( pSubProgram->pszName || pSubProgram->pszLinkageName)
&& pSubProgram->PcRange.cAttrs == 2)
{
- RTDBGSEGIDX iSeg;
- RTUINTPTR offSeg;
- rc = rtDbgModDwarfLinkAddressToSegOffset(pThis, pSubProgram->PcRange.uLowAddress,
- &iSeg, &offSeg);
- if (RT_SUCCESS(rc))
- rc = RTDbgModSymbolAdd(pThis->hCnt, pSubProgram->pszName, iSeg, offSeg,
- pSubProgram->PcRange.uHighAddress - pSubProgram->PcRange.uLowAddress,
- 0 /*fFlags*/, NULL /*piOrdinal*/);
+ if (pThis->iWatcomPass == 1)
+ rc = rtDbgModDwarfRecordSegOffset(pThis, pSubProgram->uSegment, pSubProgram->PcRange.uHighAddress);
else
- Log5(("rtDbgModDwarfLinkAddressToSegOffset failed: %Rrc\n", rc));
+ {
+ RTDBGSEGIDX iSeg;
+ RTUINTPTR offSeg;
+ rc = rtDbgModDwarfLinkAddressToSegOffset(pThis, pSubProgram->uSegment,
+ pSubProgram->PcRange.uLowAddress,
+ &iSeg, &offSeg);
+ if (RT_SUCCESS(rc))
+ {
+ uint64_t cb;
+ if (pSubProgram->PcRange.uHighAddress >= pSubProgram->PcRange.uLowAddress)
+ cb = pSubProgram->PcRange.uHighAddress - pSubProgram->PcRange.uLowAddress;
+ else
+ cb = 1;
+ rc = RTDbgModSymbolAdd(pThis->hCnt,
+ rtDwarfInfo_SelectName(pSubProgram->pszName, pSubProgram->pszLinkageName),
+ iSeg, offSeg, cb, 0 /*fFlags*/, NULL /*piOrdinal*/);
+ if (RT_FAILURE(rc))
+ {
+ if ( rc == VERR_DBG_DUPLICATE_SYMBOL
+ || rc == VERR_DBG_ADDRESS_CONFLICT /** @todo figure why this happens with 10.6.8 mach_kernel, 32-bit. */
+ )
+ rc = VINF_SUCCESS;
+ else
+ AssertMsgFailed(("%Rrc\n", rc));
+ }
+ }
+ else if ( pSubProgram->PcRange.uLowAddress == 0 /* see with vmlinux */
+ && pSubProgram->PcRange.uHighAddress == 0)
+ {
+ Log5(("rtDbgModDwarfLinkAddressToSegOffset: Ignoring empty range.\n"));
+ rc = VINF_SUCCESS; /* ignore */
+ }
+ else
+ {
+ AssertRC(rc);
+ Log5(("rtDbgModDwarfLinkAddressToSegOffset failed: %Rrc\n", rc));
+ }
+ }
}
}
}
@@ -2835,6 +3885,35 @@ static int rtDwarfInfo_SnoopSymbols(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie)
break;
}
+ case DW_TAG_label:
+ {
+ PCRTDWARFDIELABEL pLabel = (PCRTDWARFDIELABEL)pDie;
+ if (pLabel->fExternal)
+ {
+ Log5(("label %s %#x:%#llx\n", pLabel->pszName, pLabel->uSegment, pLabel->Address.uAddress));
+ if (pThis->iWatcomPass == 1)
+ rc = rtDbgModDwarfRecordSegOffset(pThis, pLabel->uSegment, pLabel->Address.uAddress);
+ else
+ {
+ RTDBGSEGIDX iSeg;
+ RTUINTPTR offSeg;
+ rc = rtDbgModDwarfLinkAddressToSegOffset(pThis, pLabel->uSegment, pLabel->Address.uAddress,
+ &iSeg, &offSeg);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTDbgModSymbolAdd(pThis->hCnt, pLabel->pszName, iSeg, offSeg, 0 /*cb*/,
+ 0 /*fFlags*/, NULL /*piOrdinal*/);
+ AssertRC(rc);
+ }
+ else
+ Log5(("rtDbgModDwarfLinkAddressToSegOffset failed: %Rrc\n", rc));
+ }
+
+ }
+ break;
+ }
+
}
return rc;
}
@@ -2901,9 +3980,19 @@ static PRTDWARFDIE rtDwarfInfo_NewDie(PRTDBGMODDWARF pThis, PCRTDWARFDIEDESC pDi
{
NOREF(pThis);
Assert(pDieDesc->cbDie >= sizeof(RTDWARFDIE));
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ uint32_t iAllocator = pDieDesc->cbDie > pThis->aDieAllocators[0].cbMax;
+ Assert(pDieDesc->cbDie <= pThis->aDieAllocators[iAllocator].cbMax);
+ PRTDWARFDIE pDie = (PRTDWARFDIE)RTMemCacheAlloc(pThis->aDieAllocators[iAllocator].hMemCache);
+#else
PRTDWARFDIE pDie = (PRTDWARFDIE)RTMemAllocZ(pDieDesc->cbDie);
+#endif
if (pDie)
{
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ RT_BZERO(pDie, pDieDesc->cbDie);
+ pDie->iAllocator = iAllocator;
+#endif
rtDwarfInfo_InitDie(pDie, pDieDesc);
pDie->uTag = pAbbrev->uTag;
@@ -2921,6 +4010,47 @@ static PRTDWARFDIE rtDwarfInfo_NewDie(PRTDBGMODDWARF pThis, PCRTDWARFDIEDESC pDi
/**
+ * Free all children of a DIE.
+ *
+ * @param pThis The DWARF instance.
+ * @param pParent The parent DIE.
+ */
+static void rtDwarfInfo_FreeChildren(PRTDBGMODDWARF pThis, PRTDWARFDIE pParentDie)
+{
+ PRTDWARFDIE pChild, pNextChild;
+ RTListForEachSafe(&pParentDie->ChildList, pChild, pNextChild, RTDWARFDIE, SiblingNode)
+ {
+ if (!RTListIsEmpty(&pChild->ChildList))
+ rtDwarfInfo_FreeChildren(pThis, pChild);
+ RTListNodeRemove(&pChild->SiblingNode);
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ RTMemCacheFree(pThis->aDieAllocators[pChild->iAllocator].hMemCache, pChild);
+#else
+ RTMemFree(pChild);
+#endif
+ }
+}
+
+
+/**
+ * Free a DIE an all its children.
+ *
+ * @param pThis The DWARF instance.
+ * @param pDie The DIE to free.
+ */
+static void rtDwarfInfo_FreeDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie)
+{
+ rtDwarfInfo_FreeChildren(pThis, pDie);
+ RTListNodeRemove(&pDie->SiblingNode);
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ RTMemCacheFree(pThis->aDieAllocators[pDie->iAllocator].hMemCache, pDie);
+#else
+ RTMemFree(pChild);
+#endif
+}
+
+
+/**
* Skips a form.
* @returns IPRT status code
* @param pCursor The cursor.
@@ -3026,16 +4156,21 @@ static int rtDwarfInfo_SkipDie(PRTDWARFCURSOR pCursor, PRTDWARFCURSOR pAbbrevCur
* @param pDieDesc The DIE descriptor.
* @param pCursor The debug_info cursor.
* @param pAbbrev The abbreviation cache entry.
+ * @param fInitDie Whether to initialize the DIE first. If not (@c
+ * false) it's safe to assume we're following a
+ * DW_AT_specification or DW_AT_abstract_origin,
+ * and that we shouldn't be snooping any symbols.
*/
static int rtDwarfInfo_ParseDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie, PCRTDWARFDIEDESC pDieDesc,
- PRTDWARFCURSOR pCursor, PCRTDWARFABBREV pAbbrev)
+ PRTDWARFCURSOR pCursor, PCRTDWARFABBREV pAbbrev, bool fInitDie)
{
RTDWARFCURSOR AbbrevCursor;
int rc = rtDwarfCursor_InitWithOffset(&AbbrevCursor, pThis, krtDbgModDwarfSect_abbrev, pAbbrev->offSpec);
if (RT_FAILURE(rc))
return rc;
- rtDwarfInfo_InitDie(pDie, pDieDesc);
+ if (fInitDie)
+ rtDwarfInfo_InitDie(pDie, pDieDesc);
for (;;)
{
uint32_t uAttr = rtDwarfCursor_GetULeb128AsU32(&AbbrevCursor, 0);
@@ -3063,6 +4198,7 @@ static int rtDwarfInfo_ParseDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie, PCRTDWAR
{
pDie->cUnhandledAttrs++;
rc = rtDwarfInfo_SkipForm(pCursor, uForm);
+ Log4((" %-20s [%s]\n", rtDwarfLog_AttrName(uAttr), rtDwarfLog_FormName(uForm)));
}
if (RT_FAILURE(rc))
break;
@@ -3073,9 +4209,9 @@ static int rtDwarfInfo_ParseDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie, PCRTDWAR
rc = pCursor->rc;
/*
- * Snoope up symbols on the way out.
+ * Snoop up symbols on the way out.
*/
- if (RT_SUCCESS(rc))
+ if (RT_SUCCESS(rc) && fInitDie)
{
rc = rtDwarfInfo_SnoopSymbols(pThis, pDie);
/* Ignore duplicates, get work done instead. */
@@ -3121,7 +4257,10 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
* Set up the abbreviation cache and store the native address size in the cursor.
*/
if (offAbbrev > UINT32_MAX)
+ {
+ Log(("Unexpected abbrviation code offset of %#llx\n", offAbbrev));
return VERR_DWARF_BAD_INFO;
+ }
rtDwarfAbbrev_SetUnitOffset(pThis, (uint32_t)offAbbrev);
pCursor->cbNativeAddr = cbNativeAddr;
@@ -3130,7 +4269,10 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
*/
uint32_t uAbbrCode = rtDwarfCursor_GetULeb128AsU32(pCursor, UINT32_MAX);
if (!uAbbrCode)
+ {
+ Log(("Unexpected abbrviation code of zero\n"));
return VERR_DWARF_BAD_INFO;
+ }
PCRTDWARFABBREV pAbbrev = rtDwarfAbbrev_Lookup(pThis, uAbbrCode);
if (!pAbbrev)
return VERR_DWARF_ABBREV_NOT_FOUND;
@@ -3152,7 +4294,7 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
pUnit->uDwarfVer = (uint8_t)uVer;
RTListAppend(&pThis->CompileUnitList, &pUnit->Core.SiblingNode);
- int rc = rtDwarfInfo_ParseDie(pThis, &pUnit->Core, &g_CompileUnitDesc, pCursor, pAbbrev);
+ int rc = rtDwarfInfo_ParseDie(pThis, &pUnit->Core, &g_CompileUnitDesc, pCursor, pAbbrev, true /*fInitDie*/);
if (RT_FAILURE(rc))
return rc;
@@ -3163,28 +4305,19 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
PRTDWARFDIE pParentDie = &pUnit->Core;
while (!rtDwarfCursor_IsAtEndOfUnit(pCursor))
{
+#ifdef LOG_ENABLED
+ uint32_t offLog = rtDwarfCursor_CalcSectOffsetU32(pCursor);
+#endif
uAbbrCode = rtDwarfCursor_GetULeb128AsU32(pCursor, UINT32_MAX);
if (!uAbbrCode)
{
- /* End of siblings, up one level. */
- pParentDie = pParentDie->pParent;
- if (!pParentDie)
- {
- if (!rtDwarfCursor_IsAtEndOfUnit(pCursor))
- return VERR_DWARF_BAD_INFO;
- break;
- }
- cDepth--;
-
- /* Unlink and free child DIEs if told to do so. */
- if (!fKeepDies && pParentDie->pParent)
+ /* End of siblings, up one level. (Is this correct?) */
+ if (pParentDie->pParent)
{
- PRTDWARFDIE pChild, pNextChild;
- RTListForEachSafe(&pParentDie->ChildList, pChild, pNextChild, RTDWARFDIE, SiblingNode)
- {
- RTListNodeRemove(&pChild->SiblingNode);
- RTMemFree(pChild);
- }
+ pParentDie = pParentDie->pParent;
+ cDepth--;
+ if (!fKeepDies && pParentDie->pParent)
+ rtDwarfInfo_FreeChildren(pThis, pParentDie);
}
}
else
@@ -3207,10 +4340,10 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
else
{
pszName = "<unknown>";
- pDieDesc = g_aTagDescs[0].pDesc;
+ pDieDesc = &g_CoreDieDesc;
}
- Log4((" %*stag=%s (%#x)%s\n", cDepth * 2, "", pszName,
- pAbbrev->uTag, pAbbrev->fChildren ? " has children" : ""));
+ Log4(("%08x: %*stag=%s (%#x, abbrev %u)%s\n", offLog, cDepth * 2, "", pszName,
+ pAbbrev->uTag, uAbbrCode, pAbbrev->fChildren ? " has children" : ""));
/*
* Create a new internal DIE structure and parse the
@@ -3226,12 +4359,20 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
cDepth++;
}
- rc = rtDwarfInfo_ParseDie(pThis, pNewDie, pDieDesc, pCursor, pAbbrev);
+ rc = rtDwarfInfo_ParseDie(pThis, pNewDie, pDieDesc, pCursor, pAbbrev, true /*fInitDie*/);
if (RT_FAILURE(rc))
return rc;
+
+ if (!fKeepDies && !pAbbrev->fChildren)
+ rtDwarfInfo_FreeDie(pThis, pNewDie);
}
} /* while more DIEs */
+
+ /* Unlink and free child DIEs if told to do so. */
+ if (!fKeepDies)
+ rtDwarfInfo_FreeChildren(pThis, &pUnit->Core);
+
return RT_SUCCESS(rc) ? pCursor->rc : rc;
}
@@ -3248,14 +4389,15 @@ static int rtDwarfInfo_LoadAll(PRTDBGMODDWARF pThis)
{
RTDWARFCURSOR Cursor;
int rc = rtDwarfCursor_Init(&Cursor, pThis, krtDbgModDwarfSect_info);
- if (RT_FAILURE(rc))
- return rc;
-
- while ( !rtDwarfCursor_IsAtEnd(&Cursor)
- && RT_SUCCESS(rc))
- rc = rtDwarfInfo_LoadUnit(pThis, &Cursor, false /* fKeepDies */);
+ if (RT_SUCCESS(rc))
+ {
+ while ( !rtDwarfCursor_IsAtEnd(&Cursor)
+ && RT_SUCCESS(rc))
+ rc = rtDwarfInfo_LoadUnit(pThis, &Cursor, false /* fKeepDies */);
- return rtDwarfCursor_Delete(&Cursor, rc);
+ rc = rtDwarfCursor_Delete(&Cursor, rc);
+ }
+ return rc;
}
@@ -3382,7 +4524,7 @@ static DECLCALLBACK(RTUINTPTR) rtDbgModDwarf_ImageSize(PRTDBGMODINT pMod)
{
PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
RTUINTPTR cb1 = RTDbgModImageSize(pThis->hCnt);
- RTUINTPTR cb2 = pMod->pImgVt->pfnImageSize(pMod);
+ RTUINTPTR cb2 = pThis->pImgMod->pImgVt->pfnImageSize(pMod);
return RT_MAX(cb1, cb2);
}
@@ -3402,10 +4544,28 @@ static DECLCALLBACK(int) rtDbgModDwarf_Close(PRTDBGMODINT pMod)
for (unsigned iSect = 0; iSect < RT_ELEMENTS(pThis->aSections); iSect++)
if (pThis->aSections[iSect].pv)
- pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[iSect].cb, &pThis->aSections[iSect].pv);
+ pThis->pDbgInfoMod->pImgVt->pfnUnmapPart(pThis->pDbgInfoMod, pThis->aSections[iSect].cb, &pThis->aSections[iSect].pv);
RTDbgModRelease(pThis->hCnt);
RTMemFree(pThis->paCachedAbbrevs);
+ if (pThis->pNestedMod)
+ {
+ pThis->pNestedMod->pImgVt->pfnClose(pThis->pNestedMod);
+ RTStrCacheRelease(g_hDbgModStrCache, pThis->pNestedMod->pszName);
+ RTStrCacheRelease(g_hDbgModStrCache, pThis->pNestedMod->pszDbgFile);
+ RTMemFree(pThis->pNestedMod);
+ pThis->pNestedMod = NULL;
+ }
+
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ uint32_t i = RT_ELEMENTS(pThis->aDieAllocators);
+ while (i-- > 0)
+ {
+ RTMemCacheDestroy(pThis->aDieAllocators[i].hMemCache);
+ pThis->aDieAllocators[i].hMemCache = NIL_RTMEMCACHE;
+ }
+#endif
+
RTMemFree(pThis);
return VINF_SUCCESS;
@@ -3413,38 +4573,42 @@ static DECLCALLBACK(int) rtDbgModDwarf_Close(PRTDBGMODINT pMod)
/** @callback_method_impl{FNRTLDRENUMDBG} */
-static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, uint32_t iDbgInfo, RTLDRDBGINFOTYPE enmType,
- uint16_t iMajorVer, uint16_t iMinorVer, const char *pszPartNm,
- RTFOFF offFile, RTLDRADDR LinkAddress, RTLDRADDR cb,
- const char *pszExtFile, void *pvUser)
+static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)
{
- NOREF(hLdrMod); NOREF(iDbgInfo); NOREF(iMajorVer); NOREF(iMinorVer); NOREF(LinkAddress);
-
/*
* Skip stuff we can't handle.
*/
- if ( enmType != RTLDRDBGINFOTYPE_DWARF
- || !pszPartNm
- || pszExtFile)
+ if (pDbgInfo->enmType != RTLDRDBGINFOTYPE_DWARF)
return VINF_SUCCESS;
+ const char *pszSection = pDbgInfo->u.Dwarf.pszSection;
+ if (!pszSection || !*pszSection)
+ return VINF_SUCCESS;
+ Assert(!pDbgInfo->pszExtFile);
/*
* Must have a part name starting with debug_ and possibly prefixed by dots
* or underscores.
*/
- if (!strncmp(pszPartNm, ".debug_", sizeof(".debug_") - 1)) /* ELF */
- pszPartNm += sizeof(".debug_") - 1;
- else if (!strncmp(pszPartNm, "__debug_", sizeof("__debug_") - 1)) /* Mach-O */
- pszPartNm += sizeof("__debug_") - 1;
+ if (!strncmp(pszSection, RT_STR_TUPLE(".debug_"))) /* ELF */
+ pszSection += sizeof(".debug_") - 1;
+ else if (!strncmp(pszSection, RT_STR_TUPLE("__debug_"))) /* Mach-O */
+ pszSection += sizeof("__debug_") - 1;
+ else if (!strcmp(pszSection, ".WATCOM_references"))
+ return VINF_SUCCESS; /* Ignore special watcom section for now.*/
+ else if ( !strcmp(pszSection, "__apple_types")
+ || !strcmp(pszSection, "__apple_namespac")
+ || !strcmp(pszSection, "__apple_objc")
+ || !strcmp(pszSection, "__apple_names"))
+ return VINF_SUCCESS; /* Ignore special apple sections for now. */
else
- AssertMsgFailedReturn(("%s\n", pszPartNm), VINF_SUCCESS /*ignore*/);
+ AssertMsgFailedReturn(("%s\n", pszSection), VINF_SUCCESS /*ignore*/);
/*
* Figure out which part we're talking about.
*/
krtDbgModDwarfSect enmSect;
if (0) { /* dummy */ }
-#define ELSE_IF_STRCMP_SET(a_Name) else if (!strcmp(pszPartNm, #a_Name)) enmSect = krtDbgModDwarfSect_ ## a_Name
+#define ELSE_IF_STRCMP_SET(a_Name) else if (!strcmp(pszSection, #a_Name)) enmSect = krtDbgModDwarfSect_ ## a_Name
ELSE_IF_STRCMP_SET(abbrev);
ELSE_IF_STRCMP_SET(aranges);
ELSE_IF_STRCMP_SET(frame);
@@ -3461,7 +4625,7 @@ static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, uint32_t iD
#undef ELSE_IF_STRCMP_SET
else
{
- AssertMsgFailed(("%s\n", pszPartNm));
+ AssertMsgFailed(("%s\n", pszSection));
return VINF_SUCCESS;
}
@@ -3469,21 +4633,66 @@ static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, uint32_t iD
* Record the section.
*/
PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pvUser;
- AssertMsgReturn(!pThis->aSections[enmSect].fPresent, ("duplicate %s\n", pszPartNm), VINF_SUCCESS /*ignore*/);
+ AssertMsgReturn(!pThis->aSections[enmSect].fPresent, ("duplicate %s\n", pszSection), VINF_SUCCESS /*ignore*/);
pThis->aSections[enmSect].fPresent = true;
- pThis->aSections[enmSect].offFile = offFile;
+ pThis->aSections[enmSect].offFile = pDbgInfo->offFile;
pThis->aSections[enmSect].pv = NULL;
- pThis->aSections[enmSect].cb = (size_t)cb;
- if (pThis->aSections[enmSect].cb != cb)
+ pThis->aSections[enmSect].cb = (size_t)pDbgInfo->cb;
+ pThis->aSections[enmSect].iDbgInfo = pDbgInfo->iDbgInfo;
+ if (pThis->aSections[enmSect].cb != pDbgInfo->cb)
pThis->aSections[enmSect].cb = ~(size_t)0;
return VINF_SUCCESS;
}
+static int rtDbgModDwarfTryOpenDbgFile(PRTDBGMODINT pDbgMod, PRTDBGMODDWARF pThis, RTLDRARCH enmArch)
+{
+ if ( !pDbgMod->pszDbgFile
+ || RTPathIsSame(pDbgMod->pszDbgFile, pDbgMod->pszImgFile) == (int)true /* returns VERR too */)
+ return VERR_DBG_NO_MATCHING_INTERPRETER;
+
+ /*
+ * Only open the image.
+ */
+ PRTDBGMODINT pDbgInfoMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgInfoMod));
+ if (!pDbgInfoMod)
+ return VERR_NO_MEMORY;
+
+ int rc;
+ pDbgInfoMod->u32Magic = RTDBGMOD_MAGIC;
+ pDbgInfoMod->cRefs = 1;
+ if (RTStrCacheRetain(pDbgMod->pszDbgFile) != UINT32_MAX)
+ {
+ pDbgInfoMod->pszImgFile = pDbgMod->pszDbgFile;
+ if (RTStrCacheRetain(pDbgMod->pszName) != UINT32_MAX)
+ {
+ pDbgInfoMod->pszName = pDbgMod->pszName;
+ pDbgInfoMod->pImgVt = &g_rtDbgModVtImgLdr;
+ rc = pDbgInfoMod->pImgVt->pfnTryOpen(pDbgInfoMod, enmArch);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->pDbgInfoMod = pDbgInfoMod;
+ pThis->pNestedMod = pDbgInfoMod;
+ return VINF_SUCCESS;
+ }
+
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgInfoMod->pszName);
+ }
+ else
+ rc = VERR_NO_STR_MEMORY;
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgInfoMod->pszImgFile);
+ }
+ else
+ rc = VERR_NO_STR_MEMORY;
+ RTMemFree(pDbgInfoMod);
+ return rc;
+}
+
+
/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
-static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
+static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
{
/*
* DWARF is only supported when part of an image.
@@ -3492,15 +4701,54 @@ static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
return VERR_DBG_NO_MATCHING_INTERPRETER;
/*
- * Enumerate the debug info in the module, looking for DWARF bits.
+ * Create the module instance data.
*/
PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)RTMemAllocZ(sizeof(*pThis));
if (!pThis)
return VERR_NO_MEMORY;
- pThis->pMod = pMod;
+ pThis->pDbgInfoMod = pMod;
+ pThis->pImgMod = pMod;
RTListInit(&pThis->CompileUnitList);
+ /** @todo better fUseLinkAddress heuristics! */
+ if ( (pMod->pszDbgFile && strstr(pMod->pszDbgFile, "mach_kernel"))
+ || (pMod->pszImgFile && strstr(pMod->pszImgFile, "mach_kernel")) )
+ pThis->fUseLinkAddress = true;
+
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ AssertCompile(RT_ELEMENTS(pThis->aDieAllocators) == 2);
+ pThis->aDieAllocators[0].cbMax = sizeof(RTDWARFDIE);
+ pThis->aDieAllocators[1].cbMax = sizeof(RTDWARFDIECOMPILEUNIT);
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aTagDescs); i++)
+ if (g_aTagDescs[i].pDesc && g_aTagDescs[i].pDesc->cbDie > pThis->aDieAllocators[1].cbMax)
+ pThis->aDieAllocators[1].cbMax = (uint32_t)g_aTagDescs[i].pDesc->cbDie;
+ pThis->aDieAllocators[1].cbMax = RT_ALIGN_32(pThis->aDieAllocators[1].cbMax, sizeof(uint64_t));
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDieAllocators); i++)
+ {
+ int rc = RTMemCacheCreate(&pThis->aDieAllocators[i].hMemCache, pThis->aDieAllocators[i].cbMax, sizeof(uint64_t),
+ UINT32_MAX, NULL /*pfnCtor*/, NULL /*pfnDtor*/, NULL /*pvUser*/, 0 /*fFlags*/);
+ if (RT_FAILURE(rc))
+ {
+ while (i-- > 0)
+ RTMemCacheDestroy(pThis->aDieAllocators[i].hMemCache);
+ RTMemFree(pThis);
+ return rc;
+ }
+ }
+#endif
- int rc = pMod->pImgVt->pfnEnumDbgInfo(pMod, rtDbgModDwarfEnumCallback, pThis);
+ /*
+ * If the debug file name is set, let's see if it's an ELF image with DWARF
+ * inside it. In that case we'll have to deal with two image modules, one
+ * for segments and address translation and one for the debug information.
+ */
+ if (pMod->pszDbgFile != NULL)
+ rtDbgModDwarfTryOpenDbgFile(pMod, pThis, enmArch);
+
+ /*
+ * Enumerate the debug info in the module, looking for DWARF bits.
+ */
+ int rc = pThis->pDbgInfoMod->pImgVt->pfnEnumDbgInfo(pThis->pDbgInfoMod, rtDbgModDwarfEnumCallback, pThis);
if (RT_SUCCESS(rc))
{
if (pThis->aSections[krtDbgModDwarfSect_info].fPresent)
@@ -3514,25 +4762,35 @@ static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
{
pMod->pvDbgPriv = pThis;
- rc = rtDbgModHlpAddSegmentsFromImage(pMod);
+ rc = rtDbgModDwarfAddSegmentsFromImage(pThis);
if (RT_SUCCESS(rc))
rc = rtDwarfInfo_LoadAll(pThis);
if (RT_SUCCESS(rc))
rc = rtDwarfLine_ExplodeAll(pThis);
+ if (RT_SUCCESS(rc) && pThis->iWatcomPass == 1)
+ {
+ rc = rtDbgModDwarfAddSegmentsFromPass1(pThis);
+ pThis->iWatcomPass = 2;
+ if (RT_SUCCESS(rc))
+ rc = rtDwarfInfo_LoadAll(pThis);
+ if (RT_SUCCESS(rc))
+ rc = rtDwarfLine_ExplodeAll(pThis);
+ }
if (RT_SUCCESS(rc))
{
/*
* Free the cached abbreviations and unload all sections.
*/
- pThis->cCachedAbbrevs = pThis->cCachedAbbrevsAlloced = 0;
+ pThis->cCachedAbbrevsAlloced = 0;
RTMemFree(pThis->paCachedAbbrevs);
+ pThis->paCachedAbbrevs = NULL;
for (unsigned iSect = 0; iSect < RT_ELEMENTS(pThis->aSections); iSect++)
if (pThis->aSections[iSect].pv)
- pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[iSect].cb,
- &pThis->aSections[iSect].pv);
-
+ pThis->pDbgInfoMod->pImgVt->pfnUnmapPart(pThis->pDbgInfoMod, pThis->aSections[iSect].cb,
+ &pThis->aSections[iSect].pv);
+ /** @todo Kill pThis->CompileUnitList and the alloc caches. */
return VINF_SUCCESS;
}
@@ -3544,7 +4802,18 @@ static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
else
rc = VERR_DBG_NO_MATCHING_INTERPRETER;
}
+
RTMemFree(pThis->paCachedAbbrevs);
+
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ uint32_t i = RT_ELEMENTS(pThis->aDieAllocators);
+ while (i-- > 0)
+ {
+ RTMemCacheDestroy(pThis->aDieAllocators[i].hMemCache);
+ pThis->aDieAllocators[i].hMemCache = NIL_RTMEMCACHE;
+ }
+#endif
+
RTMemFree(pThis);
return rc;
diff --git a/src/VBox/Runtime/common/dbg/dbgmodexports.cpp b/src/VBox/Runtime/common/dbg/dbgmodexports.cpp
new file mode 100644
index 00000000..d25bff56
--- /dev/null
+++ b/src/VBox/Runtime/common/dbg/dbgmodexports.cpp
@@ -0,0 +1,164 @@
+/* $Id: dbgmodexports.cpp $ */
+/** @file
+ * IPRT - Debug Module Using Image Exports.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DBG
+#include <iprt/dbg.h>
+#include "internal/iprt.h"
+
+#include <iprt/alloca.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include "internal/dbgmod.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+typedef struct RTDBGMODEXPORTARGS
+{
+ PRTDBGMODINT pDbgMod;
+ RTLDRADDR uImageBase;
+ RTLDRADDR uRvaNext;
+ uint32_t cSegs;
+} RTDBGMODEXPORTARGS;
+/** Pointer to an argument package. */
+typedef RTDBGMODEXPORTARGS *PRTDBGMODEXPORTARGS;
+
+
+/** @callback_method_impl{FNRTLDRENUMSYMS,
+ * Copies the symbols over into the container.} */
+static DECLCALLBACK(int) rtDbgModExportsAddSymbolCallback(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
+ RTLDRADDR Value, void *pvUser)
+{
+ PRTDBGMODEXPORTARGS pArgs = (PRTDBGMODEXPORTARGS)pvUser;
+ NOREF(hLdrMod);
+
+ if (Value >= pArgs->uImageBase)
+ {
+ int rc = RTDbgModSymbolAdd(pArgs->pDbgMod, pszSymbol, RTDBGSEGIDX_RVA, Value - pArgs->uImageBase,
+ 0 /*cb*/, 0 /* fFlags */, NULL /*piOrdinal*/);
+ Log(("Symbol #%05u %#018x %s [%Rrc]\n", uSymbol, Value, pszSymbol, rc)); NOREF(rc);
+ }
+ else
+ Log(("Symbol #%05u %#018x %s [SKIPPED - INVALID ADDRESS]\n", uSymbol, Value, pszSymbol));
+ return VINF_SUCCESS;
+}
+
+
+/** @callback_method_impl{FNRTLDRENUMSEGS,
+ * Copies the segments over into the container.} */
+static DECLCALLBACK(int) rtDbgModExportsAddSegmentsCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
+{
+ PRTDBGMODEXPORTARGS pArgs = (PRTDBGMODEXPORTARGS)pvUser;
+ Log(("Segment %.*s: LinkAddress=%#llx RVA=%#llx cb=%#llx\n",
+ pSeg->cchName, pSeg->pszName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
+ NOREF(hLdrMod);
+
+ pArgs->cSegs++;
+
+ /* Add dummy segments for segments that doesn't get mapped. */
+ if (pSeg->LinkAddress == NIL_RTLDRADDR)
+ return RTDbgModSegmentAdd(pArgs->pDbgMod, 0, 0, pSeg->pszName, 0 /*fFlags*/, NULL);
+
+ RTLDRADDR uRva = pSeg->RVA;
+#if 0 /* Kluge for the .data..percpu segment in 64-bit linux kernels and similar. (Moved to ELF.) */
+ if (uRva < pArgs->uRvaNext)
+ uRva = RT_ALIGN_T(pArgs->uRvaNext, pSeg->Alignment, RTLDRADDR);
+#endif
+
+ /* Find the best base address for the module. */
+ if ( ( !pArgs->uImageBase
+ || pArgs->uImageBase > pSeg->LinkAddress)
+ && ( pSeg->LinkAddress != 0 /* .data..percpu again. */
+ || pArgs->cSegs == 1))
+ pArgs->uImageBase = pSeg->LinkAddress;
+
+ /* Add it. */
+ RTLDRADDR cb = RT_MAX(pSeg->cb, pSeg->cbMapped);
+ pArgs->uRvaNext = uRva + cb;
+ return RTDbgModSegmentAdd(pArgs->pDbgMod, uRva, cb, pSeg->pszName, 0 /*fFlags*/, NULL);
+}
+
+
+/**
+ * Creates the debug info side of affairs based on exports and segments found in
+ * the image part.
+ *
+ * The image part must be successfully initialized prior to the call, while the
+ * debug bits must not be present of course.
+ *
+ * @returns IPRT status code
+ * @param pDbgMod The debug module structure.
+ */
+DECLHIDDEN(int) rtDbgModCreateForExports(PRTDBGMODINT pDbgMod)
+{
+ AssertReturn(!pDbgMod->pDbgVt, VERR_DBG_MOD_IPE);
+ AssertReturn(pDbgMod->pImgVt, VERR_DBG_MOD_IPE);
+ RTUINTPTR cbImage = pDbgMod->pImgVt->pfnImageSize(pDbgMod);
+ AssertReturn(cbImage > 0, VERR_DBG_MOD_IPE);
+
+ /*
+ * We simply use a container type for this work.
+ */
+ int rc = rtDbgModContainerCreate(pDbgMod, 0);
+ if (RT_FAILURE(rc))
+ return rc;
+ pDbgMod->fExports = true;
+
+ /*
+ * Copy the segments and symbols.
+ */
+ RTDBGMODEXPORTARGS Args;
+ Args.pDbgMod = pDbgMod;
+ Args.uImageBase = 0;
+ Args.uRvaNext = 0;
+ Args.cSegs = 0;
+ rc = pDbgMod->pImgVt->pfnEnumSegments(pDbgMod, rtDbgModExportsAddSegmentsCallback, &Args);
+ if (RT_SUCCESS(rc))
+ {
+ rc = pDbgMod->pImgVt->pfnEnumSymbols(pDbgMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL | RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD,
+ Args.uImageBase ? Args.uImageBase : 0x10000,
+ rtDbgModExportsAddSymbolCallback, &Args);
+ if (RT_FAILURE(rc))
+ Log(("rtDbgModCreateForExports: Error during symbol enum: %Rrc\n", rc));
+ }
+ else
+ Log(("rtDbgModCreateForExports: Error during segment enum: %Rrc\n", rc));
+
+ /* This won't fail. */
+ if (RT_SUCCESS(rc))
+ rc = VINF_SUCCESS;
+ else
+ rc = -rc; /* Change it into a warning. */
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/dbg/dbgmodldr.cpp b/src/VBox/Runtime/common/dbg/dbgmodldr.cpp
index 724be4ad..64ad918b 100644
--- a/src/VBox/Runtime/common/dbg/dbgmodldr.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgmodldr.cpp
@@ -40,6 +40,7 @@
#include <iprt/path.h>
#include <iprt/string.h>
#include "internal/dbgmod.h"
+#include "internal/ldr.h"
#include "internal/magics.h"
@@ -53,13 +54,36 @@ typedef struct RTDBGMODLDR
{
/** The loader handle. */
RTLDRMOD hLdrMod;
- /** File handle for the image. */
- RTFILE hFile;
} RTDBGMODLDR;
/** Pointer to instance data NM map reader. */
typedef RTDBGMODLDR *PRTDBGMODLDR;
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnGetArch} */
+static DECLCALLBACK(RTLDRARCH) rtDbgModLdr_GetArch(PRTDBGMODINT pMod)
+{
+ PRTDBGMODLDR pThis = (PRTDBGMODLDR)pMod->pvImgPriv;
+ return RTLdrGetArch(pThis->hLdrMod);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnGetFormat} */
+static DECLCALLBACK(RTLDRFMT) rtDbgModLdr_GetFormat(PRTDBGMODINT pMod)
+{
+ PRTDBGMODLDR pThis = (PRTDBGMODLDR)pMod->pvImgPriv;
+ return RTLdrGetFormat(pThis->hLdrMod);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnReadAt} */
+static DECLCALLBACK(int) rtDbgModLdr_ReadAt(PRTDBGMODINT pMod, uint32_t iDbgInfoHint, RTFOFF off, void *pvBuf, size_t cb)
+{
+ PRTDBGMODLDR pThis = (PRTDBGMODLDR)pMod->pvImgPriv;
+ return rtLdrReadAt(pThis->hLdrMod, pvBuf, UINT32_MAX /** @todo iDbgInfo*/, off, cb);
+}
+
+
/** @interface_method_impl{RTDBGMODVTIMG,pfnUnmapPart} */
static DECLCALLBACK(int) rtDbgModLdr_UnmapPart(PRTDBGMODINT pMod, size_t cb, void const **ppvMap)
{
@@ -71,7 +95,7 @@ static DECLCALLBACK(int) rtDbgModLdr_UnmapPart(PRTDBGMODINT pMod, size_t cb, voi
/** @interface_method_impl{RTDBGMODVTIMG,pfnMapPart} */
-static DECLCALLBACK(int) rtDbgModLdr_MapPart(PRTDBGMODINT pMod, RTFOFF off, size_t cb, void const **ppvMap)
+static DECLCALLBACK(int) rtDbgModLdr_MapPart(PRTDBGMODINT pMod, uint32_t iDbgInfo, RTFOFF off, size_t cb, void const **ppvMap)
{
PRTDBGMODLDR pThis = (PRTDBGMODLDR)pMod->pvImgPriv;
@@ -79,7 +103,7 @@ static DECLCALLBACK(int) rtDbgModLdr_MapPart(PRTDBGMODINT pMod, RTFOFF off, size
if (!pvMap)
return VERR_NO_MEMORY;
- int rc = RTFileReadAt(pThis->hFile, off, pvMap, cb, NULL);
+ int rc = rtLdrReadAt(pThis->hLdrMod, pvMap, iDbgInfo, off, cb);
if (RT_SUCCESS(rc))
*ppvMap = pvMap;
else
@@ -99,6 +123,15 @@ static DECLCALLBACK(RTUINTPTR) rtDbgModLdr_GetLoadedSize(PRTDBGMODINT pMod)
}
+/** @interface_method_impl{RTDBGMODVTIMG,pfnRvaToSegOffset} */
+static DECLCALLBACK(int) rtDbgModLdr_RvaToSegOffset(PRTDBGMODINT pMod, RTLDRADDR uRva,
+ PRTDBGSEGIDX piSeg, PRTLDRADDR poffSeg)
+{
+ PRTDBGMODLDR pThis = (PRTDBGMODLDR)pMod->pvImgPriv;
+ return RTLdrRvaToSegOffset(pThis->hLdrMod, uRva, piSeg, poffSeg);
+}
+
+
/** @interface_method_impl{RTDBGMODVTIMG,pfnLinkAddressToSegOffset} */
static DECLCALLBACK(int) rtDbgModLdr_LinkAddressToSegOffset(PRTDBGMODINT pMod, RTLDRADDR LinkAddress,
PRTDBGSEGIDX piSeg, PRTLDRADDR poffSeg)
@@ -109,6 +142,15 @@ static DECLCALLBACK(int) rtDbgModLdr_LinkAddressToSegOffset(PRTDBGMODINT pMod, R
/** @interface_method_impl{RTDBGMODVTIMG,pfnEnumSegments} */
+static DECLCALLBACK(int) rtDbgModLdr_EnumSymbols(PRTDBGMODINT pMod, uint32_t fFlags, RTLDRADDR BaseAddress,
+ PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
+{
+ PRTDBGMODLDR pThis = (PRTDBGMODLDR)pMod->pvImgPriv;
+ return RTLdrEnumSymbols(pThis->hLdrMod, fFlags, NULL /*pvBits*/, BaseAddress, pfnCallback, pvUser);
+}
+
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnEnumSegments} */
static DECLCALLBACK(int) rtDbgModLdr_EnumSegments(PRTDBGMODINT pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
{
PRTDBGMODLDR pThis = (PRTDBGMODLDR)pMod->pvImgPriv;
@@ -133,9 +175,6 @@ static DECLCALLBACK(int) rtDbgModLdr_Close(PRTDBGMODINT pMod)
int rc = RTLdrClose(pThis->hLdrMod); AssertRC(rc);
pThis->hLdrMod = NIL_RTLDRMOD;
- rc = RTFileClose(pThis->hFile); AssertRC(rc);
- pThis->hFile = NIL_RTFILE;
-
RTMemFree(pThis);
return VINF_SUCCESS;
@@ -143,30 +182,15 @@ static DECLCALLBACK(int) rtDbgModLdr_Close(PRTDBGMODINT pMod)
/** @interface_method_impl{RTDBGMODVTIMG,pfnTryOpen} */
-static DECLCALLBACK(int) rtDbgModLdr_TryOpen(PRTDBGMODINT pMod)
+static DECLCALLBACK(int) rtDbgModLdr_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
{
- RTFILE hFile;
- int rc = RTFileOpen(&hFile, pMod->pszImgFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN);
+ RTLDRMOD hLdrMod;
+ int rc = RTLdrOpen(pMod->pszImgFile, RTLDR_O_FOR_DEBUG, enmArch, &hLdrMod);
if (RT_SUCCESS(rc))
{
- RTLDRMOD hLdrMod;
- rc = RTLdrOpen(pMod->pszImgFile, 0 /*fFlags*/, RTLDRARCH_WHATEVER, &hLdrMod);
- if (RT_SUCCESS(rc))
- {
- PRTDBGMODLDR pThis = (PRTDBGMODLDR)RTMemAllocZ(sizeof(RTDBGMODLDR));
- if (pThis)
- {
- pThis->hLdrMod = hLdrMod;
- pThis->hFile = hFile;
- pMod->pvImgPriv = pThis;
- return VINF_SUCCESS;
- }
-
- rc = VERR_NO_MEMORY;
+ rc = rtDbgModLdrOpenFromHandle(pMod, hLdrMod);
+ if (RT_FAILURE(rc))
RTLdrClose(hLdrMod);
- }
-
- RTFileClose(hFile);
}
return rc;
}
@@ -182,11 +206,35 @@ DECL_HIDDEN_CONST(RTDBGMODVTIMG) const g_rtDbgModVtImgLdr =
/*.pfnClose = */ rtDbgModLdr_Close,
/*.pfnEnumDbgInfo = */ rtDbgModLdr_EnumDbgInfo,
/*.pfnEnumSegments = */ rtDbgModLdr_EnumSegments,
+ /*.pfnEnumSymbols = */ rtDbgModLdr_EnumSymbols,
/*.pfnGetLoadedSize = */ rtDbgModLdr_GetLoadedSize,
/*.pfnLinkAddressToSegOffset = */ rtDbgModLdr_LinkAddressToSegOffset,
+ /*.pfnRvaToSegOffset= */ rtDbgModLdr_RvaToSegOffset,
/*.pfnMapPart = */ rtDbgModLdr_MapPart,
/*.pfnUnmapPart = */ rtDbgModLdr_UnmapPart,
+ /*.pfnReadAt = */ rtDbgModLdr_ReadAt,
+ /*.pfnGetFormat = */ rtDbgModLdr_GetFormat,
+ /*.pfnGetArch = */ rtDbgModLdr_GetArch,
/*.u32EndMagic = */ RTDBGMODVTIMG_MAGIC
};
+
+/**
+ * Open PE-image trick.
+ *
+ * @returns IPRT status code
+ * @param pDbgMod The debug module instance.
+ * @param hLdrMod The module to open a image debug backend for.
+ */
+DECLHIDDEN(int) rtDbgModLdrOpenFromHandle(PRTDBGMODINT pDbgMod, RTLDRMOD hLdrMod)
+{
+ PRTDBGMODLDR pThis = (PRTDBGMODLDR)RTMemAllocZ(sizeof(RTDBGMODLDR));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ pThis->hLdrMod = hLdrMod;
+ pDbgMod->pvImgPriv = pThis;
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/common/dbg/dbgmodnm.cpp b/src/VBox/Runtime/common/dbg/dbgmodnm.cpp
index 8a908fc4..9a564c36 100644
--- a/src/VBox/Runtime/common/dbg/dbgmodnm.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgmodnm.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -477,8 +477,10 @@ static int rtDbgModNmScanFile(PRTDBGMODNM pThis, PRTSTREAM pStrm, bool fAddSymbo
/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
-static DECLCALLBACK(int) rtDbgModNm_TryOpen(PRTDBGMODINT pMod)
+static DECLCALLBACK(int) rtDbgModNm_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
{
+ NOREF(enmArch);
+
/*
* Fend off images.
*/
diff --git a/src/VBox/Runtime/common/dvm/dvm.cpp b/src/VBox/Runtime/common/dvm/dvm.cpp
index 10011f30..fad94226 100644
--- a/src/VBox/Runtime/common/dvm/dvm.cpp
+++ b/src/VBox/Runtime/common/dvm/dvm.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp b/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp
index 66b41b90..d6274fc9 100644
--- a/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp
+++ b/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/dvm/dvmgpt.cpp b/src/VBox/Runtime/common/dvm/dvmgpt.cpp
index a63c9ac5..866229d7 100644
--- a/src/VBox/Runtime/common/dvm/dvmgpt.cpp
+++ b/src/VBox/Runtime/common/dvm/dvmgpt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/dvm/dvmmbr.cpp b/src/VBox/Runtime/common/dvm/dvmmbr.cpp
index 43a1561a..91314dee 100644
--- a/src/VBox/Runtime/common/dvm/dvmmbr.cpp
+++ b/src/VBox/Runtime/common/dvm/dvmmbr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/err/RTErrConvertFromErrno.cpp b/src/VBox/Runtime/common/err/RTErrConvertFromErrno.cpp
index a60da983..f079f064 100644
--- a/src/VBox/Runtime/common/err/RTErrConvertFromErrno.cpp
+++ b/src/VBox/Runtime/common/err/RTErrConvertFromErrno.cpp
@@ -430,7 +430,9 @@ RTDECL(int) RTErrConvertFromErrno(unsigned uNativeCode)
case EPROCLIM: return VERR_MAX_PROCS_REACHED;
#endif
#ifdef EDOOFUS
+# if EDOOFUS != EINVAL
case EDOOFUS: return VERR_INTERNAL_ERROR;
+# endif
#endif
#ifdef ENOTSUP
# ifndef EOPNOTSUPP
diff --git a/src/VBox/Runtime/common/err/RTErrConvertToErrno.cpp b/src/VBox/Runtime/common/err/RTErrConvertToErrno.cpp
index 6371f0a6..0e90b202 100644
--- a/src/VBox/Runtime/common/err/RTErrConvertToErrno.cpp
+++ b/src/VBox/Runtime/common/err/RTErrConvertToErrno.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2009 Oracle Corporation
+ * Copyright (C) 2007-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/err/errinfo.cpp b/src/VBox/Runtime/common/err/errinfo.cpp
index 7b43ee85..4d50db5f 100644
--- a/src/VBox/Runtime/common/err/errinfo.cpp
+++ b/src/VBox/Runtime/common/err/errinfo.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/err/errmsg.cpp b/src/VBox/Runtime/common/err/errmsg.cpp
index b5d223c6..31cd4370 100644
--- a/src/VBox/Runtime/common/err/errmsg.cpp
+++ b/src/VBox/Runtime/common/err/errmsg.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/err/errmsg.sed b/src/VBox/Runtime/common/err/errmsg.sed
index 5dc80e9c..2ccc7be0 100644
--- a/src/VBox/Runtime/common/err/errmsg.sed
+++ b/src/VBox/Runtime/common/err/errmsg.sed
@@ -49,33 +49,14 @@ b end
##
# Convert descriptive comments. /** desc */
:description
-# arg! how to do N until end of comment?
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
-/\*\//!N
+
+# Read all the lines belonging to the comment into the buffer.
+:look-for-end-of-comment
+/\*\//bend-of-comment
+N
+blook-for-end-of-comment
+:end-of-comment
+
# anything with @{ and @} is skipped
/@[\{\}]/d
diff --git a/src/VBox/Runtime/common/err/errmsgcom.sed b/src/VBox/Runtime/common/err/errmsgcom.sed
index b101ad7c..bd47a60d 100644
--- a/src/VBox/Runtime/common/err/errmsgcom.sed
+++ b/src/VBox/Runtime/common/err/errmsgcom.sed
@@ -3,7 +3,7 @@
# IPRT - SED script for converting COM errors
#
-# Copyright (C) 2006-2009 Oracle Corporation
+# Copyright (C) 2006-2010 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/err/errmsgxpcom.cpp b/src/VBox/Runtime/common/err/errmsgxpcom.cpp
index 74071989..8d9903f0 100644
--- a/src/VBox/Runtime/common/err/errmsgxpcom.cpp
+++ b/src/VBox/Runtime/common/err/errmsgxpcom.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/filesystem/filesystem.cpp b/src/VBox/Runtime/common/filesystem/filesystem.cpp
index 1f929911..37deee49 100644
--- a/src/VBox/Runtime/common/filesystem/filesystem.cpp
+++ b/src/VBox/Runtime/common/filesystem/filesystem.cpp
@@ -115,4 +115,3 @@ RTDECL(int) RTFilesystemVfsFromFile(RTVFSFILE hVfsFile, PRTVFS phVfs)
return rc;
}
-
diff --git a/src/VBox/Runtime/common/filesystem/filesystemext.cpp b/src/VBox/Runtime/common/filesystem/filesystemext.cpp
index 3f527063..f6e138ae 100644
--- a/src/VBox/Runtime/common/filesystem/filesystemext.cpp
+++ b/src/VBox/Runtime/common/filesystem/filesystemext.cpp
@@ -325,6 +325,8 @@ static DECLCALLBACK(void) rtFsExtDestroy(void *pvThis)
static DECLCALLBACK(int) rtFsExtOpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
{
+ NOREF(pvThis);
+ NOREF(phVfsDir);
return VERR_NOT_IMPLEMENTED;
}
diff --git a/src/VBox/Runtime/common/ldr/ldr.cpp b/src/VBox/Runtime/common/ldr/ldr.cpp
index fda1e437..218b4105 100644
--- a/src/VBox/Runtime/common/ldr/ldr.cpp
+++ b/src/VBox/Runtime/common/ldr/ldr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -40,14 +40,6 @@
#include "internal/ldr.h"
-/**
- * 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)
{
/*
@@ -65,15 +57,6 @@ RTDECL(bool) RTLdrIsLoadable(const char *pszFilename)
RT_EXPORT_SYMBOL(RTLdrIsLoadable);
-/**
- * Gets the address of a named exported symbol.
- *
- * @returns iprt status code.
- * @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)
{
LogFlow(("RTLdrGetSymbol: hLdrMod=%RTldrm pszSymbol=%p:{%s} ppvValue=%p\n",
@@ -110,15 +93,53 @@ RTDECL(int) RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvVa
RT_EXPORT_SYMBOL(RTLdrGetSymbol);
-/**
- * Closes a loader module handle.
- *
- * The handle can be obtained using any of the RTLdrLoad(), RTLdrOpen()
- * and RTLdrOpenBits() functions.
- *
- * @returns iprt status code.
- * @param hLdrMod The loader module handle.
- */
+RTDECL(PFNRT) RTLdrGetFunction(RTLDRMOD hLdrMod, const char *pszSymbol)
+{
+ PFNRT pfn;
+ int rc = RTLdrGetSymbol(hLdrMod, pszSymbol, (void **)&pfn);
+ if (RT_SUCCESS(rc))
+ return pfn;
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTLdrGetFunction);
+
+
+RTDECL(RTLDRFMT) RTLdrGetFormat(RTLDRMOD hLdrMod)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRFMT_INVALID);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+ return pMod->enmFormat;
+}
+RT_EXPORT_SYMBOL(RTLdrGetFormat);
+
+
+RTDECL(RTLDRTYPE) RTLdrGetType(RTLDRMOD hLdrMod)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRTYPE_INVALID);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+ return pMod->enmType;
+}
+RT_EXPORT_SYMBOL(RTLdrGetType);
+
+
+RTDECL(RTLDRENDIAN) RTLdrGetEndian(RTLDRMOD hLdrMod)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRENDIAN_INVALID);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+ return pMod->enmEndian;
+}
+RT_EXPORT_SYMBOL(RTLdrGetEndian);
+
+
+RTDECL(RTLDRARCH) RTLdrGetArch(RTLDRMOD hLdrMod)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRARCH_INVALID);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+ return pMod->enmArch;
+}
+RT_EXPORT_SYMBOL(RTLdrGetArch);
+
+
RTDECL(int) RTLdrClose(RTLDRMOD hLdrMod)
{
LogFlow(("RTLdrClose: hLdrMod=%RTldrm\n", hLdrMod));
@@ -137,6 +158,12 @@ RTDECL(int) RTLdrClose(RTLDRMOD hLdrMod)
AssertRC(rc);
pMod->eState = LDR_STATE_INVALID;
pMod->u32Magic++;
+ if (pMod->pReader)
+ {
+ rc = pMod->pReader->pfnDestroy(pMod->pReader);
+ AssertRC(rc);
+ pMod->pReader = NULL;
+ }
RTMemFree(pMod);
LogFlow(("RTLdrClose: returns VINF_SUCCESS\n"));
diff --git a/src/VBox/Runtime/common/ldr/ldrELF.cpp b/src/VBox/Runtime/common/ldr/ldrELF.cpp
index 47b45f61..ce08533b 100644
--- a/src/VBox/Runtime/common/ldr/ldrELF.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrELF.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -48,8 +48,10 @@
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
-/** Finds an ELF string. */
+/** Finds an ELF symbol table string. */
#define ELF_STR(pHdrs, iStr) ((pHdrs)->pStr + (iStr))
+/** Finds an ELF section header string. */
+#define ELF_SH_STR(pHdrs, iStr) ((pHdrs)->pShStr + (iStr))
diff --git a/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h b/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h
index 20d11b35..bd7760b4 100644
--- a/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h
+++ b/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -92,21 +92,25 @@ typedef struct RTLDRMODELF
{
/** Core module structure. */
RTLDRMODINTERNAL Core;
- /** Pointer to the reader instance. */
- PRTLDRREADER pReader;
/** Pointer to readonly mapping of the image bits.
* This mapping is provided by the pReader. */
const void *pvBits;
/** The ELF header. */
Elf_Ehdr Ehdr;
- /** Pointer to our copy of the section headers.
+ /** Pointer to our copy of the section headers with sh_addr as RVAs.
* The virtual addresses in this array is the 0 based assignments we've given the image.
* Not valid if the image is DONE. */
Elf_Shdr *paShdrs;
+ /** Unmodified section headers (allocated after paShdrs, so no need to free).
+ * Not valid if the image is DONE. */
+ Elf_Shdr const *paOrgShdrs;
/** The size of the loaded image. */
size_t cbImage;
+ /** The image base address if it's an EXEC or DYN image. */
+ Elf_Addr LinkAddress;
+
/** The symbol section index. */
unsigned iSymSh;
/** Number of symbols in the table. */
@@ -120,6 +124,11 @@ typedef struct RTLDRMODELF
unsigned cbStr;
/** Pointer to string table within RTLDRMODELF::pvBits. */
const char *pStr;
+
+ /** Size of the section header string table. */
+ unsigned cbShStr;
+ /** Pointer to section header string table within RTLDRMODELF::pvBits. */
+ const char *pShStr;
} RTLDRMODELF, *PRTLDRMODELF;
@@ -136,7 +145,7 @@ static int RTLDRELF_NAME(MapBits)(PRTLDRMODELF pModElf, bool fNeedsBits)
NOREF(fNeedsBits);
if (pModElf->pvBits)
return VINF_SUCCESS;
- int rc = pModElf->pReader->pfnMap(pModElf->pReader, &pModElf->pvBits);
+ int rc = pModElf->Core.pReader->pfnMap(pModElf->Core.pReader, &pModElf->pvBits);
if (RT_SUCCESS(rc))
{
const uint8_t *pu8 = (const uint8_t *)pModElf->pvBits;
@@ -144,11 +153,244 @@ static int RTLDRELF_NAME(MapBits)(PRTLDRMODELF pModElf, bool fNeedsBits)
pModElf->paSyms = (const Elf_Sym *)(pu8 + pModElf->paShdrs[pModElf->iSymSh].sh_offset);
if (pModElf->iStrSh != ~0U)
pModElf->pStr = (const char *)(pu8 + pModElf->paShdrs[pModElf->iStrSh].sh_offset);
+ pModElf->pShStr = (const char *)(pu8 + pModElf->paShdrs[pModElf->Ehdr.e_shstrndx].sh_offset);
}
return rc;
}
+/*
+ *
+ * EXEC & DYN.
+ * EXEC & DYN.
+ * EXEC & DYN.
+ * EXEC & DYN.
+ * EXEC & DYN.
+ *
+ */
+
+
+/**
+ * Applies the fixups for a section in an executable image.
+ *
+ * @returns iprt status code.
+ * @param pModElf The ELF loader module instance data.
+ * @param BaseAddr The base address which the module is being fixedup to.
+ * @param pfnGetImport The callback function to use to resolve imports (aka unresolved externals).
+ * @param pvUser User argument to pass to the callback.
+ * @param SecAddr The section address. This is the address the relocations are relative to.
+ * @param cbSec The section size. The relocations must be inside this.
+ * @param pu8SecBaseR Where we read section bits from.
+ * @param pu8SecBaseW Where we write section bits to.
+ * @param pvRelocs Pointer to where we read the relocations from.
+ * @param cbRelocs Size of the relocations.
+ */
+static int RTLDRELF_NAME(RelocateSectionExecDyn)(PRTLDRMODELF pModElf, Elf_Addr BaseAddr,
+ PFNRTLDRIMPORT pfnGetImport, void *pvUser,
+ const Elf_Addr SecAddr, Elf_Size cbSec,
+ const uint8_t *pu8SecBaseR, uint8_t *pu8SecBaseW,
+ const void *pvRelocs, Elf_Size cbRelocs)
+{
+#if ELF_MODE != 32
+ NOREF(pu8SecBaseR);
+#endif
+
+ /*
+ * Iterate the relocations.
+ * The relocations are stored in an array of Elf32_Rel records and covers the entire relocation section.
+ */
+ const Elf_Addr offDelta = BaseAddr - pModElf->LinkAddress;
+ const Elf_Reloc *paRels = (const Elf_Reloc *)pvRelocs;
+ const unsigned iRelMax = (unsigned)(cbRelocs / sizeof(paRels[0]));
+ AssertMsgReturn(iRelMax == cbRelocs / sizeof(paRels[0]), (FMT_ELF_SIZE "\n", cbRelocs / sizeof(paRels[0])),
+ VERR_IMAGE_TOO_BIG);
+ for (unsigned iRel = 0; iRel < iRelMax; iRel++)
+ {
+ /*
+ * Skip R_XXX_NONE entries early to avoid confusion in the symbol
+ * getter code.
+ */
+#if ELF_MODE == 32
+ if (ELF_R_TYPE(paRels[iRel].r_info) == R_386_NONE)
+ continue;
+#elif ELF_MODE == 64
+ if (ELF_R_TYPE(paRels[iRel].r_info) == R_X86_64_NONE)
+ continue;
+#endif
+
+ /*
+ * Validate and find the symbol, resolve undefined ones.
+ */
+ Elf_Size iSym = ELF_R_SYM(paRels[iRel].r_info);
+ if (iSym >= pModElf->cSyms)
+ {
+ AssertMsgFailed(("iSym=%d is an invalid symbol index!\n", iSym));
+ return VERR_LDRELF_INVALID_SYMBOL_INDEX;
+ }
+ const Elf_Sym *pSym = &pModElf->paSyms[iSym];
+ if (pSym->st_name >= pModElf->cbStr)
+ {
+ AssertMsgFailed(("iSym=%d st_name=%d str sh_size=%d\n", iSym, pSym->st_name, pModElf->cbStr));
+ return VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET;
+ }
+
+ Elf_Addr SymValue = 0;
+ if (pSym->st_shndx == SHN_UNDEF)
+ {
+ /* Try to resolve the symbol. */
+ const char *pszName = ELF_STR(pModElf, pSym->st_name);
+ RTUINTPTR ExtValue;
+ int rc = pfnGetImport(&pModElf->Core, "", pszName, ~0, &ExtValue, pvUser);
+ AssertMsgRCReturn(rc, ("Failed to resolve '%s' rc=%Rrc\n", pszName, rc), rc);
+ SymValue = (Elf_Addr)ExtValue;
+ AssertMsgReturn((RTUINTPTR)SymValue == ExtValue, ("Symbol value overflowed! '%s'\n", pszName),
+ VERR_SYMBOL_VALUE_TOO_BIG);
+ Log2(("rtldrELF: #%-3d - UNDEF " FMT_ELF_ADDR " '%s'\n", iSym, SymValue, pszName));
+ }
+ else
+ {
+ AssertReturn(pSym->st_shndx < pModElf->cSyms || pSym->st_shndx == SHN_ABS, ("%#x\n", pSym->st_shndx));
+#if ELF_MODE == 64
+ SymValue = pSym->st_value;
+#endif
+ }
+
+#if ELF_MODE == 64
+ /* Calc the value. */
+ Elf_Addr Value;
+ if (pSym->st_shndx < pModElf->cSyms)
+ Value = SymValue + offDelta;
+ else
+ Value = SymValue + paRels[iRel].r_addend;
+#endif
+
+ /*
+ * Apply the fixup.
+ */
+ AssertMsgReturn(paRels[iRel].r_offset < cbSec, (FMT_ELF_ADDR " " FMT_ELF_SIZE "\n", paRels[iRel].r_offset, cbSec), VERR_LDRELF_INVALID_RELOCATION_OFFSET);
+#if ELF_MODE == 32
+ const Elf_Addr *pAddrR = (const Elf_Addr *)(pu8SecBaseR + paRels[iRel].r_offset); /* Where to read the addend. */
+#endif
+ Elf_Addr *pAddrW = (Elf_Addr *)(pu8SecBaseW + paRels[iRel].r_offset); /* Where to write the fixup. */
+ switch (ELF_R_TYPE(paRels[iRel].r_info))
+ {
+#if ELF_MODE == 32
+ /*
+ * Absolute addressing.
+ */
+ case R_386_32:
+ {
+ Elf_Addr Value;
+ if (pSym->st_shndx < pModElf->Ehdr.e_shnum)
+ Value = *pAddrR + offDelta; /* Simplified. */
+ else if (pSym->st_shndx == SHN_ABS)
+ continue; /* Internal fixup, no need to apply it. */
+ else if (pSym->st_shndx == SHN_UNDEF)
+ Value = SymValue + *pAddrR;
+ else
+ AssertFailedReturn(VERR_LDR_GENERAL_FAILURE); /** @todo SHN_COMMON */
+ *(uint32_t *)pAddrW = Value;
+ Log4((FMT_ELF_ADDR": R_386_32 Value=" FMT_ELF_ADDR "\n", SecAddr + paRels[iRel].r_offset + BaseAddr, Value));
+ break;
+ }
+
+ /*
+ * PC relative addressing.
+ */
+ case R_386_PC32:
+ {
+ Elf_Addr Value;
+ if (pSym->st_shndx < pModElf->Ehdr.e_shnum)
+ continue; /* Internal fixup, no need to apply it. */
+ else if (pSym->st_shndx == SHN_ABS)
+ Value = *pAddrR + offDelta; /* Simplified. */
+ else if (pSym->st_shndx == SHN_UNDEF)
+ {
+ const Elf_Addr SourceAddr = SecAddr + paRels[iRel].r_offset + BaseAddr; /* Where the source really is. */
+ Value = SymValue + *(uint32_t *)pAddrR - SourceAddr;
+ *(uint32_t *)pAddrW = Value;
+ }
+ else
+ AssertFailedReturn(VERR_LDR_GENERAL_FAILURE); /** @todo SHN_COMMON */
+ Log4((FMT_ELF_ADDR": R_386_PC32 Value=" FMT_ELF_ADDR "\n", SecAddr + paRels[iRel].r_offset + BaseAddr, Value));
+ break;
+ }
+
+#elif ELF_MODE == 64
+
+ /*
+ * Absolute addressing
+ */
+ case R_X86_64_64:
+ {
+ *(uint64_t *)pAddrW = Value;
+ Log4((FMT_ELF_ADDR": R_X86_64_64 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
+ SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
+ break;
+ }
+
+ /*
+ * Truncated 32-bit value (zero-extendedable to the 64-bit value).
+ */
+ case R_X86_64_32:
+ {
+ *(uint32_t *)pAddrW = (uint32_t)Value;
+ Log4((FMT_ELF_ADDR": R_X86_64_32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
+ SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
+ AssertMsgReturn((Elf_Addr)*(uint32_t *)pAddrW == SymValue, ("Value=" FMT_ELF_ADDR "\n", SymValue),
+ VERR_SYMBOL_VALUE_TOO_BIG);
+ break;
+ }
+
+ /*
+ * Truncated 32-bit value (sign-extendedable to the 64-bit value).
+ */
+ case R_X86_64_32S:
+ {
+ *(int32_t *)pAddrW = (int32_t)Value;
+ Log4((FMT_ELF_ADDR": R_X86_64_32S Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
+ SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
+ AssertMsgReturn((Elf_Addr)*(int32_t *)pAddrW == Value, ("Value=" FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG); /** @todo check the sign-extending here. */
+ break;
+ }
+
+ /*
+ * PC relative addressing.
+ */
+ case R_X86_64_PC32:
+ {
+ const Elf_Addr SourceAddr = SecAddr + paRels[iRel].r_offset + BaseAddr; /* Where the source really is. */
+ Value -= SourceAddr;
+ *(int32_t *)pAddrW = (int32_t)Value;
+ Log4((FMT_ELF_ADDR": R_X86_64_PC32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
+ SourceAddr, Value, SymValue));
+ AssertMsgReturn((Elf_Addr)*(int32_t *)pAddrW == Value, ("Value=" FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG); /** @todo check the sign-extending here. */
+ break;
+ }
+#endif
+
+ default:
+ AssertMsgFailed(("Unknown relocation type: %d (iRel=%d iRelMax=%d)\n",
+ ELF_R_TYPE(paRels[iRel].r_info), iRel, iRelMax));
+ return VERR_LDRELF_RELOCATION_NOT_SUPPORTED;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+
+/*
+ *
+ * REL
+ * REL
+ * REL
+ * REL
+ * REL
+ *
+ */
+
/**
* Get the symbol and symbol value.
*
@@ -279,9 +521,22 @@ static int RTLDRELF_NAME(RelocateSection)(PRTLDRMODELF pModElf, Elf_Addr BaseAdd
for (unsigned iRel = 0; iRel < iRelMax; iRel++)
{
/*
+ * Skip R_XXX_NONE entries early to avoid confusion in the symbol
+ * getter code.
+ */
+#if ELF_MODE == 32
+ if (ELF_R_TYPE(paRels[iRel].r_info) == R_386_NONE)
+ continue;
+#elif ELF_MODE == 64
+ if (ELF_R_TYPE(paRels[iRel].r_info) == R_X86_64_NONE)
+ continue;
+#endif
+
+
+ /*
* Get the symbol.
*/
- const Elf_Sym *pSym;
+ const Elf_Sym *pSym = NULL; /* shut up gcc */
Elf_Addr SymValue = 0; /* shut up gcc-4 */
int rc = RTLDRELF_NAME(Symbol)(pModElf, BaseAddr, pfnGetImport, pvUser, ELF_R_SYM(paRels[iRel].r_info), &pSym, &SymValue);
if (RT_FAILURE(rc))
@@ -413,12 +668,6 @@ static DECLCALLBACK(int) RTLDRELF_NAME(Close)(PRTLDRMODINTERNAL pMod)
pModElf->paShdrs = NULL;
}
- if (pModElf->pReader)
- {
- pModElf->pReader->pfnDestroy(pModElf->pReader);
- pModElf->pReader = NULL;
- }
-
pModElf->pvBits = NULL;
return VINF_SUCCESS;
@@ -474,8 +723,13 @@ static DECLCALLBACK(int) RTLDRELF_NAME(EnumSymbols)(PRTLDRMODINTERNAL pMod, unsi
/* absolute symbols are not subject to any relocation. */
Value = paSyms[iSym].st_value;
else if (paSyms[iSym].st_shndx < pModElf->Ehdr.e_shnum)
- /* relative to the section. */
- Value = BaseAddr + paSyms[iSym].st_value + pModElf->paShdrs[paSyms[iSym].st_shndx].sh_addr;
+ {
+ if (pModElf->Ehdr.e_type == ET_REL)
+ /* relative to the section. */
+ Value = BaseAddr + paSyms[iSym].st_value + pModElf->paShdrs[paSyms[iSym].st_shndx].sh_addr;
+ else /* Fixed up for link address. */
+ Value = BaseAddr + paSyms[iSym].st_value - pModElf->LinkAddress;
+ }
else
{
AssertMsgFailed(("Arg! paSyms[%u].st_shndx=" FMT_ELF_HALF "\n", iSym, paSyms[iSym].st_shndx));
@@ -524,10 +778,10 @@ static DECLCALLBACK(int) RTLDRELF_NAME(GetBits)(PRTLDRMODINTERNAL pMod, void *pv
case ET_REL:
break;
case ET_EXEC:
- Log(("RTLdrELF: %s: Executable images are not supported yet!\n", pModElf->pReader->pfnLogName(pModElf->pReader)));
+ Log(("RTLdrELF: %s: Executable images are not supported yet!\n", pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader)));
return VERR_LDRELF_EXEC;
case ET_DYN:
- Log(("RTLdrELF: %s: Dynamic images are not supported yet!\n", pModElf->pReader->pfnLogName(pModElf->pReader)));
+ Log(("RTLdrELF: %s: Dynamic images are not supported yet!\n", pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader)));
return VERR_LDRELF_DYN;
default: AssertFailedReturn(VERR_BAD_EXE_FORMAT);
}
@@ -550,12 +804,12 @@ static DECLCALLBACK(int) RTLDRELF_NAME(GetBits)(PRTLDRMODINTERNAL pMod, void *pv
case SHT_PROGBITS:
default:
{
- int rc = pModElf->pReader->pfnRead(pModElf->pReader, (uint8_t *)pvBits + paShdrs[iShdr].sh_addr,
- (size_t)paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_offset);
+ int rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, (uint8_t *)pvBits + paShdrs[iShdr].sh_addr,
+ (size_t)paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_offset);
if (RT_FAILURE(rc))
{
Log(("RTLdrELF: %s: Read error when reading " FMT_ELF_SIZE " bytes at " FMT_ELF_OFF ", iShdr=%d\n",
- pModElf->pReader->pfnLogName(pModElf->pReader),
+ pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader),
paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_offset, iShdr));
return rc;
}
@@ -577,7 +831,7 @@ static DECLCALLBACK(int) RTLDRELF_NAME(Relocate)(PRTLDRMODINTERNAL pMod, void *p
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
#ifdef LOG_ENABLED
- const char *pszLogName = pModElf->pReader->pfnLogName(pModElf->pReader);
+ const char *pszLogName = pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader);
#endif
NOREF(OldBaseAddress);
@@ -640,17 +894,26 @@ static DECLCALLBACK(int) RTLDRELF_NAME(Relocate)(PRTLDRMODINTERNAL pMod, void *p
* Relocate the section.
*/
Log2(("rtldrELF: %s: Relocation records for #%d [%s] (sh_info=%d sh_link=%d) found in #%d [%s] (sh_info=%d sh_link=%d)\n",
- pszLogName, (int)pShdrRel->sh_info, ELF_STR(pModElf, pShdr->sh_name), (int)pShdr->sh_info, (int)pShdr->sh_link,
- iShdr, ELF_STR(pModElf, pShdrRel->sh_name), (int)pShdrRel->sh_info, (int)pShdrRel->sh_link));
+ pszLogName, (int)pShdrRel->sh_info, ELF_SH_STR(pModElf, pShdr->sh_name), (int)pShdr->sh_info, (int)pShdr->sh_link,
+ iShdr, ELF_SH_STR(pModElf, pShdrRel->sh_name), (int)pShdrRel->sh_info, (int)pShdrRel->sh_link));
/** @todo Make RelocateSection a function pointer so we can select the one corresponding to the machine when opening the image. */
- rc = RTLDRELF_NAME(RelocateSection)(pModElf, BaseAddr, pfnGetImport, pvUser,
- pShdr->sh_addr,
- pShdr->sh_size,
- (const uint8_t *)pModElf->pvBits + pShdr->sh_offset,
- (uint8_t *)pvBits + pShdr->sh_addr,
- (const uint8_t *)pModElf->pvBits + pShdrRel->sh_offset,
- pShdrRel->sh_size);
+ if (pModElf->Ehdr.e_type == ET_REL)
+ rc = RTLDRELF_NAME(RelocateSection)(pModElf, BaseAddr, pfnGetImport, pvUser,
+ pShdr->sh_addr,
+ pShdr->sh_size,
+ (const uint8_t *)pModElf->pvBits + pShdr->sh_offset,
+ (uint8_t *)pvBits + pShdr->sh_addr,
+ (const uint8_t *)pModElf->pvBits + pShdrRel->sh_offset,
+ pShdrRel->sh_size);
+ else
+ rc = RTLDRELF_NAME(RelocateSectionExecDyn)(pModElf, BaseAddr, pfnGetImport, pvUser,
+ pShdr->sh_addr,
+ pShdr->sh_size,
+ (const uint8_t *)pModElf->pvBits + pShdr->sh_offset,
+ (uint8_t *)pvBits + pShdr->sh_addr,
+ (const uint8_t *)pModElf->pvBits + pShdrRel->sh_offset,
+ pShdrRel->sh_size);
if (RT_FAILURE(rc))
return rc;
}
@@ -701,8 +964,13 @@ static DECLCALLBACK(int) RTLDRELF_NAME(GetSymbolEx)(PRTLDRMODINTERNAL pMod, cons
/* absolute symbols are not subject to any relocation. */
Value = paSyms[iSym].st_value;
else if (paSyms[iSym].st_shndx < pModElf->Ehdr.e_shnum)
- /* relative to the section. */
- Value = BaseAddr + paSyms[iSym].st_value + pModElf->paShdrs[paSyms[iSym].st_shndx].sh_addr;
+ {
+ if (pModElf->Ehdr.e_type == ET_REL)
+ /* relative to the section. */
+ Value = BaseAddr + paSyms[iSym].st_value + pModElf->paShdrs[paSyms[iSym].st_shndx].sh_addr;
+ else /* Fixed up for link address. */
+ Value = BaseAddr + paSyms[iSym].st_value - pModElf->LinkAddress;
+ }
else
{
AssertMsgFailed(("Arg. paSyms[iSym].st_shndx=%d\n", paSyms[iSym].st_shndx));
@@ -730,18 +998,163 @@ static DECLCALLBACK(int) RTLDRELF_NAME(EnumDbgInfo)(PRTLDRMODINTERNAL pMod, cons
PFNRTLDRENUMDBG pfnCallback, void *pvUser)
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
- NOREF(pvBits);
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(pfnCallback); NOREF(pvUser);
+ /*
+ * Map the image bits if not already done and setup pointer into it.
+ */
+ int rc = RTLDRELF_NAME(MapBits)(pModElf, true);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Do the enumeration.
+ */
+ const Elf_Shdr *paShdrs = pModElf->paOrgShdrs;
+ for (unsigned iShdr = 0; iShdr < pModElf->Ehdr.e_shnum; iShdr++)
+ {
+ /* Debug sections are expected to be PROGBITS and not allocated. */
+ if (paShdrs[iShdr].sh_type != SHT_PROGBITS)
+ continue;
+ if (paShdrs[iShdr].sh_flags & SHF_ALLOC)
+ continue;
+
+ RTLDRDBGINFO DbgInfo;
+ const char *pszSectName = ELF_SH_STR(pModElf, paShdrs[iShdr].sh_name);
+ if ( !strncmp(pszSectName, RT_STR_TUPLE(".debug_"))
+ || !strcmp(pszSectName, ".WATCOM_references") )
+ {
+ RT_ZERO(DbgInfo.u);
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF;
+ DbgInfo.pszExtFile = NULL;
+ DbgInfo.offFile = paShdrs[iShdr].sh_offset;
+ DbgInfo.cb = paShdrs[iShdr].sh_size;
+ DbgInfo.u.Dwarf.pszSection = pszSectName;
+ }
+ else if (!strcmp(pszSectName, ".gnu_debuglink"))
+ {
+ if ((paShdrs[iShdr].sh_size & 3) || paShdrs[iShdr].sh_size < 8)
+ return VERR_BAD_EXE_FORMAT;
+
+ RT_ZERO(DbgInfo.u);
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF_DWO;
+ DbgInfo.pszExtFile = (const char *)((uintptr_t)pModElf->pvBits + (uintptr_t)paShdrs[iShdr].sh_offset);
+ if (!RTStrEnd(DbgInfo.pszExtFile, paShdrs[iShdr].sh_size))
+ return VERR_BAD_EXE_FORMAT;
+ DbgInfo.u.Dwo.uCrc32 = *(uint32_t *)((uintptr_t)DbgInfo.pszExtFile + (uintptr_t)paShdrs[iShdr].sh_size
+ - sizeof(uint32_t));
+ DbgInfo.offFile = -1;
+ DbgInfo.cb = 0;
+ }
+ else
+ continue;
+
+ DbgInfo.LinkAddress = NIL_RTLDRADDR;
+ DbgInfo.iDbgInfo = iShdr - 1;
+
+ rc = pfnCallback(pMod, &DbgInfo, pvUser);
+ if (rc != VINF_SUCCESS)
+ return rc;
+
+ }
+
+ return VINF_SUCCESS;
}
+/**
+ * Helper that locates the first allocated section.
+ *
+ * @returns Pointer to the section header if found, NULL if none.
+ * @param pShdr The section header to start searching at.
+ * @param cLeft The number of section headers left to search. Can be 0.
+ */
+static const Elf_Shdr *RTLDRELF_NAME(GetFirstAllocatedSection)(const Elf_Shdr *pShdr, unsigned cLeft)
+{
+ while (cLeft-- > 0)
+ {
+ if (pShdr->sh_flags & SHF_ALLOC)
+ return pShdr;
+ pShdr++;
+ }
+ return NULL;
+}
+
/** @copydoc RTLDROPS::pfnEnumSegments. */
static DECLCALLBACK(int) RTLDRELF_NAME(EnumSegments)(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(pfnCallback); NOREF(pvUser);
+ /*
+ * Map the image bits if not already done and setup pointer into it.
+ */
+ int rc = RTLDRELF_NAME(MapBits)(pModElf, true);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Do the enumeration.
+ */
+ char szName[32];
+ Elf_Addr uPrevMappedRva = 0;
+ const Elf_Shdr *paShdrs = pModElf->paShdrs;
+ const Elf_Shdr *paOrgShdrs = pModElf->paOrgShdrs;
+ for (unsigned iShdr = 1; iShdr < pModElf->Ehdr.e_shnum; iShdr++)
+ {
+ RTLDRSEG Seg;
+ Seg.pszName = ELF_SH_STR(pModElf, paShdrs[iShdr].sh_name);
+ Seg.cchName = (uint32_t)strlen(Seg.pszName);
+ if (Seg.cchName == 0)
+ {
+ Seg.pszName = szName;
+ Seg.cchName = (uint32_t)RTStrPrintf(szName, sizeof(szName), "UnamedSect%02u", iShdr);
+ }
+ Seg.SelFlat = 0;
+ Seg.Sel16bit = 0;
+ Seg.fFlags = 0;
+ Seg.fProt = RTMEM_PROT_READ;
+ if (paShdrs[iShdr].sh_flags & SHF_WRITE)
+ Seg.fProt |= RTMEM_PROT_WRITE;
+ if (paShdrs[iShdr].sh_flags & SHF_EXECINSTR)
+ Seg.fProt |= RTMEM_PROT_EXEC;
+ Seg.cb = paShdrs[iShdr].sh_size;
+ Seg.Alignment = paShdrs[iShdr].sh_addralign;
+ if (paShdrs[iShdr].sh_flags & SHF_ALLOC)
+ {
+ Seg.LinkAddress = paOrgShdrs[iShdr].sh_addr;
+ Seg.RVA = paShdrs[iShdr].sh_addr;
+ const Elf_Shdr *pShdr2 = RTLDRELF_NAME(GetFirstAllocatedSection)(&paShdrs[iShdr + 1],
+ pModElf->Ehdr.e_shnum - iShdr - 1);
+ if ( pShdr2
+ && pShdr2->sh_addr >= paShdrs[iShdr].sh_addr
+ && Seg.RVA >= uPrevMappedRva)
+ Seg.cbMapped = pShdr2->sh_addr - paShdrs[iShdr].sh_addr;
+ else
+ Seg.cbMapped = RT_MAX(paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_addralign);
+ uPrevMappedRva = Seg.RVA;
+ }
+ else
+ {
+ Seg.LinkAddress = NIL_RTLDRADDR;
+ Seg.RVA = NIL_RTLDRADDR;
+ Seg.cbMapped = NIL_RTLDRADDR;
+ }
+ if (paShdrs[iShdr].sh_type != SHT_NOBITS)
+ {
+ Seg.offFile = paShdrs[iShdr].sh_offset;
+ Seg.cbFile = paShdrs[iShdr].sh_size;
+ }
+ else
+ {
+ Seg.offFile = -1;
+ Seg.cbFile = 0;
+ }
+
+ rc = pfnCallback(pMod, &Seg, pvUser);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ }
+
+ return VINF_SUCCESS;
}
@@ -751,7 +1164,34 @@ static DECLCALLBACK(int) RTLDRELF_NAME(LinkAddressToSegOffset)(PRTLDRMODINTERNAL
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(LinkAddress); NOREF(piSeg); NOREF(poffSeg);
+ const Elf_Shdr *pShdrEnd = NULL;
+ unsigned cLeft = pModElf->Ehdr.e_shnum - 1;
+ const Elf_Shdr *pShdr = &pModElf->paOrgShdrs[cLeft];
+ while (cLeft-- > 0)
+ {
+ if (pShdr->sh_flags & SHF_ALLOC)
+ {
+ RTLDRADDR offSeg = LinkAddress - pShdr->sh_addr;
+ if (offSeg < pShdr->sh_size)
+ {
+ *poffSeg = offSeg;
+ *piSeg = cLeft;
+ return VINF_SUCCESS;
+ }
+ if (offSeg == pShdr->sh_size)
+ pShdrEnd = pShdr;
+ }
+ pShdr--;
+ }
+
+ if (pShdrEnd)
+ {
+ *poffSeg = pShdrEnd->sh_size;
+ *piSeg = pShdrEnd - pModElf->paOrgShdrs - 1;
+ return VINF_SUCCESS;
+ }
+
+ return VERR_LDR_INVALID_LINK_ADDRESS;
}
@@ -759,8 +1199,12 @@ static DECLCALLBACK(int) RTLDRELF_NAME(LinkAddressToSegOffset)(PRTLDRMODINTERNAL
static DECLCALLBACK(int) RTLDRELF_NAME(LinkAddressToRva)(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
-
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(LinkAddress); NOREF(pRva);
+ uint32_t iSeg;
+ RTLDRADDR offSeg;
+ int rc = RTLDRELF_NAME(LinkAddressToSegOffset)(pMod, LinkAddress, &iSeg, &offSeg);
+ if (RT_SUCCESS(rc))
+ *pRva = pModElf->paShdrs[iSeg + 1].sh_addr + offSeg;
+ return rc;
}
@@ -769,8 +1213,24 @@ static DECLCALLBACK(int) RTLDRELF_NAME(SegOffsetToRva)(PRTLDRMODINTERNAL pMod, u
PRTLDRADDR pRva)
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
+ if (iSeg >= pModElf->Ehdr.e_shnum - 1U)
+ return VERR_LDR_INVALID_SEG_OFFSET;
+
+ iSeg++; /* skip section 0 */
+ if (offSeg > pModElf->paShdrs[iSeg].sh_size)
+ {
+ const Elf_Shdr *pShdr2 = RTLDRELF_NAME(GetFirstAllocatedSection)(&pModElf->paShdrs[iSeg + 1],
+ pModElf->Ehdr.e_shnum - iSeg - 1);
+ if ( !pShdr2
+ || offSeg > (pShdr2->sh_addr - pModElf->paShdrs[iSeg].sh_addr))
+ return VERR_LDR_INVALID_SEG_OFFSET;
+ }
+
+ if (!(pModElf->paShdrs[iSeg].sh_flags & SHF_ALLOC))
+ return VERR_LDR_INVALID_SEG_OFFSET;
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(iSeg); NOREF(offSeg); NOREF(pRva);
+ *pRva = pModElf->paShdrs[iSeg].sh_addr;
+ return VINF_SUCCESS;
}
@@ -780,7 +1240,136 @@ static DECLCALLBACK(int) RTLDRELF_NAME(RvaToSegOffset)(PRTLDRMODINTERNAL pMod, R
{
PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
- return VERR_NOT_IMPLEMENTED; NOREF(pModElf); NOREF(Rva); NOREF(piSeg); NOREF(poffSeg);
+ Elf_Addr PrevAddr = 0;
+ unsigned cLeft = pModElf->Ehdr.e_shnum - 1;
+ const Elf_Shdr *pShdr = &pModElf->paShdrs[cLeft];
+ while (cLeft-- > 0)
+ {
+ if (pShdr->sh_flags & SHF_ALLOC)
+ {
+ Elf_Addr cbSeg = PrevAddr ? PrevAddr - pShdr->sh_addr : pShdr->sh_size;
+ RTLDRADDR offSeg = Rva - pShdr->sh_addr;
+ if (offSeg <= cbSeg)
+ {
+ *poffSeg = offSeg;
+ *piSeg = cLeft;
+ return VINF_SUCCESS;
+ }
+ PrevAddr = pShdr->sh_addr;
+ }
+ pShdr--;
+ }
+
+ return VERR_LDR_INVALID_RVA;
+}
+
+
+/** @callback_method_impl{FNRTLDRIMPORT, Stub used by ReadDbgInfo.} */
+static DECLCALLBACK(int) RTLDRELF_NAME(GetImportStubCallback)(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
+ unsigned uSymbol, PRTLDRADDR pValue, void *pvUser)
+{
+ return VERR_SYMBOL_NOT_FOUND;
+}
+
+
+/** @copydoc RTLDROPS::pfnRvaToSegOffset. */
+static DECLCALLBACK(int) RTLDRELF_NAME(ReadDbgInfo)(PRTLDRMODINTERNAL pMod, uint32_t iDbgInfo, RTFOFF off,
+ size_t cb, void *pvBuf)
+{
+ PRTLDRMODELF pThis = (PRTLDRMODELF)pMod;
+ LogFlow(("%s: iDbgInfo=%#x off=%RTfoff cb=%#zu\n", __FUNCTION__, iDbgInfo, off, cb));
+
+ /*
+ * Input validation.
+ */
+ AssertReturn(iDbgInfo < pThis->Ehdr.e_shnum && iDbgInfo + 1 < pThis->Ehdr.e_shnum, VERR_INVALID_PARAMETER);
+ iDbgInfo++;
+ AssertReturn(!(pThis->paShdrs[iDbgInfo].sh_flags & SHF_ALLOC), VERR_INVALID_PARAMETER);
+ AssertReturn(pThis->paShdrs[iDbgInfo].sh_type == SHT_PROGBITS, VERR_INVALID_PARAMETER);
+ AssertReturn(pThis->paShdrs[iDbgInfo].sh_offset == (uint64_t)off, VERR_INVALID_PARAMETER);
+ AssertReturn(pThis->paShdrs[iDbgInfo].sh_size == cb, VERR_INVALID_PARAMETER);
+ RTFOFF cbRawImage = pThis->Core.pReader->pfnSize(pThis->Core.pReader);
+ AssertReturn(cbRawImage >= 0, VERR_INVALID_PARAMETER);
+ AssertReturn(off >= 0 && cb <= (uint64_t)cbRawImage && (uint64_t)off + cb <= (uint64_t)cbRawImage, VERR_INVALID_PARAMETER);
+
+ /*
+ * Read it from the file and look for fixup sections.
+ */
+ int rc;
+ if (pThis->pvBits)
+ memcpy(pvBuf, (const uint8_t *)pThis->pvBits + (size_t)off, cb);
+ else
+ {
+ rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvBuf, cb, off);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ uint32_t iRelocs = iDbgInfo + 1;
+ if ( iRelocs >= pThis->Ehdr.e_shnum
+ || pThis->paShdrs[iRelocs].sh_info != iDbgInfo
+ || ( pThis->paShdrs[iRelocs].sh_type != SHT_REL
+ && pThis->paShdrs[iRelocs].sh_type != SHT_RELA) )
+ {
+ iRelocs = 0;
+ while ( iRelocs < pThis->Ehdr.e_shnum
+ && ( pThis->paShdrs[iRelocs].sh_info != iDbgInfo
+ || ( pThis->paShdrs[iRelocs].sh_type != SHT_REL
+ && pThis->paShdrs[iRelocs].sh_type != SHT_RELA)) )
+ iRelocs++;
+ }
+ if ( iRelocs < pThis->Ehdr.e_shnum
+ && pThis->paShdrs[iRelocs].sh_size > 0)
+ {
+ /*
+ * Load the relocations.
+ */
+ uint8_t *pbRelocsBuf = NULL;
+ const uint8_t *pbRelocs;
+ if (pThis->pvBits)
+ pbRelocs = (const uint8_t *)pThis->pvBits + pThis->paShdrs[iRelocs].sh_offset;
+ else
+ {
+ pbRelocs = pbRelocsBuf = (uint8_t *)RTMemTmpAlloc(pThis->paShdrs[iRelocs].sh_size);
+ if (!pbRelocsBuf)
+ return VERR_NO_TMP_MEMORY;
+ rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbRelocsBuf,
+ pThis->paShdrs[iRelocs].sh_size,
+ pThis->paShdrs[iRelocs].sh_offset);
+ if (RT_FAILURE(rc))
+ {
+ RTMemTmpFree(pbRelocsBuf);
+ return rc;
+ }
+ }
+
+ /*
+ * Apply the relocations.
+ */
+ if (pThis->Ehdr.e_type == ET_REL)
+ rc = RTLDRELF_NAME(RelocateSection)(pThis, pThis->LinkAddress,
+ RTLDRELF_NAME(GetImportStubCallback), NULL /*pvUser*/,
+ pThis->paShdrs[iDbgInfo].sh_addr,
+ pThis->paShdrs[iDbgInfo].sh_size,
+ (const uint8_t *)pvBuf,
+ (uint8_t *)pvBuf,
+ pbRelocs,
+ pThis->paShdrs[iRelocs].sh_size);
+ else
+ rc = RTLDRELF_NAME(RelocateSectionExecDyn)(pThis, pThis->LinkAddress,
+ RTLDRELF_NAME(GetImportStubCallback), NULL /*pvUser*/,
+ pThis->paShdrs[iDbgInfo].sh_addr,
+ pThis->paShdrs[iDbgInfo].sh_size,
+ (const uint8_t *)pvBuf,
+ (uint8_t *)pvBuf,
+ pbRelocs,
+ pThis->paShdrs[iRelocs].sh_size);
+
+ RTMemTmpFree(pbRelocsBuf);
+ }
+ else
+ rc = VINF_SUCCESS;
+ return rc;
}
@@ -810,6 +1399,7 @@ static RTLDROPS RTLDRELF_MID(s_rtldrElf,Ops) =
RTLDRELF_NAME(LinkAddressToRva),
RTLDRELF_NAME(SegOffsetToRva),
RTLDRELF_NAME(RvaToSegOffset),
+ RTLDRELF_NAME(ReadDbgInfo),
42
};
@@ -949,6 +1539,13 @@ static int RTLDRELF_NAME(ValidateElfHeader)(const Elf_Ehdr *pEhdr, const char *p
return VERR_BAD_EXE_FORMAT;
}
+ if (pEhdr->e_shstrndx == 0 || pEhdr->e_shstrndx > pEhdr->e_shnum)
+ {
+ Log(("RTLdrELF: %s: The section headers string table is out of bounds! e_shstrndx=" FMT_ELF_HALF " e_shnum=" FMT_ELF_HALF "\n",
+ pszLogName, pEhdr->e_shstrndx, pEhdr->e_shnum));
+ return VERR_BAD_EXE_FORMAT;
+ }
+
return VINF_SUCCESS;
}
@@ -956,7 +1553,6 @@ static int RTLDRELF_NAME(ValidateElfHeader)(const Elf_Ehdr *pEhdr, const char *p
* Gets the section header name.
*
* @returns pszName.
- * @param pReader The loader reader instance.
* @param pEhdr The elf header.
* @param offName The offset of the section header name.
* @param pszName Where to store the name.
@@ -965,13 +1561,13 @@ static int RTLDRELF_NAME(ValidateElfHeader)(const Elf_Ehdr *pEhdr, const char *p
const char *RTLDRELF_NAME(GetSHdrName)(PRTLDRMODELF pModElf, Elf_Word offName, char *pszName, size_t cbName)
{
RTFOFF off = pModElf->paShdrs[pModElf->Ehdr.e_shstrndx].sh_offset + offName;
- int rc = pModElf->pReader->pfnRead(pModElf->pReader, pszName, cbName - 1, off);
+ int rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, pszName, cbName - 1, off);
if (RT_FAILURE(rc))
{
/* read by for byte. */
for (unsigned i = 0; i < cbName; i++, off++)
{
- rc = pModElf->pReader->pfnRead(pModElf->pReader, pszName + i, 1, off);
+ rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, pszName + i, 1, off);
if (RT_FAILURE(rc))
{
pszName[i] = '\0';
@@ -1016,6 +1612,31 @@ static int RTLDRELF_NAME(ValidateSectionHeader)(PRTLDRMODELF pModElf, unsigned i
pShdr->sh_offset, pShdr->sh_size, pShdr->sh_link, pShdr->sh_info, pShdr->sh_addralign,
pShdr->sh_entsize));
+ if (iShdr == 0)
+ {
+ if ( pShdr->sh_name != 0
+ || pShdr->sh_type != SHT_NULL
+ || pShdr->sh_flags != 0
+ || pShdr->sh_addr != 0
+ || pShdr->sh_size != 0
+ || pShdr->sh_offset != 0
+ || pShdr->sh_link != SHN_UNDEF
+ || pShdr->sh_addralign != 0
+ || pShdr->sh_entsize != 0 )
+ {
+ Log(("RTLdrELF: %s: Bad #0 section: %.*Rhxs\n", pszLogName, sizeof(*pShdr), pShdr ));
+ return VERR_BAD_EXE_FORMAT;
+ }
+ return VINF_SUCCESS;
+ }
+
+ if (pShdr->sh_name >= pModElf->cbShStr)
+ {
+ Log(("RTLdrELF: %s: Shdr #%d: sh_name (%d) is beyond the end of the section header string table (%d)!\n",
+ pszLogName, iShdr, pShdr->sh_name, pModElf->cbShStr)); NOREF(pszLogName);
+ return VERR_BAD_EXE_FORMAT;
+ }
+
if (pShdr->sh_link >= pModElf->Ehdr.e_shnum)
{
Log(("RTLdrELF: %s: Shdr #%d: sh_link (%d) is beyond the end of the section table (%d)!\n",
@@ -1036,6 +1657,7 @@ static int RTLDRELF_NAME(ValidateSectionHeader)(PRTLDRMODELF pModElf, unsigned i
break;
case SHT_NULL:
+ break;
case SHT_PROGBITS:
case SHT_SYMTAB:
case SHT_STRTAB:
@@ -1096,7 +1718,6 @@ static int RTLDRELF_NAME(Open)(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH
{
const char *pszLogName = pReader->pfnLogName(pReader);
RTFOFF cbRawImage = pReader->pfnSize(pReader);
- AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
/*
* Create the loader module instance.
@@ -1107,17 +1728,28 @@ static int RTLDRELF_NAME(Open)(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH
pModElf->Core.u32Magic = RTLDRMOD_MAGIC;
pModElf->Core.eState = LDR_STATE_INVALID;
- pModElf->pReader = pReader;
+ pModElf->Core.pReader = pReader;
+ pModElf->Core.enmFormat = RTLDRFMT_ELF;
+ pModElf->Core.enmType = RTLDRTYPE_OBJECT;
+ pModElf->Core.enmEndian = RTLDRENDIAN_LITTLE;
+#if ELF_MODE == 32
+ pModElf->Core.enmArch = RTLDRARCH_X86_32;
+#else
+ pModElf->Core.enmArch = RTLDRARCH_AMD64;
+#endif
//pModElf->pvBits = NULL;
//pModElf->Ehdr = {0};
//pModElf->paShdrs = NULL;
//pModElf->paSyms = NULL;
pModElf->iSymSh = ~0U;
- pModElf->cSyms = 0;
+ //pModElf->cSyms = 0;
pModElf->iStrSh = ~0U;
- pModElf->cbStr = 0;
- pModElf->cbImage = 0;
+ //pModElf->cbStr = 0;
+ //pModElf->cbImage = 0;
+ //pModElf->LinkAddress = 0;
//pModElf->pStr = NULL;
+ //pModElf->cbShStr = 0;
+ //pModElf->pShStr = NULL;
/*
* Read and validate the ELF header and match up the CPU architecture.
@@ -1137,39 +1769,32 @@ static int RTLDRELF_NAME(Open)(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH
if (RT_SUCCESS(rc))
{
/*
- * Read the section headers.
+ * Read the section headers, keeping a prestine copy for the module
+ * introspection methods.
*/
- Elf_Shdr *paShdrs = (Elf_Shdr *)RTMemAlloc(pModElf->Ehdr.e_shnum * sizeof(Elf_Shdr));
+ size_t const cbShdrs = pModElf->Ehdr.e_shnum * sizeof(Elf_Shdr);
+ Elf_Shdr *paShdrs = (Elf_Shdr *)RTMemAlloc(cbShdrs * 2);
if (paShdrs)
{
pModElf->paShdrs = paShdrs;
- rc = pReader->pfnRead(pReader, paShdrs, pModElf->Ehdr.e_shnum * sizeof(Elf_Shdr),
- pModElf->Ehdr.e_shoff);
+ rc = pReader->pfnRead(pReader, paShdrs, cbShdrs, pModElf->Ehdr.e_shoff);
if (RT_SUCCESS(rc))
{
+ memcpy(&paShdrs[pModElf->Ehdr.e_shnum], paShdrs, cbShdrs);
+ pModElf->paOrgShdrs = &paShdrs[pModElf->Ehdr.e_shnum];
+
+ pModElf->cbShStr = paShdrs[pModElf->Ehdr.e_shstrndx].sh_size;
+
/*
- * Validate the section headers, allocate memory for the sections (determine the image size),
- * and find relevant sections.
+ * Validate the section headers and find relevant sections.
*/
+ Elf_Addr uNextAddr = 0;
for (unsigned i = 0; i < pModElf->Ehdr.e_shnum; i++)
{
rc = RTLDRELF_NAME(ValidateSectionHeader)(pModElf, i, pszLogName, cbRawImage);
if (RT_FAILURE(rc))
break;
- /* Allocate memory addresses for the section. */
- if (paShdrs[i].sh_flags & SHF_ALLOC)
- {
- paShdrs[i].sh_addr = paShdrs[i].sh_addralign
- ? RT_ALIGN_T(pModElf->cbImage, paShdrs[i].sh_addralign, Elf_Addr)
- : (Elf_Addr)pModElf->cbImage;
- pModElf->cbImage = (size_t)paShdrs[i].sh_addr + (size_t)paShdrs[i].sh_size;
- AssertMsgReturn(pModElf->cbImage == paShdrs[i].sh_addr + paShdrs[i].sh_size,
- (FMT_ELF_ADDR "\n", paShdrs[i].sh_addr + paShdrs[i].sh_size),
- VERR_IMAGE_TOO_BIG);
- Log2(("RTLdrElf: %s: Assigned " FMT_ELF_ADDR " to section #%d\n", pszLogName, paShdrs[i].sh_addr, i));
- }
-
/* We're looking for symbol tables. */
if (paShdrs[i].sh_type == SHT_SYMTAB)
{
@@ -1186,19 +1811,81 @@ static int RTLDRELF_NAME(Open)(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH
pModElf->cbStr = (unsigned)paShdrs[pModElf->iStrSh].sh_size;
AssertReturn(pModElf->cbStr == paShdrs[pModElf->iStrSh].sh_size, VERR_IMAGE_TOO_BIG);
}
+
+ /* Special checks for the section string table. */
+ if (i == pModElf->Ehdr.e_shstrndx)
+ {
+ if (paShdrs[i].sh_type != SHT_STRTAB)
+ {
+ Log(("RTLdrElf: Section header string table is not a SHT_STRTAB: %#x\n", paShdrs[i].sh_type));
+ rc = VERR_BAD_EXE_FORMAT;
+ break;
+ }
+ if (paShdrs[i].sh_size == 0)
+ {
+ Log(("RTLdrElf: Section header string table is empty\n"));
+ rc = VERR_BAD_EXE_FORMAT;
+ break;
+ }
+ }
+
+ /* Kluge for the .data..percpu segment in 64-bit linux kernels. */
+ if (paShdrs[i].sh_flags & SHF_ALLOC)
+ {
+ if ( paShdrs[i].sh_addr == 0
+ && paShdrs[i].sh_addr < uNextAddr)
+ {
+ Elf_Addr uAddr = RT_ALIGN_T(uNextAddr, paShdrs[i].sh_addralign, Elf_Addr);
+ Log(("RTLdrElf: Out of order section #%d; adjusting sh_addr from " FMT_ELF_ADDR " to " FMT_ELF_ADDR "\n",
+ paShdrs[i].sh_addr, uAddr));
+ paShdrs[i].sh_addr = uAddr;
+ }
+ uNextAddr = paShdrs[i].sh_addr + paShdrs[i].sh_size;
+ }
} /* for each section header */
- Log2(("RTLdrElf: iSymSh=%u cSyms=%u iStrSh=%u cbStr=%u rc=%Rrc cbImage=%#zx\n",
- pModElf->iSymSh, pModElf->cSyms, pModElf->iStrSh, pModElf->cbStr, rc, pModElf->cbImage));
-#if 0
/*
- * Are the section headers fine?
- * We require there to be symbol & string tables (at least for the time being).
+ * Calculate the image base address if the image isn't relocatable.
*/
- if ( pModElf->iSymSh == ~0U
- || pModElf->iStrSh == ~0U)
- rc = VERR_LDRELF_NO_SYMBOL_OR_NO_STRING_TABS;
-#endif
+ if (RT_SUCCESS(rc) && pModElf->Ehdr.e_type != ET_REL)
+ {
+ pModElf->LinkAddress = ~(Elf_Addr)0;
+ for (unsigned i = 0; i < pModElf->Ehdr.e_shnum; i++)
+ if ( (paShdrs[i].sh_flags & SHF_ALLOC)
+ && paShdrs[i].sh_addr < pModElf->LinkAddress)
+ pModElf->LinkAddress = paShdrs[i].sh_addr;
+ if (pModElf->LinkAddress == ~(Elf_Addr)0)
+ {
+ AssertFailed();
+ rc = VERR_LDR_GENERAL_FAILURE;
+ }
+ }
+
+ /*
+ * Perform allocations / RVA calculations, determine the image size.
+ */
+ if (RT_SUCCESS(rc))
+ for (unsigned i = 0; i < pModElf->Ehdr.e_shnum; i++)
+ if (paShdrs[i].sh_flags & SHF_ALLOC)
+ {
+ if (pModElf->Ehdr.e_type == ET_REL)
+ paShdrs[i].sh_addr = paShdrs[i].sh_addralign
+ ? RT_ALIGN_T(pModElf->cbImage, paShdrs[i].sh_addralign, Elf_Addr)
+ : (Elf_Addr)pModElf->cbImage;
+ else
+ paShdrs[i].sh_addr -= pModElf->LinkAddress;
+ Elf_Addr EndAddr = paShdrs[i].sh_addr + paShdrs[i].sh_size;
+ if (pModElf->cbImage < EndAddr)
+ {
+ pModElf->cbImage = (size_t)EndAddr;
+ AssertMsgReturn(pModElf->cbImage == EndAddr, (FMT_ELF_ADDR "\n", EndAddr), VERR_IMAGE_TOO_BIG);
+ }
+ Log2(("RTLdrElf: %s: Assigned " FMT_ELF_ADDR " to section #%d\n", pszLogName, paShdrs[i].sh_addr, i));
+ }
+
+ Log2(("RTLdrElf: iSymSh=%u cSyms=%u iStrSh=%u cbStr=%u rc=%Rrc cbImage=%#zx LinkAddress=" FMT_ELF_ADDR "\n",
+ pModElf->iSymSh, pModElf->cSyms, pModElf->iStrSh, pModElf->cbStr, rc,
+ pModElf->cbImage, pModElf->LinkAddress));
if (RT_SUCCESS(rc))
{
pModElf->Core.pOps = &RTLDRELF_MID(s_rtldrElf,Ops);
diff --git a/src/VBox/Runtime/common/ldr/ldrEx.cpp b/src/VBox/Runtime/common/ldr/ldrEx.cpp
index 8bc6b9bd..ba73910d 100644
--- a/src/VBox/Runtime/common/ldr/ldrEx.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrEx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -165,15 +165,6 @@ int rtldrOpenWithReader(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch
}
-/**
- * Gets the size of the loaded image.
- * This is only supported for modules which has been opened using RTLdrOpen() and RTLdrOpenBits().
- *
- * @returns image size (in bytes).
- * @returns ~(size_t)0 on if not opened by RTLdrOpen().
- * @param hLdrMod Handle to the loader module.
- * @remark Not supported for RTLdrLoad() images.
- */
RTDECL(size_t) RTLdrSize(RTLDRMOD hLdrMod)
{
LogFlow(("RTLdrSize: hLdrMod=%RTldrm\n", hLdrMod));
@@ -547,3 +538,34 @@ RTDECL(int) RTLdrRvaToSegOffset(RTLDRMOD hLdrMod, RTLDRADDR Rva, uint32_t *piSeg
}
RT_EXPORT_SYMBOL(RTLdrRvaToSegOffset);
+
+/**
+ * Internal method used by the IPRT debug bits.
+ *
+ * @returns IPRT status code.
+ * @param hLdrMod The loader handle which executable we wish to
+ * read from.
+ * @param pvBuf The output buffer.
+ * @param iDbgInfo The debug info ordinal number if the request
+ * corresponds exactly to a debug info part from
+ * pfnEnumDbgInfo. Otherwise, pass UINT32_MAX.
+ * @param off Where in the executable file to start reading.
+ * @param cb The number of bytes to read.
+ *
+ * @remarks Fixups will only be applied if @a iDbgInfo is specified.
+ */
+DECLHIDDEN(int) rtLdrReadAt(RTLDRMOD hLdrMod, void *pvBuf, uint32_t iDbgInfo, RTFOFF off, size_t cb)
+{
+ AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), VERR_INVALID_HANDLE);
+ PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
+
+ if (iDbgInfo != UINT32_MAX)
+ {
+ AssertReturn(pMod->pOps->pfnReadDbgInfo, VERR_NOT_SUPPORTED);
+ return pMod->pOps->pfnReadDbgInfo(pMod, iDbgInfo, off, cb, pvBuf);
+ }
+
+ AssertReturn(pMod->pReader, VERR_NOT_SUPPORTED);
+ return pMod->pReader->pfnRead(pMod->pReader, pvBuf, cb, off);
+}
+
diff --git a/src/VBox/Runtime/common/ldr/ldrFile.cpp b/src/VBox/Runtime/common/ldr/ldrFile.cpp
index 65f408d4..e10fe702 100644
--- a/src/VBox/Runtime/common/ldr/ldrFile.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrFile.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -253,7 +253,7 @@ RTDECL(int) RTLdrOpen(const char *pszFilename, uint32_t fFlags, RTLDRARCH enmArc
{
LogFlow(("RTLdrOpen: pszFilename=%p:{%s} fFlags=%#x enmArch=%d phLdrMod=%p\n",
pszFilename, pszFilename, fFlags, enmArch, phLdrMod));
- AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
+ AssertMsgReturn(!(fFlags & ~RTLDR_O_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
AssertMsgReturn(enmArch > RTLDRARCH_INVALID && enmArch < RTLDRARCH_END, ("%d\n", enmArch), VERR_INVALID_PARAMETER);
/*
@@ -305,6 +305,7 @@ RTDECL(int) RTLdrOpenkLdr(const char *pszFilename, uint32_t fFlags, RTLDRARCH en
#ifdef LDR_WITH_KLDR
LogFlow(("RTLdrOpenkLdr: pszFilename=%p:{%s} fFlags=%#x enmArch=%d phLdrMod=%p\n",
pszFilename, pszFilename, fFlags, enmArch, phLdrMod));
+ AssertMsgReturn(!(fFlags & ~RTLDR_O_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
/*
* Resolve RTLDRARCH_HOST.
diff --git a/src/VBox/Runtime/common/ldr/ldrMemory.cpp b/src/VBox/Runtime/common/ldr/ldrMemory.cpp
new file mode 100644
index 00000000..7e82c90b
--- /dev/null
+++ b/src/VBox/Runtime/common/ldr/ldrMemory.cpp
@@ -0,0 +1,324 @@
+
+/* $Id: ldrMemory.cpp $ */
+/** @file
+ * IPRT - Binary Image Loader, The Memory/Debugger Oriented Parts.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_LDR
+#include <iprt/ldr.h>
+#include "internal/iprt.h"
+
+#include <iprt/alloc.h>
+#include <iprt/assert.h>
+#include <iprt/log.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/ldr.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Memory reader (for debuggers) instance.
+ */
+typedef struct RTLDRRDRMEM
+{
+ /** The core. */
+ RTLDRREADER Core;
+ /** The size of the image. */
+ size_t cbImage;
+ /** The current offset. */
+ size_t offCur;
+
+ /** User parameter for the reader and destructor functions.*/
+ void *pvUser;
+ /** Read function. */
+ PFNRTLDRRDRMEMREAD pfnRead;
+ /** Destructor callback. */
+ PFNRTLDRRDRMEMDTOR pfnDtor;
+
+ /** Mapping of the file. */
+ void *pvMapping;
+ /** Mapping usage counter. */
+ uint32_t cMappings;
+
+ /** The fake filename (variable size). */
+ char szName[1];
+} RTLDRRDRMEM;
+/** Memory based loader reader instance data. */
+typedef RTLDRRDRMEM *PRTLDRRDRMEM;
+
+
+/** @callback_method_impl{FNRTLDRRDRMEMDTOR,
+ * Default destructor - pvUser points to the image memory block.}
+ */
+static DECLCALLBACK(void) rtldrRdrMemDefaultDtor(void *pvUser)
+{
+ RTMemFree(pvUser);
+}
+
+
+/** @callback_method_impl{FNRTLDRRDRMEMREAD,
+ * Default memory reader - pvUser points to the image memory block.}
+ */
+static DECLCALLBACK(int) rtldrRdrMemDefaultReader(void *pvBuf, size_t cb, size_t off, void *pvUser)
+{
+ memcpy(pvBuf, (uint8_t *)pvUser + off, cb);
+ return VINF_SUCCESS;
+}
+
+
+/** @copydoc RTLDRREADER::pfnRead */
+static DECLCALLBACK(int) rtldrRdrMem_Read(PRTLDRREADER pReader, void *pvBuf, size_t cb, RTFOFF off)
+{
+ PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
+
+ AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
+ if ( cb > pThis->cbImage
+ || off > (RTFOFF)pThis->cbImage
+ || off + (RTFOFF)cb > (RTFOFF)pThis->cbImage)
+ {
+ pThis->offCur = pThis->cbImage;
+ return VERR_EOF;
+ }
+
+ int rc = pThis->pfnRead(pvBuf, cb, (size_t)off, pThis->pvUser);
+ if (RT_SUCCESS(rc))
+ pThis->offCur = (size_t)off + cb;
+ else
+ pThis->offCur = ~(size_t)0;
+ return rc;
+}
+
+
+/** @copydoc RTLDRREADER::pfnTell */
+static DECLCALLBACK(RTFOFF) rtldrRdrMem_Tell(PRTLDRREADER pReader)
+{
+ PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
+ return pThis->offCur;
+}
+
+
+/** @copydoc RTLDRREADER::pfnSize */
+static DECLCALLBACK(RTFOFF) rtldrRdrMem_Size(PRTLDRREADER pReader)
+{
+ PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
+ return pThis->cbImage;
+}
+
+
+/** @copydoc RTLDRREADER::pfnLogName */
+static DECLCALLBACK(const char *) rtldrRdrMem_LogName(PRTLDRREADER pReader)
+{
+ PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
+ return pThis->szName;
+}
+
+
+/** @copydoc RTLDRREADER::pfnMap */
+static DECLCALLBACK(int) rtldrRdrMem_Map(PRTLDRREADER pReader, const void **ppvBits)
+{
+ PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
+
+ /*
+ * Already mapped?
+ */
+ if (pThis->pvMapping)
+ {
+ pThis->cMappings++;
+ *ppvBits = pThis->pvMapping;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Allocate memory.
+ */
+ pThis->pvMapping = RTMemAlloc(pThis->cbImage);
+ if (!pThis->pvMapping)
+ return VERR_NO_MEMORY;
+ int rc = rtldrRdrMem_Read(pReader, pThis->pvMapping, pThis->cbImage, 0);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->cMappings = 1;
+ *ppvBits = pThis->pvMapping;
+ }
+ else
+ {
+ RTMemFree(pThis->pvMapping);
+ pThis->pvMapping = NULL;
+ }
+
+ return rc;
+}
+
+
+/** @copydoc RTLDRREADER::pfnUnmap */
+static DECLCALLBACK(int) rtldrRdrMem_Unmap(PRTLDRREADER pReader, const void *pvBits)
+{
+ PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
+ AssertReturn(pThis->cMappings > 0, VERR_INVALID_PARAMETER);
+
+ if (!--pThis->cMappings)
+ {
+ RTMemFree(pThis->pvMapping);
+ pThis->pvMapping = NULL;
+ }
+
+ NOREF(pvBits);
+ return VINF_SUCCESS;
+}
+
+
+/** @copydoc RTLDRREADER::pfnDestroy */
+static DECLCALLBACK(int) rtldrRdrMem_Destroy(PRTLDRREADER pReader)
+{
+ PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
+ pThis->pfnDtor(pThis->pvUser);
+ RTMemFree(pThis);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Opens a memory based loader reader.
+ *
+ * @returns iprt status code.
+ * @param ppReader Where to store the reader instance on success.
+ * @param pszName The name to give the image.
+ * @param cbImage The image size.
+ * @param pfnRead The reader function. If NULL, a default reader is
+ * used that assumes pvUser points to a memory buffer
+ * of at least @a cbImage size.
+ * @param pfnDtor The destructor. If NULL, a default destructore is
+ * used that will call RTMemFree on @a pvUser.
+ * @param pvUser User argument. If either @a pfnRead or @a pfnDtor
+ * is NULL, this must be a pointer to readable memory
+ * (see above).
+ */
+static int rtldrRdrMem_Create(PRTLDRREADER *ppReader, const char *pszName, size_t cbImage,
+ PFNRTLDRRDRMEMREAD pfnRead, PFNRTLDRRDRMEMDTOR pfnDtor, void *pvUser)
+{
+#if ARCH_BITS > 32 /* 'ing gcc. */
+ AssertReturn(cbImage < RTFOFF_MAX, VERR_INVALID_PARAMETER);
+#endif
+ AssertReturn((RTFOFF)cbImage > 0, VERR_INVALID_PARAMETER);
+
+ size_t cchName = strlen(pszName);
+ int rc = VERR_NO_MEMORY;
+ PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)RTMemAlloc(sizeof(*pThis) + cchName);
+ if (pThis)
+ {
+ memcpy(pThis->szName, pszName, cchName + 1);
+ pThis->cbImage = cbImage;
+ pThis->pvUser = pvUser;
+ pThis->offCur = 0;
+ pThis->pvUser = pvUser;
+ pThis->pfnRead = pfnRead ? pfnRead : rtldrRdrMemDefaultReader;
+ pThis->pfnDtor = pfnDtor ? pfnDtor : rtldrRdrMemDefaultDtor;
+ pThis->pvMapping = NULL;
+ pThis->cMappings = 0;
+ pThis->Core.pszName = "rdrmem";
+ pThis->Core.pfnRead = rtldrRdrMem_Read;
+ pThis->Core.pfnTell = rtldrRdrMem_Tell;
+ pThis->Core.pfnSize = rtldrRdrMem_Size;
+ pThis->Core.pfnLogName = rtldrRdrMem_LogName;
+ pThis->Core.pfnMap = rtldrRdrMem_Map;
+ pThis->Core.pfnUnmap = rtldrRdrMem_Unmap;
+ pThis->Core.pfnDestroy = rtldrRdrMem_Destroy;
+ *ppReader = &pThis->Core;
+ return VINF_SUCCESS;
+ }
+
+ *ppReader = NULL;
+ return rc;
+}
+
+
+RTDECL(int) RTLdrOpenInMemory(const char *pszName, uint32_t fFlags, RTLDRARCH enmArch, size_t cbImage,
+ PFNRTLDRRDRMEMREAD pfnRead, PFNRTLDRRDRMEMDTOR pfnDtor, void *pvUser,
+ PRTLDRMOD phLdrMod)
+{
+ LogFlow(("RTLdrOpenInMemory: pszName=%p:{%s} fFlags=%#x enmArch=%d cbImage=%#zx pfnRead=%p pfnDtor=%p pvUser=%p phLdrMod=%p\n",
+ pszName, pszName, fFlags, enmArch, cbImage, pfnRead, pfnDtor, pvUser, phLdrMod));
+
+ if (!pfnRead || !pfnDtor)
+ AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
+ if (!pfnDtor)
+ pfnDtor = rtldrRdrMemDefaultDtor;
+ else
+ AssertPtrReturn(pfnRead, VERR_INVALID_POINTER);
+
+ /* The rest of the validations will call the destructor. */
+ AssertMsgReturnStmt(!(fFlags & ~RTLDR_O_VALID_MASK), ("%#x\n", fFlags),
+ pfnDtor(pvUser), VERR_INVALID_PARAMETER);
+ AssertMsgReturnStmt(enmArch > RTLDRARCH_INVALID && enmArch < RTLDRARCH_END, ("%d\n", enmArch),
+ pfnDtor(pvUser), VERR_INVALID_PARAMETER);
+ if (!pfnRead)
+ pfnRead = rtldrRdrMemDefaultReader;
+ else
+ AssertReturnStmt(RT_VALID_PTR(pfnRead), pfnDtor(pvUser), VERR_INVALID_POINTER);
+ AssertReturnStmt(cbImage > 0, pfnDtor(pvUser), VERR_INVALID_PARAMETER);
+
+ /*
+ * Resolve RTLDRARCH_HOST.
+ */
+ if (enmArch == RTLDRARCH_HOST)
+#if defined(RT_ARCH_AMD64)
+ enmArch = RTLDRARCH_AMD64;
+#elif defined(RT_ARCH_X86)
+ enmArch = RTLDRARCH_X86_32;
+#else
+ enmArch = RTLDRARCH_WHATEVER;
+#endif
+
+ /*
+ * Create file reader & invoke worker which identifies and calls the image interpreter.
+ */
+ PRTLDRREADER pReader = NULL; /* gcc may be wrong */
+ int rc = rtldrRdrMem_Create(&pReader, pszName, cbImage, pfnRead, pfnDtor, pvUser);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtldrOpenWithReader(pReader, fFlags, enmArch, phLdrMod);
+ if (RT_SUCCESS(rc))
+ {
+ LogFlow(("RTLdrOpen: return %Rrc *phLdrMod\n", rc, *phLdrMod));
+ return rc;
+ }
+
+ pReader->pfnDestroy(pReader);
+ }
+ else
+ pfnDtor(pvUser),
+ *phLdrMod = NIL_RTLDRMOD;
+
+ LogFlow(("RTLdrOpen: return %Rrc\n", rc));
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLdrOpenInMemory);
+
diff --git a/src/VBox/Runtime/common/ldr/ldrNative.cpp b/src/VBox/Runtime/common/ldr/ldrNative.cpp
index ad94d1cf..38fe571f 100644
--- a/src/VBox/Runtime/common/ldr/ldrNative.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrNative.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -62,7 +62,7 @@ static DECLCALLBACK(int) rtldrNativeDone(PRTLDRMODINTERNAL pMod)
/**
* Operations for a native module.
*/
-static const RTLDROPS s_rtldrNativeOps =
+static const RTLDROPS g_rtldrNativeOps =
{
"native",
rtldrNativeClose,
@@ -80,6 +80,7 @@ static const RTLDROPS s_rtldrNativeOps =
NULL,
NULL,
NULL,
+ NULL,
42
};
@@ -127,10 +128,26 @@ RTDECL(int) RTLdrLoadEx(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fF
PRTLDRMODNATIVE pMod = (PRTLDRMODNATIVE)RTMemAlloc(sizeof(*pMod));
if (pMod)
{
- pMod->Core.u32Magic = RTLDRMOD_MAGIC;
- pMod->Core.eState = LDR_STATE_LOADED;
- pMod->Core.pOps = &s_rtldrNativeOps;
- pMod->hNative = ~(uintptr_t)0;
+ pMod->Core.u32Magic = RTLDRMOD_MAGIC;
+ pMod->Core.eState = LDR_STATE_LOADED;
+ pMod->Core.pOps = &g_rtldrNativeOps;
+ pMod->Core.pReader = NULL;
+ pMod->Core.enmFormat = RTLDRFMT_NATIVE;
+ pMod->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE; /* approx */
+#ifdef RT_BIG_ENDIAN
+ pMod->Core.enmEndian = RTLDRENDIAN_BIG;
+#else
+ pMod->Core.enmEndian = RTLDRENDIAN_LITTLE;
+#endif
+#ifdef RT_ARCH_AMD64
+ pMod->Core.enmArch = RTLDRARCH_AMD64;
+#elif defined(RT_ARCH_X86)
+ pMod->Core.enmArch = RTLDRARCH_X86_32;
+#else
+ pMod->Core.enmArch = RTLDRARCH_HOST;
+#endif
+ pMod->hNative = ~(uintptr_t)0;
+ pMod->fFlags = fFlags;
/*
* Attempt to open the module.
@@ -154,6 +171,54 @@ RTDECL(int) RTLdrLoadEx(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fF
RT_EXPORT_SYMBOL(RTLdrLoadEx);
+RTDECL(int) RTLdrLoadSystem(const char *pszFilename, bool fNoUnload, PRTLDRMOD phLdrMod)
+{
+ LogFlow(("RTLdrLoadSystem: pszFilename=%p:{%s} fNoUnload=%RTbool phLdrMod=%p\n",
+ pszFilename, pszFilename, fNoUnload, phLdrMod));
+
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
+ *phLdrMod = NIL_RTLDRMOD;
+ AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(!RTPathHavePath(pszFilename), ("%s\n", pszFilename), VERR_INVALID_PARAMETER);
+
+ /*
+ * Check the filename.
+ */
+ size_t cchFilename = strlen(pszFilename);
+ AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
+
+ const char *pszExt = "";
+ if (!RTPathHaveExt(pszFilename))
+ pszExt = RTLdrGetSuff();
+
+ /*
+ * Let the platform specific code do the rest.
+ */
+ int rc = rtldrNativeLoadSystem(pszFilename, pszExt, fNoUnload ? RTLDRLOAD_FLAGS_NO_UNLOAD : 0, phLdrMod);
+ LogFlow(("RTLdrLoadSystem: returns %Rrc\n", rc));
+ return rc;
+}
+
+
+RTDECL(void *) RTLdrGetSystemSymbol(const char *pszFilename, const char *pszSymbol)
+{
+ void *pvRet = NULL;
+ RTLDRMOD hLdrMod;
+ int rc = RTLdrLoadSystem(pszFilename, true /*fNoUnload*/, &hLdrMod);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(hLdrMod, pszSymbol, &pvRet);
+ if (RT_FAILURE(rc))
+ pvRet = NULL; /* paranoia */
+ RTLdrClose(hLdrMod);
+ }
+ return pvRet;
+}
+
+
/**
* Loads a dynamic load library (/shared object) image file residing in the
* RTPathAppPrivateArch() directory.
@@ -241,3 +306,14 @@ RTDECL(const char *) RTLdrGetSuff(void)
}
RT_EXPORT_SYMBOL(RTLdrGetSuff);
+
+RTDECL(uintptr_t) RTLdrGetNativeHandle(RTLDRMOD hLdrMod)
+{
+ PRTLDRMODNATIVE pThis = (PRTLDRMODNATIVE)hLdrMod;
+ AssertPtrReturn(pThis, ~(uintptr_t)0);
+ AssertReturn(pThis->Core.u32Magic == RTLDRMOD_MAGIC, ~(uintptr_t)0);
+ AssertReturn(pThis->Core.pOps == &g_rtldrNativeOps, ~(uintptr_t)0);
+ return pThis->hNative;
+}
+RT_EXPORT_SYMBOL(RTLdrGetNativeHandle);
+
diff --git a/src/VBox/Runtime/common/ldr/ldrPE.cpp b/src/VBox/Runtime/common/ldr/ldrPE.cpp
index 259f8e93..283b861c 100644
--- a/src/VBox/Runtime/common/ldr/ldrPE.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrPE.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -35,8 +35,10 @@
#include <iprt/alloc.h>
#include <iprt/assert.h>
#include <iprt/log.h>
+#include <iprt/path.h>
#include <iprt/string.h>
#include <iprt/err.h>
+#include <iprt/formats/codeview.h>
#include "internal/ldrPE.h"
#include "internal/ldr.h"
@@ -62,13 +64,13 @@ typedef struct RTLDRMODPE
{
/** Core module structure. */
RTLDRMODINTERNAL Core;
- /** Pointer to the reader instance. */
- PRTLDRREADER pReader;
/** Pointer to internal copy of image bits.
* @todo the reader should take care of this. */
void *pvBits;
/** The offset of the NT headers. */
RTFOFF offNtHdrs;
+ /** The offset of the first byte after the section table. */
+ RTFOFF offEndOfHdrs;
/** The machine type (IMAGE_FILE_HEADER::Machine). */
uint16_t u16Machine;
@@ -87,12 +89,16 @@ typedef struct RTLDRMODPE
uint32_t cbImage;
/** Size of the header (IMAGE_OPTIONAL_HEADER32::SizeOfHeaders). */
uint32_t cbHeaders;
+ /** The image timestamp. */
+ uint32_t uTimestamp;
/** The import data directory entry. */
IMAGE_DATA_DIRECTORY ImportDir;
/** The base relocation data directory entry. */
IMAGE_DATA_DIRECTORY RelocDir;
/** The export data directory entry. */
IMAGE_DATA_DIRECTORY ExportDir;
+ /** The debug directory entry. */
+ IMAGE_DATA_DIRECTORY DebugDir;
} RTLDRMODPE, *PRTLDRMODPE;
/**
@@ -130,7 +136,227 @@ typedef struct RTLDROPSPE
*******************************************************************************/
static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr);
static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg);
-static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress);
+static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress);
+
+
+
+/**
+ * Reads a section of a PE image given by RVA + size, using mapped bits if
+ * available or allocating heap memory and reading from the file.
+ *
+ * @returns IPRT status code.
+ * @param pThis Pointer to the PE loader module structure.
+ * @param pvBits Read only bits if available. NULL if not.
+ * @param uRva The RVA to read at.
+ * @param cbMem The number of bytes to read.
+ * @param ppvMem Where to return the memory on success (heap or
+ * inside pvBits).
+ */
+static int rtldrPEReadPartByRva(PRTLDRMODPE pThis, const void *pvBits, uint32_t uRva, uint32_t cbMem, void const **ppvMem)
+{
+ *ppvMem = NULL;
+ if (!cbMem)
+ return VINF_SUCCESS;
+
+ /*
+ * Use bits if we've got some.
+ */
+ if (pvBits)
+ {
+ *ppvMem = (uint8_t const *)pvBits + uRva;
+ return VINF_SUCCESS;
+ }
+ if (pThis->pvBits)
+ {
+ *ppvMem = (uint8_t const *)pThis->pvBits + uRva;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Allocate a buffer and read the bits from the file (or whatever).
+ */
+ if (!pThis->Core.pReader)
+ return VERR_ACCESS_DENIED;
+
+ uint8_t *pbMem = (uint8_t *)RTMemAllocZ(cbMem);
+ if (!pbMem)
+ return VERR_NO_MEMORY;
+ *ppvMem = pbMem;
+
+ /* Do the reading on a per section base. */
+ RTFOFF const cbFile = pThis->Core.pReader->pfnSize(pThis->Core.pReader);
+ for (;;)
+ {
+ /* Translate the RVA into a file offset. */
+ uint32_t offFile = uRva;
+ uint32_t cbToRead = cbMem;
+ uint32_t cbToAdv = cbMem;
+
+ if (uRva < pThis->paSections[0].VirtualAddress)
+ {
+ /* Special header section. */
+ cbToRead = pThis->paSections[0].VirtualAddress - uRva;
+ if (cbToRead > cbMem)
+ cbToRead = cbMem;
+ cbToAdv = cbToRead;
+
+ /* The following capping is an approximation. */
+ uint32_t offFirstRawData = RT_ALIGN(pThis->cbHeaders, _4K);
+ if ( pThis->paSections[0].PointerToRawData > 0
+ && pThis->paSections[0].SizeOfRawData > 0)
+ offFirstRawData = pThis->paSections[0].PointerToRawData;
+ if (offFile > offFirstRawData)
+ cbToRead = 0;
+ else if (offFile + cbToRead > offFirstRawData)
+ cbToRead = offFile + cbToRead - offFirstRawData;
+ }
+ else
+ {
+ /* Find the matching section and its mapping size. */
+ uint32_t j = 0;
+ uint32_t cbMapping = 0;
+ while (j < pThis->cSections)
+ {
+ cbMapping = (j + 1 < pThis->cSections ? pThis->paSections[j + 1].VirtualAddress : pThis->cbImage)
+ - pThis->paSections[j].VirtualAddress;
+ if (uRva - pThis->paSections[j].VirtualAddress < cbMapping)
+ break;
+ j++;
+ }
+ if (j >= cbMapping)
+ break; /* This shouldn't happen, just return zeros if it does. */
+
+ /* Adjust the sizes and calc the file offset. */
+ if (cbToAdv > cbMapping)
+ cbToAdv = cbToRead = cbMapping;
+ if ( pThis->paSections[j].PointerToRawData > 0
+ && pThis->paSections[j].SizeOfRawData > 0)
+ {
+ offFile = uRva - pThis->paSections[j].VirtualAddress;
+ if (offFile + cbToRead > pThis->paSections[j].SizeOfRawData)
+ cbToRead = pThis->paSections[j].SizeOfRawData - offFile;
+ offFile += pThis->paSections[j].PointerToRawData;
+ }
+ else
+ {
+ offFile = UINT32_MAX;
+ cbToRead = 0;
+ }
+ }
+
+ /* Perform the read after adjusting a little (paranoia). */
+ if (offFile > cbFile)
+ cbToRead = 0;
+ if (cbToRead)
+ {
+ if ((RTFOFF)offFile + cbToRead > cbFile)
+ cbToRead = cbFile - (RTFOFF)offFile;
+ int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbToRead, offFile);
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree((void *)*ppvMem);
+ *ppvMem = NULL;
+ return rc;
+ }
+ }
+
+ /* Advance */
+ if (cbMem == cbToRead)
+ break;
+ cbMem -= cbToRead;
+ pbMem += cbToRead;
+ uRva += cbToRead;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Reads a part of a PE file from the file and into a heap block.
+ *
+ * @returns IRPT status code.
+ * @param pThis Pointer to the PE loader module structure..
+ * @param offFile The file offset.
+ * @param cbMem The number of bytes to read.
+ * @param ppvMem Where to return the heap block with the bytes on
+ * success.
+ */
+static int rtldrPEReadPartFromFile(PRTLDRMODPE pThis, uint32_t offFile, uint32_t cbMem, void const **ppvMem)
+{
+ *ppvMem = NULL;
+ if (!cbMem)
+ return VINF_SUCCESS;
+
+ /*
+ * Allocate a buffer and read the bits from the file (or whatever).
+ */
+ if (!pThis->Core.pReader)
+ return VERR_ACCESS_DENIED;
+
+ uint8_t *pbMem = (uint8_t *)RTMemAlloc(cbMem);
+ if (!pbMem)
+ return VERR_NO_MEMORY;
+
+ int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbMem, offFile);
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree((void *)*ppvMem);
+ return rc;
+ }
+
+ *ppvMem = pbMem;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Reads a part of a PE image into memory one way or another.
+ *
+ * Either the RVA or the offFile must be valid. We'll prefer the RVA if
+ * possible.
+ *
+ * @returns IPRT status code.
+ * @param pThis Pointer to the PE loader module structure.
+ * @param pvBits Read only bits if available. NULL if not.
+ * @param uRva The RVA to read at.
+ * @param offFile The file offset.
+ * @param cbMem The number of bytes to read.
+ * @param ppvMem Where to return the memory on success (heap or
+ * inside pvBits).
+ */
+static int rtldrPEReadPart(PRTLDRMODPE pThis, const void *pvBits, RTFOFF offFile, RTLDRADDR uRva,
+ uint32_t cbMem, void const **ppvMem)
+{
+ if (uRva == NIL_RTLDRADDR || uRva > pThis->cbImage)
+ {
+ if (offFile < 0)
+ return VERR_INVALID_PARAMETER;
+ return rtldrPEReadPartFromFile(pThis, offFile, cbMem, ppvMem);
+ }
+ return rtldrPEReadPartByRva(pThis, pvBits, uRva, cbMem, ppvMem);
+}
+
+
+/**
+ * Frees up memory returned by rtldrPEReadPart*.
+ *
+ * @param pThis Pointer to the PE loader module structure..
+ * @param pvBits Read only bits if available. NULL if not..
+ * @param pvMem The memory we were given by the reader method.
+ */
+static void rtldrPEFreePart(PRTLDRMODPE pThis, const void *pvBits, void const *pvMem)
+{
+ if (!pvMem)
+ return;
+
+ if (pvBits && (uintptr_t)pvBits - (uintptr_t)pvMem < pThis->cbImage)
+ return;
+ if (pThis->pvBits && (uintptr_t)pThis->pvBits - (uintptr_t)pvMem < pThis->cbImage)
+ return;
+
+ RTMemFree((void *)pvMem);
+}
/** @copydoc RTLDROPS::pfnGetImageSize */
@@ -153,7 +379,7 @@ static int rtldrPEGetBitsNoImportsNorFixups(PRTLDRMODPE pModPe, void *pvBits)
/*
* Both these checks are related to pfnDone().
*/
- PRTLDRREADER pReader = pModPe->pReader;
+ PRTLDRREADER pReader = pModPe->Core.pReader;
if (!pReader)
{
AssertMsgFailed(("You've called done!\n"));
@@ -666,6 +892,140 @@ static DECLCALLBACK(int) rtldrPEGetSymbolEx(PRTLDRMODINTERNAL pMod, const void *
}
+/**
+ * Slow version of rtldrPEEnumSymbols that'll work without all of the image
+ * being accessible.
+ *
+ * This is mainly for use in debuggers and similar.
+ */
+static int rtldrPEEnumSymbolsSlow(PRTLDRMODPE pThis, unsigned fFlags, RTUINTPTR BaseAddress,
+ PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
+{
+ /*
+ * We enumerates by ordinal, which means using a slow linear search for
+ * getting any name
+ */
+ PCIMAGE_EXPORT_DIRECTORY pExpDir = NULL;
+ int rc = rtldrPEReadPartByRva(pThis, NULL, pThis->ExportDir.VirtualAddress, pThis->ExportDir.Size,
+ (void const **)&pExpDir);
+ if (RT_FAILURE(rc))
+ return rc;
+ uint32_t const cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
+
+ uint32_t const *paAddress = NULL;
+ rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfFunctions, cOrdinals * sizeof(uint32_t),
+ (void const **)&paAddress);
+ uint32_t const *paRVANames = NULL;
+ if (RT_SUCCESS(rc) && pExpDir->NumberOfNames)
+ rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfNames, pExpDir->NumberOfNames * sizeof(uint32_t),
+ (void const **)&paRVANames);
+ uint16_t const *paOrdinals = NULL;
+ if (RT_SUCCESS(rc) && pExpDir->NumberOfNames)
+ rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfNameOrdinals, pExpDir->NumberOfNames * sizeof(uint16_t),
+ (void const **)&paOrdinals);
+ if (RT_SUCCESS(rc))
+ {
+ uintptr_t uNamePrev = 0;
+ for (uint32_t uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
+ {
+ if (paAddress[uOrdinal] /* needed? */)
+ {
+ /*
+ * Look for name.
+ */
+ uint32_t uRvaName = UINT32_MAX;
+ /* Search from previous + 1 to the end. */
+ unsigned uName = uNamePrev + 1;
+ while (uName < pExpDir->NumberOfNames)
+ {
+ if (paOrdinals[uName] == uOrdinal)
+ {
+ uRvaName = paRVANames[uName];
+ uNamePrev = uName;
+ break;
+ }
+ uName++;
+ }
+ if (uRvaName == UINT32_MAX)
+ {
+ /* Search from start to the previous. */
+ uName = 0;
+ for (uName = 0 ; uName <= uNamePrev; uName++)
+ {
+ if (paOrdinals[uName] == uOrdinal)
+ {
+ uRvaName = paRVANames[uName];
+ uNamePrev = uName;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Get address.
+ */
+ uintptr_t uRVAExport = paAddress[uOrdinal];
+ RTUINTPTR Value;
+ if ( uRVAExport - (uintptr_t)pThis->ExportDir.VirtualAddress
+ < pThis->ExportDir.Size)
+ {
+ if (!(fFlags & RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD))
+ {
+ /* Resolve forwarder. */
+ AssertMsgFailed(("Forwarders are not supported!\n"));
+ }
+ continue;
+ }
+
+ /* Get plain export address */
+ Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
+
+ /* Read in the name if found one. */
+ char szAltName[32];
+ const char *pszName = NULL;
+ if (uRvaName != UINT32_MAX)
+ {
+ uint32_t cbName = 0x1000 - (uRvaName & 0xfff);
+ if (cbName < 10 || cbName > 512)
+ cbName = 128;
+ rc = rtldrPEReadPartByRva(pThis, NULL, uRvaName, cbName, (void const **)&pszName);
+ while (RT_SUCCESS(rc) && RTStrNLen(pszName, cbName) == cbName)
+ {
+ rtldrPEFreePart(pThis, NULL, pszName);
+ pszName = NULL;
+ if (cbName >= _4K)
+ break;
+ cbName += 128;
+ rc = rtldrPEReadPartByRva(pThis, NULL, uRvaName, cbName, (void const **)&pszName);
+ }
+ }
+ if (!pszName)
+ {
+ RTStrPrintf(szAltName, sizeof(szAltName), "Ordinal%#x", uOrdinal);
+ pszName = szAltName;
+ }
+
+ /*
+ * Call back.
+ */
+ rc = pfnCallback(&pThis->Core, pszName, uOrdinal + pExpDir->Base, Value, pvUser);
+ if (pszName != szAltName && pszName)
+ rtldrPEFreePart(pThis, NULL, pszName);
+ if (rc)
+ break;
+ }
+ }
+ }
+
+ rtldrPEFreePart(pThis, NULL, paOrdinals);
+ rtldrPEFreePart(pThis, NULL, paRVANames);
+ rtldrPEFreePart(pThis, NULL, paAddress);
+ rtldrPEFreePart(pThis, NULL, pExpDir);
+ return rc;
+
+}
+
+
/** @copydoc RTLDROPS::pfnEnumSymbols */
static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFlags, const void *pvBits, RTUINTPTR BaseAddress,
PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
@@ -689,7 +1049,7 @@ static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFl
{
int rc = rtldrPEReadBits(pModPe);
if (RT_FAILURE(rc))
- return rc;
+ return rtldrPEEnumSymbolsSlow(pModPe, fFlags, BaseAddress, pfnCallback, pvUser);
}
pvBits = pModPe->pvBits;
}
@@ -744,16 +1104,19 @@ static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFl
*/
uintptr_t uRVAExport = paAddress[uOrdinal];
RTUINTPTR Value;
- if ( uRVAExport - (uintptr_t)pModPe->ExportDir.VirtualAddress
- < pModPe->ExportDir.Size)
+ if ( uRVAExport - (uintptr_t)pModPe->ExportDir.VirtualAddress
+ < pModPe->ExportDir.Size)
{
- /* Resolve forwarder. */
- AssertMsgFailed(("Forwarders are not supported!\n"));
+ if (!(fFlags & RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD))
+ {
+ /* Resolve forwarder. */
+ AssertMsgFailed(("Forwarders are not supported!\n"));
+ }
continue;
}
- else
- /* Get plain export address */
- Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
+
+ /* Get plain export address */
+ Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
/*
* Call back.
@@ -772,16 +1135,271 @@ static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFl
static DECLCALLBACK(int) rtldrPE_EnumDbgInfo(PRTLDRMODINTERNAL pMod, const void *pvBits,
PFNRTLDRENUMDBG pfnCallback, void *pvUser)
{
- NOREF(pMod); NOREF(pvBits); NOREF(pfnCallback); NOREF(pvUser);
- return VINF_NOT_SUPPORTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+ int rc;
+
+ /*
+ * Debug info directory empty?
+ */
+ if ( !pModPe->DebugDir.VirtualAddress
+ || !pModPe->DebugDir.Size)
+ return VINF_SUCCESS;
+
+ /*
+ * Get the debug directory.
+ */
+ if (!pvBits)
+ pvBits = pModPe->pvBits;
+
+ PCIMAGE_DEBUG_DIRECTORY paDbgDir;
+ int rcRet = rtldrPEReadPartByRva(pModPe, pvBits, pModPe->DebugDir.VirtualAddress, pModPe->DebugDir.Size,
+ (void const **)&paDbgDir);
+ if (RT_FAILURE(rcRet))
+ return rcRet;
+
+ /*
+ * Enumerate the debug directory.
+ */
+ uint32_t const cEntries = pModPe->DebugDir.Size / sizeof(paDbgDir[0]);
+ for (uint32_t i = 0; i < cEntries; i++)
+ {
+ if (paDbgDir[i].PointerToRawData < pModPe->offEndOfHdrs)
+ continue;
+ if (paDbgDir[i].SizeOfData < 4)
+ continue;
+
+ void const *pvPart = NULL;
+ char szPath[RTPATH_MAX];
+ RTLDRDBGINFO DbgInfo;
+ RT_ZERO(DbgInfo.u);
+ DbgInfo.iDbgInfo = i;
+ DbgInfo.offFile = paDbgDir[i].PointerToRawData;
+ DbgInfo.LinkAddress = paDbgDir[i].AddressOfRawData < pModPe->cbImage
+ && paDbgDir[i].AddressOfRawData >= pModPe->offEndOfHdrs
+ ? paDbgDir[i].AddressOfRawData : NIL_RTLDRADDR;
+ DbgInfo.cb = paDbgDir[i].SizeOfData;
+ DbgInfo.pszExtFile = NULL;
+
+ rc = VINF_SUCCESS;
+ switch (paDbgDir[i].Type)
+ {
+ case IMAGE_DEBUG_TYPE_CODEVIEW:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW;
+ DbgInfo.u.Cv.cbImage = pModPe->cbImage;
+ DbgInfo.u.Cv.uMajorVer = paDbgDir[i].MajorVersion;
+ DbgInfo.u.Cv.uMinorVer = paDbgDir[i].MinorVersion;
+ DbgInfo.u.Cv.uTimestamp = paDbgDir[i].TimeDateStamp;
+ if ( paDbgDir[i].SizeOfData < sizeof(szPath)
+ && paDbgDir[i].SizeOfData > 16
+ && ( DbgInfo.LinkAddress != NIL_RTLDRADDR
+ || DbgInfo.offFile > 0)
+ )
+ {
+ rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
+ if (RT_SUCCESS(rc))
+ {
+ PCCVPDB20INFO pCv20 = (PCCVPDB20INFO)pvPart;
+ if ( pCv20->u32Magic == CVPDB20INFO_MAGIC
+ && pCv20->offDbgInfo == 0
+ && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
+ {
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB20;
+ DbgInfo.u.Pdb20.cbImage = pModPe->cbImage;
+ DbgInfo.u.Pdb20.uTimestamp = pCv20->uTimestamp;
+ DbgInfo.u.Pdb20.uAge = pCv20->uAge;
+ DbgInfo.pszExtFile = (const char *)&pCv20->szPdbFilename[0];
+ }
+ else if ( pCv20->u32Magic == CVPDB70INFO_MAGIC
+ && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
+ {
+ PCCVPDB70INFO pCv70 = (PCCVPDB70INFO)pCv20;
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB70;
+ DbgInfo.u.Pdb70.cbImage = pModPe->cbImage;
+ DbgInfo.u.Pdb70.Uuid = pCv70->PdbUuid;
+ DbgInfo.u.Pdb70.uAge = pCv70->uAge;
+ DbgInfo.pszExtFile = (const char *)&pCv70->szPdbFilename[0];
+ }
+ }
+ else
+ rcRet = rc;
+ }
+ break;
+
+ case IMAGE_DEBUG_TYPE_MISC:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
+ if ( paDbgDir[i].SizeOfData < sizeof(szPath)
+ && paDbgDir[i].SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data))
+ {
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_DBG;
+ DbgInfo.u.Dbg.cbImage = pModPe->cbImage;
+ if (DbgInfo.LinkAddress != NIL_RTLDRADDR)
+ DbgInfo.u.Dbg.uTimestamp = paDbgDir[i].TimeDateStamp;
+ else
+ DbgInfo.u.Dbg.uTimestamp = pModPe->uTimestamp; /* NT4 SP1 ntfs.sys hack. Generic? */
+
+ rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
+ if (RT_SUCCESS(rc))
+ {
+ PCIMAGE_DEBUG_MISC pMisc = (PCIMAGE_DEBUG_MISC)pvPart;
+ if ( pMisc->DataType == IMAGE_DEBUG_MISC_EXENAME
+ && pMisc->Length == paDbgDir[i].SizeOfData)
+ {
+ if (!pMisc->Unicode)
+ DbgInfo.pszExtFile = (const char *)&pMisc->Data[0];
+ else
+ {
+ char *pszPath = szPath;
+ rc = RTUtf16ToUtf8Ex((PCRTUTF16)&pMisc->Data[0],
+ (pMisc->Length - RT_OFFSETOF(IMAGE_DEBUG_MISC, Data)) / sizeof(RTUTF16),
+ &pszPath, sizeof(szPath), NULL);
+ if (RT_SUCCESS(rc))
+ DbgInfo.pszExtFile = szPath;
+ else
+ rcRet = rc; /* continue without a filename. */
+ }
+ }
+ }
+ else
+ rcRet = rc; /* continue without a filename. */
+ }
+ break;
+
+ case IMAGE_DEBUG_TYPE_COFF:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_COFF;
+ DbgInfo.u.Coff.cbImage = pModPe->cbImage;
+ DbgInfo.u.Coff.uMajorVer = paDbgDir[i].MajorVersion;
+ DbgInfo.u.Coff.uMinorVer = paDbgDir[i].MinorVersion;
+ DbgInfo.u.Coff.uTimestamp = paDbgDir[i].TimeDateStamp;
+ break;
+
+ default:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
+ break;
+ }
+
+ /* Fix (hack) the file name encoding. We don't have Windows-1252 handy,
+ so we'll be using Latin-1 as a reasonable approximation.
+ (I don't think we know exactly which encoding this is anyway, as
+ it's probably the current ANSI/Windows code page for the process
+ generating the image anyways.) */
+ if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != szPath)
+ {
+ char *pszPath = szPath;
+ rc = RTLatin1ToUtf8Ex(DbgInfo.pszExtFile,
+ paDbgDir[i].SizeOfData - ((uintptr_t)DbgInfo.pszExtFile - (uintptr_t)pvBits),
+ &pszPath, sizeof(szPath), NULL);
+ if (RT_FAILURE(rc))
+ {
+ rcRet = rc;
+ DbgInfo.pszExtFile = NULL;
+ }
+ }
+ if (DbgInfo.pszExtFile)
+ RTPathChangeToUnixSlashes(szPath, true /*fForce*/);
+
+ rc = pfnCallback(pMod, &DbgInfo, pvUser);
+ rtldrPEFreePart(pModPe, pvBits, pvPart);
+ if (rc != VINF_SUCCESS)
+ {
+ rcRet = rc;
+ break;
+ }
+ }
+
+ rtldrPEFreePart(pModPe, pvBits, paDbgDir);
+ return rcRet;
}
/** @copydoc RTLDROPS::pfnEnumSegments. */
static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
{
- NOREF(pMod); NOREF(pfnCallback); NOREF(pvUser);
- return VINF_NOT_SUPPORTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+ RTLDRSEG SegInfo;
+
+ /*
+ * The first section is a fake one covering the headers.
+ */
+ SegInfo.pszName = "NtHdrs";
+ SegInfo.cchName = 6;
+ SegInfo.SelFlat = 0;
+ SegInfo.Sel16bit = 0;
+ SegInfo.fFlags = 0;
+ SegInfo.fProt = RTMEM_PROT_READ;
+ SegInfo.Alignment = 1;
+ SegInfo.LinkAddress = pModPe->uImageBase;
+ SegInfo.RVA = 0;
+ SegInfo.offFile = 0;
+ SegInfo.cb = pModPe->cbHeaders;
+ SegInfo.cbFile = pModPe->cbHeaders;
+ SegInfo.cbMapped = pModPe->cbHeaders;
+ if ((pModPe->paSections[0].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+ SegInfo.cbMapped = pModPe->paSections[0].VirtualAddress;
+ int rc = pfnCallback(pMod, &SegInfo, pvUser);
+
+ /*
+ * Then all the normal sections.
+ */
+ PCIMAGE_SECTION_HEADER pSh = pModPe->paSections;
+ for (uint32_t i = 0; i < pModPe->cSections && rc == VINF_SUCCESS; i++, pSh++)
+ {
+ char szName[32];
+ SegInfo.pszName = (const char *)&pSh->Name[0];
+ SegInfo.cchName = (uint32_t)RTStrNLen(SegInfo.pszName, sizeof(pSh->Name));
+ if (SegInfo.cchName >= sizeof(pSh->Name))
+ {
+ memcpy(szName, &pSh->Name[0], sizeof(pSh->Name));
+ szName[sizeof(sizeof(pSh->Name))] = '\0';
+ SegInfo.pszName = szName;
+ }
+ else if (SegInfo.cchName == 0)
+ {
+ SegInfo.pszName = szName;
+ SegInfo.cchName = (uint32_t)RTStrPrintf(szName, sizeof(szName), "UnamedSect%02u", i);
+ }
+ SegInfo.SelFlat = 0;
+ SegInfo.Sel16bit = 0;
+ SegInfo.fFlags = 0;
+ SegInfo.fProt = RTMEM_PROT_NONE;
+ if (pSh->Characteristics & IMAGE_SCN_MEM_READ)
+ SegInfo.fProt |= RTMEM_PROT_READ;
+ if (pSh->Characteristics & IMAGE_SCN_MEM_WRITE)
+ SegInfo.fProt |= RTMEM_PROT_WRITE;
+ if (pSh->Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ SegInfo.fProt |= RTMEM_PROT_EXEC;
+ SegInfo.Alignment = (pSh->Characteristics & IMAGE_SCN_ALIGN_MASK) >> IMAGE_SCN_ALIGN_SHIFT;
+ if (SegInfo.Alignment > 0)
+ SegInfo.Alignment = RT_BIT_64(SegInfo.Alignment - 1);
+ if (pSh->Characteristics & IMAGE_SCN_TYPE_NOLOAD)
+ {
+ SegInfo.LinkAddress = NIL_RTLDRADDR;
+ SegInfo.RVA = NIL_RTLDRADDR;
+ SegInfo.cbMapped = pSh->Misc.VirtualSize;
+ }
+ else
+ {
+ SegInfo.LinkAddress = pSh->VirtualAddress + pModPe->uImageBase ;
+ SegInfo.RVA = pSh->VirtualAddress;
+ SegInfo.cbMapped = RT_ALIGN(SegInfo.cb, SegInfo.Alignment);
+ if (i + 1 < pModPe->cSections && !(pSh[1].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+ SegInfo.cbMapped = pSh[1].VirtualAddress - pSh->VirtualAddress;
+ }
+ SegInfo.cb = pSh->Misc.VirtualSize;
+ if (pSh->PointerToRawData == 0 || pSh->SizeOfRawData == 0)
+ {
+ SegInfo.offFile = -1;
+ SegInfo.cbFile = 0;
+ }
+ else
+ {
+ SegInfo.offFile = pSh->PointerToRawData;
+ SegInfo.cbFile = pSh->SizeOfRawData;
+ }
+
+ rc = pfnCallback(pMod, &SegInfo, pvUser);
+ }
+
+ return rc;
}
@@ -789,16 +1407,53 @@ static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDREN
static DECLCALLBACK(int) rtldrPE_LinkAddressToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress,
uint32_t *piSeg, PRTLDRADDR poffSeg)
{
- NOREF(pMod); NOREF(LinkAddress); NOREF(piSeg); NOREF(poffSeg);
- return VERR_NOT_IMPLEMENTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+
+ LinkAddress -= pModPe->uImageBase;
+
+ /* Special header segment. */
+ if (LinkAddress < pModPe->paSections[0].VirtualAddress)
+ {
+ *piSeg = 0;
+ *poffSeg = LinkAddress;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Search the normal sections. (Could do this in binary fashion, they're
+ * sorted, but too much bother right now.)
+ */
+ if (LinkAddress > pModPe->cbImage)
+ return VERR_LDR_INVALID_LINK_ADDRESS;
+ uint32_t i = pModPe->cSections;
+ PCIMAGE_SECTION_HEADER paShs = pModPe->paSections;
+ while (i-- > 0)
+ if (!(paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+ {
+ uint32_t uAddr = paShs[i].VirtualAddress;
+ if (LinkAddress >= uAddr)
+ {
+ *poffSeg = LinkAddress - uAddr;
+ *piSeg = i + 1;
+ return VINF_SUCCESS;
+ }
+ }
+
+ return VERR_LDR_INVALID_LINK_ADDRESS;
}
/** @copydoc RTLDROPS::pfnLinkAddressToRva. */
static DECLCALLBACK(int) rtldrPE_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
{
- NOREF(pMod); NOREF(LinkAddress); NOREF(pRva);
- return VERR_NOT_IMPLEMENTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+
+ LinkAddress -= pModPe->uImageBase;
+ if (LinkAddress > pModPe->cbImage)
+ return VERR_LDR_INVALID_LINK_ADDRESS;
+ *pRva = LinkAddress;
+
+ return VINF_SUCCESS;
}
@@ -806,8 +1461,19 @@ static DECLCALLBACK(int) rtldrPE_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRA
static DECLCALLBACK(int) rtldrPE_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg,
PRTLDRADDR pRva)
{
- NOREF(pMod); NOREF(iSeg); NOREF(offSeg); NOREF(pRva);
- return VERR_NOT_IMPLEMENTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+
+ if (iSeg > pModPe->cSections)
+ return VERR_LDR_INVALID_SEG_OFFSET;
+
+ /** @todo should validate offSeg here... too lazy right now. */
+ if (iSeg == 0)
+ *pRva = offSeg;
+ else if (pModPe->paSections[iSeg].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
+ return VERR_LDR_INVALID_SEG_OFFSET;
+ else
+ *pRva = offSeg + pModPe->paSections[iSeg].VirtualAddress;
+ return VINF_SUCCESS;
}
@@ -815,8 +1481,11 @@ static DECLCALLBACK(int) rtldrPE_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t
static DECLCALLBACK(int) rtldrPE_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva,
uint32_t *piSeg, PRTLDRADDR poffSeg)
{
- NOREF(pMod); NOREF(Rva); NOREF(piSeg); NOREF(poffSeg);
- return VERR_NOT_IMPLEMENTED;
+ PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
+ int rc = rtldrPE_LinkAddressToSegOffset(pMod, Rva + pModPe->uImageBase, piSeg, poffSeg);
+ if (RT_FAILURE(rc))
+ rc = VERR_LDR_INVALID_RVA;
+ return rc;
}
@@ -829,12 +1498,6 @@ static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod)
RTMemFree(pModPe->pvBits);
pModPe->pvBits = NULL;
}
- if (pModPe->pReader)
- {
- int rc = pModPe->pReader->pfnDestroy(pModPe->pReader);
- AssertRC(rc);
- pModPe->pReader = NULL;
- }
return VINF_SUCCESS;
}
@@ -852,12 +1515,6 @@ static DECLCALLBACK(int) rtldrPEClose(PRTLDRMODINTERNAL pMod)
RTMemFree(pModPe->pvBits);
pModPe->pvBits = NULL;
}
- if (pModPe->pReader)
- {
- int rc = pModPe->pReader->pfnDestroy(pModPe->pReader);
- AssertRC(rc);
- pModPe->pReader = NULL;
- }
return VINF_SUCCESS;
}
@@ -884,6 +1541,7 @@ static const RTLDROPSPE s_rtldrPE32Ops =
rtldrPE_LinkAddressToRva,
rtldrPE_SegOffsetToRva,
rtldrPE_RvaToSegOffset,
+ NULL,
42
},
rtldrPEResolveImports32,
@@ -913,6 +1571,7 @@ static const RTLDROPSPE s_rtldrPE64Ops =
rtldrPE_LinkAddressToRva,
rtldrPE_SegOffsetToRva,
rtldrPE_RvaToSegOffset,
+ NULL,
42
},
rtldrPEResolveImports64,
@@ -1004,10 +1663,11 @@ static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64
*
* @returns iprt status code.
* @param pFileHdr Pointer to the file header that needs validating.
+ * @param fFlags Valid RTLDR_O_XXX combination.
* @param pszLogName The log name to prefix the errors with.
* @param penmArch Where to store the CPU architecture.
*/
-int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, const char *pszLogName, PRTLDRARCH penmArch)
+static int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, uint32_t fFlags, const char *pszLogName, PRTLDRARCH penmArch)
{
size_t cbOptionalHeader;
switch (pFileHdr->Machine)
@@ -1034,7 +1694,8 @@ int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, const char *pszLogNam
return VERR_BAD_EXE_FORMAT;
}
/* This restriction needs to be implemented elsewhere. */
- if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+ if ( (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+ && !(fFlags & RTLDR_O_FOR_DEBUG))
{
Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
return VERR_BAD_EXE_FORMAT;
@@ -1064,9 +1725,10 @@ int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, const char *pszLogNam
* @param offNtHdrs The offset of the NT headers from the start of the file.
* @param pFileHdr Pointer to the file header (valid).
* @param cbRawImage The raw image size.
+ * @param fFlags Loader flags, RTLDR_O_XXX.
*/
static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr, const char *pszLogName, RTFOFF offNtHdrs,
- const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage)
+ const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage, uint32_t fFlags)
{
const uint16_t CorrectMagic = pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
@@ -1193,6 +1855,12 @@ static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr,
Log(("rtldrPEOpen: %s: Security directory is misaligned: %#x\n", pszLogName, i, pDir->VirtualAddress));
return VERR_LDRPE_CERT_MALFORMED;
}
+ /* When using the in-memory reader with a debugger, we may get
+ into trouble here since we might not have access to the whole
+ physical file. So skip the tests below. Makes VBoxGuest.sys
+ load and check out just fine, for instance. */
+ if (fFlags & RTLDR_O_FOR_DEBUG)
+ continue;
break;
case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: // 8 /* (MIPS GP) */
@@ -1241,9 +1909,10 @@ static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr,
* @param pszLogName The log name to prefix the errors with.
* @param pOptHdr Pointer to the optional header (valid).
* @param cbRawImage The raw image size.
+ * @param fFlags Loader flags, RTLDR_O_XXX.
*/
-int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
- const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage)
+static int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
+ const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage, uint32_t fFlags)
{
const uint32_t cbImage = pOptHdr->SizeOfImage;
const IMAGE_SECTION_HEADER *pSH = &paSections[0];
@@ -1262,7 +1931,10 @@ int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsign
pSH->PointerToRawData, pSH->SizeOfRawData,
pSH->PointerToRelocations, pSH->NumberOfRelocations,
pSH->PointerToLinenumbers, pSH->NumberOfLinenumbers));
- if (pSH->Characteristics & (IMAGE_SCN_MEM_16BIT | IMAGE_SCN_MEM_FARDATA | IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD))
+
+ AssertCompile(IMAGE_SCN_MEM_16BIT == IMAGE_SCN_MEM_PURGEABLE);
+ if ( ( pSH->Characteristics & (IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD | IMAGE_SCN_MEM_FARDATA) )
+ && !(fFlags & RTLDR_O_FOR_DEBUG)) /* purgable/16-bit seen on w2ksp0 hal.dll, ignore the bunch. */
{
Log(("rtldrPEOpen: %s: Unsupported section flag(s) %#x section #%d '%.*s'!!!\n",
pszLogName, pSH->Characteristics, iSH, sizeof(pSH->Name), pSH->Name));
@@ -1344,7 +2016,7 @@ int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsign
static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t RVA)
{
const IMAGE_SECTION_HEADER *pSH = pModPe->paSections;
- PRTLDRREADER pReader = pModPe->pReader;
+ PRTLDRREADER pReader = pModPe->Core.pReader;
uint32_t cbRead;
int rc;
@@ -1421,10 +2093,11 @@ static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t
* @returns iprt status code.
* @param pModPe The PE module instance.
* @param pOptHdr Pointer to the optional header (valid).
+ * @param fFlags Loader flags, RTLDR_O_XXX.
*/
-int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr)
+static int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags)
{
- const char *pszLogName = pModPe->pReader->pfnLogName(pModPe->pReader); NOREF(pszLogName);
+ const char *pszLogName = pModPe->Core.pReader->pfnLogName(pModPe->Core.pReader); NOREF(pszLogName);
union /* combine stuff we're reading to help reduce stack usage. */
{
IMAGE_LOAD_CONFIG_DIRECTORY64 Cfg64;
@@ -1490,15 +2163,16 @@ int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64
}
/*
- * If the image is signed, take a look at the signature.
+ * If the image is signed and we're not doing this for debug purposes,
+ * take a look at the signature.
*/
Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
- if (Dir.Size)
+ if (Dir.Size && !(fFlags & RTLDR_O_FOR_DEBUG))
{
PWIN_CERTIFICATE pFirst = (PWIN_CERTIFICATE)RTMemTmpAlloc(Dir.Size);
if (!pFirst)
return VERR_NO_TMP_MEMORY;
- int rc = pModPe->pReader->pfnRead(pModPe->pReader, pFirst, Dir.Size, Dir.VirtualAddress);
+ int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pFirst, Dir.Size, Dir.VirtualAddress);
if (RT_SUCCESS(rc))
{
uint32_t off = 0;
@@ -1556,15 +2230,13 @@ int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64
*
* @returns iprt status code.
* @param pReader The loader reader instance which will provide the raw image bits.
- * @param fFlags Reserved, MBZ.
+ * @param fFlags Loader flags, RTLDR_O_XXX.
* @param enmArch Architecture specifier.
* @param offNtHdrs The offset of the NT headers (where you find "PE\0\0").
* @param phLdrMod Where to store the handle.
*/
int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod)
{
- AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
-
/*
* Read and validate the file header.
*/
@@ -1574,7 +2246,7 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
return rc;
RTLDRARCH enmArchImage;
const char *pszLogName = pReader->pfnLogName(pReader);
- rc = rtldrPEValidateFileHeader(&FileHdr, pszLogName, &enmArchImage);
+ rc = rtldrPEValidateFileHeader(&FileHdr, fFlags, pszLogName, &enmArchImage);
if (RT_FAILURE(rc))
return rc;
@@ -1594,7 +2266,7 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
return rc;
if (FileHdr.SizeOfOptionalHeader != sizeof(OptHdr))
rtldrPEConvert32BitOptionalHeaderTo64Bit(&OptHdr);
- rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader));
+ rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader), fFlags);
if (RT_FAILURE(rc))
return rc;
@@ -1605,11 +2277,12 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
PIMAGE_SECTION_HEADER paSections = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbSections);
if (!paSections)
return VERR_NO_MEMORY;
- rc = pReader->pfnRead(pReader, paSections, cbSections, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
+ rc = pReader->pfnRead(pReader, paSections, cbSections,
+ offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
if (RT_SUCCESS(rc))
{
rc = rtldrPEValidateSectionHeaders(paSections, FileHdr.NumberOfSections, pszLogName,
- &OptHdr, pReader->pfnSize(pReader));
+ &OptHdr, pReader->pfnSize(pReader), fFlags);
if (RT_SUCCESS(rc))
{
/*
@@ -1624,9 +2297,24 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
pModPe->Core.pOps = &s_rtldrPE64Ops.Core;
else
pModPe->Core.pOps = &s_rtldrPE32Ops.Core;
- pModPe->pReader = pReader;
+ pModPe->Core.pReader = pReader;
+ pModPe->Core.enmFormat= RTLDRFMT_PE;
+ pModPe->Core.enmType = FileHdr.Characteristics & IMAGE_FILE_DLL
+ ? FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED
+ ? RTLDRTYPE_EXECUTABLE_FIXED
+ : RTLDRTYPE_EXECUTABLE_RELOCATABLE
+ : FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED
+ ? RTLDRTYPE_SHARED_LIBRARY_FIXED
+ : RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
+ pModPe->Core.enmEndian= RTLDRENDIAN_LITTLE;
+ pModPe->Core.enmArch = FileHdr.Machine == IMAGE_FILE_MACHINE_I386
+ ? RTLDRARCH_X86_32
+ : FileHdr.Machine == IMAGE_FILE_MACHINE_AMD64
+ ? RTLDRARCH_AMD64
+ : RTLDRARCH_WHATEVER;
pModPe->pvBits = NULL;
pModPe->offNtHdrs = offNtHdrs;
+ pModPe->offEndOfHdrs = offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader + cbSections;
pModPe->u16Machine = FileHdr.Machine;
pModPe->fFile = FileHdr.Characteristics;
pModPe->cSections = FileHdr.NumberOfSections;
@@ -1635,15 +2323,17 @@ int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF
pModPe->uImageBase = (RTUINTPTR)OptHdr.ImageBase;
pModPe->cbImage = OptHdr.SizeOfImage;
pModPe->cbHeaders = OptHdr.SizeOfHeaders;
+ pModPe->uTimestamp = FileHdr.TimeDateStamp;
pModPe->ImportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
pModPe->RelocDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
pModPe->ExportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ pModPe->DebugDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
/*
* Perform validation of some selected data directories which requires
* inspection of the actual data.
*/
- rc = rtldrPEValidateDirectories(pModPe, &OptHdr);
+ rc = rtldrPEValidateDirectories(pModPe, &OptHdr, fFlags);
if (RT_SUCCESS(rc))
{
*phLdrMod = &pModPe->Core;
diff --git a/src/VBox/Runtime/common/ldr/ldrkStuff.cpp b/src/VBox/Runtime/common/ldr/ldrkStuff.cpp
index 61b36663..da53c29f 100644
--- a/src/VBox/Runtime/common/ldr/ldrkStuff.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrkStuff.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -240,9 +240,10 @@ static int rtkldrRdr_Create( PPKRDR ppRdr, const char *pszFilename)
/** @copydoc KLDRRDROPS::pfnDestroy */
static int rtkldrRdr_Destroy( PKRDR pRdr)
{
- PRTLDRREADER pReader = ((PRTKLDRRDR)pRdr)->pReader;
- int rc = pReader->pfnDestroy(pReader);
- return rtkldrConvertErrorFromIPRT(rc);
+ PRTKLDRRDR pThis = (PRTKLDRRDR)pRdr;
+ pThis->pReader = NULL;
+ RTMemFree(pThis);
+ return 0;
}
@@ -598,23 +599,49 @@ static int rtkldrEnumDbgInfoWrapper(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYP
PRTLDRMODKLDRARGS pArgs = (PRTLDRMODKLDRARGS)pvUser;
NOREF(pMod);
- RTLDRDBGINFOTYPE enmMyType;
+ RTLDRDBGINFO DbgInfo;
+ RT_ZERO(DbgInfo.u);
+ DbgInfo.iDbgInfo = iDbgInfo;
+ DbgInfo.offFile = offFile;
+ DbgInfo.LinkAddress = LinkAddress;
+ DbgInfo.cb = cb;
+ DbgInfo.pszExtFile = pszExtFile;
+
switch (enmType)
{
- case KLDRDBGINFOTYPE_UNKNOWN: enmMyType = RTLDRDBGINFOTYPE_UNKNOWN; break;
- case KLDRDBGINFOTYPE_STABS: enmMyType = RTLDRDBGINFOTYPE_STABS; break;
- case KLDRDBGINFOTYPE_DWARF: enmMyType = RTLDRDBGINFOTYPE_DWARF; break;
- case KLDRDBGINFOTYPE_CODEVIEW: enmMyType = RTLDRDBGINFOTYPE_CODEVIEW; break;
- case KLDRDBGINFOTYPE_WATCOM: enmMyType = RTLDRDBGINFOTYPE_WATCOM; break;
- case KLDRDBGINFOTYPE_HLL: enmMyType = RTLDRDBGINFOTYPE_HLL; break;
+ case KLDRDBGINFOTYPE_UNKNOWN:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
+ break;
+ case KLDRDBGINFOTYPE_STABS:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_STABS;
+ break;
+ case KLDRDBGINFOTYPE_DWARF:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF;
+ if (!pszExtFile)
+ DbgInfo.u.Dwarf.pszSection = pszPartNm;
+ else
+ {
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF_DWO;
+ DbgInfo.u.Dwo.uCrc32 = 0;
+ }
+ break;
+ case KLDRDBGINFOTYPE_CODEVIEW:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW;
+ /* Should make some more effort here... Assume the IPRT loader will kick in before we get here! */
+ break;
+ case KLDRDBGINFOTYPE_WATCOM:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_WATCOM;
+ break;
+ case KLDRDBGINFOTYPE_HLL:
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_HLL;
+ break;
default:
AssertFailed();
- enmMyType = RTLDRDBGINFOTYPE_UNKNOWN;
+ DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
break;
}
- int rc = pArgs->u.pfnEnumDbgInfo(&pArgs->pMod->Core, iDbgInfo, enmMyType, iMajorVer, iMinorVer, pszPartNm,
- offFile, LinkAddress, cb, pszExtFile, pArgs->pvUser);
+ int rc = pArgs->u.pfnEnumDbgInfo(&pArgs->pMod->Core, &DbgInfo, pArgs->pvUser);
if (RT_FAILURE(rc))
return rc; /* don't bother converting. */
return 0;
@@ -645,13 +672,29 @@ static DECLCALLBACK(int) rtkldr_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENU
PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod;
uint32_t const cSegments = pThis->pMod->cSegments;
PCKLDRSEG paSegments = &pThis->pMod->aSegments[0];
+ char szName[128];
for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++)
{
RTLDRSEG Seg;
- Seg.pchName = paSegments[iSeg].pchName;
- Seg.cchName = paSegments[iSeg].cchName;
+ if (!paSegments[iSeg].cchName)
+ {
+ Seg.pszName = szName;
+ Seg.cchName = (uint32_t)RTStrPrintf(szName, sizeof(szName), "Seg%02u", iSeg);
+ }
+ else if (paSegments[iSeg].pchName[paSegments[iSeg].cchName])
+ {
+ AssertReturn(paSegments[iSeg].cchName < sizeof(szName), VERR_INTERNAL_ERROR_3);
+ RTStrCopyEx(szName, sizeof(szName), paSegments[iSeg].pchName, paSegments[iSeg].cchName);
+ Seg.pszName = szName;
+ Seg.cchName = paSegments[iSeg].cchName;
+ }
+ else
+ {
+ Seg.pszName = paSegments[iSeg].pchName;
+ Seg.cchName = paSegments[iSeg].cchName;
+ }
Seg.SelFlat = paSegments[iSeg].SelFlat;
Seg.Sel16bit = paSegments[iSeg].Sel16bit;
Seg.fFlags = paSegments[iSeg].fFlags;
@@ -784,6 +827,15 @@ static DECLCALLBACK(int) rtkldr_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR
}
+/** @copydoc RTLDROPS::pfnReadDbgInfo. */
+static DECLCALLBACK(int) rtkldr_ReadDbgInfo(PRTLDRMODINTERNAL pMod, uint32_t iDbgInfo, RTFOFF off, size_t cb, void *pvBuf)
+{
+ PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod;
+ /** @todo May have to apply fixups here. */
+ return pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvBuf, cb, off);
+}
+
+
/**
* Operations for a kLdr module.
*/
@@ -805,6 +857,7 @@ static const RTLDROPS g_rtkldrOps =
rtkldr_LinkAddressToRva,
rtkldr_SegOffsetToRva,
rtkldr_RvaToSegOffset,
+ rtkldr_ReadDbgInfo,
42
};
@@ -836,6 +889,9 @@ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTL
default:
return VERR_INVALID_PARAMETER;
}
+ KU32 fKFlags = 0;
+ if (fFlags & RTLDR_O_FOR_DEBUG)
+ fKFlags |= KLDRMOD_OPEN_FLAGS_FOR_INFO;
/* Create a rtkldrRdr_ instance. */
PRTKLDRRDR pRdr = (PRTKLDRRDR)RTMemAllocZ(sizeof(*pRdr));
@@ -847,7 +903,7 @@ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTL
/* Try open it. */
PKLDRMOD pMod;
- int krc = kLdrModOpenFromRdr(&pRdr->Core, fFlags, enmCpuArch, &pMod);
+ int krc = kLdrModOpenFromRdr(&pRdr->Core, fKFlags, enmCpuArch, &pMod);
if (!krc)
{
/* Create a module wrapper for it. */
@@ -855,9 +911,59 @@ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTL
if (pNewMod)
{
pNewMod->Core.u32Magic = RTLDRMOD_MAGIC;
- pNewMod->Core.eState = LDR_STATE_OPENED;
- pNewMod->Core.pOps = &g_rtkldrOps;
- pNewMod->pMod = pMod;
+ pNewMod->Core.eState = LDR_STATE_OPENED;
+ pNewMod->Core.pOps = &g_rtkldrOps;
+ pNewMod->Core.pReader = pReader;
+ switch (pMod->enmFmt)
+ {
+ case KLDRFMT_NATIVE: pNewMod->Core.enmFormat = RTLDRFMT_NATIVE; break;
+ case KLDRFMT_AOUT: pNewMod->Core.enmFormat = RTLDRFMT_AOUT; break;
+ case KLDRFMT_ELF: pNewMod->Core.enmFormat = RTLDRFMT_ELF; break;
+ case KLDRFMT_LX: pNewMod->Core.enmFormat = RTLDRFMT_LX; break;
+ case KLDRFMT_MACHO: pNewMod->Core.enmFormat = RTLDRFMT_MACHO; break;
+ case KLDRFMT_PE: pNewMod->Core.enmFormat = RTLDRFMT_PE; break;
+ default:
+ AssertMsgFailed(("%d\n", pMod->enmFmt));
+ pNewMod->Core.enmFormat = RTLDRFMT_NATIVE;
+ break;
+ }
+ switch (pMod->enmType)
+ {
+ case KLDRTYPE_OBJECT: pNewMod->Core.enmType = RTLDRTYPE_OBJECT; break;
+ case KLDRTYPE_EXECUTABLE_FIXED: pNewMod->Core.enmType = RTLDRTYPE_EXECUTABLE_FIXED; break;
+ case KLDRTYPE_EXECUTABLE_RELOCATABLE: pNewMod->Core.enmType = RTLDRTYPE_EXECUTABLE_RELOCATABLE; break;
+ case KLDRTYPE_EXECUTABLE_PIC: pNewMod->Core.enmType = RTLDRTYPE_EXECUTABLE_PIC; break;
+ case KLDRTYPE_SHARED_LIBRARY_FIXED: pNewMod->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_FIXED; break;
+ case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE: pNewMod->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break;
+ case KLDRTYPE_SHARED_LIBRARY_PIC: pNewMod->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_PIC; break;
+ case KLDRTYPE_FORWARDER_DLL: pNewMod->Core.enmType = RTLDRTYPE_FORWARDER_DLL; break;
+ case KLDRTYPE_CORE: pNewMod->Core.enmType = RTLDRTYPE_CORE; break;
+ case KLDRTYPE_DEBUG_INFO: pNewMod->Core.enmType = RTLDRTYPE_DEBUG_INFO; break;
+ default:
+ AssertMsgFailed(("%d\n", pMod->enmType));
+ pNewMod->Core.enmType = RTLDRTYPE_OBJECT;
+ break;
+ }
+ switch (pMod->enmEndian)
+ {
+ case KLDRENDIAN_LITTLE: pNewMod->Core.enmEndian = RTLDRENDIAN_LITTLE; break;
+ case KLDRENDIAN_BIG: pNewMod->Core.enmEndian = RTLDRENDIAN_BIG; break;
+ case KLDRENDIAN_NA: pNewMod->Core.enmEndian = RTLDRENDIAN_NA; break;
+ default:
+ AssertMsgFailed(("%d\n", pMod->enmEndian));
+ pNewMod->Core.enmEndian = RTLDRENDIAN_NA;
+ break;
+ }
+ switch (pMod->enmArch)
+ {
+ case KCPUARCH_X86_32: pNewMod->Core.enmArch = RTLDRARCH_X86_32; break;
+ case KCPUARCH_AMD64: pNewMod->Core.enmArch = RTLDRARCH_AMD64; break;
+ default:
+ AssertMsgFailed(("%d\n", pMod->enmArch));
+ pNewMod->Core.enmArch = RTLDRARCH_WHATEVER;
+ break;
+ }
+ pNewMod->pMod = pMod;
*phLdrMod = &pNewMod->Core;
#ifdef LOG_ENABLED
@@ -874,9 +980,14 @@ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTL
#endif
return VINF_SUCCESS;
}
+
+ /* bail out */
kLdrModClose(pMod);
krc = KERR_NO_MEMORY;
}
+ else
+ RTMemFree(pRdr);
+
return rtkldrConvertError(krc);
}
diff --git a/src/VBox/Runtime/common/log/log.cpp b/src/VBox/Runtime/common/log/log.cpp
index 56e36c43..ed87266d 100644
--- a/src/VBox/Runtime/common/log/log.cpp
+++ b/src/VBox/Runtime/common/log/log.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -1492,6 +1492,7 @@ static unsigned rtlogGroupFlags(const char *psz)
}
} /* strincmp */
} /* for each flags */
+ AssertMsg(fFound, ("%.15s...", psz));
}
/*
@@ -2762,39 +2763,47 @@ static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst)
*/
static void rtlogFlush(PRTLOGGER pLogger)
{
- if (pLogger->offScratch == 0)
+ uint32_t const cchScratch = pLogger->offScratch;
+ if (cchScratch == 0)
return; /* nothing to flush. */
+ /* Make sure the string is terminated. On Windows, RTLogWriteDebugger
+ will get upset if it isn't. */
+ if (RT_LIKELY(cchScratch < sizeof(pLogger->achScratch)))
+ pLogger->achScratch[cchScratch] = '\0';
+ else
+ AssertFailed();
+
#ifndef IN_RC
if (pLogger->fDestFlags & RTLOGDEST_USER)
- RTLogWriteUser(pLogger->achScratch, pLogger->offScratch);
+ RTLogWriteUser(pLogger->achScratch, cchScratch);
if (pLogger->fDestFlags & RTLOGDEST_DEBUGGER)
- RTLogWriteDebugger(pLogger->achScratch, pLogger->offScratch);
+ RTLogWriteDebugger(pLogger->achScratch, cchScratch);
# ifdef IN_RING3
if (pLogger->fDestFlags & RTLOGDEST_FILE)
{
if (pLogger->pInt->hFile != NIL_RTFILE)
{
- RTFileWrite(pLogger->pInt->hFile, pLogger->achScratch, pLogger->offScratch, NULL);
+ RTFileWrite(pLogger->pInt->hFile, pLogger->achScratch, cchScratch, NULL);
if (pLogger->fFlags & RTLOGFLAGS_FLUSH)
RTFileFlush(pLogger->pInt->hFile);
}
if (pLogger->pInt->cHistory)
- pLogger->pInt->cbHistoryFileWritten += pLogger->offScratch;
+ pLogger->pInt->cbHistoryFileWritten += cchScratch;
}
# endif
if (pLogger->fDestFlags & RTLOGDEST_STDOUT)
- RTLogWriteStdOut(pLogger->achScratch, pLogger->offScratch);
+ RTLogWriteStdOut(pLogger->achScratch, cchScratch);
if (pLogger->fDestFlags & RTLOGDEST_STDERR)
- RTLogWriteStdErr(pLogger->achScratch, pLogger->offScratch);
+ RTLogWriteStdErr(pLogger->achScratch, cchScratch);
# if (defined(IN_RING0) || defined(IN_RC)) && !defined(LOG_NO_COM)
if (pLogger->fDestFlags & RTLOGDEST_COM)
- RTLogWriteCom(pLogger->achScratch, pLogger->offScratch);
+ RTLogWriteCom(pLogger->achScratch, cchScratch);
# endif
#endif /* !IN_RC */
@@ -3249,7 +3258,7 @@ static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars,
#define CCH_PREFIX_16 CCH_PREFIX_15 + 17
#define CCH_PREFIX ( CCH_PREFIX_16 )
- AssertCompile(CCH_PREFIX < 256);
+ { AssertCompile(CCH_PREFIX < 256); }
/*
* Done, figure what we've used and advance the buffer and free size.
diff --git a/src/VBox/Runtime/common/log/logcom.cpp b/src/VBox/Runtime/common/log/logcom.cpp
index 3ca78857..62400b7b 100644
--- a/src/VBox/Runtime/common/log/logcom.cpp
+++ b/src/VBox/Runtime/common/log/logcom.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/log/logellipsis.cpp b/src/VBox/Runtime/common/log/logellipsis.cpp
index dde4a096..00888921 100644
--- a/src/VBox/Runtime/common/log/logellipsis.cpp
+++ b/src/VBox/Runtime/common/log/logellipsis.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/log/logformat.cpp b/src/VBox/Runtime/common/log/logformat.cpp
index 38cdfd32..f17f4a0f 100644
--- a/src/VBox/Runtime/common/log/logformat.cpp
+++ b/src/VBox/Runtime/common/log/logformat.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/log/logrel.cpp b/src/VBox/Runtime/common/log/logrel.cpp
index 64f7eb2a..c72f5faf 100644
--- a/src/VBox/Runtime/common/log/logrel.cpp
+++ b/src/VBox/Runtime/common/log/logrel.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/log/logrelellipsis.cpp b/src/VBox/Runtime/common/log/logrelellipsis.cpp
index 5f1806c6..65239945 100644
--- a/src/VBox/Runtime/common/log/logrelellipsis.cpp
+++ b/src/VBox/Runtime/common/log/logrelellipsis.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/math/ceill.asm b/src/VBox/Runtime/common/math/ceill.asm
index 502181cd..ec2d0371 100644
--- a/src/VBox/Runtime/common/math/ceill.asm
+++ b/src/VBox/Runtime/common/math/ceill.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -38,7 +38,7 @@ BEGINPROC RT_NOCRT(ceill)
mov xBP, xSP
sub xSP, 10h
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
; Make it round up by modifying the fpu control word.
fstcw [xBP - 10h]
diff --git a/src/VBox/Runtime/common/math/cosl.asm b/src/VBox/Runtime/common/math/cosl.asm
index c37c3c6a..ab29ccb5 100644
--- a/src/VBox/Runtime/common/math/cosl.asm
+++ b/src/VBox/Runtime/common/math/cosl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -31,13 +31,13 @@ BEGINCODE
;;
; compute the cosine of ldr, measured in radians.
; @returns st(0)
-; @param lrd [rbp + xS*2]
+; @param lrd [rbp + xCB*2]
BEGINPROC RT_NOCRT(cosl)
push xBP
mov xBP, xSP
sub xSP, 10h
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
fcos
fnstsw ax
test ah, 4
diff --git a/src/VBox/Runtime/common/math/fabs.asm b/src/VBox/Runtime/common/math/fabs.asm
index 18ca0115..ea510f2d 100644
--- a/src/VBox/Runtime/common/math/fabs.asm
+++ b/src/VBox/Runtime/common/math/fabs.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -48,7 +48,7 @@ BEGINPROC RT_NOCRT(fabs)
movsd xmm0, [xSP]
%else
- fld qword [xBP + xS*2]
+ fld qword [xBP + xCB*2]
fabs
%endif
diff --git a/src/VBox/Runtime/common/math/fabsf.asm b/src/VBox/Runtime/common/math/fabsf.asm
index c58d2fc4..0bb77913 100644
--- a/src/VBox/Runtime/common/math/fabsf.asm
+++ b/src/VBox/Runtime/common/math/fabsf.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -48,7 +48,7 @@ BEGINPROC RT_NOCRT(fabsf)
movsd xmm0, [xSP]
%else
- fld dword [xBP + xS*2]
+ fld dword [xBP + xCB*2]
fabs
%endif
diff --git a/src/VBox/Runtime/common/math/fabsl.asm b/src/VBox/Runtime/common/math/fabsl.asm
index 1302b00d..b7a3dbf0 100644
--- a/src/VBox/Runtime/common/math/fabsl.asm
+++ b/src/VBox/Runtime/common/math/fabsl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -31,12 +31,12 @@ BEGINCODE
;;
; Compute the absolute value of lrd (|lrd|).
; @returns st(0)
-; @param lrd [xSP + xS*2]
+; @param lrd [xSP + xCB*2]
BEGINPROC RT_NOCRT(fabsl)
push xBP
mov xBP, xSP
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
fabs
.done:
diff --git a/src/VBox/Runtime/common/math/floor.asm b/src/VBox/Runtime/common/math/floor.asm
index 7d98b4b4..5df92114 100644
--- a/src/VBox/Runtime/common/math/floor.asm
+++ b/src/VBox/Runtime/common/math/floor.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -41,7 +41,7 @@ BEGINPROC RT_NOCRT(floor)
movsd [xSP], xmm0
fld qword [xSP]
%else
- fld qword [xBP + xS*2]
+ fld qword [xBP + xCB*2]
%endif
; Make it round down by modifying the fpu control word.
diff --git a/src/VBox/Runtime/common/math/floorf.asm b/src/VBox/Runtime/common/math/floorf.asm
index b5491919..e5c798a2 100644
--- a/src/VBox/Runtime/common/math/floorf.asm
+++ b/src/VBox/Runtime/common/math/floorf.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -41,7 +41,7 @@ BEGINPROC RT_NOCRT(floorf)
movss [xSP], xmm0
fld dword [xSP]
%else
- fld dword [xBP + xS*2]
+ fld dword [xBP + xCB*2]
%endif
; Make it round down by modifying the fpu control word.
diff --git a/src/VBox/Runtime/common/math/floorl.asm b/src/VBox/Runtime/common/math/floorl.asm
index c27ada71..6a89c0ad 100644
--- a/src/VBox/Runtime/common/math/floorl.asm
+++ b/src/VBox/Runtime/common/math/floorl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -37,7 +37,7 @@ BEGINPROC RT_NOCRT(floorl)
mov xBP, xSP
sub xSP, 10h
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
; Make it round down by modifying the fpu control word.
fstcw [xBP - 10h]
diff --git a/src/VBox/Runtime/common/math/ldexpl.asm b/src/VBox/Runtime/common/math/ldexpl.asm
index f53a4e43..f64ca4bd 100644
--- a/src/VBox/Runtime/common/math/ldexpl.asm
+++ b/src/VBox/Runtime/common/math/ldexpl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -31,7 +31,7 @@ BEGINCODE
;;
; Computes lrd * 2^exp
; @returns st(0)
-; @param lrd [rbp + xS*2]
+; @param lrd [rbp + xCB*2]
; @param exp [ebp + 14h] GCC:edi MSC:ecx
BEGINPROC RT_NOCRT(ldexpl)
push xBP
@@ -43,9 +43,9 @@ BEGINPROC RT_NOCRT(ldexpl)
mov [rsp], edi
fild dword [rsp]
%else
- fild dword [ebp + xS*2 + RTLRD_CB]
+ fild dword [ebp + xCB*2 + RTLRD_CB]
%endif
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
fscale
fstp st1
diff --git a/src/VBox/Runtime/common/math/llrint.asm b/src/VBox/Runtime/common/math/llrint.asm
index c870b913..528bdf09 100644
--- a/src/VBox/Runtime/common/math/llrint.asm
+++ b/src/VBox/Runtime/common/math/llrint.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/math/llrintf.asm b/src/VBox/Runtime/common/math/llrintf.asm
index d0c23db7..fcffd9ce 100644
--- a/src/VBox/Runtime/common/math/llrintf.asm
+++ b/src/VBox/Runtime/common/math/llrintf.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/math/llrintl.asm b/src/VBox/Runtime/common/math/llrintl.asm
index a0ce4912..c30bdfac 100644
--- a/src/VBox/Runtime/common/math/llrintl.asm
+++ b/src/VBox/Runtime/common/math/llrintl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -31,13 +31,13 @@ BEGINCODE
;;
; Round rd to the nearest integer value, rounding according to the current rounding direction.
; @returns 32-bit: edx:eax 64-bit: rax
-; @param lrd [rbp + xS*2]
+; @param lrd [rbp + xCB*2]
BEGINPROC RT_NOCRT(llrintl)
push xBP
mov xBP, xSP
sub xSP, 10h
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
fistp qword [xSP]
fwait
%ifdef RT_ARCH_AMD64
diff --git a/src/VBox/Runtime/common/math/logl.asm b/src/VBox/Runtime/common/math/logl.asm
index 83e7de96..b203c4c1 100644
--- a/src/VBox/Runtime/common/math/logl.asm
+++ b/src/VBox/Runtime/common/math/logl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -31,14 +31,14 @@ BEGINCODE
;;
; compute the natural logarithm of lrd
; @returns st(0)
-; @param lrd [rbp + xS*2]
+; @param lrd [rbp + xCB*2]
BEGINPROC RT_NOCRT(logl)
push xBP
mov xBP, xSP
sub xSP, 10h
fldln2 ; st0=log(2)
- fld tword [xBP + xS*2] ; st1=log(2) st0=lrd
+ fld tword [xBP + xCB*2] ; st1=log(2) st0=lrd
fld st0 ; st1=log(2) st0=lrd st0=lrd
fsub qword [.one xWrtRIP] ; st2=log(2) st1=lrd st0=lrd-1.0
fld st0 ; st3=log(2) st2=lrd st1=lrd-1.0 st0=lrd-1.0
diff --git a/src/VBox/Runtime/common/math/lrint.asm b/src/VBox/Runtime/common/math/lrint.asm
index 270a79f8..130598ab 100644
--- a/src/VBox/Runtime/common/math/lrint.asm
+++ b/src/VBox/Runtime/common/math/lrint.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/math/lrintf.asm b/src/VBox/Runtime/common/math/lrintf.asm
index 99729497..7bc70032 100644
--- a/src/VBox/Runtime/common/math/lrintf.asm
+++ b/src/VBox/Runtime/common/math/lrintf.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/math/lrintl.asm b/src/VBox/Runtime/common/math/lrintl.asm
index f336af6a..72795eb3 100644
--- a/src/VBox/Runtime/common/math/lrintl.asm
+++ b/src/VBox/Runtime/common/math/lrintl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -31,13 +31,13 @@ BEGINCODE
;;
; Round rd to the nearest integer value, rounding according to the current rounding direction.
; @returns 32-bit: eax 64-bit: rax
-; @param lrd [rbp + xS*2]
+; @param lrd [rbp + xCB*2]
BEGINPROC RT_NOCRT(lrintl)
push xBP
mov xBP, xSP
sub xSP, 10h
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
%ifdef RT_ARCH_AMD64
fistp qword [xSP]
fwait
diff --git a/src/VBox/Runtime/common/math/remainder.asm b/src/VBox/Runtime/common/math/remainder.asm
index 117aa502..77419139 100644
--- a/src/VBox/Runtime/common/math/remainder.asm
+++ b/src/VBox/Runtime/common/math/remainder.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/math/remainderf.asm b/src/VBox/Runtime/common/math/remainderf.asm
index c9b079b7..d6f87aae 100644
--- a/src/VBox/Runtime/common/math/remainderf.asm
+++ b/src/VBox/Runtime/common/math/remainderf.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/math/remainderl.asm b/src/VBox/Runtime/common/math/remainderl.asm
index 922f93a7..d5d53198 100644
--- a/src/VBox/Runtime/common/math/remainderl.asm
+++ b/src/VBox/Runtime/common/math/remainderl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/math/sinl.asm b/src/VBox/Runtime/common/math/sinl.asm
index 57f5ab8b..4fb0d7c4 100644
--- a/src/VBox/Runtime/common/math/sinl.asm
+++ b/src/VBox/Runtime/common/math/sinl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -31,13 +31,13 @@ BEGINCODE
;;
; Compute the sine of lrd
; @returns st(0)
-; @param lrd [xSP + xS*2]
+; @param lrd [xSP + xCB*2]
BEGINPROC RT_NOCRT(sinl)
push xBP
mov xBP, xSP
sub xSP, 10h
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
fsin
fnstsw ax
test ah, 04h
diff --git a/src/VBox/Runtime/common/math/tanl.asm b/src/VBox/Runtime/common/math/tanl.asm
index 85e61d04..2fabc362 100644
--- a/src/VBox/Runtime/common/math/tanl.asm
+++ b/src/VBox/Runtime/common/math/tanl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -31,13 +31,13 @@ BEGINCODE
;;
; Compute the sine of lrd
; @returns st(0)
-; @param lrd [xSP + xS*2]
+; @param lrd [xSP + xCB*2]
BEGINPROC RT_NOCRT(tanl)
push xBP
mov xBP, xSP
sub xSP, 10h
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
fptan
fnstsw ax
test ah, 04h ; check for C2
diff --git a/src/VBox/Runtime/common/math/trunc.asm b/src/VBox/Runtime/common/math/trunc.asm
index 9ea36820..11d310cf 100644
--- a/src/VBox/Runtime/common/math/trunc.asm
+++ b/src/VBox/Runtime/common/math/trunc.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -42,7 +42,7 @@ BEGINPROC RT_NOCRT(trunc)
movsd [xSP], xmm0
fld qword [xSP]
%else
- fld qword [xBP + xS*2]
+ fld qword [xBP + xCB*2]
%endif
; Make it truncate up by modifying the fpu control word.
diff --git a/src/VBox/Runtime/common/math/truncf.asm b/src/VBox/Runtime/common/math/truncf.asm
index 9fb8166c..5914d8ea 100644
--- a/src/VBox/Runtime/common/math/truncf.asm
+++ b/src/VBox/Runtime/common/math/truncf.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -42,7 +42,7 @@ BEGINPROC RT_NOCRT(truncf)
movss [xSP], xmm0
fld dword [xSP]
%else
- fld dword [xBP + xS*2]
+ fld dword [xBP + xCB*2]
%endif
; Make it truncate up by modifying the fpu control word.
diff --git a/src/VBox/Runtime/common/math/truncl.asm b/src/VBox/Runtime/common/math/truncl.asm
index 45576833..b703cba0 100644
--- a/src/VBox/Runtime/common/math/truncl.asm
+++ b/src/VBox/Runtime/common/math/truncl.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -38,7 +38,7 @@ BEGINPROC RT_NOCRT(truncl)
mov xBP, xSP
sub xSP, 10h
- fld tword [xBP + xS*2]
+ fld tword [xBP + xCB*2]
; Make it truncate up by modifying the fpu control word.
fstcw [xBP - 10h]
diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp
index ef0f35ee..06d6afa1 100644
--- a/src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp
+++ b/src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2.cpp
index 401baac8..69fbd049 100644
--- a/src/VBox/Runtime/common/misc/RTAssertMsg2.cpp
+++ b/src/VBox/Runtime/common/misc/RTAssertMsg2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp
index e0f3fb23..f8bd63ec 100644
--- a/src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp
+++ b/src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2009 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp
index 297e60d9..a36a30ac 100644
--- a/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp
+++ b/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2009 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp
index 99bc5e64..8ffe97e2 100644
--- a/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp
+++ b/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp
index 2b5b9cf6..7a40d265 100644
--- a/src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp
+++ b/src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2009 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp
index 2d9b5eff..f54b0446 100644
--- a/src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp
+++ b/src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp b/src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp
new file mode 100644
index 00000000..b5e10a27
--- /dev/null
+++ b/src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp
@@ -0,0 +1,337 @@
+/* $Id: RTFileModeToFlags.cpp $ */
+/** @file
+ * IPRT - RTFileModeToFlags.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+
+RTR3DECL(int) RTFileModeToFlags(const char *pszMode, uint64_t *puMode)
+{
+ AssertPtrReturn(pszMode, VERR_INVALID_POINTER);
+ AssertPtrReturn(puMode, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+
+ const char *pszCur = pszMode;
+ uint64_t uMode = 0;
+ char chPrev = 0;
+
+ if (*pszCur == '\0')
+ return VERR_INVALID_PARAMETER;
+
+ while ( pszCur
+ && *pszCur != '\0')
+ {
+ bool fSkip = false;
+ switch (*pszCur)
+ {
+ /* Opens an existing file for writing and places the
+ * file pointer at the end of the file. The file is
+ * created if it does not exist. */
+ case 'a':
+ if ((uMode & RTFILE_O_ACTION_MASK) == 0)
+ {
+ uMode |= RTFILE_O_OPEN_CREATE
+ | RTFILE_O_WRITE
+ | RTFILE_O_APPEND;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+
+ case 'b': /* Binary mode. */
+ /* Just skip as being valid. */
+ fSkip = true;
+ break;
+
+ /* Creates a file or open an existing one for
+ * writing only. The file pointer will be placed
+ * at the beginning of the file.*/
+ case 'c':
+ if ((uMode & RTFILE_O_ACTION_MASK) == 0)
+ {
+ uMode |= RTFILE_O_OPEN_CREATE
+ | RTFILE_O_WRITE;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+
+ /* Opens an existing file for reading and places the
+ * file pointer at the beginning of the file. If the
+ * file does not exist an error will be returned. */
+ case 'r':
+ if ((uMode & RTFILE_O_ACTION_MASK) == 0)
+ {
+ uMode |= RTFILE_O_OPEN
+ | RTFILE_O_READ;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+
+ case 't': /* Text mode. */
+ /* Just skip as being valid. */
+ fSkip = true;
+ break;
+
+ /* Creates a new file or replaces an existing one
+ * for writing. Places the file pointer at the beginning.
+ * An existing file will be truncated to 0 bytes. */
+ case 'w':
+ if ((uMode & RTFILE_O_ACTION_MASK) == 0)
+ {
+ uMode |= RTFILE_O_CREATE_REPLACE
+ | RTFILE_O_WRITE
+ | RTFILE_O_TRUNCATE;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+
+ /* Creates a new file and opens it for writing. Places
+ * the file pointer at the beginning. If the file
+ * exists an error will be returned. */
+ case 'x':
+ if ((uMode & RTFILE_O_ACTION_MASK) == 0)
+ {
+ uMode |= RTFILE_O_CREATE
+ | RTFILE_O_WRITE;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+
+ case '+':
+ {
+ switch (chPrev)
+ {
+ case 'a':
+ case 'c':
+ case 'w':
+ case 'x':
+ /* Also open / create file with read access. */
+ uMode |= RTFILE_O_READ;
+ break;
+
+ case 'r':
+ /* Also open / create file with write access. */
+ uMode |= RTFILE_O_WRITE;
+ break;
+
+ case 'b':
+ case 't':
+ /* Silently eat skipped parameters. */
+ fSkip = true;
+ break;
+
+ case 0: /* No previous character yet. */
+ case '+':
+ /* Eat plusses which don't belong to a command. */
+ fSkip = true;
+ break;
+
+ default:
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ break;
+ }
+
+ default:
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (RT_FAILURE(rc))
+ break;
+
+ if (!fSkip)
+ chPrev = *pszCur;
+ pszCur++;
+ }
+
+ /* No action mask set? */
+ if ( RT_SUCCESS(rc)
+ && (uMode & RTFILE_O_ACTION_MASK) == 0)
+ rc = VERR_INVALID_PARAMETER;
+
+ /** @todo Handle sharing mode. */
+ uMode |= RTFILE_O_DENY_NONE;
+
+ if (RT_SUCCESS(rc))
+ *puMode = uMode;
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTFileModeToFlags);
+
+
+RTR3DECL(int) RTFileModeToFlagsEx(const char *pszAccess, const char *pszDisposition,
+ const char *pszSharing, uint64_t *puMode)
+{
+ AssertPtrReturn(pszAccess, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszDisposition, VERR_INVALID_POINTER);
+ /* pszSharing is not used yet. */
+ AssertPtrReturn(puMode, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+
+ const char *pszCur = pszAccess;
+ uint64_t uMode = 0;
+ char chPrev = 0;
+
+ if (*pszCur == '\0')
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Handle access mode.
+ */
+ while ( pszCur
+ && *pszCur != '\0')
+ {
+ bool fSkip = false;
+ switch (*pszCur)
+ {
+ case 'b': /* Binary mode. */
+ /* Just skip as being valid. */
+ fSkip = true;
+ break;
+
+ case 'r': /* Read. */
+ uMode |= RTFILE_O_READ;
+ break;
+
+ case 't': /* Text mode. */
+ /* Just skip as being valid. */
+ fSkip = true;
+ break;
+
+ case 'w': /* Write. */
+ uMode |= RTFILE_O_WRITE;
+ break;
+
+ case '+':
+ {
+ switch (chPrev)
+ {
+ case 'w':
+ /* Also use read access in write mode. */
+ uMode |= RTFILE_O_READ;
+ break;
+
+ case 'r':
+ /* Also use write access in read mode. */
+ uMode |= RTFILE_O_WRITE;
+ break;
+
+ case 'b':
+ case 't':
+ /* Silently eat skipped parameters. */
+ fSkip = true;
+ break;
+
+ case 0: /* No previous character yet. */
+ case '+':
+ /* Eat plusses which don't belong to a command. */
+ fSkip = true;
+ break;
+
+ default:
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ break;
+ }
+
+ default:
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (RT_FAILURE(rc))
+ break;
+
+ if (!fSkip)
+ chPrev = *pszCur;
+ pszCur++;
+ }
+
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Handle disposition.
+ */
+ pszCur = pszDisposition;
+
+ /* Create a new file, always, overwrite an existing file. */
+ if (!RTStrCmp(pszCur, "ca"))
+ uMode |= RTFILE_O_CREATE_REPLACE;
+ /* Create a new file if it does not exist, fail if exist. */
+ else if (!RTStrCmp(pszCur, "ce"))
+ uMode |= RTFILE_O_CREATE;
+ /* Open existing file, create file if does not exist. */
+ else if (!RTStrCmp(pszCur, "oc"))
+ uMode |= RTFILE_O_OPEN_CREATE;
+ /* Open existing file and place the file pointer at
+ * the end of the file, if opened with write access.
+ * Create the file if does not exist. */
+ else if (!RTStrCmp(pszCur, "oa"))
+ uMode |= RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND;
+ /* Open existing, fail if does not exist. */
+ else if (!RTStrCmp(pszCur, "oe"))
+ uMode |= RTFILE_O_OPEN;
+ /* Open and truncate existing, fail of not exist. */
+ else if (!RTStrCmp(pszCur, "ot"))
+ uMode |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
+ else
+ rc = VERR_INVALID_PARAMETER;
+
+ /* No action mask set? */
+ if ( RT_SUCCESS(rc)
+ && (uMode & RTFILE_O_ACTION_MASK) == 0)
+ rc = VERR_INVALID_PARAMETER;
+
+ /** @todo Handle sharing mode. */
+ uMode |= RTFILE_O_DENY_NONE;
+
+ if (RT_SUCCESS(rc))
+ *puMode = uMode;
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTFileModeToFlagsEx);
+
diff --git a/src/VBox/Runtime/common/misc/RTFileOpenF.cpp b/src/VBox/Runtime/common/misc/RTFileOpenF.cpp
index e2737bf6..73837369 100644
--- a/src/VBox/Runtime/common/misc/RTFileOpenF.cpp
+++ b/src/VBox/Runtime/common/misc/RTFileOpenF.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/RTFileOpenV.cpp b/src/VBox/Runtime/common/misc/RTFileOpenV.cpp
index 43214e06..b8ed619e 100644
--- a/src/VBox/Runtime/common/misc/RTFileOpenV.cpp
+++ b/src/VBox/Runtime/common/misc/RTFileOpenV.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/aiomgr.cpp b/src/VBox/Runtime/common/misc/aiomgr.cpp
new file mode 100644
index 00000000..43f12c87
--- /dev/null
+++ b/src/VBox/Runtime/common/misc/aiomgr.cpp
@@ -0,0 +1,1314 @@
+/* $Id: aiomgr.cpp $ */
+/** @file
+ * IPRT - Async I/O manager.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+
+#include <iprt/aiomgr.h>
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include <iprt/mem.h>
+#include <iprt/file.h>
+#include <iprt/list.h>
+#include <iprt/thread.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <iprt/critsect.h>
+#include <iprt/memcache.h>
+#include <iprt/semaphore.h>
+#include <iprt/queueatomic.h>
+
+#include "internal/magics.h"
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+
+/** Pointer to an internal async I/O file instance. */
+typedef struct RTAIOMGRFILEINT *PRTAIOMGRFILEINT;
+
+/**
+ * Blocking event types.
+ */
+typedef enum RTAIOMGREVENT
+{
+ /** Invalid tye */
+ RTAIOMGREVENT_INVALID = 0,
+ /** No event pending. */
+ RTAIOMGREVENT_NO_EVENT,
+ /** A file is added to the manager. */
+ RTAIOMGREVENT_FILE_ADD,
+ /** A file is about to be closed. */
+ RTAIOMGREVENT_FILE_CLOSE,
+ /** The async I/O manager is shut down. */
+ RTAIOMGREVENT_SHUTDOWN,
+ /** 32bit hack */
+ RTAIOMGREVENT_32BIT_HACK = 0x7fffffff
+} RTAIOMGREVENT;
+
+/**
+ * Async I/O manager instance data.
+ */
+typedef struct RTAIOMGRINT
+{
+ /** Magic value. */
+ uint32_t u32Magic;
+ /** Reference count. */
+ volatile uint32_t cRefs;
+ /** Async I/O context handle. */
+ RTFILEAIOCTX hAioCtx;
+ /** async I/O thread. */
+ RTTHREAD hThread;
+ /** List of files assigned to this manager. */
+ RTLISTANCHOR ListFiles;
+ /** Number of requests active currently. */
+ unsigned cReqsActive;
+ /** Number of maximum requests active. */
+ uint32_t cReqsActiveMax;
+ /** Memory cache for requests. */
+ RTMEMCACHE hMemCacheReqs;
+ /** Critical section protecting the blocking event handling. */
+ RTCRITSECT CritSectBlockingEvent;
+ /** Event semaphore for blocking external events.
+ * The caller waits on it until the async I/O manager
+ * finished processing the event. */
+ RTSEMEVENT hEventSemBlock;
+ /** Blocking event type */
+ volatile RTAIOMGREVENT enmBlockingEvent;
+ /** Event type data */
+ union
+ {
+ /** The file to be added */
+ volatile PRTAIOMGRFILEINT pFileAdd;
+ /** The file to be closed */
+ volatile PRTAIOMGRFILEINT pFileClose;
+ } BlockingEventData;
+} RTAIOMGRINT;
+/** Pointer to an internal async I/O manager instance. */
+typedef RTAIOMGRINT *PRTAIOMGRINT;
+
+/**
+ * Async I/O manager file instance data.
+ */
+typedef struct RTAIOMGRFILEINT
+{
+ /** Magic value. */
+ uint32_t u32Magic;
+ /** Reference count. */
+ volatile uint32_t cRefs;
+ /** Flags. */
+ uint32_t fFlags;
+ /** Opaque user data passed on creation. */
+ void *pvUser;
+ /** File handle. */
+ RTFILE hFile;
+ /** async I/O manager this file belongs to. */
+ PRTAIOMGRINT pAioMgr;
+ /** Work queue for new requests. */
+ RTQUEUEATOMIC QueueReqs;
+ /** Completion callback for this file. */
+ PFNRTAIOMGRREQCOMPLETE pfnReqCompleted;
+ /** Data for exclusive use by the assigned async I/O manager. */
+ struct
+ {
+ /** List node of assigned files for a async I/O manager. */
+ RTLISTNODE NodeAioMgrFiles;
+ /** List of requests waiting for submission. */
+ RTLISTANCHOR ListWaitingReqs;
+ /** Number of requests currently being processed for this endpoint
+ * (excluded flush requests). */
+ unsigned cReqsActive;
+ } AioMgr;
+} RTAIOMGRFILEINT;
+
+/** Flag whether the file is closed. */
+#define RTAIOMGRFILE_FLAGS_CLOSING RT_BIT_32(1)
+
+/**
+ * Request type.
+ */
+typedef enum RTAIOMGRREQTYPE
+{
+ /** Invalid request type. */
+ RTAIOMGRREQTYPE_INVALID = 0,
+ /** Read reques type. */
+ RTAIOMGRREQTYPE_READ,
+ /** Write request. */
+ RTAIOMGRREQTYPE_WRITE,
+ /** Flush request. */
+ RTAIOMGRREQTYPE_FLUSH,
+ /** Prefetech request. */
+ RTAIOMGRREQTYPE_PREFETCH,
+ /** 32bit hack. */
+ RTAIOMGRREQTYPE_32BIT_HACK = 0x7fffffff
+} RTAIOMGRREQTYPE;
+/** Pointer to a reques type. */
+typedef RTAIOMGRREQTYPE *PRTAIOMGRREQTYPE;
+
+/**
+ * Async I/O manager request.
+ */
+typedef struct RTAIOMGRREQ
+{
+ /** Atomic queue work item. */
+ RTQUEUEATOMICITEM WorkItem;
+ /** Node for a waiting list. */
+ RTLISTNODE NodeWaitingList;
+ /** Request flags. */
+ uint32_t fFlags;
+ /** Transfer type. */
+ RTAIOMGRREQTYPE enmType;
+ /** Assigned file request. */
+ RTFILEAIOREQ hReqIo;
+ /** File the request belongs to. */
+ PRTAIOMGRFILEINT pFile;
+ /** Opaque user data. */
+ void *pvUser;
+ /** Start offset */
+ RTFOFF off;
+ /** Data segment. */
+ RTSGSEG DataSeg;
+ /** When non-zero the segment uses a bounce buffer because the provided buffer
+ * doesn't meet host requirements. */
+ size_t cbBounceBuffer;
+ /** Pointer to the used bounce buffer if any. */
+ void *pvBounceBuffer;
+ /** Start offset in the bounce buffer to copy from. */
+ uint32_t offBounceBuffer;
+} RTAIOMGRREQ;
+/** Pointer to a I/O manager request. */
+typedef RTAIOMGRREQ *PRTAIOMGRREQ;
+
+/** Flag whether the request was prepared already. */
+#define RTAIOMGRREQ_FLAGS_PREPARED RT_BIT_32(0)
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+
+/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
+#define RTAIOMGR_VALID_RETURN_RC(a_hAioMgr, a_rc) \
+ do { \
+ AssertPtrReturn((a_hAioMgr), (a_rc)); \
+ AssertReturn((a_hAioMgr)->u32Magic == RTAIOMGR_MAGIC, (a_rc)); \
+ } while (0)
+
+/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
+#define RTAIOMGR_VALID_RETURN(a_hAioMgr) RTAIOMGR_VALID_RETURN_RC((hAioMgr), VERR_INVALID_HANDLE)
+
+/** Validates a handle and returns (void) if not valid. */
+#define RTAIOMGR_VALID_RETURN_VOID(a_hAioMgr) \
+ do { \
+ AssertPtrReturnVoid(a_hAioMgr); \
+ AssertReturnVoid((a_hAioMgr)->u32Magic == RTAIOMGR_MAGIC); \
+ } while (0)
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+
+static int rtAioMgrReqsEnqueue(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile,
+ PRTFILEAIOREQ pahReqs, unsigned cReqs);
+
+/**
+ * Removes an endpoint from the currently assigned manager.
+ *
+ * @returns TRUE if there are still requests pending on the current manager for this endpoint.
+ * FALSE otherwise.
+ * @param pEndpointRemove The endpoint to remove.
+ */
+static bool rtAioMgrFileRemove(PRTAIOMGRFILEINT pFile)
+{
+ /* Make sure that there is no request pending on this manager for the endpoint. */
+ if (!pFile->AioMgr.cReqsActive)
+ {
+ RTListNodeRemove(&pFile->AioMgr.NodeAioMgrFiles);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Allocate a new I/O request.
+ *
+ * @returns Pointer to the allocated request or NULL if out of memory.
+ * @param pThis The async I/O manager instance.
+ */
+static PRTAIOMGRREQ rtAioMgrReqAlloc(PRTAIOMGRINT pThis)
+{
+ return (PRTAIOMGRREQ)RTMemCacheAlloc(pThis->hMemCacheReqs);
+}
+
+/**
+ * Frees an I/O request.
+ *
+ * @returns nothing.
+ * @param pThis The async I/O manager instance.
+ * @param pReq The request to free.
+ */
+static void rtAioMgrReqFree(PRTAIOMGRINT pThis, PRTAIOMGRREQ pReq)
+{
+ if (pReq->cbBounceBuffer)
+ {
+ AssertPtr(pReq->pvBounceBuffer);
+ RTMemPageFree(pReq->pvBounceBuffer, pReq->cbBounceBuffer);
+ pReq->pvBounceBuffer = NULL;
+ pReq->cbBounceBuffer = 0;
+ }
+ pReq->fFlags = 0;
+ RTAioMgrFileRelease(pReq->pFile);
+ RTMemCacheFree(pThis->hMemCacheReqs, pReq);
+}
+
+static void rtAioMgrReqCompleteRc(PRTAIOMGRINT pThis, PRTAIOMGRREQ pReq,
+ int rcReq, size_t cbTransfered)
+{
+ int rc = VINF_SUCCESS;
+ PRTAIOMGRFILEINT pFile;
+
+ pFile = pReq->pFile;
+ pThis->cReqsActive--;
+ pFile->AioMgr.cReqsActive--;
+
+ /*
+ * It is possible that the request failed on Linux with kernels < 2.6.23
+ * if the passed buffer was allocated with remap_pfn_range or if the file
+ * is on an NFS endpoint which does not support async and direct I/O at the same time.
+ * The endpoint will be migrated to a failsafe manager in case a request fails.
+ */
+ if (RT_FAILURE(rcReq))
+ {
+ pFile->pfnReqCompleted(pFile, rcReq, pReq->pvUser);
+ rtAioMgrReqFree(pThis, pReq);
+ }
+ else
+ {
+ /*
+ * Restart an incomplete transfer.
+ * This usually means that the request will return an error now
+ * but to get the cause of the error (disk full, file too big, I/O error, ...)
+ * the transfer needs to be continued.
+ */
+ if (RT_UNLIKELY( cbTransfered < pReq->DataSeg.cbSeg
+ || ( pReq->cbBounceBuffer
+ && cbTransfered < pReq->cbBounceBuffer)))
+ {
+ RTFOFF offStart;
+ size_t cbToTransfer;
+ uint8_t *pbBuf = NULL;
+
+ Assert(cbTransfered % 512 == 0);
+
+ if (pReq->cbBounceBuffer)
+ {
+ AssertPtr(pReq->pvBounceBuffer);
+ offStart = (pReq->off & ~((RTFOFF)512-1)) + cbTransfered;
+ cbToTransfer = pReq->cbBounceBuffer - cbTransfered;
+ pbBuf = (uint8_t *)pReq->pvBounceBuffer + cbTransfered;
+ }
+ else
+ {
+ Assert(!pReq->pvBounceBuffer);
+ offStart = pReq->off + cbTransfered;
+ cbToTransfer = pReq->DataSeg.cbSeg - cbTransfered;
+ pbBuf = (uint8_t *)pReq->DataSeg.pvSeg + cbTransfered;
+ }
+
+ if ( pReq->enmType == RTAIOMGRREQTYPE_PREFETCH
+ || pReq->enmType == RTAIOMGRREQTYPE_READ)
+ {
+ rc = RTFileAioReqPrepareRead(pReq->hReqIo, pFile->hFile, offStart,
+ pbBuf, cbToTransfer, pReq);
+ }
+ else
+ {
+ AssertMsg(pReq->enmType == RTAIOMGRREQTYPE_WRITE,
+ ("Invalid transfer type\n"));
+ rc = RTFileAioReqPrepareWrite(pReq->hReqIo, pFile->hFile, offStart,
+ pbBuf, cbToTransfer, pReq);
+ }
+ AssertRC(rc);
+
+ rc = rtAioMgrReqsEnqueue(pThis, pFile, &pReq->hReqIo, 1);
+ AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES),
+ ("Unexpected return code rc=%Rrc\n", rc));
+ }
+ else if (pReq->enmType == RTAIOMGRREQTYPE_PREFETCH)
+ {
+ Assert(pReq->cbBounceBuffer);
+ pReq->enmType = RTAIOMGRREQTYPE_WRITE;
+
+ memcpy(((uint8_t *)pReq->pvBounceBuffer) + pReq->offBounceBuffer,
+ pReq->DataSeg.pvSeg,
+ pReq->DataSeg.cbSeg);
+
+ /* Write it now. */
+ RTFOFF offStart = pReq->off & ~(RTFOFF)(512-1);
+ size_t cbToTransfer = RT_ALIGN_Z(pReq->DataSeg.cbSeg + (pReq->off - offStart), 512);
+
+ rc = RTFileAioReqPrepareWrite(pReq->hReqIo, pFile->hFile,
+ offStart, pReq->pvBounceBuffer, cbToTransfer, pReq);
+ AssertRC(rc);
+ rc = rtAioMgrReqsEnqueue(pThis, pFile, &pReq->hReqIo, 1);
+ AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES),
+ ("Unexpected return code rc=%Rrc\n", rc));
+ }
+ else
+ {
+ if (RT_SUCCESS(rc) && pReq->cbBounceBuffer)
+ {
+ if (pReq->enmType == RTAIOMGRREQTYPE_READ)
+ memcpy(pReq->DataSeg.pvSeg,
+ ((uint8_t *)pReq->pvBounceBuffer) + pReq->offBounceBuffer,
+ pReq->DataSeg.cbSeg);
+ }
+
+ /* Call completion callback */
+ pFile->pfnReqCompleted(pFile, rcReq, pReq->pvUser);
+ rtAioMgrReqFree(pThis, pReq);
+ }
+ } /* request completed successfully */
+}
+
+/**
+ * Wrapper around rtAioMgrReqCompleteRc().
+ */
+static void rtAioMgrReqComplete(PRTAIOMGRINT pThis, RTFILEAIOREQ hReq)
+{
+ size_t cbTransfered = 0;
+ int rcReq = RTFileAioReqGetRC(hReq, &cbTransfered);
+ PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)RTFileAioReqGetUser(hReq);
+
+ rtAioMgrReqCompleteRc(pThis, pReq, rcReq, cbTransfered);
+}
+
+/**
+ * Wrapper around RTFIleAioCtxSubmit() which is also doing error handling.
+ */
+static int rtAioMgrReqsEnqueue(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile,
+ PRTFILEAIOREQ pahReqs, unsigned cReqs)
+{
+ pThis->cReqsActive += cReqs;
+ pFile->AioMgr.cReqsActive += cReqs;
+
+ int rc = RTFileAioCtxSubmit(pThis->hAioCtx, pahReqs, cReqs);
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES)
+ {
+ /* Append any not submitted task to the waiting list. */
+ for (size_t i = 0; i < cReqs; i++)
+ {
+ int rcReq = RTFileAioReqGetRC(pahReqs[i], NULL);
+
+ if (rcReq != VERR_FILE_AIO_IN_PROGRESS)
+ {
+ PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)RTFileAioReqGetUser(pahReqs[i]);
+
+ Assert(pReq->hReqIo == pahReqs[i]);
+ RTListAppend(&pFile->AioMgr.ListWaitingReqs, &pReq->NodeWaitingList);
+ pThis->cReqsActive--;
+ pFile->AioMgr.cReqsActive--;
+ }
+ }
+
+ pThis->cReqsActiveMax = pThis->cReqsActive;
+ rc = VINF_SUCCESS;
+ }
+ else /* Another kind of error happened (full disk, ...) */
+ {
+ /* An error happened. Find out which one caused the error and resubmit all other tasks. */
+ for (size_t i = 0; i < cReqs; i++)
+ {
+ PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)RTFileAioReqGetUser(pahReqs[i]);
+ int rcReq = RTFileAioReqGetRC(pahReqs[i], NULL);
+
+ if (rcReq == VERR_FILE_AIO_NOT_SUBMITTED)
+ {
+ /* We call ourself again to do any error handling which might come up now. */
+ rc = rtAioMgrReqsEnqueue(pThis, pFile, &pahReqs[i], 1);
+ AssertRC(rc);
+ }
+ else if (rcReq != VERR_FILE_AIO_IN_PROGRESS)
+ rtAioMgrReqCompleteRc(pThis, pReq, rcReq, 0);
+ }
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * Adds a list of requests to the waiting list.
+ *
+ * @returns nothing.
+ * @param pFile The file instance to add the requests to.
+ * @param pReqsHead The head of the request list to add.
+ */
+static void rtAioMgrFileAddReqsToWaitingList(PRTAIOMGRFILEINT pFile, PRTAIOMGRREQ pReqsHead)
+{
+ while (pReqsHead)
+ {
+ PRTAIOMGRREQ pReqCur = pReqsHead;
+
+ pReqsHead = (PRTAIOMGRREQ)pReqsHead->WorkItem.pNext;
+ pReqCur->WorkItem.pNext = NULL;
+ RTListAppend(&pFile->AioMgr.ListWaitingReqs, &pReqCur->NodeWaitingList);
+ }
+}
+
+/**
+ * Prepare the native I/o request ensuring that all alignment prerequisites of
+ * the host are met.
+ *
+ * @returns IPRT statuse code.
+ * @param pFile The file instance data.
+ * @param pReq The request to prepare.
+ */
+static int rtAioMgrReqPrepareNonBuffered(PRTAIOMGRFILEINT pFile, PRTAIOMGRREQ pReq)
+{
+ int rc = VINF_SUCCESS;
+ RTFOFF offStart = pReq->off & ~(RTFOFF)(512-1);
+ size_t cbToTransfer = RT_ALIGN_Z(pReq->DataSeg.cbSeg + (pReq->off - offStart), 512);
+ void *pvBuf = pReq->DataSeg.pvSeg;
+ bool fAlignedReq = cbToTransfer == pReq->DataSeg.cbSeg
+ && offStart == pReq->off;
+
+ /*
+ * Check if the alignment requirements are met.
+ * Offset, transfer size and buffer address
+ * need to be on a 512 boundary.
+ */
+ if ( !fAlignedReq
+ /** @todo: || ((pEpClassFile->uBitmaskAlignment & (RTR3UINTPTR)pvBuf) != (RTR3UINTPTR)pvBuf) */)
+ {
+ /* Create bounce buffer. */
+ pReq->cbBounceBuffer = cbToTransfer;
+
+ AssertMsg(pReq->off >= offStart, ("Overflow in calculation off=%llu offStart=%llu\n",
+ pReq->off, offStart));
+ pReq->offBounceBuffer = pReq->off - offStart;
+
+ /** @todo: I think we need something like a RTMemAllocAligned method here.
+ * Current assumption is that the maximum alignment is 4096byte
+ * (GPT disk on Windows)
+ * so we can use RTMemPageAlloc here.
+ */
+ pReq->pvBounceBuffer = RTMemPageAlloc(cbToTransfer);
+ if (RT_LIKELY(pReq->pvBounceBuffer))
+ {
+ pvBuf = pReq->pvBounceBuffer;
+
+ if (pReq->enmType == RTAIOMGRREQTYPE_WRITE)
+ {
+ if ( RT_UNLIKELY(cbToTransfer != pReq->DataSeg.cbSeg)
+ || RT_UNLIKELY(offStart != pReq->off))
+ {
+ /* We have to fill the buffer first before we can update the data. */
+ pReq->enmType = RTAIOMGRREQTYPE_WRITE;
+ }
+ else
+ memcpy(pvBuf, pReq->DataSeg.pvSeg, pReq->DataSeg.cbSeg);
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ pReq->cbBounceBuffer = 0;
+
+ if (RT_SUCCESS(rc))
+ {
+ if (pReq->enmType == RTAIOMGRREQTYPE_WRITE)
+ {
+ rc = RTFileAioReqPrepareWrite(pReq->hReqIo, pFile->hFile,
+ offStart, pvBuf, cbToTransfer, pReq);
+ }
+ else /* Read or prefetch request. */
+ rc = RTFileAioReqPrepareRead(pReq->hReqIo, pFile->hFile,
+ offStart, pvBuf, cbToTransfer, pReq);
+ AssertRC(rc);
+ pReq->fFlags |= RTAIOMGRREQ_FLAGS_PREPARED;
+ }
+
+ return rc;
+}
+
+/**
+ * Prepare a new request for enqueuing.
+ *
+ * @returns IPRT status code.
+ * @param pReq The request to prepare.
+ * @param phReqIo Where to store the handle to the native I/O request on success.
+ */
+static int rtAioMgrPrepareReq(PRTAIOMGRREQ pReq, PRTFILEAIOREQ phReqIo)
+{
+ int rc = VINF_SUCCESS;
+ PRTAIOMGRFILEINT pFile = pReq->pFile;
+
+ switch (pReq->enmType)
+ {
+ case RTAIOMGRREQTYPE_FLUSH:
+ {
+ rc = RTFileAioReqPrepareFlush(pReq->hReqIo, pFile->hFile, pReq);
+ break;
+ }
+ case RTAIOMGRREQTYPE_READ:
+ case RTAIOMGRREQTYPE_WRITE:
+ {
+ rc = rtAioMgrReqPrepareNonBuffered(pFile, pReq);
+ break;
+ }
+ default:
+ AssertMsgFailed(("Invalid transfer type %d\n", pReq->enmType));
+ } /* switch transfer type */
+
+ if (RT_SUCCESS(rc))
+ *phReqIo = pReq->hReqIo;
+
+ return rc;
+}
+
+/**
+ * Prepare newly submitted requests for processing.
+ *
+ * @returns IPRT status code
+ * @param pThis The async I/O manager instance data.
+ * @param pFile The file instance.
+ * @param pReqsNew The list of new requests to prepare.
+ */
+static int rtAioMgrPrepareNewReqs(PRTAIOMGRINT pThis,
+ PRTAIOMGRFILEINT pFile,
+ PRTAIOMGRREQ pReqsNew)
+{
+ RTFILEAIOREQ apReqs[20];
+ unsigned cRequests = 0;
+ int rc = VINF_SUCCESS;
+
+ /* Go through the list and queue the requests. */
+ while ( pReqsNew
+ && (pThis->cReqsActive + cRequests < pThis->cReqsActiveMax)
+ && RT_SUCCESS(rc))
+ {
+ PRTAIOMGRREQ pCurr = pReqsNew;
+ pReqsNew = (PRTAIOMGRREQ)pReqsNew->WorkItem.pNext;
+
+ pCurr->WorkItem.pNext = NULL;
+ AssertMsg(VALID_PTR(pCurr->pFile) && (pCurr->pFile == pFile),
+ ("Files do not match\n"));
+ AssertMsg(!(pCurr->fFlags & RTAIOMGRREQ_FLAGS_PREPARED),
+ ("Request on the new list is already prepared\n"));
+
+ rc = rtAioMgrPrepareReq(pCurr, &apReqs[cRequests]);
+ if (RT_FAILURE(rc))
+ rtAioMgrReqCompleteRc(pThis, pCurr, rc, 0);
+ else
+ cRequests++;
+
+ /* Queue the requests if the array is full. */
+ if (cRequests == RT_ELEMENTS(apReqs))
+ {
+ rc = rtAioMgrReqsEnqueue(pThis, pFile, apReqs, cRequests);
+ cRequests = 0;
+ AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES),
+ ("Unexpected return code\n"));
+ }
+ }
+
+ if (cRequests)
+ {
+ rc = rtAioMgrReqsEnqueue(pThis, pFile, apReqs, cRequests);
+ AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES),
+ ("Unexpected return code rc=%Rrc\n", rc));
+ }
+
+ if (pReqsNew)
+ {
+ /* Add the rest of the tasks to the pending list */
+ rtAioMgrFileAddReqsToWaitingList(pFile, pReqsNew);
+ }
+
+ /* Insufficient resources are not fatal. */
+ if (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES)
+ rc = VINF_SUCCESS;
+
+ return rc;
+}
+
+/**
+ * Queues waiting requests.
+ *
+ * @returns IPRT status code.
+ * @param pThis The async I/O manager instance data.
+ * @param pFile The file to get the requests from.
+ */
+static int rtAioMgrQueueWaitingReqs(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile)
+{
+ RTFILEAIOREQ apReqs[20];
+ unsigned cRequests = 0;
+ int rc = VINF_SUCCESS;
+ PRTAIOMGRREQ pReqIt;
+ PRTAIOMGRREQ pReqItNext;
+
+ /* Go through the list and queue the requests. */
+ RTListForEachSafe(&pFile->AioMgr.ListWaitingReqs, pReqIt, pReqItNext, RTAIOMGRREQ, NodeWaitingList)
+ {
+ RTListNodeRemove(&pReqIt->NodeWaitingList);
+ AssertMsg(VALID_PTR(pReqIt->pFile) && (pReqIt->pFile == pFile),
+ ("Files do not match\n"));
+
+ if (!(pReqIt->fFlags & RTAIOMGRREQ_FLAGS_PREPARED))
+ {
+ rc = rtAioMgrPrepareReq(pReqIt, &apReqs[cRequests]);
+ if (RT_FAILURE(rc))
+ rtAioMgrReqCompleteRc(pThis, pReqIt, rc, 0);
+ else
+ cRequests++;
+ }
+ else
+ {
+ apReqs[cRequests] = pReqIt->hReqIo;
+ cRequests++;
+ }
+
+ /* Queue the requests if the array is full. */
+ if (cRequests == RT_ELEMENTS(apReqs))
+ {
+ rc = rtAioMgrReqsEnqueue(pThis, pFile, apReqs, cRequests);
+ cRequests = 0;
+ AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES),
+ ("Unexpected return code\n"));
+ }
+ }
+
+ if (cRequests)
+ {
+ rc = rtAioMgrReqsEnqueue(pThis, pFile, apReqs, cRequests);
+ AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES),
+ ("Unexpected return code rc=%Rrc\n", rc));
+ }
+
+ /* Insufficient resources are not fatal. */
+ if (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES)
+ rc = VINF_SUCCESS;
+
+ return rc;
+}
+
+/**
+ * Adds all pending requests for the given file.
+ *
+ * @returns IPRT status code.
+ * @param pThis The async I/O manager instance data.
+ * @param pFile The file to get the requests from.
+ */
+static int rtAioMgrQueueReqs(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile)
+{
+ int rc = VINF_SUCCESS;
+ PRTAIOMGRFILEINT pReqsHead = NULL;
+
+ /* Check the pending list first */
+ if (!RTListIsEmpty(&pFile->AioMgr.ListWaitingReqs))
+ rc = rtAioMgrQueueWaitingReqs(pThis, pFile);
+
+ if ( RT_SUCCESS(rc)
+ && RTListIsEmpty(&pFile->AioMgr.ListWaitingReqs))
+ {
+ PRTAIOMGRREQ pReqsNew = (PRTAIOMGRREQ)RTQueueAtomicRemoveAll(&pFile->QueueReqs);
+
+ if (pReqsNew)
+ {
+ rc = rtAioMgrPrepareNewReqs(pThis, pFile, pReqsNew);
+ AssertRC(rc);
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * Checks all files for new requests.
+ *
+ * @returns IPRT status code.
+ * @param pThis The I/O manager instance data.
+ */
+static int rtAioMgrCheckFiles(PRTAIOMGRINT pThis)
+{
+ int rc = VINF_SUCCESS;
+ PRTAIOMGRFILEINT pIt;
+
+ RTListForEach(&pThis->ListFiles, pIt, RTAIOMGRFILEINT, AioMgr.NodeAioMgrFiles)
+ {
+ rc = rtAioMgrQueueReqs(pThis, pIt);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ return rc;
+}
+
+/**
+ * Process a blocking event from the outside.
+ *
+ * @returns IPRT status code.
+ * @param pThis The async I/O manager instance data.
+ */
+static int rtAioMgrProcessBlockingEvent(PRTAIOMGRINT pThis)
+{
+ int rc = VINF_SUCCESS;
+ bool fNotifyWaiter = false;
+
+ switch (pThis->enmBlockingEvent)
+ {
+ case RTAIOMGREVENT_NO_EVENT:
+ /* Nothing to do. */
+ break;
+ case RTAIOMGREVENT_FILE_ADD:
+ {
+ PRTAIOMGRFILEINT pFile = ASMAtomicReadPtrT(&pThis->BlockingEventData.pFileAdd, PRTAIOMGRFILEINT);
+ AssertMsg(VALID_PTR(pFile), ("Adding file event without a file to add\n"));
+
+ RTListAppend(&pThis->ListFiles, &pFile->AioMgr.NodeAioMgrFiles);
+ fNotifyWaiter = true;
+ break;
+ }
+ case RTAIOMGREVENT_FILE_CLOSE:
+ {
+ PRTAIOMGRFILEINT pFile = ASMAtomicReadPtrT(&pThis->BlockingEventData.pFileClose, PRTAIOMGRFILEINT);
+ AssertMsg(VALID_PTR(pFile), ("Close file event without a file to close\n"));
+
+ if (!(pFile->fFlags & RTAIOMGRFILE_FLAGS_CLOSING))
+ {
+ /* Make sure all requests finished. Process the queues a last time first. */
+ rc = rtAioMgrQueueReqs(pThis, pFile);
+ AssertRC(rc);
+
+ pFile->fFlags |= RTAIOMGRFILE_FLAGS_CLOSING;
+ fNotifyWaiter = !rtAioMgrFileRemove(pFile);
+ }
+ else if (!pFile->AioMgr.cReqsActive)
+ fNotifyWaiter = true;
+ break;
+ }
+ case RTAIOMGREVENT_SHUTDOWN:
+ {
+ if (!pThis->cReqsActive)
+ fNotifyWaiter = true;
+ break;
+ }
+ default:
+ AssertReleaseMsgFailed(("Invalid event type %d\n", pThis->enmBlockingEvent));
+ }
+
+ if (fNotifyWaiter)
+ {
+ /* Release the waiting thread. */
+ rc = RTSemEventSignal(pThis->hEventSemBlock);
+ AssertRC(rc);
+ }
+
+ return rc;
+}
+
+/**
+ * async I/O manager worker loop.
+ *
+ * @returns IPRT status code.
+ * @param hThreadSelf The thread handle this worker belongs to.
+ * @param pvUser Opaque user data (Pointer to async I/O manager instance).
+ */
+static DECLCALLBACK(int) rtAioMgrWorker(RTTHREAD hThreadSelf, void *pvUser)
+{
+ PRTAIOMGRINT pThis = (PRTAIOMGRINT)pvUser;
+ bool fRunning = true;
+ int rc = VINF_SUCCESS;
+
+ do
+ {
+ uint32_t cReqsCompleted = 0;
+ RTFILEAIOREQ ahReqsCompleted[32];
+ rc = RTFileAioCtxWait(pThis->hAioCtx, 1, RT_INDEFINITE_WAIT, &ahReqsCompleted[0],
+ RT_ELEMENTS(ahReqsCompleted), &cReqsCompleted);
+ if (rc == VERR_INTERRUPTED)
+ {
+ /* Process external event. */
+ rtAioMgrProcessBlockingEvent(pThis);
+ rc = rtAioMgrCheckFiles(pThis);
+ }
+ else if (RT_FAILURE(rc))
+ {
+ /* Something bad happened. */
+ /** @todo: */
+ }
+ else
+ {
+ /* Requests completed. */
+ for (uint32_t i = 0; i < cReqsCompleted; i++)
+ rtAioMgrReqComplete(pThis, ahReqsCompleted[i]);
+
+ /* Check files for new requests and queue waiting requests. */
+ rc = rtAioMgrCheckFiles(pThis);
+ }
+ } while ( fRunning
+ && RT_SUCCESS(rc));
+
+ return rc;
+}
+
+/**
+ * Wakes up the async I/O manager.
+ *
+ * @returns IPRT status code.
+ * @param pThis The async I/O manager.
+ */
+static int rtAioMgrWakeup(PRTAIOMGRINT pThis)
+{
+ return RTFileAioCtxWakeup(pThis->hAioCtx);
+}
+
+/**
+ * Waits until the async I/O manager handled the given event.
+ *
+ * @returns IPRT status code.
+ * @param pThis The async I/O manager.
+ * @param enmEvent The event to pass to the manager.
+ */
+static int rtAioMgrWaitForBlockingEvent(PRTAIOMGRINT pThis, RTAIOMGREVENT enmEvent)
+{
+ Assert(pThis->enmBlockingEvent == RTAIOMGREVENT_NO_EVENT);
+ ASMAtomicWriteU32((volatile uint32_t *)&pThis->enmBlockingEvent, enmEvent);
+
+ /* Wakeup the async I/O manager */
+ int rc = rtAioMgrWakeup(pThis);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Wait for completion. */
+ rc = RTSemEventWait(pThis->hEventSemBlock, RT_INDEFINITE_WAIT);
+ AssertRC(rc);
+
+ ASMAtomicWriteU32((volatile uint32_t *)&pThis->enmBlockingEvent, RTAIOMGREVENT_NO_EVENT);
+
+ return rc;
+}
+
+/**
+ * Add a given file to the given I/O manager.
+ *
+ * @returns IPRT status code.
+ * @param pThis The async I/O manager.
+ * @param pFile The file to add.
+ */
+static int rtAioMgrAddFile(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile)
+{
+ /* Update the assigned I/O manager. */
+ ASMAtomicWritePtr(&pFile->pAioMgr, pThis);
+
+ int rc = RTCritSectEnter(&pThis->CritSectBlockingEvent);
+ AssertRCReturn(rc, rc);
+
+ ASMAtomicWritePtr(&pThis->BlockingEventData.pFileAdd, pFile);
+ rc = rtAioMgrWaitForBlockingEvent(pThis, RTAIOMGREVENT_FILE_ADD);
+ ASMAtomicWriteNullPtr(&pThis->BlockingEventData.pFileAdd);
+
+ RTCritSectLeave(&pThis->CritSectBlockingEvent);
+ return rc;
+}
+
+/**
+ * Removes a given file from the given I/O manager.
+ *
+ * @returns IPRT status code.
+ * @param pThis The async I/O manager.
+ * @param pFile The file to remove.
+ */
+static int rtAioMgrCloseFile(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile)
+{
+ int rc = RTCritSectEnter(&pThis->CritSectBlockingEvent);
+ AssertRCReturn(rc, rc);
+
+ ASMAtomicWritePtr(&pThis->BlockingEventData.pFileClose, pFile);
+ rc = rtAioMgrWaitForBlockingEvent(pThis, RTAIOMGREVENT_FILE_CLOSE);
+ ASMAtomicWriteNullPtr(&pThis->BlockingEventData.pFileClose);
+
+ RTCritSectLeave(&pThis->CritSectBlockingEvent);
+
+ return rc;
+}
+
+/**
+ * Process a shutdown event.
+ *
+ * @returns IPRT status code.
+ * @param pThis The async I/O manager to shut down.
+ */
+static int rtAioMgrShutdown(PRTAIOMGRINT pThis)
+{
+ int rc = RTCritSectEnter(&pThis->CritSectBlockingEvent);
+ AssertRCReturn(rc, rc);
+
+ rc = rtAioMgrWaitForBlockingEvent(pThis, RTAIOMGREVENT_SHUTDOWN);
+ RTCritSectLeave(&pThis->CritSectBlockingEvent);
+
+ return rc;
+}
+
+/**
+ * Destroys an async I/O manager.
+ *
+ * @returns nothing.
+ * @param pThis The async I/O manager instance to destroy.
+ */
+static void rtAioMgrDestroy(PRTAIOMGRINT pThis)
+{
+ int rc;
+
+ rc = rtAioMgrShutdown(pThis);
+ AssertRC(rc);
+
+ rc = RTThreadWait(pThis->hThread, RT_INDEFINITE_WAIT, NULL);
+ AssertRC(rc);
+
+ rc = RTFileAioCtxDestroy(pThis->hAioCtx);
+ AssertRC(rc);
+
+ rc = RTMemCacheDestroy(pThis->hMemCacheReqs);
+ AssertRC(rc);
+
+ pThis->hThread = NIL_RTTHREAD;
+ pThis->hAioCtx = NIL_RTFILEAIOCTX;
+ pThis->hMemCacheReqs = NIL_RTMEMCACHE;
+ pThis->u32Magic = ~RTAIOMGR_MAGIC;
+ RTCritSectDelete(&pThis->CritSectBlockingEvent);
+ RTSemEventDestroy(pThis->hEventSemBlock);
+ RTMemFree(pThis);
+}
+
+/**
+ * Queues a new request for processing.
+ */
+static void rtAioMgrFileQueueReq(PRTAIOMGRFILEINT pThis, PRTAIOMGRREQ pReq)
+{
+ RTAioMgrFileRetain(pThis);
+ RTQueueAtomicInsert(&pThis->QueueReqs, &pReq->WorkItem);
+ rtAioMgrWakeup(pThis->pAioMgr);
+}
+
+/**
+ * Destroys an async I/O manager file.
+ *
+ * @returns nothing.
+ * @param pThis The async I/O manager file.
+ */
+static void rtAioMgrFileDestroy(PRTAIOMGRFILEINT pThis)
+{
+ pThis->u32Magic = ~RTAIOMGRFILE_MAGIC;
+ rtAioMgrCloseFile(pThis->pAioMgr, pThis);
+ RTAioMgrRelease(pThis->pAioMgr);
+ RTMemFree(pThis);
+}
+
+/**
+ * Queues a new I/O request.
+ *
+ * @returns IPRT status code.
+ * @param hAioMgrFile The I/O manager file handle.
+ * @param off Start offset of the I/o request.
+ * @param pSgBuf Data S/G buffer.
+ * @param cbIo How much to transfer.
+ * @param pvUser Opaque user data.
+ * @param enmType I/O direction type (read/write).
+ */
+static int rtAioMgrFileIoReqCreate(RTAIOMGRFILE hAioMgrFile, RTFOFF off, PRTSGBUF pSgBuf,
+ size_t cbIo, void *pvUser, RTAIOMGRREQTYPE enmType)
+{
+ int rc;
+ PRTAIOMGRFILEINT pFile = hAioMgrFile;
+ PRTAIOMGRINT pAioMgr;
+
+ AssertPtrReturn(pFile, VERR_INVALID_HANDLE);
+ pAioMgr = pFile->pAioMgr;
+
+ PRTAIOMGRREQ pReq = rtAioMgrReqAlloc(pAioMgr);
+ if (RT_LIKELY(pReq))
+ {
+ unsigned cSeg = 1;
+ size_t cbSeg = RTSgBufSegArrayCreate(pSgBuf, &pReq->DataSeg, &cSeg, cbIo);
+
+ if (cbSeg == cbIo)
+ {
+ pReq->enmType = enmType;
+ pReq->pFile = pFile;
+ pReq->pvUser = pvUser;
+ pReq->off = off;
+ rtAioMgrFileQueueReq(pFile, pReq);
+ rc = VERR_FILE_AIO_IN_PROGRESS;
+ }
+ else
+ {
+ /** @todo: Real S/G buffer support. */
+ rtAioMgrReqFree(pAioMgr, pReq);
+ rc = VERR_NOT_SUPPORTED;
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ return rc;
+}
+
+/**
+ * Request constructor for the memory cache.
+ *
+ * @returns IPRT status code.
+ * @param hMemCache The cache handle.
+ * @param pvObj The memory object that should be initialized.
+ * @param pvUser The user argument.
+ */
+static DECLCALLBACK(int) rtAioMgrReqCtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)
+{
+ PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)pvObj;
+
+ memset(pReq, 0, sizeof(RTAIOMGRREQ));
+ return RTFileAioReqCreate(&pReq->hReqIo);
+}
+
+/**
+ * Request destructor for the memory cache.
+ *
+ * @param hMemCache The cache handle.
+ * @param pvObj The memory object that should be destroyed.
+ * @param pvUser The user argument.
+ */
+static DECLCALLBACK(void) rtAioMgrReqDtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)
+{
+ PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)pvObj;
+ int rc = RTFileAioReqDestroy(pReq->hReqIo);
+
+ AssertRC(rc);
+}
+
+RTDECL(int) RTAioMgrCreate(PRTAIOMGR phAioMgr, uint32_t cReqsMax)
+{
+ int rc = VINF_SUCCESS;
+ PRTAIOMGRINT pThis;
+
+ AssertPtrReturn(phAioMgr, VERR_INVALID_POINTER);
+ AssertReturn(cReqsMax > 0, VERR_INVALID_PARAMETER);
+
+ pThis = (PRTAIOMGRINT)RTMemAllocZ(sizeof(RTAIOMGRINT));
+ if (pThis)
+ {
+ pThis->u32Magic = RTAIOMGR_MAGIC;
+ pThis->cRefs = 1;
+ pThis->enmBlockingEvent = RTAIOMGREVENT_NO_EVENT;
+ RTListInit(&pThis->ListFiles);
+ rc = RTCritSectInit(&pThis->CritSectBlockingEvent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventCreate(&pThis->hEventSemBlock);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTMemCacheCreate(&pThis->hMemCacheReqs, sizeof(RTAIOMGRREQ),
+ 0, UINT32_MAX, rtAioMgrReqCtor, rtAioMgrReqDtor, NULL, 0);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTFileAioCtxCreate(&pThis->hAioCtx, cReqsMax == UINT32_MAX
+ ? RTFILEAIO_UNLIMITED_REQS
+ : cReqsMax,
+ RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTThreadCreateF(&pThis->hThread, rtAioMgrWorker, pThis, 0, RTTHREADTYPE_IO,
+ RTTHREADFLAGS_WAITABLE, "AioMgr-%u", cReqsMax);
+ if (RT_FAILURE(rc))
+ {
+ rc = RTFileAioCtxDestroy(pThis->hAioCtx);
+ AssertRC(rc);
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ RTMemCacheDestroy(pThis->hMemCacheReqs);
+ }
+
+ if (RT_FAILURE(rc))
+ RTSemEventDestroy(pThis->hEventSemBlock);
+ }
+
+ if (RT_FAILURE(rc))
+ RTCritSectDelete(&pThis->CritSectBlockingEvent);
+ }
+
+ if (RT_FAILURE(rc))
+ RTMemFree(pThis);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ if (RT_SUCCESS(rc))
+ *phAioMgr = pThis;
+
+ return rc;
+}
+
+RTDECL(uint32_t) RTAioMgrRetain(RTAIOMGR hAioMgr)
+{
+ PRTAIOMGRINT pThis = hAioMgr;
+ AssertReturn(hAioMgr != NIL_RTAIOMGR, UINT32_MAX);
+ AssertPtrReturn(pThis, UINT32_MAX);
+ AssertReturn(pThis->u32Magic == RTAIOMGR_MAGIC, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ AssertMsg(cRefs > 1 && cRefs < _1G, ("%#x %p\n", cRefs, pThis));
+ return cRefs;
+}
+
+RTDECL(uint32_t) RTAioMgrRelease(RTAIOMGR hAioMgr)
+{
+ PRTAIOMGRINT pThis = hAioMgr;
+ if (pThis == NIL_RTAIOMGR)
+ return 0;
+ AssertPtrReturn(pThis, UINT32_MAX);
+ AssertReturn(pThis->u32Magic == RTAIOMGR_MAGIC, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+ AssertMsg(cRefs < _1G, ("%#x %p\n", cRefs, pThis));
+ if (cRefs == 0)
+ rtAioMgrDestroy(pThis);
+ return cRefs;
+}
+
+RTDECL(int) RTAioMgrFileCreate(RTAIOMGR hAioMgr, RTFILE hFile, PFNRTAIOMGRREQCOMPLETE pfnReqComplete,
+ void *pvUser, PRTAIOMGRFILE phAioMgrFile)
+{
+ int rc = VINF_SUCCESS;
+ PRTAIOMGRFILEINT pThis;
+
+ AssertReturn(hAioMgr != NIL_RTAIOMGR, VERR_INVALID_HANDLE);
+ AssertReturn(hFile != NIL_RTFILE, VERR_INVALID_HANDLE);
+ AssertPtrReturn(pfnReqComplete, VERR_INVALID_POINTER);
+ AssertPtrReturn(phAioMgrFile, VERR_INVALID_POINTER);
+
+ pThis = (PRTAIOMGRFILEINT)RTMemAllocZ(sizeof(RTAIOMGRFILEINT));
+ if (pThis)
+ {
+ pThis->u32Magic = RTAIOMGRFILE_MAGIC;
+ pThis->cRefs = 1;
+ pThis->hFile = hFile;
+ pThis->pAioMgr = hAioMgr;
+ pThis->pvUser = pvUser;
+ pThis->pfnReqCompleted = pfnReqComplete;
+ RTQueueAtomicInit(&pThis->QueueReqs);
+ RTListInit(&pThis->AioMgr.ListWaitingReqs);
+ RTAioMgrRetain(hAioMgr);
+ rc = RTFileAioCtxAssociateWithFile(pThis->pAioMgr->hAioCtx, hFile);
+ if (RT_FAILURE(rc))
+ rtAioMgrFileDestroy(pThis);
+ else
+ rtAioMgrAddFile(pThis->pAioMgr, pThis);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ if (RT_SUCCESS(rc))
+ *phAioMgrFile = pThis;
+
+ return rc;
+}
+
+RTDECL(uint32_t) RTAioMgrFileRetain(RTAIOMGRFILE hAioMgrFile)
+{
+ PRTAIOMGRFILEINT pThis = hAioMgrFile;
+ AssertReturn(hAioMgrFile != NIL_RTAIOMGRFILE, UINT32_MAX);
+ AssertPtrReturn(pThis, UINT32_MAX);
+ AssertReturn(pThis->u32Magic == RTAIOMGRFILE_MAGIC, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ AssertMsg(cRefs > 1 && cRefs < _1G, ("%#x %p\n", cRefs, pThis));
+ return cRefs;
+}
+
+RTDECL(uint32_t) RTAioMgrFileRelease(RTAIOMGRFILE hAioMgrFile)
+{
+ PRTAIOMGRFILEINT pThis = hAioMgrFile;
+ if (pThis == NIL_RTAIOMGRFILE)
+ return 0;
+ AssertPtrReturn(pThis, UINT32_MAX);
+ AssertReturn(pThis->u32Magic == RTAIOMGRFILE_MAGIC, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+ AssertMsg(cRefs < _1G, ("%#x %p\n", cRefs, pThis));
+ if (cRefs == 0)
+ rtAioMgrFileDestroy(pThis);
+ return cRefs;
+}
+
+RTDECL(void *) RTAioMgrFileGetUser(RTAIOMGRFILE hAioMgrFile)
+{
+ PRTAIOMGRFILEINT pThis = hAioMgrFile;
+
+ AssertPtrReturn(pThis, NULL);
+ return pThis->pvUser;
+}
+
+RTDECL(int) RTAioMgrFileRead(RTAIOMGRFILE hAioMgrFile, RTFOFF off,
+ PRTSGBUF pSgBuf, size_t cbRead, void *pvUser)
+{
+ return rtAioMgrFileIoReqCreate(hAioMgrFile, off, pSgBuf, cbRead, pvUser,
+ RTAIOMGRREQTYPE_READ);
+}
+
+RTDECL(int) RTAioMgrFileWrite(RTAIOMGRFILE hAioMgrFile, RTFOFF off,
+ PRTSGBUF pSgBuf, size_t cbWrite, void *pvUser)
+{
+ return rtAioMgrFileIoReqCreate(hAioMgrFile, off, pSgBuf, cbWrite, pvUser,
+ RTAIOMGRREQTYPE_WRITE);
+}
+
+RTDECL(int) RTAioMgrFileFlush(RTAIOMGRFILE hAioMgrFile, void *pvUser)
+{
+ PRTAIOMGRFILEINT pFile = hAioMgrFile;
+ PRTAIOMGRINT pAioMgr;
+
+ AssertPtrReturn(pFile, VERR_INVALID_HANDLE);
+
+ pAioMgr = pFile->pAioMgr;
+
+ PRTAIOMGRREQ pReq = rtAioMgrReqAlloc(pAioMgr);
+ if (RT_UNLIKELY(!pReq))
+ return VERR_NO_MEMORY;
+
+ pReq->pFile = pFile;
+ pReq->enmType = RTAIOMGRREQTYPE_FLUSH;
+ pReq->pvUser = pvUser;
+ rtAioMgrFileQueueReq(pFile, pReq);
+
+ return VERR_FILE_AIO_IN_PROGRESS;
+}
+
diff --git a/src/VBox/Runtime/common/misc/assert.cpp b/src/VBox/Runtime/common/misc/assert.cpp
index d69a12b4..991fa0be 100644
--- a/src/VBox/Runtime/common/misc/assert.cpp
+++ b/src/VBox/Runtime/common/misc/assert.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -137,10 +137,12 @@ RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFi
#else /* !IN_RING0 */
# if !defined(IN_RING3) && !defined(LOG_NO_COM)
+# if 0 /* Enable this iff you have a COM port and really want this debug info. */
RTLogComPrintf("\n!!Assertion Failed!!\n"
"Expression: %s\n"
"Location : %s(%d) %s\n",
pszExpr, pszFile, uLine, pszFunction);
+# endif
# endif
PRTLOGGER pLog = RTLogRelDefaultInstance();
@@ -245,9 +247,11 @@ static void rtAssertMsg2Worker(bool fInitial, const char *pszFormat, va_list va)
#else /* !IN_RING0 */
# if !defined(IN_RING3) && !defined(LOG_NO_COM)
+# if 0 /* Enable this iff you have a COM port and really want this debug info. */
va_copy(vaCopy, va);
RTLogComPrintfV(pszFormat, vaCopy);
va_end(vaCopy);
+# endif
# endif
PRTLOGGER pLog = RTLogRelDefaultInstance();
diff --git a/src/VBox/Runtime/common/misc/buildconfig.cpp b/src/VBox/Runtime/common/misc/buildconfig.cpp
index 54e87b39..3509a949 100644
--- a/src/VBox/Runtime/common/misc/buildconfig.cpp
+++ b/src/VBox/Runtime/common/misc/buildconfig.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/cidr.cpp b/src/VBox/Runtime/common/misc/cidr.cpp
index d64d8e43..802fc01e 100644
--- a/src/VBox/Runtime/common/misc/cidr.cpp
+++ b/src/VBox/Runtime/common/misc/cidr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -37,7 +37,7 @@
#include <iprt/stream.h>
-RTDECL(int) RTCidrStrToIPv4(const char *pszAddress, PRTIPV4ADDR pNetwork, PRTIPV4ADDR pNetmask)
+RTDECL(int) RTCidrStrToIPv4(const char *pszAddress, PRTNETADDRIPV4 pNetwork, PRTNETADDRIPV4 pNetmask)
{
uint8_t cBits;
uint8_t addr[4];
@@ -110,8 +110,8 @@ RTDECL(int) RTCidrStrToIPv4(const char *pszAddress, PRTIPV4ADDR pNetwork, PRTIPV
if ((u32Network & ~u32Netmask) != 0)
return VERR_INVALID_PARAMETER;
- *pNetmask = u32Netmask;
- *pNetwork = u32Network;
+ pNetmask->u = u32Netmask;
+ pNetwork->u = u32Network;
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTCidrStrToIPv4);
diff --git a/src/VBox/Runtime/common/misc/getopt.cpp b/src/VBox/Runtime/common/misc/getopt.cpp
index f4321404..cf538f20 100644
--- a/src/VBox/Runtime/common/misc/getopt.cpp
+++ b/src/VBox/Runtime/common/misc/getopt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2011 Oracle Corporation
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -27,6 +27,7 @@
/*******************************************************************************
* Header Files *
*******************************************************************************/
+#include <iprt/cidr.h>
#include <iprt/net.h> /* must come before getopt.h */
#include <iprt/getopt.h>
#include "internal/iprt.h"
@@ -92,8 +93,6 @@ RT_EXPORT_SYMBOL(RTGetOptInit);
/**
* Converts an stringified IPv4 address into the RTNETADDRIPV4 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.
*
@@ -102,32 +101,8 @@ RT_EXPORT_SYMBOL(RTGetOptInit);
*/
static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr)
{
- char *pszNext;
- int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 10, &pAddr->au8[0]);
- if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
- if (*pszNext++ != '.')
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
-
- rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[1]);
- if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
- if (*pszNext++ != '.')
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
-
- rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[2]);
- if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
- if (*pszNext++ != '.')
+ if (RT_FAILURE(RTNetStrToIPv4Addr(pszValue, pAddr)))
return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
-
- rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[3]);
- if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
- pszNext = RTStrStripL(pszNext);
- if (*pszNext)
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
-
return VINF_SUCCESS;
}
@@ -135,8 +110,6 @@ static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr)
/**
* 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.
*
@@ -145,42 +118,9 @@ static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr)
*/
static int rtgetoptConvertMacAddr(const char *pszValue, PRTMAC pAddr)
{
- /*
- * Not quite sure if I should accept stuff like "08::27:::1" here...
- * The code is accepting "::" patterns now, except for for the first
- * and last parts.
- */
- /* first */
- char *pszNext;
- int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 16, &pAddr->au8[0]);
- if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
- if (*pszNext++ != ':')
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
-
- /* middle */
- for (unsigned i = 1; i < 5; i++)
- {
- if (*pszNext == ':')
- pAddr->au8[i] = 0;
- else
- {
- rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[i]);
- if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
- if (*pszNext != ':')
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
- }
- pszNext++;
- }
-
- /* last */
- rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[5]);
- if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
- return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
- pszNext = RTStrStripL(pszNext);
- if (*pszNext)
+ int rc = RTNetStrToMacAddr(pszValue, pAddr);
+ if (RT_FAILURE(rc))
return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
return VINF_SUCCESS;
@@ -257,7 +197,7 @@ static PCRTGETOPTDEF rtGetOptSearchLong(const char *pszOption, PCRTGETOPTDEF paO
if (!(fFlags & RTGETOPTINIT_FLAGS_NO_STD_OPTS))
for (uint32_t i = 0; i < RT_ELEMENTS(g_aStdOptions); i++)
if ( !strcmp(pszOption, g_aStdOptions[i].pszLong)
- || ( pOpt->fFlags & RTGETOPT_FLAG_ICASE
+ || ( g_aStdOptions[i].fFlags & RTGETOPT_FLAG_ICASE
&& !RTStrICmp(pszOption, g_aStdOptions[i].pszLong)))
return &g_aStdOptions[i];
@@ -435,8 +375,17 @@ static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPT
pValueUnion->IPv4Addr = Addr;
break;
}
-#if 0 /** @todo CIDR */
-#endif
+
+ case RTGETOPT_REQ_IPV4CIDR:
+ {
+ RTNETADDRIPV4 network;
+ RTNETADDRIPV4 netmask;
+ if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask)))
+ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
+ pValueUnion->CidrIPv4.IPv4Network.u = network.u;
+ pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u;
+ break;
+ }
case RTGETOPT_REQ_MACADDR:
{
@@ -791,8 +740,8 @@ RTDECL(RTEXITCODE) RTGetOptPrintError(int ch, PCRTGETOPTUNION pValueUnion)
else if (ch == VERR_GETOPT_UNKNOWN_OPTION)
RTMsgError("Unknown option: '%s'", pValueUnion->psz);
else if (ch == VERR_GETOPT_INVALID_ARGUMENT_FORMAT)
- /** @todo r=klaus not really ideal, as the option isn't available */
- RTMsgError("Invalid argument format: '%s'", pValueUnion->psz);
+ /** @todo r=klaus not really ideal, as the value isn't available */
+ RTMsgError("The value given '%s' has an invalid format.", pValueUnion->pDef->pszLong);
else if (pValueUnion->pDef)
RTMsgError("%s: %Rrs\n", pValueUnion->pDef->pszLong, ch);
else
diff --git a/src/VBox/Runtime/common/misc/getoptargv.cpp b/src/VBox/Runtime/common/misc/getoptargv.cpp
index 651b6f43..8f749e17 100644
--- a/src/VBox/Runtime/common/misc/getoptargv.cpp
+++ b/src/VBox/Runtime/common/misc/getoptargv.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/handletable.cpp b/src/VBox/Runtime/common/misc/handletable.cpp
index 80eb2387..375e79db 100644
--- a/src/VBox/Runtime/common/misc/handletable.cpp
+++ b/src/VBox/Runtime/common/misc/handletable.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -57,6 +57,8 @@ RTDECL(int) RTHandleTableCreateEx(PRTHANDLETABLE phHandleTable, uint32_t fFlags,
*phHandleTable = NIL_RTHANDLETABLE;
AssertPtrNullReturn(pfnRetain, VERR_INVALID_POINTER);
AssertReturn(!(fFlags & ~RTHANDLETABLE_FLAGS_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(RT_BOOL(fFlags & RTHANDLETABLE_FLAGS_LOCKED) + RT_BOOL(fFlags & RTHANDLETABLE_FLAGS_LOCKED_IRQ_SAFE) < 2,
+ VERR_INVALID_PARAMETER);
AssertReturn(cMax > 0, VERR_INVALID_PARAMETER);
AssertReturn(UINT32_MAX - cMax >= uBase, VERR_INVALID_PARAMETER);
@@ -100,9 +102,13 @@ RTDECL(int) RTHandleTableCreateEx(PRTHANDLETABLE phHandleTable, uint32_t fFlags,
pThis->cLevel1 = cLevel1 < RTHT_LEVEL1_DYN_ALLOC_THRESHOLD ? cLevel1 : 0;
pThis->iFreeHead = NIL_RTHT_INDEX;
pThis->iFreeTail = NIL_RTHT_INDEX;
- if (fFlags & RTHANDLETABLE_FLAGS_LOCKED)
+ if (fFlags & (RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_LOCKED_IRQ_SAFE))
{
- int rc = RTSpinlockCreate(&pThis->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "RTHandleTableCreateEx");
+ int rc;
+ if (fFlags & RTHANDLETABLE_FLAGS_LOCKED_IRQ_SAFE)
+ rc = RTSpinlockCreate(&pThis->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTHandleTableCreateEx");
+ else
+ rc = RTSpinlockCreate(&pThis->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "RTHandleTableCreateEx");
if (RT_FAILURE(rc))
{
RTMemFree(pThis);
diff --git a/src/VBox/Runtime/common/misc/handletable.h b/src/VBox/Runtime/common/misc/handletable.h
index 65448397..6e76463a 100644
--- a/src/VBox/Runtime/common/misc/handletable.h
+++ b/src/VBox/Runtime/common/misc/handletable.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -222,9 +222,7 @@ DECLINLINE(PRTHTENTRYCTX) rtHandleTableLookupWithCtx(PRTHANDLETABLEINT pThis, ui
DECLINLINE(void) rtHandleTableLock(PRTHANDLETABLEINT pThis)
{
if (pThis->hSpinlock != NIL_RTSPINLOCK)
- {
RTSpinlockAcquire(pThis->hSpinlock);
- }
}
diff --git a/src/VBox/Runtime/common/misc/handletablectx.cpp b/src/VBox/Runtime/common/misc/handletablectx.cpp
index 9da5b144..b4d5bfcd 100644
--- a/src/VBox/Runtime/common/misc/handletablectx.cpp
+++ b/src/VBox/Runtime/common/misc/handletablectx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/handletablesimple.cpp b/src/VBox/Runtime/common/misc/handletablesimple.cpp
index 36f2a8fc..2969dacc 100644
--- a/src/VBox/Runtime/common/misc/handletablesimple.cpp
+++ b/src/VBox/Runtime/common/misc/handletablesimple.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/http.cpp b/src/VBox/Runtime/common/misc/http.cpp
new file mode 100644
index 00000000..52baa39e
--- /dev/null
+++ b/src/VBox/Runtime/common/misc/http.cpp
@@ -0,0 +1,550 @@
+/* $Id: http.cpp $ */
+/** @file
+ * IPRT - HTTP communication API.
+ */
+
+/*
+ * Copyright (C) 2012-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/http.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/env.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/file.h>
+#include <iprt/stream.h>
+
+#include <curl/curl.h>
+#include <openssl/ssl.h>
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+typedef struct RTHTTPINTERNAL
+{
+ /** magic value */
+ uint32_t u32Magic;
+ /** cURL handle */
+ CURL *pCurl;
+ long lLastResp;
+ /** custom headers */
+ struct curl_slist *pHeaders;
+ /** CA certificate for HTTPS authentication check */
+ char *pcszCAFile;
+ /** abort the current HTTP request if true */
+ bool fAbort;
+} RTHTTPINTERNAL;
+typedef RTHTTPINTERNAL *PRTHTTPINTERNAL;
+
+typedef struct RTHTTPMEMCHUNK
+{
+ char *pszMem;
+ size_t cb;
+} RTHTTPMEMCHUNK;
+typedef RTHTTPMEMCHUNK *PRTHTTPMEMCHUNK;
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+#define CURL_FAILED(rcCurl) (RT_UNLIKELY(rcCurl != CURLE_OK))
+
+/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
+#define RTHTTP_VALID_RETURN_RC(hHttp, rcCurl) \
+ do { \
+ AssertPtrReturn((hHttp), (rcCurl)); \
+ AssertReturn((hHttp)->u32Magic == RTHTTP_MAGIC, (rcCurl)); \
+ } while (0)
+
+/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
+#define RTHTTP_VALID_RETURN(hHTTP) RTHTTP_VALID_RETURN_RC((hHttp), VERR_INVALID_HANDLE)
+
+/** Validates a handle and returns (void) if not valid. */
+#define RTHTTP_VALID_RETURN_VOID(hHttp) \
+ do { \
+ AssertPtrReturnVoid(hHttp); \
+ AssertReturnVoid((hHttp)->u32Magic == RTHTTP_MAGIC); \
+ } while (0)
+
+
+RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp)
+{
+ AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER);
+
+ CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL);
+ if (CURL_FAILED(rcCurl))
+ return VERR_HTTP_INIT_FAILED;
+
+ CURL *pCurl = curl_easy_init();
+ if (!pCurl)
+ return VERR_HTTP_INIT_FAILED;
+
+ PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
+ if (!pHttpInt)
+ return VERR_NO_MEMORY;
+
+ pHttpInt->u32Magic = RTHTTP_MAGIC;
+ pHttpInt->pCurl = pCurl;
+
+ *phHttp = (RTHTTP)pHttpInt;
+
+ return VINF_SUCCESS;
+}
+
+RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
+{
+ if (!hHttp)
+ return;
+
+ PRTHTTPINTERNAL pHttpInt = hHttp;
+ RTHTTP_VALID_RETURN_VOID(pHttpInt);
+
+ pHttpInt->u32Magic = RTHTTP_MAGIC_DEAD;
+
+ curl_easy_cleanup(pHttpInt->pCurl);
+
+ if (pHttpInt->pHeaders)
+ curl_slist_free_all(pHttpInt->pHeaders);
+
+ if (pHttpInt->pcszCAFile)
+ RTStrFree(pHttpInt->pcszCAFile);
+
+ RTMemFree(pHttpInt);
+
+ curl_global_cleanup();
+}
+
+static DECLCALLBACK(size_t) rtHttpWriteData(void *pvBuf, size_t cb, size_t n, void *pvUser)
+{
+ PRTHTTPMEMCHUNK pMem = (PRTHTTPMEMCHUNK)pvUser;
+ size_t cbAll = cb * n;
+
+ pMem->pszMem = (char*)RTMemRealloc(pMem->pszMem, pMem->cb + cbAll + 1);
+ if (pMem->pszMem)
+ {
+ memcpy(&pMem->pszMem[pMem->cb], pvBuf, cbAll);
+ pMem->cb += cbAll;
+ pMem->pszMem[pMem->cb] = '\0';
+ }
+ return cbAll;
+}
+
+static DECLCALLBACK(int) rtHttpProgress(void *pData, double DlTotal, double DlNow,
+ double UlTotal, double UlNow)
+{
+ PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)pData;
+ AssertReturn(pHttpInt->u32Magic == RTHTTP_MAGIC, 1);
+
+ return pHttpInt->fAbort ? 1 : 0;
+}
+
+RTR3DECL(int) RTHttpAbort(RTHTTP hHttp)
+{
+ PRTHTTPINTERNAL pHttpInt = hHttp;
+ RTHTTP_VALID_RETURN(pHttpInt);
+
+ pHttpInt->fAbort = true;
+
+ return VINF_SUCCESS;
+}
+
+RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp)
+{
+ PRTHTTPINTERNAL pHttpInt = hHttp;
+ RTHTTP_VALID_RETURN(pHttpInt);
+
+ /*
+ * Very limited right now, just enought to make it work for ourselves.
+ */
+ char szProxy[_1K];
+ int rc = RTEnvGetEx(RTENV_DEFAULT, "http_proxy", szProxy, sizeof(szProxy), NULL);
+ if (RT_SUCCESS(rc))
+ {
+ int rcCurl;
+ if (!strncmp(szProxy, RT_STR_TUPLE("http://")))
+ {
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, 80);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+ }
+ }
+ else if (rc == VERR_ENV_VAR_NOT_FOUND)
+ rc = VINF_SUCCESS;
+
+ return rc;
+}
+
+RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxy, uint32_t uPort,
+ const char *pcszProxyUser, const char *pcszProxyPwd)
+{
+ PRTHTTPINTERNAL pHttpInt = hHttp;
+ RTHTTP_VALID_RETURN(pHttpInt);
+ AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER);
+
+ int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, pcszProxy);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+
+ if (uPort != 0)
+ {
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, (long)uPort);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (pcszProxyUser && pcszProxyPwd)
+ {
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+ }
+
+ return VINF_SUCCESS;
+}
+
+RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders)
+{
+ PRTHTTPINTERNAL pHttpInt = hHttp;
+ RTHTTP_VALID_RETURN(pHttpInt);
+
+ if (!cHeaders)
+ {
+ if (pHttpInt->pHeaders)
+ curl_slist_free_all(pHttpInt->pHeaders);
+ pHttpInt->pHeaders = 0;
+ return VINF_SUCCESS;
+ }
+
+ struct curl_slist *pHeaders = NULL;
+ for (size_t i = 0; i < cHeaders; i++)
+ pHeaders = curl_slist_append(pHeaders, papszHeaders[i]);
+
+ pHttpInt->pHeaders = pHeaders;
+ int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_HTTPHEADER, pHeaders);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+
+ return VINF_SUCCESS;
+}
+
+RTR3DECL(int) RTHttpCertDigest(RTHTTP hHttp, char *pcszCert, size_t cbCert,
+ uint8_t **pabSha1, size_t *pcbSha1,
+ uint8_t **pabSha512, size_t *pcbSha512)
+{
+ int rc = VINF_SUCCESS;
+
+ BIO *cert = BIO_new_mem_buf(pcszCert, (int)cbCert);
+ if (cert)
+ {
+ X509 *crt = NULL;
+ if (PEM_read_bio_X509(cert, &crt, NULL, NULL))
+ {
+ unsigned cb;
+ unsigned char md[EVP_MAX_MD_SIZE];
+
+ int rc1 = X509_digest(crt, EVP_sha1(), md, &cb);
+ if (rc1 > 0)
+ {
+ *pabSha1 = (uint8_t*)RTMemAlloc(cb);
+ if (*pabSha1)
+ {
+ memcpy(*pabSha1, md, cb);
+ *pcbSha1 = cb;
+
+ rc1 = X509_digest(crt, EVP_sha512(), md, &cb);
+ if (rc1 > 0)
+ {
+ *pabSha512 = (uint8_t*)RTMemAlloc(cb);
+ if (*pabSha512)
+ {
+ memcpy(*pabSha512, md, cb);
+ *pcbSha512 = cb;
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ rc = VERR_HTTP_CACERT_WRONG_FORMAT;
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ rc = VERR_HTTP_CACERT_WRONG_FORMAT;
+ X509_free(crt);
+ }
+ else
+ rc = VERR_HTTP_CACERT_WRONG_FORMAT;
+ BIO_free(cert);
+ }
+ else
+ rc = VERR_INTERNAL_ERROR;
+
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree(*pabSha512);
+ RTMemFree(*pabSha1);
+ }
+
+ return rc;
+}
+
+RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile)
+{
+ PRTHTTPINTERNAL pHttpInt = hHttp;
+ RTHTTP_VALID_RETURN(pHttpInt);
+
+ if (pHttpInt->pcszCAFile)
+ RTStrFree(pHttpInt->pcszCAFile);
+ pHttpInt->pcszCAFile = RTStrDup(pcszCAFile);
+ if (!pHttpInt->pcszCAFile)
+ return VERR_NO_MEMORY;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Figures out the IPRT status code for a GET.
+ *
+ * @returns IPRT status code.
+ * @param pHttpInt HTTP instance.
+ * @param rcCurl What curl returned.
+ */
+static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pHttpInt, int rcCurl)
+{
+ int rc = VERR_INTERNAL_ERROR;
+ if (rcCurl == CURLE_OK)
+ {
+ curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_RESPONSE_CODE, &pHttpInt->lLastResp);
+ switch (pHttpInt->lLastResp)
+ {
+ case 200:
+ /* OK, request was fulfilled */
+ case 204:
+ /* empty response */
+ rc = VINF_SUCCESS;
+ break;
+ case 400:
+ /* bad request */
+ rc = VERR_HTTP_BAD_REQUEST;
+ break;
+ case 403:
+ /* forbidden, authorization will not help */
+ rc = VERR_HTTP_ACCESS_DENIED;
+ break;
+ case 404:
+ /* URL not found */
+ rc = VERR_HTTP_NOT_FOUND;
+ break;
+ }
+ }
+ else
+ {
+ switch (rcCurl)
+ {
+ case CURLE_URL_MALFORMAT:
+ case CURLE_COULDNT_RESOLVE_HOST:
+ rc = VERR_HTTP_NOT_FOUND;
+ break;
+ case CURLE_COULDNT_CONNECT:
+ rc = VERR_HTTP_COULDNT_CONNECT;
+ break;
+ case CURLE_SSL_CONNECT_ERROR:
+ rc = VERR_HTTP_SSL_CONNECT_ERROR;
+ break;
+ case CURLE_SSL_CACERT:
+ /* The peer certificate cannot be authenticated with the CA certificates
+ * set by RTHttpSetCAFile(). We need other or additional CA certificates. */
+ rc = VERR_HTTP_CACERT_CANNOT_AUTHENTICATE;
+ break;
+ case CURLE_SSL_CACERT_BADFILE:
+ /* CAcert file (see RTHttpSetCAFile()) has wrong format */
+ rc = VERR_HTTP_CACERT_WRONG_FORMAT;
+ break;
+ case CURLE_ABORTED_BY_CALLBACK:
+ /* forcefully aborted */
+ rc = VERR_HTTP_ABORTED;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return rc;
+}
+
+RTR3DECL(int) RTHttpGet(RTHTTP hHttp, const char *pcszUrl, char **ppszResponse)
+{
+ PRTHTTPINTERNAL pHttpInt = hHttp;
+ RTHTTP_VALID_RETURN(pHttpInt);
+
+ pHttpInt->fAbort = false;
+
+ int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pcszUrl);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+
+#if 0
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+#endif
+
+ const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
+ if (pHttpInt->pcszCAFile)
+ pcszCAFile = pHttpInt->pcszCAFile;
+ if (RTFileExists(pcszCAFile))
+ {
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+ }
+
+ RTHTTPMEMCHUNK chunk = { NULL, 0 };
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void*)&chunk);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void*)pHttpInt);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+
+ rcCurl = curl_easy_perform(pHttpInt->pCurl);
+ int rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
+ *ppszResponse = chunk.pszMem;
+
+ return rc;
+}
+
+
+static size_t rtHttpWriteDataToFile(void *pvBuf, size_t cb, size_t n, void *pvUser)
+{
+ size_t cbAll = cb * n;
+ RTFILE hFile = (RTFILE)(intptr_t)pvUser;
+
+ size_t cbWritten = 0;
+ int rc = RTFileWrite(hFile, pvBuf, cbAll, &cbWritten);
+ if (RT_SUCCESS(rc))
+ return cbWritten;
+ return 0;
+}
+
+
+RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile)
+{
+ PRTHTTPINTERNAL pHttpInt = hHttp;
+ RTHTTP_VALID_RETURN(pHttpInt);
+
+ /*
+ * Set up the request.
+ */
+ pHttpInt->fAbort = false;
+
+ int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pszUrl);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+
+#if 0
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INVALID_PARAMETER;
+#endif
+
+ const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
+ if (pHttpInt->pcszCAFile)
+ pcszCAFile = pHttpInt->pcszCAFile;
+ if (RTFileExists(pcszCAFile))
+ {
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+ }
+
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteDataToFile);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void*)pHttpInt);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
+ if (CURL_FAILED(rcCurl))
+ return VERR_INTERNAL_ERROR;
+
+ /*
+ * Open the output file.
+ */
+ RTFILE hFile;
+ int rc = RTFileOpen(&hFile, pszDstFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_READWRITE);
+ if (RT_SUCCESS(rc))
+ {
+ rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void *)(uintptr_t)hFile);
+ if (!CURL_FAILED(rcCurl))
+ {
+ /*
+ * Perform the request.
+ */
+ rcCurl = curl_easy_perform(pHttpInt->pCurl);
+ rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
+ }
+ else
+ rc = VERR_INTERNAL_ERROR;
+
+ int rc2 = RTFileClose(hFile);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/misc/lockvalidator.cpp b/src/VBox/Runtime/common/misc/lockvalidator.cpp
index 245d5b64..eac25db1 100644
--- a/src/VBox/Runtime/common/misc/lockvalidator.cpp
+++ b/src/VBox/Runtime/common/misc/lockvalidator.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -3438,6 +3438,31 @@ RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS
}
+RTDECL(int) RTLockValidatorRecSharedCreateV(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass,
+ uint32_t uSubClass, void *pvLock, bool fSignaller, bool fEnabled,
+ const char *pszNameFmt, va_list va)
+{
+ PRTLOCKVALRECSHRD pRec;
+ *ppRec = pRec = (PRTLOCKVALRECSHRD)RTMemAlloc(sizeof(*pRec));
+ if (!pRec)
+ return VERR_NO_MEMORY;
+ RTLockValidatorRecSharedInitV(pRec, hClass, uSubClass, pvLock, fSignaller, fEnabled, pszNameFmt, va);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTLockValidatorRecSharedCreate(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass,
+ uint32_t uSubClass, void *pvLock, bool fSignaller, bool fEnabled,
+ const char *pszNameFmt, ...)
+{
+ va_list va;
+ va_start(va, pszNameFmt);
+ int rc = RTLockValidatorRecSharedCreateV(ppRec, hClass, uSubClass, pvLock, fSignaller, fEnabled, pszNameFmt, va);
+ va_end(va);
+ return rc;
+}
+
+
RTDECL(void) RTLockValidatorRecSharedDelete(PRTLOCKVALRECSHRD pRec)
{
Assert(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);
@@ -3478,6 +3503,18 @@ RTDECL(void) RTLockValidatorRecSharedDelete(PRTLOCKVALRECSHRD pRec)
}
+RTDECL(void) RTLockValidatorRecSharedDestroy(PRTLOCKVALRECSHRD *ppRec)
+{
+ PRTLOCKVALRECSHRD pRec = *ppRec;
+ *ppRec = NULL;
+ if (pRec)
+ {
+ RTLockValidatorRecSharedDelete(pRec);
+ RTMemFree(pRec);
+ }
+}
+
+
RTDECL(uint32_t) RTLockValidatorRecSharedSetSubClass(PRTLOCKVALRECSHRD pRec, uint32_t uSubClass)
{
AssertPtrReturn(pRec, RTLOCKVAL_SUB_CLASS_INVALID);
diff --git a/src/VBox/Runtime/common/misc/message.cpp b/src/VBox/Runtime/common/misc/message.cpp
index e3657426..643121af 100644
--- a/src/VBox/Runtime/common/misc/message.cpp
+++ b/src/VBox/Runtime/common/misc/message.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/once.cpp b/src/VBox/Runtime/common/misc/once.cpp
index 0ac8fe42..a3b6f606 100644
--- a/src/VBox/Runtime/common/misc/once.cpp
+++ b/src/VBox/Runtime/common/misc/once.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,11 +31,91 @@
#include <iprt/once.h>
#include "internal/iprt.h"
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/err.h>
+#include <iprt/initterm.h>
#include <iprt/semaphore.h>
#include <iprt/thread.h>
-#include <iprt/err.h>
-#include <iprt/assert.h>
-#include <iprt/asm.h>
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+#ifdef IN_RING3
+
+/** For initializing the clean-up list code. */
+static RTONCE g_OnceCleanUp = RTONCE_INITIALIZER;
+/** Critical section protecting the clean-up list. */
+static RTCRITSECT g_CleanUpCritSect;
+/** The clean-up list. */
+static RTLISTANCHOR g_CleanUpList;
+
+
+/** @callback_method_impl{FNRTTERMCALLBACK} */
+static DECLCALLBACK(void) rtOnceTermCallback(RTTERMREASON enmReason, int32_t iStatus, void *pvUser)
+{
+ bool const fLazyCleanUpOk = RTTERMREASON_IS_LAZY_CLEANUP_OK(enmReason);
+ RTCritSectEnter(&g_CleanUpCritSect); /* Potentially dangerous. */
+
+ PRTONCE pCur, pPrev;
+ RTListForEachReverseSafe(&g_CleanUpList, pCur, pPrev, RTONCE, CleanUpNode)
+ {
+ /*
+ * Mostly reset it before doing the callback.
+ *
+ * Should probably introduce some new states here, but I'm not sure
+ * it's really worth it at this point.
+ */
+ PFNRTONCECLEANUP pfnCleanUp = pCur->pfnCleanUp;
+ void *pvUserCleanUp = pCur->pvUser;
+ pCur->pvUser = NULL;
+ pCur->pfnCleanUp = NULL;
+ ASMAtomicWriteS32(&pCur->rc, VERR_WRONG_ORDER);
+
+ pfnCleanUp(pvUserCleanUp, fLazyCleanUpOk);
+
+ /*
+ * Reset the reset of the state if we're being unloaded or smth.
+ */
+ if (!fLazyCleanUpOk)
+ {
+ ASMAtomicWriteS32(&pCur->rc, VERR_INTERNAL_ERROR);
+ ASMAtomicWriteS32(&pCur->iState, RTONCESTATE_UNINITIALIZED);
+ }
+ }
+
+ RTCritSectLeave(&g_CleanUpCritSect);
+ NOREF(pvUser); NOREF(enmReason); NOREF(iStatus);
+}
+
+
+
+/**
+ * Initializes the globals (using RTOnce).
+ *
+ * @returns IPRT status code
+ * @param pvUser Unused.
+ */
+static DECLCALLBACK(int32_t) rtOnceInitCleanUp(void *pvUser)
+{
+ NOREF(pvUser);
+ RTListInit(&g_CleanUpList);
+ int rc = RTCritSectInit(&g_CleanUpCritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTTermRegisterCallback(rtOnceTermCallback, NULL);
+ if (RT_SUCCESS(rc))
+ return rc;
+
+ RTCritSectDelete(&g_CleanUpCritSect);
+ }
+ return rc;
+}
+
+#endif /* IN_RING3 */
+
/**
@@ -156,7 +236,7 @@ static int rtOnceOtherThread(PRTONCE pOnce, PRTSEMEVENTMULTI phEvtM)
}
-RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser1, void *pvUser2)
+RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, PFNRTONCECLEANUP pfnCleanUp, void *pvUser)
{
/*
* Validate input (strict builds only).
@@ -181,6 +261,21 @@ RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser1, void *pv
|| iState == RTONCESTATE_BUSY_HAVE_SEM
, VERR_INTERNAL_ERROR);
+#ifndef IN_RING3
+ AssertReturn(!pfnCleanUp, VERR_NOT_SUPPORTED);
+#else /* IN_RING3 */
+
+ /*
+ * Make sure our clean-up bits are working if needed later.
+ */
+ if (pfnCleanUp)
+ {
+ int rc = RTOnce(&g_OnceCleanUp, rtOnceInitCleanUp, NULL);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+#endif /* IN_RING3 */
+
/*
* Do we initialize it?
*/
@@ -191,9 +286,23 @@ RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser1, void *pv
/*
* Yes, so do the execute once stuff.
*/
- rcOnce = pfnOnce(pvUser1, pvUser2);
+ rcOnce = pfnOnce(pvUser);
ASMAtomicWriteS32(&pOnce->rc, rcOnce);
+#ifdef IN_RING3
+ /*
+ * Register clean-up if requested and we were successful.
+ */
+ if (pfnCleanUp && RT_SUCCESS(rcOnce))
+ {
+ RTCritSectEnter(&g_CleanUpCritSect);
+ pOnce->pfnCleanUp = pfnCleanUp;
+ pOnce->pvUser = pvUser;
+ RTListAppend(&g_CleanUpList, &pOnce->CleanUpNode);
+ RTCritSectLeave(&g_CleanUpCritSect);
+ }
+#endif
+
/*
* If there is a sempahore to signal, we're in for some extra work here.
*/
@@ -253,10 +362,22 @@ RTDECL(void) RTOnceReset(PRTONCE pOnce)
Assert(pOnce->hEventMulti == NIL_RTSEMEVENTMULTI);
int32_t iState = ASMAtomicUoReadS32(&pOnce->iState);
AssertMsg( iState == RTONCESTATE_DONE
- && iState == RTONCESTATE_UNINITIALIZED,
+ || iState == RTONCESTATE_UNINITIALIZED,
("%d\n", iState));
NOREF(iState);
+#ifdef IN_RING3
+ /* Unregister clean-up. */
+ if (pOnce->pfnCleanUp)
+ {
+ RTCritSectEnter(&g_CleanUpCritSect);
+ RTListNodeRemove(&pOnce->CleanUpNode);
+ pOnce->pfnCleanUp = NULL;
+ pOnce->pvUser = NULL;
+ RTCritSectLeave(&g_CleanUpCritSect);
+ }
+#endif /* IN_RING3 */
+
/* Do the same as RTONCE_INITIALIZER does. */
ASMAtomicWriteS32(&pOnce->rc, VERR_INTERNAL_ERROR);
ASMAtomicWriteS32(&pOnce->iState, RTONCESTATE_UNINITIALIZED);
diff --git a/src/VBox/Runtime/common/misc/req.cpp b/src/VBox/Runtime/common/misc/req.cpp
index a137d89d..fa3e0c26 100644
--- a/src/VBox/Runtime/common/misc/req.cpp
+++ b/src/VBox/Runtime/common/misc/req.cpp
@@ -228,7 +228,7 @@ RT_EXPORT_SYMBOL(RTReqRelease);
RTDECL(int) RTReqSubmit(PRTREQ hReq, RTMSINTERVAL cMillies)
{
- LogFlow(("RTReqQueue: hReq=%p cMillies=%d\n", hReq, cMillies));
+ LogFlow(("RTReqSubmit: hReq=%p cMillies=%d\n", hReq, cMillies));
/*
* Verify the supplied package.
@@ -267,7 +267,7 @@ RTDECL(int) RTReqSubmit(PRTREQ hReq, RTMSINTERVAL cMillies)
if (!(fFlags & RTREQFLAGS_NO_WAIT))
rc = RTReqWait(pReq, cMillies);
- LogFlow(("RTReqQueue: returns %Rrc\n", rc));
+ LogFlow(("RTReqSubmit: returns %Rrc\n", rc));
return rc;
}
RT_EXPORT_SYMBOL(RTReqSubmit);
diff --git a/src/VBox/Runtime/common/misc/reqpool.cpp b/src/VBox/Runtime/common/misc/reqpool.cpp
index e7ab2be2..bf63d110 100644
--- a/src/VBox/Runtime/common/misc/reqpool.cpp
+++ b/src/VBox/Runtime/common/misc/reqpool.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/reqqueue.cpp b/src/VBox/Runtime/common/misc/reqqueue.cpp
index 76fc6235..4d8a6ec3 100644
--- a/src/VBox/Runtime/common/misc/reqqueue.cpp
+++ b/src/VBox/Runtime/common/misc/reqqueue.cpp
@@ -98,7 +98,7 @@ RT_EXPORT_SYMBOL(RTReqQueueDestroy);
RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies)
{
- LogFlow(("RTReqProcess %x\n", hQueue));
+ LogFlow(("RTReqQueueProcess %x\n", hQueue));
/*
* Check input.
@@ -137,7 +137,7 @@ RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies)
*/
PRTREQ pReq = pReqs;
if (pReq->pNext)
- Log2(("RTReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext));
+ Log2(("RTReqQueueProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext));
pReqs = NULL;
while (pReq)
{
@@ -168,7 +168,7 @@ RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies)
}
}
- LogFlow(("RTReqProcess: returns %Rrc\n", rc));
+ LogFlow(("RTReqQueueProcess: returns %Rrc\n", rc));
return rc;
}
RT_EXPORT_SYMBOL(RTReqQueueProcess);
@@ -209,7 +209,7 @@ RT_EXPORT_SYMBOL(RTReqQueueCallEx);
RTDECL(int) RTReqQueueCallV(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
{
- LogFlow(("RTReqCallV: cMillies=%d fFlags=%#x pfnFunction=%p cArgs=%d\n", cMillies, fFlags, pfnFunction, cArgs));
+ LogFlow(("RTReqQueueCallV: cMillies=%d fFlags=%#x pfnFunction=%p cArgs=%d\n", cMillies, fFlags, pfnFunction, cArgs));
/*
* Check input.
@@ -258,10 +258,10 @@ RTDECL(int) RTReqQueueCallV(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMill
if (!(fFlags & RTREQFLAGS_NO_WAIT))
{
*ppReq = pReq;
- LogFlow(("RTReqCallV: returns %Rrc *ppReq=%p\n", rc, pReq));
+ LogFlow(("RTReqQueueCallV: returns %Rrc *ppReq=%p\n", rc, pReq));
}
else
- LogFlow(("RTReqCallV: returns %Rrc\n", rc));
+ LogFlow(("RTReqQueueCallV: returns %Rrc\n", rc));
Assert(rc != VERR_INTERRUPTED);
return rc;
}
diff --git a/src/VBox/Runtime/common/misc/sanity-c.c b/src/VBox/Runtime/common/misc/sanity-c.c
index 042cf383..61b1dddb 100644
--- a/src/VBox/Runtime/common/misc/sanity-c.c
+++ b/src/VBox/Runtime/common/misc/sanity-c.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/sanity-cpp.cpp b/src/VBox/Runtime/common/misc/sanity-cpp.cpp
index ea0202d9..e6464288 100644
--- a/src/VBox/Runtime/common/misc/sanity-cpp.cpp
+++ b/src/VBox/Runtime/common/misc/sanity-cpp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/sanity.h b/src/VBox/Runtime/common/misc/sanity.h
index f0461c42..89151389 100644
--- a/src/VBox/Runtime/common/misc/sanity.h
+++ b/src/VBox/Runtime/common/misc/sanity.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/semspingpong.cpp b/src/VBox/Runtime/common/misc/semspingpong.cpp
index e13bed82..10633147 100644
--- a/src/VBox/Runtime/common/misc/semspingpong.cpp
+++ b/src/VBox/Runtime/common/misc/semspingpong.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/setjmp.asm b/src/VBox/Runtime/common/misc/setjmp.asm
index 9bacbbc4..f4960d98 100644
--- a/src/VBox/Runtime/common/misc/setjmp.asm
+++ b/src/VBox/Runtime/common/misc/setjmp.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2009 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/misc/sg.cpp b/src/VBox/Runtime/common/misc/sg.cpp
index fe089b81..2866722d 100644
--- a/src/VBox/Runtime/common/misc/sg.cpp
+++ b/src/VBox/Runtime/common/misc/sg.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,6 +31,7 @@
#include <iprt/sg.h>
#include <iprt/string.h>
#include <iprt/assert.h>
+#include <iprt/asm.h>
static void *sgBufGet(PRTSGBUF pSgBuf, size_t *pcbData)
@@ -46,7 +47,7 @@ static void *sgBufGet(PRTSGBUF pSgBuf, size_t *pcbData)
return NULL;
}
- AssertReleaseMsg( pSgBuf->cbSegLeft <= 5 * _1M
+ AssertReleaseMsg( pSgBuf->cbSegLeft <= 32 * _1M
&& (uintptr_t)pSgBuf->pvSegCur >= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg
&& (uintptr_t)pSgBuf->pvSegCur + pSgBuf->cbSegLeft <= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg + pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg,
("pSgBuf->idxSeg=%d pSgBuf->cSegs=%d pSgBuf->pvSegCur=%p pSgBuf->cbSegLeft=%zd pSgBuf->paSegs[%d].pvSeg=%p pSgBuf->paSegs[%d].cbSeg=%zd\n",
@@ -314,7 +315,7 @@ RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy)
}
-RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy)
+RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy)
{
AssertPtrReturn(pSgBuf, 0);
AssertPtrReturn(pvBuf, 0);
@@ -332,7 +333,7 @@ RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy)
memcpy(pvDst, pvBuf, cbThisCopy);
cbLeft -= cbThisCopy;
- pvBuf = (void *)((uintptr_t)pvBuf + cbThisCopy);
+ pvBuf = (const void *)((uintptr_t)pvBuf + cbThisCopy);
}
return cbCopy - cbLeft;
@@ -421,3 +422,52 @@ RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned *
return cb;
}
+RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck)
+{
+ bool fIsZero = true;
+ size_t cbLeft = cbCheck;
+ RTSGBUF SgBufTmp;
+
+ RTSgBufClone(&SgBufTmp, pSgBuf);
+
+ while (cbLeft)
+ {
+ size_t cbThisCheck = cbLeft;
+ void *pvBuf = sgBufGet(&SgBufTmp, &cbThisCheck);
+
+ if (!cbThisCheck)
+ break;
+
+ /* Use optimized inline assembler if possible. */
+ if ( !(cbThisCheck % 4)
+ && (cbThisCheck * 8 <= UINT32_MAX))
+ {
+ if (ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbThisCheck * 8) != -1)
+ {
+ fIsZero = false;
+ break;
+ }
+ }
+ else
+ {
+ for (unsigned i = 0; i < cbThisCheck; i++)
+ {
+ char *pbBuf = (char *)pvBuf;
+ if (*pbBuf)
+ {
+ fIsZero = false;
+ break;
+ }
+ pvBuf = pbBuf + 1;
+ }
+
+ if (!fIsZero)
+ break;
+ }
+
+ cbLeft -= cbThisCheck;
+ }
+
+ return fIsZero;
+}
+
diff --git a/src/VBox/Runtime/common/misc/term.cpp b/src/VBox/Runtime/common/misc/term.cpp
index 7b789df8..7a7fb765 100644
--- a/src/VBox/Runtime/common/misc/term.cpp
+++ b/src/VBox/Runtime/common/misc/term.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -76,10 +76,9 @@ static PRTTERMCALLBACKREC g_pCallbackHead = NULL;
* Initializes the globals.
*
* @returns IPRT status code
- * @param pvUser1 Ignored.
- * @param pvUser2 Ignored.
+ * @param pvUser Ignored.
*/
-static DECLCALLBACK(int32_t) rtTermInitOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int32_t) rtTermInitOnce(void *pvUser)
{
RTSEMFASTMUTEX hFastMutex;
int rc;
@@ -92,8 +91,7 @@ static DECLCALLBACK(int32_t) rtTermInitOnce(void *pvUser1, void *pvUser2)
if (RT_SUCCESS(rc))
g_hFastMutex = hFastMutex;
- NOREF(pvUser1);
- NOREF(pvUser2);
+ NOREF(pvUser);
return rc;
}
@@ -110,7 +108,7 @@ RTDECL(int) RTTermRegisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser)
*/
AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
- rc = RTOnce(&g_InitTermCallbacksOnce, rtTermInitOnce, NULL, NULL);
+ rc = RTOnce(&g_InitTermCallbacksOnce, rtTermInitOnce, NULL);
if (RT_FAILURE(rc))
return rc;
diff --git a/src/VBox/Runtime/common/misc/thread.cpp b/src/VBox/Runtime/common/misc/thread.cpp
index f1d4b1d2..1be4a458 100644
--- a/src/VBox/Runtime/common/misc/thread.cpp
+++ b/src/VBox/Runtime/common/misc/thread.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -185,6 +185,20 @@ DECLHIDDEN(int) rtThreadInit(void)
}
+#ifdef IN_RING3
+/**
+ * Called when IPRT was first initialized in unobtrusive mode and later changed
+ * to obtrustive.
+ *
+ * This is only applicable in ring-3.
+ */
+DECLHIDDEN(void) rtThreadReInitObtrusive(void)
+{
+ rtThreadNativeReInitObtrusive();
+}
+#endif
+
+
/**
* Terminates the thread database.
*/
diff --git a/src/VBox/Runtime/common/net/macstr.cpp b/src/VBox/Runtime/common/net/macstr.cpp
new file mode 100644
index 00000000..84ac038f
--- /dev/null
+++ b/src/VBox/Runtime/common/net/macstr.cpp
@@ -0,0 +1,91 @@
+/* $Id: macstr.cpp $ */
+/** @file
+ * IPRT - Command Line Parsing
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/cidr.h>
+#include <iprt/net.h> /* must come before getopt.h */
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/message.h>
+#include <iprt/string.h>
+
+
+/**
+ * Converts an stringified Ethernet MAC address into the RTMAC representation.
+ *
+ * @returns VINF_SUCCESS on success.
+ *
+ * @param pszValue The value to convert.
+ * @param pAddr Where to store the result.
+ */
+RTDECL(int) RTNetStrToMacAddr(const char *pszValue, PRTMAC pAddr)
+{
+ /*
+ * Not quite sure if I should accept stuff like "08::27:::1" here...
+ * The code is accepting "::" patterns now, except for for the first
+ * and last parts.
+ */
+
+ /* first */
+ char *pszNext;
+ int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 16, &pAddr->au8[0]);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
+ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
+ if (*pszNext++ != ':')
+ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
+
+ /* middle */
+ for (unsigned i = 1; i < 5; i++)
+ {
+ if (*pszNext == ':')
+ pAddr->au8[i] = 0;
+ else
+ {
+ rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[i]);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
+ return rc;
+ if (*pszNext != ':')
+ return VERR_INVALID_PARAMETER;
+ }
+ pszNext++;
+ }
+
+ /* last */
+ rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[5]);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
+ return rc;
+ pszNext = RTStrStripL(pszNext);
+ if (*pszNext)
+ return VERR_INVALID_PARAMETER;
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTNetStrToMacAddr);
diff --git a/src/VBox/Runtime/common/net/netaddrstr.cpp b/src/VBox/Runtime/common/net/netaddrstr.cpp
index 4cc88a39..ba4df40f 100644
--- a/src/VBox/Runtime/common/net/netaddrstr.cpp
+++ b/src/VBox/Runtime/common/net/netaddrstr.cpp
@@ -1,6 +1,10 @@
/* $Id: netaddrstr.cpp $ */
/** @file
* IPRT - Network Address String Handling.
+ *
+ * @remarks Don't add new functionality to this file, it goes into netaddrstr2.cpp
+ * or some other suitable file (legal reasons + code not up to oracle
+ * quality standards and requires rewrite from scratch).
*/
/*
@@ -202,7 +206,8 @@
* This function should NOT be used directly. If you do, note
* that no security checks are done at the moment. This can change.
*
- * @returns iprt sstatus code.
+ * @returns iprt sstatus code, yeah, right... This function most certainly DOES
+ * NOT RETURN ANY IPRT STATUS CODES. It's also a unreadable mess.
* @param pszAddress The strin that holds the IPv6 address
* @param addressLength The length of pszAddress
* @param pszAddressOut Returns a plain, full blown IPv6 address
@@ -1147,7 +1152,7 @@ static int rtNetIpv6CheckAddrStr(const char *psz, char *pszResultAddress, size_t
{
int rc;
int rc2;
- int returnValue;
+ int returnValue = VERR_NOT_SUPPORTED; /* gcc want's this initialized, I understand its confusion. */
char *p = NULL, *pl = NULL;
@@ -1283,4 +1288,3 @@ RTDECL(bool) RTNetIsIPv4AddrStr(const char *pszAddress)
return true;
}
RT_EXPORT_SYMBOL(RTNetIsIPv4AddrStr);
-
diff --git a/src/VBox/Runtime/common/net/netaddrstr2.cpp b/src/VBox/Runtime/common/net/netaddrstr2.cpp
new file mode 100644
index 00000000..eb9c70a8
--- /dev/null
+++ b/src/VBox/Runtime/common/net/netaddrstr2.cpp
@@ -0,0 +1,72 @@
+/* $Id: netaddrstr2.cpp $ */
+/** @file
+ * IPRT - Network Address String Handling.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/net.h>
+
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/stream.h>
+#include "internal/string.h"
+
+RTDECL(int) RTNetStrToIPv4Addr(const char *pszAddr, PRTNETADDRIPV4 pAddr)
+{
+ char *pszNext;
+ AssertPtrReturn(pszAddr, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
+
+ int rc = RTStrToUInt8Ex(RTStrStripL(pszAddr), &pszNext, 10, &pAddr->au8[0]);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
+ return VERR_INVALID_PARAMETER;
+ if (*pszNext++ != '.')
+ return VERR_INVALID_PARAMETER;
+
+ rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[1]);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
+ return VERR_INVALID_PARAMETER;
+ if (*pszNext++ != '.')
+ return VERR_INVALID_PARAMETER;
+
+ rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[2]);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
+ return VERR_INVALID_PARAMETER;
+ if (*pszNext++ != '.')
+ return VERR_INVALID_PARAMETER;
+
+ rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[3]);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
+ return VERR_INVALID_PARAMETER;
+ pszNext = RTStrStripL(pszNext);
+ if (*pszNext)
+ return VERR_INVALID_PARAMETER;
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTNetStrToIPv4Addr);
+
diff --git a/src/VBox/Runtime/common/path/RTPathAbsDup.cpp b/src/VBox/Runtime/common/path/RTPathAbsDup.cpp
index b9f217f9..337ce128 100644
--- a/src/VBox/Runtime/common/path/RTPathAbsDup.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAbsDup.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathAbsEx.cpp b/src/VBox/Runtime/common/path/RTPathAbsEx.cpp
index c647b547..86ce86a0 100644
--- a/src/VBox/Runtime/common/path/RTPathAbsEx.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAbsEx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathAbsExDup.cpp b/src/VBox/Runtime/common/path/RTPathAbsExDup.cpp
index 8bb8cd17..9247d899 100644
--- a/src/VBox/Runtime/common/path/RTPathAbsExDup.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAbsExDup.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathAppend.cpp b/src/VBox/Runtime/common/path/RTPathAppend.cpp
index 5bad6483..af3e5917 100644
--- a/src/VBox/Runtime/common/path/RTPathAppend.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAppend.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathAppendEx.cpp b/src/VBox/Runtime/common/path/RTPathAppendEx.cpp
index e5de4ffe..ebed3864 100644
--- a/src/VBox/Runtime/common/path/RTPathAppendEx.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAppendEx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp b/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp
new file mode 100644
index 00000000..fbb6b64c
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp
@@ -0,0 +1,130 @@
+/* $Id: RTPathCalcRelative.cpp $ */
+/** @file
+ * IPRT - RTPathCreateRelative.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+
+RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst,
+ const char *pszPathFrom,
+ const char *pszPathTo)
+{
+ int rc = VINF_SUCCESS;
+
+ AssertPtrReturn(pszPathDst, VERR_INVALID_POINTER);
+ AssertReturn(cbPathDst, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszPathFrom, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPathTo, VERR_INVALID_POINTER);
+ AssertReturn(RTPathStartsWithRoot(pszPathFrom), VERR_INVALID_PARAMETER);
+ AssertReturn(RTPathStartsWithRoot(pszPathTo), VERR_INVALID_PARAMETER);
+ AssertReturn(RTStrCmp(pszPathFrom, pszPathTo), VERR_INVALID_PARAMETER);
+
+ /*
+ * Check for different root specifiers (drive letters), creating a relative path doesn't work here.
+ * @todo: How to handle case insensitive root specifiers correctly?
+ */
+ size_t offRootFrom = rtPathRootSpecLen(pszPathFrom);
+ size_t offRootTo = rtPathRootSpecLen(pszPathTo);
+
+ if ( offRootFrom != offRootTo
+ || RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom))
+ return VERR_NOT_SUPPORTED;
+
+ /* Filter out the parent path which is equal to both paths. */
+ while ( *pszPathFrom == *pszPathTo
+ && *pszPathFrom != '\0'
+ && *pszPathTo != '\0')
+ {
+ pszPathFrom++;
+ pszPathTo++;
+ }
+
+ /*
+ * Because path components can start with an equal string but differ afterwards we
+ * need to go back to the beginning of the current component.
+ */
+ while (!RTPATH_IS_SEP(*pszPathFrom))
+ pszPathFrom--;
+
+ pszPathFrom++; /* Skip path separator. */
+
+ while (!RTPATH_IS_SEP(*pszPathTo))
+ pszPathTo--;
+
+ pszPathTo++; /* Skip path separator. */
+
+ /* Paths point to the first non equal component now. */
+ char aszPathTmp[RTPATH_MAX + 1];
+ unsigned offPathTmp = 0;
+
+ /* Create the part to go up from pszPathFrom. */
+ while (*pszPathFrom != '\0')
+ {
+ while ( !RTPATH_IS_SEP(*pszPathFrom)
+ && *pszPathFrom != '\0')
+ pszPathFrom++;
+
+ if (RTPATH_IS_SEP(*pszPathFrom))
+ {
+ if (offPathTmp + 3 >= sizeof(aszPathTmp) - 1)
+ return VERR_FILENAME_TOO_LONG;
+ aszPathTmp[offPathTmp++] = '.';
+ aszPathTmp[offPathTmp++] = '.';
+ aszPathTmp[offPathTmp++] = RTPATH_SLASH;
+ pszPathFrom++;
+ }
+ }
+
+ aszPathTmp[offPathTmp] = '\0';
+
+ /* Now append the rest of pszPathTo to the final path. */
+ char *pszPathTmp = &aszPathTmp[offPathTmp];
+ size_t cbPathTmp = sizeof(aszPathTmp) - offPathTmp - 1;
+ rc = RTStrCatP(&pszPathTmp, &cbPathTmp, pszPathTo);
+ if (RT_SUCCESS(rc))
+ {
+ *pszPathTmp = '\0';
+
+ size_t cchPathTmp = strlen(aszPathTmp);
+ if (cchPathTmp >= cbPathDst)
+ return VERR_BUFFER_OVERFLOW;
+ memcpy(pszPathDst, aszPathTmp, cchPathTmp + 1);
+ }
+ else
+ rc = VERR_FILENAME_TOO_LONG;
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathExt.cpp b/src/VBox/Runtime/common/path/RTPathExt.cpp
index 292c5f2f..bb2ee52e 100644
--- a/src/VBox/Runtime/common/path/RTPathExt.cpp
+++ b/src/VBox/Runtime/common/path/RTPathExt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathFilename.cpp b/src/VBox/Runtime/common/path/RTPathFilename.cpp
index 2eeaba5e..3278383d 100644
--- a/src/VBox/Runtime/common/path/RTPathFilename.cpp
+++ b/src/VBox/Runtime/common/path/RTPathFilename.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,46 +30,70 @@
*******************************************************************************/
#include "internal/iprt.h"
#include <iprt/path.h>
-#include <iprt/string.h>
+
+#include <iprt/assert.h>
-/**
- * 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)
{
+ return RTPathFilenameEx(pszPath, RTPATH_STYLE);
+}
+RT_EXPORT_SYMBOL(RTPathFilename);
+
+
+RTDECL(char *) RTPathFilenameEx(const char *pszPath, uint32_t fFlags)
+{
const char *psz = pszPath;
const char *pszName = pszPath;
- for (;; psz++)
+ Assert(RTPATH_STR_F_IS_VALID(fFlags, 0 /*no extra flags*/));
+ fFlags &= RTPATH_STR_F_STYLE_MASK;
+ if (fFlags == RTPATH_STR_F_STYLE_HOST)
+ fFlags = RTPATH_STYLE;
+ if (fFlags == RTPATH_STR_F_STYLE_DOS)
{
- switch (*psz)
+ for (;; psz++)
{
- /* handle separators. */
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
- case ':':
- pszName = psz + 1;
- break;
+ switch (*psz)
+ {
+ /* handle separators. */
+ case ':':
+ case '\\':
+ case '/':
+ pszName = psz + 1;
+ break;
- case '\\':
-#endif
- case '/':
- pszName = psz + 1;
- break;
+ /* the end */
+ case '\0':
+ if (*pszName)
+ return (char *)(void *)pszName;
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ Assert(fFlags == RTPATH_STR_F_STYLE_UNIX);
+ for (;; psz++)
+ {
+ switch (*psz)
+ {
+ /* handle separators. */
+ case '/':
+ pszName = psz + 1;
+ break;
- /* the end */
- case '\0':
- if (*pszName)
- return (char *)(void *)pszName;
- return NULL;
+ /* the end */
+ case '\0':
+ if (*pszName)
+ return (char *)(void *)pszName;
+ return NULL;
+ }
}
}
/* not reached */
}
+RT_EXPORT_SYMBOL(RTPathFilenameEx);
diff --git a/src/VBox/Runtime/common/path/RTPathParse.cpp b/src/VBox/Runtime/common/path/RTPathParse.cpp
index ce42e330..3ead6908 100644
--- a/src/VBox/Runtime/common/path/RTPathParse.cpp
+++ b/src/VBox/Runtime/common/path/RTPathParse.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,88 +31,45 @@
#include "internal/iprt.h"
#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
-/**
- * Parses 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) RTPathParse(const char *pszPath, size_t *pcchDir, ssize_t *poffName, ssize_t *poffSuff)
+#define RTPATH_TEMPLATE_CPP_H "RTPathParse.cpp.h"
+#include "rtpath-expand-template.cpp.h"
+
+
+RTDECL(int) RTPathParse(const char *pszPath, PRTPATHPARSED pParsed, size_t cbParsed, uint32_t fFlags)
{
- const char *psz = pszPath;
- ssize_t offRoot = 0;
- const char *pszName = pszPath;
- const char *pszLastDot = NULL;
+ /*
+ * Input validation.
+ */
+ AssertReturn(cbParsed >= RT_UOFFSETOF(RTPATHPARSED, aComps), VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pParsed, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(*pszPath, VERR_PATH_ZERO_LENGTH);
+ AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0), VERR_INVALID_FLAGS);
- for (;; psz++)
+ /*
+ * Invoke the worker for the selected path style.
+ */
+ switch (fFlags & RTPATH_STR_F_STYLE_MASK)
{
- switch (*psz)
- {
- /* handle separators. */
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
- case ':':
- pszName = psz + 1;
- offRoot = pszName - psz;
- break;
-
- case '\\':
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+ case RTPATH_STR_F_STYLE_HOST:
#endif
- case '/':
- pszName = psz + 1;
- break;
-
- case '.':
- pszLastDot = psz;
- break;
-
- /*
- * The end. Complete the results.
- */
- case '\0':
- {
- ssize_t offName = *pszName != '\0' ? pszName - pszPath : -1;
- if (poffName)
- *poffName = offName;
+ case RTPATH_STR_F_STYLE_DOS:
+ return rtPathParseStyleDos(pszPath, pParsed, cbParsed, fFlags);
- if (poffSuff)
- {
- ssize_t offSuff = -1;
- if (pszLastDot)
- {
- offSuff = pszLastDot - pszPath;
- if (offSuff <= offName)
- offSuff = -1;
- }
- *poffSuff = offSuff;
- }
-
- if (pcchDir)
- {
- ssize_t off = offName - 1;
- while (off >= offRoot && RTPATH_IS_SLASH(pszPath[off]))
- off--;
- *pcchDir = RT_MAX(off, offRoot) + 1;
- }
+#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS)
+ case RTPATH_STR_F_STYLE_HOST:
+#endif
+ case RTPATH_STR_F_STYLE_UNIX:
+ return rtPathParseStyleUnix(pszPath, pParsed, cbParsed, fFlags);
- return psz - pszPath;
- }
- }
+ default:
+ AssertFailedReturn(VERR_INVALID_FLAGS); /* impossible */
}
-
- /* will never get here */
- return 0;
}
diff --git a/src/VBox/Runtime/common/path/RTPathParse.cpp.h b/src/VBox/Runtime/common/path/RTPathParse.cpp.h
new file mode 100644
index 00000000..bef8e7a1
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathParse.cpp.h
@@ -0,0 +1,250 @@
+/* $Id: RTPathParse.cpp.h $ */
+/** @file
+ * IPRT - RTPathParse - Code Template.
+ *
+ * This file included multiple times with different path style macros.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+
+/**
+ * @copydoc RTPathParse
+ */
+static int RTPATH_STYLE_FN(rtPathParse)(const char *pszPath, PRTPATHPARSED pParsed, size_t cbParsed, uint32_t fFlags)
+{
+ /*
+ * Parse the root specification if present and initialize the parser state
+ * (keep it on the stack for speed).
+ */
+ uint32_t const cMaxComps = cbParsed < RT_UOFFSETOF(RTPATHPARSED, aComps[0xfff0])
+ ? (uint32_t)((cbParsed - RT_UOFFSETOF(RTPATHPARSED, aComps)) / sizeof(pParsed->aComps[0]))
+ : 0xfff0;
+ uint32_t idxComp = 0;
+ uint32_t cchPath;
+ uint32_t offCur;
+ uint16_t fProps;
+
+ if (RTPATH_IS_SLASH(pszPath[0]))
+ {
+ if (fFlags & RTPATH_STR_F_NO_START)
+ {
+ offCur = 1;
+ while (RTPATH_IS_SLASH(pszPath[offCur]))
+ offCur++;
+ if (!pszPath[offCur])
+ return VERR_PATH_ZERO_LENGTH;
+ fProps = RTPATH_PROP_RELATIVE | RTPATH_PROP_EXTRA_SLASHES;
+ cchPath = 0;
+ }
+#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
+ else if ( RTPATH_IS_SLASH(pszPath[1])
+ && !RTPATH_IS_SLASH(pszPath[2])
+ && pszPath[2])
+ {
+ /* UNC - skip to the end of the potential namespace or computer name. */
+ offCur = 2;
+ while (!RTPATH_IS_SLASH(pszPath[offCur]) && pszPath[offCur])
+ offCur++;
+
+ /* If there is another slash, we considered it a valid UNC path, if
+ not it's just a root path with an extra slash thrown in. */
+ if (RTPATH_IS_SLASH(pszPath[offCur]))
+ {
+ fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_UNC | RTPATH_PROP_ABSOLUTE;
+ offCur++;
+ cchPath = offCur;
+ }
+ else
+ {
+ fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_RELATIVE;
+ offCur = 1;
+ cchPath = 1;
+ }
+ }
+#endif
+ else
+ {
+#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
+ fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_RELATIVE;
+#else
+ fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE;
+#endif
+ offCur = 1;
+ cchPath = 1;
+ }
+ }
+#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
+ else if (RT_C_IS_ALPHA(pszPath[0]) && pszPath[1] == ':')
+ {
+ if (!RTPATH_IS_SLASH(pszPath[2]))
+ {
+ fProps = RTPATH_PROP_VOLUME | RTPATH_PROP_RELATIVE;
+ offCur = 2;
+ }
+ else
+ {
+ fProps = RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE;
+ offCur = 3;
+ }
+ cchPath = offCur;
+ }
+#endif
+ else
+ {
+ fProps = RTPATH_PROP_RELATIVE;
+ offCur = 0;
+ cchPath = 0;
+ }
+
+ /* Add it to the component array . */
+ if (offCur && !(fFlags & RTPATH_STR_F_NO_START))
+ {
+ cchPath = offCur;
+ if (idxComp < cMaxComps)
+ {
+ pParsed->aComps[idxComp].off = 0;
+ pParsed->aComps[idxComp].cch = offCur;
+ }
+ idxComp++;
+
+ /* Skip unnecessary slashes following the root-spec. */
+ if (RTPATH_IS_SLASH(pszPath[offCur]))
+ {
+ fProps |= RTPATH_PROP_EXTRA_SLASHES;
+ do
+ offCur++;
+ while (RTPATH_IS_SLASH(pszPath[offCur]));
+ }
+ }
+
+ /*
+ * Parse the rest.
+ */
+ if (pszPath[offCur])
+ {
+ for (;;)
+ {
+ Assert(!RTPATH_IS_SLASH(pszPath[offCur]));
+
+ /* Find the end of the component. */
+ uint32_t offStart = offCur;
+ char ch;
+ while ((ch = pszPath[offCur]) != '\0' && !RTPATH_IS_SLASH(ch))
+ offCur++;
+ if (offCur >= _64K)
+ return VERR_FILENAME_TOO_LONG;
+
+ /* Add it. */
+ uint32_t cchComp = offCur - offStart;
+ if (idxComp < cMaxComps)
+ {
+ pParsed->aComps[idxComp].off = offStart;
+ pParsed->aComps[idxComp].cch = cchComp;
+ }
+ idxComp++;
+ cchPath += cchComp;
+
+ /* Look for '.' and '..' references. */
+ if (cchComp == 1 && pszPath[offCur - 1] == '.')
+ fProps |= RTPATH_PROP_DOT_REFS;
+ else if (cchComp == 2 && pszPath[offCur - 1] == '.' && pszPath[offCur - 2] == '.')
+ {
+ fProps &= ~RTPATH_PROP_ABSOLUTE;
+ fProps |= RTPATH_PROP_DOTDOT_REFS | RTPATH_PROP_RELATIVE;
+ }
+
+ /* Skip unnecessary slashes. Leave ch unchanged! */
+ char ch2 = ch;
+ if (ch2)
+ {
+ ch2 = pszPath[++offCur];
+ if (RTPATH_IS_SLASH(ch2))
+ {
+ fProps |= RTPATH_PROP_EXTRA_SLASHES;
+ do
+ ch2 = pszPath[++offCur];
+ while (RTPATH_IS_SLASH(ch2));
+ }
+ }
+
+ /* The end? */
+ if (ch2 == '\0')
+ {
+ pParsed->offSuffix = offCur;
+ pParsed->cchSuffix = 0;
+ if (ch)
+ {
+ if (!(fFlags & RTPATH_STR_F_NO_END))
+ {
+ fProps |= RTPATH_PROP_DIR_SLASH; /* (not counted in component, but in cchPath) */
+ cchPath++;
+ }
+ else
+ fProps |= RTPATH_PROP_EXTRA_SLASHES;
+ }
+ else if (!(fFlags & RTPATH_STR_F_NO_END))
+ {
+ fProps |= RTPATH_PROP_FILENAME;
+
+ /* look for an ? */
+ uint16_t cDots = 0;
+ uint32_t offSuffix = offStart + cchComp;
+ while (offSuffix-- > offStart)
+ if (pszPath[offSuffix] == '.')
+ {
+ uint32_t cchSuffix = offStart + cchComp - offSuffix;
+ if (cchSuffix > 1 && offStart != offSuffix)
+ {
+ pParsed->cchSuffix = cchSuffix;
+ pParsed->offSuffix = offSuffix;
+ fProps |= RTPATH_PROP_SUFFIX;
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ /* No, not the end. Account for an separator before we restart the loop. */
+ cchPath += sizeof(RTPATH_SLASH_STR) - 1;
+ }
+ }
+ else
+ {
+ pParsed->offSuffix = offCur;
+ pParsed->cchSuffix = 0;
+ }
+ if (offCur >= _64K)
+ return VERR_FILENAME_TOO_LONG;
+
+ /*
+ * Store the remainder of the state and we're done.
+ */
+ pParsed->fProps = fProps;
+ pParsed->cchPath = cchPath;
+ pParsed->cComps = idxComp;
+
+ return idxComp <= cMaxComps ? VINF_SUCCESS : VERR_BUFFER_OVERFLOW;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathParseSimple.cpp b/src/VBox/Runtime/common/path/RTPathParseSimple.cpp
new file mode 100644
index 00000000..f6de9aa2
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathParseSimple.cpp
@@ -0,0 +1,118 @@
+/* $Id: RTPathParseSimple.cpp $ */
+/** @file
+ * IPRT - RTPathParseSimple
+ */
+
+/*
+ * Copyright (C) 2006-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+
+/**
+ * Parses 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)
+{
+ const char *psz = pszPath;
+ ssize_t offRoot = 0;
+ const char *pszName = pszPath;
+ const char *pszLastDot = NULL;
+
+ for (;; psz++)
+ {
+ switch (*psz)
+ {
+ /* handle separators. */
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ case ':':
+ pszName = psz + 1;
+ offRoot = pszName - psz;
+ break;
+
+ case '\\':
+#endif
+ case '/':
+ pszName = psz + 1;
+ break;
+
+ case '.':
+ pszLastDot = psz;
+ break;
+
+ /*
+ * The end. Complete the results.
+ */
+ case '\0':
+ {
+ ssize_t offName = *pszName != '\0' ? pszName - pszPath : -1;
+ if (poffName)
+ *poffName = offName;
+
+ if (poffSuff)
+ {
+ ssize_t offSuff = -1;
+ if (pszLastDot)
+ {
+ offSuff = pszLastDot - pszPath;
+ if (offSuff <= offName)
+ offSuff = -1;
+ }
+ *poffSuff = offSuff;
+ }
+
+ if (pcchDir)
+ {
+ ssize_t off = offName - 1;
+ while (off >= offRoot && RTPATH_IS_SLASH(pszPath[off]))
+ off--;
+ *pcchDir = RT_MAX(off, offRoot) + 1;
+ }
+
+ return psz - pszPath;
+ }
+ }
+ }
+
+ /* will never get here */
+ return 0;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp b/src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp
new file mode 100644
index 00000000..5ba842c0
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp
@@ -0,0 +1,122 @@
+/* $Id: RTPathParsedReassemble.cpp $ */
+/** @file
+ * IPRT - RTPathParsedReassemble.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTPathParsedReassemble(const char *pszSrcPath, PRTPATHPARSED pParsed, uint32_t fFlags,
+ char *pszDstPath, size_t cbDstPath)
+{
+ /*
+ * Input validation.
+ */
+ AssertPtrReturn(pszSrcPath, VERR_INVALID_POINTER);
+ AssertPtrReturn(pParsed, VERR_INVALID_POINTER);
+ AssertReturn(pParsed->cComps > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0) && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS);
+ AssertPtrReturn(pszDstPath, VERR_INVALID_POINTER);
+ AssertReturn(cbDstPath > pParsed->cchPath, VERR_BUFFER_OVERFLOW);
+
+ /*
+ * Figure which slash to use.
+ */
+ char chSlash;
+ switch (fFlags & RTPATH_STR_F_STYLE_MASK)
+ {
+ case RTPATH_STR_F_STYLE_HOST:
+ chSlash = RTPATH_SLASH;
+ break;
+
+ case RTPATH_STR_F_STYLE_DOS:
+ chSlash = '\\';
+ break;
+
+ case RTPATH_STR_F_STYLE_UNIX:
+ chSlash = '/';
+ break;
+
+ default:
+ AssertFailedReturn(VERR_INVALID_FLAGS); /* impossible */
+ }
+
+ /*
+ * Do the joining.
+ */
+ uint32_t const cchOrgPath = pParsed->cchPath;
+ uint32_t cchDstPath = 0;
+ uint32_t const cComps = pParsed->cComps;
+ uint32_t idxComp = 0;
+ char *pszDst = pszDstPath;
+ uint32_t cchComp;
+
+ if (RTPATH_PROP_HAS_ROOT_SPEC(pParsed->fProps))
+ {
+ cchComp = pParsed->aComps[0].cch;
+ cchDstPath += cchComp;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ memcpy(pszDst, &pszSrcPath[pParsed->aComps[0].off], cchComp);
+
+ /* fix the slashes */
+ char chOtherSlash = chSlash == '\\' ? '/' : '\\';
+ while (cchComp-- > 0)
+ {
+ if (*pszDst == chOtherSlash)
+ *pszDst = chSlash;
+ pszDst++;
+ }
+ idxComp = 1;
+ }
+
+ while (idxComp < cComps)
+ {
+ cchComp = pParsed->aComps[idxComp].cch;
+ cchDstPath += cchComp;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ memcpy(pszDst, &pszSrcPath[pParsed->aComps[idxComp].off], cchComp);
+ pszDst += cchComp;
+ idxComp++;
+ if (idxComp != cComps || (pParsed->fProps & RTPATH_PROP_DIR_SLASH))
+ {
+ cchDstPath++;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ *pszDst++ = chSlash;
+ }
+ }
+
+ *pszDst = '\0';
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathRealDup.cpp b/src/VBox/Runtime/common/path/RTPathRealDup.cpp
index 18ce0a82..c0d84e40 100644
--- a/src/VBox/Runtime/common/path/RTPathRealDup.cpp
+++ b/src/VBox/Runtime/common/path/RTPathRealDup.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathRmCmd.cpp b/src/VBox/Runtime/common/path/RTPathRmCmd.cpp
new file mode 100644
index 00000000..cfb9b73b
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathRmCmd.cpp
@@ -0,0 +1,648 @@
+/* $Id: RTPathRmCmd.cpp $ */
+/** @file
+ * IPRT - TAR Command.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/path.h>
+
+#include <iprt/buildconfig.h>
+#include <iprt/ctype.h>
+#include <iprt/file.h>
+#include <iprt/dir.h>
+#include <iprt/getopt.h>
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/symlink.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+#define RTPATHRMCMD_OPT_INTERACTIVE 1000
+#define RTPATHRMCMD_OPT_ONE_FILE_SYSTEM 1001
+#define RTPATHRMCMD_OPT_PRESERVE_ROOT 1002
+#define RTPATHRMCMD_OPT_NO_PRESERVE_ROOT 1003
+#define RTPATHRMCMD_OPT_MACHINE_READABLE 1004
+
+/** The max directory entry size. */
+#define RTPATHRM_DIR_MAX_ENTRY_SIZE (sizeof(RTDIRENTRYEX) + 4096)
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/** Interactive option. */
+typedef enum
+{
+ RTPATHRMCMDINTERACTIVE_NONE = 1,
+ RTPATHRMCMDINTERACTIVE_ALL,
+ RTPATHRMCMDINTERACTIVE_ONCE
+ /** @todo possible that we should by default prompt if removing read-only
+ * files or files owned by someone else. We currently don't. */
+} RTPATHRMCMDINTERACTIVE;
+
+/**
+ * IPRT rm option structure.
+ */
+typedef struct RTPATHRMCMDOPTS
+{
+ /** Whether to delete recursively. */
+ bool fRecursive;
+ /** Whether to delete directories as well as other kinds of files. */
+ bool fDirsAndOther;
+ /** Whether to remove files without prompting and ignoring non-existing
+ * files. */
+ bool fForce;
+ /** Machine readable output. */
+ bool fMachineReadable;
+ /** Don't try remove root ('/') if set, otherwise don't treat root specially. */
+ bool fPreserveRoot;
+ /** Whether to keep to one file system. */
+ bool fOneFileSystem;
+ /** Whether to safely delete files (overwrite 3x before unlinking). */
+ bool fSafeDelete;
+ /** Whether to be verbose about the operation. */
+ bool fVerbose;
+ /** The interactive setting. */
+ RTPATHRMCMDINTERACTIVE enmInteractive;
+} RTPATHRMCMDOPTS;
+/** Pointer to the IPRT rm options. */
+typedef RTPATHRMCMDOPTS *PRTPATHRMCMDOPTS;
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** A bunch of zeros. */
+static uint8_t const g_abZeros[16384] = { 0 };
+/** A bunch of 0xFF bytes. (lazy init) */
+static uint8_t g_ab0xFF[16384];
+
+
+static void rtPathRmVerbose(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ if (!pOpts->fMachineReadable)
+ RTPrintf("%s\n", pszPath);
+}
+
+
+static int rtPathRmError(PRTPATHRMCMDOPTS pOpts, const char *pszPath, int rc,
+ const char *pszFormat, ...)
+{
+ if (pOpts->fMachineReadable)
+ RTPrintf("fname=%s%crc=%d%c", pszPath, rc);
+ else
+ {
+ va_list va;
+ va_start(va, pszFormat);
+ RTMsgErrorV(pszFormat, va);
+ va_end(va);
+ }
+ return rc;
+}
+
+
+/**
+ * Worker that removes a symbolic link.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the symbolic link.
+ */
+static int rtPathRmOneSymlink(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ if (pOpts->fVerbose)
+ rtPathRmVerbose(pOpts, pszPath);
+ int rc = RTSymlinkDelete(pszPath, 0);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Error removing symbolic link '%s': %Rrc\n", pszPath, rc);
+ return rc;
+}
+
+
+/**
+ * Worker that removes a file.
+ *
+ * Currently used to delete both regular and special files.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the file.
+ * @param pObjInfo The FS object info for the file.
+ */
+static int rtPathRmOneFile(PRTPATHRMCMDOPTS pOpts, const char *pszPath, PRTFSOBJINFO pObjInfo)
+{
+ int rc;
+ if (pOpts->fVerbose)
+ rtPathRmVerbose(pOpts, pszPath);
+
+ /*
+ * Wipe the file if requested and possible.
+ */
+ if (pOpts->fSafeDelete && RTFS_IS_FILE(pObjInfo->Attr.fMode))
+ {
+ /* Lazy init of the 0xff buffer. */
+ if (g_ab0xFF[0] != 0xff || g_ab0xFF[sizeof(g_ab0xFF) - 1] != 0xff)
+ memset(g_ab0xFF, 0xff, sizeof(g_ab0xFF));
+
+ RTFILE hFile;
+ rc = RTFileOpen(&hFile, pszPath, RTFILE_O_WRITE);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Opening '%s' for overwriting: %Rrc\n", pszPath, rc);
+
+ for (unsigned iPass = 0; iPass < 3; iPass++)
+ {
+ uint8_t const *pabFiller = iPass == 1 ? g_abZeros : g_ab0xFF;
+ size_t const cbFiller = iPass == 1 ? sizeof(g_abZeros) : sizeof(g_ab0xFF);
+
+ rc = RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL);
+ if (RT_FAILURE(rc))
+ {
+ rc = rtPathRmError(pOpts, pszPath, rc, "Error seeking to start of '%s': %Rrc\n", pszPath, rc);
+ break;
+ }
+ for (RTFOFF cbLeft = pObjInfo->cbObject; cbLeft > 0; cbLeft -= cbFiller)
+ {
+ size_t cbToWrite = cbFiller;
+ if (cbLeft < (RTFOFF)cbToWrite)
+ cbToWrite = (size_t)cbLeft;
+ rc = RTFileWrite(hFile, pabFiller, cbToWrite, NULL);
+ if (RT_FAILURE(rc))
+ {
+ rc = rtPathRmError(pOpts, pszPath, rc, "Error writing to '%s': %Rrc\n", pszPath, rc);
+ break;
+ }
+ }
+ }
+
+ int rc2 = RTFileClose(hFile);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ return rtPathRmError(pOpts, pszPath, rc2, "Closing '%s' failed: %Rrc\n", pszPath, rc);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ /*
+ * Remove the file.
+ */
+ rc = RTFileDelete(pszPath);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc,
+ RTFS_IS_FILE(pObjInfo->Attr.fMode)
+ ? "Error removing regular file '%s': %Rrc\n"
+ : "Error removing special file '%s': %Rrc\n",
+ pszPath, rc);
+ return rc;
+}
+
+
+/**
+ * Deletes one directory (if it's empty).
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the directory.
+ */
+static int rtPathRmOneDir(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ if (pOpts->fVerbose)
+ rtPathRmVerbose(pOpts, pszPath);
+
+ int rc = RTDirRemove(pszPath);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Error removing directory '%s': %Rrc", pszPath, rc);
+ return rc;
+}
+
+
+/**
+ * Recursively delete a directory.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath Pointer to a writable buffer holding the path to
+ * the directory.
+ * @param cchPath The length of the path (avoid strlen).
+ * @param pDirEntry Pointer to a directory entry buffer that is
+ * RTPATHRM_DIR_MAX_ENTRY_SIZE bytes big.
+ */
+static int rtPathRmRecursive(PRTPATHRMCMDOPTS pOpts, char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry)
+{
+ /*
+ * Make sure the path ends with a slash.
+ */
+ if (!cchPath || !RTPATH_IS_SLASH(pszPath[cchPath - 1]))
+ {
+ if (cchPath + 1 >= RTPATH_MAX)
+ return rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Buffer overflow fixing up '%s'.\n", pszPath);
+ pszPath[cchPath++] = RTPATH_SLASH;
+ pszPath[cchPath] = '\0';
+ }
+
+ /*
+ * Traverse the directory.
+ */
+ PRTDIR hDir;
+ int rc = RTDirOpen(&hDir, pszPath);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Error opening directory '%s': %Rrc", pszPath, rc);
+ int rcRet = VINF_SUCCESS;
+ for (;;)
+ {
+ /*
+ * Read the next entry, constructing an full path for it.
+ */
+ size_t cbEntry = RTPATHRM_DIR_MAX_ENTRY_SIZE;
+ rc = RTDirReadEx(hDir, pDirEntry, &cbEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+ if (rc == VERR_NO_MORE_FILES)
+ {
+ /*
+ * Reached the end of the directory.
+ */
+ pszPath[cchPath] = '\0';
+ rc = RTDirClose(hDir);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Error closing directory '%s': %Rrc", pszPath, rc);
+
+ /* Delete the directory. */
+ int rc2 = rtPathRmOneDir(pOpts, pszPath);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rcRet))
+ return rc2;
+ return rcRet;
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ rc = rtPathRmError(pOpts, pszPath, rc, "Error reading directory '%s': %Rrc", pszPath, rc);
+ break;
+ }
+
+ /* Skip '.' and '..'. */
+ if ( pDirEntry->szName[0] == '.'
+ && ( pDirEntry->cbName == 1
+ || ( pDirEntry->cbName == 2
+ && pDirEntry->szName[1] == '.')))
+ continue;
+
+ /* Construct full path. */
+ if (cchPath + pDirEntry->cbName >= RTPATH_MAX)
+ {
+ pszPath[cchPath] = '\0';
+ rc = rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Path buffer overflow in directory '%s'.", pszPath);
+ break;
+ }
+ memcpy(pszPath + cchPath, pDirEntry->szName, pDirEntry->cbName + 1);
+
+ /*
+ * Take action according to the type.
+ */
+ switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
+ {
+ case RTFS_TYPE_FILE:
+ rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info);
+ break;
+
+ case RTFS_TYPE_DIRECTORY:
+ rc = rtPathRmRecursive(pOpts, pszPath, cchPath + pDirEntry->cbName, pDirEntry);
+ break;
+
+ case RTFS_TYPE_SYMLINK:
+ rc = rtPathRmOneSymlink(pOpts, pszPath);
+ break;
+
+ case RTFS_TYPE_FIFO:
+ case RTFS_TYPE_DEV_CHAR:
+ case RTFS_TYPE_DEV_BLOCK:
+ case RTFS_TYPE_SOCKET:
+ rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info);
+ break;
+
+ case RTFS_TYPE_WHITEOUT:
+ default:
+ rc = rtPathRmError(pOpts, pszPath, VERR_UNEXPECTED_FS_OBJ_TYPE,
+ "Object '%s' has an unknown file type: %o\n",
+ pszPath, pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK);
+ break;
+ }
+ if (RT_FAILURE(rc) && RT_SUCCESS(rcRet))
+ rcRet = rc;
+ }
+
+ /*
+ * Some error occured, close and return.
+ */
+ RTDirClose(hDir);
+ return rc;
+}
+
+/**
+ * Validates the specified file or directory.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the file, directory, whatever.
+ */
+static int rtPathRmOneValidate(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ /*
+ * RTPathFilename doesn't do the trailing slash thing the way we need it to.
+ * E.g. both '..' and '../' should be rejected.
+ */
+ size_t cchPath = strlen(pszPath);
+ while (cchPath > 0 && RTPATH_IS_SLASH(pszPath[cchPath - 1]))
+ cchPath--;
+
+ if ( ( cchPath == 0
+ || 0 /** @todo drive letter + UNC crap */)
+ && pOpts->fPreserveRoot)
+ return rtPathRmError(pOpts, pszPath, VERR_CANT_DELETE_DIRECTORY, "Cannot remove root directory ('%s').\n", pszPath);
+
+ size_t offLast = cchPath - 1;
+ while (offLast > 0 && !RTPATH_IS_SEP(pszPath[offLast - 1]))
+ offLast--;
+
+ size_t cchLast = cchPath - offLast;
+ if ( pszPath[offLast] == '.'
+ && ( cchLast == 1
+ || (cchLast == 2 && pszPath[offLast + 1] == '.')))
+ return rtPathRmError(pOpts, pszPath, VERR_CANT_DELETE_DIRECTORY, "Cannot remove special directory '%s'.\n", pszPath);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Remove one user specified file or directory.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the file, directory, whatever.
+ */
+static int rtPathRmOne(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ /*
+ * RM refuses to delete some directories.
+ */
+ int rc = rtPathRmOneValidate(pOpts, pszPath);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Query file system object info.
+ */
+ RTFSOBJINFO ObjInfo;
+ rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
+ if (RT_FAILURE(rc))
+ {
+ if (pOpts->fForce && (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND))
+ return VINF_SUCCESS;
+ return rtPathRmError(pOpts, pszPath, rc, "Error deleting '%s': %Rrc", pszPath, rc);
+ }
+
+ /*
+ * Take type specific action.
+ */
+ switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
+ {
+ case RTFS_TYPE_FILE:
+ return rtPathRmOneFile(pOpts, pszPath, &ObjInfo);
+
+ case RTFS_TYPE_DIRECTORY:
+ if (pOpts->fRecursive)
+ {
+ char szPath[RTPATH_MAX];
+ rc = RTPathAbs(pszPath, szPath, sizeof(szPath));
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "RTPathAbs failed on '%s': %Rrc\n", pszPath, rc);
+
+ union
+ {
+ RTDIRENTRYEX Core;
+ uint8_t abPadding[RTPATHRM_DIR_MAX_ENTRY_SIZE];
+ } DirEntry;
+
+ return rtPathRmRecursive(pOpts, szPath, strlen(szPath), &DirEntry.Core);
+ }
+ if (pOpts->fDirsAndOther)
+ return rtPathRmOneDir(pOpts, pszPath);
+ return rtPathRmError(pOpts, pszPath, VERR_IS_A_DIRECTORY, "Cannot remove '%s': %Rrc\n", pszPath, VERR_IS_A_DIRECTORY);
+
+ case RTFS_TYPE_SYMLINK:
+ return rtPathRmOneSymlink(pOpts, pszPath);
+
+ case RTFS_TYPE_FIFO:
+ case RTFS_TYPE_DEV_CHAR:
+ case RTFS_TYPE_DEV_BLOCK:
+ case RTFS_TYPE_SOCKET:
+ return rtPathRmOneFile(pOpts, pszPath, &ObjInfo);
+
+ case RTFS_TYPE_WHITEOUT:
+ default:
+ return rtPathRmError(pOpts, pszPath, VERR_UNEXPECTED_FS_OBJ_TYPE,
+ "Object '%s' has an unknown file type: %o\n", pszPath, ObjInfo.Attr.fMode & RTFS_TYPE_MASK);
+
+ }
+}
+
+
+RTDECL(RTEXITCODE) RTPathRmCmd(unsigned cArgs, char **papszArgs)
+{
+ /*
+ * Parse the command line.
+ */
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ /* operations */
+ { "--dirs-and-more", 'd', RTGETOPT_REQ_NOTHING },
+ { "--force", 'f', RTGETOPT_REQ_NOTHING },
+ { "--prompt", 'i', RTGETOPT_REQ_NOTHING },
+ { "--prompt-once", 'I', RTGETOPT_REQ_NOTHING },
+ { "--interactive", RTPATHRMCMD_OPT_INTERACTIVE, RTGETOPT_REQ_STRING },
+ { "--one-file-system", RTPATHRMCMD_OPT_ONE_FILE_SYSTEM, RTGETOPT_REQ_NOTHING },
+ { "--preserve-root", RTPATHRMCMD_OPT_PRESERVE_ROOT, RTGETOPT_REQ_NOTHING },
+ { "--no-preserve-root", RTPATHRMCMD_OPT_NO_PRESERVE_ROOT, RTGETOPT_REQ_NOTHING },
+ { "--recursive", 'R', RTGETOPT_REQ_NOTHING },
+ { "--recursive", 'r', RTGETOPT_REQ_NOTHING },
+ { "--safe-delete", 'P', RTGETOPT_REQ_NOTHING },
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+
+ /* IPRT extensions */
+ { "--machine-readable", RTPATHRMCMD_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING },
+ { "--machinereadable", RTPATHRMCMD_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING }, /* bad long option style */
+ };
+
+ RTGETOPTSTATE GetState;
+ int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
+ RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc);
+
+ RTPATHRMCMDOPTS Opts;
+ RT_ZERO(Opts);
+ Opts.fPreserveRoot = true;
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_NONE;
+
+ RTGETOPTUNION ValueUnion;
+ while ( (rc = RTGetOpt(&GetState, &ValueUnion)) != 0
+ && rc != VINF_GETOPT_NOT_OPTION)
+ {
+ switch (rc)
+ {
+ case 'd':
+ Opts.fDirsAndOther = true;
+ break;
+
+ case 'f':
+ Opts.fForce = true;
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_NONE;
+ break;
+
+ case 'i':
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ALL;
+ break;
+
+ case 'I':
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ONCE;
+ break;
+
+ case RTPATHRMCMD_OPT_INTERACTIVE:
+ if (!strcmp(ValueUnion.psz, "always"))
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ALL;
+ else if (!strcmp(ValueUnion.psz, "once"))
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ONCE;
+ else
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown --interactive option value: '%s'\n", ValueUnion.psz);
+ break;
+
+ case RTPATHRMCMD_OPT_ONE_FILE_SYSTEM:
+ Opts.fOneFileSystem = true;
+ break;
+
+ case RTPATHRMCMD_OPT_PRESERVE_ROOT:
+ Opts.fPreserveRoot = true;
+ break;
+
+ case RTPATHRMCMD_OPT_NO_PRESERVE_ROOT:
+ Opts.fPreserveRoot = false;
+ break;
+
+ case 'R':
+ case 'r':
+ Opts.fRecursive = true;
+ Opts.fDirsAndOther = true;
+ break;
+
+ case 'P':
+ Opts.fSafeDelete = true;
+ break;
+
+ case 'v':
+ Opts.fVerbose = true;
+ break;
+
+
+ case RTPATHRMCMD_OPT_MACHINE_READABLE:
+ Opts.fMachineReadable = true;
+ break;
+
+ case 'h':
+ RTPrintf("Usage: to be written\nOption dump:\n");
+ for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
+ if (RT_C_IS_PRINT(s_aOptions[i].iShort))
+ RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
+ else
+ RTPrintf(" %s\n", s_aOptions[i].pszLong);
+ return RTEXITCODE_SUCCESS;
+
+ case 'V':
+ RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
+ return RTEXITCODE_SUCCESS;
+
+ default:
+ return RTGetOptPrintError(rc, &ValueUnion);
+ }
+ }
+
+ /*
+ * Options we don't support.
+ */
+ if (Opts.fOneFileSystem)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "The --one-file-system option is not yet implemented.\n");
+ if (Opts.enmInteractive != RTPATHRMCMDINTERACTIVE_NONE)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "The -i, -I and --interactive options are not implemented yet.\n");
+
+ /*
+ * No files means error.
+ */
+ if (rc != VINF_GETOPT_NOT_OPTION && !Opts.fForce)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "No files or directories specified.\n");
+
+ /*
+ * Machine readable init + header.
+ */
+ if (Opts.fMachineReadable)
+ {
+ rc = RTStrmSetMode(g_pStdOut, true /*fBinary*/, false /*fCurrentCodeSet*/);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTStrmSetMode failed: %Rrc.\n", rc);
+ static const char s_achHeader[] = "hdr_id=rm\0hdr_ver=1";
+ RTStrmWrite(g_pStdOut, s_achHeader, sizeof(s_achHeader));
+ }
+
+ /*
+ * Delete the specified files/dirs/whatever.
+ */
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ while (rc == VINF_GETOPT_NOT_OPTION)
+ {
+ rc = rtPathRmOne(&Opts, ValueUnion.psz);
+ if (RT_FAILURE(rc))
+ rcExit = RTEXITCODE_FAILURE;
+
+ /* next */
+ rc = RTGetOpt(&GetState, &ValueUnion);
+ }
+ if (rc != 0)
+ rcExit = RTGetOptPrintError(rc, &ValueUnion);
+
+ /*
+ * Terminate the machine readable stuff.
+ */
+ if (Opts.fMachineReadable)
+ {
+ RTStrmWrite(g_pStdOut, "\0\0\0", 4);
+ rc = RTStrmFlush(g_pStdOut);
+ if (RT_FAILURE(rc) && rcExit == RTEXITCODE_SUCCESS)
+ rcExit = RTEXITCODE_FAILURE;
+ }
+
+ return rcExit;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathSplit.cpp b/src/VBox/Runtime/common/path/RTPathSplit.cpp
new file mode 100644
index 00000000..6c528ce1
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathSplit.cpp
@@ -0,0 +1,133 @@
+/* $Id: RTPathSplit.cpp $ */
+/** @file
+ * IPRT - RTPathSplit
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+
+
+RTDECL(int) RTPathSplit(const char *pszPath, PRTPATHSPLIT pSplit, size_t cbSplit, uint32_t fFlags)
+{
+ /*
+ * Input validation.
+ */
+ AssertReturn(cbSplit >= RT_UOFFSETOF(RTPATHSPLIT, apszComps), VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pSplit, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(*pszPath, VERR_PATH_ZERO_LENGTH);
+ AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0), VERR_INVALID_FLAGS);
+
+ /*
+ * Use RTPathParse to do the parsing.
+ * - This makes the ASSUMPTION that the output of this function is greater
+ * or equal to that of RTPathParsed.
+ * - We're aliasing the buffer here, so use volatile to avoid issues due to
+ * compiler optimizations.
+ */
+ RTPATHPARSED volatile *pParsedVolatile = (RTPATHPARSED volatile *)pSplit;
+ RTPATHSPLIT volatile *pSplitVolatile = (RTPATHSPLIT volatile *)pSplit;
+
+ AssertCompile(sizeof(*pParsedVolatile) <= sizeof(*pSplitVolatile));
+ AssertCompile(sizeof(pParsedVolatile->aComps[0]) <= sizeof(pSplitVolatile->apszComps[0]));
+
+ int rc = RTPathParse(pszPath, (PRTPATHPARSED)pParsedVolatile, cbSplit, fFlags);
+ if (RT_FAILURE(rc) && rc != VERR_BUFFER_OVERFLOW)
+ return rc;
+
+ /*
+ * Calculate the required buffer space.
+ */
+ uint16_t const cComps = pParsedVolatile->cComps;
+ uint16_t const fProps = pParsedVolatile->fProps;
+ uint16_t const cchPath = pParsedVolatile->cchPath;
+ uint16_t const offSuffix = pParsedVolatile->offSuffix;
+ uint32_t cbNeeded = RT_OFFSETOF(RTPATHSPLIT, apszComps[cComps])
+ + cchPath
+ + RTPATH_PROP_FIRST_NEEDS_NO_SLASH(fProps) /* zero terminator for root spec. */
+ - RT_BOOL(fProps & RTPATH_PROP_DIR_SLASH) /* counted by cchPath, not included in the comp str. */
+ + 1; /* zero terminator. */
+ if (cbNeeded > cbSplit)
+ {
+ pSplitVolatile->cbNeeded = cbNeeded;
+ return VERR_BUFFER_OVERFLOW;
+ }
+ Assert(RT_SUCCESS(rc));
+
+ /*
+ * Convert the array and copy the strings, both backwards.
+ */
+ char *psz = (char *)pSplit + cbNeeded;
+ uint32_t idxComp = cComps - 1;
+
+ /* the final component first (because of suffix handling). */
+ uint16_t offComp = pParsedVolatile->aComps[idxComp].off;
+ uint16_t cchComp = pParsedVolatile->aComps[idxComp].cch;
+
+ *--psz = '\0';
+ psz -= cchComp;
+ memcpy(psz, &pszPath[offComp], cchComp);
+ pSplitVolatile->apszComps[idxComp] = psz;
+
+ char *pszSuffix;
+ if (offSuffix >= offComp + cchComp)
+ pszSuffix = &psz[cchComp];
+ else
+ pszSuffix = &psz[offSuffix - offComp];
+
+ /* the remainder */
+ while (idxComp-- > 0)
+ {
+ offComp = pParsedVolatile->aComps[idxComp].off;
+ cchComp = pParsedVolatile->aComps[idxComp].cch;
+ *--psz = '\0';
+ psz -= cchComp;
+ memcpy(psz, &pszPath[offComp], cchComp);
+ pSplitVolatile->apszComps[idxComp] = psz;
+ }
+
+ /*
+ * Store / reshuffle the non-array bits. This MUST be done after finishing
+ * the array processing because there may be members in RTPATHSPLIT
+ * overlapping the array of RTPATHPARSED.
+ */
+ AssertCompileMembersSameSizeAndOffset(RTPATHPARSED, cComps, RTPATHSPLIT, cComps); Assert(pSplitVolatile->cComps == cComps);
+ AssertCompileMembersSameSizeAndOffset(RTPATHPARSED, fProps, RTPATHSPLIT, fProps); Assert(pSplitVolatile->fProps == fProps);
+ AssertCompileMembersSameSizeAndOffset(RTPATHPARSED, cchPath, RTPATHSPLIT, cchPath); Assert(pSplitVolatile->cchPath == cchPath);
+ pSplitVolatile->u16Reserved = 0;
+ pSplitVolatile->cbNeeded = cbNeeded;
+ pSplitVolatile->pszSuffix = pszSuffix;
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathSplitA.cpp b/src/VBox/Runtime/common/path/RTPathSplitA.cpp
new file mode 100644
index 00000000..e29d315d
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathSplitA.cpp
@@ -0,0 +1,91 @@
+/* $Id: RTPathSplitA.cpp $ */
+/** @file
+ * IPRT - RTPathSplitA and RTPathSplitFree.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+
+
+
+RTDECL(int) RTPathSplitATag(const char *pszPath, PRTPATHSPLIT *ppSplit, uint32_t fFlags, const char *pszTag)
+{
+ AssertPtrReturn(ppSplit, VERR_INVALID_POINTER);
+ *ppSplit = NULL;
+
+ /*
+ * Try estimate a reasonable buffer size based on the path length.
+ * Note! No point in trying very hard to get it right.
+ */
+ size_t cbSplit = strlen(pszPath);
+ cbSplit += RT_OFFSETOF(RTPATHSPLIT, apszComps[cbSplit / 8]) + cbSplit / 8 + 8;
+ cbSplit = RT_ALIGN(cbSplit, 64);
+ PRTPATHSPLIT pSplit = (PRTPATHSPLIT)RTMemAllocTag(cbSplit, pszTag);
+ if (pSplit == NULL)
+ return VERR_NO_MEMORY;
+
+ /*
+ * First try. If it fails due to buffer, reallocate the buffer and try again.
+ */
+ int rc = RTPathSplit(pszPath, pSplit, cbSplit, fFlags);
+ if (rc == VERR_BUFFER_OVERFLOW)
+ {
+ cbSplit = RT_ALIGN(pSplit->cbNeeded, 64);
+ RTMemFree(pSplit);
+
+ pSplit = (PRTPATHSPLIT)RTMemAllocTag(cbSplit, pszTag);
+ if (pSplit == NULL)
+ return VERR_NO_MEMORY;
+ rc = RTPathSplit(pszPath, pSplit, cbSplit, fFlags);
+ }
+
+ /*
+ * Done (one way or the other).
+ */
+ if (RT_SUCCESS(rc))
+ *ppSplit = pSplit;
+ else
+ RTMemFree(pSplit);
+ return rc;
+}
+
+
+RTDECL(void) RTPathSplitFree(PRTPATHSPLIT pSplit)
+{
+ if (pSplit)
+ {
+ Assert(pSplit->u16Reserved = UINT16_C(0xbeef));
+ RTMemFree(pSplit);
+ }
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathSplitReassemble.cpp b/src/VBox/Runtime/common/path/RTPathSplitReassemble.cpp
new file mode 100644
index 00000000..8d703171
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathSplitReassemble.cpp
@@ -0,0 +1,120 @@
+/* $Id: RTPathSplitReassemble.cpp $ */
+/** @file
+ * IPRT - RTPathSplitReassemble.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTPathSplitReassemble(PRTPATHSPLIT pSplit, uint32_t fFlags, char *pszDstPath, size_t cbDstPath)
+{
+ /*
+ * Input validation.
+ */
+ AssertPtrReturn(pSplit, VERR_INVALID_POINTER);
+ AssertReturn(pSplit->cComps > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0) && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS);
+ AssertPtrReturn(pszDstPath, VERR_INVALID_POINTER);
+ AssertReturn(cbDstPath > pSplit->cchPath, VERR_BUFFER_OVERFLOW);
+
+ /*
+ * Figure which slash to use.
+ */
+ char chSlash;
+ switch (fFlags & RTPATH_STR_F_STYLE_MASK)
+ {
+ case RTPATH_STR_F_STYLE_HOST:
+ chSlash = RTPATH_SLASH;
+ break;
+
+ case RTPATH_STR_F_STYLE_DOS:
+ chSlash = '\\';
+ break;
+
+ case RTPATH_STR_F_STYLE_UNIX:
+ chSlash = '/';
+ break;
+
+ default:
+ AssertFailedReturn(VERR_INVALID_FLAGS); /* impossible */
+ }
+
+ /*
+ * Do the joining.
+ */
+ uint32_t const cchOrgPath = pSplit->cchPath;
+ size_t cchDstPath = 0;
+ uint32_t const cComps = pSplit->cComps;
+ uint32_t idxComp = 0;
+ char *pszDst = pszDstPath;
+ size_t cchComp;
+
+ if (RTPATH_PROP_HAS_ROOT_SPEC(pSplit->fProps))
+ {
+ cchComp = strlen(pSplit->apszComps[0]);
+ cchDstPath += cchComp;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ memcpy(pszDst, pSplit->apszComps[0], cchComp);
+
+ /* fix the slashes */
+ char chOtherSlash = chSlash == '\\' ? '/' : '\\';
+ while (cchComp-- > 0)
+ {
+ if (*pszDst == chOtherSlash)
+ *pszDst = chSlash;
+ pszDst++;
+ }
+ idxComp = 1;
+ }
+
+ while (idxComp < cComps)
+ {
+ cchComp = strlen(pSplit->apszComps[idxComp]);
+ cchDstPath += cchComp;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ memcpy(pszDst, pSplit->apszComps[idxComp], cchComp);
+ pszDst += cchComp;
+ idxComp++;
+ if (idxComp != cComps || (pSplit->fProps & RTPATH_PROP_DIR_SLASH))
+ {
+ cchDstPath++;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ *pszDst++ = chSlash;
+ }
+ }
+
+ *pszDst = '\0';
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathStripExt.cpp b/src/VBox/Runtime/common/path/RTPathStripExt.cpp
index 789bb3e9..8156f6a0 100644
--- a/src/VBox/Runtime/common/path/RTPathStripExt.cpp
+++ b/src/VBox/Runtime/common/path/RTPathStripExt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathStripFilename.cpp b/src/VBox/Runtime/common/path/RTPathStripFilename.cpp
index 3db34165..b2647833 100644
--- a/src/VBox/Runtime/common/path/RTPathStripFilename.cpp
+++ b/src/VBox/Runtime/common/path/RTPathStripFilename.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathTraverseList.cpp b/src/VBox/Runtime/common/path/RTPathTraverseList.cpp
index daa88dce..361b0f82 100644
--- a/src/VBox/Runtime/common/path/RTPathTraverseList.cpp
+++ b/src/VBox/Runtime/common/path/RTPathTraverseList.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/comparepaths.cpp b/src/VBox/Runtime/common/path/comparepaths.cpp
index 40271362..bfa5e71c 100644
--- a/src/VBox/Runtime/common/path/comparepaths.cpp
+++ b/src/VBox/Runtime/common/path/comparepaths.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp b/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp
index 92c91136..9cdbb400 100644
--- a/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp
+++ b/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp
@@ -54,7 +54,7 @@ DECLHIDDEN(size_t) rtPathRootSpecLen(const char *pszPath)
size_t off = 0;
if (RTPATH_IS_SLASH(pszPath[0]))
{
-#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
if ( RTPATH_IS_SLASH(pszPath[1])
&& !RTPATH_IS_SLASH(pszPath[2])
&& pszPath[2])
@@ -78,7 +78,7 @@ DECLHIDDEN(size_t) rtPathRootSpecLen(const char *pszPath)
while (RTPATH_IS_SLASH(pszPath[off]))
off++;
}
-#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
else if (RT_C_IS_ALPHA(pszPath[0]) && pszPath[1] == ':')
{
off = 2;
diff --git a/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp b/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp
index c80c7976..5e95e5d9 100644
--- a/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp
+++ b/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/rtpath-expand-template.cpp.h b/src/VBox/Runtime/common/path/rtpath-expand-template.cpp.h
new file mode 100644
index 00000000..3797733a
--- /dev/null
+++ b/src/VBox/Runtime/common/path/rtpath-expand-template.cpp.h
@@ -0,0 +1,82 @@
+/* $Id: rtpath-expand-template.cpp.h $ */
+/** @file
+ * IPRT - RTPath - Internal header that includes RTPATH_TEMPLATE_CPP_H multiple
+ * times to expand the code for different path styles.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#undef RTPATH_DELIMITER
+
+/*
+ * DOS style
+ */
+#undef RTPATH_STYLE
+#undef RTPATH_SLASH
+#undef RTPATH_SLASH_STR
+#undef RTPATH_IS_SLASH
+#undef RTPATH_IS_VOLSEP
+#undef RTPATH_STYLE_FN
+
+#define RTPATH_STYLE RTPATH_STR_F_STYLE_DOS
+#define RTPATH_SLASH '\\'
+#define RTPATH_SLASH_STR "\\"
+#define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '\\' || (a_ch) == '/' )
+#define RTPATH_IS_VOLSEP(a_ch) ( (a_ch) == ':' )
+#define RTPATH_STYLE_FN(a_Name) a_Name ## StyleDos
+#include RTPATH_TEMPLATE_CPP_H
+
+/*
+ * Unix style.
+ */
+#undef RTPATH_STYLE
+#undef RTPATH_SLASH
+#undef RTPATH_SLASH_STR
+#undef RTPATH_IS_SLASH
+#undef RTPATH_IS_VOLSEP
+#undef RTPATH_STYLE_FN
+
+#define RTPATH_STYLE RTPATH_STR_F_STYLE_UNIX
+#define RTPATH_SLASH '/'
+#define RTPATH_SLASH_STR "/"
+#define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '/' )
+#define RTPATH_IS_VOLSEP(a_ch) ( false )
+#define RTPATH_STYLE_FN(a_Name) a_Name ## StyleUnix
+#include RTPATH_TEMPLATE_CPP_H
+
+/*
+ * Clean up and restore the host style.
+ */
+#undef RTPATH_STYLE_FN
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+# undef RTPATH_STYLE
+# undef RTPATH_SLASH
+# undef RTPATH_SLASH_STR
+# undef RTPATH_IS_SLASH
+# undef RTPATH_IS_VOLSEP
+# define RTPATH_STYLE RTPATH_STR_F_STYLE_DOS
+# define RTPATH_SLASH '\\'
+# define RTPATH_SLASH_STR "\\"
+# define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '\\' || (a_ch) == '/' )
+# define RTPATH_IS_VOLSEP(a_ch) ( (a_ch) == ':' )
+#endif
+
diff --git a/src/VBox/Runtime/common/rand/rand.cpp b/src/VBox/Runtime/common/rand/rand.cpp
index beb195e4..75637eb7 100644
--- a/src/VBox/Runtime/common/rand/rand.cpp
+++ b/src/VBox/Runtime/common/rand/rand.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -55,10 +55,9 @@ static RTRAND g_hRand = NIL_RTRAND;
* Perform lazy initialization.
*
* @returns IPRT status code.
- * @param pvUser1 Ignored.
- * @param pvUser2 Ignored.
+ * @param pvUser Ignored.
*/
-static DECLCALLBACK(int) rtRandInitOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int) rtRandInitOnce(void *pvUser)
{
RTRAND hRand;
int rc = RTRandAdvCreateSystemFaster(&hRand);
@@ -76,15 +75,14 @@ static DECLCALLBACK(int) rtRandInitOnce(void *pvUser1, void *pvUser2)
else
AssertRC(rc);
- NOREF(pvUser1);
- NOREF(pvUser2);
+ NOREF(pvUser);
return rc;
}
RTDECL(void) RTRandBytes(void *pv, size_t cb) RT_NO_THROW
{
- RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
+ RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL);
RTRandAdvBytes(g_hRand, pv, cb);
}
RT_EXPORT_SYMBOL(RTRandBytes);
@@ -92,7 +90,7 @@ RT_EXPORT_SYMBOL(RTRandBytes);
RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last) RT_NO_THROW
{
- RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
+ RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL);
return RTRandAdvU32Ex(g_hRand, u32First, u32Last);
}
RT_EXPORT_SYMBOL(RTRandU32Ex);
@@ -100,7 +98,7 @@ RT_EXPORT_SYMBOL(RTRandU32Ex);
RTDECL(uint32_t) RTRandU32(void) RT_NO_THROW
{
- RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
+ RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL);
return RTRandAdvU32(g_hRand);
}
RT_EXPORT_SYMBOL(RTRandU32);
@@ -108,7 +106,7 @@ RT_EXPORT_SYMBOL(RTRandU32);
RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last) RT_NO_THROW
{
- RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
+ RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL);
return RTRandAdvS32Ex(g_hRand, i32First, i32Last);
}
RT_EXPORT_SYMBOL(RTRandS32Ex);
@@ -116,7 +114,7 @@ RT_EXPORT_SYMBOL(RTRandS32Ex);
RTDECL(int32_t) RTRandS32(void) RT_NO_THROW
{
- RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
+ RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL);
return RTRandAdvS32(g_hRand);
}
RT_EXPORT_SYMBOL(RTRandS32);
@@ -124,7 +122,7 @@ RT_EXPORT_SYMBOL(RTRandS32);
RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last) RT_NO_THROW
{
- RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
+ RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL);
return RTRandAdvU64Ex(g_hRand, u64First, u64Last);
}
RT_EXPORT_SYMBOL(RTRandU64Ex);
@@ -132,7 +130,7 @@ RT_EXPORT_SYMBOL(RTRandU64Ex);
RTDECL(uint64_t) RTRandU64(void) RT_NO_THROW
{
- RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
+ RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL);
return RTRandAdvU64(g_hRand);
}
RT_EXPORT_SYMBOL(RTRandU64);
@@ -140,7 +138,7 @@ RT_EXPORT_SYMBOL(RTRandU64);
RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last) RT_NO_THROW
{
- RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
+ RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL);
return RTRandAdvS64Ex(g_hRand, i64First, i64Last);
}
RT_EXPORT_SYMBOL(RTRandS64Ex);
@@ -148,7 +146,7 @@ RT_EXPORT_SYMBOL(RTRandS64Ex);
RTDECL(int64_t) RTRandS64(void) RT_NO_THROW
{
- RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
+ RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL);
return RTRandAdvS32(g_hRand);
}
RT_EXPORT_SYMBOL(RTRandS64);
diff --git a/src/VBox/Runtime/common/rand/randadv.cpp b/src/VBox/Runtime/common/rand/randadv.cpp
index e4506c0a..feff3356 100644
--- a/src/VBox/Runtime/common/rand/randadv.cpp
+++ b/src/VBox/Runtime/common/rand/randadv.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/rand/randparkmiller.cpp b/src/VBox/Runtime/common/rand/randparkmiller.cpp
index 4c0f3fd1..4a429045 100644
--- a/src/VBox/Runtime/common/rand/randparkmiller.cpp
+++ b/src/VBox/Runtime/common/rand/randparkmiller.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/RTStrCmp.cpp b/src/VBox/Runtime/common/string/RTStrCmp.cpp
index 779675f0..598a1869 100644
--- a/src/VBox/Runtime/common/string/RTStrCmp.cpp
+++ b/src/VBox/Runtime/common/string/RTStrCmp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/RTStrNCmp.cpp b/src/VBox/Runtime/common/string/RTStrNCmp.cpp
index 5070218a..5880c8ff 100644
--- a/src/VBox/Runtime/common/string/RTStrNCmp.cpp
+++ b/src/VBox/Runtime/common/string/RTStrNCmp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -41,7 +41,22 @@ RTDECL(int) RTStrNCmp(const char *psz1, const char *psz2, size_t cchMax)
if (!psz2)
return 1;
+#ifdef RT_OS_SOLARIS
+ /* Solaris: tstUtf8 found to fail for some RTSTR_MAX on testboxsh1:
+ solaris.amd64 v5.10 (Generic_142901-12 (Assembled 30 March 2009)). */
+ while (cchMax-- > 0)
+ {
+ char ch1 = *psz1++;
+ char ch2 = *psz2++;
+ if (ch1 != ch2)
+ return ch1 > ch2 ? 1 : -1;
+ else if (ch1 == 0)
+ break;
+ }
+ return 0;
+#else
return strncmp(psz1, psz2, cchMax);
+#endif
}
RT_EXPORT_SYMBOL(RTStrNCmp);
diff --git a/src/VBox/Runtime/common/string/RTStrNLen.cpp b/src/VBox/Runtime/common/string/RTStrNLen.cpp
index d30c9ed5..777c7509 100644
--- a/src/VBox/Runtime/common/string/RTStrNLen.cpp
+++ b/src/VBox/Runtime/common/string/RTStrNLen.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/RTStrNLenEx.cpp b/src/VBox/Runtime/common/string/RTStrNLenEx.cpp
index 3764ce35..19e18152 100644
--- a/src/VBox/Runtime/common/string/RTStrNLenEx.cpp
+++ b/src/VBox/Runtime/common/string/RTStrNLenEx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp b/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp
index f00298e5..492f2f49 100644
--- a/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp
+++ b/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/RTStrStr.cpp b/src/VBox/Runtime/common/string/RTStrStr.cpp
index 903826e1..a6555bf5 100644
--- a/src/VBox/Runtime/common/string/RTStrStr.cpp
+++ b/src/VBox/Runtime/common/string/RTStrStr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/base64.cpp b/src/VBox/Runtime/common/string/base64.cpp
index 514d4474..96269644 100644
--- a/src/VBox/Runtime/common/string/base64.cpp
+++ b/src/VBox/Runtime/common/string/base64.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memchr.asm b/src/VBox/Runtime/common/string/memchr.asm
index 0ee2968d..95fd1654 100644
--- a/src/VBox/Runtime/common/string/memchr.asm
+++ b/src/VBox/Runtime/common/string/memchr.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memchr.cpp b/src/VBox/Runtime/common/string/memchr.cpp
index ba2de095..abfa379d 100644
--- a/src/VBox/Runtime/common/string/memchr.cpp
+++ b/src/VBox/Runtime/common/string/memchr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memchr_alias.c b/src/VBox/Runtime/common/string/memchr_alias.c
index 0d009c7d..90929549 100644
--- a/src/VBox/Runtime/common/string/memchr_alias.c
+++ b/src/VBox/Runtime/common/string/memchr_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcmp.asm b/src/VBox/Runtime/common/string/memcmp.asm
index afadf923..5176dfed 100644
--- a/src/VBox/Runtime/common/string/memcmp.asm
+++ b/src/VBox/Runtime/common/string/memcmp.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcmp.cpp b/src/VBox/Runtime/common/string/memcmp.cpp
index 3dea769e..6ccf9b1f 100644
--- a/src/VBox/Runtime/common/string/memcmp.cpp
+++ b/src/VBox/Runtime/common/string/memcmp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcmp_alias.c b/src/VBox/Runtime/common/string/memcmp_alias.c
index 30f78637..6a4337b8 100644
--- a/src/VBox/Runtime/common/string/memcmp_alias.c
+++ b/src/VBox/Runtime/common/string/memcmp_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcpy.asm b/src/VBox/Runtime/common/string/memcpy.asm
index 6f1bed22..b8f94df5 100644
--- a/src/VBox/Runtime/common/string/memcpy.asm
+++ b/src/VBox/Runtime/common/string/memcpy.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcpy.cpp b/src/VBox/Runtime/common/string/memcpy.cpp
index 56ccdfb2..d04cfe04 100644
--- a/src/VBox/Runtime/common/string/memcpy.cpp
+++ b/src/VBox/Runtime/common/string/memcpy.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcpy_alias.c b/src/VBox/Runtime/common/string/memcpy_alias.c
index 5ddc7b8c..ecea9ae3 100644
--- a/src/VBox/Runtime/common/string/memcpy_alias.c
+++ b/src/VBox/Runtime/common/string/memcpy_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memmove.asm b/src/VBox/Runtime/common/string/memmove.asm
index b10ede77..c52d988e 100644
--- a/src/VBox/Runtime/common/string/memmove.asm
+++ b/src/VBox/Runtime/common/string/memmove.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2008 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memmove_alias.c b/src/VBox/Runtime/common/string/memmove_alias.c
index f30c9149..1fc2e0ce 100644
--- a/src/VBox/Runtime/common/string/memmove_alias.c
+++ b/src/VBox/Runtime/common/string/memmove_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/mempcpy.asm b/src/VBox/Runtime/common/string/mempcpy.asm
index b47c4368..157a63db 100644
--- a/src/VBox/Runtime/common/string/mempcpy.asm
+++ b/src/VBox/Runtime/common/string/mempcpy.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memset.asm b/src/VBox/Runtime/common/string/memset.asm
index 96cc48ec..a2d562ba 100644
--- a/src/VBox/Runtime/common/string/memset.asm
+++ b/src/VBox/Runtime/common/string/memset.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memset.cpp b/src/VBox/Runtime/common/string/memset.cpp
index 9bf35893..9935bef5 100644
--- a/src/VBox/Runtime/common/string/memset.cpp
+++ b/src/VBox/Runtime/common/string/memset.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memset_alias.c b/src/VBox/Runtime/common/string/memset_alias.c
index 49d4abd3..64793471 100644
--- a/src/VBox/Runtime/common/string/memset_alias.c
+++ b/src/VBox/Runtime/common/string/memset_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/simplepattern.cpp b/src/VBox/Runtime/common/string/simplepattern.cpp
index f54d4ce0..6f6bdd2b 100644
--- a/src/VBox/Runtime/common/string/simplepattern.cpp
+++ b/src/VBox/Runtime/common/string/simplepattern.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/straprintf.cpp b/src/VBox/Runtime/common/string/straprintf.cpp
index a0ee0350..a09abd33 100644
--- a/src/VBox/Runtime/common/string/straprintf.cpp
+++ b/src/VBox/Runtime/common/string/straprintf.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcache.cpp b/src/VBox/Runtime/common/string/strcache.cpp
index 642d5836..e452a4a7 100644
--- a/src/VBox/Runtime/common/string/strcache.cpp
+++ b/src/VBox/Runtime/common/string/strcache.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,12 +31,93 @@
#include <iprt/strcache.h>
#include "internal/iprt.h"
+#include <iprt/alloca.h>
#include <iprt/asm.h>
#include <iprt/assert.h>
+#include <iprt/critsect.h>
#include <iprt/err.h>
-#include <iprt/mempool.h>
-#include <iprt/string.h>
+#include <iprt/list.h>
+#include <iprt/mem.h>
#include <iprt/once.h>
+#include <iprt/param.h>
+#include <iprt/string.h>
+
+#include "internal/strhash.h"
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** Special NIL pointer for the hash table. It differs from NULL in that it is
+ * a valid hash table entry when doing a lookup. */
+#define PRTSTRCACHEENTRY_NIL ((PRTSTRCACHEENTRY)~(uintptr_t)1)
+
+/** Calcuates the increment when handling a collision.
+ * The current formula makes sure it's always odd so we cannot possibly end
+ * up a cyclic loop with an even sized table. It also takes more bits from
+ * the length part. */
+#define RTSTRCACHE_COLLISION_INCR(uHashLen) ( ((uHashLen >> 8) | 1) )
+
+/** The initial hash table size. Must be power of two. */
+#define RTSTRCACHE_INITIAL_HASH_SIZE 512
+/** The hash table growth factor. */
+#define RTSTRCACHE_HASH_GROW_FACTOR 4
+
+/**
+ * The RTSTRCACHEENTRY size threshold at which we stop using our own allocator
+ * and switch to the application heap, expressed as a power of two.
+ *
+ * Using a 1KB as a reasonable limit here.
+ */
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+# define RTSTRCACHE_HEAP_THRESHOLD_BIT 10
+#else
+# define RTSTRCACHE_HEAP_THRESHOLD_BIT 9
+#endif
+/** The RTSTRCACHE_HEAP_THRESHOLD_BIT as a byte limit. */
+#define RTSTRCACHE_HEAP_THRESHOLD RT_BIT_32(RTSTRCACHE_HEAP_THRESHOLD_BIT)
+/** Big (heap) entry size alignment. */
+#define RTSTRCACHE_HEAP_ENTRY_SIZE_ALIGN 16
+
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+/**
+ * The RTSTRCACHEENTRY size threshold at which we start using the merge free
+ * list for allocations, expressed as a power of two.
+ */
+# define RTSTRCACHE_MERGED_THRESHOLD_BIT 6
+
+/** The number of bytes (power of two) that the merged allocation lists should
+ * be grown by. Must be much greater than RTSTRCACHE_MERGED_THRESHOLD. */
+# define RTSTRCACHE_MERGED_GROW_SIZE _32K
+#endif
+
+/** The number of bytes (power of two) that the fixed allocation lists should
+ * be grown by. */
+#define RTSTRCACHE_FIXED_GROW_SIZE _32K
+
+/** The number of fixed sized lists. */
+#define RTSTRCACHE_NUM_OF_FIXED_SIZES 12
+
+
+/** Validates a string cache handle, translating RTSTRCACHE_DEFAULT when found,
+ * and returns rc if not valid. */
+#define RTSTRCACHE_VALID_RETURN_RC(pStrCache, rc) \
+ do { \
+ if ((pStrCache) == RTSTRCACHE_DEFAULT) \
+ { \
+ int rcOnce = RTOnce(&g_rtStrCacheOnce, rtStrCacheInitDefault, NULL); \
+ if (RT_FAILURE(rcOnce)) \
+ return (rc); \
+ (pStrCache) = g_hrtStrCacheDefault; \
+ } \
+ else \
+ { \
+ AssertPtrReturn((pStrCache), (rc)); \
+ AssertReturn((pStrCache)->u32Magic == RTSTRCACHE_MAGIC, (rc)); \
+ } \
+ } while (0)
+
/*******************************************************************************
@@ -44,117 +125,790 @@
*******************************************************************************/
/**
* String cache entry.
- *
- * Each entry is
*/
typedef struct RTSTRCACHEENTRY
{
/** The number of references. */
uint32_t volatile cRefs;
- /** Offset into the chunk (bytes). */
- uint32_t offChunk;
- /** The string length. */
- uint32_t cch;
- /** The primary hash value. */
- uint32_t uHash1;
+ /** The lower 16-bit hash value. */
+ uint16_t uHash;
+ /** The string length (excluding the terminator).
+ * If this is set to RTSTRCACHEENTRY_BIG_LEN, this is a BIG entry
+ * (RTSTRCACHEBIGENTRY). */
+ uint16_t cchString;
/** The string. */
- char szString[16];
+ char szString[8];
} RTSTRCACHEENTRY;
-AssertCompileSize(RTSTRCACHEENTRY, 32);
+AssertCompileSize(RTSTRCACHEENTRY, 16);
/** Pointer to a string cache entry. */
typedef RTSTRCACHEENTRY *PRTSTRCACHEENTRY;
/** Pointer to a const string cache entry. */
typedef RTSTRCACHEENTRY *PCRTSTRCACHEENTRY;
+/** RTSTCACHEENTRY::cchString value for big cache entries. */
+#define RTSTRCACHEENTRY_BIG_LEN UINT16_MAX
+
+/**
+ * Big string cache entry.
+ *
+ * These are allocated individually from the application heap.
+ */
+typedef struct RTSTRCACHEBIGENTRY
+{
+ /** List entry. */
+ RTLISTNODE ListEntry;
+ /** The string length. */
+ uint32_t cchString;
+ /** The full hash value / padding. */
+ uint32_t uHash;
+ /** The core entry. */
+ RTSTRCACHEENTRY Core;
+} RTSTRCACHEBIGENTRY;
+AssertCompileSize(RTSTRCACHEENTRY, 16);
+/** Pointer to a big string cache entry. */
+typedef RTSTRCACHEBIGENTRY *PRTSTRCACHEBIGENTRY;
+/** Pointer to a const big string cache entry. */
+typedef RTSTRCACHEBIGENTRY *PCRTSTRCACHEBIGENTRY;
+
+
/**
- * Allocation chunk.
+ * A free string cache entry.
+ */
+typedef struct RTSTRCACHEFREE
+{
+ /** Zero value indicating that it's a free entry (no refs, no hash). */
+ uint32_t uZero;
+ /** Number of free bytes. Only used for > 32 byte allocations. */
+ uint32_t cbFree;
+ /** Pointer to the next free item. */
+ struct RTSTRCACHEFREE *pNext;
+} RTSTRCACHEFREE;
+AssertCompileSize(RTSTRCACHEENTRY, 16);
+AssertCompileMembersAtSameOffset(RTSTRCACHEENTRY, cRefs, RTSTRCACHEFREE, uZero);
+AssertCompileMembersAtSameOffset(RTSTRCACHEENTRY, szString, RTSTRCACHEFREE, pNext);
+/** Pointer to a free string cache entry. */
+typedef RTSTRCACHEFREE *PRTSTRCACHEFREE;
+
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+
+/**
+ * A free string cache entry with merging.
+ *
+ * This differs from RTSTRCACHEFREE only in having a back pointer for more
+ * efficient list management (doubly vs. singly linked lists).
+ */
+typedef struct RTSTRCACHEFREEMERGE
+{
+ /** Marker that indicates what kind of entry this is, either . */
+ uint32_t uMarker;
+ /** Number of free bytes. Only used for > 32 byte allocations. */
+ uint32_t cbFree;
+ /** Pointer to the main node. NULL for main nodes. */
+ struct RTSTRCACHEFREEMERGE *pMain;
+ /** The free list entry. */
+ RTLISTNODE ListEntry;
+ /** Pads the size up to the minimum allocation unit for the merge list.
+ * This both defines the minimum allocation unit and simplifies pointer
+ * manipulation during merging and splitting. */
+ uint8_t abPadding[ARCH_BITS == 32 ? 44 : 32];
+} RTSTRCACHEFREEMERGE;
+AssertCompileSize(RTSTRCACHEFREEMERGE, RT_BIT_32(RTSTRCACHE_MERGED_THRESHOLD_BIT));
+/** Pointer to a free cache string in the merge list. */
+typedef RTSTRCACHEFREEMERGE *PRTSTRCACHEFREEMERGE;
+
+/** RTSTRCACHEFREEMERGE::uMarker value indicating that it's the real free chunk
+ * header. Must be something that's invalid UTF-8 for both little and big
+ * endian system. */
+# define RTSTRCACHEFREEMERGE_MAIN UINT32_C(0xfffffff1)
+/** RTSTRCACHEFREEMERGE::uMarker value indicating that it's part of a larger
+ * chunk of free memory. Must be something that's invalid UTF-8 for both little
+ * and big endian system. */
+# define RTSTRCACHEFREEMERGE_PART UINT32_C(0xfffffff2)
+
+#endif /* RTSTRCACHE_WITH_MERGED_ALLOCATOR */
+
+/**
+ * Tracking structure chunk of memory used by the 16 byte or 32 byte
+ * allocations.
+ *
+ * This occupies the first entry in the chunk.
*/
typedef struct RTSTRCACHECHUNK
{
- /** Pointer to the main string cache structure. */
- struct RTSTRCACHEINT *pCache;
- /** Padding to align the entries on a 32-byte boundary. */
- uint32_t au32Padding[8 - (ARCH_BITS == 64) - 4];
- /** The index of the first unused entry. */
- uint32_t iUnused;
- /** The number of used entries. */
- uint32_t cUsed;
- /** The number of entries in this chunk. */
- uint32_t cEntries;
- /** The string cache entries, variable size. */
- RTSTRCACHEENTRY aEntries[1];
+ /** The size of the chunk. */
+ size_t cb;
+ /** Pointer to the next chunk. */
+ struct RTSTRCACHECHUNK *pNext;
} RTSTRCACHECHUNK;
+AssertCompile(sizeof(RTSTRCACHECHUNK) <= sizeof(RTSTRCACHEENTRY));
+/** Pointer to the chunk tracking structure. */
+typedef RTSTRCACHECHUNK *PRTSTRCACHECHUNK;
+/**
+ * Cache instance data.
+ */
typedef struct RTSTRCACHEINT
{
/** The string cache magic (RTSTRCACHE_MAGIC). */
- uint32_t u32Magic;
+ uint32_t u32Magic;
+ /** Ref counter for the cache handle. */
+ uint32_t volatile cRefs;
+ /** The number of strings currently entered in the cache. */
+ uint32_t cStrings;
+ /** The size of the hash table. */
+ uint32_t cHashTab;
+ /** Pointer to the hash table. */
+ PRTSTRCACHEENTRY *papHashTab;
+ /** Free list for allocations of the sizes defined by g_acbFixedLists. */
+ PRTSTRCACHEFREE apFreeLists[RTSTRCACHE_NUM_OF_FIXED_SIZES];
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ /** Free lists based on */
+ RTLISTANCHOR aMergedFreeLists[RTSTRCACHE_HEAP_THRESHOLD_BIT - RTSTRCACHE_MERGED_THRESHOLD_BIT + 1];
+#endif
+ /** List of allocated memory chunks. */
+ PRTSTRCACHECHUNK pChunkList;
+ /** List of big cache entries. */
+ RTLISTANCHOR BigEntryList;
-} RTSTRCACHEINT;
+ /** @name Statistics
+ * @{ */
+ /** The total size of all chunks. */
+ size_t cbChunks;
+ /** The total length of all the strings, terminators included. */
+ size_t cbStrings;
+ /** The total size of all the big entries. */
+ size_t cbBigEntries;
+ /** Hash collisions. */
+ uint32_t cHashCollisions;
+ /** Secondary hash collisions. */
+ uint32_t cHashCollisions2;
+ /** The number of inserts to compare cHashCollisions to. */
+ uint32_t cHashInserts;
+ /** The number of rehashes. */
+ uint32_t cRehashes;
+ /** @} */
+ /** Critical section protecting the cache structures. */
+ RTCRITSECT CritSect;
+} RTSTRCACHEINT;
+/** Pointer to a cache instance. */
+typedef RTSTRCACHEINT *PRTSTRCACHEINT;
/*******************************************************************************
-* Defined Constants And Macros *
+* Global Variables *
*******************************************************************************/
-/** Validates a string cache handle, translating RTSTRCACHE_DEFAULT when found,
- * and returns rc if not valid. */
-#define RTSTRCACHE_VALID_RETURN_RC(pStrCache, rc) \
- do { \
- if ((pStrCache) == RTMEMPOOL_DEFAULT) \
- (pStrCache) = &g_rtMemPoolDefault; \
- else \
- { \
- AssertPtrReturn((pStrCache), (rc)); \
- AssertReturn((pStrCache)->u32Magic == RTSTRCACHE_MAGIC, (rc)); \
- } \
- } while (0)
+/** The entry sizes of the fixed lists (RTSTRCACHEINT::apFreeLists). */
+static const uint32_t g_acbFixedLists[RTSTRCACHE_NUM_OF_FIXED_SIZES] =
+{
+ 16, 32, 48, 64, 96, 128, 192, 256, 320, 384, 448, 512
+};
-/** Validates a memory pool entry and returns rc if not valid. */
-#define RTSTRCACHE_VALID_ENTRY_RETURN_RC(pEntry, rc) \
- do { \
- AssertPtrReturn(pEntry, (rc)); \
- AssertPtrNullReturn((pEntry)->pMemPool, (rc)); \
- Assert((pEntry)->cRefs < UINT32_MAX / 2); \
- AssertReturn((pEntry)->pMemPool->u32Magic == RTMEMPOOL_MAGIC, (rc)); \
- } while (0)
+/** Init once for the default string cache. */
+static RTONCE g_rtStrCacheOnce = RTONCE_INITIALIZER;
+/** The default string cache. */
+static RTSTRCACHE g_hrtStrCacheDefault = NIL_RTSTRCACHE;
-/*******************************************************************************
-* Global Variables *
-*******************************************************************************/
-
+/** @callback_method_impl{FNRTONCE, Initializes g_hrtStrCacheDefault} */
+static DECLCALLBACK(int) rtStrCacheInitDefault(void *pvUser)
+{
+ NOREF(pvUser);
+ return RTStrCacheCreate(&g_hrtStrCacheDefault, "Default");
+}
RTDECL(int) RTStrCacheCreate(PRTSTRCACHE phStrCache, const char *pszName)
{
- AssertCompile(sizeof(RTSTRCACHE) == sizeof(RTMEMPOOL));
- AssertCompile(NIL_RTSTRCACHE == (RTSTRCACHE)NIL_RTMEMPOOL);
- AssertCompile(RTSTRCACHE_DEFAULT == (RTSTRCACHE)RTMEMPOOL_DEFAULT);
- return RTMemPoolCreate((PRTMEMPOOL)phStrCache, pszName);
+ int rc = VERR_NO_MEMORY;
+ PRTSTRCACHEINT pThis = (PRTSTRCACHEINT)RTMemAllocZ(sizeof(*pThis));
+ if (pThis)
+ {
+ pThis->cHashTab = RTSTRCACHE_INITIAL_HASH_SIZE;
+ pThis->papHashTab = (PRTSTRCACHEENTRY*)RTMemAllocZ(sizeof(pThis->papHashTab[0]) * pThis->cHashTab);
+ if (pThis->papHashTab)
+ {
+ rc = RTCritSectInit(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ RTListInit(&pThis->BigEntryList);
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aMergedFreeLists); i++)
+ RTListInit(&pThis->aMergedFreeLists[i]);
+#endif
+ pThis->cRefs = 1;
+ pThis->u32Magic = RTSTRCACHE_MAGIC;
+
+ *phStrCache = pThis;
+ return VINF_SUCCESS;
+ }
+ RTMemFree(pThis->papHashTab);
+ }
+ RTMemFree(pThis);
+ }
+ return rc;
}
RT_EXPORT_SYMBOL(RTStrCacheCreate);
RTDECL(int) RTStrCacheDestroy(RTSTRCACHE hStrCache)
{
- if ( hStrCache == NIL_RTSTRCACHE
- || hStrCache == RTSTRCACHE_DEFAULT)
+ if ( hStrCache == NIL_RTSTRCACHE
+ || hStrCache == RTSTRCACHE_DEFAULT)
return VINF_SUCCESS;
- return RTMemPoolDestroy((RTMEMPOOL)hStrCache);
+
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+
+ /*
+ * Invalidate it. Enter the crit sect just to be on the safe side.
+ */
+ AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSTRCACHE_MAGIC_DEAD, RTSTRCACHE_MAGIC), VERR_INVALID_HANDLE);
+ RTCritSectEnter(&pThis->CritSect);
+ Assert(pThis->cRefs == 1);
+
+ PRTSTRCACHECHUNK pChunk;
+ while ((pChunk = pThis->pChunkList) != NULL)
+ {
+ pThis->pChunkList = pChunk->pNext;
+ RTMemPageFree(pChunk, pChunk->cb);
+ }
+
+ RTMemFree(pThis->papHashTab);
+ pThis->papHashTab = NULL;
+ pThis->cHashTab = 0;
+
+ PRTSTRCACHEBIGENTRY pCur, pNext;
+ RTListForEachSafe(&pThis->BigEntryList, pCur, pNext, RTSTRCACHEBIGENTRY, ListEntry)
+ {
+ RTMemFree(pCur);
+ }
+
+ RTCritSectLeave(&pThis->CritSect);
+ RTCritSectDelete(&pThis->CritSect);
+
+ RTMemFree(pThis);
+ return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTStrCacheDestroy);
+/**
+ * Selects the fixed free list index for a given minimum entry size.
+ *
+ * @returns Free list index.
+ * @param cbMin Minimum entry size.
+ */
+DECLINLINE(uint32_t) rtStrCacheSelectFixedList(uint32_t cbMin)
+{
+ Assert(cbMin <= g_acbFixedLists[RT_ELEMENTS(g_acbFixedLists) - 1]);
+ unsigned i = 0;
+ while (cbMin > g_acbFixedLists[i])
+ i++;
+ return i;
+}
+
+
+#ifdef RT_STRICT
+# define RTSTRCACHE_CHECK(a_pThis) do { rtStrCacheCheck(pThis); } while (0)
+/**
+ * Internal cache check.
+ */
+static void rtStrCacheCheck(PRTSTRCACHEINT pThis)
+{
+# ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aMergedFreeLists); i++)
+ {
+ PRTSTRCACHEFREEMERGE pFree;
+ RTListForEach(&pThis->aMergedFreeLists[i], pFree, RTSTRCACHEFREEMERGE, ListEntry)
+ {
+ Assert(pFree->uMarker == RTSTRCACHEFREEMERGE_MAIN);
+ Assert(pFree->cbFree > 0);
+ Assert(RT_ALIGN_32(pFree->cbFree, sizeof(*pFree)) == pFree->cbFree);
+ }
+ }
+# endif
+}
+#else
+# define RTSTRCACHE_CHECK(a_pThis) do { } while (0)
+#endif
+
+
+/**
+ * Finds the first empty hash table entry given a hash+length value.
+ *
+ * ASSUMES that the hash table isn't full.
+ *
+ * @returns Hash table index.
+ * @param pThis The string cache instance.
+ * @param uHashLen The hash + length (not RTSTRCACHEENTRY_BIG_LEN).
+ */
+static uint32_t rtStrCacheFindEmptyHashTabEntry(PRTSTRCACHEINT pThis, uint32_t uHashLen)
+{
+ uint32_t iHash = uHashLen % pThis->cHashTab;
+ for (;;)
+ {
+ PRTSTRCACHEENTRY pEntry = pThis->papHashTab[iHash];
+ if (pEntry == NULL || pEntry == PRTSTRCACHEENTRY_NIL)
+ return iHash;
+
+ /* Advance. */
+ iHash += RTSTRCACHE_COLLISION_INCR(uHashLen);
+ iHash %= pThis->cHashTab;
+ }
+}
+
+/**
+ * Grows the hash table.
+ *
+ * @returns vINF_SUCCESS or VERR_NO_MEMORY.
+ * @param pThis The string cache instance.
+ */
+static int rtStrCacheGrowHashTab(PRTSTRCACHEINT pThis)
+{
+ /*
+ * Allocate a new hash table two times the size of the old one.
+ */
+ uint32_t cNew = pThis->cHashTab * RTSTRCACHE_HASH_GROW_FACTOR;
+ PRTSTRCACHEENTRY *papNew = (PRTSTRCACHEENTRY *)RTMemAllocZ(sizeof(papNew[0]) * cNew);
+ if (papNew == NULL)
+ return VERR_NO_MEMORY;
+
+ /*
+ * Install the new table and move the items from the old table and into the new one.
+ */
+ PRTSTRCACHEENTRY *papOld = pThis->papHashTab;
+ uint32_t iOld = pThis->cHashTab;
+
+ pThis->papHashTab = papNew;
+ pThis->cHashTab = cNew;
+ pThis->cRehashes++;
+
+ while (iOld-- > 0)
+ {
+ PRTSTRCACHEENTRY pEntry = papOld[iOld];
+ if (pEntry != NULL && pEntry != PRTSTRCACHEENTRY_NIL)
+ {
+ uint32_t cchString = pEntry->cchString;
+ if (cchString == RTSTRCACHEENTRY_BIG_LEN)
+ cchString = RT_FROM_MEMBER(pEntry, RTSTRCACHEBIGENTRY, Core)->cchString;
+
+ uint32_t iHash = rtStrCacheFindEmptyHashTabEntry(pThis, RT_MAKE_U32(pEntry->uHash, cchString));
+ pThis->papHashTab[iHash] = pEntry;
+ }
+ }
+
+ /*
+ * Free the old hash table.
+ */
+ RTMemFree(papOld);
+ return VINF_SUCCESS;
+}
+
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+
+/**
+ * Link/Relink into the free right list.
+ *
+ * @param pThis The string cache instance.
+ * @param pFree The free string entry.
+ */
+static void rtStrCacheRelinkMerged(PRTSTRCACHEINT pThis, PRTSTRCACHEFREEMERGE pFree)
+{
+ Assert(pFree->uMarker == RTSTRCACHEFREEMERGE_MAIN);
+ Assert(pFree->cbFree > 0);
+ Assert(RT_ALIGN_32(pFree->cbFree, sizeof(*pFree)) == pFree->cbFree);
+
+ if (!RTListIsEmpty(&pFree->ListEntry))
+ RTListNodeRemove(&pFree->ListEntry);
+
+ uint32_t iList = (ASMBitLastSetU32(pFree->cbFree) - 1) - RTSTRCACHE_MERGED_THRESHOLD_BIT;
+ if (iList >= RT_ELEMENTS(pThis->aMergedFreeLists))
+ iList = RT_ELEMENTS(pThis->aMergedFreeLists) - 1;
+
+ RTListPrepend(&pThis->aMergedFreeLists[iList], &pFree->ListEntry);
+}
+
+
+/**
+ * Allocate a cache entry from the merged free lists.
+ *
+ * @returns Pointer to the cache entry on success, NULL on allocation error.
+ * @param pThis The string cache instance.
+ * @param uHash The full hash of the string.
+ * @param pchString The string.
+ * @param cchString The string length.
+ * @param cbEntry The required entry size.
+ */
+static PRTSTRCACHEENTRY rtStrCacheAllocMergedEntry(PRTSTRCACHEINT pThis, uint32_t uHash,
+ const char *pchString, uint32_t cchString, uint32_t cbEntry)
+{
+ cbEntry = RT_ALIGN_32(cbEntry, sizeof(RTSTRCACHEFREEMERGE));
+ Assert(cbEntry > cchString);
+
+ /*
+ * Search the list heads first.
+ */
+ PRTSTRCACHEFREEMERGE pFree = NULL;
+
+ uint32_t iList = ASMBitLastSetU32(cbEntry) - 1;
+ if (!RT_IS_POWER_OF_TWO(cbEntry))
+ iList++;
+ iList -= RTSTRCACHE_MERGED_THRESHOLD_BIT;
+
+ while (iList < RT_ELEMENTS(pThis->aMergedFreeLists))
+ {
+ pFree = RTListGetFirst(&pThis->aMergedFreeLists[iList], RTSTRCACHEFREEMERGE, ListEntry);
+ if (pFree)
+ {
+ /*
+ * Found something. Should we we split it? We split from the end
+ * to avoid having to update all the sub entries.
+ */
+ Assert(pFree->uMarker == RTSTRCACHEFREEMERGE_MAIN);
+ Assert(pFree->cbFree >= cbEntry);
+ Assert(RT_ALIGN_32(pFree->cbFree, sizeof(*pFree)) == pFree->cbFree);
+
+ if (pFree->cbFree == cbEntry)
+ RTListNodeRemove(&pFree->ListEntry);
+ else
+ {
+ uint32_t cRemainder = (pFree->cbFree - cbEntry) / sizeof(*pFree);
+ PRTSTRCACHEFREEMERGE pRemainder = pFree;
+ pFree += cRemainder;
+
+ Assert((pRemainder->cbFree - cbEntry) == cRemainder * sizeof(*pFree));
+ pRemainder->cbFree = cRemainder * sizeof(*pFree);
+
+ rtStrCacheRelinkMerged(pThis, pRemainder);
+ }
+ break;
+ }
+ iList++;
+ }
+ if (!pFree)
+ {
+ /*
+ * Allocate a new block. (We could search the list below in some
+ * cases, but it's too much effort to write and execute).
+ */
+ size_t const cbChunk = RTSTRCACHE_MERGED_GROW_SIZE; AssertReturn(cbChunk > cbEntry * 2, NULL);
+ PRTSTRCACHECHUNK pChunk = (PRTSTRCACHECHUNK)RTMemPageAlloc(cbChunk);
+ if (!pChunk)
+ return NULL;
+ pChunk->cb = cbChunk;
+ pChunk->pNext = pThis->pChunkList;
+ pThis->pChunkList = pChunk;
+ pThis->cbChunks += cbChunk;
+ AssertCompile(sizeof(*pChunk) <= sizeof(*pFree));
+
+ /*
+ * Get one node for the allocation at hand.
+ */
+ pFree = (PRTSTRCACHEFREEMERGE)((uintptr_t)pChunk + sizeof(*pFree));
+
+ /*
+ * Create a free block out of the remainder (always a reminder).
+ */
+ PRTSTRCACHEFREEMERGE pNewFree = (PRTSTRCACHEFREEMERGE)((uintptr_t)pFree + cbEntry);
+ pNewFree->uMarker = RTSTRCACHEFREEMERGE_MAIN;
+ pNewFree->cbFree = cbChunk - sizeof(*pNewFree) - cbEntry; Assert(pNewFree->cbFree < cbChunk && pNewFree->cbFree > 0);
+ pNewFree->pMain = NULL;
+ RTListInit(&pNewFree->ListEntry);
+
+ uint32_t iInternalBlock = pNewFree->cbFree / sizeof(*pNewFree);
+ while (iInternalBlock-- > 1)
+ {
+ pNewFree[iInternalBlock].uMarker = RTSTRCACHEFREEMERGE_PART;
+ pNewFree[iInternalBlock].cbFree = 0;
+ pNewFree[iInternalBlock].pMain = pNewFree;
+ }
+
+ rtStrCacheRelinkMerged(pThis, pNewFree);
+ }
+
+ /*
+ * Initialize the entry. We zero all bytes we don't use so they cannot
+ * accidentally be mistaken for a free entry.
+ */
+ ASMCompilerBarrier();
+ PRTSTRCACHEENTRY pEntry = (PRTSTRCACHEENTRY)pFree;
+ pEntry->cRefs = 1;
+ pEntry->uHash = (uint16_t)uHash;
+ pEntry->cchString = (uint16_t)cchString;
+ memcpy(pEntry->szString, pchString, cchString);
+ RT_BZERO(&pEntry->szString[cchString], cbEntry - RT_UOFFSETOF(RTSTRCACHEENTRY, szString) - cchString);
+
+ RTSTRCACHE_CHECK(pThis);
+
+ return pEntry;
+}
+
+#endif /* RTSTRCACHE_WITH_MERGED_ALLOCATOR */
+
+/**
+ * Allocate a cache entry from the heap.
+ *
+ * @returns Pointer to the cache entry on success, NULL on allocation error.
+ * @param pThis The string cache instance.
+ * @param uHash The full hash of the string.
+ * @param pchString The string.
+ * @param cchString The string length.
+ */
+static PRTSTRCACHEENTRY rtStrCacheAllocHeapEntry(PRTSTRCACHEINT pThis, uint32_t uHash,
+ const char *pchString, uint32_t cchString)
+{
+ /*
+ * Allocate a heap block for storing the string. We do some size aligning
+ * here to encourage the heap to give us optimal alignment.
+ */
+ size_t cbEntry = RT_UOFFSETOF(RTSTRCACHEBIGENTRY, Core.szString[cchString + 1]);
+ PRTSTRCACHEBIGENTRY pBigEntry = (PRTSTRCACHEBIGENTRY)RTMemAlloc(RT_ALIGN_Z(cbEntry, RTSTRCACHE_HEAP_ENTRY_SIZE_ALIGN));
+ if (!pBigEntry)
+ return NULL;
+
+ /*
+ * Initialize the block.
+ */
+ RTListAppend(&pThis->BigEntryList, &pBigEntry->ListEntry);
+ pThis->cbBigEntries += cbEntry;
+ pBigEntry->cchString = cchString;
+ pBigEntry->uHash = uHash;
+ pBigEntry->Core.cRefs = 1;
+ pBigEntry->Core.uHash = (uint16_t)uHash;
+ pBigEntry->Core.cchString = RTSTRCACHEENTRY_BIG_LEN;
+ memcpy(pBigEntry->Core.szString, pchString, cchString);
+ pBigEntry->Core.szString[cchString] = '\0';
+
+ return &pBigEntry->Core;
+}
+
+
+/**
+ * Allocate a cache entry from a fixed size free list.
+ *
+ * @returns Pointer to the cache entry on success, NULL on allocation error.
+ * @param pThis The string cache instance.
+ * @param uHash The full hash of the string.
+ * @param pchString The string.
+ * @param cchString The string length.
+ * @param iFreeList Which free list.
+ */
+static PRTSTRCACHEENTRY rtStrCacheAllocFixedEntry(PRTSTRCACHEINT pThis, uint32_t uHash,
+ const char *pchString, uint32_t cchString, uint32_t iFreeList)
+{
+ /*
+ * Get an entry from the free list. If empty, allocate another chunk of
+ * memory and split it up into free entries of the desired size.
+ */
+ PRTSTRCACHEFREE pFree = pThis->apFreeLists[iFreeList];
+ if (!pFree)
+ {
+ PRTSTRCACHECHUNK pChunk = (PRTSTRCACHECHUNK)RTMemPageAlloc(RTSTRCACHE_FIXED_GROW_SIZE);
+ if (!pChunk)
+ return NULL;
+ pChunk->cb = RTSTRCACHE_FIXED_GROW_SIZE;
+ pChunk->pNext = pThis->pChunkList;
+ pThis->pChunkList = pChunk;
+ pThis->cbChunks += RTSTRCACHE_FIXED_GROW_SIZE;
+
+ PRTSTRCACHEFREE pPrev = NULL;
+ uint32_t const cbEntry = g_acbFixedLists[iFreeList];
+ uint32_t cLeft = RTSTRCACHE_FIXED_GROW_SIZE / cbEntry - 1;
+ pFree = (PRTSTRCACHEFREE)((uintptr_t)pChunk + cbEntry);
+
+ Assert(sizeof(*pChunk) <= cbEntry);
+ Assert(sizeof(*pFree) <= cbEntry);
+ Assert(cbEntry < RTSTRCACHE_FIXED_GROW_SIZE / 16);
+
+ while (cLeft-- > 0)
+ {
+ pFree->uZero = 0;
+ pFree->cbFree = cbEntry;
+ pFree->pNext = pPrev;
+ pPrev = pFree;
+ pFree = (PRTSTRCACHEFREE)((uintptr_t)pFree + cbEntry);
+ }
+
+ Assert(pPrev);
+ pThis->apFreeLists[iFreeList] = pFree = pPrev;
+ }
+
+ /*
+ * Unlink it.
+ */
+ pThis->apFreeLists[iFreeList] = pFree->pNext;
+ ASMCompilerBarrier();
+
+ /*
+ * Initialize the entry.
+ */
+ PRTSTRCACHEENTRY pEntry = (PRTSTRCACHEENTRY)pFree;
+ pEntry->cRefs = 1;
+ pEntry->uHash = (uint16_t)uHash;
+ pEntry->cchString = (uint16_t)cchString;
+ memcpy(pEntry->szString, pchString, cchString);
+ pEntry->szString[cchString] = '\0';
+
+ return pEntry;
+}
+
+
+/**
+ * Looks up a string in the hash table.
+ *
+ * @returns Pointer to the string cache entry, NULL + piFreeHashTabEntry if not
+ * found.
+ * @param pThis The string cache instance.
+ * @param uHashLen The hash + length (not RTSTRCACHEENTRY_BIG_LEN).
+ * @param cchString The real length.
+ * @param pchString The string.
+ * @param piFreeHashTabEntry Where to store the index insertion index if NULL
+ * is returned (same as what
+ * rtStrCacheFindEmptyHashTabEntry would return).
+ * @param pcCollisions Where to return a collision counter.
+ */
+static PRTSTRCACHEENTRY rtStrCacheLookUp(PRTSTRCACHEINT pThis, uint32_t uHashLen, uint32_t cchString, const char *pchString,
+ uint32_t *piFreeHashTabEntry, uint32_t *pcCollisions)
+{
+ *piFreeHashTabEntry = UINT32_MAX;
+ *pcCollisions = 0;
+
+ uint16_t cchStringFirst = RT_UOFFSETOF(RTSTRCACHEENTRY, szString[cchString + 1]) < RTSTRCACHE_HEAP_THRESHOLD
+ ? (uint16_t)cchString : RTSTRCACHEENTRY_BIG_LEN;
+ uint32_t iHash = uHashLen % pThis->cHashTab;
+ for (;;)
+ {
+ PRTSTRCACHEENTRY pEntry = pThis->papHashTab[iHash];
+
+ /* Give up if NULL, but record the index for insertion. */
+ if (pEntry == NULL)
+ {
+ if (*piFreeHashTabEntry == UINT32_MAX)
+ *piFreeHashTabEntry = iHash;
+ return NULL;
+ }
+
+ if (pEntry != PRTSTRCACHEENTRY_NIL)
+ {
+ /* Compare. */
+ if ( pEntry->uHash == (uint16_t)uHashLen
+ && pEntry->cchString == cchStringFirst)
+ {
+ if (pEntry->cchString != RTSTRCACHEENTRY_BIG_LEN)
+ {
+ if ( !memcmp(pEntry->szString, pchString, cchString)
+ && pEntry->szString[cchString] == '\0')
+ return pEntry;
+ }
+ else
+ {
+ PRTSTRCACHEBIGENTRY pBigEntry = RT_FROM_MEMBER(pEntry, RTSTRCACHEBIGENTRY, Core);
+ if ( pBigEntry->cchString == cchString
+ && !memcmp(pBigEntry->Core.szString, pchString, cchString))
+ return &pBigEntry->Core;
+ }
+ }
+
+ if (*piFreeHashTabEntry == UINT32_MAX)
+ *pcCollisions += 1;
+ }
+ /* Record the first NIL index for insertion in case we don't get a hit. */
+ else if (*piFreeHashTabEntry == UINT32_MAX)
+ *piFreeHashTabEntry = iHash;
+
+ /* Advance. */
+ iHash += RTSTRCACHE_COLLISION_INCR(uHashLen);
+ iHash %= pThis->cHashTab;
+ }
+}
+
+
RTDECL(const char *) RTStrCacheEnterN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString)
{
- AssertPtr(pchString);
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, NULL);
+
+
+ /*
+ * Calculate the hash and figure the exact string length, then look for an existing entry.
+ */
+ uint32_t const uHash = sdbmN(pchString, cchString, &cchString);
+ uint32_t const uHashLen = RT_MAKE_U32(uHash, cchString);
AssertReturn(cchString < _1G, NULL);
- Assert(!RTStrEnd(pchString, cchString));
+ uint32_t const cchString32 = (uint32_t)cchString;
+
+ RTCritSectEnter(&pThis->CritSect);
+ RTSTRCACHE_CHECK(pThis);
- return (const char *)RTMemPoolDupEx((RTMEMPOOL)hStrCache, pchString, cchString, 1);
+ uint32_t cCollisions;
+ uint32_t iFreeHashTabEntry;
+ PRTSTRCACHEENTRY pEntry = rtStrCacheLookUp(pThis, uHashLen, cchString32, pchString, &iFreeHashTabEntry, &cCollisions);
+ if (pEntry)
+ {
+ uint32_t cRefs = ASMAtomicIncU32(&pEntry->cRefs);
+ Assert(cRefs < UINT32_MAX / 2);
+ }
+ else
+ {
+ /*
+ * Allocate a new entry.
+ */
+ uint32_t cbEntry = cchString32 + 1U + RT_UOFFSETOF(RTSTRCACHEENTRY, szString);
+ if (cbEntry >= RTSTRCACHE_HEAP_THRESHOLD)
+ pEntry = rtStrCacheAllocHeapEntry(pThis, uHash, pchString, cchString32);
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ else if (cbEntry >= RTSTRCACHE_MERGED_THRESHOLD_BIT)
+ pEntry = rtStrCacheAllocMergedEntry(pThis, uHash, pchString, cchString32, cbEntry);
+#endif
+ else
+ pEntry = rtStrCacheAllocFixedEntry(pThis, uHash, pchString, cchString32,
+ rtStrCacheSelectFixedList(cbEntry));
+ if (!pEntry)
+ {
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+ return NULL;
+ }
+
+ /*
+ * Insert it into the hash table.
+ */
+ if (pThis->cHashTab - pThis->cStrings < pThis->cHashTab / 2)
+ {
+ int rc = rtStrCacheGrowHashTab(pThis);
+ if (RT_SUCCESS(rc))
+ iFreeHashTabEntry = rtStrCacheFindEmptyHashTabEntry(pThis, uHashLen);
+ else if (pThis->cHashTab - pThis->cStrings <= pThis->cHashTab / 8) /* 12.5% full => error */
+ {
+ pThis->papHashTab[iFreeHashTabEntry] = pEntry;
+ pThis->cStrings++;
+ pThis->cHashInserts++;
+ pThis->cHashCollisions += cCollisions > 0;
+ pThis->cHashCollisions2 += cCollisions > 1;
+ pThis->cbStrings += cchString32 + 1;
+ RTStrCacheRelease(hStrCache, pEntry->szString);
+
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+ return NULL;
+ }
+ }
+
+ pThis->papHashTab[iFreeHashTabEntry] = pEntry;
+ pThis->cStrings++;
+ pThis->cHashInserts++;
+ pThis->cHashCollisions += cCollisions > 0;
+ pThis->cHashCollisions2 += cCollisions > 1;
+ pThis->cbStrings += cchString32 + 1;
+ Assert(pThis->cStrings < pThis->cHashTab && pThis->cStrings > 0);
+ }
+
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+ return pEntry->szString;
}
RT_EXPORT_SYMBOL(RTStrCacheEnterN);
@@ -166,19 +920,249 @@ RTDECL(const char *) RTStrCacheEnter(RTSTRCACHE hStrCache, const char *psz)
RT_EXPORT_SYMBOL(RTStrCacheEnter);
+static const char *rtStrCacheEnterLowerWorker(PRTSTRCACHEINT pThis, const char *pchString, size_t cchString)
+{
+ /*
+ * Try use a dynamic heap buffer first.
+ */
+ if (cchString < 512)
+ {
+ char *pszStackBuf = (char *)alloca(cchString + 1);
+ if (pszStackBuf)
+ {
+ memcpy(pszStackBuf, pchString, cchString);
+ pszStackBuf[cchString] = '\0';
+ RTStrToLower(pszStackBuf);
+ return RTStrCacheEnterN(pThis, pszStackBuf, cchString);
+ }
+ }
+
+ /*
+ * Fall back on heap.
+ */
+ char *pszHeapBuf = (char *)RTMemTmpAlloc(cchString + 1);
+ if (!pszHeapBuf)
+ return NULL;
+ memcpy(pszHeapBuf, pchString, cchString);
+ pszHeapBuf[cchString] = '\0';
+ RTStrToLower(pszHeapBuf);
+ const char *pszRet = RTStrCacheEnterN(pThis, pszHeapBuf, cchString);
+ RTMemTmpFree(pszHeapBuf);
+ return pszRet;
+}
+
+RTDECL(const char *) RTStrCacheEnterLowerN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString)
+{
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, NULL);
+ return rtStrCacheEnterLowerWorker(pThis, pchString, RTStrNLen(pchString, cchString));
+}
+RT_EXPORT_SYMBOL(RTStrCacheEnterLowerN);
+
+
+RTDECL(const char *) RTStrCacheEnterLower(RTSTRCACHE hStrCache, const char *psz)
+{
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, NULL);
+ return rtStrCacheEnterLowerWorker(pThis, psz, strlen(psz));
+}
+RT_EXPORT_SYMBOL(RTStrCacheEnterLower);
+
+
RTDECL(uint32_t) RTStrCacheRetain(const char *psz)
{
AssertPtr(psz);
- return RTMemPoolRetain((void *)psz);
+
+ PRTSTRCACHEENTRY pStr = RT_FROM_MEMBER(psz, RTSTRCACHEENTRY, szString);
+ Assert(!((uintptr_t)pStr & 15) || pStr->cchString == RTSTRCACHEENTRY_BIG_LEN);
+
+ uint32_t cRefs = ASMAtomicIncU32(&pStr->cRefs);
+ Assert(cRefs > 1);
+ Assert(cRefs < UINT32_MAX / 2);
+
+ return cRefs;
}
RT_EXPORT_SYMBOL(RTStrCacheRetain);
+static uint32_t rtStrCacheFreeEntry(PRTSTRCACHEINT pThis, PRTSTRCACHEENTRY pStr)
+{
+ RTCritSectEnter(&pThis->CritSect);
+ RTSTRCACHE_CHECK(pThis);
+
+ /* Remove it from the hash table. */
+ uint32_t cchString = pStr->cchString == RTSTRCACHEENTRY_BIG_LEN
+ ? RT_FROM_MEMBER(pStr, RTSTRCACHEBIGENTRY, Core)->cchString
+ : pStr->cchString;
+ uint32_t uHashLen = RT_MAKE_U32(pStr->uHash, cchString);
+ uint32_t iHash = uHashLen % pThis->cHashTab;
+ if (pThis->papHashTab[iHash] == pStr)
+ pThis->papHashTab[iHash] = PRTSTRCACHEENTRY_NIL;
+ else
+ {
+ do
+ {
+ AssertBreak(pThis->papHashTab[iHash] != NULL);
+ iHash += RTSTRCACHE_COLLISION_INCR(uHashLen);
+ iHash %= pThis->cHashTab;
+ } while (pThis->papHashTab[iHash] != pStr);
+ if (RT_LIKELY(pThis->papHashTab[iHash] == pStr))
+ pThis->papHashTab[iHash] = PRTSTRCACHEENTRY_NIL;
+ else
+ {
+ AssertFailed();
+ iHash = pThis->cHashTab;
+ while (iHash-- > 0)
+ if (pThis->papHashTab[iHash] == pStr)
+ break;
+ AssertMsgFailed(("iHash=%u cHashTab=%u\n", iHash, pThis->cHashTab));
+ }
+ }
+
+ pThis->cStrings--;
+ pThis->cbStrings -= cchString;
+ Assert(pThis->cStrings < pThis->cHashTab);
+
+ /* Free it. */
+ if (pStr->cchString != RTSTRCACHEENTRY_BIG_LEN)
+ {
+ uint32_t const cbMin = pStr->cchString + 1U + RT_UOFFSETOF(RTSTRCACHEENTRY, szString);
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ if (cbMin <= RTSTRCACHE_MAX_FIXED)
+#endif
+ {
+ /*
+ * No merging, just add it to the list.
+ */
+ uint32_t const iFreeList = rtStrCacheSelectFixedList(cbMin);
+ ASMCompilerBarrier();
+ PRTSTRCACHEFREE pFreeStr = (PRTSTRCACHEFREE)pStr;
+ pFreeStr->cbFree = cbMin;
+ pFreeStr->uZero = 0;
+ pFreeStr->pNext = pThis->apFreeLists[iFreeList];
+ pThis->apFreeLists[iFreeList] = pFreeStr;
+ }
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ else
+ {
+ /*
+ * Complicated mode, we merge with adjecent nodes.
+ */
+ ASMCompilerBarrier();
+ PRTSTRCACHEFREEMERGE pFreeStr = (PRTSTRCACHEFREEMERGE)pStr;
+ pFreeStr->cbFree = RT_ALIGN_32(cbMin, sizeof(*pFreeStr));
+ pFreeStr->uMarker = RTSTRCACHEFREEMERGE_MAIN;
+ pFreeStr->pMain = NULL;
+ RTListInit(&pFreeStr->ListEntry);
+
+ /*
+ * Merge with previous?
+ * (Reading one block back is safe because there is always the
+ * RTSTRCACHECHUNK structure at the head of each memory chunk.)
+ */
+ uint32_t cInternalBlocks = pFreeStr->cbFree / sizeof(*pFreeStr);
+ PRTSTRCACHEFREEMERGE pMain = pFreeStr - 1;
+ if ( pMain->uMarker == RTSTRCACHEFREEMERGE_MAIN
+ || pMain->uMarker == RTSTRCACHEFREEMERGE_PART)
+ {
+ while (pMain->uMarker != RTSTRCACHEFREEMERGE_MAIN)
+ pMain--;
+ pMain->cbFree += pFreeStr->cbFree;
+ }
+ else
+ {
+ pMain = pFreeStr;
+ pFreeStr++;
+ cInternalBlocks--;
+ }
+
+ /*
+ * Mark internal blocks in the string we're freeing.
+ */
+ while (cInternalBlocks-- > 0)
+ {
+ pFreeStr->uMarker = RTSTRCACHEFREEMERGE_PART;
+ pFreeStr->cbFree = 0;
+ pFreeStr->pMain = pMain;
+ RTListInit(&pFreeStr->ListEntry);
+ pFreeStr++;
+ }
+
+ /*
+ * Merge with next? Limitation: We won't try cross page boundraries.
+ * (pFreeStr points to the next first free enter after the string now.)
+ */
+ if ( PAGE_ADDRESS(pFreeStr) == PAGE_ADDRESS(&pFreeStr[-1])
+ && pFreeStr->uMarker == RTSTRCACHEFREEMERGE_MAIN)
+ {
+ pMain->cbFree += pFreeStr->cbFree;
+ cInternalBlocks = pFreeStr->cbFree / sizeof(*pFreeStr);
+ Assert(cInternalBlocks > 0);
+
+ /* Update the main block we merge with. */
+ pFreeStr->cbFree = 0;
+ pFreeStr->uMarker = RTSTRCACHEFREEMERGE_PART;
+ RTListNodeRemove(&pFreeStr->ListEntry);
+ RTListInit(&pFreeStr->ListEntry);
+
+ /* Change the internal blocks we merged in. */
+ cInternalBlocks--;
+ while (cInternalBlocks-- > 0)
+ {
+ pFreeStr++;
+ pFreeStr->pMain = pMain;
+ Assert(pFreeStr->uMarker == RTSTRCACHEFREEMERGE_PART);
+ Assert(!pFreeStr->cbFree);
+ }
+ }
+
+ /*
+ * Add/relink into the appropriate free list.
+ */
+ rtStrCacheRelinkMerged(pThis, pMain);
+ }
+#endif /* RTSTRCACHE_WITH_MERGED_ALLOCATOR */
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ else
+ {
+ /* Big string. */
+ PRTSTRCACHEBIGENTRY pBigStr = RT_FROM_MEMBER(pStr, RTSTRCACHEBIGENTRY, Core);
+ RTListNodeRemove(&pBigStr->ListEntry);
+ pThis->cbBigEntries -= RT_ALIGN_32(RT_UOFFSETOF(RTSTRCACHEBIGENTRY, Core.szString[cchString + 1]),
+ RTSTRCACHE_HEAP_ENTRY_SIZE_ALIGN);
+
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+
+ RTMemFree(pBigStr);
+ }
+
+ return 0;
+}
+
RTDECL(uint32_t) RTStrCacheRelease(RTSTRCACHE hStrCache, const char *psz)
{
if (!psz)
return 0;
- return RTMemPoolRelease((RTMEMPOOL)hStrCache, (void *)psz);
+
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, UINT32_MAX);
+
+ AssertPtr(psz);
+ PRTSTRCACHEENTRY pStr = RT_FROM_MEMBER(psz, RTSTRCACHEENTRY, szString);
+ Assert(!((uintptr_t)pStr & 15) || pStr->cchString == RTSTRCACHEENTRY_BIG_LEN);
+
+ /*
+ * Drop a reference and maybe free the entry.
+ */
+ uint32_t cRefs = ASMAtomicDecU32(&pStr->cRefs);
+ Assert(cRefs < UINT32_MAX / 2);
+ if (!cRefs)
+ return rtStrCacheFreeEntry(pThis, pStr);
+
+ return cRefs;
}
RT_EXPORT_SYMBOL(RTStrCacheRelease);
@@ -187,7 +1171,54 @@ RTDECL(size_t) RTStrCacheLength(const char *psz)
{
if (!psz)
return 0;
- return strlen(psz);
+
+ AssertPtr(psz);
+ PRTSTRCACHEENTRY pStr = RT_FROM_MEMBER(psz, RTSTRCACHEENTRY, szString);
+ if (pStr->cchString == RTSTRCACHEENTRY_BIG_LEN)
+ {
+ PRTSTRCACHEBIGENTRY pBigStr = RT_FROM_MEMBER(psz, RTSTRCACHEBIGENTRY, Core.szString);
+ return pBigStr->cchString;
+ }
+ Assert(!((uintptr_t)pStr & 15));
+ return pStr->cchString;
}
RT_EXPORT_SYMBOL(RTStrCacheLength);
+
+RTDECL(bool) RTStrCacheIsRealImpl(void)
+{
+ return true;
+}
+RT_EXPORT_SYMBOL(RTStrCacheIsRealImpl);
+
+
+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)
+{
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, UINT32_MAX);
+
+ RTCritSectEnter(&pThis->CritSect);
+
+ if (pcbStrings)
+ *pcbStrings = pThis->cbStrings;
+ if (pcbChunks)
+ *pcbChunks = pThis->cbChunks;
+ if (pcbBigEntries)
+ *pcbBigEntries = pThis->cbBigEntries;
+ if (pcHashCollisions)
+ *pcHashCollisions = pThis->cHashCollisions;
+ if (pcHashCollisions2)
+ *pcHashCollisions2 = pThis->cHashCollisions2;
+ if (pcHashInserts)
+ *pcHashInserts = pThis->cHashInserts;
+ if (pcRehashes)
+ *pcRehashes = pThis->cRehashes;
+ uint32_t cStrings = pThis->cStrings;
+
+ RTCritSectLeave(&pThis->CritSect);
+ return cStrings;
+}
+RT_EXPORT_SYMBOL(RTStrCacheRelease);
+
diff --git a/src/VBox/Runtime/common/string/strchr.asm b/src/VBox/Runtime/common/string/strchr.asm
index 7163f28c..e890e9c8 100644
--- a/src/VBox/Runtime/common/string/strchr.asm
+++ b/src/VBox/Runtime/common/string/strchr.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strchr_alias.c b/src/VBox/Runtime/common/string/strchr_alias.c
index 4b4fe4b1..63a9a598 100644
--- a/src/VBox/Runtime/common/string/strchr_alias.c
+++ b/src/VBox/Runtime/common/string/strchr_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcmp.asm b/src/VBox/Runtime/common/string/strcmp.asm
index 574e5d14..31de02d8 100644
--- a/src/VBox/Runtime/common/string/strcmp.asm
+++ b/src/VBox/Runtime/common/string/strcmp.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcmp_alias.c b/src/VBox/Runtime/common/string/strcmp_alias.c
index 3c5f7f83..9347aff3 100644
--- a/src/VBox/Runtime/common/string/strcmp_alias.c
+++ b/src/VBox/Runtime/common/string/strcmp_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcpy.asm b/src/VBox/Runtime/common/string/strcpy.asm
index bee8738b..85f7edec 100644
--- a/src/VBox/Runtime/common/string/strcpy.asm
+++ b/src/VBox/Runtime/common/string/strcpy.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcpy.cpp b/src/VBox/Runtime/common/string/strcpy.cpp
index 55da775d..3ea6cf00 100644
--- a/src/VBox/Runtime/common/string/strcpy.cpp
+++ b/src/VBox/Runtime/common/string/strcpy.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcpy_alias.c b/src/VBox/Runtime/common/string/strcpy_alias.c
index 517cd801..d703d4cd 100644
--- a/src/VBox/Runtime/common/string/strcpy_alias.c
+++ b/src/VBox/Runtime/common/string/strcpy_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strformat.cpp b/src/VBox/Runtime/common/string/strformat.cpp
index 56dc5ec5..335d3033 100644
--- a/src/VBox/Runtime/common/string/strformat.cpp
+++ b/src/VBox/Runtime/common/string/strformat.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strformatnum.cpp b/src/VBox/Runtime/common/string/strformatnum.cpp
index f5b68740..777e8ec7 100644
--- a/src/VBox/Runtime/common/string/strformatnum.cpp
+++ b/src/VBox/Runtime/common/string/strformatnum.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -49,7 +49,7 @@ RTDECL(ssize_t) RTStrFormatU8(char *pszBuf, size_t cbBuf, uint8_t u8Value, unsig
{
char szTmp[64];
cchRet = RTStrFormatNumber(szTmp, u8Value, uiBase, cchWidth, cchPrecision, fFlags);
- if ((size_t)cchRet <= cbBuf)
+ if ((size_t)cchRet < cbBuf)
memcpy(pszBuf, szTmp, cchRet + 1);
else
{
diff --git a/src/VBox/Runtime/common/string/strformatrt.cpp b/src/VBox/Runtime/common/string/strformatrt.cpp
index b5d23853..4dd69f17 100644
--- a/src/VBox/Runtime/common/string/strformatrt.cpp
+++ b/src/VBox/Runtime/common/string/strformatrt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -56,6 +56,121 @@
#include "internal/string.h"
+/**
+ * Helper function to format IPv6 address according to RFC 5952.
+ *
+ * @returns The number of bytes formatted.
+ * @param pfnOutput Pointer to output function.
+ * @param pvArgOutput Argument for the output function.
+ * @param pIpv6Addr IPv6 address
+ */
+static size_t rtstrFormatIPv6(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PCRTNETADDRIPV6 pIpv6Addr)
+{
+ size_t cch = 0; /* result */
+
+ bool fEmbeddedIpv4;
+ size_t cwHexPart;
+ size_t cwZeroRun, cwLongestZeroRun;
+ size_t iZeroStart, iLongestZeroStart;
+ size_t idx;
+
+ Assert(pIpv6Addr != NULL);
+
+ /*
+ * Check for embedded IPv4 address.
+ *
+ * IPv4-compatible - ::11.22.33.44 (obsolete)
+ * IPv4-mapped - ::ffff:11.22.33.44
+ * IPv4-translated - ::ffff:0:11.22.33.44 (RFC 2765)
+ */
+ fEmbeddedIpv4 = false;
+ cwHexPart = RT_ELEMENTS(pIpv6Addr->au16);
+ if (pIpv6Addr->au64[0] == 0
+ && ( (pIpv6Addr->au32[2] == 0
+ && ( pIpv6Addr->au32[3] != 0
+ && pIpv6Addr->au32[3] != RT_H2BE_U32_C(1)))
+ || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0x0000ffff)
+ || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0xffff0000)))
+ {
+ fEmbeddedIpv4 = true;
+ cwHexPart -= 2;
+ }
+
+ cwZeroRun = cwLongestZeroRun = 0;
+ iZeroStart = iLongestZeroStart = -1;
+ for (idx = 0; idx <= cwHexPart; ++idx)
+ {
+ if (idx < cwHexPart && pIpv6Addr->au16[idx] == 0)
+ {
+ if (cwZeroRun == 0)
+ {
+ cwZeroRun = 1;
+ iZeroStart = idx;
+ }
+ else
+ ++cwZeroRun;
+ }
+ else
+ {
+ if (cwZeroRun != 0)
+ {
+ if (cwZeroRun > 1 && cwZeroRun > cwLongestZeroRun)
+ {
+ cwLongestZeroRun = cwZeroRun;
+ iLongestZeroStart = iZeroStart;
+ }
+ cwZeroRun = 0;
+ iZeroStart = -1;
+ }
+ }
+ }
+
+ if (cwLongestZeroRun == 0)
+ {
+ for (idx = 0; idx < cwHexPart; ++idx)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%s%x",
+ idx == 0 ? "" : ":",
+ RT_BE2H_U16(pIpv6Addr->au16[idx]));
+
+ if (fEmbeddedIpv4)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, ":");
+ }
+ else
+ {
+ const size_t iLongestZeroEnd = iLongestZeroStart + cwLongestZeroRun;
+
+ if (iLongestZeroStart == 0)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, ":");
+ else
+ for (idx = 0; idx < iLongestZeroStart; ++idx)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%x:", RT_BE2H_U16(pIpv6Addr->au16[idx]));
+
+ if (iLongestZeroEnd == cwHexPart)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, ":");
+ else
+ {
+ for (idx = iLongestZeroEnd; idx < cwHexPart; ++idx)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ ":%x", RT_BE2H_U16(pIpv6Addr->au16[idx]));
+
+ if (fEmbeddedIpv4)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, ":");
+ }
+ }
+
+ if (fEmbeddedIpv4)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%u.%u.%u.%u",
+ pIpv6Addr->au8[12],
+ pIpv6Addr->au8[13],
+ pIpv6Addr->au8[14],
+ pIpv6Addr->au8[15]);
+
+ return cch;
+}
+
/**
* Callback to format iprt formatting extentions.
@@ -141,7 +256,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
{ STRMEM("Gx"), sizeof(RTGCUINT), 16, RTSF_INT, 0 },
{ STRMEM("Hi"), sizeof(RTHCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
{ STRMEM("Hp"), sizeof(RTHCPHYS), 16, RTSF_INTW, 0 },
- { STRMEM("Hr"), sizeof(RTGCUINTREG), 16, RTSF_INTW, 0 },
+ { STRMEM("Hr"), sizeof(RTHCUINTREG), 16, RTSF_INTW, 0 },
{ STRMEM("Hu"), sizeof(RTHCUINT), 10, RTSF_INT, 0 },
{ STRMEM("Hv"), sizeof(RTHCPTR), 16, RTSF_INTW, 0 },
{ STRMEM("Hx"), sizeof(RTHCUINT), 16, RTSF_INT, 0 },
@@ -394,24 +509,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
case RTSF_IPV6:
{
if (VALID_PTR(u.pIpv6Addr))
- return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
- u.pIpv6Addr->au8[0],
- u.pIpv6Addr->au8[1],
- u.pIpv6Addr->au8[2],
- u.pIpv6Addr->au8[3],
- u.pIpv6Addr->au8[4],
- u.pIpv6Addr->au8[5],
- u.pIpv6Addr->au8[6],
- u.pIpv6Addr->au8[7],
- u.pIpv6Addr->au8[8],
- u.pIpv6Addr->au8[9],
- u.pIpv6Addr->au8[10],
- u.pIpv6Addr->au8[11],
- u.pIpv6Addr->au8[12],
- u.pIpv6Addr->au8[13],
- u.pIpv6Addr->au8[14],
- u.pIpv6Addr->au8[15]);
+ return rtstrFormatIPv6(pfnOutput, pvArgOutput, u.pIpv6Addr);
return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
}
@@ -453,42 +551,11 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
case RTNETADDRTYPE_IPV6:
if (u.pNetAddr->uPort == RTNETADDR_PORT_NA)
- return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
- u.pNetAddr->uAddr.IPv6.au8[0],
- u.pNetAddr->uAddr.IPv6.au8[1],
- u.pNetAddr->uAddr.IPv6.au8[2],
- u.pNetAddr->uAddr.IPv6.au8[3],
- u.pNetAddr->uAddr.IPv6.au8[4],
- u.pNetAddr->uAddr.IPv6.au8[5],
- u.pNetAddr->uAddr.IPv6.au8[6],
- u.pNetAddr->uAddr.IPv6.au8[7],
- u.pNetAddr->uAddr.IPv6.au8[8],
- u.pNetAddr->uAddr.IPv6.au8[9],
- u.pNetAddr->uAddr.IPv6.au8[10],
- u.pNetAddr->uAddr.IPv6.au8[11],
- u.pNetAddr->uAddr.IPv6.au8[12],
- u.pNetAddr->uAddr.IPv6.au8[13],
- u.pNetAddr->uAddr.IPv6.au8[14],
- u.pNetAddr->uAddr.IPv6.au8[15]);
+ return rtstrFormatIPv6(pfnOutput, pvArgOutput, &u.pNetAddr->uAddr.IPv6);
+
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x %u",
- u.pNetAddr->uAddr.IPv6.au8[0],
- u.pNetAddr->uAddr.IPv6.au8[1],
- u.pNetAddr->uAddr.IPv6.au8[2],
- u.pNetAddr->uAddr.IPv6.au8[3],
- u.pNetAddr->uAddr.IPv6.au8[4],
- u.pNetAddr->uAddr.IPv6.au8[5],
- u.pNetAddr->uAddr.IPv6.au8[6],
- u.pNetAddr->uAddr.IPv6.au8[7],
- u.pNetAddr->uAddr.IPv6.au8[8],
- u.pNetAddr->uAddr.IPv6.au8[9],
- u.pNetAddr->uAddr.IPv6.au8[10],
- u.pNetAddr->uAddr.IPv6.au8[11],
- u.pNetAddr->uAddr.IPv6.au8[12],
- u.pNetAddr->uAddr.IPv6.au8[13],
- u.pNetAddr->uAddr.IPv6.au8[14],
- u.pNetAddr->uAddr.IPv6.au8[15],
+ "[%RTnaipv6]:%u",
+ &u.pNetAddr->uAddr.IPv6,
u.pNetAddr->uPort);
case RTNETADDRTYPE_MAC:
@@ -558,7 +625,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
const char *pszLastSep;
const char *psz = pszLastSep = va_arg(*pArgs, const char *);
if (!VALID_PTR(psz))
- return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
while ((ch = *psz) != '\0')
{
@@ -602,7 +669,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
const char *pszStart;
const char *psz = pszStart = va_arg(*pArgs, const char *);
if (!VALID_PTR(psz))
- return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
while ((ch = *psz) != '\0' && ch != '(')
{
@@ -664,7 +731,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
while (off < cchPrecision)
{
int i;
- cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*x %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*p %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
for (i = 0; i < cchWidth && off + i < cchPrecision ; i++)
cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
off + i < cchPrecision ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pu8[i]);
@@ -707,7 +774,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
}
}
else
- return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
break;
}
@@ -903,7 +970,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
* If it's a pointer, we'll check if it's valid before going on.
*/
if ((s_aTypes[i].fFlags & RTST_FLAGS_POINTER) && !VALID_PTR(u.pv))
- return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
/*
* Format the output.
@@ -1098,7 +1165,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
REG_OUT_BIT(cr4, X86_CR4_SMXE, "SMXE");
REG_OUT_BIT(cr4, X86_CR4_PCIDE, "PCIDE");
REG_OUT_BIT(cr4, X86_CR4_OSXSAVE, "OSXSAVE");
- REG_OUT_BIT(cr4, X86_CR4_SMEP, "SMPE");
+ REG_OUT_BIT(cr4, X86_CR4_SMEP, "SMEP");
REG_OUT_CLOSE(cr4);
}
else
diff --git a/src/VBox/Runtime/common/string/strformattype.cpp b/src/VBox/Runtime/common/string/strformattype.cpp
index e9e3611a..c37f3b53 100644
--- a/src/VBox/Runtime/common/string/strformattype.cpp
+++ b/src/VBox/Runtime/common/string/strformattype.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -466,9 +466,9 @@ DECLHIDDEN(size_t) rtstrFormatType(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
{
rtstrFormatTypeReadUnlock();
- cch = pfnOutput(pvArgOutput, "<missing:%R[", sizeof("<missing:%R[") - 1);
+ cch = pfnOutput(pvArgOutput, RT_STR_TUPLE("<missing:%R["));
cch += pfnOutput(pvArgOutput, pszType, pszTypeEnd - pszType);
- cch += pfnOutput(pvArgOutput, "]>", sizeof("]>") - 1);
+ cch += pfnOutput(pvArgOutput, RT_STR_TUPLE("]>"));
}
return cch;
diff --git a/src/VBox/Runtime/common/string/strlen.asm b/src/VBox/Runtime/common/string/strlen.asm
index e3ff2f37..b34e5769 100644
--- a/src/VBox/Runtime/common/string/strlen.asm
+++ b/src/VBox/Runtime/common/string/strlen.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2008 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strlen.cpp b/src/VBox/Runtime/common/string/strlen.cpp
index 173ba2cb..792b040c 100644
--- a/src/VBox/Runtime/common/string/strlen.cpp
+++ b/src/VBox/Runtime/common/string/strlen.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strlen_alias.c b/src/VBox/Runtime/common/string/strlen_alias.c
index 8fab3d16..da471606 100644
--- a/src/VBox/Runtime/common/string/strlen_alias.c
+++ b/src/VBox/Runtime/common/string/strlen_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strncmp.cpp b/src/VBox/Runtime/common/string/strncmp.cpp
index 16faf4b1..24d3fe43 100644
--- a/src/VBox/Runtime/common/string/strncmp.cpp
+++ b/src/VBox/Runtime/common/string/strncmp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strpbrk.cpp b/src/VBox/Runtime/common/string/strpbrk.cpp
index e8d49a81..4e341ee9 100644
--- a/src/VBox/Runtime/common/string/strpbrk.cpp
+++ b/src/VBox/Runtime/common/string/strpbrk.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strprintf.cpp b/src/VBox/Runtime/common/string/strprintf.cpp
index 13bfd4b7..5e96e253 100644
--- a/src/VBox/Runtime/common/string/strprintf.cpp
+++ b/src/VBox/Runtime/common/string/strprintf.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strspace.cpp b/src/VBox/Runtime/common/string/strspace.cpp
index a27a417d..d76c1c19 100644
--- a/src/VBox/Runtime/common/string/strspace.cpp
+++ b/src/VBox/Runtime/common/string/strspace.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strstrip.cpp b/src/VBox/Runtime/common/string/strstrip.cpp
index 3f1b2809..9e930c8a 100644
--- a/src/VBox/Runtime/common/string/strstrip.cpp
+++ b/src/VBox/Runtime/common/string/strstrip.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strtonum.cpp b/src/VBox/Runtime/common/string/strtonum.cpp
index beb9b082..4d49a307 100644
--- a/src/VBox/Runtime/common/string/strtonum.cpp
+++ b/src/VBox/Runtime/common/string/strtonum.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strversion.cpp b/src/VBox/Runtime/common/string/strversion.cpp
index 7a93bc8d..8c38c864 100644
--- a/src/VBox/Runtime/common/string/strversion.cpp
+++ b/src/VBox/Runtime/common/string/strversion.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/uni.cpp b/src/VBox/Runtime/common/string/uni.cpp
index 1fe613ec..d1bdb8b0 100644
--- a/src/VBox/Runtime/common/string/uni.cpp
+++ b/src/VBox/Runtime/common/string/uni.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/unidata.cpp b/src/VBox/Runtime/common/string/unidata.cpp
index ea5ce4ed..aa2679e2 100644
--- a/src/VBox/Runtime/common/string/unidata.cpp
+++ b/src/VBox/Runtime/common/string/unidata.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/uniread.cpp b/src/VBox/Runtime/common/string/uniread.cpp
index e532482f..01ddd1ca 100644
--- a/src/VBox/Runtime/common/string/uniread.cpp
+++ b/src/VBox/Runtime/common/string/uniread.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -919,7 +919,7 @@ static int Stream1Printf(const char *pszFormat, ...)
if (!g_fQuiet)
cch = vfprintf(stdout, pszFormat, va);
else
- cch = strlen(pszFormat);
+ cch = (int)strlen(pszFormat);
va_end(va);
return cch;
}
diff --git a/src/VBox/Runtime/common/string/utf-16.cpp b/src/VBox/Runtime/common/string/utf-16.cpp
index 3c89a3b0..9386b5d7 100644
--- a/src/VBox/Runtime/common/string/utf-16.cpp
+++ b/src/VBox/Runtime/common/string/utf-16.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/utf-8-case.cpp b/src/VBox/Runtime/common/string/utf-8-case.cpp
index 7a0bf2eb..e674944f 100644
--- a/src/VBox/Runtime/common/string/utf-8-case.cpp
+++ b/src/VBox/Runtime/common/string/utf-8-case.cpp
@@ -338,3 +338,82 @@ RTDECL(char *) RTStrToUpper(char *psz)
}
RT_EXPORT_SYMBOL(RTStrToUpper);
+
+RTDECL(bool) RTStrIsCaseFoldable(const char *psz)
+{
+ /*
+ * Loop the code points in the string, checking them one by one until we
+ * find something that can be folded.
+ */
+ RTUNICP uc;
+ do
+ {
+ int rc = RTStrGetCpEx(&psz, &uc);
+ if (RT_SUCCESS(rc))
+ {
+ if (RTUniCpIsFoldable(uc))
+ return true;
+ }
+ else
+ {
+ /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */
+ AssertRC(rc);
+ }
+ } while (uc != 0);
+
+ return false;
+}
+RT_EXPORT_SYMBOL(RTStrIsCaseFoldable);
+
+
+RTDECL(bool) RTStrIsUpperCased(const char *psz)
+{
+ /*
+ * Check that there are no lower case chars in the string.
+ */
+ RTUNICP uc;
+ do
+ {
+ int rc = RTStrGetCpEx(&psz, &uc);
+ if (RT_SUCCESS(rc))
+ {
+ if (RTUniCpIsLower(uc))
+ return false;
+ }
+ else
+ {
+ /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */
+ AssertRC(rc);
+ }
+ } while (uc != 0);
+
+ return true;
+}
+RT_EXPORT_SYMBOL(RTStrIsUpperCased);
+
+
+RTDECL(bool) RTStrIsLowerCased(const char *psz)
+{
+ /*
+ * Check that there are no lower case chars in the string.
+ */
+ RTUNICP uc;
+ do
+ {
+ int rc = RTStrGetCpEx(&psz, &uc);
+ if (RT_SUCCESS(rc))
+ {
+ if (RTUniCpIsUpper(uc))
+ return false;
+ }
+ else
+ {
+ /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */
+ AssertRC(rc);
+ }
+ } while (uc != 0);
+
+ return true;
+}
+RT_EXPORT_SYMBOL(RTStrIsLowerCased);
+
diff --git a/src/VBox/Runtime/common/string/utf-8.cpp b/src/VBox/Runtime/common/string/utf-8.cpp
index 0e486e97..fdeb505e 100644
--- a/src/VBox/Runtime/common/string/utf-8.cpp
+++ b/src/VBox/Runtime/common/string/utf-8.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/table/avl_Base.cpp.h b/src/VBox/Runtime/common/table/avl_Base.cpp.h
index 6ea6d0ef..3fc89cb3 100644
--- a/src/VBox/Runtime/common/table/avl_Base.cpp.h
+++ b/src/VBox/Runtime/common/table/avl_Base.cpp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2002 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2012 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/table/avl_Destroy.cpp.h b/src/VBox/Runtime/common/table/avl_Destroy.cpp.h
index 0e0174b4..5ae25210 100644
--- a/src/VBox/Runtime/common/table/avl_Destroy.cpp.h
+++ b/src/VBox/Runtime/common/table/avl_Destroy.cpp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 1999-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 1999-2011 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -47,7 +47,7 @@ KAVL_DECL(int) KAVL_FN(Destroy)(PPKAVLNODECORE ppTree, PKAVLCALLBACK pfnCallBack
int rc;
if (*ppTree == KAVL_NULL)
- return 0;
+ return VINF_SUCCESS;
cEntries = 1;
apEntries[0] = KAVL_GET_POINTER(ppTree);
@@ -74,7 +74,7 @@ KAVL_DECL(int) KAVL_FN(Destroy)(PPKAVLNODECORE ppTree, PKAVLCALLBACK pfnCallBack
pEqual->pList = KAVL_NULL;
rc = pfnCallBack(pEqual, pvUser);
- if (rc)
+ if (rc != VINF_SUCCESS)
return rc;
}
#endif
@@ -96,14 +96,14 @@ KAVL_DECL(int) KAVL_FN(Destroy)(PPKAVLNODECORE ppTree, PKAVLCALLBACK pfnCallBack
kASSERT(pNode->pLeft == KAVL_NULL);
kASSERT(pNode->pRight == KAVL_NULL);
rc = pfnCallBack(pNode, pvUser);
- if (rc)
+ if (rc != VINF_SUCCESS)
return rc;
}
} /* while */
kASSERT(*ppTree == KAVL_NULL);
- return 0;
+ return VINF_SUCCESS;
}
#endif
diff --git a/src/VBox/Runtime/common/table/avl_DoWithAll.cpp.h b/src/VBox/Runtime/common/table/avl_DoWithAll.cpp.h
index 25c9e82d..fad8e72a 100644
--- a/src/VBox/Runtime/common/table/avl_DoWithAll.cpp.h
+++ b/src/VBox/Runtime/common/table/avl_DoWithAll.cpp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 1999-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 1999-2011 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -47,7 +47,7 @@ KAVL_DECL(int) KAVL_FN(DoWithAll)(PPKAVLNODECORE ppTree, int fFromLeft, PKAVLCAL
int rc;
if (*ppTree == KAVL_NULL)
- return 0;
+ return VINF_SUCCESS;
AVLStack.cEntries = 1;
AVLStack.achFlags[0] = 0;
@@ -72,14 +72,14 @@ KAVL_DECL(int) KAVL_FN(DoWithAll)(PPKAVLNODECORE ppTree, int fFromLeft, PKAVLCAL
/* center */
rc = pfnCallBack(pNode, pvParam);
- if (rc)
+ if (rc != VINF_SUCCESS)
return rc;
#ifdef KAVL_EQUAL_ALLOWED
if (pNode->pList != KAVL_NULL)
for (pEqual = KAVL_GET_POINTER(&pNode->pList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->pList))
{
rc = pfnCallBack(pEqual, pvParam);
- if (rc)
+ if (rc != VINF_SUCCESS)
return rc;
}
#endif
@@ -112,14 +112,14 @@ KAVL_DECL(int) KAVL_FN(DoWithAll)(PPKAVLNODECORE ppTree, int fFromLeft, PKAVLCAL
/* center */
rc = pfnCallBack(pNode, pvParam);
- if (rc)
+ if (rc != VINF_SUCCESS)
return rc;
#ifdef KAVL_EQUAL_ALLOWED
if (pNode->pList != KAVL_NULL)
for (pEqual = KAVL_GET_POINTER(&pNode->pList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->pList))
{
rc = pfnCallBack(pEqual, pvParam);
- if (rc)
+ if (rc != VINF_SUCCESS)
return rc;
}
#endif
@@ -134,7 +134,7 @@ KAVL_DECL(int) KAVL_FN(DoWithAll)(PPKAVLNODECORE ppTree, int fFromLeft, PKAVLCAL
} /* while */
}
- return 0;
+ return VINF_SUCCESS;
}
diff --git a/src/VBox/Runtime/common/table/avl_Enum.cpp.h b/src/VBox/Runtime/common/table/avl_Enum.cpp.h
index 1d6e5365..6cde86a1 100644
--- a/src/VBox/Runtime/common/table/avl_Enum.cpp.h
+++ b/src/VBox/Runtime/common/table/avl_Enum.cpp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/table/avl_Get.cpp.h b/src/VBox/Runtime/common/table/avl_Get.cpp.h
index 36c8713b..9b245923 100644
--- a/src/VBox/Runtime/common/table/avl_Get.cpp.h
+++ b/src/VBox/Runtime/common/table/avl_Get.cpp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 1999-2002 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 1999-2012 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/table/avl_GetBestFit.cpp.h b/src/VBox/Runtime/common/table/avl_GetBestFit.cpp.h
index d15f167f..ad217498 100644
--- a/src/VBox/Runtime/common/table/avl_GetBestFit.cpp.h
+++ b/src/VBox/Runtime/common/table/avl_GetBestFit.cpp.h
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 1999-2002 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 1999-2012 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/table/avl_Range.cpp.h b/src/VBox/Runtime/common/table/avl_Range.cpp.h
index 3e66c206..be4de7b4 100644
--- a/src/VBox/Runtime/common/table/avl_Range.cpp.h
+++ b/src/VBox/Runtime/common/table/avl_Range.cpp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 1999-2006 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 1999-2011 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/table/avl_RemoveBestFit.cpp.h b/src/VBox/Runtime/common/table/avl_RemoveBestFit.cpp.h
index 77825f82..45f9bc38 100644
--- a/src/VBox/Runtime/common/table/avl_RemoveBestFit.cpp.h
+++ b/src/VBox/Runtime/common/table/avl_RemoveBestFit.cpp.h
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 1999-2002 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 1999-2011 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/table/avl_RemoveNode.cpp.h b/src/VBox/Runtime/common/table/avl_RemoveNode.cpp.h
index 179e1359..ce87aa3d 100644
--- a/src/VBox/Runtime/common/table/avl_RemoveNode.cpp.h
+++ b/src/VBox/Runtime/common/table/avl_RemoveNode.cpp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2002 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2012 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -141,4 +141,3 @@ KAVL_DECL(PKAVLNODECORE) KAVL_FN(RemoveNode)(PPKAVLNODECORE ppTree, PKAVLNODECOR
#endif
}
-
diff --git a/src/VBox/Runtime/common/table/avlgcphys.cpp b/src/VBox/Runtime/common/table/avlgcphys.cpp
index 7f8566b1..3ab3f972 100644
--- a/src/VBox/Runtime/common/table/avlgcphys.cpp
+++ b/src/VBox/Runtime/common/table/avlgcphys.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -60,6 +60,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlgcptr.cpp b/src/VBox/Runtime/common/table/avlgcptr.cpp
index 42666860..8eb2b946 100644
--- a/src/VBox/Runtime/common/table/avlgcptr.cpp
+++ b/src/VBox/Runtime/common/table/avlgcptr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2003 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -60,7 +60,7 @@ static const char szFileId[] = "Id: kAVLPVInt.c,v 1.5 2003/02/13 02:02:35 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
-
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlhcphys.cpp b/src/VBox/Runtime/common/table/avlhcphys.cpp
index 499c5553..229dc638 100644
--- a/src/VBox/Runtime/common/table/avlhcphys.cpp
+++ b/src/VBox/Runtime/common/table/avlhcphys.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -60,6 +60,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avllu32.cpp b/src/VBox/Runtime/common/table/avllu32.cpp
index 45bc2a2f..f6ec3bc0 100644
--- a/src/VBox/Runtime/common/table/avllu32.cpp
+++ b/src/VBox/Runtime/common/table/avllu32.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2006 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2012 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -60,6 +60,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlogcphys.cpp b/src/VBox/Runtime/common/table/avlogcphys.cpp
index 01cb5f0e..0d4ddefe 100644
--- a/src/VBox/Runtime/common/table/avlogcphys.cpp
+++ b/src/VBox/Runtime/common/table/avlogcphys.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -61,6 +61,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlogcptr.cpp b/src/VBox/Runtime/common/table/avlogcptr.cpp
index 6602c309..f25536ba 100644
--- a/src/VBox/Runtime/common/table/avlogcptr.cpp
+++ b/src/VBox/Runtime/common/table/avlogcptr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -62,6 +62,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlohcphys.cpp b/src/VBox/Runtime/common/table/avlohcphys.cpp
index 9f6dabae..39f64c18 100644
--- a/src/VBox/Runtime/common/table/avlohcphys.cpp
+++ b/src/VBox/Runtime/common/table/avlohcphys.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -61,6 +61,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avloioport.cpp b/src/VBox/Runtime/common/table/avloioport.cpp
index 38aa6906..e1f5f91c 100644
--- a/src/VBox/Runtime/common/table/avloioport.cpp
+++ b/src/VBox/Runtime/common/table/avloioport.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -61,6 +61,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlou32.cpp b/src/VBox/Runtime/common/table/avlou32.cpp
index c01cafa1..0ae06da1 100644
--- a/src/VBox/Runtime/common/table/avlou32.cpp
+++ b/src/VBox/Runtime/common/table/avlou32.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -62,6 +62,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlpv.cpp b/src/VBox/Runtime/common/table/avlpv.cpp
index c3068070..ee090ad4 100644
--- a/src/VBox/Runtime/common/table/avlpv.cpp
+++ b/src/VBox/Runtime/common/table/avlpv.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2003 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -60,7 +60,7 @@ static const char szFileId[] = "Id: kAVLPVInt.c,v 1.5 2003/02/13 02:02:35 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
-
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlrfoff.cpp b/src/VBox/Runtime/common/table/avlrfoff.cpp
index dd6391b6..268482be 100644
--- a/src/VBox/Runtime/common/table/avlrfoff.cpp
+++ b/src/VBox/Runtime/common/table/avlrfoff.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -65,6 +65,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlrgcptr.cpp b/src/VBox/Runtime/common/table/avlrgcptr.cpp
index 4ea64fd2..c83ae932 100644
--- a/src/VBox/Runtime/common/table/avlrgcptr.cpp
+++ b/src/VBox/Runtime/common/table/avlrgcptr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -65,6 +65,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlrogcphys.cpp b/src/VBox/Runtime/common/table/avlrogcphys.cpp
index f52acdbb..c7496e91 100644
--- a/src/VBox/Runtime/common/table/avlrogcphys.cpp
+++ b/src/VBox/Runtime/common/table/avlrogcphys.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -66,6 +66,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlrogcptr.cpp b/src/VBox/Runtime/common/table/avlrogcptr.cpp
index 2f455947..ab167f2d 100644
--- a/src/VBox/Runtime/common/table/avlrogcptr.cpp
+++ b/src/VBox/Runtime/common/table/avlrogcptr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -66,6 +66,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlroioport.cpp b/src/VBox/Runtime/common/table/avlroioport.cpp
index 9aa58341..9534c29c 100644
--- a/src/VBox/Runtime/common/table/avlroioport.cpp
+++ b/src/VBox/Runtime/common/table/avlroioport.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -66,6 +66,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlroogcptr.cpp b/src/VBox/Runtime/common/table/avlroogcptr.cpp
index 6c425d5b..5d45aaf8 100644
--- a/src/VBox/Runtime/common/table/avlroogcptr.cpp
+++ b/src/VBox/Runtime/common/table/avlroogcptr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -62,6 +62,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlrpv.cpp b/src/VBox/Runtime/common/table/avlrpv.cpp
index f7e00339..40d865f2 100644
--- a/src/VBox/Runtime/common/table/avlrpv.cpp
+++ b/src/VBox/Runtime/common/table/avlrpv.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2003 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -64,7 +64,7 @@ static const char szFileId[] = "Id: kAVLPVInt.c,v 1.5 2003/02/13 02:02:35 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
-
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlru64.cpp b/src/VBox/Runtime/common/table/avlru64.cpp
index a7476ea5..6b575b7f 100644
--- a/src/VBox/Runtime/common/table/avlru64.cpp
+++ b/src/VBox/Runtime/common/table/avlru64.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2003 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -64,7 +64,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.5 2003/02/13 02:02:35 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
-
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlruintptr.cpp b/src/VBox/Runtime/common/table/avlruintptr.cpp
index c267284a..5fc868ba 100644
--- a/src/VBox/Runtime/common/table/avlruintptr.cpp
+++ b/src/VBox/Runtime/common/table/avlruintptr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -65,6 +65,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlu32.cpp b/src/VBox/Runtime/common/table/avlu32.cpp
index 3bf1283b..41de76f4 100644
--- a/src/VBox/Runtime/common/table/avlu32.cpp
+++ b/src/VBox/Runtime/common/table/avlu32.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2006 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -60,6 +60,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avluintptr.cpp b/src/VBox/Runtime/common/table/avluintptr.cpp
index 08d3eb45..94834f8b 100644
--- a/src/VBox/Runtime/common/table/avluintptr.cpp
+++ b/src/VBox/Runtime/common/table/avluintptr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2006-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -60,6 +60,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/avlul.cpp b/src/VBox/Runtime/common/table/avlul.cpp
index 62b94f97..62858dc2 100644
--- a/src/VBox/Runtime/common/table/avlul.cpp
+++ b/src/VBox/Runtime/common/table/avlul.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2003 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -60,6 +60,7 @@ static const char szFileId[] = "Id: kAVLULInt.c,v 1.4 2003/02/13 02:02:38 bird E
*******************************************************************************/
#include <iprt/avl.h>
#include <iprt/assert.h>
+#include <iprt/err.h>
/*
* Include the code.
diff --git a/src/VBox/Runtime/common/table/table.cpp b/src/VBox/Runtime/common/table/table.cpp
index b2d7c8b0..6c0a9a2e 100644
--- a/src/VBox/Runtime/common/table/table.cpp
+++ b/src/VBox/Runtime/common/table/table.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2001-2006 knut st. osmundsen (bird-src-spam@anduin.net)
+ * Copyright (C) 2001-2010 knut st. osmundsen (bird-src-spam@anduin.net)
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/time/time.cpp b/src/VBox/Runtime/common/time/time.cpp
index bbeeeb7d..f16911ad 100644
--- a/src/VBox/Runtime/common/time/time.cpp
+++ b/src/VBox/Runtime/common/time/time.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -32,6 +32,7 @@
#include <iprt/time.h>
#include "internal/iprt.h"
+#include <iprt/ctype.h>
#include <iprt/string.h>
#include <iprt/assert.h>
#include "internal/time.h"
@@ -743,3 +744,164 @@ RTDECL(char *) RTTimeSpecToString(PCRTTIMESPEC pTime, char *psz, size_t cb)
}
RT_EXPORT_SYMBOL(RTTimeSpecToString);
+
+
+/**
+ * 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)
+{
+ /* Ignore leading spaces. */
+ while (RT_C_IS_SPACE(*pszString))
+ pszString++;
+
+ /*
+ * Init non date & time parts.
+ */
+ pTime->fFlags = RTTIME_FLAGS_TYPE_LOCAL;
+ pTime->offUTC = 0;
+
+ /*
+ * The day part.
+ */
+
+ /* Year */
+ int rc = RTStrToInt32Ex(pszString, (char **)&pszString, 10, &pTime->i32Year);
+ if (rc != VWRN_TRAILING_CHARS)
+ return NULL;
+
+ bool const fLeapYear = rtTimeIsLeapYear(pTime->i32Year);
+ if (fLeapYear)
+ pTime->fFlags |= RTTIME_FLAGS_LEAP_YEAR;
+
+ if (*pszString++ != '-')
+ return NULL;
+
+ /* Month of the year. */
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Month);
+ if (rc != VWRN_TRAILING_CHARS)
+ return NULL;
+ if (pTime->u8Month == 0 || pTime->u8Month > 12)
+ return NULL;
+ if (*pszString++ != '-')
+ return NULL;
+
+ /* Day of month.*/
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8MonthDay);
+ if (rc != VWRN_TRAILING_CHARS && rc != VINF_SUCCESS)
+ return NULL;
+ unsigned const cDaysInMonth = fLeapYear
+ ? g_acDaysInMonthsLeap[pTime->u8Month - 1]
+ : g_acDaysInMonthsLeap[pTime->u8Month - 1];
+ if (pTime->u8MonthDay == 0 || pTime->u8MonthDay > cDaysInMonth)
+ return NULL;
+
+ /* Calculate year day. */
+ pTime->u16YearDay = pTime->u8MonthDay - 1
+ + (fLeapYear
+ ? g_aiDayOfYearLeap[pTime->u8Month - 1]
+ : g_aiDayOfYear[pTime->u8Month - 1]);
+
+ /*
+ * The time part.
+ */
+ if (*pszString++ != 'T')
+ return NULL;
+
+ /* Hour. */
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Hour);
+ if (rc != VWRN_TRAILING_CHARS)
+ return NULL;
+ if (pTime->u8Hour > 23)
+ return NULL;
+ if (*pszString++ != ':')
+ return NULL;
+
+ /* Minute. */
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Minute);
+ if (rc != VWRN_TRAILING_CHARS)
+ return NULL;
+ if (pTime->u8Minute > 59)
+ return NULL;
+ if (*pszString++ != ':')
+ return NULL;
+
+ /* Second. */
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Minute);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES)
+ return NULL;
+ if (pTime->u8Second > 59)
+ return NULL;
+
+ /* Nanoseconds is optional and probably non-standard. */
+ if (*pszString == '.')
+ {
+ rc = RTStrToUInt32Ex(pszString + 1, (char **)&pszString, 10, &pTime->u32Nanosecond);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES)
+ return NULL;
+ if (pTime->u32Nanosecond >= 1000000000)
+ return NULL;
+ }
+ else
+ pTime->u32Nanosecond = 0;
+
+ /*
+ * Time zone.
+ */
+ if (*pszString == 'Z')
+ {
+ pszString++;
+ pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK;
+ pTime->fFlags |= ~RTTIME_FLAGS_TYPE_UTC;
+ pTime->offUTC = 0;
+ }
+ else if ( *pszString == '+'
+ || *pszString == '-')
+ {
+ rc = RTStrToInt32Ex(pszString, (char **)&pszString, 10, &pTime->offUTC);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES)
+ return NULL;
+ }
+ /* else: No time zone given, local with offUTC = 0. */
+
+ /*
+ * The rest of the string should be blanks.
+ */
+ char ch;
+ while ((ch = *pszString++) != '\0')
+ if (!RT_C_IS_BLANK(ch))
+ return NULL;
+
+ return pTime;
+}
+RT_EXPORT_SYMBOL(RTTimeFromString);
+
+
+/**
+ * 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)
+{
+ RTTIME Time;
+ if (RTTimeFromString(&Time, pszString))
+ return RTTimeImplode(pTime, &Time);
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTTimeSpecFromString);
+
diff --git a/src/VBox/Runtime/common/time/timeprog.cpp b/src/VBox/Runtime/common/time/timeprog.cpp
index fefe4082..13e810cf 100644
--- a/src/VBox/Runtime/common/time/timeprog.cpp
+++ b/src/VBox/Runtime/common/time/timeprog.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/time/timesup.cpp b/src/VBox/Runtime/common/time/timesup.cpp
index 6a51fd6d..b95c4f37 100644
--- a/src/VBox/Runtime/common/time/timesup.cpp
+++ b/src/VBox/Runtime/common/time/timesup.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/time/timesupA.asm b/src/VBox/Runtime/common/time/timesupA.asm
index 9c044930..2cee44cf 100644
--- a/src/VBox/Runtime/common/time/timesupA.asm
+++ b/src/VBox/Runtime/common/time/timesupA.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/time/timesupA.mac b/src/VBox/Runtime/common/time/timesupA.mac
index b146c5a6..54c92000 100644
--- a/src/VBox/Runtime/common/time/timesupA.mac
+++ b/src/VBox/Runtime/common/time/timesupA.mac
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2011 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/time/timesupref.h b/src/VBox/Runtime/common/time/timesupref.h
index e7b34513..60438983 100644
--- a/src/VBox/Runtime/common/time/timesupref.h
+++ b/src/VBox/Runtime/common/time/timesupref.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/time/timesysalias.cpp b/src/VBox/Runtime/common/time/timesysalias.cpp
index 37f65d39..3b5e47a4 100644
--- a/src/VBox/Runtime/common/time/timesysalias.cpp
+++ b/src/VBox/Runtime/common/time/timesysalias.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/vfs/vfsbase.cpp b/src/VBox/Runtime/common/vfs/vfsbase.cpp
index 49984513..8e38715b 100644
--- a/src/VBox/Runtime/common/vfs/vfsbase.cpp
+++ b/src/VBox/Runtime/common/vfs/vfsbase.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/vfs/vfschain.cpp b/src/VBox/Runtime/common/vfs/vfschain.cpp
index 0017cf38..2e43b261 100644
--- a/src/VBox/Runtime/common/vfs/vfschain.cpp
+++ b/src/VBox/Runtime/common/vfs/vfschain.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -63,13 +63,11 @@ static RTLISTANCHOR g_rtVfsChainElementProviderList;
* Initializes the globals via RTOnce.
*
* @returns IPRT status code
- * @param pvUser1 Unused, ignored.
- * @param pvUser2 Unused, ignored.
+ * @param pvUser Unused, ignored.
*/
-static DECLCALLBACK(int) rtVfsChainElementRegisterInit(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int) rtVfsChainElementRegisterInit(void *pvUser)
{
- NOREF(pvUser1);
- NOREF(pvUser2);
+ NOREF(pvUser);
return RTCritSectInit(&g_rtVfsChainElementCritSect);
}
@@ -97,7 +95,7 @@ RTDECL(int) RTVfsChainElementRegisterProvider(PRTVFSCHAINELEMENTREG pRegRec, boo
*/
if (!fFromCtor)
{
- rc = RTOnce(&g_rtVfsChainElementInitOnce, rtVfsChainElementRegisterInit, NULL, NULL);
+ rc = RTOnce(&g_rtVfsChainElementInitOnce, rtVfsChainElementRegisterInit, NULL);
if (RT_FAILURE(rc))
return rc;
rc = RTCritSectEnter(&g_rtVfsChainElementCritSect);
diff --git a/src/VBox/Runtime/common/vfs/vfsmisc.cpp b/src/VBox/Runtime/common/vfs/vfsmisc.cpp
index f35005d3..1f353fb0 100644
--- a/src/VBox/Runtime/common/vfs/vfsmisc.cpp
+++ b/src/VBox/Runtime/common/vfs/vfsmisc.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/vfs/vfsstdfile.cpp b/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
index 8b01af67..5f023e74 100644
--- a/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
+++ b/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -418,6 +418,31 @@ DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtVfsStdFileOps =
};
+/**
+ * Internal worker for RTVfsFileFromRTFile and RTVfsFileOpenNormal.
+ *
+ * @returns IRPT status code.
+ * @param hFile The IPRT file handle.
+ * @param fOpen The RTFILE_O_XXX flags.
+ * @param fLeaveOpen Whether to leave it open or close it.
+ * @param phVfsFile Where to return the handle.
+ */
+static int rtVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
+{
+ PRTVFSSTDFILE pThis;
+ RTVFSFILE hVfsFile;
+ int rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(RTVFSSTDFILE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK,
+ &hVfsFile, (void **)&pThis);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ pThis->hFile = hFile;
+ pThis->fLeaveOpen = fLeaveOpen;
+ *phVfsFile = hVfsFile;
+ return VINF_SUCCESS;
+}
+
+
RTDECL(int) RTVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
{
/*
@@ -429,28 +454,36 @@ RTDECL(int) RTVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, P
return rc;
/*
- * Set up some fake fOpen flags.
+ * Set up some fake fOpen flags if necessary and create a VFS file handle.
*/
if (!fOpen)
fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN_CREATE;
+ return rtVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, phVfsFile);
+}
+
+
+RTDECL(int) RTVfsFileOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
+{
/*
- * Create the handle.
+ * Open the file the normal way and pass it to RTVfsFileFromRTFile.
*/
- PRTVFSSTDFILE pThis;
- RTVFSFILE hVfsFile;
- rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(RTVFSSTDFILE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
- if (RT_FAILURE(rc))
- return rc;
-
- pThis->hFile = hFile;
- pThis->fLeaveOpen = fLeaveOpen;
- *phVfsFile = hVfsFile;
- return VINF_SUCCESS;
+ RTFILE hFile;
+ int rc = RTFileOpen(&hFile, pszFilename, fOpen);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create a VFS file handle.
+ */
+ rc = rtVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, phVfsFile);
+ if (RT_FAILURE(rc))
+ RTFileClose(hFile);
+ }
+ return rc;
}
-RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
+RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
{
RTVFSFILE hVfsFile;
int rc = RTVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, &hVfsFile);
@@ -459,3 +492,13 @@ RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLe
return rc;
}
+
+RTDECL(int) RTVfsIoStrmOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
+{
+ RTVFSFILE hVfsFile;
+ int rc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
+ if (RT_SUCCESS(rc))
+ *phVfsIos = RTVfsFileToIoStream(hVfsFile);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/zip/gzipvfs.cpp b/src/VBox/Runtime/common/zip/gzipvfs.cpp
index d6b952ca..87efeb1b 100644
--- a/src/VBox/Runtime/common/zip/gzipvfs.cpp
+++ b/src/VBox/Runtime/common/zip/gzipvfs.cpp
@@ -56,6 +56,7 @@ PFNRT g_apfnRTZlibDeps[] =
};
#endif /* RT_OS_OS2 || RT_OS_SOLARIS || RT_OS_WINDOWS */
+
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
@@ -167,6 +168,12 @@ typedef struct RTZIPGZIPSTREAM
typedef RTZIPGZIPSTREAM *PRTZIPGZIPSTREAM;
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int rtZipGzip_FlushIt(PRTZIPGZIPSTREAM pThis, uint8_t fFlushType);
+
+
/**
* Convert from zlib to IPRT status codes.
*
@@ -223,11 +230,22 @@ static DECLCALLBACK(int) rtZipGzip_Close(void *pvThis)
int rc;
if (pThis->fDecompress)
+ {
rc = inflateEnd(&pThis->Zlib);
+ if (rc != Z_OK)
+ rc = rtZipGzipConvertErrFromZlib(pThis, rc);
+ }
else
- rc = deflateEnd(&pThis->Zlib);
- if (rc != Z_OK)
- rc = rtZipGzipConvertErrFromZlib(pThis, rc);
+ {
+ /* Flush the compression stream before terminating it. */
+ rc = VINF_SUCCESS;
+ if (!pThis->fFatalError)
+ rc = rtZipGzip_FlushIt(pThis, Z_FINISH);
+
+ int rc2 = deflateEnd(&pThis->Zlib);
+ if (RT_SUCCESS(rc) && rc2 != Z_OK)
+ rc = rtZipGzipConvertErrFromZlib(pThis, rc);
+ }
RTVfsIoStrmRelease(pThis->hVfsIos);
pThis->hVfsIos = NIL_RTVFSIOSTREAM;
@@ -349,44 +367,138 @@ static int rtZipGzip_ReadOneSeg(PRTZIPGZIPSTREAM pThis, void *pvBuf, size_t cbTo
return rc;
}
+
/**
* @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
*/
static DECLCALLBACK(int) rtZipGzip_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
{
PRTZIPGZIPSTREAM pThis = (PRTZIPGZIPSTREAM)pvThis;
- int rc;
+ Assert(pSgBuf->cSegs == 1);
AssertReturn(off == -1, VERR_INVALID_PARAMETER);
if (!pThis->fDecompress)
return VERR_ACCESS_DENIED;
- if (pSgBuf->cSegs == 1)
- rc = rtZipGzip_ReadOneSeg(pThis, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, fBlocking, pcbRead);
- else
+ return rtZipGzip_ReadOneSeg(pThis, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, fBlocking, pcbRead);
+}
+
+
+/**
+ * Internal helper for rtZipGzip_Write, rtZipGzip_Flush and rtZipGzip_Close.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_SUCCESS
+ * @retval VINF_TRY_AGAIN - the only informational status.
+ * @retval VERR_INTERRUPTED - call again.
+ *
+ * @param pThis The gzip I/O stream instance data.
+ * @param fBlocking Whether to block or not.
+ */
+static int rtZipGzip_WriteOutputBuffer(PRTZIPGZIPSTREAM pThis, bool fBlocking)
+{
+ /*
+ * Anything to write? No, then just return immediately.
+ */
+ size_t cbToWrite = sizeof(pThis->abBuffer) - pThis->Zlib.avail_out;
+ if (cbToWrite == 0)
{
- rc = VINF_SUCCESS;
- size_t cbRead = 0;
- size_t cbReadSeg;
- size_t *pcbReadSeg = pcbRead ? &cbReadSeg : NULL;
- for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
+ Assert(pThis->Zlib.next_out == &pThis->abBuffer[0]);
+ return VINF_SUCCESS;
+ }
+ Assert(cbToWrite <= sizeof(pThis->abBuffer));
+
+ /*
+ * Loop write on VERR_INTERRUPTED.
+ *
+ * Note! Asserting a bit extra here to make sure the
+ * RTVfsIoStrmSgWrite works correctly.
+ */
+ int rc;
+ size_t cbWrittenOut;
+ for (;;)
+ {
+ /* Set up the buffer. */
+ pThis->SgSeg.cbSeg = cbToWrite;
+ Assert(pThis->SgSeg.pvSeg == &pThis->abBuffer[0]);
+ RTSgBufReset(&pThis->SgBuf);
+
+ cbWrittenOut = ~(size_t)0;
+ rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, &pThis->SgBuf, fBlocking, &cbWrittenOut);
+ if (rc != VINF_SUCCESS)
{
- cbReadSeg = 0;
- rc = rtZipGzip_ReadOneSeg(pThis, pSgBuf->paSegs[iSeg].pvSeg, pSgBuf->paSegs[iSeg].cbSeg, fBlocking, pcbReadSeg);
- if (RT_FAILURE(rc))
- break;
- if (pcbRead)
+ AssertMsg(RT_FAILURE(rc) || rc == VINF_TRY_AGAIN, ("%Rrc\n", rc));
+ if (rc == VERR_INTERRUPTED)
{
- cbRead += cbReadSeg;
- if (cbReadSeg != pSgBuf->paSegs[iSeg].cbSeg)
- break;
+ Assert(cbWrittenOut == 0);
+ continue;
+ }
+ if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN || cbWrittenOut == 0)
+ {
+ AssertReturn(cbWrittenOut == 0, VERR_INTERNAL_ERROR_3);
+ AssertReturn(rc != VINF_SUCCESS, VERR_IPE_UNEXPECTED_INFO_STATUS);
+ return rc;
}
}
- if (pcbRead)
- *pcbRead = cbRead;
+ break;
}
+ AssertMsgReturn(cbWrittenOut > 0 && cbWrittenOut <= sizeof(pThis->abBuffer),
+ ("%zu %Rrc\n", cbWrittenOut, rc),
+ VERR_INTERNAL_ERROR_4);
- return rc;
+ /*
+ * Adjust the Zlib output buffer members.
+ */
+ if (cbWrittenOut == pThis->SgBuf.paSegs[0].cbSeg)
+ {
+ pThis->Zlib.avail_out = sizeof(pThis->abBuffer);
+ pThis->Zlib.next_out = &pThis->abBuffer[0];
+ }
+ else
+ {
+ Assert(cbWrittenOut <= pThis->SgBuf.paSegs[0].cbSeg);
+ size_t cbLeft = pThis->SgBuf.paSegs[0].cbSeg - cbWrittenOut;
+ memmove(&pThis->abBuffer[0], &pThis->abBuffer[cbWrittenOut], cbLeft);
+ pThis->Zlib.avail_out += (uInt)cbWrittenOut;
+ pThis->Zlib.next_out = &pThis->abBuffer[cbWrittenOut];
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Processes all available input.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pThis The gzip I/O stream instance data.
+ * @param fBlocking Whether to block or not.
+ */
+static int rtZipGzip_CompressIt(PRTZIPGZIPSTREAM pThis, bool fBlocking)
+{
+ /*
+ * Processes all the intput currently lined up for us.
+ */
+ while (pThis->Zlib.avail_in > 0)
+ {
+ /* Make sure there is some space in the output buffer before calling
+ deflate() so we don't waste time filling up the corners. */
+ static const size_t s_cbFlushThreshold = 4096;
+ AssertCompile(sizeof(pThis->abBuffer) >= s_cbFlushThreshold * 4);
+ if (pThis->Zlib.avail_out < s_cbFlushThreshold)
+ {
+ int rc = rtZipGzip_WriteOutputBuffer(pThis, fBlocking);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ Assert(pThis->Zlib.avail_out >= s_cbFlushThreshold);
+ }
+
+ int rcZlib = deflate(&pThis->Zlib, Z_NO_FLUSH);
+ if (rcZlib != Z_OK)
+ return rtZipGzipConvertErrFromZlib(pThis, rcZlib);
+ }
+ return VINF_SUCCESS;
}
@@ -396,16 +508,87 @@ static DECLCALLBACK(int) rtZipGzip_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgB
static DECLCALLBACK(int) rtZipGzip_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
{
PRTZIPGZIPSTREAM pThis = (PRTZIPGZIPSTREAM)pvThis;
- //int rc;
AssertReturn(off == -1, VERR_INVALID_PARAMETER);
- NOREF(fBlocking);
+ Assert(pSgBuf->cSegs == 1); NOREF(fBlocking);
+
if (pThis->fDecompress)
return VERR_ACCESS_DENIED;
- /** @todo implement compression. */
- NOREF(pSgBuf); NOREF(pcbWritten);
- return VERR_NOT_IMPLEMENTED;
+ /*
+ * Write out the intput buffer. Using a loop here because of potential
+ * integer type overflow since avail_in is uInt and cbSeg is size_t.
+ */
+ int rc = VINF_SUCCESS;
+ size_t cbWritten = 0;
+ uint8_t const *pbSrc = (uint8_t const *)pSgBuf->paSegs[0].pvSeg;
+ size_t cbLeft = pSgBuf->paSegs[0].cbSeg;
+ if (cbLeft > 0)
+ for (;;)
+ {
+ size_t cbThis = cbLeft < ~(uInt)0 ? cbLeft : ~(uInt)0 / 2;
+ pThis->Zlib.next_in = (Bytef * )pbSrc;
+ pThis->Zlib.avail_in = (uInt)cbThis;
+ rc = rtZipGzip_CompressIt(pThis, fBlocking);
+
+ Assert(cbThis >= pThis->Zlib.avail_in);
+ cbThis -= pThis->Zlib.avail_in;
+ cbWritten += cbThis;
+ if (cbLeft == cbThis || rc != VINF_SUCCESS)
+ break;
+ pbSrc += cbThis;
+ cbLeft -= cbThis;
+ }
+
+ if (pcbWritten)
+ *pcbWritten = cbWritten;
+ return rc;
+}
+
+
+/**
+ * Processes all available input.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pThis The gzip I/O stream instance data.
+ * @param fFlushType The flush type to pass to deflate().
+ */
+static int rtZipGzip_FlushIt(PRTZIPGZIPSTREAM pThis, uint8_t fFlushType)
+{
+ /*
+ * Tell Zlib to flush until it stops producing more output.
+ */
+ int rc;
+ bool fMaybeMore = true;
+ for (;;)
+ {
+ /* Write the entire output buffer. */
+ do
+ {
+ rc = rtZipGzip_WriteOutputBuffer(pThis, true /*fBlocking*/);
+ if (RT_FAILURE(rc))
+ return rc;
+ Assert(rc == VINF_SUCCESS);
+ } while (pThis->Zlib.avail_out < sizeof(pThis->abBuffer));
+
+ if (!fMaybeMore)
+ return VINF_SUCCESS;
+
+ /* Do the flushing. */
+ pThis->Zlib.next_in = NULL;
+ pThis->Zlib.avail_in = 0;
+ int rcZlib = deflate(&pThis->Zlib, fFlushType);
+ if (rcZlib == Z_OK)
+ fMaybeMore = pThis->Zlib.avail_out < 64 || fFlushType == Z_FINISH;
+ else if (rcZlib == Z_STREAM_END)
+ fMaybeMore = false;
+ else
+ {
+ rtZipGzip_WriteOutputBuffer(pThis, true /*fBlocking*/);
+ return rtZipGzipConvertErrFromZlib(pThis, rcZlib);
+ }
+ }
}
@@ -415,6 +598,13 @@ static DECLCALLBACK(int) rtZipGzip_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSg
static DECLCALLBACK(int) rtZipGzip_Flush(void *pvThis)
{
PRTZIPGZIPSTREAM pThis = (PRTZIPGZIPSTREAM)pvThis;
+ if (!pThis->fDecompress)
+ {
+ int rc = rtZipGzip_FlushIt(pThis, Z_SYNC_FLUSH);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
return RTVfsIoStrmFlush(pThis->hVfsIos);
}
@@ -480,7 +670,7 @@ static RTVFSIOSTREAMOPS g_rtZipGzipOps =
RTVFSOBJOPS_VERSION
},
RTVFSIOSTREAMOPS_VERSION,
- 0,
+ RTVFSIOSTREAMOPS_FEAT_NO_SG,
rtZipGzip_Read,
rtZipGzip_Write,
rtZipGzip_Flush,
@@ -495,7 +685,7 @@ static RTVFSIOSTREAMOPS g_rtZipGzipOps =
RTDECL(int) RTZipGzipDecompressIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSIOSTREAM phVfsIosOut)
{
AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE);
- AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fFlags & ~RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR), VERR_INVALID_PARAMETER);
AssertPtrReturn(phVfsIosOut, VERR_INVALID_POINTER);
uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn);
@@ -519,12 +709,15 @@ RTDECL(int) RTZipGzipDecompressIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags
memset(&pThis->Zlib, 0, sizeof(pThis->Zlib));
pThis->Zlib.opaque = pThis;
- rc = inflateInit2(&pThis->Zlib, MAX_WBITS + 16 /* autodetect gzip header */);
+ rc = inflateInit2(&pThis->Zlib,
+ fFlags & RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR
+ ? MAX_WBITS
+ : MAX_WBITS + 16 /* autodetect gzip header */);
if (rc >= 0)
{
/*
* Read the gzip header from the input stream to check that it's
- * a gzip stream.
+ * a gzip stream as specified by the user.
*
* Note!. Since we've told zlib to check for the gzip header, we
* prebuffer what we read in the input buffer so it can
@@ -535,23 +728,37 @@ RTDECL(int) RTZipGzipDecompressIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags
{
/* Validate the header and make a copy of it. */
PCRTZIPGZIPHDR pHdr = (PCRTZIPGZIPHDR)pThis->abBuffer;
- if ( pHdr->bId1 != RTZIPGZIPHDR_ID1
- || pHdr->bId2 != RTZIPGZIPHDR_ID2
- || pHdr->fFlags & ~RTZIPGZIPHDR_FLG_VALID_MASK)
- rc = VERR_ZIP_BAD_HEADER;
- else if (pHdr->bCompressionMethod != RTZIPGZIPHDR_CM_DEFLATE)
- rc = VERR_ZIP_UNSUPPORTED_METHOD;
+ if ( pHdr->bId1 == RTZIPGZIPHDR_ID1
+ && pHdr->bId2 == RTZIPGZIPHDR_ID2
+ && !(pHdr->fFlags & ~RTZIPGZIPHDR_FLG_VALID_MASK))
+ {
+ if (pHdr->bCompressionMethod == RTZIPGZIPHDR_CM_DEFLATE)
+ rc = VINF_SUCCESS;
+ else
+ rc = VERR_ZIP_UNSUPPORTED_METHOD;
+ }
+ else if ( (fFlags & RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR)
+ && (RT_MAKE_U16(pHdr->bId2, pHdr->bId1) % 31) == 0
+ && (pHdr->bId1 & 0xf) == RTZIPGZIPHDR_CM_DEFLATE )
+ {
+ pHdr = NULL;
+ rc = VINF_SUCCESS;
+ }
else
+ rc = VERR_ZIP_BAD_HEADER;
+ if (RT_SUCCESS(rc))
{
- pThis->Hdr = *pHdr;
pThis->Zlib.avail_in = sizeof(RTZIPGZIPHDR);
pThis->Zlib.next_in = &pThis->abBuffer[0];
-
- /* Parse on if there are names or comments. */
- if (pHdr->fFlags & (RTZIPGZIPHDR_FLG_NAME | RTZIPGZIPHDR_FLG_COMMENT))
+ if (pHdr)
{
- /** @todo Can implement this when someone needs the
- * name or comment for something useful. */
+ pThis->Hdr = *pHdr;
+ /* Parse on if there are names or comments. */
+ if (pHdr->fFlags & (RTZIPGZIPHDR_FLG_NAME | RTZIPGZIPHDR_FLG_COMMENT))
+ {
+ /** @todo Can implement this when someone needs the
+ * name or comment for something useful. */
+ }
}
if (RT_SUCCESS(rc))
{
@@ -570,3 +777,56 @@ RTDECL(int) RTZipGzipDecompressIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags
return rc;
}
+
+RTDECL(int) RTZipGzipCompressIoStream(RTVFSIOSTREAM hVfsIosDst, uint32_t fFlags, uint8_t uLevel, PRTVFSIOSTREAM phVfsIosZip)
+{
+ AssertPtrReturn(hVfsIosDst, VERR_INVALID_HANDLE);
+ AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(phVfsIosZip, VERR_INVALID_POINTER);
+ AssertReturn(uLevel > 0 && uLevel <= 9, VERR_INVALID_PARAMETER);
+
+ uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosDst);
+ AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
+
+ /*
+ * Create the compression I/O stream.
+ */
+ RTVFSIOSTREAM hVfsIos;
+ PRTZIPGZIPSTREAM pThis;
+ int rc = RTVfsNewIoStream(&g_rtZipGzipOps, sizeof(RTZIPGZIPSTREAM), RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
+ &hVfsIos, (void **)&pThis);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->hVfsIos = hVfsIosDst;
+ pThis->offStream = 0;
+ pThis->fDecompress = false;
+ pThis->SgSeg.pvSeg = &pThis->abBuffer[0];
+ pThis->SgSeg.cbSeg = sizeof(pThis->abBuffer);
+ RTSgBufInit(&pThis->SgBuf, &pThis->SgSeg, 1);
+
+ RT_ZERO(pThis->Zlib);
+ pThis->Zlib.opaque = pThis;
+ pThis->Zlib.next_out = &pThis->abBuffer[0];
+ pThis->Zlib.avail_out = sizeof(pThis->abBuffer);
+
+ rc = deflateInit2(&pThis->Zlib,
+ uLevel,
+ Z_DEFLATED,
+ 15 /* Windows Size */ + 16 /* GZIP header */,
+ 9 /* Max memory level for optimal speed */,
+ Z_DEFAULT_STRATEGY);
+
+ if (rc >= 0)
+ {
+ *phVfsIosZip = hVfsIos;
+ return VINF_SUCCESS;
+ }
+
+ rc = rtZipGzipConvertErrFromZlib(pThis, rc); /** @todo cleaning up in this situation is going to go wrong. */
+ RTVfsIoStrmRelease(hVfsIos);
+ }
+ else
+ RTVfsIoStrmRelease(hVfsIosDst);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/zip/tar.cpp b/src/VBox/Runtime/common/zip/tar.cpp
index cb342d23..e2ced7e6 100644
--- a/src/VBox/Runtime/common/zip/tar.cpp
+++ b/src/VBox/Runtime/common/zip/tar.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -40,6 +40,7 @@
#include <iprt/string.h>
#include "internal/magics.h"
+#include "tar.h"
/******************************************************************************
@@ -85,19 +86,10 @@ typedef union RTTARRECORD
} RTTARRECORD;
AssertCompileSize(RTTARRECORD, 512);
AssertCompileMemberOffset(RTTARRECORD, h.size, 100+8*3);
+AssertCompileMemberSize(RTTARRECORD, h.name, RTTAR_NAME_MAX+1);
/** Pointer to a tar file header. */
typedef RTTARRECORD *PRTTARRECORD;
-
-#if 0 /* not currently used */
-typedef struct RTTARFILELIST
-{
- char *pszFilename;
- RTTARFILELIST *pNext;
-} RTTARFILELIST;
-typedef RTTARFILELIST *PRTTARFILELIST;
-#endif
-
/** Pointer to a tar file handle. */
typedef struct RTTARFILEINTERNAL *PRTTARFILEINTERNAL;
@@ -144,10 +136,22 @@ typedef struct RTTARFILEINTERNAL
uint64_t offCurrent;
/** The open mode. */
uint32_t fOpenMode;
+ /** The link flag. */
+ char linkflag;
} RTTARFILEINTERNAL;
/** Pointer to the internal data of a tar file. */
typedef RTTARFILEINTERNAL *PRTTARFILEINTERNAL;
+#if 0 /* not currently used */
+typedef struct RTTARFILELIST
+{
+ char *pszFilename;
+ RTTARFILELIST *pNext;
+} RTTARFILELIST;
+typedef RTTARFILELIST *PRTTARFILELIST;
+#endif
+
+
/******************************************************************************
* Defined Constants And Macros *
@@ -265,29 +269,59 @@ DECLINLINE(uint64_t) rtTarRecToSize(PRTTARRECORD pRecord)
return (uint64_t)cbSize;
}
-DECLINLINE(int) rtTarCalcChkSum(PRTTARRECORD pRecord, uint32_t *pChkSum)
+/**
+ * Calculates the TAR header checksums and detects if it's all zeros.
+ *
+ * @returns true if all zeros, false if not.
+ * @param pHdr The header to checksum.
+ * @param pi32Unsigned Where to store the checksum calculated using
+ * unsigned chars. This is the one POSIX
+ * specifies.
+ * @param pi32Signed Where to store the checksum calculated using
+ * signed chars.
+ *
+ * @remarks The reason why we calculate the checksum as both signed and unsigned
+ * has to do with various the char C type being signed on some hosts
+ * and unsigned on others.
+ *
+ * @remarks Borrowed from tarvfs.cpp.
+ */
+static bool rtZipTarCalcChkSum(PCRTZIPTARHDR pHdr, int32_t *pi32Unsigned, int32_t *pi32Signed)
{
- uint32_t check = 0;
- uint32_t zero = 0;
- for (size_t i = 0; i < sizeof(RTTARRECORD); ++i)
+ int32_t i32Unsigned = 0;
+ int32_t i32Signed = 0;
+
+ /*
+ * Sum up the entire header.
+ */
+ const char *pch = (const char *)pHdr;
+ const char *pchEnd = pch + sizeof(*pHdr);
+ do
{
- /* Calculate the sum of every byte from the header. The checksum field
- * itself is counted as all blanks. */
- if ( i < RT_UOFFSETOF(RTTARRECORD, h.chksum)
- || i >= RT_UOFFSETOF(RTTARRECORD, h.linkflag))
- check += pRecord->d[i];
- else
- check += ' ';
- /* Additional check if all fields are zero, which indicate EOF. */
- zero += pRecord->d[i];
- }
+ i32Unsigned += *(unsigned char *)pch;
+ i32Signed += *(signed char *)pch;
+ } while (++pch != pchEnd);
- /* EOF? */
- if (!zero)
- return VERR_TAR_END_OF_FILE;
+ /*
+ * Check if it's all zeros and replace the chksum field with spaces.
+ */
+ bool const fZeroHdr = i32Unsigned == 0;
- *pChkSum = check;
- return VINF_SUCCESS;
+ pch = pHdr->Common.chksum;
+ pchEnd = pch + sizeof(pHdr->Common.chksum);
+ do
+ {
+ i32Unsigned -= *(unsigned char *)pch;
+ i32Signed -= *(signed char *)pch;
+ } while (++pch != pchEnd);
+
+ i32Unsigned += (unsigned char)' ' * sizeof(pHdr->Common.chksum);
+ i32Signed += (signed char)' ' * sizeof(pHdr->Common.chksum);
+
+ *pi32Unsigned = i32Unsigned;
+ if (pi32Signed)
+ *pi32Signed = i32Signed;
+ return fZeroHdr;
}
DECLINLINE(int) rtTarReadHeaderRecord(RTFILE hFile, PRTTARRECORD pRecord)
@@ -302,16 +336,16 @@ DECLINLINE(int) rtTarReadHeaderRecord(RTFILE hFile, PRTTARRECORD pRecord)
return rc;
/* Check for data integrity & an EOF record */
- uint32_t check = 0;
- rc = rtTarCalcChkSum(pRecord, &check);
- /* EOF? */
- if (RT_FAILURE(rc))
- return rc;
+ int32_t iUnsignedChksum, iSignedChksum;
+ if (rtZipTarCalcChkSum((PCRTZIPTARHDR)pRecord, &iUnsignedChksum, &iSignedChksum))
+ return VERR_TAR_END_OF_FILE;
/* Verify the checksum */
uint32_t sum;
rc = RTStrToUInt32Full(pRecord->h.chksum, 8, &sum);
- if (RT_SUCCESS(rc) && sum == check)
+ if ( RT_SUCCESS(rc)
+ && ( sum == (uint32_t)iSignedChksum
+ || sum == (uint32_t)iUnsignedChksum) )
{
/* Make sure the strings are zero terminated. */
pRecord->h.name[sizeof(pRecord->h.name) - 1] = 0;
@@ -332,24 +366,27 @@ DECLINLINE(int) rtTarCreateHeaderRecord(PRTTARRECORD pRecord, const char *pszSrc
/** @todo check for field overflows. */
/* Fill the header record */
// RT_ZERO(pRecord); - done by the caller.
- RTStrPrintf(pRecord->h.name, sizeof(pRecord->h.name), "%s", pszSrcName);
- RTStrPrintf(pRecord->h.mode, sizeof(pRecord->h.mode), "%0.7o", fmode);
- RTStrPrintf(pRecord->h.uid, sizeof(pRecord->h.uid), "%0.7o", uid);
- RTStrPrintf(pRecord->h.gid, sizeof(pRecord->h.gid), "%0.7o", gid);
+ /** @todo use RTStrCopy */
+ size_t cb = RTStrPrintf(pRecord->h.name, sizeof(pRecord->h.name), "%s", pszSrcName);
+ if (cb < strlen(pszSrcName))
+ return VERR_BUFFER_OVERFLOW;
+ RTStrPrintf(pRecord->h.mode, sizeof(pRecord->h.mode), "%0.7o", fmode);
+ RTStrPrintf(pRecord->h.uid, sizeof(pRecord->h.uid), "%0.7o", uid);
+ RTStrPrintf(pRecord->h.gid, sizeof(pRecord->h.gid), "%0.7o", gid);
rtTarSizeToRec(pRecord, cbSize);
- RTStrPrintf(pRecord->h.mtime, sizeof(pRecord->h.mtime), "%0.11o", mtime);
+ RTStrPrintf(pRecord->h.mtime, sizeof(pRecord->h.mtime), "%0.11llo", mtime);
RTStrPrintf(pRecord->h.magic, sizeof(pRecord->h.magic), "ustar ");
RTStrPrintf(pRecord->h.uname, sizeof(pRecord->h.uname), "someone");
RTStrPrintf(pRecord->h.gname, sizeof(pRecord->h.gname), "someone");
pRecord->h.linkflag = LF_NORMAL;
/* Create the checksum out of the new header */
- uint32_t uChkSum = 0;
- int rc = rtTarCalcChkSum(pRecord, &uChkSum);
- if (RT_FAILURE(rc))
- return rc;
+ int32_t iUnsignedChksum, iSignedChksum;
+ if (rtZipTarCalcChkSum((PCRTZIPTARHDR)pRecord, &iUnsignedChksum, &iSignedChksum))
+ return VERR_TAR_END_OF_FILE;
+
/* Format the checksum */
- RTStrPrintf(pRecord->h.chksum, sizeof(pRecord->h.chksum), "%0.7o", uChkSum);
+ RTStrPrintf(pRecord->h.chksum, sizeof(pRecord->h.chksum), "%0.7o", iUnsignedChksum);
return VINF_SUCCESS;
}
@@ -1178,7 +1215,7 @@ RTR3DECL(int) RTTarFileSetTime(RTTARFILE hFile, PRTTIMESPEC pTime)
/* Convert the time to an string. */
char szModTime[RT_SIZEOFMEMB(RTTARRECORD, h.mtime)];
- RTStrPrintf(szModTime, sizeof(szModTime), "%0.11o", RTTimeSpecGetSeconds(pTime));
+ RTStrPrintf(szModTime, sizeof(szModTime), "%0.11llo", RTTimeSpecGetSeconds(pTime));
/* Write it directly into the header */
return RTFileWriteAt(pFileInt->pTar->hTarFile,
@@ -1617,14 +1654,23 @@ RTR3DECL(int) RTTarSeekNextFile(RTTAR hTar)
* If not we are somehow busted. */
uint64_t offCur = RTFileTell(pInt->hTarFile);
if (!( pInt->pFileCache->offStart <= offCur
- && offCur < pInt->pFileCache->offStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize))
+ && offCur <= pInt->pFileCache->offStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize))
return VERR_INVALID_STATE;
/* Seek to the next file header. */
uint64_t offNext = RT_ALIGN(pInt->pFileCache->offStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize, sizeof(RTTARRECORD));
- rc = RTFileSeek(pInt->hTarFile, offNext - offCur, RTFILE_SEEK_CURRENT, NULL);
- if (RT_FAILURE(rc))
- return rc;
+ if (pInt->pFileCache->cbSize != 0)
+ {
+ rc = RTFileSeek(pInt->hTarFile, offNext - offCur, RTFILE_SEEK_CURRENT, NULL);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+ else
+ {
+ /* Else delete the last open file cache. Might be recreated below. */
+ rtDeleteTarFileInternal(pInt->pFileCache);
+ pInt->pFileCache = NULL;
+ }
/* Again check the current filename to fill the cache with the new value. */
return RTTarCurrentFile(hTar, NULL);
@@ -1648,20 +1694,24 @@ RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **pps
/* Is there some cached entry? */
if (pInt->pFileCache)
{
- /* Are we still direct behind that header? */
- if (pInt->pFileCache->offStart + sizeof(RTTARRECORD) == RTFileTell(pInt->hTarFile))
+ if (pInt->pFileCache->offStart + sizeof(RTTARRECORD) < RTFileTell(pInt->hTarFile))
+ {
+ /* Else delete the last open file cache. Might be recreated below. */
+ rtDeleteTarFileInternal(pInt->pFileCache);
+ pInt->pFileCache = NULL;
+ }
+ else/* Are we still directly behind that header? */
{
/* Yes, so the streaming can start. Just return the cached file
* structure to the caller. */
*phFile = rtCopyTarFileInternal(pInt->pFileCache);
if (ppszFilename)
*ppszFilename = RTStrDup(pInt->pFileCache->pszFilename);
+ if (pInt->pFileCache->linkflag == LF_DIR)
+ return VINF_TAR_DIR_PATH;
return VINF_SUCCESS;
}
- /* Else delete the last open file cache. Might be recreated below. */
- rtDeleteTarFileInternal(pInt->pFileCache);
- pInt->pFileCache = NULL;
}
PRTTARFILEINTERNAL pFileInt = NULL;
@@ -1679,7 +1729,8 @@ RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **pps
/* We support normal files only */
if ( record.h.linkflag == LF_OLDNORMAL
- || record.h.linkflag == LF_NORMAL)
+ || record.h.linkflag == LF_NORMAL
+ || record.h.linkflag == LF_DIR)
{
pFileInt = rtCreateTarFileInternal(pInt, record.h.name, fOpen);
if (!pFileInt)
@@ -1692,11 +1743,16 @@ RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **pps
pFileInt->cbSize = rtTarRecToSize(&record);
/* The start is -512 from here. */
pFileInt->offStart = RTFileTell(pInt->hTarFile) - sizeof(RTTARRECORD);
+ /* remember the type of a file */
+ pFileInt->linkflag = record.h.linkflag;
/* Copy the new file structure to our cache. */
pInt->pFileCache = rtCopyTarFileInternal(pFileInt);
if (ppszFilename)
*ppszFilename = RTStrDup(pFileInt->pszFilename);
+
+ if (pFileInt->linkflag == LF_DIR)
+ rc = VINF_TAR_DIR_PATH;
}
} while (0);
diff --git a/src/VBox/Runtime/common/zip/tarcmd.cpp b/src/VBox/Runtime/common/zip/tarcmd.cpp
index 6e7f84a9..b018b283 100644
--- a/src/VBox/Runtime/common/zip/tarcmd.cpp
+++ b/src/VBox/Runtime/common/zip/tarcmd.cpp
@@ -1,10 +1,10 @@
/* $Id: tarcmd.cpp $ */
/** @file
- * IPRT - TAR Command.
+ * IPRT - A mini TAR Command.
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,35 +33,58 @@
#include <iprt/asm.h>
#include <iprt/buildconfig.h>
#include <iprt/ctype.h>
+#include <iprt/dir.h>
#include <iprt/file.h>
#include <iprt/getopt.h>
#include <iprt/initterm.h>
#include <iprt/mem.h>
#include <iprt/message.h>
#include <iprt/param.h>
+#include <iprt/path.h>
#include <iprt/stream.h>
#include <iprt/string.h>
+#include <iprt/symlink.h>
#include <iprt/vfs.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
-#define RTZIPTARCMD_OPT_DELETE 1000
-#define RTZIPTARCMD_OPT_OWNER 1001
-#define RTZIPTARCMD_OPT_GROUP 1002
-#define RTZIPTARCMD_OPT_UTC 1003
-#define RTZIPTARCMD_OPT_PREFIX 1004
+#define RTZIPTARCMD_OPT_DELETE 1000
+#define RTZIPTARCMD_OPT_OWNER 1001
+#define RTZIPTARCMD_OPT_GROUP 1002
+#define RTZIPTARCMD_OPT_UTC 1003
+#define RTZIPTARCMD_OPT_PREFIX 1004
+#define RTZIPTARCMD_OPT_FILE_MODE_AND_MASK 1005
+#define RTZIPTARCMD_OPT_FILE_MODE_OR_MASK 1006
+#define RTZIPTARCMD_OPT_DIR_MODE_AND_MASK 1007
+#define RTZIPTARCMD_OPT_DIR_MODE_OR_MASK 1008
+#define RTZIPTARCMD_OPT_FORMAT 1009
+
+/** File format. */
+typedef enum RTZIPTARFORMAT
+{
+ RTZIPTARFORMAT_INVALID = 0,
+ /** Autodetect if possible, defaulting to TAR. */
+ RTZIPTARFORMAT_AUTO_DEFAULT,
+ /** TAR. */
+ RTZIPTARFORMAT_TAR,
+ /** XAR. */
+ RTZIPTARFORMAT_XAR
+} RTZIPTARFORMAT;
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
- * IPT TAR option structure.
+ * IPRT TAR option structure.
*/
typedef struct RTZIPTARCMDOPS
{
+ /** The file format. */
+ RTZIPTARFORMAT enmFormat;
+
/** The operation (Acdrtux or RTZIPTARCMD_OPT_DELETE). */
int iOperation;
/** The long operation option name. */
@@ -73,21 +96,36 @@ typedef struct RTZIPTARCMDOPS
const char *pszFile;
/** Whether we're verbose or quiet. */
bool fVerbose;
- /** Whether to preserve permissions when restoring. */
- bool fPreservePermissions;
+ /** Whether to preserve the original file owner when restoring. */
+ bool fPreserveOwner;
+ /** Whether to preserve the original file group when restoring. */
+ bool fPreserveGroup;
+ /** Whether to skip restoring the modification time (only time stored by the
+ * traditional TAR format). */
+ bool fNoModTime;
/** The compressor/decompressor method to employ (0, z or j). */
char chZipper;
- /** The owner to set. */
+ /** The owner to set. NULL if not applicable.
+ * Always resolved into uidOwner for extraction. */
const char *pszOwner;
- /** The owner ID to set when unpacking if pszOwner is not NULL. */
+ /** The owner ID to set. NIL_RTUID if not applicable. */
RTUID uidOwner;
- /** The group to set. */
+ /** The group to set. NULL if not applicable.
+ * Always resolved into gidGroup for extraction. */
const char *pszGroup;
- /** The group ID to set when unpacking if pszGroup is not NULL. */
+ /** The group ID to set. NIL_RTGUID if not applicable. */
RTGID gidGroup;
/** Display the modification times in UTC instead of local time. */
bool fDisplayUtc;
+ /** File mode AND mask. */
+ RTFMODE fFileModeAndMask;
+ /** File mode OR mask. */
+ RTFMODE fFileModeOrMask;
+ /** Directory mode AND mask. */
+ RTFMODE fDirModeAndMask;
+ /** Directory mode OR mask. */
+ RTFMODE fDirModeOrMask;
/** What to prefix all names with when creating, adding, whatever. */
const char *pszPrefix;
@@ -101,6 +139,17 @@ typedef struct RTZIPTARCMDOPS
/** Pointer to the IPRT tar options. */
typedef RTZIPTARCMDOPS *PRTZIPTARCMDOPS;
+/**
+ * Callback used by rtZipTarDoWithMembers
+ *
+ * @returns rcExit or RTEXITCODE_FAILURE.
+ * @param pOpts The tar options.
+ * @param hVfsObj The tar object to display
+ * @param pszName The name.
+ * @param rcExit The current exit code.
+ */
+typedef RTEXITCODE (*PFNDOWITHMEMBER)(PRTZIPTARCMDOPS pOpts, RTVFSOBJ hVfsObj, const char *pszName, RTEXITCODE rcExit);
+
/**
* Checks if @a pszName is a member of @a papszNames, optionally returning the
@@ -213,9 +262,18 @@ static RTEXITCODE rtZipTarCmdOpenInputArchive(PRTZIPTARCMDOPS pOpts, PRTVFSFSSTR
}
/*
- * Open the tar filesystem stream.
+ * Open the filesystem stream.
*/
- rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0/*fFlags*/, phVfsFss);
+ if (pOpts->enmFormat == RTZIPTARFORMAT_TAR)
+ rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0/*fFlags*/, phVfsFss);
+ else if (pOpts->enmFormat == RTZIPTARFORMAT_XAR)
+#ifdef IPRT_WITH_XAR /* Requires C++ and XML, so only in some configruation of IPRT. */
+ rc = RTZipXarFsStreamFromIoStream(hVfsIos, 0/*fFlags*/, phVfsFss);
+#else
+ rc = VERR_NOT_SUPPORTED;
+#endif
+ else /** @todo make RTZipTarFsStreamFromIoStream fail if not tar file! */
+ rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0/*fFlags*/, phVfsFss);
RTVfsIoStrmRelease(hVfsIos);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open tar filesystem stream: %Rrc", rc);
@@ -225,17 +283,424 @@ static RTEXITCODE rtZipTarCmdOpenInputArchive(PRTZIPTARCMDOPS pOpts, PRTVFSFSSTR
/**
- * Display a tar entry in the verbose form.
+ * Worker for the --list and --extract commands.
+ *
+ * @returns The appropriate exit code.
+ * @param pOpts The tar options.
+ * @param pfnCallback The command specific callback.
+ */
+static RTEXITCODE rtZipTarDoWithMembers(PRTZIPTARCMDOPS pOpts, PFNDOWITHMEMBER pfnCallback)
+{
+ /*
+ * Allocate a bitmap to go with the file list. This will be used to
+ * indicate which files we've processed and which not.
+ */
+ uint32_t *pbmFound = NULL;
+ if (pOpts->cFiles)
+ {
+ pbmFound = (uint32_t *)RTMemAllocZ(((pOpts->cFiles + 31) / 32) * sizeof(uint32_t));
+ if (!pbmFound)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate the found-file-bitmap");
+ }
+
+
+ /*
+ * Open the input archive.
+ */
+ RTVFSFSSTREAM hVfsFssIn;
+ RTEXITCODE rcExit = rtZipTarCmdOpenInputArchive(pOpts, &hVfsFssIn);
+ if (rcExit == RTEXITCODE_SUCCESS)
+ {
+ /*
+ * Process the stream.
+ */
+ for (;;)
+ {
+ /*
+ * Retrive the next object.
+ */
+ char *pszName;
+ RTVFSOBJ hVfsObj;
+ int rc = RTVfsFsStrmNext(hVfsFssIn, &pszName, NULL, &hVfsObj);
+ if (RT_FAILURE(rc))
+ {
+ if (rc != VERR_EOF)
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext returned %Rrc", rc);
+ break;
+ }
+
+ /*
+ * Should we process this entry?
+ */
+ uint32_t iFile = UINT32_MAX;
+ if ( !pOpts->cFiles
+ || rtZipTarCmdIsNameInArray(pszName, pOpts->papszFiles, &iFile) )
+ {
+ if (pbmFound)
+ ASMBitSet(pbmFound, iFile);
+
+ rcExit = pfnCallback(pOpts, hVfsObj, pszName, rcExit);
+ }
+
+ /*
+ * Release the current object and string.
+ */
+ RTVfsObjRelease(hVfsObj);
+ RTStrFree(pszName);
+ }
+
+ /*
+ * Complain about any files we didn't find.
+ */
+ for (uint32_t iFile = 0; iFile < pOpts->cFiles; iFile++)
+ if (!ASMBitTest(pbmFound, iFile))
+ {
+ RTMsgError("%s: Was not found in the archive", pOpts->papszFiles[iFile]);
+ rcExit = RTEXITCODE_FAILURE;
+ }
+ }
+ RTMemFree(pbmFound);
+ return rcExit;
+}
+
+
+/**
+ * Checks if the name contains any escape sequences.
+ *
+ * An escape sequence would generally be one or more '..' references. On DOS
+ * like system, something that would make up a drive letter reference is also
+ * considered an escape sequence.
+ *
+ * @returns true / false.
+ * @param pszName The name to consider.
+ */
+static bool rtZipTarHasEscapeSequence(const char *pszName)
+{
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ if (pszName[0] == ':')
+ return true;
+#endif
+ while (*pszName)
+ {
+ while (RTPATH_IS_SEP(*pszName))
+ pszName++;
+ if ( pszName[0] == '.'
+ && pszName[1] == '.'
+ && (pszName[2] == '\0' || RTPATH_IS_SLASH(pszName[2])) )
+ return true;
+ while (*pszName && !RTPATH_IS_SEP(*pszName))
+ pszName++;
+ }
+
+ return false;
+}
+
+
+/**
+ * Queries the user ID to use when extracting a member.
*
* @returns rcExit or RTEXITCODE_FAILURE.
+ * @param pOpts The tar options.
+ * @param pUser The user info.
+ * @param pszName The file name to use when complaining.
* @param rcExit The current exit code.
- * @param hVfsObj The tar object to display
- * @param pszName The name.
+ * @param pUid Where to return the user ID.
+ */
+static RTEXITCODE rtZipTarQueryExtractOwner(PRTZIPTARCMDOPS pOpts, PCRTFSOBJINFO pOwner, const char *pszName, RTEXITCODE rcExit,
+ PRTUID pUid)
+{
+ if (pOpts->uidOwner != NIL_RTUID)
+ *pUid = pOpts->uidOwner;
+ else if (pOpts->fPreserveGroup)
+ {
+ if (!pOwner->Attr.u.UnixGroup.szName[0])
+ *pUid = pOwner->Attr.u.UnixOwner.uid;
+ else
+ {
+ *pUid = NIL_RTUID;
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: User resolving is not implemented.", pszName);
+ }
+ }
+ else
+ *pUid = NIL_RTUID;
+ return rcExit;
+}
+
+
+/**
+ * Queries the group ID to use when extracting a member.
+ *
+ * @returns rcExit or RTEXITCODE_FAILURE.
* @param pOpts The tar options.
+ * @param pGroup The group info.
+ * @param pszName The file name to use when complaining.
+ * @param rcExit The current exit code.
+ * @param pGid Where to return the group ID.
*/
-static RTEXITCODE rtZipTarCmdDisplayEntryVerbose(RTEXITCODE rcExit, RTVFSOBJ hVfsObj, const char *pszName,
- PRTZIPTARCMDOPS pOpts)
+static RTEXITCODE rtZipTarQueryExtractGroup(PRTZIPTARCMDOPS pOpts, PCRTFSOBJINFO pGroup, const char *pszName, RTEXITCODE rcExit,
+ PRTGID pGid)
{
+ if (pOpts->gidGroup != NIL_RTGID)
+ *pGid = pOpts->gidGroup;
+ else if (pOpts->fPreserveGroup)
+ {
+ if (!pGroup->Attr.u.UnixGroup.szName[0])
+ *pGid = pGroup->Attr.u.UnixGroup.gid;
+ else
+ {
+ *pGid = NIL_RTGID;
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Group resolving is not implemented.", pszName);
+ }
+ }
+ else
+ *pGid = NIL_RTGID;
+ return rcExit;
+}
+
+
+
+/**
+ * Extracts a file.
+ *
+ * Since we can restore permissions and attributes more efficiently by working
+ * directly on the file handle, we have special code path for files.
+ *
+ * @returns rcExit or RTEXITCODE_FAILURE.
+ * @param pOpts The tar options.
+ * @param hVfsObj The tar object to display
+ * @param rcExit The current exit code.
+ * @param pUnixInfo The unix fs object info.
+ * @param pOwner The owner info.
+ * @param pGroup The group info.
+ */
+static RTEXITCODE rtZipTarCmdExtractFile(PRTZIPTARCMDOPS pOpts, RTVFSOBJ hVfsObj, RTEXITCODE rcExit,
+ const char *pszDst, PCRTFSOBJINFO pUnixInfo, PCRTFSOBJINFO pOwner, PCRTFSOBJINFO pGroup)
+{
+ /*
+ * Open the destination file and create a stream object for it.
+ */
+ uint32_t fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_ACCESS_ATTR_DEFAULT
+ | ((RTFS_UNIX_IWUSR | RTFS_UNIX_IRUSR) << RTFILE_O_CREATE_MODE_SHIFT);
+ RTFILE hFile;
+ int rc = RTFileOpen(&hFile, pszDst, fOpen);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error creating file: %Rrc", pszDst, rc);
+
+ RTVFSIOSTREAM hVfsIosDst;
+ rc = RTVfsIoStrmFromRTFile(hFile, fOpen, true /*fLeaveOpen*/, &hVfsIosDst);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Pump the data thru.
+ */
+ RTVFSIOSTREAM hVfsIosSrc = RTVfsObjToIoStream(hVfsObj);
+ rc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, (uint32_t)RT_MIN(pUnixInfo->cbObject, _1M));
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Correct the file mode and other attributes.
+ */
+ if (!pOpts->fNoModTime)
+ {
+ rc = RTFileSetTimes(hFile, NULL, &pUnixInfo->ModificationTime, NULL, NULL);
+ if (RT_FAILURE(rc))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error setting times: %Rrc", pszDst, rc);
+ }
+
+#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
+ if ( pOpts->uidOwner != NIL_RTUID
+ || pOpts->gidGroup != NIL_RTGID
+ || pOpts->fPreserveOwner
+ || pOpts->fPreserveGroup)
+ {
+ RTUID uidFile;
+ rcExit = rtZipTarQueryExtractOwner(pOpts, pOwner, pszDst, rcExit, &uidFile);
+
+ RTGID gidFile;
+ rcExit = rtZipTarQueryExtractGroup(pOpts, pGroup, pszDst, rcExit, &gidFile);
+ if (uidFile != NIL_RTUID || gidFile != NIL_RTGID)
+ {
+ rc = RTFileSetOwner(hFile, uidFile, gidFile);
+ if (RT_FAILURE(rc))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error owner/group: %Rrc", pszDst, rc);
+ }
+ }
+#endif
+
+ RTFMODE fMode = (pUnixInfo->Attr.fMode & pOpts->fFileModeAndMask) | pOpts->fFileModeOrMask;
+ rc = RTFileSetMode(hFile, fMode | RTFS_TYPE_FILE);
+ if (RT_FAILURE(rc))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error changing mode: %Rrc", pszDst, rc);
+ }
+ else
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error writing out file: %Rrc", pszDst, rc);
+ RTVfsIoStrmRelease(hVfsIosSrc);
+ RTVfsIoStrmRelease(hVfsIosDst);
+ }
+ else
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error creating I/O stream for file: %Rrc", pszDst, rc);
+ RTFileClose(hFile);
+ return rcExit;
+}
+
+
+/**
+ * @callback_method_impl{PFNDOWITHMEMBER, Implements --extract.}
+ */
+static RTEXITCODE rtZipTarCmdExtractCallback(PRTZIPTARCMDOPS pOpts, RTVFSOBJ hVfsObj, const char *pszName, RTEXITCODE rcExit)
+{
+ if (pOpts->fVerbose)
+ RTPrintf("%s\n", pszName);
+
+ /*
+ * Query all the information.
+ */
+ RTFSOBJINFO UnixInfo;
+ int rc = RTVfsObjQueryInfo(hVfsObj, &UnixInfo, RTFSOBJATTRADD_UNIX);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo returned %Rrc on '%s'", rc, pszName);
+
+ RTFSOBJINFO Owner;
+ rc = RTVfsObjQueryInfo(hVfsObj, &Owner, RTFSOBJATTRADD_UNIX_OWNER);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE,
+ "RTVfsObjQueryInfo(,,UNIX_OWNER) returned %Rrc on '%s'",
+ rc, pszName);
+
+ RTFSOBJINFO Group;
+ rc = RTVfsObjQueryInfo(hVfsObj, &Group, RTFSOBJATTRADD_UNIX_GROUP);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE,
+ "RTVfsObjQueryInfo(,,UNIX_OWNER) returned %Rrc on '%s'",
+ rc, pszName);
+
+ const char *pszLinkType = NULL;
+ char szTarget[RTPATH_MAX];
+ szTarget[0] = '\0';
+ RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
+ if (hVfsSymlink != NIL_RTVFSSYMLINK)
+ {
+ rc = RTVfsSymlinkRead(hVfsSymlink, szTarget, sizeof(szTarget));
+ RTVfsSymlinkRelease(hVfsSymlink);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: RTVfsSymlinkRead failed: %Rrc", pszName, rc);
+ if (!RTFS_IS_SYMLINK(UnixInfo.Attr.fMode))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Hardlinks are not supported.", pszName);
+ if (!szTarget[0])
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Link target is empty.", pszName);
+ }
+ else if (RTFS_IS_SYMLINK(UnixInfo.Attr.fMode))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get symlink object for '%s'", pszName);
+
+ if (rtZipTarHasEscapeSequence(pszName))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Name '%s' contains an escape sequence.", pszName);
+
+ /*
+ * Construct the path to the extracted member.
+ */
+ char szDst[RTPATH_MAX];
+ rc = RTPathJoin(szDst, sizeof(szDst), pOpts->pszDirectory ? pOpts->pszDirectory : ".", pszName);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to construct destination path for: %Rrc", pszName, rc);
+
+ /*
+ * Extract according to the type.
+ */
+ switch (UnixInfo.Attr.fMode & RTFS_TYPE_MASK)
+ {
+ case RTFS_TYPE_FILE:
+ return rtZipTarCmdExtractFile(pOpts, hVfsObj, rcExit, szDst, &UnixInfo, &Owner, &Group);
+
+ case RTFS_TYPE_DIRECTORY:
+ rc = RTDirCreateFullPath(szDst, UnixInfo.Attr.fMode & RTFS_UNIX_ALL_ACCESS_PERMS);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error creating directory: %Rrc", szDst, rc);
+ break;
+
+ case RTFS_TYPE_SYMLINK:
+ rc = RTSymlinkCreate(szDst, szTarget, RTSYMLINKTYPE_UNKNOWN, 0);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error creating symbolic link: %Rrc", szDst, rc);
+ break;
+
+ case RTFS_TYPE_FIFO:
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: FIFOs are not supported.", pszName);
+ case RTFS_TYPE_DEV_CHAR:
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: FIFOs are not supported.", pszName);
+ case RTFS_TYPE_DEV_BLOCK:
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Block devices are not supported.", pszName);
+ case RTFS_TYPE_SOCKET:
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Sockets are not supported.", pszName);
+ case RTFS_TYPE_WHITEOUT:
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Whiteouts are not support.", pszName);
+ default:
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Unknown file type.", pszName);
+ }
+
+ /*
+ * Set other attributes as requested .
+ * .
+ * Note! File extraction does get here.
+ */
+ if (!pOpts->fNoModTime)
+ {
+ rc = RTPathSetTimesEx(szDst, NULL, &UnixInfo.ModificationTime, NULL, NULL, RTPATH_F_ON_LINK);
+ if (RT_FAILURE(rc) && rc != VERR_NOT_SUPPORTED && rc != VERR_NS_SYMLINK_SET_TIME)
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error changing modification time: %Rrc.", pszName, rc);
+ }
+
+#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
+ if ( pOpts->uidOwner != NIL_RTUID
+ || pOpts->gidGroup != NIL_RTGID
+ || pOpts->fPreserveOwner
+ || pOpts->fPreserveGroup)
+ {
+ RTUID uidFile;
+ rcExit = rtZipTarQueryExtractOwner(pOpts, &Owner, szDst, rcExit, &uidFile);
+
+ RTGID gidFile;
+ rcExit = rtZipTarQueryExtractGroup(pOpts, &Group, szDst, rcExit, &gidFile);
+ if (uidFile != NIL_RTUID || gidFile != NIL_RTGID)
+ {
+ rc = RTPathSetOwnerEx(szDst, uidFile, gidFile, RTPATH_F_ON_LINK);
+ if (RT_FAILURE(rc))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error owner/group: %Rrc", szDst, rc);
+ }
+ }
+#endif
+
+#if !defined(RT_OS_WINDOWS) /** @todo implement RTPathSetMode on windows... */
+ if (!RTFS_IS_SYMLINK(UnixInfo.Attr.fMode)) /* RTPathSetMode follows symbolic links atm. */
+ {
+ RTFMODE fMode;
+ if (RTFS_IS_DIRECTORY(UnixInfo.Attr.fMode))
+ fMode = (UnixInfo.Attr.fMode & (pOpts->fDirModeAndMask | RTFS_TYPE_MASK)) | pOpts->fDirModeOrMask;
+ else
+ fMode = (UnixInfo.Attr.fMode & (pOpts->fFileModeAndMask | RTFS_TYPE_MASK)) | pOpts->fFileModeOrMask;
+ rc = RTPathSetMode(szDst, fMode);
+ if (RT_FAILURE(rc))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Error changing mode: %Rrc", szDst, rc);
+ }
+#endif
+
+ return rcExit;
+}
+
+
+/**
+ * @callback_method_impl{PFNDOWITHMEMBER, Implements --list.}
+ */
+static RTEXITCODE rtZipTarCmdListCallback(PRTZIPTARCMDOPS pOpts, RTVFSOBJ hVfsObj, const char *pszName, RTEXITCODE rcExit)
+{
+ /*
+ * This is very simple in non-verbose mode.
+ */
+ if (!pOpts->fVerbose)
+ {
+ RTPrintf("%s\n", pszName);
+ return rcExit;
+ }
+
/*
* Query all the information.
*/
@@ -392,91 +857,86 @@ static RTEXITCODE rtZipTarCmdDisplayEntryVerbose(RTEXITCODE rcExit, RTVFSOBJ hVf
return rcExit;
}
+
/**
- * Implements the -t/--list operation.
+ * Display usage.
*
- * @returns The appropriate exit code.
- * @param pOpts The tar options.
+ * @param pszProgName The program name.
*/
-static RTEXITCODE rtZipTarCmdList(PRTZIPTARCMDOPS pOpts)
+static void rtZipTarUsage(const char *pszProgName)
{
/*
- * Allocate a bitmap to go with the file list. This will be used to
- * indicate which files we've processed and which not.
+ * 0 1 2 3 4 5 6 7 8
+ * 012345678901234567890123456789012345678901234567890123456789012345678901234567890
*/
- uint32_t *pbmFound = NULL;
- if (pOpts->cFiles)
- {
- pbmFound = (uint32_t *)RTMemAllocZ(((pOpts->cFiles + 31) / 32) * sizeof(uint32_t));
- if (!pbmFound)
- return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate the found-file-bitmap");
- }
-
-
- /*
- * Open the input archive.
- */
- RTVFSFSSTREAM hVfsFssIn;
- RTEXITCODE rcExit = rtZipTarCmdOpenInputArchive(pOpts, &hVfsFssIn);
- if (rcExit == RTEXITCODE_SUCCESS)
- {
- /*
- * Process the stream.
- */
- for (;;)
- {
- /*
- * Retrive the next object.
- */
- char *pszName;
- RTVFSOBJ hVfsObj;
- int rc = RTVfsFsStrmNext(hVfsFssIn, &pszName, NULL, &hVfsObj);
- if (RT_FAILURE(rc))
- {
- if (rc != VERR_EOF)
- rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext returned %Rrc", rc);
- break;
- }
-
- /*
- * Should we display this entry?
- */
- uint32_t iFile = UINT32_MAX;
- if ( !pOpts->cFiles
- || rtZipTarCmdIsNameInArray(pszName, pOpts->papszFiles, &iFile) )
- {
- if (pbmFound)
- ASMBitSet(pbmFound, iFile);
-
- if (!pOpts->fVerbose)
- RTPrintf("%s\n", pszName);
- else
- rcExit = rtZipTarCmdDisplayEntryVerbose(rcExit, hVfsObj, pszName, pOpts);
- }
-
- /*
- * Release the current object and string.
- */
- RTVfsObjRelease(hVfsObj);
- RTStrFree(pszName);
- }
-
- /*
- * Complain about any files we didn't find.
- */
- for (uint32_t iFile = 0; iFile < pOpts->cFiles; iFile++)
- if (!ASMBitTest(pbmFound, iFile))
- {
- RTMsgError("%s: Was not found in the archive", pOpts->papszFiles[iFile]);
- rcExit = RTEXITCODE_FAILURE;
- }
- }
- RTMemFree(pbmFound);
- return rcExit;
+ RTPrintf("Usage: %s [options]\n"
+ "\n",
+ pszProgName);
+ RTPrintf("Operations:\n"
+ " -A, --concatenate, --catenate\n"
+ " Append the content of one tar archive to another. (not impl)\n"
+ " -c, --create\n"
+ " Create a new tar archive. (not impl)\n"
+ " -d, --diff, --compare\n"
+ " Compare atar archive with the file system. (not impl)\n"
+ " -r, --append\n"
+ " Append more files to the tar archive. (not impl)\n"
+ " -t, --list\n"
+ " List the contents of the tar archive.\n"
+ " -u, --update\n"
+ " Update the archive, adding files that are newer than the\n"
+ " ones in the archive. (not impl)\n"
+ " -x, --extract, --get\n"
+ " Extract the files from the tar archive.\n"
+ " --delete\n"
+ " Delete files from the tar archive.\n"
+ "\n"
+ );
+ RTPrintf("Basic Options:\n"
+ " -C <dir>, --directory <dir> (-A, -C, -d, -r, -u, -x)\n"
+ " Sets the base directory for input and output file members.\n"
+ " This does not apply to --file, even if it preceeds it.\n"
+ " -f <archive>, --file <archive> (all)\n"
+ " The tar file to create or process. '-' indicates stdout/stdin,\n"
+ " which is is the default.\n"
+ " -v, --verbose (all)\n"
+ " Verbose operation.\n"
+ " -p, --preserve-permissions (-x)\n"
+ " Preserve all permissions when extracting. Must be used\n"
+ " before the mode mask options as it will change some of these.\n"
+ " -j, --bzip2 (all)\n"
+ " Compress/decompress the archive with bzip2.\n"
+ " -z, --gzip, --gunzip, --ungzip (all)\n"
+ " Compress/decompress the archive with gzip.\n"
+ "\n");
+ RTPrintf("Misc Options:\n"
+ " --owner <uid/username> (-A, -C, -d, -r, -u, -x)\n"
+ " Set the owner of extracted and archived files to the user specified.\n"
+ " --group <uid/username> (-A, -C, -d, -r, -u, -x)\n"
+ " Set the group of extracted and archived files to the group specified.\n"
+ " --utc (-t)\n"
+ " Display timestamps as UTC instead of local time.\n"
+ "\n");
+ RTPrintf("IPRT Options:\n"
+ " --prefix <dir-prefix> (-A, -C, -d, -r, -u)\n"
+ " Directory prefix to give the members added to the archive.\n"
+ " --file-mode-and-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
+ " Restrict the access mode of regular and special files.\n"
+ " --file-mode-and-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
+ " Include the given access mode for regular and special files.\n"
+ " --dir-mode-and-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
+ " Restrict the access mode of directories.\n"
+ " --dir-mode-and-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
+ " Include the given access mode for directories.\n"
+ "\n");
+ RTPrintf("Standard Options:\n"
+ " -h, -?, --help\n"
+ " Display this help text.\n"
+ " -V, --version\n"
+ " Display version number.\n");
}
-
RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
{
/*
@@ -514,10 +974,15 @@ RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
/* other options. */
{ "--owner", RTZIPTARCMD_OPT_OWNER, RTGETOPT_REQ_STRING },
{ "--group", RTZIPTARCMD_OPT_GROUP, RTGETOPT_REQ_STRING },
- { "--utc", RTZIPTARCMD_OPT_UTC, RTGETOPT_REQ_NOTHING },
+ { "--utc", RTZIPTARCMD_OPT_UTC, RTGETOPT_REQ_NOTHING },
/* IPRT extensions */
- { "--prefix", RTZIPTARCMD_OPT_PREFIX, RTGETOPT_REQ_STRING },
+ { "--prefix", RTZIPTARCMD_OPT_PREFIX, RTGETOPT_REQ_STRING },
+ { "--file-mode-and-mask", RTZIPTARCMD_OPT_FILE_MODE_AND_MASK, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT },
+ { "--file-mode-or-mask", RTZIPTARCMD_OPT_FILE_MODE_OR_MASK, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT },
+ { "--dir-mode-and-mask", RTZIPTARCMD_OPT_DIR_MODE_AND_MASK, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT },
+ { "--dir-mode-or-mask", RTZIPTARCMD_OPT_DIR_MODE_OR_MASK, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT },
+ { "--format", RTZIPTARCMD_OPT_FORMAT, RTGETOPT_REQ_STRING },
};
RTGETOPTSTATE GetState;
@@ -527,7 +992,21 @@ RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc);
RTZIPTARCMDOPS Opts;
- RT_ZERO(Opts); /* nice defaults :-) */
+ RT_ZERO(Opts);
+ Opts.enmFormat = RTZIPTARFORMAT_AUTO_DEFAULT;
+ Opts.uidOwner = NIL_RTUID;
+ Opts.gidGroup = NIL_RTUID;
+ Opts.fFileModeAndMask = RTFS_UNIX_ALL_ACCESS_PERMS;
+ Opts.fDirModeAndMask = RTFS_UNIX_ALL_ACCESS_PERMS;
+#if 0
+ if (RTPermIsSuperUser())
+ {
+ Opts.fFileModeAndMask = RTFS_UNIX_ALL_PERMS;
+ Opts.fDirModeAndMask = RTFS_UNIX_ALL_PERMS;
+ Opts.fPreserveOwner = true;
+ Opts.fPreserveGroup = true;
+ }
+#endif
RTGETOPTUNION ValueUnion;
while ( (rc = RTGetOpt(&GetState, &ValueUnion)) != 0
@@ -569,7 +1048,10 @@ RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
break;
case 'p':
- Opts.fPreservePermissions = true;
+ Opts.fFileModeAndMask = RTFS_UNIX_ALL_PERMS;
+ Opts.fDirModeAndMask = RTFS_UNIX_ALL_PERMS;
+ Opts.fPreserveOwner = true;
+ Opts.fPreserveGroup = true;
break;
case 'j':
@@ -583,12 +1065,32 @@ RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
if (Opts.pszOwner)
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify --owner once");
Opts.pszOwner = ValueUnion.psz;
+
+ rc = RTStrToUInt32Full(Opts.pszOwner, 0, &ValueUnion.u32);
+ if (RT_SUCCESS(rc) && rc != VINF_SUCCESS)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX,
+ "Error convering --owner '%s' into a number: %Rrc", Opts.pszOwner, rc);
+ if (RT_SUCCESS(rc))
+ {
+ Opts.uidOwner = ValueUnion.u32;
+ Opts.pszOwner = NULL;
+ }
break;
case RTZIPTARCMD_OPT_GROUP:
if (Opts.pszGroup)
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify --group once");
Opts.pszGroup = ValueUnion.psz;
+
+ rc = RTStrToUInt32Full(Opts.pszGroup, 0, &ValueUnion.u32);
+ if (RT_SUCCESS(rc) && rc != VINF_SUCCESS)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX,
+ "Error convering --group '%s' into a number: %Rrc", Opts.pszGroup, rc);
+ if (RT_SUCCESS(rc))
+ {
+ Opts.gidGroup = ValueUnion.u32;
+ Opts.pszGroup = NULL;
+ }
break;
case RTZIPTARCMD_OPT_UTC:
@@ -602,13 +1104,36 @@ RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
Opts.pszPrefix = ValueUnion.psz;
break;
+ case RTZIPTARCMD_OPT_FILE_MODE_AND_MASK:
+ Opts.fFileModeAndMask = ValueUnion.u32 & RTFS_UNIX_ALL_PERMS;
+ break;
+
+ case RTZIPTARCMD_OPT_FILE_MODE_OR_MASK:
+ Opts.fFileModeOrMask = ValueUnion.u32 & RTFS_UNIX_ALL_PERMS;
+ break;
+
+ case RTZIPTARCMD_OPT_DIR_MODE_AND_MASK:
+ Opts.fDirModeAndMask = ValueUnion.u32 & RTFS_UNIX_ALL_PERMS;
+ break;
+
+ case RTZIPTARCMD_OPT_DIR_MODE_OR_MASK:
+ Opts.fDirModeOrMask = ValueUnion.u32 & RTFS_UNIX_ALL_PERMS;
+ break;
+
+ case RTZIPTARCMD_OPT_FORMAT:
+ if (!strcmp(ValueUnion.psz, "auto") || !strcmp(ValueUnion.psz, "default"))
+ Opts.enmFormat = RTZIPTARFORMAT_AUTO_DEFAULT;
+ else if (!strcmp(ValueUnion.psz, "tar"))
+ Opts.enmFormat = RTZIPTARFORMAT_TAR;
+ else if (!strcmp(ValueUnion.psz, "xar"))
+ Opts.enmFormat = RTZIPTARFORMAT_XAR;
+ else
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown archive format: '%s'", ValueUnion.psz);
+ break;
+
+ /* Standard bits. */
case 'h':
- RTPrintf("Usage: to be written\nOption dump:\n");
- for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
- if (RT_C_IS_PRINT(s_aOptions[i].iShort))
- RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
- else
- RTPrintf(" %s\n", s_aOptions[i].pszLong);
+ rtZipTarUsage(RTPathFilename(papszArgs[0]));
return RTEXITCODE_SUCCESS;
case 'V':
@@ -651,14 +1176,16 @@ RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
switch (Opts.iOperation)
{
case 't':
- return rtZipTarCmdList(&Opts);
+ return rtZipTarDoWithMembers(&Opts, rtZipTarCmdListCallback);
+
+ case 'x':
+ return rtZipTarDoWithMembers(&Opts, rtZipTarCmdExtractCallback);
case 'A':
case 'c':
case 'd':
case 'r':
case 'u':
- case 'x':
case RTZIPTARCMD_OPT_DELETE:
return RTMsgErrorExit(RTEXITCODE_FAILURE, "The operation %s is not implemented yet", Opts.pszOperation);
diff --git a/src/VBox/Runtime/common/zip/tarvfs.cpp b/src/VBox/Runtime/common/zip/tarvfs.cpp
index 740c1397..67200fe8 100644
--- a/src/VBox/Runtime/common/zip/tarvfs.cpp
+++ b/src/VBox/Runtime/common/zip/tarvfs.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/zip/xarvfs.cpp b/src/VBox/Runtime/common/zip/xarvfs.cpp
new file mode 100644
index 00000000..8b6d0abc
--- /dev/null
+++ b/src/VBox/Runtime/common/zip/xarvfs.cpp
@@ -0,0 +1,2111 @@
+/* $Id: xarvfs.cpp $ */
+/** @file
+ * IPRT - XAR Virtual Filesystem.
+ */
+
+/*
+ * Copyright (C) 2010-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/******************************************************************************
+ * Header Files *
+ ******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/zip.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/md5.h>
+#include <iprt/poll.h>
+#include <iprt/file.h>
+#include <iprt/sha.h>
+#include <iprt/string.h>
+#include <iprt/vfs.h>
+#include <iprt/vfslowlevel.h>
+#include <iprt/formats/xar.h>
+#include <iprt/cpp/xml.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** @name Hash state
+ * @{ */
+#define RTZIPXAR_HASH_PENDING 0
+#define RTZIPXAR_HASH_OK 1
+#define RTZIPXAR_HASH_FAILED_ARCHIVED 2
+#define RTZIPXAR_HASH_FAILED_EXTRACTED 3
+/** @} */
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Hash digest value union for the supported XAR hash functions.
+ * @todo This could be generalized in iprt/checksum.h or somewhere.
+ */
+typedef union RTZIPXARHASHDIGEST
+{
+ uint8_t abMd5[RTMD5_HASH_SIZE];
+ uint8_t abSha1[RTSHA1_HASH_SIZE];
+} RTZIPXARHASHDIGEST;
+/** Pointer to a XAR hash digest union. */
+typedef RTZIPXARHASHDIGEST *PRTZIPXARHASHDIGEST;
+/** Pointer to a const XAR hash digest union. */
+typedef RTZIPXARHASHDIGEST *PCRTZIPXARHASHDIGEST;
+
+/**
+ * Hash context union.
+ */
+typedef union RTZIPXARHASHCTX
+{
+ RTMD5CONTEXT Md5;
+ RTSHA1CONTEXT Sha1;
+} RTZIPXARHASHCTX;
+/** Pointer to a hash context union. */
+typedef RTZIPXARHASHCTX *PRTZIPXARHASHCTX;
+
+/**
+ * XAR reader instance data.
+ */
+typedef struct RTZIPXARREADER
+{
+ /** The TOC XML element. */
+ xml::ElementNode const *pToc;
+ /** The TOC XML document. */
+ xml::Document *pDoc;
+
+ /** The current file. */
+ xml::ElementNode const *pCurFile;
+ /** The depth of the current file, with 0 being the root level. */
+ uint32_t cCurDepth;
+} RTZIPXARREADER;
+/** Pointer to the XAR reader instance data. */
+typedef RTZIPXARREADER *PRTZIPXARREADER;
+
+/**
+ * Xar directory, character device, block device, fifo socket or symbolic link.
+ */
+typedef struct RTZIPXARBASEOBJ
+{
+ /** The file TOC element. */
+ xml::ElementNode const *pFileElem;
+ /** RTFS_TYPE_XXX value for the object. */
+ RTFMODE fModeType;
+} RTZIPXARBASEOBJ;
+/** Pointer to a XAR filesystem stream base object. */
+typedef RTZIPXARBASEOBJ *PRTZIPXARBASEOBJ;
+
+
+/**
+ * XAR data encoding.
+ */
+typedef enum RTZIPXARENCODING
+{
+ RTZIPXARENCODING_INVALID = 0,
+ RTZIPXARENCODING_STORE,
+ RTZIPXARENCODING_GZIP,
+ RTZIPXARENCODING_UNSUPPORTED,
+ RTZIPXARENCODING_END
+} RTZIPXARENCODING;
+
+
+/**
+ * Data stream attributes.
+ */
+typedef struct RTZIPXARDATASTREAM
+{
+ /** Offset of the data in the stream.
+ * @remarks The I/O stream and file constructor will adjust this so that it
+ * relative to the start of the input stream, instead of the first byte
+ * after the TOC. */
+ RTFOFF offData;
+ /** The size of the archived data. */
+ RTFOFF cbDataArchived;
+ /** The size of the extracted data. */
+ RTFOFF cbDataExtracted;
+ /** The encoding of the archived ata. */
+ RTZIPXARENCODING enmEncoding;
+ /** The hash function used for the archived data. */
+ uint8_t uHashFunArchived;
+ /** The hash function used for the extracted data. */
+ uint8_t uHashFunExtracted;
+ /** The digest of the archived data. */
+ RTZIPXARHASHDIGEST DigestArchived;
+ /** The digest of the extracted data. */
+ RTZIPXARHASHDIGEST DigestExtracted;
+} RTZIPXARDATASTREAM;
+/** Pointer to XAR data stream attributes. */
+typedef RTZIPXARDATASTREAM *PRTZIPXARDATASTREAM;
+
+
+/**
+ * Xar file represented as a VFS I/O stream.
+ */
+typedef struct RTZIPXARIOSTREAM
+{
+ /** The basic XAR object data. */
+ RTZIPXARBASEOBJ BaseObj;
+ /** The attributes of the primary data stream. */
+ RTZIPXARDATASTREAM DataAttr;
+ /** The current file position in the archived file. */
+ RTFOFF offCurPos;
+ /** The input I/O stream. */
+ RTVFSIOSTREAM hVfsIos;
+ /** Set if we've reached the end of the file or if the next object in the
+ * file system stream has been requested. */
+ bool fEndOfStream;
+ /** Whether the stream is seekable. */
+ bool fSeekable;
+ /** Hash state. */
+ uint8_t uHashState;
+ /** The size of the file that we've currently hashed.
+ * We use this to check whether the user skips part of the file while reading
+ * and when to compare the digests. */
+ RTFOFF cbDigested;
+ /** The digest of the archived data. */
+ RTZIPXARHASHCTX CtxArchived;
+ /** The digest of the extracted data. */
+ RTZIPXARHASHCTX CtxExtracted;
+} RTZIPXARIOSTREAM;
+/** Pointer to a the private data of a XAR file I/O stream. */
+typedef RTZIPXARIOSTREAM *PRTZIPXARIOSTREAM;
+
+
+/**
+ * Xar file represented as a VFS file.
+ */
+typedef struct RTZIPXARFILE
+{
+ /** The XAR I/O stream data. */
+ RTZIPXARIOSTREAM Ios;
+ /** The input file. */
+ RTVFSFILE hVfsFile;
+} RTZIPXARFILE;
+/** Pointer to the private data of a XAR file. */
+typedef RTZIPXARFILE *PRTZIPXARFILE;
+
+
+/**
+ * Decompressed I/O stream instance.
+ *
+ * This is just a front that checks digests and other sanity stuff.
+ */
+typedef struct RTZIPXARDECOMPIOS
+{
+ /** The decompressor I/O stream. */
+ RTVFSIOSTREAM hVfsIosDecompressor;
+ /** The raw XAR I/O stream. */
+ RTVFSIOSTREAM hVfsIosRaw;
+ /** Pointer to the raw XAR I/O stream instance data. */
+ PRTZIPXARIOSTREAM pIosRaw;
+ /** The current file position in the archived file. */
+ RTFOFF offCurPos;
+ /** The hash function to use on the extracted data. */
+ uint8_t uHashFunExtracted;
+ /** Hash state on the extracted data. */
+ uint8_t uHashState;
+ /** The digest of the extracted data. */
+ RTZIPXARHASHCTX CtxExtracted;
+ /** The expected digest of the extracted data. */
+ RTZIPXARHASHDIGEST DigestExtracted;
+} RTZIPXARDECOMPIOS;
+/** Pointer to the private data of a XAR decompressed I/O stream. */
+typedef RTZIPXARDECOMPIOS *PRTZIPXARDECOMPIOS;
+
+
+/**
+ * Xar filesystem stream private data.
+ */
+typedef struct RTZIPXARFSSTREAM
+{
+ /** The input I/O stream. */
+ RTVFSIOSTREAM hVfsIos;
+ /** The input file, if the stream is actually a file. */
+ RTVFSFILE hVfsFile;
+
+ /** The start offset in the input I/O stream. */
+ RTFOFF offStart;
+ /** The zero offset in the file which all others are relative to. */
+ RTFOFF offZero;
+
+ /** The hash function we're using (XAR_HASH_XXX). */
+ uint8_t uHashFunction;
+ /** The size of the digest produced by the hash function we're using. */
+ uint8_t cbHashDigest;
+
+ /** Set if we've reached the end of the stream. */
+ bool fEndOfStream;
+ /** Set if we've encountered a fatal error. */
+ int rcFatal;
+
+
+ /** The XAR reader instance data. */
+ RTZIPXARREADER XarReader;
+} RTZIPXARFSSTREAM;
+/** Pointer to a the private data of a XAR filesystem stream. */
+typedef RTZIPXARFSSTREAM *PRTZIPXARFSSTREAM;
+
+
+/**
+ * Hashes a block of data.
+ *
+ * @param uHashFunction The hash function to use.
+ * @param pvSrc The data to hash.
+ * @param cbSrc The size of the data to hash.
+ * @param pHashDigest Where to return the message digest.
+ */
+static void rtZipXarCalcHash(uint32_t uHashFunction, void const *pvSrc, size_t cbSrc, PRTZIPXARHASHDIGEST pHashDigest)
+{
+ switch (uHashFunction)
+ {
+ case XAR_HASH_SHA1:
+ RTSha1(pvSrc, cbSrc, pHashDigest->abSha1);
+ break;
+ case XAR_HASH_MD5:
+ RTMd5(pvSrc, cbSrc, pHashDigest->abMd5);
+ break;
+ default:
+ RT_ZERO(*pHashDigest);
+ break;
+ }
+}
+
+
+/**
+ * Initializes a hash context.
+ *
+ * @param pCtx Pointer to the context union.
+ * @param uHashFunction The hash function to use.
+ */
+static void rtZipXarHashInit(PRTZIPXARHASHCTX pCtx, uint32_t uHashFunction)
+{
+ switch (uHashFunction)
+ {
+ case XAR_HASH_SHA1:
+ RTSha1Init(&pCtx->Sha1);
+ break;
+ case XAR_HASH_MD5:
+ RTMd5Init(&pCtx->Md5);;
+ break;
+ default:
+ RT_ZERO(*pCtx);
+ break;
+ }
+}
+
+
+/**
+ * Adds a block to the hash calculation.
+ *
+ * @param pCtx Pointer to the context union.
+ * @param uHashFunction The hash function to use.
+ * @param pvSrc The data to add to the hash.
+ * @param cbSrc The size of the data.
+ */
+static void rtZipXarHashUpdate(PRTZIPXARHASHCTX pCtx, uint32_t uHashFunction, void const *pvSrc, size_t cbSrc)
+{
+ switch (uHashFunction)
+ {
+ case XAR_HASH_SHA1:
+ RTSha1Update(&pCtx->Sha1, pvSrc, cbSrc);
+ break;
+ case XAR_HASH_MD5:
+ RTMd5Update(&pCtx->Md5, pvSrc, cbSrc);
+ break;
+ }
+}
+
+
+/**
+ * Finalizes the hash, producing the message digest.
+ *
+ * @param pCtx Pointer to the context union.
+ * @param uHashFunction The hash function to use.
+ * @param pHashDigest Where to return the message digest.
+ */
+static void rtZipXarHashFinal(PRTZIPXARHASHCTX pCtx, uint32_t uHashFunction, PRTZIPXARHASHDIGEST pHashDigest)
+{
+ switch (uHashFunction)
+ {
+ case XAR_HASH_SHA1:
+ RTSha1Final(&pCtx->Sha1, pHashDigest->abSha1);
+ break;
+ case XAR_HASH_MD5:
+ RTMd5Final(pHashDigest->abMd5, &pCtx->Md5);
+ break;
+ default:
+ RT_ZERO(*pHashDigest);
+ break;
+ }
+}
+
+
+/**
+ * Compares two hash digests.
+ *
+ * @returns true if equal, false if not.
+ * @param uHashFunction The hash function to use.
+ * @param pHashDigest1 The first hash digest.
+ * @param pHashDigest2 The second hash digest.
+ */
+static bool rtZipXarHashIsEqual(uint32_t uHashFunction, PRTZIPXARHASHDIGEST pHashDigest1, PRTZIPXARHASHDIGEST pHashDigest2)
+{
+ switch (uHashFunction)
+ {
+ case XAR_HASH_SHA1:
+ return memcmp(pHashDigest1->abSha1, pHashDigest2->abSha1, sizeof(pHashDigest1->abSha1)) == 0;
+ case XAR_HASH_MD5:
+ return memcmp(pHashDigest1->abMd5, pHashDigest2->abMd5, sizeof(pHashDigest1->abMd5)) == 0;
+ default:
+ return true;
+ }
+}
+
+
+/**
+ * Gets the 'offset', 'size' and optionally 'length' sub elements.
+ *
+ * @returns IPRT status code.
+ * @param pElement The parent element.
+ * @param poff Where to return the offset value.
+ * @param pcbSize Where to return the size value.
+ * @param pcbLength Where to return the length value, optional.
+ */
+static int rtZipXarGetOffsetSizeLengthFromElem(xml::ElementNode const *pElement,
+ PRTFOFF poff, PRTFOFF pcbSize, PRTFOFF pcbLength)
+{
+ /*
+ * The offset.
+ */
+ xml::ElementNode const *pElem = pElement->findChildElement("offset");
+ if (!pElem)
+ return VERR_XAR_MISSING_OFFSET_ELEMENT;
+ const char *pszValue = pElem->getValue();
+ if (!pszValue)
+ return VERR_XAR_BAD_OFFSET_ELEMENT;
+
+ int rc = RTStrToInt64Full(pszValue, 0, poff);
+ if ( RT_FAILURE(rc)
+ || rc == VWRN_NUMBER_TOO_BIG
+ || *poff > RTFOFF_MAX / 2 /* make sure to not overflow calculating offsets. */
+ || *poff < 0)
+ return VERR_XAR_BAD_OFFSET_ELEMENT;
+
+ /*
+ * The 'size' stored in the archive.
+ */
+ pElem = pElement->findChildElement("size");
+ if (!pElem)
+ return VERR_XAR_MISSING_SIZE_ELEMENT;
+
+ pszValue = pElem->getValue();
+ if (!pszValue)
+ return VERR_XAR_BAD_SIZE_ELEMENT;
+
+ rc = RTStrToInt64Full(pszValue, 0, pcbSize);
+ if ( RT_FAILURE(rc)
+ || rc == VWRN_NUMBER_TOO_BIG
+ || *pcbSize >= RTFOFF_MAX - _1M
+ || *pcbSize < 0)
+ return VERR_XAR_BAD_SIZE_ELEMENT;
+ AssertCompile(RTFOFF_MAX == UINT64_MAX / 2);
+
+ /*
+ * The 'length' of the uncompressed data. Not present for checksums, so
+ * the caller might not want it.
+ */
+ if (pcbLength)
+ {
+ pElem = pElement->findChildElement("length");
+ if (!pElem)
+ return VERR_XAR_MISSING_LENGTH_ELEMENT;
+
+ pszValue = pElem->getValue();
+ if (!pszValue)
+ return VERR_XAR_BAD_LENGTH_ELEMENT;
+
+ rc = RTStrToInt64Full(pszValue, 0, pcbLength);
+ if ( RT_FAILURE(rc)
+ || rc == VWRN_NUMBER_TOO_BIG
+ || *pcbLength >= RTFOFF_MAX - _1M
+ || *pcbLength < 0)
+ return VERR_XAR_BAD_LENGTH_ELEMENT;
+ AssertCompile(RTFOFF_MAX == UINT64_MAX / 2);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Convers a checksum style value into a XAR hash function number.
+ *
+ * @returns IPRT status code.
+ * @param pszStyle The XAR checksum style.
+ * @param puHashFunction Where to return the hash function number on success.
+ */
+static int rtZipXarParseChecksumStyle(const char *pszStyle, uint8_t *puHashFunction)
+{
+ size_t cchStyle = strlen(pszStyle);
+ if ( cchStyle == 4
+ && (pszStyle[0] == 's' || pszStyle[0] == 'S')
+ && (pszStyle[1] == 'h' || pszStyle[1] == 'H')
+ && (pszStyle[2] == 'a' || pszStyle[2] == 'A')
+ && pszStyle[3] == '1' )
+ *puHashFunction = XAR_HASH_SHA1;
+ else if ( cchStyle == 3
+ && (pszStyle[0] == 'm' || pszStyle[0] == 'M')
+ && (pszStyle[1] == 'd' || pszStyle[1] == 'D')
+ && pszStyle[2] == '5' )
+ *puHashFunction = XAR_HASH_MD5;
+ else if ( cchStyle == 4
+ && (pszStyle[0] == 'n' || pszStyle[0] == 'N')
+ && (pszStyle[1] == 'o' || pszStyle[1] == 'O')
+ && (pszStyle[2] == 'n' || pszStyle[2] == 'N')
+ && (pszStyle[3] == 'e' || pszStyle[3] == 'E') )
+ *puHashFunction = XAR_HASH_NONE;
+ else
+ {
+ *puHashFunction = UINT8_MAX;
+ return VERR_XAR_BAD_CHECKSUM_ELEMENT;
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Parses a checksum element typically found under 'data'.
+ *
+ * @returns IPRT status code.
+ * @param pParentElem The parent element ('data').
+ * @param pszName The name of the element, like 'checksum-archived' or
+ * 'checksum-extracted'.
+ * @param puHashFunction Where to return the XAR hash function number.
+ * @param pDigest Where to return the expected message digest.
+ */
+static int rtZipXarParseChecksumElem(xml::ElementNode const *pParentElem, const char *pszName,
+ uint8_t *puHashFunction, PRTZIPXARHASHDIGEST pDigest)
+{
+ /* Default is no checksum. */
+ *puHashFunction = XAR_HASH_NONE;
+ RT_ZERO(*pDigest);
+
+ xml::ElementNode const *pChecksumElem = pParentElem->findChildElement(pszName);
+ if (!pChecksumElem)
+ return VINF_SUCCESS;
+
+ /* The style. */
+ const char *pszStyle = pChecksumElem->findAttributeValue("style");
+ if (!pszStyle)
+ return VERR_XAR_BAD_CHECKSUM_ELEMENT;
+ int rc = rtZipXarParseChecksumStyle(pszStyle, puHashFunction);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ if (*puHashFunction == XAR_HASH_NONE)
+ return VINF_SUCCESS;
+
+ /* The digest. */
+ const char *pszDigest = pChecksumElem->getValue();
+ if (!pszDigest)
+ return VERR_XAR_BAD_CHECKSUM_ELEMENT;
+
+ switch (*puHashFunction)
+ {
+ case XAR_HASH_SHA1:
+ rc = RTSha1FromString(pszDigest, pDigest->abSha1);
+ break;
+ case XAR_HASH_MD5:
+ rc = RTMd5FromString(pszDigest, pDigest->abMd5);
+ break;
+ default:
+ rc = VERR_INTERNAL_ERROR_2;
+ }
+ return rc;
+}
+
+
+/**
+ * Gets all the attributes of the primary data stream.
+ *
+ * @returns IPRT status code.
+ * @param pFileElem The file element, we'll be parsing the 'data'
+ * sub element of this.
+ * @param pDataAttr Where to return the attributes.
+ */
+static int rtZipXarGetDataStreamAttributes(xml::ElementNode const *pFileElem, PRTZIPXARDATASTREAM pDataAttr)
+{
+ /*
+ * Get the data element.
+ */
+ xml::ElementNode const *pDataElem = pFileElem->findChildElement("data");
+ if (!pDataElem)
+ return VERR_XAR_MISSING_DATA_ELEMENT;
+
+ /*
+ * Checksums.
+ */
+ int rc = rtZipXarParseChecksumElem(pDataElem, "extracted-checksum",
+ &pDataAttr->uHashFunExtracted, &pDataAttr->DigestExtracted);
+ if (RT_FAILURE(rc))
+ return rc;
+ rc = rtZipXarParseChecksumElem(pDataElem, "archived-checksum",
+ &pDataAttr->uHashFunArchived, &pDataAttr->DigestArchived);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * The encoding.
+ */
+ const char *pszEncoding = pDataElem->findChildElementAttributeValueP("encoding", "style");
+ if (!pszEncoding)
+ return VERR_XAR_NO_ENCODING;
+ if (!strcmp(pszEncoding, "application/octet-stream"))
+ pDataAttr->enmEncoding = RTZIPXARENCODING_STORE;
+ else if (!strcmp(pszEncoding, "application/x-gzip"))
+ pDataAttr->enmEncoding = RTZIPXARENCODING_GZIP;
+ else
+ pDataAttr->enmEncoding = RTZIPXARENCODING_UNSUPPORTED;
+
+ /*
+ * The data offset and the compressed and uncompressed sizes.
+ */
+ rc = rtZipXarGetOffsetSizeLengthFromElem(pDataElem, &pDataAttr->offData,
+ &pDataAttr->cbDataExtracted, &pDataAttr->cbDataArchived);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* No zero padding or other alignment crap, please. */
+ if ( pDataAttr->enmEncoding == RTZIPXARENCODING_STORE
+ && pDataAttr->cbDataExtracted != pDataAttr->cbDataArchived)
+ return VERR_XAR_ARCHIVED_AND_EXTRACTED_SIZES_MISMATCH;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Parses a timestamp.
+ *
+ * We consider all timestamps optional, and will only fail (return @c false) on
+ * parse errors. If the specified element isn't found, we'll return epoc time.
+ *
+ * @returns boolean success indicator.
+ * @param pParent The parent element (typically 'file').
+ * @param pszChild The name of the child element.
+ * @param pTimeSpec Where to return the timespec on success.
+ */
+static bool rtZipXarParseTimestamp(const xml::ElementNode *pParent, const char *pszChild, PRTTIMESPEC pTimeSpec)
+{
+ const char *pszValue = pParent->findChildElementValueP(pszChild);
+ if (pszValue)
+ {
+ if (RTTimeSpecFromString(pTimeSpec, pszValue))
+ return true;
+ return false;
+ }
+ RTTimeSpecSetNano(pTimeSpec, 0);
+ return true;
+}
+
+
+/**
+ * Gets the next file element in the TOC.
+ *
+ * @returns Pointer to the next file, NULL if we've reached the end.
+ * @param pCurFile The current element.
+ * @param pcCurDepth Depth gauge we update when decending and
+ * acending thru the tree.
+ */
+static xml::ElementNode const *rtZipXarGetNextFileElement(xml::ElementNode const *pCurFile, uint32_t *pcCurDepth)
+{
+ /*
+ * Consider children first.
+ */
+ xml::ElementNode const *pChild = pCurFile->findChildElement("file");
+ if (pChild)
+ {
+ *pcCurDepth += 1;
+ return pChild;
+ }
+
+ /*
+ * Siblings and ancestor siblings.
+ */
+ for (;;)
+ {
+ xml::ElementNode const *pSibling = pCurFile->findNextSibilingElement("file");
+ if (pSibling != NULL)
+ return pSibling;
+
+ if (*pcCurDepth == 0)
+ break;
+ *pcCurDepth -= 1;
+ pCurFile = static_cast<const xml::ElementNode *>(pCurFile->getParent());
+ AssertBreak(pCurFile);
+ Assert(pCurFile->nameEquals("file"));
+ }
+
+ return NULL;
+}
+
+
+
+/*
+ *
+ * T h e V F S F i l e s y s t e m S t r e a m B i t s.
+ * T h e V F S F i l e s y s t e m S t r e a m B i t s.
+ * T h e V F S F i l e s y s t e m S t r e a m B i t s.
+ *
+ */
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnClose}
+ */
+static DECLCALLBACK(int) rtZipXarFssBaseObj_Close(void *pvThis)
+{
+ PRTZIPXARBASEOBJ pThis = (PRTZIPXARBASEOBJ)pvThis;
+
+ /* Currently there is nothing we really have to do here. */
+ NOREF(pThis);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
+ */
+static DECLCALLBACK(int) rtZipXarFssBaseObj_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
+{
+ PRTZIPXARBASEOBJ pThis = (PRTZIPXARBASEOBJ)pvThis;
+
+ /*
+ * Get the common data.
+ */
+
+ /* Sizes. */
+ if (pThis->fModeType == RTFS_TYPE_FILE)
+ {
+ PRTZIPXARIOSTREAM pThisIos = RT_FROM_MEMBER(pThis, RTZIPXARIOSTREAM, BaseObj);
+ pObjInfo->cbObject = pThisIos->DataAttr.cbDataArchived; /* Modified by decomp ios. */
+ pObjInfo->cbAllocated = pThisIos->DataAttr.cbDataArchived;
+ }
+ else
+ {
+ pObjInfo->cbObject = 0;
+ pObjInfo->cbAllocated = 0;
+ }
+
+ /* The file mode. */
+ if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("mode", 0755, &pObjInfo->Attr.fMode)))
+ return VERR_XAR_BAD_FILE_MODE;
+ if (pObjInfo->Attr.fMode & RTFS_TYPE_MASK)
+ return VERR_XAR_BAD_FILE_MODE;
+ pObjInfo->Attr.fMode &= RTFS_UNIX_MASK & ~RTFS_TYPE_MASK;
+ pObjInfo->Attr.fMode |= pThis->fModeType;
+
+ /* File times. */
+ if (RT_UNLIKELY(!rtZipXarParseTimestamp(pThis->pFileElem, "atime", &pObjInfo->AccessTime)))
+ return VERR_XAR_BAD_FILE_TIMESTAMP;
+ if (RT_UNLIKELY(!rtZipXarParseTimestamp(pThis->pFileElem, "ctime", &pObjInfo->ChangeTime)))
+ return VERR_XAR_BAD_FILE_TIMESTAMP;
+ if (RT_UNLIKELY(!rtZipXarParseTimestamp(pThis->pFileElem, "mtime", &pObjInfo->ModificationTime)))
+ return VERR_XAR_BAD_FILE_TIMESTAMP;
+ pObjInfo->BirthTime = RTTimeSpecGetNano(&pObjInfo->AccessTime) <= RTTimeSpecGetNano(&pObjInfo->ChangeTime)
+ ? pObjInfo->AccessTime : pObjInfo->ChangeTime;
+ if (RTTimeSpecGetNano(&pObjInfo->BirthTime) > RTTimeSpecGetNano(&pObjInfo->ModificationTime))
+ pObjInfo->BirthTime = pObjInfo->ModificationTime;
+
+ /*
+ * Copy the desired data.
+ */
+ switch (enmAddAttr)
+ {
+ case RTFSOBJATTRADD_NOTHING:
+ case RTFSOBJATTRADD_UNIX:
+ pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
+ if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("uid", 0, &pObjInfo->Attr.u.Unix.uid)))
+ return VERR_XAR_BAD_FILE_UID;
+ if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("gid", 0, &pObjInfo->Attr.u.Unix.gid)))
+ return VERR_XAR_BAD_FILE_GID;
+ if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("deviceno", 0, &pObjInfo->Attr.u.Unix.INodeIdDevice)))
+ return VERR_XAR_BAD_FILE_DEVICE_NO;
+ if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("inode", 0, &pObjInfo->Attr.u.Unix.INodeId)))
+ return VERR_XAR_BAD_FILE_INODE;
+ pObjInfo->Attr.u.Unix.cHardlinks = 1;
+ pObjInfo->Attr.u.Unix.fFlags = 0;
+ pObjInfo->Attr.u.Unix.GenerationId = 0;
+ pObjInfo->Attr.u.Unix.Device = 0;
+ break;
+
+ case RTFSOBJATTRADD_UNIX_OWNER:
+ {
+ pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
+ if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("uid", 0, &pObjInfo->Attr.u.Unix.uid)))
+ return VERR_XAR_BAD_FILE_UID;
+ const char *pszUser = pThis->pFileElem->findChildElementValueP("user");
+ if (pszUser)
+ RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName), pszUser);
+ else
+ pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
+ break;
+ }
+
+ case RTFSOBJATTRADD_UNIX_GROUP:
+ {
+ pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
+ if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("gid", 0, &pObjInfo->Attr.u.Unix.gid)))
+ return VERR_XAR_BAD_FILE_GID;
+ const char *pszGroup = pThis->pFileElem->findChildElementValueP("group");
+ if (pszGroup)
+ RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName), pszGroup);
+ else
+ pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
+ break;
+ }
+
+ case RTFSOBJATTRADD_EASIZE:
+ pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
+ RT_ZERO(pObjInfo->Attr.u);
+ break;
+
+ default:
+ return VERR_NOT_SUPPORTED;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Xar filesystem base object operations.
+ */
+static const RTVFSOBJOPS g_rtZipXarFssBaseObjOps =
+{
+ RTVFSOBJOPS_VERSION,
+ RTVFSOBJTYPE_BASE,
+ "XarFsStream::Obj",
+ rtZipXarFssBaseObj_Close,
+ rtZipXarFssBaseObj_QueryInfo,
+ RTVFSOBJOPS_VERSION
+};
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnClose}
+ */
+static DECLCALLBACK(int) rtZipXarFssIos_Close(void *pvThis)
+{
+ PRTZIPXARIOSTREAM pThis = (PRTZIPXARIOSTREAM)pvThis;
+
+ RTVfsIoStrmRelease(pThis->hVfsIos);
+ pThis->hVfsIos = NIL_RTVFSIOSTREAM;
+
+ return rtZipXarFssBaseObj_Close(&pThis->BaseObj);
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
+ */
+static DECLCALLBACK(int) rtZipXarFssIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
+{
+ PRTZIPXARIOSTREAM pThis = (PRTZIPXARIOSTREAM)pvThis;
+ return rtZipXarFssBaseObj_QueryInfo(&pThis->BaseObj, pObjInfo, enmAddAttr);
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
+ */
+static DECLCALLBACK(int) rtZipXarFssIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
+{
+ PRTZIPXARIOSTREAM pThis = (PRTZIPXARIOSTREAM)pvThis;
+ AssertReturn(off >= -1, VERR_INVALID_PARAMETER);
+ AssertReturn(pSgBuf->cSegs == 1, VERR_INVALID_PARAMETER);
+
+ /*
+ * Fend of reads beyond the end of the stream here. If
+ */
+ if (off == -1)
+ off = pThis->offCurPos;
+ if (off < 0 || off > pThis->DataAttr.cbDataArchived)
+ return VERR_EOF;
+ if (pThis->fEndOfStream)
+ {
+ if (off >= pThis->DataAttr.cbDataArchived)
+ return pcbRead ? VINF_EOF : VERR_EOF;
+ if (!pThis->fSeekable)
+ return VERR_SEEK_ON_DEVICE;
+ pThis->fEndOfStream = false;
+ }
+
+ size_t cbToRead = pSgBuf->paSegs[0].cbSeg;
+ uint64_t cbLeft = pThis->DataAttr.cbDataArchived - off;
+ if (cbToRead > cbLeft)
+ {
+ if (!pcbRead)
+ return VERR_EOF;
+ cbToRead = (size_t)cbLeft;
+ }
+
+ /*
+ * Do the reading.
+ */
+ size_t cbReadStack = 0;
+ if (!pcbRead)
+ pcbRead = &cbReadStack;
+ int rc = RTVfsIoStrmReadAt(pThis->hVfsIos, off + pThis->DataAttr.offData, pSgBuf->paSegs[0].pvSeg,
+ cbToRead, fBlocking, pcbRead);
+
+ /* Feed the hashes. */
+ size_t cbActuallyRead = *pcbRead;
+ if (pThis->uHashState == RTZIPXAR_HASH_PENDING)
+ {
+ if (pThis->offCurPos == pThis->cbDigested)
+ {
+ rtZipXarHashUpdate(&pThis->CtxArchived, pThis->DataAttr.uHashFunArchived, pSgBuf->paSegs[0].pvSeg, cbActuallyRead);
+ rtZipXarHashUpdate(&pThis->CtxExtracted, pThis->DataAttr.uHashFunExtracted, pSgBuf->paSegs[0].pvSeg, cbActuallyRead);
+ pThis->cbDigested += cbActuallyRead;
+ }
+ else if ( pThis->cbDigested > pThis->offCurPos
+ && pThis->cbDigested < (RTFOFF)(pThis->offCurPos + cbActuallyRead))
+ {
+ size_t offHash = pThis->cbDigested - pThis->offCurPos;
+ void const *pvHash = (uint8_t const *)pSgBuf->paSegs[0].pvSeg + offHash;
+ size_t cbHash = cbActuallyRead - offHash;
+ rtZipXarHashUpdate(&pThis->CtxArchived, pThis->DataAttr.uHashFunArchived, pvHash, cbHash);
+ rtZipXarHashUpdate(&pThis->CtxExtracted, pThis->DataAttr.uHashFunExtracted, pvHash, cbHash);
+ pThis->cbDigested += cbHash;
+ }
+ }
+
+ /* Update the file position. */
+ pThis->offCurPos += cbActuallyRead;
+
+ /*
+ * Check for end of stream, also check the hash.
+ */
+ if (pThis->offCurPos >= pThis->DataAttr.cbDataArchived)
+ {
+ Assert(pThis->offCurPos == pThis->DataAttr.cbDataArchived);
+ pThis->fEndOfStream = true;
+
+ /* Check hash. */
+ if ( pThis->uHashState == RTZIPXAR_HASH_PENDING
+ && pThis->cbDigested == pThis->DataAttr.cbDataArchived)
+ {
+ RTZIPXARHASHDIGEST Digest;
+ rtZipXarHashFinal(&pThis->CtxArchived, pThis->DataAttr.uHashFunArchived, &Digest);
+ if (rtZipXarHashIsEqual(pThis->DataAttr.uHashFunArchived, &Digest, &pThis->DataAttr.DigestArchived))
+ {
+ rtZipXarHashFinal(&pThis->CtxExtracted, pThis->DataAttr.uHashFunExtracted, &Digest);
+ if (rtZipXarHashIsEqual(pThis->DataAttr.uHashFunExtracted, &Digest, &pThis->DataAttr.DigestExtracted))
+ pThis->uHashState = RTZIPXAR_HASH_OK;
+ else
+ {
+ pThis->uHashState = RTZIPXAR_HASH_FAILED_EXTRACTED;
+ rc = VERR_XAR_EXTRACTED_HASH_MISMATCH;
+ }
+ }
+ else
+ {
+ pThis->uHashState = RTZIPXAR_HASH_FAILED_ARCHIVED;
+ rc = VERR_XAR_ARCHIVED_HASH_MISMATCH;
+ }
+ }
+ else if (pThis->uHashState == RTZIPXAR_HASH_FAILED_ARCHIVED)
+ rc = VERR_XAR_ARCHIVED_HASH_MISMATCH;
+ else if (pThis->uHashState == RTZIPXAR_HASH_FAILED_EXTRACTED)
+ rc = VERR_XAR_EXTRACTED_HASH_MISMATCH;
+ }
+
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
+ */
+static DECLCALLBACK(int) rtZipXarFssIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
+{
+ /* Cannot write to a read-only I/O stream. */
+ NOREF(pvThis); NOREF(off); NOREF(pSgBuf); NOREF(fBlocking); NOREF(pcbWritten);
+ return VERR_ACCESS_DENIED;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
+ */
+static DECLCALLBACK(int) rtZipXarFssIos_Flush(void *pvThis)
+{
+ /* It's a read only stream, nothing dirty to flush. */
+ NOREF(pvThis);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
+ */
+static DECLCALLBACK(int) rtZipXarFssIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
+ uint32_t *pfRetEvents)
+{
+ PRTZIPXARIOSTREAM pThis = (PRTZIPXARIOSTREAM)pvThis;
+
+ /* When we've reached the end, read will be set to indicate it. */
+ if ( (fEvents & RTPOLL_EVT_READ)
+ && pThis->fEndOfStream)
+ {
+ int rc = RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, 0, fIntr, pfRetEvents);
+ if (RT_SUCCESS(rc))
+ *pfRetEvents |= RTPOLL_EVT_READ;
+ else
+ *pfRetEvents = RTPOLL_EVT_READ;
+ return VINF_SUCCESS;
+ }
+
+ return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
+ */
+static DECLCALLBACK(int) rtZipXarFssIos_Tell(void *pvThis, PRTFOFF poffActual)
+{
+ PRTZIPXARIOSTREAM pThis = (PRTZIPXARIOSTREAM)pvThis;
+ *poffActual = pThis->offCurPos;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Xar I/O stream operations.
+ */
+static const RTVFSIOSTREAMOPS g_rtZipXarFssIosOps =
+{
+ { /* Obj */
+ RTVFSOBJOPS_VERSION,
+ RTVFSOBJTYPE_IO_STREAM,
+ "XarFsStream::IoStream",
+ rtZipXarFssIos_Close,
+ rtZipXarFssIos_QueryInfo,
+ RTVFSOBJOPS_VERSION
+ },
+ RTVFSIOSTREAMOPS_VERSION,
+ 0,
+ rtZipXarFssIos_Read,
+ rtZipXarFssIos_Write,
+ rtZipXarFssIos_Flush,
+ rtZipXarFssIos_PollOne,
+ rtZipXarFssIos_Tell,
+ NULL /*Skip*/,
+ NULL /*ZeroFill*/,
+ RTVFSIOSTREAMOPS_VERSION
+};
+
+
+/**
+ * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
+ */
+static DECLCALLBACK(int) rtZipXarFssFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
+{
+ NOREF(pvThis);
+ NOREF(fMode);
+ NOREF(fMask);
+ return VERR_NOT_SUPPORTED;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
+ */
+static DECLCALLBACK(int) rtZipXarFssFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+ PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
+{
+ NOREF(pvThis);
+ NOREF(pAccessTime);
+ NOREF(pModificationTime);
+ NOREF(pChangeTime);
+ NOREF(pBirthTime);
+ return VERR_NOT_SUPPORTED;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
+ */
+static DECLCALLBACK(int) rtZipXarFssFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
+{
+ NOREF(pvThis);
+ NOREF(uid);
+ NOREF(gid);
+ return VERR_NOT_SUPPORTED;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
+ */
+static DECLCALLBACK(int) rtZipXarFssFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
+{
+ PRTZIPXARFILE pThis = (PRTZIPXARFILE)pvThis;
+
+ /* Recalculate the request to RTFILE_SEEK_BEGIN. */
+ switch (uMethod)
+ {
+ case RTFILE_SEEK_BEGIN:
+ break;
+ case RTFILE_SEEK_CURRENT:
+ offSeek += pThis->Ios.offCurPos;
+ break;
+ case RTFILE_SEEK_END:
+ offSeek = pThis->Ios.DataAttr.cbDataArchived + offSeek;
+ break;
+ default:
+ AssertFailedReturn(VERR_INVALID_PARAMETER);
+ }
+
+ /* Do limit checks. */
+ if (offSeek < 0)
+ offSeek = 0;
+ else if (offSeek > pThis->Ios.DataAttr.cbDataArchived)
+ offSeek = pThis->Ios.DataAttr.cbDataArchived;
+
+ /* Apply and return. */
+ pThis->Ios.fEndOfStream = (offSeek >= pThis->Ios.DataAttr.cbDataArchived);
+ pThis->Ios.offCurPos = offSeek;
+ if (poffActual)
+ *poffActual = offSeek;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
+ */
+static DECLCALLBACK(int) rtZipXarFssFile_QuerySize(void *pvThis, uint64_t *pcbFile)
+{
+ PRTZIPXARFILE pThis = (PRTZIPXARFILE)pvThis;
+ *pcbFile = pThis->Ios.DataAttr.cbDataArchived;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Xar file operations.
+ */
+static const RTVFSFILEOPS g_rtZipXarFssFileOps =
+{
+ { /* I/O stream */
+ { /* Obj */
+ RTVFSOBJOPS_VERSION,
+ RTVFSOBJTYPE_FILE,
+ "XarFsStream::File",
+ rtZipXarFssIos_Close,
+ rtZipXarFssIos_QueryInfo,
+ RTVFSOBJOPS_VERSION
+ },
+ RTVFSIOSTREAMOPS_VERSION,
+ RTVFSIOSTREAMOPS_FEAT_NO_SG,
+ rtZipXarFssIos_Read,
+ rtZipXarFssIos_Write,
+ rtZipXarFssIos_Flush,
+ rtZipXarFssIos_PollOne,
+ rtZipXarFssIos_Tell,
+ NULL /*Skip*/,
+ NULL /*ZeroFill*/,
+ RTVFSIOSTREAMOPS_VERSION
+ },
+ RTVFSFILEOPS_VERSION,
+ 0,
+ { /* ObjSet */
+ RTVFSOBJSETOPS_VERSION,
+ RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
+ rtZipXarFssFile_SetMode,
+ rtZipXarFssFile_SetTimes,
+ rtZipXarFssFile_SetOwner,
+ RTVFSOBJSETOPS_VERSION
+ },
+ rtZipXarFssFile_Seek,
+ rtZipXarFssFile_QuerySize,
+ RTVFSFILEOPS_VERSION,
+};
+
+
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnClose}
+ */
+static DECLCALLBACK(int) rtZipXarFssDecompIos_Close(void *pvThis)
+{
+ PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
+
+ RTVfsIoStrmRelease(pThis->hVfsIosDecompressor);
+ pThis->hVfsIosDecompressor = NIL_RTVFSIOSTREAM;
+
+ int rc = RTVfsIoStrmRelease(pThis->hVfsIosRaw);
+ pThis->hVfsIosRaw = NIL_RTVFSIOSTREAM;
+ pThis->pIosRaw = NULL;
+
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
+ */
+static DECLCALLBACK(int) rtZipXarFssDecompIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
+{
+ PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
+
+ int rc = rtZipXarFssBaseObj_QueryInfo(&pThis->pIosRaw->BaseObj, pObjInfo, enmAddAttr);
+ pObjInfo->cbObject = pThis->pIosRaw->DataAttr.cbDataExtracted;
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
+ */
+static DECLCALLBACK(int) rtZipXarFssDecompIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
+{
+ PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
+ AssertReturn(pSgBuf->cSegs == 1, VERR_INVALID_PARAMETER);
+
+ /*
+ * Enforce the cbDataExtracted limit.
+ */
+ if (pThis->offCurPos > pThis->pIosRaw->DataAttr.cbDataExtracted)
+ return VERR_XAR_EXTRACTED_SIZE_EXCEEDED;
+
+ /*
+ * Read the data.
+ *
+ * ASSUMES the decompressor stream isn't seekable, so we don't have to
+ * validate off wrt data digest updating.
+ */
+ int rc = RTVfsIoStrmReadAt(pThis->hVfsIosDecompressor, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg,
+ fBlocking, pcbRead);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Hash the data. When reaching the end match against the expected digest.
+ */
+ size_t cbActuallyRead = pcbRead ? *pcbRead : pSgBuf->paSegs[0].cbSeg;
+ pThis->offCurPos += cbActuallyRead;
+ rtZipXarHashUpdate(&pThis->CtxExtracted, pThis->uHashFunExtracted, pSgBuf->paSegs[0].pvSeg, cbActuallyRead);
+ if (rc == VINF_EOF)
+ {
+ if (pThis->offCurPos == pThis->pIosRaw->DataAttr.cbDataExtracted)
+ {
+ if (pThis->uHashState == RTZIPXAR_HASH_PENDING)
+ {
+ RTZIPXARHASHDIGEST Digest;
+ rtZipXarHashFinal(&pThis->CtxExtracted, pThis->uHashFunExtracted, &Digest);
+ if (rtZipXarHashIsEqual(pThis->uHashFunExtracted, &Digest, &pThis->DigestExtracted))
+ pThis->uHashState = RTZIPXAR_HASH_OK;
+ else
+ {
+ pThis->uHashState = RTZIPXAR_HASH_FAILED_EXTRACTED;
+ rc = VERR_XAR_EXTRACTED_HASH_MISMATCH;
+ }
+ }
+ else if (pThis->uHashState != RTZIPXAR_HASH_OK)
+ rc = VERR_XAR_EXTRACTED_HASH_MISMATCH;
+ }
+ else
+ rc = VERR_XAR_EXTRACTED_SIZE_EXCEEDED;
+
+ /* Ensure that the raw stream is also at the end so that both
+ message digests are checked. */
+ if (RT_SUCCESS(rc))
+ {
+ if ( pThis->pIosRaw->offCurPos < pThis->pIosRaw->DataAttr.cbDataArchived
+ || pThis->pIosRaw->uHashState == RTZIPXAR_HASH_PENDING)
+ rc = VERR_XAR_UNUSED_ARCHIVED_DATA;
+ else if (pThis->pIosRaw->uHashState != RTZIPXAR_HASH_OK)
+ rc = VERR_XAR_ARCHIVED_HASH_MISMATCH;
+ }
+ }
+
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
+ */
+static DECLCALLBACK(int) rtZipXarFssDecompIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
+{
+ /* Cannot write to a read-only I/O stream. */
+ NOREF(pvThis); NOREF(off); NOREF(pSgBuf); NOREF(fBlocking); NOREF(pcbWritten);
+ return VERR_ACCESS_DENIED;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
+ */
+static DECLCALLBACK(int) rtZipXarFssDecompIos_Flush(void *pvThis)
+{
+ /* It's a read only stream, nothing dirty to flush. */
+ NOREF(pvThis);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
+ */
+static DECLCALLBACK(int) rtZipXarFssDecompIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
+ uint32_t *pfRetEvents)
+{
+ PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
+ return RTVfsIoStrmPoll(pThis->hVfsIosDecompressor, fEvents, cMillies, fIntr, pfRetEvents);
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
+ */
+static DECLCALLBACK(int) rtZipXarFssDecompIos_Tell(void *pvThis, PRTFOFF poffActual)
+{
+ PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
+ *poffActual = pThis->offCurPos;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Xar I/O stream operations.
+ */
+static const RTVFSIOSTREAMOPS g_rtZipXarFssDecompIosOps =
+{
+ { /* Obj */
+ RTVFSOBJOPS_VERSION,
+ RTVFSOBJTYPE_IO_STREAM,
+ "XarFsStream::DecompIoStream",
+ rtZipXarFssDecompIos_Close,
+ rtZipXarFssDecompIos_QueryInfo,
+ RTVFSOBJOPS_VERSION
+ },
+ RTVFSIOSTREAMOPS_VERSION,
+ 0,
+ rtZipXarFssDecompIos_Read,
+ rtZipXarFssDecompIos_Write,
+ rtZipXarFssDecompIos_Flush,
+ rtZipXarFssDecompIos_PollOne,
+ rtZipXarFssDecompIos_Tell,
+ NULL /*Skip*/,
+ NULL /*ZeroFill*/,
+ RTVFSIOSTREAMOPS_VERSION
+};
+
+
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnClose}
+ */
+static DECLCALLBACK(int) rtZipXarFssSym_Close(void *pvThis)
+{
+ PRTZIPXARBASEOBJ pThis = (PRTZIPXARBASEOBJ)pvThis;
+ return rtZipXarFssBaseObj_Close(pThis);
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
+ */
+static DECLCALLBACK(int) rtZipXarFssSym_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
+{
+ PRTZIPXARBASEOBJ pThis = (PRTZIPXARBASEOBJ)pvThis;
+ return rtZipXarFssBaseObj_QueryInfo(pThis, pObjInfo, enmAddAttr);
+}
+
+/**
+ * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
+ */
+static DECLCALLBACK(int) rtZipXarFssSym_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
+{
+ NOREF(pvThis); NOREF(fMode); NOREF(fMask);
+ return VERR_ACCESS_DENIED;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
+ */
+static DECLCALLBACK(int) rtZipXarFssSym_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+ PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
+{
+ NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
+ return VERR_ACCESS_DENIED;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
+ */
+static DECLCALLBACK(int) rtZipXarFssSym_SetOwner(void *pvThis, RTUID uid, RTGID gid)
+{
+ NOREF(pvThis); NOREF(uid); NOREF(gid);
+ return VERR_ACCESS_DENIED;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSSYMLINKOPS,pfnRead}
+ */
+static DECLCALLBACK(int) rtZipXarFssSym_Read(void *pvThis, char *pszTarget, size_t cbXarget)
+{
+ PRTZIPXARBASEOBJ pThis = (PRTZIPXARBASEOBJ)pvThis;
+#if 0
+ return RTStrCopy(pszTarget, cbXarget, pThis->pXarReader->szTarget);
+#else
+ return VERR_NOT_IMPLEMENTED;
+#endif
+}
+
+
+/**
+ * Xar symbolic (and hardlink) operations.
+ */
+static const RTVFSSYMLINKOPS g_rtZipXarFssSymOps =
+{
+ { /* Obj */
+ RTVFSOBJOPS_VERSION,
+ RTVFSOBJTYPE_SYMLINK,
+ "XarFsStream::Symlink",
+ rtZipXarFssSym_Close,
+ rtZipXarFssSym_QueryInfo,
+ RTVFSOBJOPS_VERSION
+ },
+ RTVFSSYMLINKOPS_VERSION,
+ 0,
+ { /* ObjSet */
+ RTVFSOBJSETOPS_VERSION,
+ RT_OFFSETOF(RTVFSSYMLINKOPS, Obj) - RT_OFFSETOF(RTVFSSYMLINKOPS, ObjSet),
+ rtZipXarFssSym_SetMode,
+ rtZipXarFssSym_SetTimes,
+ rtZipXarFssSym_SetOwner,
+ RTVFSOBJSETOPS_VERSION
+ },
+ rtZipXarFssSym_Read,
+ RTVFSSYMLINKOPS_VERSION
+};
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnClose}
+ */
+static DECLCALLBACK(int) rtZipXarFss_Close(void *pvThis)
+{
+ PRTZIPXARFSSTREAM pThis = (PRTZIPXARFSSTREAM)pvThis;
+
+ RTVfsIoStrmRelease(pThis->hVfsIos);
+ pThis->hVfsIos = NIL_RTVFSIOSTREAM;
+
+ RTVfsFileRelease(pThis->hVfsFile);
+ pThis->hVfsFile = NIL_RTVFSFILE;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
+ */
+static DECLCALLBACK(int) rtZipXarFss_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
+{
+ PRTZIPXARFSSTREAM pThis = (PRTZIPXARFSSTREAM)pvThis;
+ /* Take the lazy approach here, with the sideffect of providing some info
+ that is actually kind of useful. */
+ return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
+}
+
+
+/**
+ * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
+ */
+static DECLCALLBACK(int) rtZipXarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
+{
+ PRTZIPXARFSSTREAM pThis = (PRTZIPXARFSSTREAM)pvThis;
+
+ /*
+ * Check if we've already reached the end in some way.
+ */
+ if (pThis->fEndOfStream)
+ return VERR_EOF;
+ if (pThis->rcFatal != VINF_SUCCESS)
+ return pThis->rcFatal;
+
+ /*
+ * Get the next file element.
+ */
+ xml::ElementNode const *pCurFile = pThis->XarReader.pCurFile;
+ if (pCurFile)
+ pThis->XarReader.pCurFile = pCurFile = rtZipXarGetNextFileElement(pCurFile, &pThis->XarReader.cCurDepth);
+ else if (!pThis->fEndOfStream)
+ {
+ pThis->XarReader.cCurDepth = 0;
+ pThis->XarReader.pCurFile = pCurFile = pThis->XarReader.pToc->findChildElement("file");
+ }
+ if (!pCurFile)
+ {
+ pThis->fEndOfStream = true;
+ return VERR_EOF;
+ }
+
+ /*
+ * Retrive the fundamental attributes (elements actually).
+ */
+ const char *pszName = pCurFile->findChildElementValueP("name");
+ const char *pszType = pCurFile->findChildElementValueP("type");
+ if (RT_UNLIKELY(!pszName || !pszType))
+ return pThis->rcFatal = VERR_XAR_BAD_FILE_ELEMENT;
+
+ /*
+ * Validate the filename. Being a little too paranoid here, perhaps, wrt
+ * path separators and escapes...
+ */
+ if ( !*pszName
+ || strchr(pszName, '/')
+ || strchr(pszName, '\\')
+ || strchr(pszName, ':')
+ || !strcmp(pszName, "..") )
+ return pThis->rcFatal = VERR_XAR_INVALID_FILE_NAME;
+
+ /*
+ * Gather any additional attributes that are essential to the file type,
+ * then create the VFS object we're going to return.
+ */
+ int rc;
+ RTVFSOBJ hVfsObj;
+ RTVFSOBJTYPE enmType;
+ if (!strcmp(pszType, "file"))
+ {
+ RTZIPXARDATASTREAM DataAttr;
+ rc = rtZipXarGetDataStreamAttributes(pCurFile, &DataAttr);
+ if (RT_FAILURE(rc))
+ return pThis->rcFatal = rc;
+ DataAttr.offData += pThis->offZero + pThis->offStart;
+
+ if ( pThis->hVfsFile != NIL_RTVFSFILE
+ && DataAttr.enmEncoding == RTZIPXARENCODING_STORE)
+ {
+ /*
+ * The input is seekable and the XAR file isn't compressed, so we
+ * can provide a seekable file to the user.
+ */
+ RTVFSFILE hVfsFile;
+ PRTZIPXARFILE pFileData;
+ rc = RTVfsNewFile(&g_rtZipXarFssFileOps,
+ sizeof(*pFileData),
+ RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
+ NIL_RTVFS,
+ NIL_RTVFSLOCK,
+ &hVfsFile,
+ (void **)&pFileData);
+ if (RT_FAILURE(rc))
+ return pThis->rcFatal = rc;
+
+ pFileData->Ios.BaseObj.pFileElem = pCurFile;
+ pFileData->Ios.BaseObj.fModeType = RTFS_TYPE_FILE;
+ pFileData->Ios.DataAttr = DataAttr;
+ pFileData->Ios.offCurPos = 0;
+ pFileData->Ios.fEndOfStream = false;
+ pFileData->Ios.fSeekable = true;
+ pFileData->Ios.uHashState = RTZIPXAR_HASH_PENDING;
+ pFileData->Ios.cbDigested = 0;
+ rtZipXarHashInit(&pFileData->Ios.CtxArchived, pFileData->Ios.DataAttr.uHashFunArchived);
+ rtZipXarHashInit(&pFileData->Ios.CtxExtracted, pFileData->Ios.DataAttr.uHashFunExtracted);
+
+ pFileData->Ios.hVfsIos = pThis->hVfsIos;
+ RTVfsIoStrmRetain(pFileData->Ios.hVfsIos);
+ pFileData->hVfsFile = pThis->hVfsFile;
+ RTVfsFileRetain(pFileData->hVfsFile);
+
+ /* Try avoid double content hashing. */
+ if (pFileData->Ios.DataAttr.uHashFunArchived == pFileData->Ios.DataAttr.uHashFunExtracted)
+ pFileData->Ios.DataAttr.uHashFunExtracted = XAR_HASH_NONE;
+
+ enmType = RTVFSOBJTYPE_FILE;
+ hVfsObj = RTVfsObjFromFile(hVfsFile);
+ RTVfsFileRelease(hVfsFile);
+ }
+ else
+ {
+ RTVFSIOSTREAM hVfsIosRaw;
+ PRTZIPXARIOSTREAM pIosData;
+ rc = RTVfsNewIoStream(&g_rtZipXarFssIosOps,
+ sizeof(*pIosData),
+ RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
+ NIL_RTVFS,
+ NIL_RTVFSLOCK,
+ &hVfsIosRaw,
+ (void **)&pIosData);
+ if (RT_FAILURE(rc))
+ return pThis->rcFatal = rc;
+
+ pIosData->BaseObj.pFileElem = pCurFile;
+ pIosData->BaseObj.fModeType = RTFS_TYPE_FILE;
+ pIosData->DataAttr = DataAttr;
+ pIosData->offCurPos = 0;
+ pIosData->fEndOfStream = false;
+ pIosData->fSeekable = pThis->hVfsFile != NIL_RTVFSFILE;
+ pIosData->uHashState = RTZIPXAR_HASH_PENDING;
+ pIosData->cbDigested = 0;
+ rtZipXarHashInit(&pIosData->CtxArchived, pIosData->DataAttr.uHashFunArchived);
+ rtZipXarHashInit(&pIosData->CtxExtracted, pIosData->DataAttr.uHashFunExtracted);
+
+ pIosData->hVfsIos = pThis->hVfsIos;
+ RTVfsIoStrmRetain(pThis->hVfsIos);
+
+ if ( pIosData->DataAttr.enmEncoding != RTZIPXARENCODING_STORE
+ && pIosData->DataAttr.enmEncoding != RTZIPXARENCODING_UNSUPPORTED)
+ {
+ /*
+ * We need to set up a decompression chain.
+ */
+ RTVFSIOSTREAM hVfsIosDecomp;
+ PRTZIPXARDECOMPIOS pIosDecompData;
+ rc = RTVfsNewIoStream(&g_rtZipXarFssDecompIosOps,
+ sizeof(*pIosDecompData),
+ RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
+ NIL_RTVFS,
+ NIL_RTVFSLOCK,
+ &hVfsIosDecomp,
+ (void **)&pIosDecompData);
+ if (RT_FAILURE(rc))
+ {
+ RTVfsIoStrmRelease(hVfsIosRaw);
+ return pThis->rcFatal = rc;
+ }
+
+ pIosDecompData->hVfsIosDecompressor = NIL_RTVFSIOSTREAM;
+ pIosDecompData->hVfsIosRaw = hVfsIosRaw;
+ pIosDecompData->pIosRaw = pIosData;
+ pIosDecompData->offCurPos = 0;
+ pIosDecompData->uHashFunExtracted = DataAttr.uHashFunExtracted;
+ pIosDecompData->uHashState = RTZIPXAR_HASH_PENDING;
+ rtZipXarHashInit(&pIosDecompData->CtxExtracted, pIosDecompData->uHashFunExtracted);
+ pIosDecompData->DigestExtracted = DataAttr.DigestExtracted;
+
+ /* Tell the raw end to only hash the archived data. */
+ pIosData->DataAttr.uHashFunExtracted = XAR_HASH_NONE;
+
+ /*
+ * Hook up the decompressor.
+ */
+ switch (DataAttr.enmEncoding)
+ {
+ case RTZIPXARENCODING_GZIP:
+ /* Must allow zlib header, all examples I've got seems
+ to be using it rather than the gzip one. Makes
+ sense as there is no need to repeat the file name
+ and the attributes. */
+ rc = RTZipGzipDecompressIoStream(hVfsIosRaw, RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR,
+ &pIosDecompData->hVfsIosDecompressor);
+ break;
+ default:
+ rc = VERR_INTERNAL_ERROR_5;
+ break;
+ }
+ if (RT_FAILURE(rc))
+ {
+ RTVfsIoStrmRelease(hVfsIosDecomp);
+ return pThis->rcFatal = rc;
+ }
+
+ /* What to return. */
+ hVfsObj = RTVfsObjFromIoStream(hVfsIosDecomp);
+ RTVfsIoStrmRelease(hVfsIosDecomp);
+ }
+ else
+ {
+ /* Try avoid double content hashing. */
+ if (pIosData->DataAttr.uHashFunArchived == pIosData->DataAttr.uHashFunExtracted)
+ pIosData->DataAttr.uHashFunExtracted = XAR_HASH_NONE;
+
+ /* What to return. */
+ hVfsObj = RTVfsObjFromIoStream(hVfsIosRaw);
+ RTVfsIoStrmRelease(hVfsIosRaw);
+ }
+ enmType = RTVFSOBJTYPE_IO_STREAM;
+ }
+ }
+ else if (!strcmp(pszType, "directory"))
+ {
+ PRTZIPXARBASEOBJ pBaseObjData;
+ rc = RTVfsNewBaseObj(&g_rtZipXarFssBaseObjOps,
+ sizeof(*pBaseObjData),
+ NIL_RTVFS,
+ NIL_RTVFSLOCK,
+ &hVfsObj,
+ (void **)&pBaseObjData);
+ if (RT_FAILURE(rc))
+ return pThis->rcFatal = rc;
+
+ pBaseObjData->pFileElem = pCurFile;
+ pBaseObjData->fModeType = RTFS_TYPE_DIRECTORY;
+
+ enmType = RTVFSOBJTYPE_BASE;
+ }
+ else if (!strcmp(pszType, "symlink"))
+ {
+ RTVFSSYMLINK hVfsSym;
+ PRTZIPXARBASEOBJ pBaseObjData;
+ rc = RTVfsNewSymlink(&g_rtZipXarFssSymOps,
+ sizeof(*pBaseObjData),
+ NIL_RTVFS,
+ NIL_RTVFSLOCK,
+ &hVfsSym,
+ (void **)&pBaseObjData);
+ if (RT_FAILURE(rc))
+ return pThis->rcFatal = rc;
+
+ pBaseObjData->pFileElem = pCurFile;
+ pBaseObjData->fModeType = RTFS_TYPE_SYMLINK;
+
+ enmType = RTVFSOBJTYPE_SYMLINK;
+ hVfsObj = RTVfsObjFromSymlink(hVfsSym);
+ RTVfsSymlinkRelease(hVfsSym);
+ }
+ else
+ return pThis->rcFatal = VERR_XAR_UNKNOWN_FILE_TYPE;
+
+ /*
+ * Set the return data and we're done.
+ */
+ if (ppszName)
+ {
+ /* Figure the length. */
+ size_t const cbCurName = strlen(pszName) + 1;
+ size_t cbFullName = cbCurName;
+ const xml::ElementNode *pAncestor = pCurFile;
+ uint32_t cLeft = pThis->XarReader.cCurDepth;
+ while (cLeft-- > 0)
+ {
+ pAncestor = (const xml::ElementNode *)pAncestor->getParent(); Assert(pAncestor);
+ const char *pszAncestorName = pAncestor->findChildElementValueP("name"); Assert(pszAncestorName);
+ cbFullName += strlen(pszAncestorName) + 1;
+ }
+
+ /* Allocate a buffer. */
+ char *psz = *ppszName = RTStrAlloc(cbFullName);
+ if (!psz)
+ {
+ RTVfsObjRelease(hVfsObj);
+ return VERR_NO_STR_MEMORY;
+ }
+
+ /* Construct it, from the end. */
+ psz += cbFullName;
+ psz -= cbCurName;
+ memcpy(psz, pszName, cbCurName);
+
+ pAncestor = pCurFile;
+ cLeft = pThis->XarReader.cCurDepth;
+ while (cLeft-- > 0)
+ {
+ pAncestor = (const xml::ElementNode *)pAncestor->getParent(); Assert(pAncestor);
+ const char *pszAncestorName = pAncestor->findChildElementValueP("name"); Assert(pszAncestorName);
+ *--psz = '/';
+ size_t cchAncestorName = strlen(pszAncestorName);
+ psz -= cchAncestorName;
+ memcpy(psz, pszAncestorName, cchAncestorName);
+ }
+ Assert(*ppszName == psz);
+ }
+
+ if (phVfsObj)
+ {
+ RTVfsObjRetain(hVfsObj);
+ *phVfsObj = hVfsObj;
+ }
+
+ if (penmType)
+ *penmType = enmType;
+
+ return VINF_SUCCESS;
+}
+
+
+
+/**
+ * Xar filesystem stream operations.
+ */
+static const RTVFSFSSTREAMOPS rtZipXarFssOps =
+{
+ { /* Obj */
+ RTVFSOBJOPS_VERSION,
+ RTVFSOBJTYPE_FS_STREAM,
+ "XarFsStream",
+ rtZipXarFss_Close,
+ rtZipXarFss_QueryInfo,
+ RTVFSOBJOPS_VERSION
+ },
+ RTVFSFSSTREAMOPS_VERSION,
+ 0,
+ rtZipXarFss_Next,
+ RTVFSFSSTREAMOPS_VERSION
+};
+
+
+
+/**
+ * TOC validation part 2.
+ *
+ * Will advance the input stream past the TOC hash and signature data.
+ *
+ * @returns IPRT status code.
+ * @param pThis The FS stream instance being created.
+ * @param pXarHdr The XAR header.
+ * @param pTocDigest The TOC input data digest.
+ */
+static int rtZipXarValidateTocPart2(PRTZIPXARFSSTREAM pThis, PCXARHEADER pXarHdr, PCRTZIPXARHASHDIGEST pTocDigest)
+{
+ int rc;
+
+ /*
+ * Check that the hash function in the TOC matches the one in the XAR header.
+ */
+ const xml::ElementNode *pChecksumElem = pThis->XarReader.pToc->findChildElement("checksum");
+ if (pChecksumElem)
+ {
+ const xml::AttributeNode *pAttr = pChecksumElem->findAttribute("style");
+ if (!pAttr)
+ return VERR_XAR_BAD_CHECKSUM_ELEMENT;
+
+ const char *pszStyle = pAttr->getValue();
+ if (!pszStyle)
+ return VERR_XAR_BAD_CHECKSUM_ELEMENT;
+
+ uint8_t uHashFunction;
+ rc = rtZipXarParseChecksumStyle(pszStyle, &uHashFunction);
+ if (RT_FAILURE(rc))
+ return rc;
+ if (uHashFunction != pThis->uHashFunction)
+ return VERR_XAR_HASH_FUNCTION_MISMATCH;
+
+ /*
+ * Verify the checksum if we got one.
+ */
+ if (pThis->uHashFunction != XAR_HASH_NONE)
+ {
+ RTFOFF offChecksum;
+ RTFOFF cbChecksum;
+ rc = rtZipXarGetOffsetSizeLengthFromElem(pChecksumElem, &offChecksum, &cbChecksum, NULL);
+ if (RT_FAILURE(rc))
+ return rc;
+ if (cbChecksum != (RTFOFF)pThis->cbHashDigest)
+ return VERR_XAR_BAD_DIGEST_LENGTH;
+ if (offChecksum != 0 && pThis->hVfsFile == NIL_RTVFSFILE)
+ return VERR_XAR_NOT_STREAMBLE_ELEMENT_ORDER;
+
+ RTZIPXARHASHDIGEST StoredDigest;
+ rc = RTVfsIoStrmReadAt(pThis->hVfsIos, pThis->offZero + offChecksum, &StoredDigest, pThis->cbHashDigest,
+ true /*fBlocking*/, NULL /*pcbRead*/);
+ if (RT_FAILURE(rc))
+ return rc;
+ if (memcmp(&StoredDigest, pTocDigest, pThis->cbHashDigest))
+ return VERR_XAR_TOC_DIGEST_MISMATCH;
+ }
+ }
+ else if (pThis->uHashFunction != XAR_HASH_NONE)
+ return VERR_XAR_BAD_CHECKSUM_ELEMENT;
+
+ /*
+ * Check the signature, if we got one.
+ */
+ /** @todo signing. */
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Reads and validates the table of content.
+ *
+ * @returns IPRT status code.
+ * @param hVfsIosIn The input stream.
+ * @param pXarHdr The XAR header.
+ * @param pDoc The TOC XML document.
+ * @param ppTocElem Where to return the pointer to the TOC element on
+ * success.
+ * @param pTocDigest Where to return the TOC digest on success.
+ */
+static int rtZipXarReadAndValidateToc(RTVFSIOSTREAM hVfsIosIn, PCXARHEADER pXarHdr,
+ xml::Document *pDoc, xml::ElementNode const **ppTocElem, PRTZIPXARHASHDIGEST pTocDigest)
+{
+ /*
+ * Decompress it, calculating the hash while doing so.
+ */
+ char *pszOutput = (char *)RTMemTmpAlloc(pXarHdr->cbTocUncompressed + 1);
+ if (!pszOutput)
+ return VERR_NO_TMP_MEMORY;
+ int rc = VERR_NO_TMP_MEMORY;
+ void *pvInput = RTMemTmpAlloc(pXarHdr->cbTocCompressed);
+ if (pvInput)
+ {
+ rc = RTVfsIoStrmRead(hVfsIosIn, pvInput, pXarHdr->cbTocCompressed, true /*fBlocking*/, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rtZipXarCalcHash(pXarHdr->uHashFunction, pvInput, pXarHdr->cbTocCompressed, pTocDigest);
+
+ size_t cbActual;
+ rc = RTZipBlockDecompress(RTZIPTYPE_ZLIB, 0 /*fFlags*/,
+ pvInput, pXarHdr->cbTocCompressed, NULL,
+ pszOutput, pXarHdr->cbTocUncompressed, &cbActual);
+ if (RT_SUCCESS(rc) && cbActual != pXarHdr->cbTocUncompressed)
+ rc = VERR_XAR_TOC_UNCOMP_SIZE_MISMATCH;
+ }
+ RTMemTmpFree(pvInput);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ pszOutput[pXarHdr->cbTocUncompressed] = '\0';
+
+ /*
+ * Parse the TOC (XML document) and do some basic validations.
+ */
+ size_t cchToc = strlen(pszOutput);
+ if ( cchToc == pXarHdr->cbTocUncompressed
+ || cchToc + 1 == pXarHdr->cbTocUncompressed)
+ {
+ rc = RTStrValidateEncoding(pszOutput);
+ if (RT_SUCCESS(rc))
+ {
+ xml::XmlMemParser Parser;
+ try
+ {
+ Parser.read(pszOutput, cchToc, RTCString("xar-toc.xml"), *pDoc);
+ }
+ catch (xml::XmlError Err)
+ {
+ rc = VERR_XAR_TOC_XML_PARSE_ERROR;
+ }
+ catch (...)
+ {
+ rc = VERR_NO_MEMORY;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ xml::ElementNode const *pRootElem = pDoc->getRootElement();
+ xml::ElementNode const *pTocElem = NULL;
+ if (pRootElem && pRootElem->nameEquals("xar"))
+ pTocElem = pRootElem ? pRootElem->findChildElement("toc") : NULL;
+ if (pTocElem)
+ {
+#ifndef USE_STD_LIST_FOR_CHILDREN
+ Assert(pRootElem->getParent() == NULL);
+ Assert(pTocElem->getParent() == pRootElem);
+ if ( !pTocElem->getNextSibiling()
+ && !pTocElem->getPrevSibiling())
+#endif
+ {
+ /*
+ * Further parsing and validation is done after the
+ * caller has created an file system stream instance.
+ */
+ *ppTocElem = pTocElem;
+
+ RTMemTmpFree(pszOutput);
+ return VINF_SUCCESS;
+ }
+
+ rc = VERR_XML_TOC_ELEMENT_HAS_SIBLINGS;
+ }
+ else
+ rc = VERR_XML_TOC_ELEMENT_MISSING;
+ }
+ }
+ else
+ rc = VERR_XAR_TOC_UTF8_ENCODING;
+ }
+ else
+ rc = VERR_XAR_TOC_STRLEN_MISMATCH;
+ }
+
+ RTMemTmpFree(pszOutput);
+ return rc;
+}
+
+
+/**
+ * Reads and validates the XAR header.
+ *
+ * @returns IPRT status code.
+ * @param hVfsIosIn The input stream.
+ * @param pXarHdr Where to return the XAR header in host byte order.
+ */
+static int rtZipXarReadAndValidateHeader(RTVFSIOSTREAM hVfsIosIn, PXARHEADER pXarHdr)
+{
+ /*
+ * Read it and check the signature.
+ */
+ int rc = RTVfsIoStrmRead(hVfsIosIn, pXarHdr, sizeof(*pXarHdr), true /*fBlocking*/, NULL);
+ if (RT_FAILURE(rc))
+ return rc;
+ if (pXarHdr->u32Magic != XAR_HEADER_MAGIC)
+ return VERR_XAR_WRONG_MAGIC;
+
+ /*
+ * Correct the byte order.
+ */
+ pXarHdr->cbHeader = RT_BE2H_U16(pXarHdr->cbHeader);
+ pXarHdr->uVersion = RT_BE2H_U16(pXarHdr->uVersion);
+ pXarHdr->cbTocCompressed = RT_BE2H_U64(pXarHdr->cbTocCompressed);
+ pXarHdr->cbTocUncompressed = RT_BE2H_U64(pXarHdr->cbTocUncompressed);
+ pXarHdr->uHashFunction = RT_BE2H_U32(pXarHdr->uHashFunction);
+
+ /*
+ * Validate the header.
+ */
+ if (pXarHdr->uVersion > XAR_HEADER_VERSION)
+ return VERR_XAR_UNSUPPORTED_VERSION;
+ if (pXarHdr->cbHeader < sizeof(XARHEADER))
+ return VERR_XAR_BAD_HDR_SIZE;
+ if (pXarHdr->uHashFunction > XAR_HASH_MAX)
+ return VERR_XAR_UNSUPPORTED_HASH_FUNCTION;
+ if (pXarHdr->cbTocUncompressed < 16)
+ return VERR_XAR_TOC_TOO_SMALL;
+ if (pXarHdr->cbTocUncompressed > _4M)
+ return VERR_XAR_TOC_TOO_BIG;
+ if (pXarHdr->cbTocCompressed > _4M)
+ return VERR_XAR_TOC_TOO_BIG_COMPRESSED;
+
+ /*
+ * Skip over bytes we don't understand (could be padding).
+ */
+ if (pXarHdr->cbHeader > sizeof(XARHEADER))
+ {
+ rc = RTVfsIoStrmSkip(hVfsIosIn, pXarHdr->cbHeader - sizeof(XARHEADER));
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTZipXarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
+{
+ /*
+ * Input validation.
+ */
+ AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
+ *phVfsFss = NIL_RTVFSFSSTREAM;
+ AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE);
+ AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+
+ RTFOFF const offStart = RTVfsIoStrmTell(hVfsIosIn);
+ AssertReturn(offStart >= 0, (int)offStart);
+
+ uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn);
+ AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
+
+ /*
+ * Read and validate the header, then uncompress the TOC.
+ */
+ XARHEADER XarHdr;
+ int rc = rtZipXarReadAndValidateHeader(hVfsIosIn, &XarHdr);
+ if (RT_SUCCESS(rc))
+ {
+ xml::Document *pDoc = NULL;
+ try { pDoc = new xml::Document(); }
+ catch (...) { }
+ if (pDoc)
+ {
+ RTZIPXARHASHDIGEST TocDigest;
+ xml::ElementNode const *pTocElem = NULL;
+ rc = rtZipXarReadAndValidateToc(hVfsIosIn, &XarHdr, pDoc, &pTocElem, &TocDigest);
+ if (RT_SUCCESS(rc))
+ {
+ size_t offZero = RTVfsIoStrmTell(hVfsIosIn);
+ if (offZero > 0)
+ {
+ /*
+ * Create a file system stream before we continue the parsing.
+ */
+ PRTZIPXARFSSTREAM pThis;
+ RTVFSFSSTREAM hVfsFss;
+ rc = RTVfsNewFsStream(&rtZipXarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFss, (void **)&pThis);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->hVfsIos = hVfsIosIn;
+ pThis->hVfsFile = RTVfsIoStrmToFile(hVfsIosIn);
+ pThis->offStart = offStart;
+ pThis->offZero = offZero;
+ pThis->uHashFunction = (uint8_t)XarHdr.uHashFunction;
+ switch (pThis->uHashFunction)
+ {
+ case XAR_HASH_MD5: pThis->cbHashDigest = sizeof(TocDigest.abMd5); break;
+ case XAR_HASH_SHA1: pThis->cbHashDigest = sizeof(TocDigest.abSha1); break;
+ default: pThis->cbHashDigest = 0; break;
+ }
+ pThis->fEndOfStream = false;
+ pThis->rcFatal = VINF_SUCCESS;
+ pThis->XarReader.pDoc = pDoc;
+ pThis->XarReader.pToc = pTocElem;
+ pThis->XarReader.pCurFile = 0;
+ pThis->XarReader.cCurDepth = 0;
+
+ /*
+ * Next validation step.
+ */
+ rc = rtZipXarValidateTocPart2(pThis, &XarHdr, &TocDigest);
+ if (RT_SUCCESS(rc))
+ {
+ *phVfsFss = hVfsFss;
+ return VINF_SUCCESS;
+ }
+
+ RTVfsFsStrmRelease(hVfsFss);
+ return rc;
+ }
+ }
+ else
+ rc = (int)offZero;
+ }
+ delete pDoc;
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+
+ RTVfsIoStrmRelease(hVfsIosIn);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/zip/zip.cpp b/src/VBox/Runtime/common/zip/zip.cpp
index 8abc2602..fa8d140f 100644
--- a/src/VBox/Runtime/common/zip/zip.cpp
+++ b/src/VBox/Runtime/common/zip/zip.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -574,7 +574,8 @@ static DECLCALLBACK(int) rtZipZlibCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
static DECLCALLBACK(int) rtZipZlibDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
{
pZip->u.Zlib.next_out = (Bytef *)pvBuf;
- pZip->u.Zlib.avail_out = (uInt)cbBuf; Assert(pZip->u.Zlib.avail_out == cbBuf);
+ pZip->u.Zlib.avail_out = (uInt)cbBuf;
+ Assert(pZip->u.Zlib.avail_out == cbBuf);
/*
* Be greedy reading input, even if no output buffer is left. It's possible
@@ -1915,6 +1916,46 @@ RTDECL(int) RTZipBlockDecompress(RTZIPTYPE enmType, uint32_t fFlags,
}
case RTZIPTYPE_ZLIB:
+ {
+#ifdef RTZIP_USE_ZLIB
+ AssertReturn(cbSrc == (uInt)cbSrc, VERR_TOO_MUCH_DATA);
+ AssertReturn(cbDst == (uInt)cbDst, VERR_OUT_OF_RANGE);
+
+ z_stream ZStrm;
+ RT_ZERO(ZStrm);
+ ZStrm.next_in = (Bytef *)pvSrc;
+ ZStrm.avail_in = (uInt)cbSrc;
+ ZStrm.next_out = (Bytef *)pvDst;
+ ZStrm.avail_out = (uInt)cbDst;
+
+ int rc = inflateInit(&ZStrm);
+ if (RT_UNLIKELY(rc != Z_OK))
+ return zipErrConvertFromZlib(rc, false /*fCompressing*/);
+ rc = inflate(&ZStrm, Z_FINISH);
+ if (rc != Z_STREAM_END)
+ {
+ inflateEnd(&ZStrm);
+ if ((rc == Z_BUF_ERROR && ZStrm.avail_in == 0) || rc == Z_NEED_DICT)
+ return VERR_ZIP_CORRUPTED;
+ if (rc == Z_BUF_ERROR)
+ return VERR_BUFFER_OVERFLOW;
+ AssertReturn(rc < Z_OK, VERR_GENERAL_FAILURE);
+ return zipErrConvertFromZlib(rc, false /*fCompressing*/);
+ }
+ rc = inflateEnd(&ZStrm);
+ if (rc != Z_OK)
+ return zipErrConvertFromZlib(rc, false /*fCompressing*/);
+
+ if (pcbSrcActual)
+ *pcbSrcActual = ZStrm.avail_in - cbSrc;
+ if (pcbDstActual)
+ *pcbDstActual = ZStrm.total_out;
+ break;
+#else
+ return VERR_NOT_SUPPORTED;
+#endif
+ }
+
case RTZIPTYPE_BZLIB:
return VERR_NOT_SUPPORTED;
diff --git a/src/VBox/Runtime/darwin/RTErrConvertFromDarwin.cpp b/src/VBox/Runtime/darwin/RTErrConvertFromDarwin.cpp
index b1d40a4e..361b25d9 100644
--- a/src/VBox/Runtime/darwin/RTErrConvertFromDarwin.cpp
+++ b/src/VBox/Runtime/darwin/RTErrConvertFromDarwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/darwin/RTErrConvertFromDarwinCOM.cpp b/src/VBox/Runtime/darwin/RTErrConvertFromDarwinCOM.cpp
index 19663e7d..9759529e 100644
--- a/src/VBox/Runtime/darwin/RTErrConvertFromDarwinCOM.cpp
+++ b/src/VBox/Runtime/darwin/RTErrConvertFromDarwinCOM.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/darwin/RTErrConvertFromDarwinIO.cpp b/src/VBox/Runtime/darwin/RTErrConvertFromDarwinIO.cpp
index 2bf4fe7d..daabeafd 100644
--- a/src/VBox/Runtime/darwin/RTErrConvertFromDarwinIO.cpp
+++ b/src/VBox/Runtime/darwin/RTErrConvertFromDarwinIO.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/darwin/RTErrConvertFromDarwinKern.cpp b/src/VBox/Runtime/darwin/RTErrConvertFromDarwinKern.cpp
index caeceb24..9f32e09c 100644
--- a/src/VBox/Runtime/darwin/RTErrConvertFromDarwinKern.cpp
+++ b/src/VBox/Runtime/darwin/RTErrConvertFromDarwinKern.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/gc/initterm-gc.cpp b/src/VBox/Runtime/gc/initterm-gc.cpp
index b35ca578..adb07cc9 100644
--- a/src/VBox/Runtime/gc/initterm-gc.cpp
+++ b/src/VBox/Runtime/gc/initterm-gc.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTAssertShouldPanic-generic.cpp b/src/VBox/Runtime/generic/RTAssertShouldPanic-generic.cpp
index 52ea2eef..7c359ff2 100644
--- a/src/VBox/Runtime/generic/RTAssertShouldPanic-generic.cpp
+++ b/src/VBox/Runtime/generic/RTAssertShouldPanic-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTDirExists-generic.cpp b/src/VBox/Runtime/generic/RTDirExists-generic.cpp
index 0b5f04a9..186160d3 100644
--- a/src/VBox/Runtime/generic/RTDirExists-generic.cpp
+++ b/src/VBox/Runtime/generic/RTDirExists-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTDirQueryInfo-generic.cpp b/src/VBox/Runtime/generic/RTDirQueryInfo-generic.cpp
index a01a8d80..8e92bf14 100644
--- a/src/VBox/Runtime/generic/RTDirQueryInfo-generic.cpp
+++ b/src/VBox/Runtime/generic/RTDirQueryInfo-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTDirSetTimes-generic.cpp b/src/VBox/Runtime/generic/RTDirSetTimes-generic.cpp
index b5b781e2..1616c4f4 100644
--- a/src/VBox/Runtime/generic/RTDirSetTimes-generic.cpp
+++ b/src/VBox/Runtime/generic/RTDirSetTimes-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTFileCopy-generic.cpp b/src/VBox/Runtime/generic/RTFileCopy-generic.cpp
index ea55290c..a87ecb49 100644
--- a/src/VBox/Runtime/generic/RTFileCopy-generic.cpp
+++ b/src/VBox/Runtime/generic/RTFileCopy-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTFileExists-generic.cpp b/src/VBox/Runtime/generic/RTFileExists-generic.cpp
index f8198816..e238361d 100644
--- a/src/VBox/Runtime/generic/RTFileExists-generic.cpp
+++ b/src/VBox/Runtime/generic/RTFileExists-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTFileMove-generic.cpp b/src/VBox/Runtime/generic/RTFileMove-generic.cpp
index 21556ec7..3b4e9897 100644
--- a/src/VBox/Runtime/generic/RTFileMove-generic.cpp
+++ b/src/VBox/Runtime/generic/RTFileMove-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTFileQuerySize-generic.cpp b/src/VBox/Runtime/generic/RTFileQuerySize-generic.cpp
index a561eea6..8ff41f46 100644
--- a/src/VBox/Runtime/generic/RTFileQuerySize-generic.cpp
+++ b/src/VBox/Runtime/generic/RTFileQuerySize-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTFileReadAll-generic.cpp b/src/VBox/Runtime/generic/RTFileReadAll-generic.cpp
index 71c0af12..1eb3f367 100644
--- a/src/VBox/Runtime/generic/RTFileReadAll-generic.cpp
+++ b/src/VBox/Runtime/generic/RTFileReadAll-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTFileReadAllByHandle-generic.cpp b/src/VBox/Runtime/generic/RTFileReadAllByHandle-generic.cpp
index 2d94160f..05a32e66 100644
--- a/src/VBox/Runtime/generic/RTFileReadAllByHandle-generic.cpp
+++ b/src/VBox/Runtime/generic/RTFileReadAllByHandle-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTFileReadAllByHandleEx-generic.cpp b/src/VBox/Runtime/generic/RTFileReadAllByHandleEx-generic.cpp
index 0c41126c..5d5f01f1 100644
--- a/src/VBox/Runtime/generic/RTFileReadAllByHandleEx-generic.cpp
+++ b/src/VBox/Runtime/generic/RTFileReadAllByHandleEx-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTFileReadAllEx-generic.cpp b/src/VBox/Runtime/generic/RTFileReadAllEx-generic.cpp
index 2046d731..98f92a81 100644
--- a/src/VBox/Runtime/generic/RTFileReadAllEx-generic.cpp
+++ b/src/VBox/Runtime/generic/RTFileReadAllEx-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTFileReadAllFree-generic.cpp b/src/VBox/Runtime/generic/RTFileReadAllFree-generic.cpp
index 1f1dd292..2bdcc5c7 100644
--- a/src/VBox/Runtime/generic/RTFileReadAllFree-generic.cpp
+++ b/src/VBox/Runtime/generic/RTFileReadAllFree-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTLogDefaultInit-generic.cpp b/src/VBox/Runtime/generic/RTLogDefaultInit-generic.cpp
index 5a1e122c..7a44173b 100644
--- a/src/VBox/Runtime/generic/RTLogDefaultInit-generic.cpp
+++ b/src/VBox/Runtime/generic/RTLogDefaultInit-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTLogWriteDebugger-generic.cpp b/src/VBox/Runtime/generic/RTLogWriteDebugger-generic.cpp
index 116900b5..a295fd05 100644
--- a/src/VBox/Runtime/generic/RTLogWriteDebugger-generic.cpp
+++ b/src/VBox/Runtime/generic/RTLogWriteDebugger-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTLogWriteStdErr-generic.cpp b/src/VBox/Runtime/generic/RTLogWriteStdErr-generic.cpp
index fc7af981..0f72f31b 100644
--- a/src/VBox/Runtime/generic/RTLogWriteStdErr-generic.cpp
+++ b/src/VBox/Runtime/generic/RTLogWriteStdErr-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTLogWriteStdErr-stub-generic.cpp b/src/VBox/Runtime/generic/RTLogWriteStdErr-stub-generic.cpp
index 4a42187a..946df0ea 100644
--- a/src/VBox/Runtime/generic/RTLogWriteStdErr-stub-generic.cpp
+++ b/src/VBox/Runtime/generic/RTLogWriteStdErr-stub-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTLogWriteStdOut-generic.cpp b/src/VBox/Runtime/generic/RTLogWriteStdOut-generic.cpp
index a358c08d..cb5377fc 100644
--- a/src/VBox/Runtime/generic/RTLogWriteStdOut-generic.cpp
+++ b/src/VBox/Runtime/generic/RTLogWriteStdOut-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTLogWriteStdOut-stub-generic.cpp b/src/VBox/Runtime/generic/RTLogWriteStdOut-stub-generic.cpp
index 99b6b2bb..a154edeb 100644
--- a/src/VBox/Runtime/generic/RTLogWriteStdOut-stub-generic.cpp
+++ b/src/VBox/Runtime/generic/RTLogWriteStdOut-stub-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTLogWriteUser-generic.cpp b/src/VBox/Runtime/generic/RTLogWriteUser-generic.cpp
index 2fe4d0df..a9cdab7f 100644
--- a/src/VBox/Runtime/generic/RTLogWriteUser-generic.cpp
+++ b/src/VBox/Runtime/generic/RTLogWriteUser-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpCpuId-generic.cpp b/src/VBox/Runtime/generic/RTMpCpuId-generic.cpp
index 591d8318..59a7e33a 100644
--- a/src/VBox/Runtime/generic/RTMpCpuId-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpCpuId-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpCpuIdFromSetIndex-generic.cpp b/src/VBox/Runtime/generic/RTMpCpuIdFromSetIndex-generic.cpp
index 2fec3382..91842c08 100644
--- a/src/VBox/Runtime/generic/RTMpCpuIdFromSetIndex-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpCpuIdFromSetIndex-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpCpuIdToSetIndex-generic.cpp b/src/VBox/Runtime/generic/RTMpCpuIdToSetIndex-generic.cpp
index 894f8f4f..6cda69fb 100644
--- a/src/VBox/Runtime/generic/RTMpCpuIdToSetIndex-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpCpuIdToSetIndex-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp b/src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp
index c65eeb2e..08504976 100644
--- a/src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010-2011 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpGetCoreCount-generic.cpp b/src/VBox/Runtime/generic/RTMpGetCoreCount-generic.cpp
new file mode 100644
index 00000000..9155bc4b
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTMpGetCoreCount-generic.cpp
@@ -0,0 +1,40 @@
+/* $Id: RTMpGetCoreCount-generic.cpp $ */
+/** @file
+ * IPRT - Multiprocessor, Generic RTMpGetCoreCount.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/mp.h>
+#include "internal/iprt.h"
+
+
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ return RTMpGetCount();
+}
+RT_EXPORT_SYMBOL(RTMpGetCoreCount);
+
diff --git a/src/VBox/Runtime/generic/RTMpGetCount-generic.cpp b/src/VBox/Runtime/generic/RTMpGetCount-generic.cpp
index f8625e18..af5cb9fc 100644
--- a/src/VBox/Runtime/generic/RTMpGetCount-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetCount-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpGetCurFrequency-generic.cpp b/src/VBox/Runtime/generic/RTMpGetCurFrequency-generic.cpp
index 04c9a68d..f4509e0e 100644
--- a/src/VBox/Runtime/generic/RTMpGetCurFrequency-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetCurFrequency-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpGetDescription-generic-stub.cpp b/src/VBox/Runtime/generic/RTMpGetDescription-generic-stub.cpp
index a3c17668..e0c8cb7b 100644
--- a/src/VBox/Runtime/generic/RTMpGetDescription-generic-stub.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetDescription-generic-stub.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpGetDescription-generic.cpp b/src/VBox/Runtime/generic/RTMpGetDescription-generic.cpp
index dccd4058..fbf11f2a 100644
--- a/src/VBox/Runtime/generic/RTMpGetDescription-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetDescription-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -99,10 +99,11 @@ RTDECL(int) RTMpGetDescription(RTCPUID idCpu, char *pszBuf, size_t cbBuf)
/*
* Copy it out into the buffer supplied by the caller.
*/
- size_t cch = strlen(szString);
- if (cch >= cbBuf)
+ char *pszSrc = RTStrStrip(szString);
+ size_t cchSrc = strlen(pszSrc);
+ if (cchSrc >= cbBuf)
return VERR_BUFFER_OVERFLOW;
- memcpy(pszBuf, szString, cch + 1);
+ memcpy(pszBuf, pszSrc, cchSrc + 1);
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTMpGetDescription);
diff --git a/src/VBox/Runtime/generic/RTMpGetMaxCpuId-generic.cpp b/src/VBox/Runtime/generic/RTMpGetMaxCpuId-generic.cpp
index e7963301..8c385471 100644
--- a/src/VBox/Runtime/generic/RTMpGetMaxCpuId-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetMaxCpuId-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpGetMaxFrequency-generic.cpp b/src/VBox/Runtime/generic/RTMpGetMaxFrequency-generic.cpp
index 4f468d88..197928f3 100644
--- a/src/VBox/Runtime/generic/RTMpGetMaxFrequency-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetMaxFrequency-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpGetOnlineCoreCount-generic.cpp b/src/VBox/Runtime/generic/RTMpGetOnlineCoreCount-generic.cpp
new file mode 100644
index 00000000..19f78141
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTMpGetOnlineCoreCount-generic.cpp
@@ -0,0 +1,40 @@
+/* $Id: RTMpGetOnlineCoreCount-generic.cpp $ */
+/** @file
+ * IPRT - Multiprocessor, Generic RTMpGetCoreCount.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/mp.h>
+#include "internal/iprt.h"
+
+
+RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void)
+{
+ return RTMpGetOnlineCount();
+}
+RT_EXPORT_SYMBOL(RTMpGetOnlineCoreCount);
+
diff --git a/src/VBox/Runtime/generic/RTMpGetOnlineCount-generic.cpp b/src/VBox/Runtime/generic/RTMpGetOnlineCount-generic.cpp
index e11543e0..40be3d00 100644
--- a/src/VBox/Runtime/generic/RTMpGetOnlineCount-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetOnlineCount-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpGetOnlineSet-generic.cpp b/src/VBox/Runtime/generic/RTMpGetOnlineSet-generic.cpp
index 753ee62d..b3a4fee4 100644
--- a/src/VBox/Runtime/generic/RTMpGetOnlineSet-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetOnlineSet-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpGetSet-generic.cpp b/src/VBox/Runtime/generic/RTMpGetSet-generic.cpp
index 01b72496..debd0524 100644
--- a/src/VBox/Runtime/generic/RTMpGetSet-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpGetSet-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpIsCpuOnline-generic.cpp b/src/VBox/Runtime/generic/RTMpIsCpuOnline-generic.cpp
index b53c13ae..987b60a6 100644
--- a/src/VBox/Runtime/generic/RTMpIsCpuOnline-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpIsCpuOnline-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTMpIsCpuPossible-generic.cpp b/src/VBox/Runtime/generic/RTMpIsCpuPossible-generic.cpp
index 7c57ae83..67256312 100644
--- a/src/VBox/Runtime/generic/RTMpIsCpuPossible-generic.cpp
+++ b/src/VBox/Runtime/generic/RTMpIsCpuPossible-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTPathIsSame-generic.cpp b/src/VBox/Runtime/generic/RTPathIsSame-generic.cpp
new file mode 100644
index 00000000..2ed42a5f
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTPathIsSame-generic.cpp
@@ -0,0 +1,93 @@
+/* $Id: RTPathIsSame-generic.cpp $ */
+/** @file
+ * IPRT - Assertions, generic RTPathIsSame.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/path.h>
+#include "internal/iprt.h"
+
+#include <iprt/string.h>
+
+
+RTDECL(int) RTPathIsSame(const char *pszPath1, const char *pszPath2)
+{
+ /*
+ * Simple checks based on the path values.
+ */
+ if (pszPath1 == pszPath2)
+ return true;
+ if (!pszPath1)
+ return false;
+ if (!pszPath2)
+ return false;
+ if (!strcmp(pszPath1, pszPath2))
+ return true;
+
+ /*
+ * If the files exist, try use the attributes.
+ */
+ RTFSOBJINFO ObjInfo1, ObjInfo2;
+ int rc = RTPathQueryInfoEx(pszPath1, &ObjInfo1, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
+ if (RT_SUCCESS(rc))
+ rc = RTPathQueryInfoEx(pszPath2, &ObjInfo2, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
+ if (RT_SUCCESS(rc))
+ {
+ if ((ObjInfo1.Attr.fMode & RTFS_TYPE_MASK) != (ObjInfo2.Attr.fMode & RTFS_TYPE_MASK))
+ return false;
+ if (ObjInfo1.Attr.u.Unix.INodeIdDevice != ObjInfo2.Attr.u.Unix.INodeIdDevice)
+ return false;
+ if (ObjInfo1.Attr.u.Unix.INodeId != ObjInfo2.Attr.u.Unix.INodeId)
+ return false;
+ if (ObjInfo1.Attr.u.Unix.GenerationId != ObjInfo2.Attr.u.Unix.GenerationId)
+ return false;
+ if ( ObjInfo1.Attr.u.Unix.INodeIdDevice != 0
+ && ObjInfo1.Attr.u.Unix.INodeId != 0)
+ return true;
+ }
+
+ /*
+ * Fallback, compare absolute/real paths. Return failure on paths that are
+ * too long.
+ */
+ char szPath1[RTPATH_MAX];
+ rc = RTPathAbs(pszPath1, szPath1, sizeof(szPath1));
+ AssertRCReturn(rc, VERR_FILENAME_TOO_LONG);
+
+ char szPath2[RTPATH_MAX];
+ rc = RTPathAbs(pszPath2, szPath2, sizeof(szPath2)); AssertRC(rc);
+ AssertRCReturn(rc, VERR_FILENAME_TOO_LONG);
+
+ if (RTPathCompare(szPath1, szPath2) == 0)
+ return true;
+
+ /** @todo Relsolve any symbolic links in the paths. Too lazy for that right
+ * now. */
+ return false;
+}
+RT_EXPORT_SYMBOL(RTPathIsSame);
+
diff --git a/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp b/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp
index 3ee4d28b..744dce9b 100644
--- a/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp
+++ b/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -80,7 +80,8 @@ RTR3DECL(int) RTProcDaemonize(const char * const *papszArgs, const char *pszDaem
{
hStdOutAndErr.enmType = RTHANDLETYPE_FILE;
- rc = RTProcCreateEx(szExecPath, papszNewArgs, RTENV_DEFAULT, RTPROC_FLAGS_DETACHED,
+ rc = RTProcCreateEx(szExecPath, papszNewArgs, RTENV_DEFAULT,
+ RTPROC_FLAGS_DETACHED | RTPROC_FLAGS_SAME_CONTRACT,
&hStdIn, &hStdOutAndErr, &hStdOutAndErr,
NULL /*pszAsUser*/, NULL /*pszPassword*/, NULL /*phProcess*/);
diff --git a/src/VBox/Runtime/generic/RTProcIsRunningByName-generic.cpp b/src/VBox/Runtime/generic/RTProcIsRunningByName-generic.cpp
index 1682369a..56eb5191 100644
--- a/src/VBox/Runtime/generic/RTProcIsRunningByName-generic.cpp
+++ b/src/VBox/Runtime/generic/RTProcIsRunningByName-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTProcessQueryUsernameA-generic.cpp b/src/VBox/Runtime/generic/RTProcessQueryUsernameA-generic.cpp
index 9fcba42c..cd7790b6 100644
--- a/src/VBox/Runtime/generic/RTProcessQueryUsernameA-generic.cpp
+++ b/src/VBox/Runtime/generic/RTProcessQueryUsernameA-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTRandAdvCreateSystemFaster-generic.cpp b/src/VBox/Runtime/generic/RTRandAdvCreateSystemFaster-generic.cpp
index 0b05fa5e..1aaab2d2 100644
--- a/src/VBox/Runtime/generic/RTRandAdvCreateSystemFaster-generic.cpp
+++ b/src/VBox/Runtime/generic/RTRandAdvCreateSystemFaster-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTRandAdvCreateSystemTruer-generic.cpp b/src/VBox/Runtime/generic/RTRandAdvCreateSystemTruer-generic.cpp
index 375757a7..402ccb80 100644
--- a/src/VBox/Runtime/generic/RTRandAdvCreateSystemTruer-generic.cpp
+++ b/src/VBox/Runtime/generic/RTRandAdvCreateSystemTruer-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp b/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp
index 437be6be..af7933ec 100644
--- a/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp
+++ b/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTSemEventMultiWait-generic.cpp b/src/VBox/Runtime/generic/RTSemEventMultiWait-generic.cpp
index 16a9580b..46ee3c6b 100644
--- a/src/VBox/Runtime/generic/RTSemEventMultiWait-generic.cpp
+++ b/src/VBox/Runtime/generic/RTSemEventMultiWait-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp b/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp
index c3eb88db..19175a78 100644
--- a/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp
+++ b/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp b/src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp
index b2e78807..650d25e5 100644
--- a/src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp
+++ b/src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTSemEventWait-generic.cpp b/src/VBox/Runtime/generic/RTSemEventWait-generic.cpp
index ade77808..b24fe9dc 100644
--- a/src/VBox/Runtime/generic/RTSemEventWait-generic.cpp
+++ b/src/VBox/Runtime/generic/RTSemEventWait-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp b/src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp
index 3dbe66cd..2c8181ef 100644
--- a/src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp
+++ b/src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTSemMutexRequest-generic.cpp b/src/VBox/Runtime/generic/RTSemMutexRequest-generic.cpp
index 32c3f876..0ef65f43 100644
--- a/src/VBox/Runtime/generic/RTSemMutexRequest-generic.cpp
+++ b/src/VBox/Runtime/generic/RTSemMutexRequest-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTSemMutexRequestDebug-generic.cpp b/src/VBox/Runtime/generic/RTSemMutexRequestDebug-generic.cpp
index 4ba15039..a26b4af1 100644
--- a/src/VBox/Runtime/generic/RTSemMutexRequestDebug-generic.cpp
+++ b/src/VBox/Runtime/generic/RTSemMutexRequestDebug-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTSystemQueryOSInfo-generic.cpp b/src/VBox/Runtime/generic/RTSystemQueryOSInfo-generic.cpp
index ec52c77d..7ba8e781 100644
--- a/src/VBox/Runtime/generic/RTSystemQueryOSInfo-generic.cpp
+++ b/src/VBox/Runtime/generic/RTSystemQueryOSInfo-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTTimeLocalDeltaNano-generic.cpp b/src/VBox/Runtime/generic/RTTimeLocalDeltaNano-generic.cpp
index 92826f0e..c24b5f38 100644
--- a/src/VBox/Runtime/generic/RTTimeLocalDeltaNano-generic.cpp
+++ b/src/VBox/Runtime/generic/RTTimeLocalDeltaNano-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTTimeLocalExplode-generic.cpp b/src/VBox/Runtime/generic/RTTimeLocalExplode-generic.cpp
index ae760602..b7b4e567 100644
--- a/src/VBox/Runtime/generic/RTTimeLocalExplode-generic.cpp
+++ b/src/VBox/Runtime/generic/RTTimeLocalExplode-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTTimeLocalNow-generic.cpp b/src/VBox/Runtime/generic/RTTimeLocalNow-generic.cpp
index f3d268eb..f26124e7 100644
--- a/src/VBox/Runtime/generic/RTTimeLocalNow-generic.cpp
+++ b/src/VBox/Runtime/generic/RTTimeLocalNow-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTTimerLRCreate-generic.cpp b/src/VBox/Runtime/generic/RTTimerLRCreate-generic.cpp
index 6af2c79a..415fcd05 100644
--- a/src/VBox/Runtime/generic/RTTimerLRCreate-generic.cpp
+++ b/src/VBox/Runtime/generic/RTTimerLRCreate-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/RTUuidCreate-generic.cpp b/src/VBox/Runtime/generic/RTUuidCreate-generic.cpp
index e88ab1ff..439bf7bc 100644
--- a/src/VBox/Runtime/generic/RTUuidCreate-generic.cpp
+++ b/src/VBox/Runtime/generic/RTUuidCreate-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/cdrom-generic.cpp b/src/VBox/Runtime/generic/cdrom-generic.cpp
index 13e8e96f..65332a58 100644
--- a/src/VBox/Runtime/generic/cdrom-generic.cpp
+++ b/src/VBox/Runtime/generic/cdrom-generic.cpp
@@ -28,7 +28,6 @@
/*******************************************************************************
* Header Files *
*******************************************************************************/
-#define RTCRITSECT_WITHOUT_REMAPPING
#include <iprt/cdrom.h>
#include "internal/iprt.h"
diff --git a/src/VBox/Runtime/generic/createtemp-generic.cpp b/src/VBox/Runtime/generic/createtemp-generic.cpp
index 984dc1bf..addbb5db 100644
--- a/src/VBox/Runtime/generic/createtemp-generic.cpp
+++ b/src/VBox/Runtime/generic/createtemp-generic.cpp
@@ -149,7 +149,7 @@ RTDECL(int) RTDirCreateTempSecure(char *pszTemplate)
/* bool fSafe; */
/* Temporarily convert pszTemplate to a path. */
- RTPathParse(pszTemplate, &cchDir, NULL, NULL);
+ RTPathParseSimple(pszTemplate, &cchDir, NULL, NULL);
chOld = pszTemplate[cchDir];
pszTemplate[cchDir] = '\0';
/** @todo Implement this. */
@@ -218,7 +218,7 @@ RTDECL(int) RTFileCreateTempSecure(char *pszTemplate)
/* bool fSafe; */
/* Temporarily convert pszTemplate to a path. */
- RTPathParse(pszTemplate, &cchDir, NULL, NULL);
+ RTPathParseSimple(pszTemplate, &cchDir, NULL, NULL);
chOld = pszTemplate[cchDir];
pszTemplate[cchDir] = '\0';
/** @todo Implement this. */
diff --git a/src/VBox/Runtime/generic/critsect-generic.cpp b/src/VBox/Runtime/generic/critsect-generic.cpp
index ed276451..4258fcff 100644
--- a/src/VBox/Runtime/generic/critsect-generic.cpp
+++ b/src/VBox/Runtime/generic/critsect-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/critsectrw-generic.cpp b/src/VBox/Runtime/generic/critsectrw-generic.cpp
new file mode 100644
index 00000000..41099ec9
--- /dev/null
+++ b/src/VBox/Runtime/generic/critsectrw-generic.cpp
@@ -0,0 +1,917 @@
+/* $Id: critsectrw-generic.cpp $ */
+/** @file
+ * IPRT - Read/Write Critical Section, Generic.
+ */
+
+/*
+ * Copyright (C) 2009-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define RTCRITSECTRW_WITHOUT_REMAPPING
+#define RTASSERT_QUIET
+#include <iprt/critsect.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/lockvalidator.h>
+#include <iprt/mem.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+
+#include "internal/magics.h"
+#include "internal/strict.h"
+
+
+
+RTDECL(int) RTCritSectRwInit(PRTCRITSECTRW pThis)
+{
+ return RTCritSectRwInitEx(pThis, 0, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectRw");
+}
+RT_EXPORT_SYMBOL(RTCritSectRwInit);
+
+
+RTDECL(int) RTCritSectRwInitEx(PRTCRITSECTRW pThis, uint32_t fFlags,
+ RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
+{
+ int rc;
+ AssertReturn(!(fFlags & ~( RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_BOOTSTRAP_HACK
+ | RTCRITSECT_FLAGS_NOP )),
+ VERR_INVALID_PARAMETER);
+
+ /*
+ * Initialize the structure, allocate the lock validator stuff and sems.
+ */
+ pThis->u32Magic = RTCRITSECTRW_MAGIC_DEAD;
+ pThis->fNeedReset = false;
+ pThis->u64State = 0;
+ pThis->hNativeWriter = NIL_RTNATIVETHREAD;
+ pThis->cWriterReads = 0;
+ pThis->cWriteRecursions = 0;
+ pThis->hEvtWrite = NIL_RTSEMEVENT;
+ pThis->hEvtRead = NIL_RTSEMEVENTMULTI;
+ pThis->pValidatorWrite = NULL;
+ pThis->pValidatorRead = NULL;
+#if HC_ARCH_BITS == 32
+ pThis->HCPtrPadding = NIL_RTHCPTR;
+#endif
+
+#ifdef RTCRITSECTRW_STRICT
+ bool const fLVEnabled = !(fFlags & RTCRITSECT_FLAGS_NO_LOCK_VAL);
+ if (!pszNameFmt)
+ {
+ static uint32_t volatile s_iAnon = 0;
+ uint32_t i = ASMAtomicIncU32(&s_iAnon) - 1;
+ rc = RTLockValidatorRecExclCreate(&pThis->pValidatorWrite, hClass, uSubClass, pThis,
+ fLVEnabled, "RTCritSectRw-%u", i);
+ if (RT_SUCCESS(rc))
+ rc = RTLockValidatorRecSharedCreate(&pThis->pValidatorRead, hClass, uSubClass, pThis,
+ false /*fSignaller*/, fLVEnabled, "RTCritSectRw-%u", i);
+ }
+ else
+ {
+ va_list va;
+ va_start(va, pszNameFmt);
+ rc = RTLockValidatorRecExclCreateV(&pThis->pValidatorWrite, hClass, uSubClass, pThis,
+ fLVEnabled, pszNameFmt, va);
+ va_end(va);
+ if (RT_SUCCESS(rc))
+ {
+ va_start(va, pszNameFmt);
+ RTLockValidatorRecSharedCreateV(&pThis->pValidatorRead, hClass, uSubClass, pThis,
+ false /*fSignaller*/, fLVEnabled, pszNameFmt, va);
+ va_end(va);
+ }
+ }
+ if (RT_SUCCESS(rc))
+ rc = RTLockValidatorRecMakeSiblings(&pThis->pValidatorWrite->Core, &pThis->pValidatorRead->Core);
+
+ if (RT_SUCCESS(rc))
+#endif
+ {
+ rc = RTSemEventMultiCreate(&pThis->hEvtRead);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventCreate(&pThis->hEvtWrite);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->u32Magic = RTCRITSECTRW_MAGIC;
+ return VINF_SUCCESS;
+ }
+ RTSemEventMultiDestroy(pThis->hEvtRead);
+ }
+ }
+
+#ifdef RTCRITSECTRW_STRICT
+ RTLockValidatorRecSharedDestroy(&pThis->pValidatorRead);
+ RTLockValidatorRecExclDestroy(&pThis->pValidatorWrite);
+#endif
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCritSectRwInitEx);
+
+
+RTDECL(uint32_t) RTCritSectRwSetSubClass(PRTCRITSECTRW pThis, uint32_t uSubClass)
+{
+ AssertPtrReturn(pThis, RTLOCKVAL_SUB_CLASS_INVALID);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
+#ifdef RTCRITSECTRW_STRICT
+ AssertReturn(!(pThis->fFlags & RTCRITSECT_FLAGS_NOP), RTLOCKVAL_SUB_CLASS_INVALID);
+
+ RTLockValidatorRecSharedSetSubClass(pThis->pValidatorRead, uSubClass);
+ return RTLockValidatorRecExclSetSubClass(pThis->pValidatorWrite, uSubClass);
+#else
+ NOREF(uSubClass);
+ return RTLOCKVAL_SUB_CLASS_INVALID;
+#endif
+}
+RT_EXPORT_SYMBOL(RTCritSectRwSetSubClass);
+
+
+static int rtCritSectRwEnterShared(PRTCRITSECTRW pThis, PCRTLOCKVALSRCPOS pSrcPos, bool fTryOnly)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtr(pThis);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
+
+#ifdef RTCRITSECTRW_STRICT
+ RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
+ if (!fTryOnly)
+ {
+ int rc9;
+ RTNATIVETHREAD hNativeWriter;
+ ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
+ if (hNativeWriter != NIL_RTTHREAD && hNativeWriter == RTThreadNativeSelf())
+ rc9 = RTLockValidatorRecExclCheckOrder(pThis->pValidatorWrite, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
+ else
+ rc9 = RTLockValidatorRecSharedCheckOrder(pThis->pValidatorRead, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
+ if (RT_FAILURE(rc9))
+ return rc9;
+ }
+#endif
+
+ /*
+ * Get cracking...
+ */
+ uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
+ uint64_t u64OldState = u64State;
+
+ for (;;)
+ {
+ if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
+ {
+ /* It flows in the right direction, try follow it before it changes. */
+ uint64_t c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
+ c++;
+ Assert(c < RTCSRW_CNT_MASK / 2);
+ u64State &= ~RTCSRW_CNT_RD_MASK;
+ u64State |= c << RTCSRW_CNT_RD_SHIFT;
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ {
+#ifdef RTCRITSECTRW_STRICT
+ RTLockValidatorRecSharedAddOwner(pThis->pValidatorRead, hThreadSelf, pSrcPos);
+#endif
+ break;
+ }
+ }
+ else if ((u64State & (RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK)) == 0)
+ {
+ /* Wrong direction, but we're alone here and can simply try switch the direction. */
+ u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK | RTCSRW_DIR_MASK);
+ u64State |= (UINT64_C(1) << RTCSRW_CNT_RD_SHIFT) | (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT);
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ {
+ Assert(!pThis->fNeedReset);
+#ifdef RTCRITSECTRW_STRICT
+ RTLockValidatorRecSharedAddOwner(pThis->pValidatorRead, hThreadSelf, pSrcPos);
+#endif
+ break;
+ }
+ }
+ else
+ {
+ /* Is the writer perhaps doing a read recursion? */
+ RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
+ RTNATIVETHREAD hNativeWriter;
+ ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
+ if (hNativeSelf == hNativeWriter)
+ {
+#ifdef RTCRITSECTRW_STRICT
+ int rc9 = RTLockValidatorRecExclRecursionMixed(pThis->pValidatorWrite, &pThis->pValidatorRead->Core, pSrcPos);
+ if (RT_FAILURE(rc9))
+ return rc9;
+#endif
+ Assert(pThis->cWriterReads < UINT32_MAX / 2);
+ ASMAtomicIncU32(&pThis->cWriterReads);
+ return VINF_SUCCESS; /* don't break! */
+ }
+
+ /* If we're only trying, return already. */
+ if (fTryOnly)
+ return VERR_SEM_BUSY;
+
+ /* Add ourselves to the queue and wait for the direction to change. */
+ uint64_t c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
+ c++;
+ Assert(c < RTCSRW_CNT_MASK / 2);
+
+ uint64_t cWait = (u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT;
+ cWait++;
+ Assert(cWait <= c);
+ Assert(cWait < RTCSRW_CNT_MASK / 2);
+
+ u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_WAIT_CNT_RD_MASK);
+ u64State |= (c << RTCSRW_CNT_RD_SHIFT) | (cWait << RTCSRW_WAIT_CNT_RD_SHIFT);
+
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ {
+ for (uint32_t iLoop = 0; ; iLoop++)
+ {
+ int rc;
+#ifdef RTCRITSECTRW_STRICT
+ rc = RTLockValidatorRecSharedCheckBlocking(pThis->pValidatorRead, hThreadSelf, pSrcPos, true,
+ RT_INDEFINITE_WAIT, RTTHREADSTATE_RW_READ, false);
+ if (RT_SUCCESS(rc))
+#else
+ RTTHREAD hThreadSelf = RTThreadSelf();
+ RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, false);
+#endif
+ {
+ rc = RTSemEventMultiWait(pThis->hEvtRead, RT_INDEFINITE_WAIT);
+ RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
+ if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
+ return VERR_SEM_DESTROYED;
+ }
+ if (RT_FAILURE(rc))
+ {
+ /* Decrement the counts and return the error. */
+ for (;;)
+ {
+ u64OldState = u64State = ASMAtomicReadU64(&pThis->u64State);
+ c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT; Assert(c > 0);
+ c--;
+ cWait = (u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT; Assert(cWait > 0);
+ cWait--;
+ u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_WAIT_CNT_RD_MASK);
+ u64State |= (c << RTCSRW_CNT_RD_SHIFT) | (cWait << RTCSRW_WAIT_CNT_RD_SHIFT);
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ break;
+ }
+ return rc;
+ }
+
+ Assert(pThis->fNeedReset);
+ u64State = ASMAtomicReadU64(&pThis->u64State);
+ if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
+ break;
+ AssertMsg(iLoop < 1, ("%u\n", iLoop));
+ }
+
+ /* Decrement the wait count and maybe reset the semaphore (if we're last). */
+ for (;;)
+ {
+ u64OldState = u64State;
+
+ cWait = (u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT;
+ Assert(cWait > 0);
+ cWait--;
+ u64State &= ~RTCSRW_WAIT_CNT_RD_MASK;
+ u64State |= cWait << RTCSRW_WAIT_CNT_RD_SHIFT;
+
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ {
+ if (cWait == 0)
+ {
+ if (ASMAtomicXchgBool(&pThis->fNeedReset, false))
+ {
+ int rc = RTSemEventMultiReset(pThis->hEvtRead);
+ AssertRCReturn(rc, rc);
+ }
+ }
+ break;
+ }
+ u64State = ASMAtomicReadU64(&pThis->u64State);
+ }
+
+#ifdef RTCRITSECTRW_STRICT
+ RTLockValidatorRecSharedAddOwner(pThis->pValidatorRead, hThreadSelf, pSrcPos);
+#endif
+ break;
+ }
+ }
+
+ if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
+ return VERR_SEM_DESTROYED;
+
+ ASMNopPause();
+ u64State = ASMAtomicReadU64(&pThis->u64State);
+ u64OldState = u64State;
+ }
+
+ /* got it! */
+ Assert((ASMAtomicReadU64(&pThis->u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT));
+ return VINF_SUCCESS;
+
+}
+
+
+RTDECL(int) RTCritSectRwEnterShared(PRTCRITSECTRW pThis)
+{
+#ifndef RTCRITSECTRW_STRICT
+ return rtCritSectRwEnterShared(pThis, NULL, false /*fTryOnly*/);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtCritSectRwEnterShared(pThis, &SrcPos, false /*fTryOnly*/);
+#endif
+}
+RT_EXPORT_SYMBOL(RTCritSectRwEnterShared);
+
+
+RTDECL(int) RTCritSectRwEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtCritSectRwEnterShared(pThis, &SrcPos, false /*fTryOnly*/);
+}
+RT_EXPORT_SYMBOL(RTCritSectRwEnterSharedDebug);
+
+
+RTDECL(int) RTCritSectRwTryEnterShared(PRTCRITSECTRW pThis)
+{
+#ifndef RTCRITSECTRW_STRICT
+ return rtCritSectRwEnterShared(pThis, NULL, true /*fTryOnly*/);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtCritSectRwEnterShared(pThis, &SrcPos, true /*fTryOnly*/);
+#endif
+}
+RT_EXPORT_SYMBOL(RTCritSectRwEnterShared);
+
+
+RTDECL(int) RTCritSectRwTryEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtCritSectRwEnterShared(pThis, &SrcPos, true /*fTryOnly*/);
+}
+RT_EXPORT_SYMBOL(RTCritSectRwEnterSharedDebug);
+
+
+
+RTDECL(int) RTCritSectRwLeaveShared(PRTCRITSECTRW pThis)
+{
+ /*
+ * Validate handle.
+ */
+ AssertPtr(pThis);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
+
+ /*
+ * Check the direction and take action accordingly.
+ */
+ uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
+ uint64_t u64OldState = u64State;
+ if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
+ {
+#ifdef RTCRITSECTRW_STRICT
+ int rc9 = RTLockValidatorRecSharedCheckAndRelease(pThis->pValidatorRead, NIL_RTTHREAD);
+ if (RT_FAILURE(rc9))
+ return rc9;
+#endif
+ for (;;)
+ {
+ uint64_t c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
+ AssertReturn(c > 0, VERR_NOT_OWNER);
+ c--;
+
+ if ( c > 0
+ || (u64State & RTCSRW_CNT_WR_MASK) == 0)
+ {
+ /* Don't change the direction. */
+ u64State &= ~RTCSRW_CNT_RD_MASK;
+ u64State |= c << RTCSRW_CNT_RD_SHIFT;
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ break;
+ }
+ else
+ {
+ /* Reverse the direction and signal the reader threads. */
+ u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_DIR_MASK);
+ u64State |= RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT;
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ {
+ int rc = RTSemEventSignal(pThis->hEvtWrite);
+ AssertRC(rc);
+ break;
+ }
+ }
+
+ ASMNopPause();
+ u64State = ASMAtomicReadU64(&pThis->u64State);
+ u64OldState = u64State;
+ }
+ }
+ else
+ {
+ RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
+ RTNATIVETHREAD hNativeWriter;
+ ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
+ AssertReturn(hNativeSelf == hNativeWriter, VERR_NOT_OWNER);
+ AssertReturn(pThis->cWriterReads > 0, VERR_NOT_OWNER);
+#ifdef RTCRITSECTRW_STRICT
+ int rc = RTLockValidatorRecExclUnwindMixed(pThis->pValidatorWrite, &pThis->pValidatorRead->Core);
+ if (RT_FAILURE(rc))
+ return rc;
+#endif
+ ASMAtomicDecU32(&pThis->cWriterReads);
+ }
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTCritSectRwLeaveShared);
+
+
+static int rtCritSectRwEnterExcl(PRTCRITSECTRW pThis, PCRTLOCKVALSRCPOS pSrcPos, bool fTryOnly)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtr(pThis);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
+
+#ifdef RTCRITSECTRW_STRICT
+ RTTHREAD hThreadSelf = NIL_RTTHREAD;
+ if (!fTryOnly)
+ {
+ hThreadSelf = RTThreadSelfAutoAdopt();
+ int rc9 = RTLockValidatorRecExclCheckOrder(pThis->pValidatorWrite, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
+ if (RT_FAILURE(rc9))
+ return rc9;
+ }
+#endif
+
+ /*
+ * Check if we're already the owner and just recursing.
+ */
+ RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
+ RTNATIVETHREAD hNativeWriter;
+ ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
+ if (hNativeSelf == hNativeWriter)
+ {
+ Assert((ASMAtomicReadU64(&pThis->u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT));
+#ifdef RTCRITSECTRW_STRICT
+ int rc9 = RTLockValidatorRecExclRecursion(pThis->pValidatorWrite, pSrcPos);
+ if (RT_FAILURE(rc9))
+ return rc9;
+#endif
+ Assert(pThis->cWriteRecursions < UINT32_MAX / 2);
+ ASMAtomicIncU32(&pThis->cWriteRecursions);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Get cracking.
+ */
+ uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
+ uint64_t u64OldState = u64State;
+
+ for (;;)
+ {
+ if ( (u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT)
+ || (u64State & (RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK)) != 0)
+ {
+ /* It flows in the right direction, try follow it before it changes. */
+ uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT;
+ c++;
+ Assert(c < RTCSRW_CNT_MASK / 2);
+ u64State &= ~RTCSRW_CNT_WR_MASK;
+ u64State |= c << RTCSRW_CNT_WR_SHIFT;
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ break;
+ }
+ else if ((u64State & (RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK)) == 0)
+ {
+ /* Wrong direction, but we're alone here and can simply try switch the direction. */
+ u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK | RTCSRW_DIR_MASK);
+ u64State |= (UINT64_C(1) << RTCSRW_CNT_WR_SHIFT) | (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT);
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ break;
+ }
+ else if (fTryOnly)
+ /* Wrong direction and we're not supposed to wait, just return. */
+ return VERR_SEM_BUSY;
+ else
+ {
+ /* Add ourselves to the write count and break out to do the wait. */
+ uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT;
+ c++;
+ Assert(c < RTCSRW_CNT_MASK / 2);
+ u64State &= ~RTCSRW_CNT_WR_MASK;
+ u64State |= c << RTCSRW_CNT_WR_SHIFT;
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ break;
+ }
+
+ if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
+ return VERR_SEM_DESTROYED;
+
+ ASMNopPause();
+ u64State = ASMAtomicReadU64(&pThis->u64State);
+ u64OldState = u64State;
+ }
+
+ /*
+ * If we're in write mode now try grab the ownership. Play fair if there
+ * are threads already waiting.
+ */
+ bool fDone = (u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT)
+ && ( ((u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT) == 1
+ || fTryOnly);
+ if (fDone)
+ ASMAtomicCmpXchgHandle(&pThis->hNativeWriter, hNativeSelf, NIL_RTNATIVETHREAD, fDone);
+ if (!fDone)
+ {
+ /*
+ * If only trying, undo the above writer incrementation and return.
+ */
+ if (fTryOnly)
+ {
+ for (;;)
+ {
+ u64OldState = u64State = ASMAtomicReadU64(&pThis->u64State);
+ uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT; Assert(c > 0);
+ c--;
+ u64State &= ~RTCSRW_CNT_WR_MASK;
+ u64State |= c << RTCSRW_CNT_WR_SHIFT;
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ break;
+ }
+ return VERR_SEM_BUSY;
+ }
+
+ /*
+ * Wait for our turn.
+ */
+ for (uint32_t iLoop = 0; ; iLoop++)
+ {
+ int rc;
+#ifdef RTCRITSECTRW_STRICT
+ if (hThreadSelf == NIL_RTTHREAD)
+ hThreadSelf = RTThreadSelfAutoAdopt();
+ rc = RTLockValidatorRecExclCheckBlocking(pThis->pValidatorWrite, hThreadSelf, pSrcPos, true,
+ RT_INDEFINITE_WAIT, RTTHREADSTATE_RW_WRITE, false);
+ if (RT_SUCCESS(rc))
+#else
+ RTTHREAD hThreadSelf = RTThreadSelf();
+ RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, false);
+#endif
+ {
+ rc = RTSemEventWait(pThis->hEvtWrite, RT_INDEFINITE_WAIT);
+ RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
+ if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
+ return VERR_SEM_DESTROYED;
+ }
+ if (RT_FAILURE(rc))
+ {
+ /* Decrement the counts and return the error. */
+ for (;;)
+ {
+ u64OldState = u64State = ASMAtomicReadU64(&pThis->u64State);
+ uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT; Assert(c > 0);
+ c--;
+ u64State &= ~RTCSRW_CNT_WR_MASK;
+ u64State |= c << RTCSRW_CNT_WR_SHIFT;
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ break;
+ }
+ return rc;
+ }
+
+ u64State = ASMAtomicReadU64(&pThis->u64State);
+ if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT))
+ {
+ ASMAtomicCmpXchgHandle(&pThis->hNativeWriter, hNativeSelf, NIL_RTNATIVETHREAD, fDone);
+ if (fDone)
+ break;
+ }
+ AssertMsg(iLoop < 1000, ("%u\n", iLoop)); /* may loop a few times here... */
+ }
+ }
+
+ /*
+ * Got it!
+ */
+ Assert((ASMAtomicReadU64(&pThis->u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT));
+ ASMAtomicWriteU32(&pThis->cWriteRecursions, 1);
+ Assert(pThis->cWriterReads == 0);
+#ifdef RTCRITSECTRW_STRICT
+ RTLockValidatorRecExclSetOwner(pThis->pValidatorWrite, hThreadSelf, pSrcPos, true);
+#endif
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTCritSectRwEnterExcl(PRTCRITSECTRW pThis)
+{
+#ifndef RTCRITSECTRW_STRICT
+ return rtCritSectRwEnterExcl(pThis, NULL, false /*fTryAgain*/);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtCritSectRwEnterExcl(pThis, &SrcPos, false /*fTryAgain*/);
+#endif
+}
+RT_EXPORT_SYMBOL(RTCritSectRwEnterExcl);
+
+
+RTDECL(int) RTCritSectRwEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtCritSectRwEnterExcl(pThis, &SrcPos, false /*fTryAgain*/);
+}
+RT_EXPORT_SYMBOL(RTCritSectRwEnterExclDebug);
+
+
+RTDECL(int) RTCritSectRwTryEnterExcl(PRTCRITSECTRW pThis)
+{
+#ifndef RTCRITSECTRW_STRICT
+ return rtCritSectRwEnterExcl(pThis, NULL, true /*fTryAgain*/);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtCritSectRwEnterExcl(pThis, &SrcPos, true /*fTryAgain*/);
+#endif
+}
+RT_EXPORT_SYMBOL(RTCritSectRwTryEnterExcl);
+
+
+RTDECL(int) RTCritSectRwTryEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtCritSectRwEnterExcl(pThis, &SrcPos, true /*fTryAgain*/);
+}
+RT_EXPORT_SYMBOL(RTCritSectRwTryEnterExclDebug);
+
+
+RTDECL(int) RTCritSectRwLeaveExcl(PRTCRITSECTRW pThis)
+{
+ /*
+ * Validate handle.
+ */
+ AssertPtr(pThis);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
+
+ RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
+ RTNATIVETHREAD hNativeWriter;
+ ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
+ AssertReturn(hNativeSelf == hNativeWriter, VERR_NOT_OWNER);
+
+ /*
+ * Unwind a recursion.
+ */
+ if (pThis->cWriteRecursions == 1)
+ {
+ AssertReturn(pThis->cWriterReads == 0, VERR_WRONG_ORDER); /* (must release all read recursions before the final write.) */
+#ifdef RTCRITSECTRW_STRICT
+ int rc9 = RTLockValidatorRecExclReleaseOwner(pThis->pValidatorWrite, true);
+ if (RT_FAILURE(rc9))
+ return rc9;
+#endif
+ /*
+ * Update the state.
+ */
+ ASMAtomicWriteU32(&pThis->cWriteRecursions, 0);
+ ASMAtomicWriteHandle(&pThis->hNativeWriter, NIL_RTNATIVETHREAD);
+
+ for (;;)
+ {
+ uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
+ uint64_t u64OldState = u64State;
+
+ uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT;
+ Assert(c > 0);
+ c--;
+
+ if ( c > 0
+ || (u64State & RTCSRW_CNT_RD_MASK) == 0)
+ {
+ /* Don't change the direction, wait up the next writer if any. */
+ u64State &= ~RTCSRW_CNT_WR_MASK;
+ u64State |= c << RTCSRW_CNT_WR_SHIFT;
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ {
+ if (c > 0)
+ {
+ int rc = RTSemEventSignal(pThis->hEvtWrite);
+ AssertRC(rc);
+ }
+ break;
+ }
+ }
+ else
+ {
+ /* Reverse the direction and signal the reader threads. */
+ u64State &= ~(RTCSRW_CNT_WR_MASK | RTCSRW_DIR_MASK);
+ u64State |= RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT;
+ if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
+ {
+ Assert(!pThis->fNeedReset);
+ ASMAtomicWriteBool(&pThis->fNeedReset, true);
+ int rc = RTSemEventMultiSignal(pThis->hEvtRead);
+ AssertRC(rc);
+ break;
+ }
+ }
+
+ ASMNopPause();
+ if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
+ return VERR_SEM_DESTROYED;
+ }
+ }
+ else
+ {
+ Assert(pThis->cWriteRecursions != 0);
+#ifdef RTCRITSECTRW_STRICT
+ int rc9 = RTLockValidatorRecExclUnwind(pThis->pValidatorWrite);
+ if (RT_FAILURE(rc9))
+ return rc9;
+#endif
+ ASMAtomicDecU32(&pThis->cWriteRecursions);
+ }
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTCritSectRwLeaveExcl);
+
+
+RTDECL(bool) RTCritSectRwIsWriteOwner(PRTCRITSECTRW pThis)
+{
+ /*
+ * Validate handle.
+ */
+ AssertPtr(pThis);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, false);
+
+ /*
+ * Check ownership.
+ */
+ RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
+ RTNATIVETHREAD hNativeWriter;
+ ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
+ return hNativeWriter == hNativeSelf;
+}
+RT_EXPORT_SYMBOL(RTCritSectRwIsWriteOwner);
+
+
+RTDECL(bool) RTCritSectRwIsReadOwner(PRTCRITSECTRW pThis, bool fWannaHear)
+{
+ /*
+ * Validate handle.
+ */
+ AssertPtr(pThis);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, false);
+
+ /*
+ * Inspect the state.
+ */
+ uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
+ if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT))
+ {
+ /*
+ * It's in write mode, so we can only be a reader if we're also the
+ * current writer.
+ */
+ RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
+ RTNATIVETHREAD hWriter;
+ ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hWriter);
+ return hWriter == hNativeSelf;
+ }
+
+ /*
+ * Read mode. If there are no current readers, then we cannot be a reader.
+ */
+ if (!(u64State & RTCSRW_CNT_RD_MASK))
+ return false;
+
+#ifdef RTCRITSECTRW_STRICT
+ /*
+ * Ask the lock validator.
+ */
+ return RTLockValidatorRecSharedIsOwner(pThis->pValidatorRead, NIL_RTTHREAD);
+#else
+ /*
+ * Ok, we don't know, just tell the caller what he want to hear.
+ */
+ return fWannaHear;
+#endif
+}
+RT_EXPORT_SYMBOL(RTCritSectRwIsReadOwner);
+
+
+RTDECL(uint32_t) RTCritSectRwGetWriteRecursion(PRTCRITSECTRW pThis)
+{
+ /*
+ * Validate handle.
+ */
+ AssertPtr(pThis);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, 0);
+
+ /*
+ * Return the requested data.
+ */
+ return pThis->cWriteRecursions;
+}
+RT_EXPORT_SYMBOL(RTCritSectRwGetWriteRecursion);
+
+
+RTDECL(uint32_t) RTCritSectRwGetWriterReadRecursion(PRTCRITSECTRW pThis)
+{
+ /*
+ * Validate handle.
+ */
+ AssertPtr(pThis);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, 0);
+
+ /*
+ * Return the requested data.
+ */
+ return pThis->cWriterReads;
+}
+RT_EXPORT_SYMBOL(RTCritSectRwGetWriterReadRecursion);
+
+
+RTDECL(uint32_t) RTCritSectRwGetReadCount(PRTCRITSECTRW pThis)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtr(pThis);
+ AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, 0);
+
+ /*
+ * Return the requested data.
+ */
+ uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
+ if ((u64State & RTCSRW_DIR_MASK) != (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
+ return 0;
+ return (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
+}
+RT_EXPORT_SYMBOL(RTCritSectRwGetReadCount);
+
+
+RTDECL(int) RTCritSectRwDelete(PRTCRITSECTRW pThis)
+{
+ /*
+ * Assert free waiters and so on.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->u32Magic == RTCRITSECTRW_MAGIC);
+ //Assert(pThis->cNestings == 0);
+ //Assert(pThis->cLockers == -1);
+ Assert(pThis->hNativeWriter == NIL_RTNATIVETHREAD);
+
+ /*
+ * Invalidate the structure and free the semaphores.
+ */
+ if (!ASMAtomicCmpXchgU32(&pThis->u32Magic, RTCRITSECTRW_MAGIC_DEAD, RTCRITSECTRW_MAGIC))
+ return VERR_INVALID_PARAMETER;
+
+ pThis->fFlags = 0;
+ pThis->u64State = 0;
+
+ RTSEMEVENT hEvtWrite = pThis->hEvtWrite;
+ pThis->hEvtWrite = NIL_RTSEMEVENT;
+ RTSEMEVENTMULTI hEvtRead = pThis->hEvtRead;
+ pThis->hEvtRead = NIL_RTSEMEVENTMULTI;
+
+ int rc1 = RTSemEventDestroy(hEvtWrite); AssertRC(rc1);
+ int rc2 = RTSemEventMultiDestroy(hEvtRead); AssertRC(rc2);
+
+ RTLockValidatorRecSharedDestroy(&pThis->pValidatorRead);
+ RTLockValidatorRecExclDestroy(&pThis->pValidatorWrite);
+
+ return RT_SUCCESS(rc1) ? rc2 : rc1;
+}
+RT_EXPORT_SYMBOL(RTCritSectRwDelete);
+
diff --git a/src/VBox/Runtime/generic/env-generic.cpp b/src/VBox/Runtime/generic/env-generic.cpp
index c4de0471..0d9a13b9 100644
--- a/src/VBox/Runtime/generic/env-generic.cpp
+++ b/src/VBox/Runtime/generic/env-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -56,11 +56,27 @@ RT_C_DECLS_END
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
+/** The allocation granularity of the RTENVINTERNAL::papszEnv memory. */
+#define RTENV_GROW_SIZE 16
+
/** Macro that unlocks the specified environment block. */
#define RTENV_LOCK(pEnvInt) do { } while (0)
/** Macro that unlocks the specified environment block. */
#define RTENV_UNLOCK(pEnvInt) do { } while (0)
+/** @def RTENV_HAVE_WENVIRON
+ * Indicates that we have a _wenviron variable with UTF-16 strings that we
+ * better use instead of the current-cp strings in environ. */
+#if defined(RT_OS_WINDOWS) || defined(DOXYGEN_RUNNING)
+# define RTENV_HAVE_WENVIRON 1
+#endif
+
+/** @def RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API
+ * Indicates the RTEnv*Utf8 APIs are implemented. */
+#if defined(RT_OS_WINDOWS) || defined(DOXYGEN_RUNNING)
+# define RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API 1
+#endif
+
/*******************************************************************************
* Structures and Typedefs *
@@ -84,10 +100,10 @@ typedef struct RTENVINTERNAL
/** Array of environment variables in the process CP.
* This get (re-)constructed when RTEnvGetExecEnvP method is called. */
char **papszEnvOtherCP;
-} RTENVINTERNAL, *PRTENVINTERNAL;
-/** The allocation granularity of the RTENVINTERNAL::papszEnv memory. */
-#define RTENV_GROW_SIZE 16
+ /** The compare function we're using. */
+ DECLCALLBACKMEMBER(int, pfnCompare)(const char *psz1, const char *psz2, size_t cchMax);
+} RTENVINTERNAL, *PRTENVINTERNAL;
/**
@@ -101,9 +117,6 @@ static const char * const *rtEnvDefault(void)
{
#ifdef RT_OS_DARWIN
return *(_NSGetEnviron());
-#elif defined(RT_OS_L4)
- /* So far, our L4 libraries do not include environment support. */
- return NULL;
#else
return environ;
#endif
@@ -114,10 +127,12 @@ static const char * const *rtEnvDefault(void)
* Internal worker that creates an environment handle with a specified capacity.
*
* @returns IPRT status code.
- * @param ppIntEnv Where to store the result.
- * @param cAllocated The initial array size.
+ * @param ppIntEnv Where to store the result.
+ * @param cAllocated The initial array size.
+ * @param fCaseSensitive Whether the environment block is case sensitive or
+ * not.
*/
-static int rtEnvCreate(PRTENVINTERNAL *ppIntEnv, size_t cAllocated)
+static int rtEnvCreate(PRTENVINTERNAL *ppIntEnv, size_t cAllocated, bool fCaseSensitive)
{
/*
* Allocate environment handle.
@@ -129,6 +144,7 @@ static int rtEnvCreate(PRTENVINTERNAL *ppIntEnv, size_t cAllocated)
* Pre-allocate the variable array.
*/
pIntEnv->u32Magic = RTENV_MAGIC;
+ pIntEnv->pfnCompare = fCaseSensitive ? RTStrNCmp : RTStrNICmp;
pIntEnv->papszEnvOtherCP = NULL;
pIntEnv->cVars = 0;
pIntEnv->cAllocated = RT_ALIGN_Z(RT_MAX(cAllocated, RTENV_GROW_SIZE), RTENV_GROW_SIZE);
@@ -149,7 +165,7 @@ static int rtEnvCreate(PRTENVINTERNAL *ppIntEnv, size_t cAllocated)
RTDECL(int) RTEnvCreate(PRTENV pEnv)
{
AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
- return rtEnvCreate(pEnv, RTENV_GROW_SIZE);
+ return rtEnvCreate(pEnv, RTENV_GROW_SIZE, false /*fCaseSensitive*/);
}
RT_EXPORT_SYMBOL(RTEnvCreate);
@@ -203,18 +219,41 @@ RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone)
/*
* Validate input and figure out how many variable to clone and where to get them.
*/
+ bool fCaseSensitive = true;
size_t cVars;
const char * const *papszEnv;
+#ifdef RTENV_HAVE_WENVIRON
+ PCRTUTF16 const * papwszEnv;
+#endif
PRTENVINTERNAL pIntEnvToClone;
AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
if (EnvToClone == RTENV_DEFAULT)
{
+ cVars = 0;
pIntEnvToClone = NULL;
+#ifdef RTENV_HAVE_WENVIRON
+ papszEnv = NULL;
+ papwszEnv = (PCRTUTF16 * const )_wenviron;
+ if (!papwszEnv)
+ {
+ _wgetenv(L"Path"); /* Force the CRT to initalize it. */
+ papwszEnv = (PCRTUTF16 * const)_wenviron;
+ }
+ if (papwszEnv)
+ while (papwszEnv[cVars])
+ cVars++;
+#else
papszEnv = rtEnvDefault();
- cVars = 0;
if (papszEnv)
while (papszEnv[cVars])
cVars++;
+#endif
+
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+ /* DOS systems was case insensitive. A prime example is the 'Path'
+ variable on windows which turns into the 'PATH' variable. */
+ fCaseSensitive = false;
+#endif
}
else
{
@@ -231,7 +270,7 @@ RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone)
* Create the duplicate.
*/
PRTENVINTERNAL pIntEnv;
- int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */);
+ int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */, fCaseSensitive);
if (RT_SUCCESS(rc))
{
pIntEnv->cVars = cVars;
@@ -242,7 +281,11 @@ RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone)
size_t iDst = 0;
for (size_t iSrc = 0; iSrc < cVars; iSrc++)
{
+#ifdef RTENV_HAVE_WENVIRON
+ int rc2 = RTUtf16ToUtf8(papwszEnv[iSrc], &pIntEnv->papszEnv[iDst]);
+#else
int rc2 = RTStrCurrentCPToUtf8(&pIntEnv->papszEnv[iDst], papszEnv[iSrc]);
+#endif
if (RT_SUCCESS(rc2))
iDst++;
else if (rc2 == VERR_NO_TRANSLATION)
@@ -321,6 +364,9 @@ RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue)
int rc;
if (Env == RTENV_DEFAULT)
{
+#ifdef RT_OS_WINDOWS
+ rc = RTEnvSetUtf8(pszVar, pszValue);
+#else
/*
* Since RTEnvPut isn't UTF-8 clean and actually expects the strings
* to be in the current code page (codeset), we'll do the necessary
@@ -339,6 +385,7 @@ RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue)
}
RTStrFree(pszVarOtherCP);
}
+#endif
}
else
{
@@ -366,7 +413,7 @@ RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue)
rc = VINF_SUCCESS;
size_t iVar;
for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
- if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
+ if ( !pIntEnv->pfnCompare(pIntEnv->papszEnv[iVar], pszVar, cchVar)
&& pIntEnv->papszEnv[iVar][cchVar] == '=')
break;
if (iVar < pIntEnv->cVars)
@@ -426,6 +473,9 @@ RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar)
int rc;
if (Env == RTENV_DEFAULT)
{
+#ifdef RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API
+ rc = RTEnvUnsetUtf8(pszVar);
+#else
/*
* Since RTEnvUnset isn't UTF-8 clean and actually expects the strings
* to be in the current code page (codeset), we'll do the necessary
@@ -438,6 +488,7 @@ RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar)
rc = RTEnvUnset(pszVarOtherCP);
RTStrFree(pszVarOtherCP);
}
+#endif
}
else
{
@@ -454,7 +505,7 @@ RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar)
const size_t cchVar = strlen(pszVar);
size_t iVar;
for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
- if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
+ if ( !pIntEnv->pfnCompare(pIntEnv->papszEnv[iVar], pszVar, cchVar)
&& pIntEnv->papszEnv[iVar][cchVar] == '=')
{
RTMemFree(pIntEnv->papszEnv[iVar]);
@@ -486,6 +537,9 @@ RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbV
int rc;
if (Env == RTENV_DEFAULT)
{
+#ifdef RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API
+ rc = RTEnvGetUtf8(pszVar, pszValue, cbValue, pcchActual);
+#else
/*
* Since RTEnvGet isn't UTF-8 clean and actually expects the strings
* to be in the current code page (codeset), we'll do the necessary
@@ -520,6 +574,7 @@ RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbV
else
rc = VERR_ENV_VAR_NOT_FOUND;
}
+#endif
}
else
{
@@ -536,7 +591,7 @@ RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbV
const size_t cchVar = strlen(pszVar);
size_t iVar;
for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
- if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
+ if ( !pIntEnv->pfnCompare(pIntEnv->papszEnv[iVar], pszVar, cchVar)
&& pIntEnv->papszEnv[iVar][cchVar] == '=')
{
rc = VINF_SUCCESS;
@@ -557,7 +612,6 @@ RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbV
RTENV_UNLOCK(pIntEnv);
}
return rc;
-
}
RT_EXPORT_SYMBOL(RTEnvGetEx);
@@ -566,9 +620,12 @@ RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar)
{
AssertPtrReturn(pszVar, false);
- bool fExist = false;
+ bool fExists = false;
if (Env == RTENV_DEFAULT)
{
+#ifdef RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API
+ fExists = RTEnvExistsUtf8(pszVar);
+#else
/*
* Since RTEnvExist isn't UTF-8 clean and actually expects the strings
* to be in the current code page (codeset), we'll do the necessary
@@ -578,9 +635,10 @@ RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar)
int rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
if (RT_SUCCESS(rc))
{
- fExist = RTEnvExist(pszVarOtherCP);
+ fExists = RTEnvExist(pszVarOtherCP);
RTStrFree(pszVarOtherCP);
}
+#endif
}
else
{
@@ -595,16 +653,16 @@ RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar)
*/
const size_t cchVar = strlen(pszVar);
for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
- if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
+ if ( !pIntEnv->pfnCompare(pIntEnv->papszEnv[iVar], pszVar, cchVar)
&& pIntEnv->papszEnv[iVar][cchVar] == '=')
{
- fExist = true;
+ fExists = true;
break;
}
RTENV_UNLOCK(pIntEnv);
}
- return fExist;
+ return fExists;
}
RT_EXPORT_SYMBOL(RTEnvExistEx);
@@ -614,6 +672,7 @@ RTDECL(char const * const *) RTEnvGetExecEnvP(RTENV Env)
const char * const *papszRet;
if (Env == RTENV_DEFAULT)
{
+ /** @todo fix this API it's fundamentally wrong! */
papszRet = rtEnvDefault();
if (!papszRet)
{
diff --git a/src/VBox/Runtime/generic/fs-stubs-generic.cpp b/src/VBox/Runtime/generic/fs-stubs-generic.cpp
index 4d4403ad..9f07d41a 100644
--- a/src/VBox/Runtime/generic/fs-stubs-generic.cpp
+++ b/src/VBox/Runtime/generic/fs-stubs-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/mempool-generic.cpp b/src/VBox/Runtime/generic/mempool-generic.cpp
index 3ec82610..d9bdf357 100644
--- a/src/VBox/Runtime/generic/mempool-generic.cpp
+++ b/src/VBox/Runtime/generic/mempool-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/mppresent-generic.cpp b/src/VBox/Runtime/generic/mppresent-generic.cpp
index 2d345f77..2915a656 100644
--- a/src/VBox/Runtime/generic/mppresent-generic.cpp
+++ b/src/VBox/Runtime/generic/mppresent-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -46,6 +46,13 @@ RTDECL(RTCPUID) RTMpGetPresentCount(void)
RT_EXPORT_SYMBOL(RTMpGetPresentCount);
+RTDECL(RTCPUID) RTMpGetPresentCoreCount(void)
+{
+ return RTMpGetCoreCount();
+}
+RT_EXPORT_SYMBOL(RTMpGetPresentCoreCount);
+
+
RTDECL(bool) RTMpIsCpuPresent(RTCPUID idCpu)
{
return RTMpIsCpuPossible(idCpu);
diff --git a/src/VBox/Runtime/generic/sched-generic.cpp b/src/VBox/Runtime/generic/sched-generic.cpp
index f272b4d7..fb5cd97c 100644
--- a/src/VBox/Runtime/generic/sched-generic.cpp
+++ b/src/VBox/Runtime/generic/sched-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/semfastmutex-generic.cpp b/src/VBox/Runtime/generic/semfastmutex-generic.cpp
index 69de1410..299162f2 100644
--- a/src/VBox/Runtime/generic/semfastmutex-generic.cpp
+++ b/src/VBox/Runtime/generic/semfastmutex-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/semrw-generic.cpp b/src/VBox/Runtime/generic/semrw-generic.cpp
index 929c14e3..9078619e 100644
--- a/src/VBox/Runtime/generic/semrw-generic.cpp
+++ b/src/VBox/Runtime/generic/semrw-generic.cpp
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/semrw-lockless-generic.cpp b/src/VBox/Runtime/generic/semrw-lockless-generic.cpp
index 3da9d6fe..27a37c06 100644
--- a/src/VBox/Runtime/generic/semrw-lockless-generic.cpp
+++ b/src/VBox/Runtime/generic/semrw-lockless-generic.cpp
@@ -1,10 +1,10 @@
/* $Id: semrw-lockless-generic.cpp $ */
/** @file
- * IPRT Testcase - RTSemXRoads, generic implementation.
+ * IPRT - Read-Write Semaphore, Generic, lockless variant.
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -51,8 +51,10 @@ typedef struct RTSEMRWINTERNAL
{
/** Magic value (RTSEMRW_MAGIC). */
uint32_t volatile u32Magic;
- uint32_t u32Padding; /**< alignment padding.*/
- /* The state variable.
+ /** Indicates whether hEvtRead needs resetting. */
+ bool volatile fNeedReset;
+
+ /** The state variable.
* All accesses are atomic and it bits are defined like this:
* Bits 0..14 - cReads.
* Bit 15 - Unused.
@@ -68,7 +70,8 @@ typedef struct RTSEMRWINTERNAL
RTNATIVETHREAD volatile hNativeWriter;
/** The number of reads made by the current writer. */
uint32_t volatile cWriterReads;
- /** The number of reads made by the current writer. */
+ /** The number of recursions made by the current writer. (The initial grabbing
+ * of the lock counts as the first one.) */
uint32_t volatile cWriteRecursions;
/** What the writer threads are blocking on. */
@@ -76,8 +79,6 @@ typedef struct RTSEMRWINTERNAL
/** What the read threads are blocking on when waiting for the writer to
* finish. */
RTSEMEVENTMULTI hEvtRead;
- /** Indicates whether hEvtRead needs resetting. */
- bool volatile fNeedReset;
#ifdef RTSEMRW_STRICT
/** The validator record for the writer. */
@@ -494,7 +495,7 @@ RTDECL(int) RTSemRWReleaseRead(RTSEMRW hRWSem)
c--;
if ( c > 0
- || (u64State & RTSEMRW_CNT_RD_MASK) == 0)
+ || (u64State & RTSEMRW_CNT_WD_MASK) == 0)
{
/* Don't change the direction. */
u64State &= ~RTSEMRW_CNT_RD_MASK;
@@ -888,7 +889,7 @@ RTDECL(bool) RTSemRWIsReadOwner(RTSEMRW hRWSem, bool fWannaHear)
*/
RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
RTNATIVETHREAD hWriter;
- ASMAtomicUoReadHandle(&pThis->hWriter, &hWriter);
+ ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hWriter);
return hWriter == hNativeSelf;
}
diff --git a/src/VBox/Runtime/generic/semxroads-generic.cpp b/src/VBox/Runtime/generic/semxroads-generic.cpp
index 55f9670a..6e3ea2eb 100644
--- a/src/VBox/Runtime/generic/semxroads-generic.cpp
+++ b/src/VBox/Runtime/generic/semxroads-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/strcache-stubs-generic.cpp b/src/VBox/Runtime/generic/strcache-stubs-generic.cpp
index 0b358a46..71bf5c12 100644
--- a/src/VBox/Runtime/generic/strcache-stubs-generic.cpp
+++ b/src/VBox/Runtime/generic/strcache-stubs-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -77,6 +77,27 @@ RTDECL(const char *) RTStrCacheEnter(RTSTRCACHE hStrCache, const char *psz)
RT_EXPORT_SYMBOL(RTStrCacheEnter);
+RTDECL(const char *) RTStrCacheEnterLowerN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString)
+{
+ AssertPtr(pchString);
+ AssertReturn(cchString < _1G, NULL);
+ Assert(!RTStrEnd(pchString, cchString));
+
+ char *pszRet = (char *)RTMemPoolDupEx((RTMEMPOOL)hStrCache, pchString, cchString, 1);
+ if (pszRet)
+ RTStrToLower(pszRet);
+ return pszRet;
+}
+RT_EXPORT_SYMBOL(RTStrCacheEnterLowerN);
+
+
+RTDECL(const char *) RTStrCacheEnterLower(RTSTRCACHE hStrCache, const char *psz)
+{
+ return RTStrCacheEnterLowerN(hStrCache, psz, strlen(psz));
+}
+RT_EXPORT_SYMBOL(RTStrCacheEnterLower);
+
+
RTDECL(uint32_t) RTStrCacheRetain(const char *psz)
{
AssertPtr(psz);
@@ -102,3 +123,19 @@ RTDECL(size_t) RTStrCacheLength(const char *psz)
}
RT_EXPORT_SYMBOL(RTStrCacheLength);
+
+RTDECL(bool) RTStrCacheIsRealImpl(void)
+{
+ return false;
+}
+RT_EXPORT_SYMBOL(RTStrCacheIsRealImpl);
+
+
+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)
+{
+ return UINT32_MAX;
+}
+RT_EXPORT_SYMBOL(RTStrCacheGetStats);
+
diff --git a/src/VBox/Runtime/generic/timer-generic.cpp b/src/VBox/Runtime/generic/timer-generic.cpp
index ab409c02..8e4c3270 100644
--- a/src/VBox/Runtime/generic/timer-generic.cpp
+++ b/src/VBox/Runtime/generic/timer-generic.cpp
@@ -116,7 +116,7 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
int rc = RTSemEventCreate(&pTimer->Event);
if (RT_SUCCESS(rc))
{
- rc = RTThreadCreate(&pTimer->Thread, rtTimerThread, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "TIMER");
+ rc = RTThreadCreate(&pTimer->Thread, rtTimerThread, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "Timer");
if (RT_SUCCESS(rc))
{
*ppTimer = pTimer;
@@ -256,18 +256,15 @@ static DECLCALLBACK(int) rtTimerThread(RTTHREAD hThreadSelf, void *pvUser)
if (u64NanoTS >= pTimer->u64NextTS)
{
pTimer->iTick++;
- pTimer->pfnTimer(pTimer, pTimer->pvUser, pTimer->iTick);
-
- /* status changed? */
- if (pTimer->fSuspended || pTimer->fDestroyed)
- continue;
/* one shot? */
if (!pTimer->u64NanoInterval)
- {
ASMAtomicXchgU8(&pTimer->fSuspended, true);
+ pTimer->pfnTimer(pTimer, pTimer->pvUser, pTimer->iTick);
+
+ /* status changed? */
+ if (pTimer->fSuspended || pTimer->fDestroyed)
continue;
- }
/* calc the next time we should fire. */
pTimer->u64NextTS = pTimer->u64StartTS + pTimer->iTick * pTimer->u64NanoInterval;
diff --git a/src/VBox/Runtime/generic/timerlr-generic.cpp b/src/VBox/Runtime/generic/timerlr-generic.cpp
index fa46ac78..9f320a88 100644
--- a/src/VBox/Runtime/generic/timerlr-generic.cpp
+++ b/src/VBox/Runtime/generic/timerlr-generic.cpp
@@ -122,7 +122,7 @@ RTDECL(int) RTTimerLRCreateEx(RTTIMERLR *phTimerLR, uint64_t u64NanoInterval, ui
int rc = RTSemEventCreate(&pThis->hEvent);
if (RT_SUCCESS(rc))
{
- rc = RTThreadCreate(&pThis->hThread, rtTimerLRThread, pThis, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "TIMER");
+ rc = RTThreadCreate(&pThis->hThread, rtTimerLRThread, pThis, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "TimerLR");
if (RT_SUCCESS(rc))
{
*phTimerLR = pThis;
diff --git a/src/VBox/Runtime/generic/tls-generic.cpp b/src/VBox/Runtime/generic/tls-generic.cpp
index 7729c77a..cbcbe4b6 100644
--- a/src/VBox/Runtime/generic/tls-generic.cpp
+++ b/src/VBox/Runtime/generic/tls-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/utf16locale-generic.cpp b/src/VBox/Runtime/generic/utf16locale-generic.cpp
index b75ec9d1..7f9f4439 100644
--- a/src/VBox/Runtime/generic/utf16locale-generic.cpp
+++ b/src/VBox/Runtime/generic/utf16locale-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/generic/uuid-generic.cpp b/src/VBox/Runtime/generic/uuid-generic.cpp
index 0b4b17dd..c6df68fd 100644
--- a/src/VBox/Runtime/generic/uuid-generic.cpp
+++ b/src/VBox/Runtime/generic/uuid-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/alignmentchecks.h b/src/VBox/Runtime/include/internal/alignmentchecks.h
index 96e96e88..38f69153 100644
--- a/src/VBox/Runtime/include/internal/alignmentchecks.h
+++ b/src/VBox/Runtime/include/internal/alignmentchecks.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/assert.h b/src/VBox/Runtime/include/internal/assert.h
index ef6334a6..0db64e04 100644
--- a/src/VBox/Runtime/include/internal/assert.h
+++ b/src/VBox/Runtime/include/internal/assert.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/dbgmod.h b/src/VBox/Runtime/include/internal/dbgmod.h
index 577da5c0..2d06044d 100644
--- a/src/VBox/Runtime/include/internal/dbgmod.h
+++ b/src/VBox/Runtime/include/internal/dbgmod.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2011 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -74,8 +74,9 @@ typedef struct RTDBGMODVTIMG
*
* Upon successful return the method is expected to
* initialize pImgOps and pvImgPriv.
+ * @param enmArch The desired architecture.
*/
- DECLCALLBACKMEMBER(int, pfnTryOpen)(PRTDBGMODINT pMod);
+ DECLCALLBACKMEMBER(int, pfnTryOpen)(PRTDBGMODINT pMod, RTLDRARCH enmArch);
/**
* Close the interpreter, freeing all associated resources.
@@ -116,6 +117,21 @@ typedef struct RTDBGMODVTIMG
DECLCALLBACKMEMBER(int, pfnEnumSegments)(PRTDBGMODINT pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser);
/**
+ * Enumerates the symbols exported by the module.
+ *
+ * @returns iprt status code, which might have been returned by pfnCallback.
+ * @param pMod Pointer to the module structure.
+ * @param fFlags Flags indicating what to return and such.
+ * @param BaseAddress The image base addressto use when calculating the
+ * symbol values.
+ * @param pfnCallback The callback function which each symbol is to be fed
+ * to.
+ * @param pvUser User argument to pass to the enumerator.
+ */
+ DECLCALLBACKMEMBER(int, pfnEnumSymbols)(PRTDBGMODINT pMod, uint32_t fFlags, RTLDRADDR BaseAddress,
+ PFNRTLDRENUMSYMS pfnCallback, void *pvUser);
+
+ /**
* Gets the size of the loaded image.
*
* Identical to RTLdrSize.
@@ -140,16 +156,33 @@ typedef struct RTDBGMODVTIMG
PRTDBGSEGIDX piSeg, PRTLDRADDR poffSeg);
/**
+ * Converts an image relative virtual address to a segment:offset.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pMod Pointer to the loader module structure.
+ * @param Rva The RVA to convert.
+ * @param piSeg The segment index.
+ * @param poffSeg Where to return the segment offset.
+ */
+ DECLCALLBACKMEMBER(int, pfnRvaToSegOffset)(PRTDBGMODINT pMod, RTLDRADDR Rva, uint32_t *piSeg, PRTLDRADDR poffSeg);
+
+ /**
* Creates a read-only mapping of a part of the image file.
*
* @returns IPRT status code and *ppvMap set on success.
*
* @param pMod Pointer to the module structure.
+ * @param iDbgInfo The debug info ordinal number if the request
+ * corresponds exactly to a debug info part from
+ * pfnEnumDbgInfo. Otherwise, pass UINT32_MAX.
* @param off The offset into the image file.
* @param cb The number of bytes to map.
* @param ppvMap Where to return the mapping address on success.
+ *
+ * @remarks Fixups will only be applied if @a iDbgInfo is specified.
*/
- DECLCALLBACKMEMBER(int, pfnMapPart)(PRTDBGMODINT pMod, RTFOFF off, size_t cb, void const **ppvMap);
+ DECLCALLBACKMEMBER(int, pfnMapPart)(PRTDBGMODINT pMod, uint32_t iDbgInfo, RTFOFF off, size_t cb, void const **ppvMap);
/**
* Unmaps memory previously mapped by pfnMapPart.
@@ -163,6 +196,36 @@ typedef struct RTDBGMODVTIMG
*/
DECLCALLBACKMEMBER(int, pfnUnmapPart)(PRTDBGMODINT pMod, size_t cb, void const **ppvMap);
+ /**
+ * Reads data from the image file.
+ *
+ * @returns IPRT status code, *ppvMap set to NULL on success.
+ *
+ * @param pMod Pointer to the module structure.
+ * @param iDbgInfoHint The debug info ordinal number hint, pass UINT32_MAX
+ * if not know or sure.
+ * @param off The offset into the image file.
+ * @param pvBuf The buffer to read into.
+ * @param cb The number of bytes to read.
+ */
+ DECLCALLBACKMEMBER(int, pfnReadAt)(PRTDBGMODINT pMod, uint32_t iDbgInfoHint, RTFOFF off, void *pvBuf, size_t cb);
+
+ /**
+ * Gets the image format.
+ *
+ * @returns Valid image format on success, RTLDRFMT_INVALID if not supported.
+ * @param pMod Pointer to the module structure.
+ */
+ DECLCALLBACKMEMBER(RTLDRFMT, pfnGetFormat)(PRTDBGMODINT pMod);
+
+ /**
+ * Gets the image architecture.
+ *
+ * @returns Valid image architecutre on success, RTLDRARCH_WHATEVER if not
+ * supported.
+ * @param pMod Pointer to the module structure.
+ */
+ DECLCALLBACKMEMBER(RTLDRARCH, pfnGetArch)(PRTDBGMODINT pMod);
/** For catching initialization errors (RTDBGMODVTIMG_MAGIC). */
uint32_t u32EndMagic;
@@ -203,8 +266,9 @@ typedef struct RTDBGMODVTDBG
*
* Upon successful return the method is expected to
* initialize pDbgOps and pvDbgPriv.
+ * @param enmArch The desired architecture.
*/
- DECLCALLBACKMEMBER(int, pfnTryOpen)(PRTDBGMODINT pMod);
+ DECLCALLBACKMEMBER(int, pfnTryOpen)(PRTDBGMODINT pMod, RTLDRARCH enmArch);
/**
* Close the interpreter, freeing all associated resources.
@@ -443,6 +507,64 @@ typedef RTDBGMODVTDBG const *PCRTDBGMODVTDBG;
/**
+ * Deferred loading callback.
+ *
+ * @returns IPRT status code. On success the necessary method tables should be
+ * installed in @a pMod.
+ * @param pMod Pointer to the debug module structure.
+ * @param pDeferred The deferred load data.
+ */
+typedef DECLCALLBACK(int) FNRTDBGMODDEFERRED(PRTDBGMODINT pMod, struct RTDBGMODDEFERRED *pDeferred);
+/** Pointer to a deferred loading callback. */
+typedef FNRTDBGMODDEFERRED *PFNRTDBGMODDEFERRED;
+
+
+/**
+ * Structure pointed to by pvDbgPriv and/or pvImgPriv when
+ * g_rtDbgModVtDbgDeferred and/or g_rtDbgModVtImgDeferred are being used.
+ */
+typedef struct RTDBGMODDEFERRED
+{
+ /** The image size.
+ * Deferred loading is almost pointless without knowing the module size, as
+ * it cannot be mapped (correctly) without it. */
+ RTUINTPTR cbImage;
+ /** Reference counter. */
+ uint32_t volatile cRefs;
+ /** The configuration instance (referenced), can be NIL. */
+ RTDBGCFG hDbgCfg;
+ /** Performs deferred loading of the module. */
+ PFNRTDBGMODDEFERRED pfnDeferred;
+ /** Callback specific data. */
+ union
+ {
+ struct
+ {
+ /** The time/date stamp of the executable image and codeview file. */
+ uint32_t uTimestamp;
+ } PeImage,
+ OldCodeView;
+
+ struct
+ {
+ /** The PDB uuid. */
+ RTUUID Uuid;
+ /** The PDB age. */
+ uint32_t uAge;
+ } NewCodeview;
+
+ struct
+ {
+ /** The CRC-32 value found in the .gnu_debuglink section. */
+ uint32_t uCrc32;
+ } GnuDebugLink;
+ } u;
+} RTDBGMODDEFERRED;
+/** Pointer to the deferred loading data. */
+typedef RTDBGMODDEFERRED *PRTDBGMODDEFERRED;
+
+
+/**
* Debug module structure.
*/
typedef struct RTDBGMODINT
@@ -454,16 +576,29 @@ typedef struct RTDBGMODINT
uint32_t volatile cRefs;
/** The module tag. */
uint64_t uTag;
+
+ /** When set, the loading of the image and debug info (including locating any
+ * external files), will not have taken place yet. */
+ uint32_t fDeferred : 1;
+ /** Set if deferred loading failed. */
+ uint32_t fDeferredFailed : 1;
+ /** Set if the debug info is based on image exports and segments. */
+ uint32_t fExports : 1;
+ /** Alignment padding. */
+ uint32_t fPadding1 : 29;
+#if ARCH_BITS == 64
+ uint32_t u32Padding2;
+#endif
+
/** The module name (short). */
char const *pszName;
+ /** The image file specified by the user. Can be NULL. */
+ char const *pszImgFileSpecified;
/** The module filename. Can be NULL. */
char const *pszImgFile;
/** The debug info file (if external). Can be NULL. */
char const *pszDbgFile;
- /** Critical section serializing access to the module. */
- RTCRITSECT CritSect;
-
/** The method table for the executable image interpreter. */
PCRTDBGMODVTIMG pImgVt;
/** Pointer to the private data of the executable image interpreter. */
@@ -474,17 +609,36 @@ typedef struct RTDBGMODINT
/** Pointer to the private data of the debug info interpreter. */
void *pvDbgPriv;
+ /** Critical section serializing access to the module. */
+ RTCRITSECT CritSect;
} RTDBGMODINT;
/** Pointer to an debug module structure. */
typedef RTDBGMODINT *PRTDBGMODINT;
extern DECLHIDDEN(RTSTRCACHE) g_hDbgModStrCache;
+extern DECLHIDDEN(RTDBGMODVTDBG const) g_rtDbgModVtDbgCodeView;
extern DECLHIDDEN(RTDBGMODVTDBG const) g_rtDbgModVtDbgDwarf;
extern DECLHIDDEN(RTDBGMODVTDBG const) g_rtDbgModVtDbgNm;
+#ifdef RT_OS_WINDOWS
+extern DECLHIDDEN(RTDBGMODVTDBG const) g_rtDbgModVtDbgDbgHelp;
+#endif
+extern DECLHIDDEN(RTDBGMODVTDBG const) g_rtDbgModVtDbgDeferred;
+extern DECLHIDDEN(RTDBGMODVTDBG const) g_rtDbgModVtDbgContainer;
+
extern DECLHIDDEN(RTDBGMODVTIMG const) g_rtDbgModVtImgLdr;
+extern DECLHIDDEN(RTDBGMODVTIMG const) g_rtDbgModVtImgDeferred;
+
+DECLHIDDEN(int) rtDbgModContainerCreate(PRTDBGMODINT pMod, RTUINTPTR cbSeg);
+DECLHIDDEN(int) rtDbgModContainer_SymbolRemoveAll(PRTDBGMODINT pMod);
+DECLHIDDEN(int) rtDbgModContainer_LineRemoveAll(PRTDBGMODINT pMod);
+DECLHIDDEN(int) rtDbgModContainer_RemoveAll(PRTDBGMODINT pMod);
+
+DECLHIDDEN(int) rtDbgModCreateForExports(PRTDBGMODINT pDbgMod);
+DECLHIDDEN(int) rtDbgModDeferredCreate(PRTDBGMODINT pDbgMod, PFNRTDBGMODDEFERRED pfnDeferred, RTUINTPTR cbImage,
+ RTDBGCFG hDbgCfg, PRTDBGMODDEFERRED *ppDeferred);
-int rtDbgModContainerCreate(PRTDBGMODINT pMod, RTUINTPTR cbSeg);
+DECLHIDDEN(int) rtDbgModLdrOpenFromHandle(PRTDBGMODINT pDbgMod, RTLDRMOD hLdrMod);
/** @} */
diff --git a/src/VBox/Runtime/include/internal/dir.h b/src/VBox/Runtime/include/internal/dir.h
index 987fe32a..8a85a1e6 100644
--- a/src/VBox/Runtime/include/internal/dir.h
+++ b/src/VBox/Runtime/include/internal/dir.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -83,23 +83,55 @@ typedef struct RTDIR
#endif
/** The length of the converted filename. */
size_t cchName;
+ /** The size of this structure. */
+ size_t cbSelf;
-#ifdef RT_OS_WINDOWS
+#ifndef RTDIR_AGNOSTIC
+# ifdef RT_OS_WINDOWS
/** Handle to the opened directory search. */
HANDLE hDir;
+# ifndef RT_USE_NATIVE_NT
/** Find data buffer.
* fDataUnread indicates valid data. */
WIN32_FIND_DATAW Data;
-
-#else /* 'POSIX': */
+# else
+ /** The size of the name buffer pszName points to. */
+ size_t cbNameAlloc;
+ /** NT filter string. */
+ UNICODE_STRING NtFilterStr;
+ /** Pointer to NtFilterStr if applicable, otherwise NULL. */
+ PUNICODE_STRING pNtFilterStr;
+ /** The information class we're using. */
+ FILE_INFORMATION_CLASS enmInfoClass;
+ /** Object directory context data. */
+ ULONG uObjDirCtx;
+ /** Pointer to the current data entry in the buffer. */
+ union
+ {
+ /** Both file names, no file ID. */
+ PFILE_BOTH_DIR_INFORMATION pBoth;
+ /** Both file names with file ID. */
+ PFILE_ID_BOTH_DIR_INFORMATION pBothId;
+ /** Object directory info. */
+ POBJECT_DIRECTORY_INFORMATION pObjDir;
+ /** Unsigned view. */
+ uintptr_t u;
+ } uCurData;
+ /** The amount of valid data in the buffer. */
+ uint32_t cbBuffer;
+ /** The allocate buffer size. */
+ uint32_t cbBufferAlloc;
+ /** Find data buffer containing multiple directory entries.
+ * fDataUnread indicates valid data. */
+ uint8_t *pabBuffer;
+# endif
+# else /* 'POSIX': */
/** What opendir() returned. */
DIR *pDir;
- /** The max size of the d_name member.
- * This includes the 0 terminator of course.*/
- size_t cbMaxName;
/** Find data buffer.
* fDataUnread indicates valid data. */
struct dirent Data;
+# endif
#endif
} RTDIR;
@@ -130,4 +162,12 @@ DECLINLINE(bool) rtDirValidHandle(PRTDIR pDir)
*/
int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf);
+/**
+ * Returns the size of the directory structure.
+ *
+ * @returns The size in bytes.
+ * @param pszPath The path to the directory we're about to open.
+ */
+size_t rtDirNativeGetStructSize(const char *pszPath);
+
#endif
diff --git a/src/VBox/Runtime/include/internal/dvm.h b/src/VBox/Runtime/include/internal/dvm.h
index 0970900b..1064a128 100644
--- a/src/VBox/Runtime/include/internal/dvm.h
+++ b/src/VBox/Runtime/include/internal/dvm.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/file.h b/src/VBox/Runtime/include/internal/file.h
index c8efe1b7..c6e0e15c 100644
--- a/src/VBox/Runtime/include/internal/file.h
+++ b/src/VBox/Runtime/include/internal/file.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/fileaio.h b/src/VBox/Runtime/include/internal/fileaio.h
index 81172acc..b5beb86d 100644
--- a/src/VBox/Runtime/include/internal/fileaio.h
+++ b/src/VBox/Runtime/include/internal/fileaio.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/fs.h b/src/VBox/Runtime/include/internal/fs.h
index f5ba0429..00af45a4 100644
--- a/src/VBox/Runtime/include/internal/fs.h
+++ b/src/VBox/Runtime/include/internal/fs.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/initterm.h b/src/VBox/Runtime/include/internal/initterm.h
index 04472903..a7eebd6f 100644
--- a/src/VBox/Runtime/include/internal/initterm.h
+++ b/src/VBox/Runtime/include/internal/initterm.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/iprt.h b/src/VBox/Runtime/include/internal/iprt.h
index e408958e..3cadf9de 100644
--- a/src/VBox/Runtime/include/internal/iprt.h
+++ b/src/VBox/Runtime/include/internal/iprt.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/ldr.h b/src/VBox/Runtime/include/internal/ldr.h
index f0c17eaa..9999827d 100644
--- a/src/VBox/Runtime/include/internal/ldr.h
+++ b/src/VBox/Runtime/include/internal/ldr.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -296,13 +296,31 @@ typedef struct RTLDROPS
* @returns IPRT status code.
*
* @param pMod Pointer to the loader module structure.
- * @param iSeg The segment index.
- * @param offSeg The segment offset.
- * @param pRva Where to return the RVA.
+ * @param Rva The RVA to convert.
+ * @param piSeg Where to return the segment index.
+ * @param poffSeg Where to return the segment offset.
* @remark This is an optional entry point that can be NULL.
*/
DECLCALLBACKMEMBER(int, pfnRvaToSegOffset)(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva, uint32_t *piSeg, PRTLDRADDR poffSeg);
+ /**
+ * Reads a debug info part (section) from the image.
+ *
+ * This is primarily needed for getting DWARF sections in ELF image with fixups
+ * applied and won't be required by most other loader backends.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pvBuf The buffer to read into.
+ * @param iDbgInfo The debug info ordinal number if the request
+ * corresponds exactly to a debug info part from
+ * pfnEnumDbgInfo. Otherwise, pass UINT32_MAX.
+ * @param off The offset into the image file.
+ * @param cb The number of bytes to read.
+ * @param pMod Pointer to the loader module structure.
+ */
+ DECLCALLBACKMEMBER(int, pfnReadDbgInfo)(PRTLDRMODINTERNAL pMod, uint32_t iDbgInfo, RTFOFF off, size_t cb, void *pvBuf);
+
/** Dummy entry to make sure we've initialized it all. */
RTUINT uDummy;
} RTLDROPS;
@@ -402,6 +420,16 @@ typedef struct RTLDRMODINTERNAL
RTLDRSTATE eState;
/** Loader ops. */
PCRTLDROPS pOps;
+ /** Pointer to the reader instance. This is NULL for native image. */
+ PRTLDRREADER pReader;
+ /** Image format. */
+ RTLDRFMT enmFormat;
+ /** Image type. */
+ RTLDRTYPE enmType;
+ /** Image endianness. */
+ RTLDRENDIAN enmEndian;
+ /** Image target architecture. */
+ RTLDRARCH enmArch;
} RTLDRMODINTERNAL;
@@ -430,7 +458,11 @@ typedef struct RTLDRMODNATIVE
RTLDRMODINTERNAL Core;
/** The native handle. */
uintptr_t hNative;
-} RTLDRMODNATIVE, *PRTLDRMODNATIVE;
+ /** The load flags (RTLDRLOAD_FLAGS_XXX). */
+ uint32_t fFlags;
+} RTLDRMODNATIVE;
+/** Pointer to a native module. */
+typedef RTLDRMODNATIVE *PRTLDRMODNATIVE;
/** @copydoc RTLDROPS::pfnGetSymbol */
DECLCALLBACK(int) rtldrNativeGetSymbol(PRTLDRMODINTERNAL pMod, const char *pszSymbol, void **ppvValue);
@@ -443,11 +475,22 @@ DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod);
* @returns iprt status code.
* @param pszFilename The image filename.
* @param phHandle Where to store the module handle on success.
- * @param fFlags See RTLDRFLAGS_.
+ * @param fFlags RTLDRLOAD_FLAGS_XXX.
* @param pErrInfo Where to return extended error information. Optional.
*/
int rtldrNativeLoad(const char *pszFilename, uintptr_t *phHandle, uint32_t fFlags, PRTERRINFO pErrInfo);
+/**
+ * Load a system library.
+ *
+ * @returns iprt status code.
+ * @param pszFilename The image filename.
+ * @param pszExt Extension to add. NULL if none.
+ * @param fFlags RTLDRLOAD_FLAGS_XXX.
+ * @param phLdrMod Where to return the module handle on success.
+ */
+int rtldrNativeLoadSystem(const char *pszFilename, const char *pszExt, uint32_t fFlags, PRTLDRMOD phLdrMod);
+
int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod);
int rtldrELFOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod);
int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod);
@@ -455,6 +498,8 @@ int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTL
int rtldrMachoOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offSomething, PRTLDRMOD phLdrMod);*/
+DECLHIDDEN(int) rtLdrReadAt(RTLDRMOD hLdrMod, void *pvBuf, uint32_t iDbgInfo, RTFOFF off, size_t cb);
+
RT_C_DECLS_END
#endif
diff --git a/src/VBox/Runtime/include/internal/ldrELF.h b/src/VBox/Runtime/include/internal/ldrELF.h
index c52cd816..ecb354bd 100644
--- a/src/VBox/Runtime/include/internal/ldrELF.h
+++ b/src/VBox/Runtime/include/internal/ldrELF.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/ldrELF32.h b/src/VBox/Runtime/include/internal/ldrELF32.h
index 0873357e..a6f789e8 100644
--- a/src/VBox/Runtime/include/internal/ldrELF32.h
+++ b/src/VBox/Runtime/include/internal/ldrELF32.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/ldrELF64.h b/src/VBox/Runtime/include/internal/ldrELF64.h
index 8a60fd9c..30e1b555 100644
--- a/src/VBox/Runtime/include/internal/ldrELF64.h
+++ b/src/VBox/Runtime/include/internal/ldrELF64.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/ldrMZ.h b/src/VBox/Runtime/include/internal/ldrMZ.h
index c6c15c16..2feab758 100644
--- a/src/VBox/Runtime/include/internal/ldrMZ.h
+++ b/src/VBox/Runtime/include/internal/ldrMZ.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/ldrMach-O.h b/src/VBox/Runtime/include/internal/ldrMach-O.h
deleted file mode 100644
index 502f931e..00000000
--- a/src/VBox/Runtime/include/internal/ldrMach-O.h
+++ /dev/null
@@ -1,625 +0,0 @@
-/* $Id: ldrMach-O.h $ */
-/** @file
- * IPRT - Mach-O Structures and Constants.
- */
-
-/*
- * Copyright (C) 2011-2012 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-#ifndef ___internal_ldrMach_O_h
-#define ___internal_ldrMach_O_h
-
-#include <iprt/types.h>
-
-#ifndef CPU_ARCH_MASK
-
-/* cputype */
-#define CPU_ARCH_MASK INT32_C(0xff000000)
-#define CPU_ARCH_ABI64 INT32_C(0x01000000)
-#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_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_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;
- int32_t cputype;
- int32_t cpusubtype;
- uint32_t filetype;
- uint32_t ncmds;
- uint32_t sizeofcmds;
- uint32_t flags;
- uint32_t reserved;
-} mach_header_64_t;
-
-/* 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)
-
-/* 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_VALID_FLAGS UINT32_C(0x01ffffff)
-
-
-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)
-#define LC_DYLIB_CODE_SIGN_DRS UINT32_C(0x2b)
-
-
-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)
-
-/* 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;
- uint32_t reserved1;
- 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;
- uint32_t reserved1;
- uint32_t reserved2;
- uint32_t reserved3;
-} section_64_t;
-
-/* section flags */
-#define SECTION_TYPE UINT32_C(0x000000ff)
-#define S_REGULAR 0x0
-#define S_ZEROFILL 0x1
-#define S_CSTRING_LITERALS 0x2
-#define S_4BYTE_LITERALS 0x3
-#define S_8BYTE_LITERALS 0x4
-#define S_LITERAL_POINTERS 0x5
-#define S_NON_LAZY_SYMBOL_POINTERS 0x6
-#define S_LAZY_SYMBOL_POINTERS 0x7
-#define S_SYMBOL_STUBS 0x8
-#define S_MOD_INIT_FUNC_POINTERS 0x9
-#define S_MOD_TERM_FUNC_POINTERS 0xa
-#define S_COALESCED 0xb
-#define S_GB_ZEROFILL 0xc
-#define S_INTERPOSING 0xd
-#define S_16BYTE_LITERALS 0xe
-#define S_DTRACE_DOF 0xf
-#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10
-
-#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 uuid_command
-{
- uint32_t cmd;
- uint32_t cmdsize;
- uint8_t uuid[16];
-} uuid_command_t;
-
-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)
-
-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;
-
-#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;
-
-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
-
diff --git a/src/VBox/Runtime/include/internal/ldrPE.h b/src/VBox/Runtime/include/internal/ldrPE.h
index 6b973a2c..dd2bc378 100644
--- a/src/VBox/Runtime/include/internal/ldrPE.h
+++ b/src/VBox/Runtime/include/internal/ldrPE.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,8 +28,9 @@
#define ___internal_ldrPE_h
#include <iprt/types.h>
+#include <iprt/assert.h>
-#pragma pack(4)
+#pragma pack(4) /** @todo Necessary? */
/*******************************************************************************
@@ -144,7 +145,8 @@
#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_MASK 0x00F00000
+#define IMAGE_SCN_ALIGN_SHIFT 20
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
@@ -180,28 +182,110 @@
/* debug dir */
-#define IMAGE_DEBUG_TYPE_UNKNOWN 0x0
-#define IMAGE_DEBUG_TYPE_COFF 0x1
-#define IMAGE_DEBUG_TYPE_CODEVIEW 0x2
-#define IMAGE_DEBUG_TYPE_FPO 0x3
-#define IMAGE_DEBUG_TYPE_MISC 0x4
-#define IMAGE_DEBUG_TYPE_EXCEPTION 0x5
-#define IMAGE_DEBUG_TYPE_FIXUP 0x6
-#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 0x7
-#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 0x8
-#define IMAGE_DEBUG_TYPE_BORLAND 0x9
-#define IMAGE_DEBUG_TYPE_RESERVED10 0x10
+#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)
+#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
+
+#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 )
/*******************************************************************************
@@ -209,15 +293,17 @@
*******************************************************************************/
typedef struct _IMAGE_FILE_HEADER
{
- uint16_t Machine;
- uint16_t NumberOfSections;
- uint32_t TimeDateStamp;
- uint32_t PointerToSymbolTable;
- uint32_t NumberOfSymbols;
- uint16_t SizeOfOptionalHeader;
- uint16_t Characteristics;
-} 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;
typedef struct _IMAGE_DATA_DIRECTORY
@@ -226,95 +312,107 @@ typedef struct _IMAGE_DATA_DIRECTORY
uint32_t Size;
} IMAGE_DATA_DIRECTORY;
typedef IMAGE_DATA_DIRECTORY *PIMAGE_DATA_DIRECTORY;
+typedef IMAGE_DATA_DIRECTORY const *PCIMAGE_DATA_DIRECTORY;
typedef struct _IMAGE_OPTIONAL_HEADER32
{
- uint16_t Magic;
- uint8_t MajorLinkerVersion;
- uint8_t MinorLinkerVersion;
- uint32_t SizeOfCode;
- uint32_t SizeOfInitializedData;
- uint32_t SizeOfUninitializedData;
- uint32_t AddressOfEntryPoint;
- uint32_t BaseOfCode;
- uint32_t BaseOfData;
- uint32_t ImageBase;
- uint32_t SectionAlignment;
- uint32_t FileAlignment;
- uint16_t MajorOperatingSystemVersion;
- uint16_t MinorOperatingSystemVersion;
- uint16_t MajorImageVersion;
- uint16_t MinorImageVersion;
- uint16_t MajorSubsystemVersion;
- uint16_t MinorSubsystemVersion;
- uint32_t Win32VersionValue;
- uint32_t SizeOfImage;
- uint32_t SizeOfHeaders;
- uint32_t CheckSum;
- uint16_t Subsystem;
- uint16_t DllCharacteristics;
- uint32_t SizeOfStackReserve;
- uint32_t SizeOfStackCommit;
- uint32_t SizeOfHeapReserve;
- uint32_t SizeOfHeapCommit;
- uint32_t LoaderFlags;
- uint32_t NumberOfRvaAndSizes;
- IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
-} 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;
typedef struct _IMAGE_OPTIONAL_HEADER64
{
- uint16_t Magic;
- uint8_t MajorLinkerVersion;
- uint8_t MinorLinkerVersion;
- uint32_t SizeOfCode;
- uint32_t SizeOfInitializedData;
- uint32_t SizeOfUninitializedData;
- uint32_t AddressOfEntryPoint;
- uint32_t BaseOfCode;
- uint64_t ImageBase;
- uint32_t SectionAlignment;
- uint32_t FileAlignment;
- uint16_t MajorOperatingSystemVersion;
- uint16_t MinorOperatingSystemVersion;
- uint16_t MajorImageVersion;
- uint16_t MinorImageVersion;
- uint16_t MajorSubsystemVersion;
- uint16_t MinorSubsystemVersion;
- uint32_t Win32VersionValue;
- uint32_t SizeOfImage;
- uint32_t SizeOfHeaders;
- uint32_t CheckSum;
- uint16_t Subsystem;
- uint16_t DllCharacteristics;
- uint64_t SizeOfStackReserve;
- uint64_t SizeOfStackCommit;
- uint64_t SizeOfHeapReserve;
- uint64_t SizeOfHeapCommit;
- uint32_t LoaderFlags;
- uint32_t NumberOfRvaAndSizes;
- IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
-} 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 */
typedef IMAGE_OPTIONAL_HEADER64 *PIMAGE_OPTIONAL_HEADER64;
+typedef IMAGE_OPTIONAL_HEADER64 const *PCIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_NT_HEADERS
{
- uint32_t Signature;
- IMAGE_FILE_HEADER FileHeader;
- IMAGE_OPTIONAL_HEADER32 OptionalHeader;
-} 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;
typedef struct _IMAGE_NT_HEADERS64
{
- uint32_t Signature;
- IMAGE_FILE_HEADER FileHeader;
- IMAGE_OPTIONAL_HEADER64 OptionalHeader;
-} 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;
typedef struct _IMAGE_SECTION_HEADER
@@ -335,6 +433,7 @@ typedef struct _IMAGE_SECTION_HEADER
uint32_t Characteristics;
} IMAGE_SECTION_HEADER;
typedef IMAGE_SECTION_HEADER *PIMAGE_SECTION_HEADER;
+typedef IMAGE_SECTION_HEADER const *PCIMAGE_SECTION_HEADER;
typedef struct _IMAGE_BASE_RELOCATION
@@ -343,6 +442,7 @@ typedef struct _IMAGE_BASE_RELOCATION
uint32_t SizeOfBlock;
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION *PIMAGE_BASE_RELOCATION;
+typedef IMAGE_BASE_RELOCATION const *PCIMAGE_BASE_RELOCATION;
typedef struct _IMAGE_EXPORT_DIRECTORY
@@ -358,7 +458,9 @@ typedef struct _IMAGE_EXPORT_DIRECTORY
uint32_t AddressOfFunctions;
uint32_t AddressOfNames;
uint32_t AddressOfNameOrdinals;
-} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
+} IMAGE_EXPORT_DIRECTORY;
+typedef IMAGE_EXPORT_DIRECTORY *PIMAGE_EXPORT_DIRECTORY;
+typedef IMAGE_EXPORT_DIRECTORY const *PCIMAGE_EXPORT_DIRECTORY;
typedef struct _IMAGE_IMPORT_DESCRIPTOR
@@ -374,14 +476,16 @@ typedef struct _IMAGE_IMPORT_DESCRIPTOR
uint32_t FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR *PIMAGE_IMPORT_DESCRIPTOR;
+typedef IMAGE_IMPORT_DESCRIPTOR const *PCIMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_BY_NAME
{
uint16_t Hint;
- uint8_t Name[1];
+ uint8_t Name[1];
} IMAGE_IMPORT_BY_NAME;
typedef IMAGE_IMPORT_BY_NAME *PIMAGE_IMPORT_BY_NAME;
+typedef IMAGE_IMPORT_BY_NAME const *PCIMAGE_IMPORT_BY_NAME;
/* The image_thunk_data32/64 structures are not very helpful except for getting RSI. keep them around till all the code has been converted. */
@@ -396,6 +500,7 @@ typedef struct _IMAGE_THUNK_DATA64
} u1;
} IMAGE_THUNK_DATA64;
typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64;
+typedef IMAGE_THUNK_DATA64 const *PCIMAGE_THUNK_DATA64;
typedef struct _IMAGE_THUNK_DATA32
{
@@ -408,6 +513,7 @@ typedef struct _IMAGE_THUNK_DATA32
} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32;
+typedef IMAGE_THUNK_DATA32 const *PCIMAGE_THUNK_DATA32;
typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32
@@ -433,7 +539,8 @@ typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32
uint32_t SEHandlerTable;
uint32_t SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIRECTORY32;
-typedef IMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY32;
+typedef IMAGE_LOAD_CONFIG_DIRECTORY32 *PIMAGE_LOAD_CONFIG_DIRECTORY32;
+typedef IMAGE_LOAD_CONFIG_DIRECTORY32 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32;
typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64
{
@@ -459,6 +566,7 @@ typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64
uint64_t SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIRECTORY64;
typedef IMAGE_LOAD_CONFIG_DIRECTORY64 *PIMAGE_LOAD_CONFIG_DIRECTORY64;
+typedef IMAGE_LOAD_CONFIG_DIRECTORY64 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64;
typedef struct _IMAGE_DEBUG_DIRECTORY
@@ -473,6 +581,18 @@ typedef struct _IMAGE_DEBUG_DIRECTORY
uint32_t PointerToRawData;
} IMAGE_DEBUG_DIRECTORY;
typedef IMAGE_DEBUG_DIRECTORY *PIMAGE_DEBUG_DIRECTORY;
+typedef IMAGE_DEBUG_DIRECTORY const *PCIMAGE_DEBUG_DIRECTORY;
+
+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;
+typedef IMAGE_DEBUG_MISC *PIMAGE_DEBUG_MISC;
+typedef IMAGE_DEBUG_MISC const *PCIMAGE_DEBUG_MISC;
typedef struct WIN_CERTIFICATE
@@ -483,8 +603,243 @@ typedef struct WIN_CERTIFICATE
uint8_t bCertificate[8];
} WIN_CERTIFICATE;
typedef WIN_CERTIFICATE *PWIN_CERTIFICATE;
+typedef WIN_CERTIFICATE const *PCWIN_CERTIFICATE;
+
+
+
+
+/* WARNING! NO MORE PRAGMA PACK 4 from here on. Assert size of all new types. */
+/* WARNING! NO MORE PRAGMA PACK 4 from here on. Assert size of all new types. */
+/* WARNING! NO MORE PRAGMA PACK 4 from here on. Assert size of all new types. */
+/* WARNING! NO MORE PRAGMA PACK 4 from here on. Assert size of all new types. */
+/* WARNING! NO MORE PRAGMA PACK 4 from here on. Assert size of all new types. */
+/* WARNING! NO MORE PRAGMA PACK 4 from here on. Assert size of all new types. */
+/* WARNING! NO MORE PRAGMA PACK 4 from here on. Assert size of all new types. */
+/* WARNING! NO MORE PRAGMA PACK 4 from here on. Assert size of all new types. */
+/* WARNING! NO MORE PRAGMA PACK 4 from here on. Assert size of all new types. */
+#pragma pack()
+
+
+
+
+/** 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;
+
+
+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;
+
+
+#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;
+
+
+#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;
+
+
+#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;
+
+
+#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;
+
+
+
+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;
+
+
+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;
+
#endif
diff --git a/src/VBox/Runtime/include/internal/lockvalidator.h b/src/VBox/Runtime/include/internal/lockvalidator.h
index 793e3fff..a40a0981 100644
--- a/src/VBox/Runtime/include/internal/lockvalidator.h
+++ b/src/VBox/Runtime/include/internal/lockvalidator.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/magics.h b/src/VBox/Runtime/include/internal/magics.h
index 239c45cf..16be9000 100644
--- a/src/VBox/Runtime/include/internal/magics.h
+++ b/src/VBox/Runtime/include/internal/magics.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2011 Oracle Corporation
+ * Copyright (C) 2007-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,8 +30,14 @@
/** @name Magic Numbers.
* @{ */
+/** Magic number for RTAIOMGRINT::u32Magic. (Emil Erich Kaestner) */
+#define RTAIOMGR_MAGIC UINT32_C(0x18990223)
+/** Magic number for RTAIOMGRINTFILE::u32Magic. (Ephraim Kishon) */
+#define RTAIOMGRFILE_MAGIC UINT32_C(0x19240823)
/** Magic number for RTDBGMODINT::u32Magic. (Charles Lloyd) */
#define RTDBGAS_MAGIC UINT32_C(0x19380315)
+/** Magic number for RTDBGCFGINT::u32Magic. (McCoy Tyner) */
+#define RTDBGCFG_MAGIC UINT32_C(0x19381211)
/** Magic number for RTDBGMODINT::u32Magic. (Keith Jarrett) */
#define RTDBGMOD_MAGIC UINT32_C(0x19450508)
/** Magic number for RTDBGMODVTIMG::u32Magic. (Jack DeJohnette) */
@@ -68,6 +74,10 @@
#define RTHEAPOFFSET_MAGIC UINT32_C(0x19591031)
/** Magic number for RTHEAPSIMPLEINTERNAL::uMagic. (Kyoichi Katayama) */
#define RTHEAPSIMPLE_MAGIC UINT32_C(0x19590105)
+/** The magic value for RTHTTPINTERNAL::u32Magic. (Karl May) */
+#define RTHTTP_MAGIC UINT32_C(0x18420225)
+/** The value of RTHTTPINTERNAL::u32Magic after close. */
+#define RTHTTP_MAGIC_DEAD UINT32_C(0x19120330)
/** The magic value for RTLDRMODINTERNAL::u32Magic. (Alan Moore) */
#define RTLDRMOD_MAGIC UINT32_C(0x19531118)
/** The magic value for RTLOCALIPCSERVER::u32Magic. (Naoki Yamamoto) */
@@ -104,6 +114,8 @@
#define RTMEMPOOL_MAGIC_DEAD UINT32_C(0x18170718)
/** The magic value for heap blocks. (Edgar Allan Poe) */
#define RTMEMHDR_MAGIC UINT32_C(0x18090119)
+/** The magic value for heap blocks after freeing. */
+#define RTMEMHDR_MAGIC_DEAD UINT32_C(0x18491007)
/** The value of RTPIPEINTERNAL::u32Magic. (Frank Schaetzing) */
#define RTPIPE_MAGIC UINT32_C(0x19570528)
/** The value of RTPOLLSETINTERNAL::u32Magic. (Ai Yazawa) */
@@ -178,6 +190,8 @@
#define RTTARFILE_MAGIC_DEAD UINT32_C(0x19120420)
/** RTTESTINT::u32Magic value. (Daniel Kehlmann) */
#define RTTESTINT_MAGIC UINT32_C(0x19750113)
+/** RTTHREADCTXINT::u32Magic value. (Dennis MacAlistair Ritchie) */
+#define RTTHREADCTXINT_MAGIC UINT32_C(0x19410909)
/** RTTHREADINT::u32Magic value. (Gilbert Keith Chesterton) */
#define RTTHREADINT_MAGIC UINT32_C(0x18740529)
/** RTTHREADINT::u32Magic value for a dead thread. */
diff --git a/src/VBox/Runtime/include/internal/path.h b/src/VBox/Runtime/include/internal/path.h
index a1cdb1ee..3f6a5a9d 100644
--- a/src/VBox/Runtime/include/internal/path.h
+++ b/src/VBox/Runtime/include/internal/path.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/pipe.h b/src/VBox/Runtime/include/internal/pipe.h
index e5566d4f..6712b11e 100644
--- a/src/VBox/Runtime/include/internal/pipe.h
+++ b/src/VBox/Runtime/include/internal/pipe.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,15 +28,58 @@
#define ___internal_pipe_h
#include <iprt/pipe.h>
-/* Requires Windows.h on windows. */
RT_C_DECLS_BEGIN
-#ifdef RT_OS_WINDOWS
-int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PHANDLE ph);
+/**
+ * Internal RTPollSetAdd helper that returns the handle that should be added to
+ * the pollset.
+ *
+ * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure.
+ * @param hPipe The pipe handle.
+ * @param fEvents The events we're polling for.
+ * @param phNative Where to put the primary handle.
+ */
+int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative);
+
+/**
+ * Internal RTPoll helper that polls the pipe handle and, if @a fNoWait is
+ * clear, starts whatever actions we've got running during the poll call.
+ *
+ * @returns 0 if no pending events, actions initiated if @a fNoWait is clear.
+ * Event mask (in @a fEvents) and no actions if the handle is ready
+ * already.
+ * UINT32_MAX (asserted) if the pipe handle is busy in I/O or a
+ * different poll set.
+ *
+ * @param hPipe The pipe handle.
+ * @param hPollSet The poll set handle (for access checks).
+ * @param fEvents The events we're polling for.
+ * @param fFinalEntry Set if this is the final entry for this handle
+ * in this poll set. This can be used for dealing
+ * with duplicate entries.
+ * @param fNoWait Set if it's a zero-wait poll call. Clear if
+ * we'll wait for an event to occur.
+ */
uint32_t rtPipePollStart(RTPIPE hPipe, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait);
+
+/**
+ * Called after a WaitForMultipleObjects returned in order to check for pending
+ * events and stop whatever actions that rtPipePollStart() initiated.
+ *
+ * @returns Event mask or 0.
+ *
+ * @param hPipe The pipe handle.
+ * @param fEvents The events we're polling for.
+ * @param fFinalEntry Set if this is the final entry for this handle
+ * in this poll set. This can be used for dealing
+ * with duplicate entries. Only keep in mind that
+ * this method is called in reverse order, so the
+ * first call will have this set (when the entire
+ * set was processed).
+ * @param fHarvestEvents Set if we should check for pending events.
+ */
uint32_t rtPipePollDone(RTPIPE hPipe, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents);
-#endif /* RT_OS_WINDOWS */
RT_C_DECLS_END
diff --git a/src/VBox/Runtime/include/internal/process.h b/src/VBox/Runtime/include/internal/process.h
index cf2c0799..ab00fb95 100644
--- a/src/VBox/Runtime/include/internal/process.h
+++ b/src/VBox/Runtime/include/internal/process.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/rand.h b/src/VBox/Runtime/include/internal/rand.h
index a68de658..88c8fba6 100644
--- a/src/VBox/Runtime/include/internal/rand.h
+++ b/src/VBox/Runtime/include/internal/rand.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/sched.h b/src/VBox/Runtime/include/internal/sched.h
index bab1a063..075a583d 100644
--- a/src/VBox/Runtime/include/internal/sched.h
+++ b/src/VBox/Runtime/include/internal/sched.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/socket.h b/src/VBox/Runtime/include/internal/socket.h
index 8ebfd7e1..e3ff4eb1 100644
--- a/src/VBox/Runtime/include/internal/socket.h
+++ b/src/VBox/Runtime/include/internal/socket.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -61,11 +61,9 @@ int rtSocketConnect(RTSOCKET hSocket, PCRTNETADDR pAddr);
int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValue, int cbValue);
#endif /* IPRT_INTERNAL_SOCKET_POLLING_ONLY */
-#ifdef RT_OS_WINDOWS
-int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PHANDLE ph);
+int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PRTHCINTPTR phNative);
uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait);
uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents);
-#endif /* RT_OS_WINDOWS */
RT_C_DECLS_END
diff --git a/src/VBox/Runtime/include/internal/strhash.h b/src/VBox/Runtime/include/internal/strhash.h
index a7399d06..e8684c0f 100644
--- a/src/VBox/Runtime/include/internal/strhash.h
+++ b/src/VBox/Runtime/include/internal/strhash.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/include/internal/strict.h b/src/VBox/Runtime/include/internal/strict.h
index eed9a33c..0d242490 100644
--- a/src/VBox/Runtime/include/internal/strict.h
+++ b/src/VBox/Runtime/include/internal/strict.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -37,6 +37,13 @@
# define RTCRITSECT_STRICT
#endif
+/** @def RTCRITSECTRW_STRICT
+ * Enables strictness checks and lock accounting of the RTCritSectRw API.
+ */
+#if (!defined(RTCRITSECTRW_STRICT) && defined(IN_RING3) && defined(RT_LOCK_STRICT)) || defined(DOXYGEN_RUNNING)
+# define RTCRITSECTRW_STRICT
+#endif
+
/** @def RTSEMEVENT_STRICT
* Enables strictness checks and lock accounting of the RTSemEvent API.
*/
diff --git a/src/VBox/Runtime/include/internal/thread.h b/src/VBox/Runtime/include/internal/thread.h
index ed6412d0..337b0bfc 100644
--- a/src/VBox/Runtime/include/internal/thread.h
+++ b/src/VBox/Runtime/include/internal/thread.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -139,6 +139,16 @@ typedef RTTHREADINT *PRTTHREADINT;
*/
DECLHIDDEN(int) rtThreadNativeInit(void);
+#ifdef IN_RING3
+/**
+ * Called when IPRT was first initialized in unobtrusive mode and later changed
+ * to obtrustive.
+ *
+ * This is only applicable in ring-3.
+ */
+DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void);
+#endif
+
/**
* Create a native thread.
* This creates the thread as described in pThreadInt and stores the thread id in *pThread.
@@ -199,6 +209,9 @@ DECLHIDDEN(void) rtThreadTerminate(PRTTHREADINT pThread, int rc);
DECLHIDDEN(PRTTHREADINT) rtThreadGetByNative(RTNATIVETHREAD NativeThread);
DECLHIDDEN(PRTTHREADINT) rtThreadGet(RTTHREAD Thread);
DECLHIDDEN(int) rtThreadInit(void);
+#ifdef IN_RING3
+DECLHIDDEN(void) rtThreadReInitObtrusive(void);
+#endif
DECLHIDDEN(void) rtThreadTerm(void);
DECLHIDDEN(void) rtThreadInsert(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread);
#ifdef IN_RING3
diff --git a/src/VBox/Runtime/nt/NtProcessStartup-stub.cpp b/src/VBox/Runtime/nt/NtProcessStartup-stub.cpp
index fcb3bc21..5da37811 100644
--- a/src/VBox/Runtime/nt/NtProcessStartup-stub.cpp
+++ b/src/VBox/Runtime/nt/NtProcessStartup-stub.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/nt/RTErrConvertFromNtStatus.cpp b/src/VBox/Runtime/nt/RTErrConvertFromNtStatus.cpp
index 0f74823b..a102b0a1 100644
--- a/src/VBox/Runtime/nt/RTErrConvertFromNtStatus.cpp
+++ b/src/VBox/Runtime/nt/RTErrConvertFromNtStatus.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -40,17 +40,30 @@ RTDECL(int) RTErrConvertFromNtStatus(long lNativeCode)
{
switch (lNativeCode)
{
- case STATUS_SUCCESS:
- return VINF_SUCCESS;
- case STATUS_ALERTED:
- case STATUS_USER_APC:
- return VERR_INTERRUPTED;
- case STATUS_OBJECT_NAME_NOT_FOUND:
- return VERR_FILE_NOT_FOUND;
+ case STATUS_SUCCESS: return VINF_SUCCESS;
+
+ case STATUS_ALERTED: return VERR_INTERRUPTED;
+ case STATUS_USER_APC: return VERR_INTERRUPTED;
+
+ case STATUS_DATATYPE_MISALIGNMENT: return VERR_INVALID_POINTER;
+ case STATUS_NO_MORE_FILES: return VERR_NO_MORE_FILES;
+ case STATUS_NO_MORE_ENTRIES: return VERR_NO_MORE_FILES;
+
+ case STATUS_INVALID_HANDLE: return VERR_INVALID_HANDLE;
+ case STATUS_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
+ case STATUS_INVALID_DEVICE_REQUEST: return VERR_IO_BAD_COMMAND;
+ case STATUS_ACCESS_DENIED: return VERR_ACCESS_DENIED;
+ case STATUS_OBJECT_TYPE_MISMATCH: return VERR_UNEXPECTED_FS_OBJ_TYPE;
+ case STATUS_OBJECT_NAME_INVALID: return VERR_INVALID_NAME;
+ case STATUS_OBJECT_NAME_NOT_FOUND: return VERR_FILE_NOT_FOUND;
+ case STATUS_OBJECT_PATH_INVALID: return VERR_INVALID_NAME;
+ case STATUS_OBJECT_PATH_NOT_FOUND: return VERR_PATH_NOT_FOUND;
+ case STATUS_BAD_NETWORK_PATH: return VERR_NET_PATH_NOT_FOUND;
+ case STATUS_NOT_A_DIRECTORY: return VERR_NOT_A_DIRECTORY;
}
/* unknown error. */
- AssertMsgFailed(("Unhandled error %ld\n", lNativeCode));
+ AssertMsgFailed(("Unhandled error %#lx (%lu)\n", lNativeCode, lNativeCode));
return VERR_UNRESOLVED_ERROR;
}
diff --git a/src/VBox/Runtime/os2/RTErrConvertFromOS2.cpp b/src/VBox/Runtime/os2/RTErrConvertFromOS2.cpp
index edbfb331..e8b61f2e 100644
--- a/src/VBox/Runtime/os2/RTErrConvertFromOS2.cpp
+++ b/src/VBox/Runtime/os2/RTErrConvertFromOS2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/os2/rtSemWaitOs2ConvertTimeout.cpp b/src/VBox/Runtime/os2/rtSemWaitOs2ConvertTimeout.cpp
index 51b194d8..5107bc72 100644
--- a/src/VBox/Runtime/os2/rtSemWaitOs2ConvertTimeout.cpp
+++ b/src/VBox/Runtime/os2/rtSemWaitOs2ConvertTimeout.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -36,8 +36,8 @@
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
-/** Too lazy to include the right OS/2 header, duplicating the define we
- * need here. */
+/** Too lazy to include the right OS/2 header, duplicating the define we
+ * need here. */
#define MY_SEM_INDEFINITE_WAIT UINT32_MAX
@@ -56,7 +56,7 @@ uint32_t rtR0SemWaitOs2ConvertTimeout(uint32_t fFlags, uint64_t uTimeout)
if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
return MY_SEM_INDEFINITE_WAIT;
- if ( (fFlags & (RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE))
+ if ( (fFlags & (RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE))
== RTSEMWAIT_FLAGS_MILLISECS)
{
if (uTimeout < UINT32_MAX)
@@ -66,7 +66,7 @@ uint32_t rtR0SemWaitOs2ConvertTimeout(uint32_t fFlags, uint64_t uTimeout)
if (!uTimeout)
return 0;
-
+
if (uTimeout == UINT64_MAX)
return MY_SEM_INDEFINITE_WAIT;
diff --git a/src/VBox/Runtime/os2/sys0.asm b/src/VBox/Runtime/os2/sys0.asm
index 476a5b50..32b431c5 100644
--- a/src/VBox/Runtime/os2/sys0.asm
+++ b/src/VBox/Runtime/os2/sys0.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/alloc-r0drv.cpp b/src/VBox/Runtime/r0drv/alloc-r0drv.cpp
index 8444838f..c34ffc32 100644
--- a/src/VBox/Runtime/r0drv/alloc-r0drv.cpp
+++ b/src/VBox/Runtime/r0drv/alloc-r0drv.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -336,7 +336,7 @@ RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, cons
int rc;
RT_ASSERT_PREEMPT_CPUID_VAR();
- if (!(fFlags & RTMEMHDR_FLAG_ANY_CTX_ALLOC))
+ if (!(fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC))
RT_ASSERT_INTS_ON();
/*
@@ -349,7 +349,7 @@ RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, cons
/*
* Validate and convert flags.
*/
- AssertMsgReturn(!(fFlags & ~RTMEMALLOCEX_FLAGS_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
+ AssertMsgReturn(!(fFlags & ~RTMEMALLOCEX_FLAGS_VALID_MASK_R0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
if (fFlags & RTMEMALLOCEX_FLAGS_ZEROED)
fHdrFlags |= RTMEMHDR_FLAG_ZEROED;
if (fFlags & RTMEMALLOCEX_FLAGS_EXEC)
diff --git a/src/VBox/Runtime/r0drv/alloc-r0drv.h b/src/VBox/Runtime/r0drv/alloc-r0drv.h
index 10350fb5..bf790c1f 100644
--- a/src/VBox/Runtime/r0drv/alloc-r0drv.h
+++ b/src/VBox/Runtime/r0drv/alloc-r0drv.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/RTLogWriteDebugger-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/RTLogWriteDebugger-r0drv-darwin.cpp
index 9a65df82..6b895353 100644
--- a/src/VBox/Runtime/r0drv/darwin/RTLogWriteDebugger-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/RTLogWriteDebugger-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp
index 57da5a76..bf5e5906 100644
--- a/src/VBox/Runtime/r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp
index 15aebedb..c221df41 100644
--- a/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp
index 42e15391..293c4ab2 100644
--- a/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp
@@ -57,7 +57,7 @@ RT_C_DECLS_END
#include <iprt/log.h>
#include <iprt/mem.h>
#include <iprt/string.h>
-#include "internal/ldrMach-O.h"
+#include <iprt/formats/mach-o.h>
#include "internal/magics.h"
/** @def MY_CPU_TYPE
diff --git a/src/VBox/Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp
index 9cf01463..98ba22ab 100644
--- a/src/VBox/Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp
index 822b9cd1..6faf85ae 100644
--- a/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp
@@ -360,8 +360,7 @@ DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
*/
if (pMemDarwin->pMemDesc)
{
- if (pMemDarwin->Core.enmType == RTR0MEMOBJTYPE_LOCK)
- pMemDarwin->pMemDesc->complete(); /* paranoia */
+ pMemDarwin->pMemDesc->complete();
pMemDarwin->pMemDesc->release();
pMemDarwin->pMemDesc = NULL;
}
@@ -452,7 +451,7 @@ static int rtR0MemObjNativeAllocWorker(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
* we'll use rtR0MemObjNativeAllocCont as a fallback for dealing with that.
*
* The kIOMemoryKernelUserShared flag just forces the result to be page aligned.
- *
+ *
* The kIOMemoryMapperNone flag is required since 10.8.2 (IOMMU changes?).
*/
int rc;
@@ -511,6 +510,7 @@ static int rtR0MemObjNativeAllocWorker(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
&& Addr == AddrPrev + PAGE_SIZE))
{
/* Buggy API, try allocate the memory another way. */
+ pMemDesc->complete();
pMemDesc->release();
if (PhysMask)
LogRel(("rtR0MemObjNativeAllocWorker: off=%x Addr=%llx AddrPrev=%llx MaxPhysAddr=%llx PhysMas=%llx fContiguous=%RTbool fOptions=%#x - buggy API!\n",
@@ -593,6 +593,8 @@ static int rtR0MemObjNativeAllocWorker(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
}
else
rc = VERR_MEMOBJ_INIT_FAILED;
+
+ pMemDesc->complete();
}
else
rc = RTErrConvertFromDarwinIO(IORet);
diff --git a/src/VBox/Runtime/r0drv/darwin/memuserkernel-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/memuserkernel-r0drv-darwin.cpp
index edd6c671..1c167327 100644
--- a/src/VBox/Runtime/r0drv/darwin/memuserkernel-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/memuserkernel-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -110,4 +110,3 @@ RTR0DECL(int) RTR0MemKernelCopyTo(void *pvDst, void const *pvSrc, size_t cb)
return VERR_NOT_SUPPORTED;
}
-
diff --git a/src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp
index f5a73166..48d0e097 100644
--- a/src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/process-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/process-r0drv-darwin.cpp
index 35542030..71ce84de 100644
--- a/src/VBox/Runtime/r0drv/darwin/process-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/process-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp
index cf57135a..9a216f4a 100644
--- a/src/VBox/Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp
index a77d41d0..9239860b 100644
--- a/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp
index 2b01e760..ef0f9d87 100644
--- a/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp
index 26d934a8..bc744dac 100644
--- a/src/VBox/Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h b/src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h
index cad8dc95..d8be50d6 100644
--- a/src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h
+++ b/src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -85,6 +85,12 @@
# define AST_URGENT UINT32_C(4)
#endif
+/* This flag was added in 10.6, it seems. Should be harmless in earlier
+ releases... */
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+# define kIOMemoryMapperNone UINT32_C(0x800)
+#endif
+
RT_C_DECLS_BEGIN
diff --git a/src/VBox/Runtime/r0drv/darwin/thread-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/thread-r0drv-darwin.cpp
index e603e9e1..0bce605b 100644
--- a/src/VBox/Runtime/r0drv/darwin/thread-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/thread-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp
index 64cabf79..139c0156 100644
--- a/src/VBox/Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/darwin/threadpreempt-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/threadpreempt-r0drv-darwin.cpp
index 23b28a10..b636e1d8 100644
--- a/src/VBox/Runtime/r0drv/darwin/threadpreempt-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/threadpreempt-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -109,8 +109,8 @@ RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread)
uint32_t volatile *pfAstPending = g_pfnR0DarwinAstPending(); AssertPtr(pfAstPending);
uint32_t const fAstPending = *pfAstPending;
- AssertMsg(!(fAstPending & UINT32_C(0xfffff000)), ("%#x\n", fAstPending));
- return (fAstPending & (AST_PREEMPT | AST_URGENT)) != 0;
+ AssertMsg(!(fAstPending & UINT32_C(0xffff8000)), ("%#x\n", fAstPending));
+ return (fAstPending & (AST_PREEMPT | AST_QUANTUM | AST_URGENT)) != 0;
}
diff --git a/src/VBox/Runtime/r0drv/darwin/time-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/time-r0drv-darwin.cpp
index 913fa711..4d9ef806 100644
--- a/src/VBox/Runtime/r0drv/darwin/time-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/time-r0drv-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c
index 349ad7bb..b6c3d231 100644
--- a/src/VBox/Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c
+++ b/src/VBox/Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c
@@ -79,8 +79,13 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
return VERR_NO_EXEC_MEMORY;
/* Addr contains a start address vm_map_find will start searching for suitable space at. */
+#if __FreeBSD_version >= 1000055
+ int rc = vm_map_find(kernel_map, pVmObject, 0, &Addr,
+ cbAllocated, 0, VMFS_ANY_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0);
+#else
int rc = vm_map_find(kernel_map, pVmObject, 0, &Addr,
cbAllocated, TRUE, VM_PROT_ALL, VM_PROT_ALL, 0);
+#endif
if (rc == KERN_SUCCESS)
{
rc = vm_map_wire(kernel_map, Addr, Addr + cbAllocated,
diff --git a/src/VBox/Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c
index 5c90cf38..2486fd13 100644
--- a/src/VBox/Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c
+++ b/src/VBox/Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c
@@ -162,7 +162,11 @@ DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
case RTR0MEMOBJTYPE_PHYS:
case RTR0MEMOBJTYPE_PHYS_NC:
{
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WLOCK(pMemFreeBSD->pObject);
+#else
VM_OBJECT_LOCK(pMemFreeBSD->pObject);
+#endif
vm_page_t pPage = vm_page_find_least(pMemFreeBSD->pObject, 0);
vm_page_lock_queues();
for (vm_page_t pPage = vm_page_find_least(pMemFreeBSD->pObject, 0);
@@ -172,7 +176,11 @@ DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
vm_page_unwire(pPage, 0);
}
vm_page_unlock_queues();
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WUNLOCK(pMemFreeBSD->pObject);
+#else
VM_OBJECT_UNLOCK(pMemFreeBSD->pObject);
+#endif
vm_object_deallocate(pMemFreeBSD->pObject);
break;
}
@@ -200,10 +208,18 @@ static vm_page_t rtR0MemObjFreeBSDContigPhysAllocHelper(vm_object_t pObject, vm_
while (cTries <= 1)
{
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WLOCK(pObject);
+#else
VM_OBJECT_LOCK(pObject);
+#endif
pPages = vm_page_alloc_contig(pObject, iPIndex, fFlags, cPages, 0,
VmPhysAddrHigh, uAlignment, 0, VM_MEMATTR_DEFAULT);
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WUNLOCK(pObject);
+#else
VM_OBJECT_UNLOCK(pObject);
+#endif
if (pPages)
break;
vm_pageout_grow_cache(cTries, 0, VmPhysAddrHigh);
@@ -223,7 +239,11 @@ static vm_page_t rtR0MemObjFreeBSDContigPhysAllocHelper(vm_object_t pObject, vm_
if (!pPages)
return pPages;
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WLOCK(pObject);
+#else
VM_OBJECT_LOCK(pObject);
+#endif
for (vm_pindex_t iPage = 0; iPage < cPages; iPage++)
{
vm_page_t pPage = pPages + iPage;
@@ -235,7 +255,11 @@ static vm_page_t rtR0MemObjFreeBSDContigPhysAllocHelper(vm_object_t pObject, vm_
atomic_add_int(&cnt.v_wire_count, 1);
}
}
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WUNLOCK(pObject);
+#else
VM_OBJECT_UNLOCK(pObject);
+#endif
return pPages;
#endif
}
@@ -259,7 +283,11 @@ static int rtR0MemObjFreeBSDPhysAllocHelper(vm_object_t pObject, u_long cPages,
if (!pPage)
{
/* Free all allocated pages */
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WLOCK(pObject);
+#else
VM_OBJECT_LOCK(pObject);
+#endif
while (iPage-- > 0)
{
pPage = vm_page_lookup(pObject, iPage);
@@ -269,7 +297,11 @@ static int rtR0MemObjFreeBSDPhysAllocHelper(vm_object_t pObject, u_long cPages,
vm_page_free(pPage);
vm_page_unlock_queues();
}
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WUNLOCK(pObject);
+#else
VM_OBJECT_UNLOCK(pObject);
+#endif
return rcNoMem;
}
}
@@ -286,9 +318,15 @@ static int rtR0MemObjFreeBSDAllocHelper(PRTR0MEMOBJFREEBSD pMemFreeBSD, bool fEx
pMemFreeBSD->pObject = vm_object_allocate(OBJT_PHYS, cPages);
/* No additional object reference for auto-deallocation upon unmapping. */
+#if __FreeBSD_version >= 1000055
+ rc = vm_map_find(kernel_map, pMemFreeBSD->pObject, 0,
+ &MapAddress, pMemFreeBSD->Core.cb, 0, VMFS_ANY_SPACE,
+ fExecutable ? VM_PROT_ALL : VM_PROT_RW, VM_PROT_ALL, 0);
+#else
rc = vm_map_find(kernel_map, pMemFreeBSD->pObject, 0,
&MapAddress, pMemFreeBSD->Core.cb, VMFS_ANY_SPACE,
fExecutable ? VM_PROT_ALL : VM_PROT_RW, VM_PROT_ALL, 0);
+#endif
if (rc == KERN_SUCCESS)
{
@@ -402,9 +440,17 @@ static int rtR0MemObjFreeBSDAllocPhysPages(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOB
if (fContiguous)
{
Assert(enmType == RTR0MEMOBJTYPE_PHYS);
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WLOCK(pMemFreeBSD->pObject);
+#else
VM_OBJECT_LOCK(pMemFreeBSD->pObject);
+#endif
pMemFreeBSD->Core.u.Phys.PhysBase = VM_PAGE_TO_PHYS(vm_page_find_least(pMemFreeBSD->pObject, 0));
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WUNLOCK(pMemFreeBSD->pObject);
+#else
VM_OBJECT_UNLOCK(pMemFreeBSD->pObject);
+#endif
pMemFreeBSD->Core.u.Phys.fAllocated = true;
}
@@ -551,6 +597,9 @@ static int rtR0MemObjNativeReserveInMap(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixe
0, /* offset */
&MapAddress, /* addr (IN/OUT) */
cb, /* length */
+#if __FreeBSD_version >= 1000055
+ 0, /* max addr */
+#endif
pvFixed == (void *)-1 ? VMFS_ANY_SPACE : VMFS_NO_SPACE,
/* find_space */
VM_PROT_NONE, /* protection */
@@ -628,6 +677,9 @@ DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ
offSub, /* Start offset in the object */
&Addr, /* Start address IN/OUT */
cbSub, /* Size of the mapping */
+#if __FreeBSD_version >= 1000055
+ 0, /* Upper bound of mapping */
+#endif
VMFS_ANY_SPACE, /* Whether a suitable address should be searched for first */
ProtectionFlags, /* protection flags */
VM_PROT_ALL, /* Maximum protection flags */
@@ -704,6 +756,9 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
0, /* Start offset in the object */
&AddrR3, /* Start address IN/OUT */
pMemToMap->cb, /* Size of the mapping */
+#if __FreeBSD_version >= 1000055
+ 0, /* Upper bound of the mapping */
+#endif
R3PtrFixed == (RTR3PTR)-1 ? VMFS_ANY_SPACE : VMFS_NO_SPACE,
/* Whether a suitable address should be searched for first */
ProtectionFlags, /* protection flags */
@@ -814,9 +869,17 @@ DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, s
case RTR0MEMOBJTYPE_PHYS_NC:
{
RTHCPHYS addr;
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WLOCK(pMemFreeBSD->pObject);
+#else
VM_OBJECT_LOCK(pMemFreeBSD->pObject);
+#endif
addr = VM_PAGE_TO_PHYS(vm_page_lookup(pMemFreeBSD->pObject, iPage));
+#if __FreeBSD_version >= 1000030
+ VM_OBJECT_WUNLOCK(pMemFreeBSD->pObject);
+#else
VM_OBJECT_UNLOCK(pMemFreeBSD->pObject);
+#endif
return addr;
}
diff --git a/src/VBox/Runtime/r0drv/freebsd/memuserkernel-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/memuserkernel-r0drv-freebsd.c
index be8006b3..d7fa0b2d 100644
--- a/src/VBox/Runtime/r0drv/freebsd/memuserkernel-r0drv-freebsd.c
+++ b/src/VBox/Runtime/r0drv/freebsd/memuserkernel-r0drv-freebsd.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -81,4 +81,3 @@ RTR0DECL(int) RTR0MemKernelCopyTo(void *pvDst, void const *pvSrc, size_t cb)
return VERR_NOT_SUPPORTED;
}
-
diff --git a/src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c
index 87e82ff2..a38e78a3 100644
--- a/src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c
+++ b/src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -88,6 +88,11 @@ RTDECL(RTCPUID) RTMpGetCount(void)
}
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ return mp_maxid + 1;
+}
+
RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
{
return idCpu <= mp_maxid
diff --git a/src/VBox/Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c
index b20b9603..addd9d01 100644
--- a/src/VBox/Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c
+++ b/src/VBox/Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h b/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h
index 2d0201d9..0a0be656 100644
--- a/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h
+++ b/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -36,7 +36,7 @@
#include <iprt/time.h>
/**
- * Kernel mode Linux wait state structure.
+ * Kernel mode FreeBSD wait state structure.
*/
typedef struct RTR0SEMBSDSLEEP
{
@@ -259,7 +259,7 @@ DECLINLINE(void) rtR0SemBsdWaitDoIt(PRTR0SEMBSDSLEEP pWait)
*
* @returns true / false
* @param pWait The wait structure.
- * @remarks This shall be called before the first rtR0SemLnxWaitDoIt().
+ * @remarks This shall be called before the first rtR0SemBsdWaitDoIt().
*/
DECLINLINE(bool) rtR0SemBsdWaitWasInterrupted(PRTR0SEMBSDSLEEP pWait)
{
diff --git a/src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h b/src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h
index 718b6741..306bb3af 100644
--- a/src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h
+++ b/src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h
@@ -50,6 +50,9 @@
#include <sys/unistd.h>
#include <sys/kthread.h>
#include <sys/lock.h>
+#if __FreeBSD_version >= 1000030
+#include <sys/rwlock.h>
+#endif
#include <sys/mutex.h>
#include <sys/sched.h>
#include <sys/callout.h>
@@ -66,6 +69,7 @@
#include <vm/vm_page.h>
#include <vm/vm_phys.h> /* vm_phys_alloc_* */
#include <vm/vm_extern.h> /* kmem_alloc_attr */
+#include <vm/vm_pageout.h> /* vm_contig_grow_cache */
#include <sys/vmmeter.h> /* cnt */
#include <sys/resourcevar.h>
#include <machine/cpu.h>
diff --git a/src/VBox/Runtime/r0drv/freebsd/thread-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/thread-r0drv-freebsd.c
index d61e6f0b..de14e764 100644
--- a/src/VBox/Runtime/r0drv/freebsd/thread-r0drv-freebsd.c
+++ b/src/VBox/Runtime/r0drv/freebsd/thread-r0drv-freebsd.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2009 Oracle Corporation
+ * Copyright (C) 2007-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp
index 925842eb..c8d93f53 100644
--- a/src/VBox/Runtime/r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp
index a9844ace..ba352a63 100644
--- a/src/VBox/Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/RTMpPokeCpu-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/RTMpPokeCpu-r0drv-generic.cpp
index 01835679..52db8375 100644
--- a/src/VBox/Runtime/r0drv/generic/RTMpPokeCpu-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/RTMpPokeCpu-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptDisable-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptDisable-r0drv-generic.cpp
index 0d943b3b..3a81521f 100644
--- a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptDisable-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptDisable-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsEnabled-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsEnabled-r0drv-generic.cpp
index 0e00439d..107971a3 100644
--- a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsEnabled-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsEnabled-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPending-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPending-r0drv-generic.cpp
index 1fc9b894..3eaf98a1 100644
--- a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPending-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPending-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPendingTrusty-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPendingTrusty-r0drv-generic.cpp
index fe94d022..44057f0b 100644
--- a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPendingTrusty-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptIsPendingTrusty-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptRestore-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptRestore-r0drv-generic.cpp
index 9fa8461e..ef2c2dc1 100644
--- a/src/VBox/Runtime/r0drv/generic/RTThreadPreemptRestore-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/RTThreadPreemptRestore-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp
index 5310c13b..9a1406cf 100644
--- a/src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c b/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c
index 69f29f24..7044961c 100644
--- a/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c
+++ b/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/generic/threadctxhooks-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/threadctxhooks-r0drv-generic.cpp
new file mode 100644
index 00000000..cce89ba6
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/generic/threadctxhooks-r0drv-generic.cpp
@@ -0,0 +1,84 @@
+/* $Id: threadctxhooks-r0drv-generic.cpp $ */
+/** @file
+ * IPRT - Thread-Context Hooks, Ring-0 Driver, Generic.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/thread.h>
+#include <iprt/err.h>
+
+#include "internal/iprt.h"
+
+RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
+{
+ NOREF(phThreadCtx);
+ return VERR_NOT_SUPPORTED;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
+
+
+RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
+{
+ NOREF(hThreadCtx);
+ return UINT32_MAX;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
+
+
+RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
+{
+ NOREF(hThreadCtx);
+ return UINT32_MAX;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
+
+
+RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnCallback, void *pvUser)
+{
+ NOREF(hThreadCtx);
+ NOREF(pfnCallback);
+ NOREF(pvUser);
+ return VERR_NOT_SUPPORTED;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
+
+
+RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
+{
+ NOREF(hThreadCtx);
+ return VERR_NOT_SUPPORTED;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
+
+
+RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
+{
+ NOREF(hThreadCtx);
+ return false;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksAreRegistered);
+
diff --git a/src/VBox/Runtime/r0drv/haiku/RTLogWriteDebugger-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/RTLogWriteDebugger-r0drv-haiku.c
new file mode 100644
index 00000000..7d67906f
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/RTLogWriteDebugger-r0drv-haiku.c
@@ -0,0 +1,42 @@
+/* $Id: RTLogWriteDebugger-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Log To Debugger, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/log.h>
+
+
+RTDECL(void) RTLogWriteDebugger(const char *pch, size_t cb)
+{
+ /** @todo implement this */
+ /*kprintf("%.*s", (int)cb, pch);*/
+ return;
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/RTLogWriteStdOut-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/RTLogWriteStdOut-r0drv-haiku.c
new file mode 100644
index 00000000..80996090
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/RTLogWriteStdOut-r0drv-haiku.c
@@ -0,0 +1,41 @@
+/* $Id: RTLogWriteStdOut-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Log To StdOut, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/log.h>
+
+
+RTDECL(void) RTLogWriteStdOut(const char *pch, size_t cb)
+{
+ dprintf("%.*s", (int)cb, pch);
+ return;
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/alloc-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/alloc-r0drv-haiku.c
new file mode 100644
index 00000000..58c72036
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/alloc-r0drv-haiku.c
@@ -0,0 +1,124 @@
+/* $Id: alloc-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Memory Allocation, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/mem.h>
+#include <iprt/log.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/thread.h>
+#include "r0drv/alloc-r0drv.h"
+
+
+/**
+ * OS specific allocation function.
+ */
+int rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
+{
+ if (RT_UNLIKELY(fFlags & RTMEMHDR_FLAG_ANY_CTX))
+ return VERR_NOT_SUPPORTED;
+
+ PRTMEMHDR pHdr = (PRTMEMHDR)malloc(cb + sizeof(*pHdr));
+ if (RT_UNLIKELY(!pHdr))
+ {
+ LogRel(("rtR0MemAllocEx(%u, %#x) failed\n",(unsigned)cb + sizeof(*pHdr), fFlags));
+ return VERR_NO_MEMORY;
+ }
+
+ pHdr->u32Magic = RTMEMHDR_MAGIC;
+ pHdr->fFlags = fFlags;
+ pHdr->cb = cb;
+ pHdr->cbReq = cb;
+ *ppHdr = pHdr;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * OS specific free function.
+ */
+void rtR0MemFree(PRTMEMHDR pHdr)
+{
+ pHdr->u32Magic += 1;
+ free(pHdr);
+}
+
+
+RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb) RT_NO_THROW
+{
+ /*
+ * Validate input.
+ */
+ AssertPtr(pPhys);
+ Assert(cb > 0);
+ RT_ASSERT_PREEMPTIBLE();
+
+ /*
+ * Allocate the memory and ensure that the API is still providing
+ * memory that's always below 4GB.
+ */
+ cb = RT_ALIGN_Z(cb, PAGE_SIZE);
+ void *pv;
+ area_id area = create_area("VirtualBox Contig Alloc", &pv, B_ANY_KERNEL_ADDRESS, cb, B_32_BIT_CONTIGUOUS,
+ B_READ_AREA | B_WRITE_AREA);
+ if (area >= 0)
+ {
+ physical_entry physMap[2];
+ if (get_memory_map(pv, cb, physMap, 2)>= B_OK)
+ {
+ *pPhys = physMap[0].address;
+ return pv;
+ }
+ delete_area(area);
+ AssertMsgFailed(("Cannot get_memory_map for contig alloc! cb=%u\n",(unsigned)cb));
+ }
+ else
+ AssertMsgFailed(("Cannot create_area for contig alloc! cb=%u error=0x%08lx\n",(unsigned)cb, area));
+ return NULL;
+}
+
+
+RTR0DECL(void) RTMemContFree(void *pv, size_t cb) RT_NO_THROW
+{
+ RT_ASSERT_PREEMPTIBLE();
+ if (pv)
+ {
+ Assert(cb > 0);
+
+ area_id area = area_for(pv);
+ if (area >= B_OK)
+ delete_area(area);
+ else
+ AssertMsgFailed(("Cannot find area to delete! cb=%u error=0x%08lx\n",(unsigned)cb, area));
+ }
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/assert-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/assert-r0drv-haiku.c
new file mode 100644
index 00000000..8241e9b1
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/assert-r0drv-haiku.c
@@ -0,0 +1,68 @@
+/* $Id: assert-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Assertion Workers, Ring-0 Drivers, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/assert.h>
+
+#include <iprt/asm.h>
+#include <iprt/log.h>
+#include <iprt/stdarg.h>
+#include <iprt/string.h>
+
+#include "internal/assert.h"
+
+
+void rtR0AssertNativeMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
+{
+ dprintf("\r\n!!Assertion Failed!!\r\n"
+ "Expression: %s\r\n"
+ "Location : %s(%d) %s\r\n",
+ pszExpr, pszFile, uLine, pszFunction);
+}
+
+
+void rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_list va)
+{
+ char szMsg[256];
+
+ RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
+ szMsg[sizeof(szMsg) - 1] = '\0';
+ dprintf("%s", szMsg);
+
+ NOREF(fInitial);
+}
+
+
+RTR0DECL(void) RTR0AssertPanicSystem(void)
+{
+ panic("%s%s", g_szRTAssertMsg1, g_szRTAssertMsg2);
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/initterm-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/initterm-r0drv-haiku.c
new file mode 100644
index 00000000..3041bea1
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/initterm-r0drv-haiku.c
@@ -0,0 +1,48 @@
+/* $Id: initterm-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Initialization & Termination, R0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+#include "internal/initterm.h"
+
+
+int rtR0InitNative(void)
+{
+ return VINF_SUCCESS;
+}
+
+
+void rtR0TermNative(void)
+{
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/memobj-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/memobj-r0drv-haiku.c
new file mode 100644
index 00000000..8c27a26e
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/memobj-r0drv-haiku.c
@@ -0,0 +1,663 @@
+/* $Id: memobj-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Ring-0 Memory Objects, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+
+#include <iprt/memobj.h>
+#include <iprt/mem.h>
+#include <iprt/err.h>
+#include <iprt/assert.h>
+#include <iprt/log.h>
+#include <iprt/param.h>
+#include <iprt/process.h>
+#include "internal/memobj.h"
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * The Haiku version of the memory object structure.
+ */
+typedef struct RTR0MEMOBJHAIKU
+{
+ /** The core structure. */
+ RTR0MEMOBJINTERNAL Core;
+ /** Area identifier */
+ area_id AreaId;
+} RTR0MEMOBJHAIKU, *PRTR0MEMOBJHAIKU;
+
+
+//MALLOC_DEFINE(M_IPRTMOBJ, "iprtmobj", "IPRT - R0MemObj");
+#if 0
+/**
+ * Gets the virtual memory map the specified object is mapped into.
+ *
+ * @returns VM map handle on success, NULL if no map.
+ * @param pMem The memory object.
+ */
+static vm_map_t rtR0MemObjHaikuGetMap(PRTR0MEMOBJINTERNAL pMem)
+{
+ switch (pMem->enmType)
+ {
+ case RTR0MEMOBJTYPE_PAGE:
+ case RTR0MEMOBJTYPE_LOW:
+ case RTR0MEMOBJTYPE_CONT:
+ return kernel_map;
+
+ case RTR0MEMOBJTYPE_PHYS:
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ return NULL; /* pretend these have no mapping atm. */
+
+ case RTR0MEMOBJTYPE_LOCK:
+ return pMem->u.Lock.R0Process == NIL_RTR0PROCESS
+ ? kernel_map
+ : &((struct proc *)pMem->u.Lock.R0Process)->p_vmspace->vm_map;
+
+ case RTR0MEMOBJTYPE_RES_VIRT:
+ return pMem->u.ResVirt.R0Process == NIL_RTR0PROCESS
+ ? kernel_map
+ : &((struct proc *)pMem->u.ResVirt.R0Process)->p_vmspace->vm_map;
+
+ case RTR0MEMOBJTYPE_MAPPING:
+ return pMem->u.Mapping.R0Process == NIL_RTR0PROCESS
+ ? kernel_map
+ : &((struct proc *)pMem->u.Mapping.R0Process)->p_vmspace->vm_map;
+
+ default:
+ return NULL;
+ }
+}
+#endif
+
+
+int rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
+{
+ PRTR0MEMOBJHAIKU pMemHaiku = (PRTR0MEMOBJHAIKU)pMem;
+ int rc = B_OK;
+
+ switch (pMemHaiku->Core.enmType)
+ {
+ case RTR0MEMOBJTYPE_PAGE:
+ case RTR0MEMOBJTYPE_LOW:
+ case RTR0MEMOBJTYPE_CONT:
+ case RTR0MEMOBJTYPE_MAPPING:
+ case RTR0MEMOBJTYPE_PHYS:
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ {
+ if (pMemHaiku->AreaId > -1)
+ rc = delete_area(pMemHaiku->AreaId);
+
+ AssertMsg(rc == B_OK, ("%#x", rc));
+ break;
+ }
+
+ case RTR0MEMOBJTYPE_LOCK:
+ {
+ team_id team = B_SYSTEM_TEAM;
+
+ if (pMemHaiku->Core.u.Lock.R0Process != NIL_RTR0PROCESS)
+ team = ((team_id)pMemHaiku->Core.u.Lock.R0Process);
+
+ rc = unlock_memory_etc(team, pMemHaiku->Core.pv, pMemHaiku->Core.cb, B_READ_DEVICE);
+ AssertMsg(rc == B_OK, ("%#x", rc));
+ break;
+ }
+
+ case RTR0MEMOBJTYPE_RES_VIRT:
+ {
+ team_id team = B_SYSTEM_TEAM;
+ if (pMemHaiku->Core.u.Lock.R0Process != NIL_RTR0PROCESS)
+ team = ((team_id)pMemHaiku->Core.u.Lock.R0Process);
+
+ rc = vm_unreserve_address_range(team, pMemHaiku->Core.pv, pMemHaiku->Core.cb);
+ AssertMsg(rc == B_OK, ("%#x", rc));
+ break;
+ }
+
+ default:
+ AssertMsgFailed(("enmType=%d\n", pMemHaiku->Core.enmType));
+ return VERR_INTERNAL_ERROR;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+static int rtR0MemObjNativeAllocArea(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
+ bool fExecutable, RTR0MEMOBJTYPE type, RTHCPHYS PhysHighest, size_t uAlignment)
+{
+ NOREF(fExecutable);
+
+ int rc;
+ void *pvMap = NULL;
+ const char *pszName = NULL;
+ uint32 addressSpec = B_ANY_KERNEL_ADDRESS;
+ uint32 fLock = ~0U;
+ LogFlowFunc(("ppMem=%p cb=%u, fExecutable=%s, type=%08x, PhysHighest=%RX64 uAlignment=%u\n", ppMem,(unsigned)cb,
+ fExecutable ? "true" : "false", type, PhysHighest,(unsigned)uAlignment));
+
+ switch (type)
+ {
+ case RTR0MEMOBJTYPE_PAGE:
+ pszName = "IPRT R0MemObj Alloc";
+ fLock = B_FULL_LOCK;
+ break;
+ case RTR0MEMOBJTYPE_LOW:
+ pszName = "IPRT R0MemObj AllocLow";
+ fLock = B_32_BIT_FULL_LOCK;
+ break;
+ case RTR0MEMOBJTYPE_CONT:
+ pszName = "IPRT R0MemObj AllocCont";
+ fLock = B_32_BIT_CONTIGUOUS;
+ break;
+#if 0
+ case RTR0MEMOBJTYPE_MAPPING:
+ pszName = "IPRT R0MemObj Mapping";
+ fLock = B_FULL_LOCK;
+ break;
+#endif
+ case RTR0MEMOBJTYPE_PHYS:
+ /** @todo alignment */
+ if (uAlignment != PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+ /** @todo r=ramshankar: no 'break' here?? */
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ pszName = "IPRT R0MemObj AllocPhys";
+ fLock = (PhysHighest < _4G ? B_LOMEM : B_32_BIT_CONTIGUOUS);
+ break;
+#if 0
+ case RTR0MEMOBJTYPE_LOCK:
+ break;
+#endif
+ default:
+ return VERR_INTERNAL_ERROR;
+ }
+
+ /* Create the object. */
+ PRTR0MEMOBJHAIKU pMemHaiku;
+ pMemHaiku = (PRTR0MEMOBJHAIKU)rtR0MemObjNew(sizeof(RTR0MEMOBJHAIKU), type, NULL, cb);
+ if (RT_UNLIKELY(!pMemHaiku))
+ return VERR_NO_MEMORY;
+
+ rc = pMemHaiku->AreaId = create_area(pszName, &pvMap, addressSpec, cb, fLock, B_READ_AREA | B_WRITE_AREA);
+ if (pMemHaiku->AreaId >= 0)
+ {
+ physical_entry physMap[2];
+ pMemHaiku->Core.pv = pvMap; /* store start address */
+ switch (type)
+ {
+ case RTR0MEMOBJTYPE_CONT:
+ rc = get_memory_map(pvMap, cb, physMap, 2);
+ if (rc == B_OK)
+ pMemHaiku->Core.u.Cont.Phys = physMap[0].address;
+ break;
+
+ case RTR0MEMOBJTYPE_PHYS:
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ rc = get_memory_map(pvMap, cb, physMap, 2);
+ if (rc == B_OK)
+ {
+ pMemHaiku->Core.u.Phys.PhysBase = physMap[0].address;
+ pMemHaiku->Core.u.Phys.fAllocated = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (rc >= B_OK)
+ {
+ *ppMem = &pMemHaiku->Core;
+ return VINF_SUCCESS;
+ }
+
+ delete_area(pMemHaiku->AreaId);
+ }
+
+ rtR0MemObjDelete(&pMemHaiku->Core);
+ return RTErrConvertFromHaikuKernReturn(rc);
+}
+
+
+int rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
+{
+ return rtR0MemObjNativeAllocArea(ppMem, cb, fExecutable, RTR0MEMOBJTYPE_PAGE, 0 /* PhysHighest */, 0 /* uAlignment */);
+}
+
+
+int rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
+{
+ return rtR0MemObjNativeAllocArea(ppMem, cb, fExecutable, RTR0MEMOBJTYPE_LOW, 0 /* PhysHighest */, 0 /* uAlignment */);
+}
+
+
+int rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
+{
+ return rtR0MemObjNativeAllocArea(ppMem, cb, fExecutable, RTR0MEMOBJTYPE_CONT, 0 /* PhysHighest */, 0 /* uAlignment */);
+}
+
+int rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment)
+{
+ return rtR0MemObjNativeAllocArea(ppMem, cb, false, RTR0MEMOBJTYPE_PHYS, PhysHighest, uAlignment);
+}
+
+
+int rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
+{
+ return rtR0MemObjNativeAllocPhys(ppMem, cb, PhysHighest, PAGE_SIZE);
+}
+
+
+int rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy)
+{
+ AssertReturn(uCachePolicy == RTMEM_CACHE_POLICY_DONT_CARE, VERR_NOT_SUPPORTED);
+ LogFlowFunc(("ppMem=%p Phys=%08x cb=%u uCachePolicy=%x\n", ppMem, Phys,(unsigned)cb, uCachePolicy));
+
+ /* Create the object. */
+ PRTR0MEMOBJHAIKU pMemHaiku = (PRTR0MEMOBJHAIKU)rtR0MemObjNew(sizeof(*pMemHaiku), RTR0MEMOBJTYPE_PHYS, NULL, cb);
+ if (!pMemHaiku)
+ return VERR_NO_MEMORY;
+
+ /* There is no allocation here, it needs to be mapped somewhere first. */
+ pMemHaiku->AreaId = -1;
+ pMemHaiku->Core.u.Phys.fAllocated = false;
+ pMemHaiku->Core.u.Phys.PhysBase = Phys;
+ pMemHaiku->Core.u.Phys.uCachePolicy = uCachePolicy;
+ *ppMem = &pMemHaiku->Core;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker locking the memory in either kernel or user maps.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the allocated memory object.
+ * @param pvStart The starting address.
+ * @param cb The size of the block.
+ * @param fAccess The mapping protection to apply.
+ * @param R0Process The process to map the memory to (use NIL_RTR0PROCESS
+ * for the kernel)
+ * @param fFlags Memory flags (B_READ_DEVICE indicates the memory is
+ * intended to be written from a "device").
+ */
+static int rtR0MemObjNativeLockInMap(PPRTR0MEMOBJINTERNAL ppMem, void *pvStart, size_t cb, uint32_t fAccess,
+ RTR0PROCESS R0Process, int fFlags)
+{
+ NOREF(fAccess);
+ int rc;
+ team_id TeamId = B_SYSTEM_TEAM;
+
+ LogFlowFunc(("ppMem=%p pvStart=%p cb=%u fAccess=%x R0Process=%d fFlags=%x\n", ppMem, pvStart, cb, fAccess, R0Process,
+ fFlags));
+
+ /* Create the object. */
+ PRTR0MEMOBJHAIKU pMemHaiku = (PRTR0MEMOBJHAIKU)rtR0MemObjNew(sizeof(*pMemHaiku), RTR0MEMOBJTYPE_LOCK, pvStart, cb);
+ if (RT_UNLIKELY(!pMemHaiku))
+ return VERR_NO_MEMORY;
+
+ if (R0Process != NIL_RTR0PROCESS)
+ TeamId = (team_id)R0Process;
+ rc = lock_memory_etc(TeamId, pvStart, cb, fFlags);
+ if (rc == B_OK)
+ {
+ pMemHaiku->AreaId = -1;
+ pMemHaiku->Core.u.Lock.R0Process = R0Process;
+ *ppMem = &pMemHaiku->Core;
+ return VINF_SUCCESS;
+ }
+ rtR0MemObjDelete(&pMemHaiku->Core);
+ return RTErrConvertFromHaikuKernReturn(rc);
+}
+
+
+int rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess, RTR0PROCESS R0Process)
+{
+ return rtR0MemObjNativeLockInMap(ppMem, (void *)R3Ptr, cb, fAccess, R0Process, B_READ_DEVICE);
+}
+
+
+int rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess)
+{
+ return rtR0MemObjNativeLockInMap(ppMem, pv, cb, fAccess, NIL_RTR0PROCESS, B_READ_DEVICE);
+}
+
+
+#if 0
+/** @todo Reserve address space */
+/**
+ * Worker for the two virtual address space reservers.
+ *
+ * We're leaning on the examples provided by mmap and vm_mmap in vm_mmap.c here.
+ */
+static int rtR0MemObjNativeReserveInMap(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment,
+ RTR0PROCESS R0Process)
+{
+ int rc;
+ team_id TeamId = B_SYSTEM_TEAM;
+
+ LogFlowFunc(("ppMem=%p pvFixed=%p cb=%u uAlignment=%u R0Process=%d\n", ppMem, pvFixed, (unsigned)cb, uAlignment, R0Process));
+
+ if (R0Process != NIL_RTR0PROCESS)
+ team = (team_id)R0Process;
+
+ /* Check that the specified alignment is supported. */
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+
+ /* Create the object. */
+ PRTR0MEMOBJHAIKU pMemHaiku = (PRTR0MEMOBJHAIKU)rtR0MemObjNew(sizeof(*pMemHaiku), RTR0MEMOBJTYPE_RES_VIRT, NULL, cb);
+ if (!pMemHaiku)
+ return VERR_NO_MEMORY;
+
+ /* Ask the kernel to reserve the address range. */
+ //XXX: vm_reserve_address_range ?
+ return VERR_NOT_SUPPORTED;
+}
+#endif
+
+
+int rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
+
+int rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
+
+int rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
+ unsigned fProt, size_t offSub, size_t cbSub)
+{
+ PRTR0MEMOBJHAIKU pMemToMapHaiku = (PRTR0MEMOBJHAIKU)pMemToMap;
+ PRTR0MEMOBJHAIKU pMemHaiku;
+ area_id area = -1;
+ void *pvMap = pvFixed;
+ uint32 uAddrSpec = B_EXACT_ADDRESS;
+ uint32 fProtect = 0;
+ int rc = VERR_MAP_FAILED;
+ AssertMsgReturn(!offSub && !cbSub, ("%#x %#x\n", offSub, cbSub), VERR_NOT_SUPPORTED);
+ AssertMsgReturn(pvFixed == (void *)-1, ("%p\n", pvFixed), VERR_NOT_SUPPORTED);
+#if 0
+ /** @todo r=ramshankar: Wrong format specifiers, fix later! */
+ dprintf("%s(%p, %p, %p, %d, %x, %u, %u)\n", __FUNCTION__, ppMem, pMemToMap, pvFixed, uAlignment,
+ fProt, offSub, cbSub);
+#endif
+ /* Check that the specified alignment is supported. */
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+
+ /* We can't map anything to the first page, sorry. */
+ if (pvFixed == 0)
+ return VERR_NOT_SUPPORTED;
+
+ if (fProt & RTMEM_PROT_READ)
+ fProtect |= B_KERNEL_READ_AREA;
+ if (fProt & RTMEM_PROT_WRITE)
+ fProtect |= B_KERNEL_WRITE_AREA;
+
+ /*
+ * Either the object we map has an area associated with, which we can clone,
+ * or it's a physical address range which we must map.
+ */
+ if (pMemToMapHaiku->AreaId > -1)
+ {
+ if (pvFixed == (void *)-1)
+ uAddrSpec = B_ANY_KERNEL_ADDRESS;
+
+ rc = area = clone_area("IPRT R0MemObj MapKernel", &pvMap, uAddrSpec, fProtect, pMemToMapHaiku->AreaId);
+ LogFlow(("rtR0MemObjNativeMapKernel: clone_area uAddrSpec=%d fProtect=%x AreaId=%d rc=%d\n", uAddrSpec, fProtect,
+ pMemToMapHaiku->AreaId, rc));
+ }
+ else if (pMemToMapHaiku->Core.enmType == RTR0MEMOBJTYPE_PHYS)
+ {
+ /* map_physical_memory() won't let you choose where. */
+ if (pvFixed != (void *)-1)
+ return VERR_NOT_SUPPORTED;
+ uAddrSpec = B_ANY_KERNEL_ADDRESS;
+
+ rc = area = map_physical_memory("IPRT R0MemObj MapKernelPhys", (phys_addr_t)pMemToMapHaiku->Core.u.Phys.PhysBase,
+ pMemToMapHaiku->Core.cb, uAddrSpec, fProtect, &pvMap);
+ }
+ else
+ return VERR_NOT_SUPPORTED;
+
+ if (rc >= B_OK)
+ {
+ /* Create the object. */
+ pMemHaiku = (PRTR0MEMOBJHAIKU)rtR0MemObjNew(sizeof(RTR0MEMOBJHAIKU), RTR0MEMOBJTYPE_MAPPING, pvMap,
+ pMemToMapHaiku->Core.cb);
+ if (RT_UNLIKELY(!pMemHaiku))
+ return VERR_NO_MEMORY;
+
+ pMemHaiku->Core.u.Mapping.R0Process = NIL_RTR0PROCESS;
+ pMemHaiku->Core.pv = pvMap;
+ pMemHaiku->AreaId = area;
+ *ppMem = &pMemHaiku->Core;
+ return VINF_SUCCESS;
+ }
+ rc = VERR_MAP_FAILED;
+
+ /** @todo finish the implementation. */
+
+ rtR0MemObjDelete(&pMemHaiku->Core);
+ return rc;
+}
+
+
+int rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, RTR3PTR R3PtrFixed, size_t uAlignment,
+ unsigned fProt, RTR0PROCESS R0Process)
+{
+#if 0
+ /*
+ * Check for unsupported stuff.
+ */
+ AssertMsgReturn(R0Process == RTR0ProcHandleSelf(), ("%p != %p\n", R0Process, RTR0ProcHandleSelf()), VERR_NOT_SUPPORTED);
+ AssertMsgReturn(R3PtrFixed == (RTR3PTR)-1, ("%p\n", R3PtrFixed), VERR_NOT_SUPPORTED);
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+
+ int rc;
+ PRTR0MEMOBJHAIKU pMemToMapHaiku = (PRTR0MEMOBJHAIKU)pMemToMap;
+ struct proc *pProc = (struct proc *)R0Process;
+ struct vm_map *pProcMap = &pProc->p_vmspace->vm_map;
+
+ /* calc protection */
+ vm_prot_t ProtectionFlags = 0;
+ if ((fProt & RTMEM_PROT_NONE) == RTMEM_PROT_NONE)
+ ProtectionFlags = VM_PROT_NONE;
+ if ((fProt & RTMEM_PROT_READ) == RTMEM_PROT_READ)
+ ProtectionFlags |= VM_PROT_READ;
+ if ((fProt & RTMEM_PROT_WRITE) == RTMEM_PROT_WRITE)
+ ProtectionFlags |= VM_PROT_WRITE;
+ if ((fProt & RTMEM_PROT_EXEC) == RTMEM_PROT_EXEC)
+ ProtectionFlags |= VM_PROT_EXECUTE;
+
+ /* calc mapping address */
+ PROC_LOCK(pProc);
+ vm_offset_t AddrR3 = round_page((vm_offset_t)pProc->p_vmspace->vm_daddr + lim_max(pProc, RLIMIT_DATA));
+ PROC_UNLOCK(pProc);
+
+ /* Insert the object in the map. */
+ rc = vm_map_find(pProcMap, /* Map to insert the object in */
+ NULL, /* Object to map */
+ 0, /* Start offset in the object */
+ &AddrR3, /* Start address IN/OUT */
+ pMemToMap->cb, /* Size of the mapping */
+ TRUE, /* Whether a suitable address should be searched for first */
+ ProtectionFlags, /* protection flags */
+ VM_PROT_ALL, /* Maximum protection flags */
+ 0); /* Copy on write */
+
+ /* Map the memory page by page into the destination map. */
+ if (rc == KERN_SUCCESS)
+ {
+ size_t cPages = pMemToMap->cb >> PAGE_SHIFT;;
+ pmap_t pPhysicalMap = pProcMap->pmap;
+ vm_offset_t AddrR3Dst = AddrR3;
+
+ if ( pMemToMap->enmType == RTR0MEMOBJTYPE_PHYS
+ || pMemToMap->enmType == RTR0MEMOBJTYPE_PHYS_NC
+ || pMemToMap->enmType == RTR0MEMOBJTYPE_PAGE)
+ {
+ /* Mapping physical allocations */
+ Assert(cPages == pMemToMapHaiku->u.Phys.cPages);
+
+ /* Insert the memory page by page into the mapping. */
+ for (uint32_t iPage = 0; iPage < cPages; iPage++)
+ {
+ vm_page_t pPage = pMemToMapHaiku->u.Phys.apPages[iPage];
+
+ MY_PMAP_ENTER(pPhysicalMap, AddrR3Dst, pPage, ProtectionFlags, TRUE);
+ AddrR3Dst += PAGE_SIZE;
+ }
+ }
+ else
+ {
+ /* Mapping cont or low memory types */
+ vm_offset_t AddrToMap = (vm_offset_t)pMemToMap->pv;
+
+ for (uint32_t iPage = 0; iPage < cPages; iPage++)
+ {
+ vm_page_t pPage = PHYS_TO_VM_PAGE(vtophys(AddrToMap));
+
+ MY_PMAP_ENTER(pPhysicalMap, AddrR3Dst, pPage, ProtectionFlags, TRUE);
+ AddrR3Dst += PAGE_SIZE;
+ AddrToMap += PAGE_SIZE;
+ }
+ }
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create a mapping object for it.
+ */
+ PRTR0MEMOBJHAIKU pMemHaiku = (PRTR0MEMOBJHAIKU)rtR0MemObjNew(sizeof(RTR0MEMOBJHAIKU),
+ RTR0MEMOBJTYPE_MAPPING,
+ (void *)AddrR3,
+ pMemToMap->cb);
+ if (pMemHaiku)
+ {
+ Assert((vm_offset_t)pMemHaiku->Core.pv == AddrR3);
+ pMemHaiku->Core.u.Mapping.R0Process = R0Process;
+ *ppMem = &pMemHaiku->Core;
+ return VINF_SUCCESS;
+ }
+
+ rc = vm_map_remove(pProcMap, ((vm_offset_t)AddrR3), ((vm_offset_t)AddrR3) + pMemToMap->cb);
+ AssertMsg(rc == KERN_SUCCESS, ("Deleting mapping failed\n"));
+ }
+#endif
+ return VERR_NOT_SUPPORTED;
+}
+
+
+int rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
+
+RTHCPHYS rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
+{
+ PRTR0MEMOBJHAIKU pMemHaiku = (PRTR0MEMOBJHAIKU)pMem;
+ status_t rc;
+
+ /** @todo r=ramshankar: Validate objects */
+
+ LogFlow(("rtR0MemObjNativeGetPagePhysAddr: pMem=%p enmType=%x iPage=%u\n", pMem, pMemHaiku->Core.enmType,(unsigned)iPage));
+
+ switch (pMemHaiku->Core.enmType)
+ {
+ case RTR0MEMOBJTYPE_LOCK:
+ {
+ team_id TeamId = B_SYSTEM_TEAM;
+ physical_entry aPhysMap[2];
+ int32 cPhysMap = 2; /** @todo r=ramshankar: why not use RT_ELEMENTS? */
+
+ if (pMemHaiku->Core.u.Lock.R0Process != NIL_RTR0PROCESS)
+ TeamId = (team_id)pMemHaiku->Core.u.Lock.R0Process;
+ void *pb = pMemHaiku->Core.pv + (iPage << PAGE_SHIFT);
+
+ rc = get_memory_map_etc(TeamId, pb, B_PAGE_SIZE, aPhysMap, &cPhysMap);
+ if (rc < B_OK || cPhysMap < 1)
+ return NIL_RTHCPHYS;
+
+ return aPhysMap[0].address;
+ }
+
+#if 0
+ case RTR0MEMOBJTYPE_MAPPING:
+ {
+ vm_offset_t pb = (vm_offset_t)pMemHaiku->Core.pv + (iPage << PAGE_SHIFT);
+
+ if (pMemHaiku->Core.u.Mapping.R0Process != NIL_RTR0PROCESS)
+ {
+ struct proc *pProc = (struct proc *)pMemHaiku->Core.u.Mapping.R0Process;
+ struct vm_map *pProcMap = &pProc->p_vmspace->vm_map;
+ pmap_t pPhysicalMap = pProcMap->pmap;
+
+ return pmap_extract(pPhysicalMap, pb);
+ }
+ return vtophys(pb);
+ }
+#endif
+ case RTR0MEMOBJTYPE_CONT:
+ return pMemHaiku->Core.u.Cont.Phys + (iPage << PAGE_SHIFT);
+
+ case RTR0MEMOBJTYPE_PHYS:
+ return pMemHaiku->Core.u.Phys.PhysBase + (iPage << PAGE_SHIFT);
+
+ case RTR0MEMOBJTYPE_LOW:
+ case RTR0MEMOBJTYPE_PAGE:
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ {
+ team_id TeamId = B_SYSTEM_TEAM;
+ physical_entry aPhysMap[2];
+ int32 cPhysMap = 2; /** @todo r=ramshankar: why not use RT_ELEMENTS? */
+
+ void *pb = pMemHaiku->Core.pv + (iPage << PAGE_SHIFT);
+ rc = get_memory_map_etc(TeamId, pb, B_PAGE_SIZE, aPhysMap, &cPhysMap);
+ if (rc < B_OK || cPhysMap < 1)
+ return NIL_RTHCPHYS;
+
+ return aPhysMap[0].address;
+ }
+
+ case RTR0MEMOBJTYPE_RES_VIRT:
+ default:
+ return NIL_RTHCPHYS;
+ }
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/mp-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/mp-r0drv-haiku.c
new file mode 100644
index 00000000..0d0af546
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/mp-r0drv-haiku.c
@@ -0,0 +1,218 @@
+/* $Id: mp-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Multiprocessor, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+
+#include <iprt/mp.h>
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include <iprt/cpuset.h>
+#include "r0drv/mp-r0drv.h"
+
+
+RTDECL(RTCPUID) RTMpCpuId(void)
+{
+ return smp_get_current_cpu();
+}
+
+
+RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
+{
+ return idCpu < smp_get_num_cpus() ? (int)idCpu : -1;
+}
+
+
+RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
+{
+ return (unsigned)iCpu < smp_get_num_cpus() ? (RTCPUID)iCpu : NIL_RTCPUID;
+}
+
+
+RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
+{
+ return smp_get_num_cpus() - 1;
+}
+
+
+RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
+{
+ return idCpu < smp_get_num_cpus();
+}
+
+
+RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
+{
+ RTCPUID idCpu;
+
+ RTCpuSetEmpty(pSet);
+ idCpu = RTMpGetMaxCpuId();
+ do
+ {
+ if (RTMpIsCpuPossible(idCpu))
+ RTCpuSetAdd(pSet, idCpu);
+ } while (idCpu-- > 0);
+ return pSet;
+}
+
+
+RTDECL(RTCPUID) RTMpGetCount(void)
+{
+ return smp_get_num_cpus();
+}
+
+
+RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
+{
+ return idCpu < smp_get_num_cpus();
+ /** @todo: FixMe && !CPU_ABSENT(idCpu) */
+}
+
+
+RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
+{
+ RTCPUID idCpu;
+
+ RTCpuSetEmpty(pSet);
+ idCpu = RTMpGetMaxCpuId();
+ do
+ {
+ if (RTMpIsCpuOnline(idCpu))
+ RTCpuSetAdd(pSet, idCpu);
+ } while (idCpu-- > 0);
+
+ return pSet;
+}
+
+
+RTDECL(RTCPUID) RTMpGetOnlineCount(void)
+{
+ return smp_get_num_cpus();
+}
+
+
+/**
+ * Wrapper between the native Haiku per-cpu callback and PFNRTWORKER
+ * for the RTMpOnAll API.
+ *
+ * @param pvArg Pointer to the RTMPARGS package.
+ */
+static void rtmpOnAllHaikuWrapper(void *pvArg, int current)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvArg;
+ pArgs->pfnWorker(current, pArgs->pvUser1, pArgs->pvUser2);
+}
+
+
+RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ RTMPARGS Args;
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = NIL_RTCPUID;
+ Args.cHits = 0;
+ /* is _sync needed ? */
+ call_all_cpus_sync(rtmpOnAllHaikuWrapper, &Args);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Wrapper between the native Haiku per-cpu callback and PFNRTWORKER
+ * for the RTMpOnOthers API.
+ *
+ * @param pvArg Pointer to the RTMPARGS package.
+ */
+static void rtmpOnOthersHaikuWrapper(void *pvArg, int current)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvArg;
+ RTCPUID idCpu = current;
+ if (pArgs->idCpu != idCpu)
+ pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+}
+
+
+RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ /* Will panic if no rendezvousing cpus, so check up front. */
+ if (RTMpGetOnlineCount() > 1)
+ {
+ RTMPARGS Args;
+
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = RTMpCpuId();
+ Args.cHits = 0;
+ /* is _sync needed ? */
+ call_all_cpus_sync(rtmpOnOthersHaikuWrapper, &Args);
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Wrapper between the native Haiku per-cpu callback and PFNRTWORKER
+ * for the RTMpOnSpecific API.
+ *
+ * @param pvArg Pointer to the RTMPARGS package.
+ */
+static void rtmpOnSpecificHaikuWrapper(void *pvArg, int current)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvArg;
+ RTCPUID idCpu = current;
+ if (pArgs->idCpu == idCpu)
+ {
+ pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+ ASMAtomicIncU32(&pArgs->cHits);
+ }
+}
+
+
+RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ RTMPARGS Args;
+
+ /* Will panic if no rendezvousing cpus, so make sure the cpu is online. */
+ if (!RTMpIsCpuOnline(idCpu))
+ return VERR_CPU_NOT_FOUND;
+
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = idCpu;
+ Args.cHits = 0;
+ /* is _sync needed ? */
+ call_all_cpus_sync(rtmpOnSpecificHaikuWrapper, &Args);
+ return Args.cHits == 1
+ ? VINF_SUCCESS
+ : VERR_CPU_NOT_FOUND;
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/process-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/process-r0drv-haiku.c
new file mode 100644
index 00000000..a3b6a5c8
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/process-r0drv-haiku.c
@@ -0,0 +1,46 @@
+/* $Id: process-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Process, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/process.h>
+
+
+RTDECL(RTPROCESS) RTProcSelf(void)
+{
+ return getpid();
+}
+
+
+RTR0DECL(RTR0PROCESS) RTR0ProcHandleSelf(void)
+{
+ return (RTR0PROCESS)(team_id)getpid();
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/semevent-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/semevent-r0drv-haiku.c
new file mode 100644
index 00000000..9914262f
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/semevent-r0drv-haiku.c
@@ -0,0 +1,264 @@
+/* $Id: semevent-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Single Release Event Semaphores, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/lockvalidator.h>
+#include <iprt/mem.h>
+
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Haiku event semaphore.
+ */
+typedef struct RTSEMEVENTINTERNAL
+{
+ /** Magic value (RTSEMEVENT_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** Reference counter. */
+ uint32_t volatile cRefs;
+ /** The semaphore Id. */
+ sem_id SemId;
+} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
+
+
+RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem)
+{
+ return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
+}
+
+
+RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
+{
+ AssertCompile(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *));
+ AssertReturn(!(fFlags & ~(RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)), VERR_INVALID_PARAMETER);
+ Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL));
+ AssertPtrReturn(phEventSem, VERR_INVALID_POINTER);
+
+ PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAllocZ(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ pThis->u32Magic = RTSEMEVENT_MAGIC;
+ pThis->cRefs = 1;
+ pThis->SemId = create_sem(0, "IPRT Semaphore Event");
+ if (pThis->SemId >= B_OK)
+ {
+ set_sem_owner(pThis->SemId, B_SYSTEM_TEAM);
+ *phEventSem = pThis;
+ return VINF_SUCCESS;
+ }
+
+ RTMemFree(pThis);
+ return VERR_TOO_MANY_SEMAPHORES; /** @todo r=ramshankar: use RTErrConvertFromHaikuKernReturn */
+}
+
+
+/**
+ * Retains a reference to the event semaphore.
+ *
+ * @param pThis The event semaphore.
+ */
+DECLINLINE(void) rtR0SemEventHkuRetain(PRTSEMEVENTINTERNAL pThis)
+{
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs < 100000); NOREF(cRefs);
+}
+
+
+/**
+ * Releases a reference to the event semaphore.
+ *
+ * @param pThis The event semaphore.
+ */
+DECLINLINE(void) rtR0SemEventHkuRelease(PRTSEMEVENTINTERNAL pThis)
+{
+ if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
+ RTMemFree(pThis);
+}
+
+
+RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTINTERNAL pThis = hEventSem;
+ if (pThis == NIL_RTSEMEVENT)
+ return VINF_SUCCESS;
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+ Assert(pThis->cRefs > 0);
+
+ /*
+ * Invalidate it and delete the semaphore to unblock everyone.
+ */
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENT_MAGIC);
+ delete_sem(pThis->SemId);
+ pThis->SemId = -1;
+ rtR0SemEventHkuRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+ rtR0SemEventHkuRetain(pThis);
+
+ /*
+ * Signal the event object.
+ * We must use B_DO_NOT_RESCHEDULE since we are being used from an irq handler.
+ */
+ release_sem_etc(pThis->SemId, 1, B_DO_NOT_RESCHEDULE);
+ rtR0SemEventHkuRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug.
+ *
+ * @returns VBox status code.
+ * @param pThis The event semaphore.
+ * @param fFlags See RTSemEventWaitEx.
+ * @param uTimeout See RTSemEventWaitEx.
+ * @param pSrcPos The source code position of the wait.
+ */
+static int rtR0SemEventWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
+ PCRTLOCKVALSRCPOS pSrcPos)
+{
+ status_t status;
+ int rc;
+ int32 flags = 0;
+ bigtime_t timeout; /* in microseconds */
+
+ /*
+ * Validate the input.
+ */
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
+
+ if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
+ timeout = B_INFINITE_TIMEOUT;
+ else
+ {
+ if (fFlags & RTSEMWAIT_FLAGS_NANOSECS)
+ timeout = uTimeout / 1000;
+ else if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
+ timeout = uTimeout * 1000;
+ else
+ return VERR_INVALID_PARAMETER;
+
+ if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
+ flags |= B_RELATIVE_TIMEOUT;
+ else if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
+ flags |= B_ABSOLUTE_TIMEOUT;
+ else
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE)
+ flags |= B_CAN_INTERRUPT;
+ // likely not:
+ //else
+ // flags |= B_KILL_CAN_INTERRUPT;
+
+ rtR0SemEventHkuRetain(pThis);
+
+ status = acquire_sem_etc(pThis->SemId, 1, flags, timeout);
+
+ switch (status)
+ {
+ case B_OK:
+ rc = VINF_SUCCESS;
+ break;
+ case B_BAD_SEM_ID:
+ rc = VERR_SEM_DESTROYED;
+ break;
+ case B_INTERRUPTED:
+ rc = VERR_INTERRUPTED;
+ break;
+ case B_WOULD_BLOCK:
+ /* fallthrough ? */
+ case B_TIMED_OUT:
+ rc = VERR_TIMEOUT;
+ break;
+ default:
+ rc = RTErrConvertFromHaikuKernReturn(status);
+ break;
+ }
+
+ rtR0SemEventHkuRelease(pThis);
+ return rc;
+}
+
+
+RTDECL(int) RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
+{
+#ifndef RTSEMEVENT_STRICT
+ return rtR0SemEventWait(hEventSem, fFlags, uTimeout, NULL);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtR0SemEventWait(hEventSem, fFlags, uTimeout, &SrcPos);
+#endif
+}
+RT_EXPORT_SYMBOL(RTSemEventWaitEx);
+
+
+RTDECL(int) RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
+ RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtR0SemEventWait(hEventSem, fFlags, uTimeout, &SrcPos);
+}
+RT_EXPORT_SYMBOL(RTSemEventWaitExDebug);
+
+
+RTDECL(uint32_t) RTSemEventGetResolution(void)
+{
+ /* At least that's what the API supports. */
+ return 1000;
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/semeventmulti-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/semeventmulti-r0drv-haiku.c
new file mode 100644
index 00000000..3179fc9b
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/semeventmulti-r0drv-haiku.c
@@ -0,0 +1,291 @@
+/* $Id: semeventmulti-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/lockvalidator.h>
+
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Haiku multiple release event semaphore.
+ */
+typedef struct RTSEMEVENTMULTIINTERNAL
+{
+ /** Magic value (RTSEMEVENTMULTI_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** Reference counter. */
+ uint32_t volatile cRefs;
+ /** The semaphore Id. */
+ sem_id SemId;
+} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
+
+
+RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
+{
+ return RTSemEventMultiCreateEx(phEventMultiSem, 0 /* fFlags */, NIL_RTLOCKVALCLASS, NULL);
+}
+
+
+RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
+ const char *pszNameFmt, ...)
+{
+ PRTSEMEVENTMULTIINTERNAL pThis;
+
+ AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
+ pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
+ pThis->cRefs = 1;
+ pThis->SemId = create_sem(0, "IPRT Semaphore Event Multi");
+ if (pThis->SemId < B_OK)
+ {
+ set_sem_owner(pThis->SemId, B_SYSTEM_TEAM);
+ *phEventMultiSem = pThis;
+ return VINF_SUCCESS;
+ }
+
+ RTMemFree(pThis);
+ return VERR_TOO_MANY_SEMAPHORES; /** @todo r=ramshankar: use RTErrConvertFromHaikuKernReturn */
+}
+
+
+/**
+ * Retain a reference to the semaphore.
+ *
+ * @param pThis The semaphore.
+ */
+DECLINLINE(void) rtR0SemEventMultiHkuRetain(PRTSEMEVENTMULTIINTERNAL pThis)
+{
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs && cRefs < 100000);
+}
+
+
+/**
+ * Release a reference, destroy the thing if necessary.
+ *
+ * @param pThis The semaphore.
+ */
+DECLINLINE(void) rtR0SemEventMultiHkuRelease(PRTSEMEVENTMULTIINTERNAL pThis)
+{
+ if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
+ {
+ Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
+ RTMemFree(pThis);
+ }
+}
+
+
+RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+ if (pThis == NIL_RTSEMEVENTMULTI)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ Assert(pThis->cRefs > 0);
+
+ /*
+ * Invalidate it and signal the object just in case.
+ */
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
+ delete_sem(pThis->SemId);
+ pThis->SemId = -1;
+ rtR0SemEventMultiHkuRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+ if (!pThis)
+ return VERR_INVALID_PARAMETER;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ rtR0SemEventMultiHkuRetain(pThis);
+
+ /*
+ * Signal the event object.
+ * We must use B_DO_NOT_RESCHEDULE since we are being used from an irq handler.
+ */
+ release_sem_etc(pThis->SemId, 1, B_RELEASE_ALL | B_DO_NOT_RESCHEDULE);
+ rtR0SemEventMultiHkuRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+ if (!pThis)
+ return VERR_INVALID_PARAMETER;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ rtR0SemEventMultiHkuRetain(pThis);
+
+ /*
+ * Reset it.
+ */
+ //FIXME: what should I do ???
+ // delete_sem + create_sem ??
+ rtR0SemEventMultiHkuRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
+ *
+ * @returns VBox status code.
+ * @param pThis The event semaphore.
+ * @param fFlags See RTSemEventMultiWaitEx.
+ * @param uTimeout See RTSemEventMultiWaitEx.
+ * @param pSrcPos The source code position of the wait.
+ */
+static int rtR0SemEventMultiHkuWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
+ PCRTLOCKVALSRCPOS pSrcPos)
+{
+ status_t status;
+ int rc;
+ int32 flags = 0;
+ bigtime_t timeout; /* in microseconds */
+
+ /*
+ * Validate the input.
+ */
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
+
+ if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
+ timeout = B_INFINITE_TIMEOUT;
+ else
+ {
+ if (fFlags & RTSEMWAIT_FLAGS_NANOSECS)
+ timeout = uTimeout / 1000;
+ else if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
+ timeout = uTimeout * 1000;
+ else
+ return VERR_INVALID_PARAMETER;
+
+ if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
+ flags |= B_RELATIVE_TIMEOUT;
+ else if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
+ flags |= B_ABSOLUTE_TIMEOUT;
+ else
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE)
+ flags |= B_CAN_INTERRUPT;
+ // likely not:
+ //else
+ // flags |= B_KILL_CAN_INTERRUPT;
+
+ rtR0SemEventMultiHkuRetain(pThis);
+
+ status = acquire_sem_etc(pThis->SemId, 1, flags, timeout);
+
+ switch (status)
+ {
+ case B_OK:
+ rc = VINF_SUCCESS;
+ break;
+ case B_BAD_SEM_ID:
+ rc = VERR_SEM_DESTROYED;
+ break;
+ case B_INTERRUPTED:
+ rc = VERR_INTERRUPTED;
+ break;
+ case B_WOULD_BLOCK:
+ /* fallthrough? */
+ case B_TIMED_OUT:
+ rc = VERR_TIMEOUT;
+ break;
+ default:
+ rc = RTErrConvertFromHaikuKernReturn(status);
+ break;
+ }
+
+ rtR0SemEventMultiHkuRelease(pThis);
+ return rc;
+}
+
+
+RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
+{
+#ifndef RTSEMEVENT_STRICT
+ return rtR0SemEventMultiHkuWait(hEventMultiSem, fFlags, uTimeout, NULL);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtR0SemEventMultiHkuWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
+#endif
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx);
+
+
+RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
+ RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtR0SemEventMultiHkuWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug);
+
+
+RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
+{
+ /* At least that's what the API supports. */
+ return 1000;
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution);
+
diff --git a/src/VBox/Runtime/r0drv/haiku/semfastmutex-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/semfastmutex-r0drv-haiku.c
new file mode 100644
index 00000000..c34189cb
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/semfastmutex-r0drv-haiku.c
@@ -0,0 +1,120 @@
+/* $Id: semfastmutex-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Fast Mutex Semaphores, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+
+#include <iprt/semaphore.h>
+#include <iprt/err.h>
+#include <iprt/alloc.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Wrapper for the Haiku (sleep) mutex.
+ */
+typedef struct RTSEMFASTMUTEXINTERNAL
+{
+ /** Magic value (RTSEMFASTMUTEX_MAGIC). */
+ uint32_t u32Magic;
+ /** A good old Benaphore. */
+ vint32 BenId;
+ sem_id SemId;
+} RTSEMFASTMUTEXINTERNAL, *PRTSEMFASTMUTEXINTERNAL;
+
+
+RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)
+{
+ AssertCompile(sizeof(RTSEMFASTMUTEXINTERNAL) > sizeof(void *));
+ AssertPtrReturn(phFastMtx, VERR_INVALID_POINTER);
+
+ PRTSEMFASTMUTEXINTERNAL pThis = (PRTSEMFASTMUTEXINTERNAL)RTMemAllocZ(sizeof(*pThis));
+ if (RT_UNLIKELY(!pThis))
+ return VERR_NO_MEMORY;
+
+ pThis->u32Magic = RTSEMFASTMUTEX_MAGIC;
+ pThis->BenId = 0;
+ pThis->SemId = create_sem(0, "IPRT Fast Mutex Semaphore");
+ if (pThis->SemId >= B_OK)
+ {
+ *phFastMtx = pThis;
+ return VINF_SUCCESS;
+ }
+ RTMemFree(pThis);
+ return VERR_TOO_MANY_SEMAPHORES; /** @todo r=ramshankar: use RTErrConvertFromHaikuKernReturn */
+}
+
+
+RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx)
+{
+ PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
+ if (pThis == NIL_RTSEMFASTMUTEX)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ ASMAtomicWriteU32(&pThis->u32Magic, RTSEMFASTMUTEX_MAGIC_DEAD);
+ delete_sem(pThis->SemId);
+ RTMemFree(pThis);
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx)
+{
+ PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ if (atomic_add(&pThis->BenId, 1) > 0)
+ acquire_sem(pThis->SemId);
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx)
+{
+ PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ if (atomic_add(&pThis->BenId, -1) > 1)
+ release_sem(pThis->SemId);
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/semmutex-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/semmutex-r0drv-haiku.c
new file mode 100644
index 00000000..4f4f68a8
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/semmutex-r0drv-haiku.c
@@ -0,0 +1,233 @@
+/* $Id: semmutex-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Mutex Semaphores, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Wrapper for the Haiku (sleep) mutex.
+ */
+/* XXX: not optimal, maybe should use the (private)
+ kernel recursive_lock ? (but it's not waitable) */
+typedef struct RTSEMMUTEXINTERNAL
+{
+ /** Magic value (RTSEMMUTEX_MAGIC). */
+ uint32_t u32Magic;
+ /** Kernel semaphore. */
+ sem_id SemId;
+ /** Current holder */
+ volatile thread_id OwnerId;
+ /** Recursion count */
+ int32 cRecursion;
+} RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;
+
+
+RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem)
+{
+ AssertCompile(sizeof(RTSEMMUTEXINTERNAL) > sizeof(void *));
+ AssertPtrReturn(phMutexSem, VERR_INVALID_POINTER);
+
+ PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)RTMemAllocZ(sizeof(*pThis));
+ if (RT_UNLIKELY(!pThis))
+ return VERR_NO_MEMORY;
+
+ pThis->u32Magic = RTSEMMUTEX_MAGIC;
+ pThis->SemId = create_sem(0, "IPRT Mutex Semaphore");
+ if (pThis->SemId < B_OK)
+ {
+ pThis->OwnerId = -1;
+ pThis->cRecursion = 0;
+ *phMutexSem = pThis;
+ return VINF_SUCCESS;
+ }
+ RTMemFree(pThis);
+ return VERR_TOO_MANY_SEMAPHORES; /** @todo r=ramshankar: use RTErrConvertFromHaikuKernReturn */
+}
+
+
+RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ if (pThis == NIL_RTSEMMUTEX)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
+
+ delete_sem(pThis->SemId);
+ RTMemFree(pThis);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker function for acquiring the mutex.
+ *
+ * @param hMutexSem The mutex object.
+ * @param fFlags Mutex flags (see RTSEMWAIT_FLAGS_*)
+ * @param uTimeout Timeout in units specified by the flags.
+ *
+ * @return IPRT status code.
+ */
+static int rtSemMutexRequestEx(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ int rc;
+ status_t status;
+ int32 flags = 0;
+ bigtime_t timeout; /* in microseconds */
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ if (pThis->OwnerId == find_thread(NULL))
+ {
+ pThis->OwnerId++;
+ return VINF_SUCCESS;
+ }
+
+ if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
+ timeout = B_INFINITE_TIMEOUT;
+ else
+ {
+ if (fFlags & RTSEMWAIT_FLAGS_NANOSECS)
+ timeout = uTimeout / 1000;
+ else if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
+ timeout = uTimeout * 1000;
+ else
+ return VERR_INVALID_PARAMETER;
+
+ if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
+ flags |= B_RELATIVE_TIMEOUT;
+ else if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
+ flags |= B_ABSOLUTE_TIMEOUT;
+ else
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE)
+ flags |= B_CAN_INTERRUPT;
+
+ status = acquire_sem_etc(pThis->SemId, 1, flags, timeout);
+
+ switch (status)
+ {
+ case B_OK:
+ rc = VINF_SUCCESS;
+ pThis->cRecursion = 1;
+ pThis->OwnerId = find_thread(NULL);
+ break;
+ case B_BAD_SEM_ID:
+ rc = VERR_SEM_DESTROYED;
+ break;
+ case B_INTERRUPTED:
+ rc = VERR_INTERRUPTED;
+ break;
+ case B_WOULD_BLOCK:
+ /* fallthrough? */
+ case B_TIMED_OUT:
+ rc = VERR_TIMEOUT;
+ break;
+ default:
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ return rc;
+}
+
+
+RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
+{
+ return rtSemMutexRequestEx(hMutexSem, RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS, cMillies);
+}
+
+
+RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ return RTSemMutexRequest(hMutexSem, cMillies);
+}
+
+
+RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
+{
+ return rtSemMutexRequestEx(hMutexSem, RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_MILLISECS, cMillies);
+}
+
+
+RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ return RTSemMutexRequestNoResume(hMutexSem, cMillies);
+}
+
+
+RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ if (pThis->OwnerId != find_thread(NULL))
+ return VERR_INVALID_HANDLE;
+
+ if (--pThis->cRecursion == 0)
+ {
+ pThis->OwnerId == -1;
+ release_sem(pThis->SemId);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ AssertPtrReturn(pThis, false);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), false);
+
+ return pThis->OwnerId != -1;
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/spinlock-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/spinlock-r0drv-haiku.c
new file mode 100644
index 00000000..6ffed171
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/spinlock-r0drv-haiku.c
@@ -0,0 +1,146 @@
+/* $Id: spinlock-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Spinlocks, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/spinlock.h>
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+#include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/thread.h>
+
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Wrapper for the KSPIN_LOCK type.
+ */
+typedef struct RTSPINLOCKINTERNAL
+{
+ /** Spinlock magic value (RTSPINLOCK_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** Spinlock creation flags */
+ uint32_t fFlags;
+ /** Saved interrupt CPU status. */
+ cpu_status volatile fIntSaved;
+ /** The Haiku spinlock structure. */
+ spinlock hSpinLock;
+} RTSPINLOCKINTERNAL, *PRTSPINLOCKINTERNAL;
+
+
+
+RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char *pszName)
+{
+ RT_ASSERT_PREEMPTIBLE();
+ NOREF(pszName);
+
+ /*
+ * Allocate.
+ */
+ AssertCompile(sizeof(RTSPINLOCKINTERNAL) > sizeof(void *));
+ PRTSPINLOCKINTERNAL pSpinlockInt = (PRTSPINLOCKINTERNAL)RTMemAllocZ(sizeof(*pSpinlockInt));
+ if (RT_UNLIKELY(!pSpinlockInt))
+ return VERR_NO_MEMORY;
+
+ /*
+ * Initialize & return.
+ */
+ pSpinlockInt->u32Magic = RTSPINLOCK_MAGIC;
+ pSpinlockInt->fFlags = fFlags;
+ pSpinlockInt->fIntSaved = 0;
+ B_INITIALIZE_SPINLOCK(&pSpinlockInt->hSpinLock);
+
+ *pSpinlock = pSpinlockInt;
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSpinlockDestroy(RTSPINLOCK Spinlock)
+{
+ /*
+ * Validate input.
+ */
+ PRTSPINLOCKINTERNAL pSpinlockInt = (PRTSPINLOCKINTERNAL)Spinlock;
+ if (RT_UNLIKELY(!pSpinlockInt))
+ return VERR_INVALID_PARAMETER;
+ AssertMsgReturn(pSpinlockInt->u32Magic == RTSPINLOCK_MAGIC,
+ ("Invalid spinlock %p magic=%#x\n", pSpinlockInt, pSpinlockInt->u32Magic),
+ VERR_INVALID_PARAMETER);
+
+ /*
+ * Make the lock invalid and release the memory.
+ */
+ ASMAtomicIncU32(&pSpinlockInt->u32Magic);
+
+ B_INITIALIZE_SPINLOCK(&pSpinlockInt->hSpinLock);
+
+ RTMemFree(pSpinlockInt);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
+{
+ PRTSPINLOCKINTERNAL pSpinlockInt = (PRTSPINLOCKINTERNAL)Spinlock;
+ AssertPtr(pSpinlockInt);
+ Assert(pSpinlockInt->u32Magic == RTSPINLOCK_MAGIC);
+
+ /* Haiku cannot take spinlocks without disabling interrupts. Ignore our spinlock creation flags. */
+ pSpinlockInt->fIntSaved = disable_interrupts();
+ acquire_spinlock(&pSpinlockInt->hSpinLock);
+}
+
+
+RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
+{
+ PRTSPINLOCKINTERNAL pSpinlockInt = (PRTSPINLOCKINTERNAL)Spinlock;
+ AssertPtr(pSpinlockInt);
+ Assert(pSpinlockInt->u32Magic == RTSPINLOCK_MAGIC);
+
+ release_spinlock(&pSpinlockInt->hSpinLock);
+ restore_interrupts(pSpinlockInt->fIntSaved);
+}
+
+
+RTDECL(void) RTSpinlockReleaseNoInts(RTSPINLOCK Spinlock)
+{
+ if (!(Spinlock->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE))
+ RTAssertMsg2("RTSpinlockReleaseNoInts: p=%p (magic=%#x)\n", Spinlock, Spinlock->u32Magic);
+ RTSpinlockRelease(Spinlock);
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/the-haiku-kernel.h b/src/VBox/Runtime/r0drv/haiku/the-haiku-kernel.h
new file mode 100644
index 00000000..d75a163b
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/the-haiku-kernel.h
@@ -0,0 +1,114 @@
+/* $Id: the-haiku-kernel.h $ */
+/** @file
+ * IPRT - Include all necessary headers for the Haiku kernel.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___the_haiku_kernel_h
+#define ___the_haiku_kernel_h
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <stdlib.h>
+
+#include <OS.h>
+#include <KernelExport.h>
+
+#include <iprt/cdefs.h>
+#include <iprt/err.h>
+#include <iprt/types.h>
+
+RT_C_DECLS_BEGIN
+
+/* headers/private/kernel/smp.h */
+
+extern int32 smp_get_num_cpus(void);
+extern int32 smp_get_current_cpu(void);
+
+/* headers/private/kernel/vm/vm.h */
+extern status_t vm_unreserve_address_range(team_id team, void *address, addr_t size);
+extern status_t vm_reserve_address_range(team_id team, void **_address, uint32 addressSpec, addr_t size, uint32 flags);
+extern area_id vm_clone_area(team_id team, const char *name, void **address, uint32 addressSpec, uint32 protection,
+ uint32 mapping, area_id sourceArea, bool kernel);
+
+/* headers/private/kernel/thread_type.h */
+
+extern spinlock gThreadSpinlock;
+#define GRAB_THREAD_LOCK() acquire_spinlock(&gThreadSpinlock)
+#define RELEASE_THREAD_LOCK() release_spinlock(&gThreadSpinlock)
+typedef struct
+{
+ int32 flags; /* summary of events relevant in interrupt handlers (signals pending, user debugging
+ enabled, etc.) */
+#if 0
+ Thread *all_next;
+ Thread *team_next;
+ Thread *queue_next; /* i.e. run queue, release queue, etc. */
+ timer alarm;
+ thread_id id;
+ char name[B_OS_NAME_LENGTH];
+ int32 priority;
+ int32 next_priority;
+ int32 io_priority;
+ int32 state;
+ int32 next_state;
+#endif
+ // and a lot more...
+} Thread;
+
+/* headers/private/kernel/thread.h */
+
+extern Thread* thread_get_thread_struct(thread_id id);
+extern Thread* thread_get_thread_struct_locked(thread_id id);
+
+extern void thread_yield(bool force);
+
+RT_C_DECLS_END
+
+/**
+ * Convert from Haiku kernel return code to IPRT status code.
+ * @todo put this where it belongs! (i.e. in a separate file and prototype in iprt/err.h)
+ * Or as generic call since it's not r0 specific.
+ */
+DECLINLINE(int) RTErrConvertFromHaikuKernReturn(status_t rc)
+{
+ switch (rc)
+ {
+ case B_OK: return VINF_SUCCESS;
+ case B_BAD_SEM_ID: return VERR_SEM_ERROR;
+ case B_NO_MORE_SEMS: return VERR_TOO_MANY_SEMAPHORES;
+ case B_BAD_THREAD_ID: return VERR_INVALID_PARAMETER;
+ case B_NO_MORE_THREADS: return VERR_MAX_THRDS_REACHED;
+ case B_BAD_TEAM_ID: return VERR_INVALID_PARAMETER;
+ case B_NO_MORE_TEAMS: return VERR_MAX_PROCS_REACHED;
+ //default: return VERR_GENERAL_FAILURE;
+ /** POSIX Errors are defined as a subset of system errors. */
+ default: return RTErrConvertFromErrno(rc);
+ }
+}
+
+#endif /* ___the_haiku_kernel_h */
+
diff --git a/src/VBox/Runtime/r0drv/haiku/thread-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/thread-r0drv-haiku.c
new file mode 100644
index 00000000..97766d3f
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/thread-r0drv-haiku.c
@@ -0,0 +1,127 @@
+/* $Id: thread-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Threads, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/thread.h>
+
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+#include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mp.h>
+
+
+RTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void)
+{
+ return (RTNATIVETHREAD)find_thread(NULL);
+}
+
+
+RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies)
+{
+ RT_ASSERT_PREEMPTIBLE();
+ snooze((bigtime_t)cMillies * 1000);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(bool) RTThreadYield(void)
+{
+ RT_ASSERT_PREEMPTIBLE();
+ //FIXME
+ //snooze(0);
+ thread_yield(true);
+ return true; /* this is fishy */
+}
+
+
+RTDECL(bool) RTThreadPreemptIsEnabled(RTTHREAD hThread)
+{
+ Assert(hThread == NIL_RTTHREAD);
+
+ //XXX: can't do this, it might actually be held by another cpu
+ //return !B_SPINLOCK_IS_LOCKED(&gThreadSpinlock);
+ return ASMIntAreEnabled(); /** @todo find a better way. */
+}
+
+
+RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread)
+{
+ Assert(hThread == NIL_RTTHREAD);
+ /** @todo check if Thread::next_priority or
+ * cpu_ent::invoke_scheduler could do. */
+ return false;
+}
+
+
+RTDECL(bool) RTThreadPreemptIsPendingTrusty(void)
+{
+ /* RTThreadPreemptIsPending is not reliable yet. */
+ return false;
+}
+
+
+RTDECL(bool) RTThreadPreemptIsPossible(void)
+{
+ /* yes, kernel preemption is possible. */
+ return true;
+}
+
+
+RTDECL(void) RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState)
+{
+ AssertPtr(pState);
+ Assert(pState->uOldCpuState == 0);
+
+ pState->uOldCpuState = (uint32_t)disable_interrupts();
+ RT_ASSERT_PREEMPT_CPUID_DISABLE(pState);
+}
+
+
+RTDECL(void) RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState)
+{
+ AssertPtr(pState);
+
+ RT_ASSERT_PREEMPT_CPUID_RESTORE(pState);
+ restore_interrupts((cpu_status)pState->uOldCpuState);
+ pState->uOldCpuState = 0;
+}
+
+
+RTDECL(bool) RTThreadIsInInterrupt(RTTHREAD hThread)
+{
+ Assert(hThread == NIL_RTTHREAD); NOREF(hThread);
+ /** @todo Implement RTThreadIsInInterrupt. Required for guest
+ * additions! */
+ return !ASMIntAreEnabled();
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/thread2-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/thread2-r0drv-haiku.c
new file mode 100644
index 00000000..f4c4a471
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/thread2-r0drv-haiku.c
@@ -0,0 +1,131 @@
+/* $Id: thread2-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Threads (Part 2), Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/thread.h>
+
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+#include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include "internal/thread.h"
+
+
+int rtThreadNativeInit(void)
+{
+ /* No TLS in Ring-0. :-/ */
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(RTTHREAD) RTThreadSelf(void)
+{
+ return rtThreadGetByNative((RTNATIVETHREAD)find_thread(NULL));
+}
+
+
+int rtThreadNativeSetPriority(PRTTHREADINT pThread, RTTHREADTYPE enmType)
+{
+ int32 iPriority;
+ status_t status;
+
+ /*
+ * Convert the priority type to native priorities.
+ * (This is quite naive but should be ok.)
+ */
+ switch (enmType)
+ {
+ case RTTHREADTYPE_INFREQUENT_POLLER: iPriority = B_LOWEST_ACTIVE_PRIORITY; break;
+ case RTTHREADTYPE_EMULATION: iPriority = B_LOW_PRIORITY; break;
+ case RTTHREADTYPE_DEFAULT: iPriority = B_NORMAL_PRIORITY; break;
+ case RTTHREADTYPE_MSG_PUMP: iPriority = B_DISPLAY_PRIORITY; break;
+ case RTTHREADTYPE_IO: iPriority = B_URGENT_DISPLAY_PRIORITY; break;
+ case RTTHREADTYPE_TIMER: iPriority = B_REAL_TIME_DISPLAY_PRIORITY; break;
+ default:
+ AssertMsgFailed(("enmType=%d\n", enmType));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ status = set_thread_priority((thread_id)pThread->Core.Key, iPriority);
+
+ return RTErrConvertFromHaikuKernReturn(status);
+}
+
+
+int rtThreadNativeAdopt(PRTTHREADINT pThread)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+void rtThreadNativeDestroy(PRTTHREADINT pThread)
+{
+ NOREF(pThread);
+}
+
+
+/**
+ * Native kernel thread wrapper function.
+ *
+ * This will forward to rtThreadMain and do termination upon return.
+ *
+ * @param pvArg Pointer to the argument package.
+ * @param Ignored Wait result, which we ignore.
+ */
+static status_t rtThreadNativeMain(void *pvArg)
+{
+ const thread_id Self = find_thread(NULL);
+ PRTTHREADINT pThread = (PRTTHREADINT)pvArg;
+
+ int rc = rtThreadMain(pThread, (RTNATIVETHREAD)Self, &pThread->szName[0]);
+
+ if (rc < 0)
+ return RTErrConvertFromHaikuKernReturn(rc);
+ return rc;
+}
+
+
+int rtThreadNativeCreate(PRTTHREADINT pThreadInt, PRTNATIVETHREAD pNativeThread)
+{
+ thread_id NativeThread;
+ RT_ASSERT_PREEMPTIBLE();
+
+ NativeThread = spawn_kernel_thread(rtThreadNativeMain, pThreadInt->szName, B_NORMAL_PRIORITY, pThreadInt);
+ if (NativeThread >= B_OK)
+ {
+ resume_thread(NativeThread);
+ *pNativeThread = (RTNATIVETHREAD)NativeThread;
+ return VINF_SUCCESS;
+ }
+ return RTErrConvertFromHaikuKernReturn(NativeThread);
+}
+
diff --git a/src/VBox/Runtime/r0drv/haiku/time-r0drv-haiku.c b/src/VBox/Runtime/r0drv/haiku/time-r0drv-haiku.c
new file mode 100644
index 00000000..889ac193
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/haiku/time-r0drv-haiku.c
@@ -0,0 +1,79 @@
+/* $Id: time-r0drv-haiku.c $ */
+/** @file
+ * IPRT - Time, Ring-0 Driver, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_TIME
+#include "the-haiku-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/time.h>
+
+#include <iprt/asm.h>
+
+
+DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void)
+{
+ return system_time() * 1000;
+}
+
+
+DECLINLINE(uint64_t) rtTimeGetSystemMilliTS(void)
+{
+ return system_time() / 1000;
+}
+
+
+RTDECL(uint64_t) RTTimeNanoTS(void)
+{
+ return rtTimeGetSystemNanoTS();
+}
+
+
+RTDECL(uint64_t) RTTimeMilliTS(void)
+{
+ return rtTimeGetSystemMilliTS();
+}
+
+
+RTDECL(uint64_t) RTTimeSystemNanoTS(void)
+{
+ return rtTimeGetSystemNanoTS();
+}
+
+
+RTDECL(uint64_t) RTTimeSystemMilliTS(void)
+{
+ return rtTimeGetSystemMilliTS();
+}
+
+
+RTDECL(PRTTIMESPEC) RTTimeNow(PRTTIMESPEC pTime)
+{
+ return RTTimeSpecSetNano(pTime, real_time_clock_usecs() * 1000);
+}
+
diff --git a/src/VBox/Runtime/r0drv/initterm-r0drv.cpp b/src/VBox/Runtime/r0drv/initterm-r0drv.cpp
index 09929142..db963feb 100644
--- a/src/VBox/Runtime/r0drv/initterm-r0drv.cpp
+++ b/src/VBox/Runtime/r0drv/initterm-r0drv.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -64,6 +64,7 @@ static int32_t volatile g_crtR0Users = 0;
RTR0DECL(int) RTR0Init(unsigned fReserved)
{
int rc;
+ uint32_t cNewUsers;
Assert(fReserved == 0);
RT_ASSERT_PREEMPTIBLE();
@@ -72,8 +73,14 @@ RTR0DECL(int) RTR0Init(unsigned fReserved)
* We rely on the module loader to ensure that there are no
* initialization races should two modules share the IPRT.
*/
- if (ASMAtomicIncS32(&g_crtR0Users) != 1)
- return VINF_SUCCESS;
+ cNewUsers = ASMAtomicIncS32(&g_crtR0Users);
+ if (cNewUsers != 1)
+ {
+ if (cNewUsers > 1)
+ return VINF_SUCCESS;
+ ASMAtomicDecS32(&g_crtR0Users);
+ return VERR_INTERNAL_ERROR_3;
+ }
rc = rtR0InitNative();
if (RT_SUCCESS(rc))
@@ -126,6 +133,8 @@ RTR0DECL(void) RTR0Term(void)
Assert(cNewUsers >= 0);
if (cNewUsers == 0)
rtR0Term();
+ else if (cNewUsers < 0)
+ ASMAtomicIncS32(&g_crtR0Users);
}
RT_EXPORT_SYMBOL(RTR0Term);
@@ -134,7 +143,9 @@ RT_EXPORT_SYMBOL(RTR0Term);
RTR0DECL(void) RTR0TermForced(void)
{
RT_ASSERT_PREEMPTIBLE();
+
AssertMsg(g_crtR0Users == 1, ("%d\n", g_crtR0Users));
+ ASMAtomicWriteS32(&g_crtR0Users, 0);
rtR0Term();
}
diff --git a/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c
index 144d637e..c34f8543 100644
--- a/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
index 2f597651..21e124bd 100644
--- a/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -173,7 +173,7 @@ static PRTMEMHDR rtR0MemAllocExecVmArea(size_t cb)
for (iPage = 0; iPage < cPages; iPage++)
{
- papPages[iPage] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ papPages[iPage] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN);
if (!papPages[iPage])
break;
}
@@ -383,15 +383,15 @@ RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
cOrder = CalcPowerOf2Order(cPages);
#if (defined(RT_ARCH_AMD64) || defined(CONFIG_X86_PAE)) && defined(GFP_DMA32)
/* ZONE_DMA32: 0-4GB */
- paPages = alloc_pages(GFP_DMA32, cOrder);
+ paPages = alloc_pages(GFP_DMA32 | __GFP_NOWARN, cOrder);
if (!paPages)
#endif
#ifdef RT_ARCH_AMD64
/* ZONE_DMA; 0-16MB */
- paPages = alloc_pages(GFP_DMA, cOrder);
+ paPages = alloc_pages(GFP_DMA | __GFP_NOWARN, cOrder);
#else
/* ZONE_NORMAL: 0-896MB */
- paPages = alloc_pages(GFP_USER, cOrder);
+ paPages = alloc_pages(GFP_USER | __GFP_NOWARN, cOrder);
#endif
if (paPages)
{
diff --git a/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c
index 2a7fef9f..11b3a27e 100644
--- a/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c
index 5cf9ad66..fda6e35f 100644
--- a/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
index e21af78c..2840dd4d 100644
--- a/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
@@ -1,10 +1,10 @@
-/* $Revision: 81432 $ */
+/* $Revision: 91595 $ */
/** @file
* IPRT - Ring-0 Memory Objects, Linux.
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -320,9 +320,9 @@ static int rtR0MemObjLinuxAllocPages(PRTR0MEMOBJLNX *ppMemLnx, RTR0MEMOBJTYPE en
|| cb <= PAGE_SIZE * 2)
{
# ifdef VBOX_USE_INSERT_PAGE
- paPages = alloc_pages(fFlagsLnx | __GFP_COMP, rtR0MemObjLinuxOrder(cPages));
+ paPages = alloc_pages(fFlagsLnx | __GFP_COMP | __GFP_NOWARN, rtR0MemObjLinuxOrder(cPages));
# else
- paPages = alloc_pages(fFlagsLnx, rtR0MemObjLinuxOrder(cPages));
+ paPages = alloc_pages(fFlagsLnx | __GFP_NOWARN, rtR0MemObjLinuxOrder(cPages));
# endif
if (paPages)
{
@@ -341,7 +341,7 @@ static int rtR0MemObjLinuxAllocPages(PRTR0MEMOBJLNX *ppMemLnx, RTR0MEMOBJTYPE en
{
for (iPage = 0; iPage < cPages; iPage++)
{
- pMemLnx->apPages[iPage] = alloc_page(fFlagsLnx);
+ pMemLnx->apPages[iPage] = alloc_page(fFlagsLnx | __GFP_NOWARN);
if (RT_UNLIKELY(!pMemLnx->apPages[iPage]))
{
while (iPage-- > 0)
@@ -1170,7 +1170,7 @@ DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *
* Allocate a dummy page and create a page pointer array for vmap such that
* the dummy page is mapped all over the reserved area.
*/
- pDummyPage = alloc_page(GFP_HIGHUSER);
+ pDummyPage = alloc_page(GFP_HIGHUSER | __GFP_NOWARN);
if (!pDummyPage)
return VERR_NO_MEMORY;
papPages = RTMemAlloc(sizeof(*papPages) * cPages);
@@ -1407,7 +1407,7 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
/*
* Allocate a dummy page for use when mapping the memory.
*/
- pDummyPage = alloc_page(GFP_USER);
+ pDummyPage = alloc_page(GFP_USER | __GFP_NOWARN);
if (!pDummyPage)
return VERR_NO_MEMORY;
SetPageReserved(pDummyPage);
@@ -1527,6 +1527,25 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
}
}
+#ifdef CONFIG_NUMA_BALANCING
+ if (RT_SUCCESS(rc))
+ {
+ /** @todo Ugly hack! But right now we have no other means to disable
+ * automatic NUMA page balancing. */
+# ifdef RT_OS_X86
+# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ pTask->mm->numa_next_reset = jiffies + 0x7fffffffUL;
+# endif
+ pTask->mm->numa_next_scan = jiffies + 0x7fffffffUL;
+# else
+# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ pTask->mm->numa_next_reset = jiffies + 0x7fffffffffffffffUL;
+# endif
+ pTask->mm->numa_next_scan = jiffies + 0x7fffffffffffffffUL;
+# endif
+ }
+#endif
+
up_write(&pTask->mm->mmap_sem);
if (RT_SUCCESS(rc))
diff --git a/src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c
index 55431c99..211fc361 100644
--- a/src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c
index 32ab1234..88971ac5 100644
--- a/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c
index b2a6ab9c..687f3bbd 100644
--- a/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/process-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/process-r0drv-linux.c
index e69aeace..ce2fe313 100644
--- a/src/VBox/Runtime/r0drv/linux/process-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/process-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c
index 2506adc8..9c4c131f 100644
--- a/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c
index 74cc3900..702e1d00 100644
--- a/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
index 8297d6dd..25f07654 100644
--- a/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c
index 714bc35f..eb141e82 100644
--- a/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -93,6 +93,7 @@ RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char
pThis->idCpuOwner = NIL_RTCPUID;
pThis->idAssertCpu = NIL_RTCPUID;
#endif
+
spin_lock_init(&pThis->Spinlock);
*pSpinlock = pThis;
@@ -129,6 +130,9 @@ RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
AssertMsg(pThis && pThis->u32Magic == RTSPINLOCK_MAGIC,
("pThis=%p u32Magic=%08x\n", pThis, pThis ? (int)pThis->u32Magic : 0));
+#if defined(CONFIG_PROVE_LOCKING) && !defined(RT_STRICT)
+ lockdep_off();
+#endif
if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
{
unsigned long fIntSaved;
@@ -137,6 +141,9 @@ RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
}
else
spin_lock(&pThis->Spinlock);
+#if defined(CONFIG_PROVE_LOCKING) && !defined(RT_STRICT)
+ lockdep_on();
+#endif
RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED(pThis);
}
@@ -151,6 +158,9 @@ RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
("pThis=%p u32Magic=%08x\n", pThis, pThis ? (int)pThis->u32Magic : 0));
RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE(pThis);
+#if defined(CONFIG_PROVE_LOCKING) && !defined(RT_STRICT)
+ lockdep_off();
+#endif
if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
{
unsigned long fIntSaved = pThis->fIntSaved;
@@ -159,6 +169,9 @@ RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
}
else
spin_unlock(&pThis->Spinlock);
+#if defined(CONFIG_PROVE_LOCKING) && !defined(RT_STRICT)
+ lockdep_on();
+#endif
RT_ASSERT_PREEMPT_CPUID();
}
diff --git a/src/VBox/Runtime/r0drv/linux/string.h b/src/VBox/Runtime/r0drv/linux/string.h
index f2f31941..2314d13c 100644
--- a/src/VBox/Runtime/r0drv/linux/string.h
+++ b/src/VBox/Runtime/r0drv/linux/string.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h b/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
index eebf6734..a1791eea 100644
--- a/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
+++ b/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -90,6 +90,9 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/sched.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+# include <linux/sched/rt.h>
+#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7)
# include <linux/jiffies.h>
#endif
@@ -121,6 +124,11 @@
#include <asm/uaccess.h>
#include <asm/div64.h>
+/* For thread-context hooks. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) && defined(CONFIG_PREEMPT_NOTIFIERS)
+# include <linux/preempt.h>
+#endif
+
/* for workqueue / task queues. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
# include <linux/workqueue.h>
@@ -142,6 +150,10 @@
# define DEFINE_WAIT(name) DECLARE_WAITQUEUE(name, current)
#endif
+#ifndef __GFP_NOWARN
+# define __GFP_NOWARN 0
+#endif
+
/*
* 2.4 / early 2.6 compatibility wrappers
*/
diff --git a/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c
index ecd53717..d5b69d62 100644
--- a/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -87,6 +87,7 @@ RTDECL(bool) RTThreadYield(void)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20)
yield();
#else
+ /** @todo r=ramshankar: Can we use cond_resched() instead? */
set_current_state(TASK_RUNNING);
sys_sched_yield();
schedule();
@@ -159,6 +160,8 @@ RT_EXPORT_SYMBOL(RTThreadPreemptIsPendingTrusty);
RTDECL(bool) RTThreadPreemptIsPossible(void)
{
+ /** @todo r=ramshankar: What about CONFIG_PREEMPT_VOLUNTARY? That can preempt
+ * too but does so in voluntarily in explicit preemption points. */
#ifdef CONFIG_PREEMPT
return true; /* yes, kernel preemption is possible. */
#else
@@ -174,6 +177,7 @@ RTDECL(void) RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState)
AssertPtr(pState);
Assert(pState->u32Reserved == 0);
pState->u32Reserved = 42;
+ /* This ASSUMES that CONFIG_PREEMPT_COUNT is always defined with CONFIG_PREEMPT. */
preempt_disable();
RT_ASSERT_PREEMPT_CPUID_DISABLE(pState);
diff --git a/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c
index a9561c42..01956565 100644
--- a/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c
new file mode 100644
index 00000000..c0b39371
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c
@@ -0,0 +1,330 @@
+/* $Id: threadctxhooks-r0drv-linux.c $ */
+/** @file
+ * IPRT - Thread-Context Hook, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/mem.h>
+#include <iprt/assert.h>
+#include <iprt/thread.h>
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include "internal/thread.h"
+
+/*
+ * Linux kernel 2.6.23 introduced thread-context hooks but RedHat 2.6.18 kernels
+ * got it backported.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) && defined(CONFIG_PREEMPT_NOTIFIERS)
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * The internal thread-context object.
+ */
+typedef struct RTTHREADCTXINT
+{
+ /** Magic value (RTTHREADCTXINT_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** The thread handle (owner) for which the context-hooks are registered. */
+ RTNATIVETHREAD hOwner;
+ /** The preemption notifier object. */
+ struct preempt_notifier hPreemptNotifier;
+ /** Whether this handle has any hooks registered or not. */
+ bool fRegistered;
+ /** Pointer to the registered thread-context hook. */
+ PFNRTTHREADCTXHOOK pfnThreadCtxHook;
+ /** User argument passed to the thread-context hook. */
+ void *pvUser;
+ /** The thread-context operations. */
+ struct preempt_ops hPreemptOps;
+ /** The reference count for this object. */
+ uint32_t volatile cRefs;
+} RTTHREADCTXINT, *PRTTHREADCTXINT;
+
+
+/**
+ * Hook function for the thread-preempting event.
+ *
+ * @param pPreemptNotifier Pointer to the preempt_notifier struct.
+ * @param pNext Pointer to the task that is preempting the
+ * current thread.
+ *
+ * @remarks Called with the rq (runqueue) lock held and with preemption and
+ * interrupts disabled!
+ */
+static void rtThreadCtxHooksLnxSchedOut(struct preempt_notifier *pPreemptNotifier, struct task_struct *pNext)
+{
+ PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
+ AssertPtr(pThis);
+ AssertPtr(pThis->pfnThreadCtxHook);
+ Assert(pThis->fRegistered);
+ Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
+ pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_PREEMPTING, pThis->pvUser);
+}
+
+
+/**
+ * Hook function for the thread-resumed event.
+ *
+ * @param pPreemptNotifier Pointer to the preempt_notifier struct.
+ * @param iCpu The CPU this thread is scheduled on.
+ *
+ * @remarks Called without holding the rq (runqueue) lock and with preemption
+ * enabled!
+ */
+static void rtThreadCtxHooksLnxSchedIn(struct preempt_notifier *pPreemptNotifier, int iCpu)
+{
+ PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
+ AssertPtr(pThis);
+ AssertPtr(pThis->pfnThreadCtxHook);
+ Assert(pThis->fRegistered);
+
+ pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_RESUMED, pThis->pvUser);
+}
+
+
+/**
+ * Worker function for RTThreadCtxHooks(Deregister|Release)().
+ *
+ * @param pThis Pointer to the internal thread-context object.
+ */
+DECLINLINE(void) rtThreadCtxHooksDeregister(PRTTHREADCTXINT pThis)
+{
+ preempt_notifier_unregister(&pThis->hPreemptNotifier);
+ pThis->hPreemptOps.sched_out = NULL;
+ pThis->hPreemptOps.sched_in = NULL;
+ pThis->fRegistered = false;
+}
+
+
+RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
+{
+ PRTTHREADCTXINT pThis;
+ Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
+ pThis = (PRTTHREADCTXINT)RTMemAllocZ(sizeof(*pThis));
+ if (RT_UNLIKELY(!pThis))
+ return VERR_NO_MEMORY;
+ pThis->u32Magic = RTTHREADCTXINT_MAGIC;
+ pThis->hOwner = RTThreadNativeSelf();
+ pThis->fRegistered = false;
+ preempt_notifier_init(&pThis->hPreemptNotifier, &pThis->hPreemptOps);
+ pThis->cRefs = 1;
+
+ *phThreadCtx = pThis;
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
+
+
+RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
+{
+ /*
+ * Validate input.
+ */
+ uint32_t cRefs;
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ AssertPtr(pThis);
+ AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
+ UINT32_MAX);
+
+ cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs < UINT32_MAX / 2);
+ return cRefs;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
+
+
+
+RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
+{
+ /*
+ * Validate input.
+ */
+ uint32_t cRefs;
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ if (pThis == NIL_RTTHREADCTX)
+ return 0;
+
+ AssertPtr(pThis);
+ AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
+ UINT32_MAX);
+ Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
+ cRefs = ASMAtomicDecU32(&pThis->cRefs);
+ if (!cRefs)
+ {
+ /*
+ * If there's still a registered thread-context hook, deregister it now before destroying the object.
+ */
+ if (pThis->fRegistered)
+ rtThreadCtxHooksDeregister(pThis);
+
+ /*
+ * Paranoia... but since these are ring-0 threads we can't be too careful.
+ */
+ Assert(!pThis->fRegistered);
+ Assert(!pThis->hPreemptOps.sched_out);
+ Assert(!pThis->hPreemptOps.sched_in);
+
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
+ RTMemFree(pThis);
+ }
+ else
+ Assert(cRefs < UINT32_MAX / 2);
+
+ return cRefs;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
+
+
+RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
+{
+ /*
+ * Validate input.
+ */
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ if (pThis == NIL_RTTHREADCTX)
+ return VERR_INVALID_HANDLE;
+ AssertPtr(pThis);
+ AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
+ VERR_INVALID_HANDLE);
+ Assert(pThis->hOwner == RTThreadNativeSelf());
+ Assert(!pThis->hPreemptOps.sched_out);
+ Assert(!pThis->hPreemptOps.sched_in);
+
+ /*
+ * Register the callback.
+ */
+ pThis->hPreemptOps.sched_out = rtThreadCtxHooksLnxSchedOut;
+ pThis->hPreemptOps.sched_in = rtThreadCtxHooksLnxSchedIn;
+ pThis->pvUser = pvUser;
+ pThis->pfnThreadCtxHook = pfnThreadCtxHook;
+ pThis->fRegistered = true;
+ preempt_notifier_register(&pThis->hPreemptNotifier);
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
+
+
+RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
+{
+ /*
+ * Validate input.
+ */
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ if (pThis == NIL_RTTHREADCTX)
+ return VERR_INVALID_HANDLE;
+ AssertPtr(pThis);
+ AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
+ VERR_INVALID_HANDLE);
+ Assert(pThis->hOwner == RTThreadNativeSelf());
+ Assert(pThis->fRegistered);
+
+ /*
+ * Deregister the callback.
+ */
+ rtThreadCtxHooksDeregister(pThis);
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
+
+
+RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
+{
+ /*
+ * Validate input.
+ */
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ if (pThis == NIL_RTTHREADCTX)
+ return false;
+ AssertPtr(pThis);
+ AssertMsg(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
+
+ return pThis->fRegistered;
+}
+
+#else /* Not supported / Not needed */
+
+RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
+{
+ NOREF(phThreadCtx);
+ return VERR_NOT_SUPPORTED;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
+
+
+RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
+{
+ NOREF(hThreadCtx);
+ return UINT32_MAX;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
+
+
+RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
+{
+ NOREF(hThreadCtx);
+ return UINT32_MAX;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
+
+
+RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
+{
+ NOREF(hThreadCtx);
+ NOREF(pfnThreadCtxHook);
+ NOREF(pvUser);
+ return VERR_NOT_SUPPORTED;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
+
+
+RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
+{
+ NOREF(hThreadCtx);
+ return VERR_NOT_SUPPORTED;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
+
+
+RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
+{
+ NOREF(hThreadCtx);
+ return false;
+}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksAreRegistered);
+
+#endif /* Not supported / Not needed */
+
diff --git a/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c
index c0fb357f..cd2e70f1 100644
--- a/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c
index 710a0489..b5c875d3 100644
--- a/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -1557,7 +1557,7 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
*/
if (cCpus > 1)
{
- int rc = RTSpinlockCreate(&pTimer->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "RTTimerLnx");
+ int rc = RTSpinlockCreate(&pTimer->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTTimerLnx");
if (RT_SUCCESS(rc))
rc = RTMpNotificationRegister(rtTimerLinuxMpEvent, pTimer);
else
diff --git a/src/VBox/Runtime/r0drv/memobj-r0drv.cpp b/src/VBox/Runtime/r0drv/memobj-r0drv.cpp
index 622406e4..2d5c85c9 100644
--- a/src/VBox/Runtime/r0drv/memobj-r0drv.cpp
+++ b/src/VBox/Runtime/r0drv/memobj-r0drv.cpp
@@ -1,10 +1,10 @@
-/* $Revision: 77489 $ */
+/* $Revision: 89632 $ */
/** @file
* IPRT - Ring-0 Memory Objects, Common Code.
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -264,6 +264,12 @@ RT_EXPORT_SYMBOL(RTR0MemObjSize);
* @param MemObj The ring-0 memory object handle.
* @param iPage The page number within the object.
*/
+/* Work around gcc bug 55940 */
+#if defined(__GNUC__) && defined(RT_ARCH_X86)
+# if (__GNUC__ * 100 + __GNUC_MINOR__) == 407
+ __attribute__((__optimize__ ("no-shrink-wrap")))
+# endif
+#endif
RTR0DECL(RTHCPHYS) RTR0MemObjGetPagePhysAddr(RTR0MEMOBJ MemObj, size_t iPage)
{
/* Validate the object handle. */
diff --git a/src/VBox/Runtime/r0drv/mp-r0drv.h b/src/VBox/Runtime/r0drv/mp-r0drv.h
index 807ef642..0166cef3 100644
--- a/src/VBox/Runtime/r0drv/mp-r0drv.h
+++ b/src/VBox/Runtime/r0drv/mp-r0drv.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/mpnotification-r0drv.c b/src/VBox/Runtime/r0drv/mpnotification-r0drv.c
index b42be8c9..612ca01b 100644
--- a/src/VBox/Runtime/r0drv/mpnotification-r0drv.c
+++ b/src/VBox/Runtime/r0drv/mpnotification-r0drv.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -276,7 +276,7 @@ RT_EXPORT_SYMBOL(RTMpNotificationDeregister);
DECLHIDDEN(int) rtR0MpNotificationInit(void)
{
- int rc = RTSpinlockCreate((PRTSPINLOCK)&g_hRTMpNotifySpinLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "RTR0Mp");
+ int rc = RTSpinlockCreate((PRTSPINLOCK)&g_hRTMpNotifySpinLock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTR0Mp");
if (RT_SUCCESS(rc))
{
rc = rtR0MpNotificationNativeInit();
diff --git a/src/VBox/Runtime/r0drv/nt/RTLogWriteDebugger-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/RTLogWriteDebugger-r0drv-nt.cpp
index 95d6a112..0342dbd7 100644
--- a/src/VBox/Runtime/r0drv/nt/RTLogWriteDebugger-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/RTLogWriteDebugger-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/alloc-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/alloc-r0drv-nt.cpp
index 10b15115..e8720347 100644
--- a/src/VBox/Runtime/r0drv/nt/alloc-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/alloc-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/assert-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/assert-r0drv-nt.cpp
index 63728663..df6b5483 100644
--- a/src/VBox/Runtime/r0drv/nt/assert-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/assert-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp
index 7f0d2153..a199e135 100644
--- a/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -35,12 +35,14 @@
#include <iprt/string.h>
#include "internal/initterm.h"
#include "internal-r0drv-nt.h"
+#include "symdb.h"
+#include "symdbdata.h"
/*******************************************************************************
* Global Variables *
*******************************************************************************/
-/** The Nt CPU set.
+/** The NT CPU set.
* KeQueryActiveProcssors() cannot be called at all IRQLs and therefore we'll
* have to cache it. Fortunately, Nt doesn't really support taking CPUs offline
* or online. It's first with W2K8 that support for CPU hotplugging was added.
@@ -61,6 +63,8 @@ PFNHALSENDSOFTWAREINTERRUPT g_pfnrtNtHalSendSoftwareInterrupt;
PFNRTSENDIPI g_pfnrtSendIpi;
/** KeIpiGenericCall - Windows Server 2003+ only */
PFNRTKEIPIGENERICCALL g_pfnrtKeIpiGenericCall;
+/** RtlGetVersion, introduced in ??. */
+PFNRTRTLGETVERSION g_pfnrtRtlGetVersion;
/** Offset of the _KPRCB::QuantumEnd field. 0 if not found. */
uint32_t g_offrtNtPbQuantumEnd;
@@ -70,6 +74,116 @@ uint32_t g_cbrtNtPbQuantumEnd;
uint32_t g_offrtNtPbDpcQueueDepth;
+/**
+ * Determines the NT kernel verison information.
+ *
+ * @param pOsVerInfo Where to return the version information.
+ *
+ * @remarks pOsVerInfo->fSmp is only definitive if @c true.
+ * @remarks pOsVerInfo->uCsdNo is set to MY_NIL_CSD if it cannot be determined.
+ */
+static void rtR0NtGetOsVersionInfo(PRTNTSDBOSVER pOsVerInfo)
+{
+ ULONG ulMajorVersion = 0;
+ ULONG ulMinorVersion = 0;
+ ULONG ulBuildNumber = 0;
+
+ pOsVerInfo->fChecked = PsGetVersion(&ulMajorVersion, &ulMinorVersion, &ulBuildNumber, NULL) == TRUE;
+ pOsVerInfo->uMajorVer = (uint8_t)ulMajorVersion;
+ pOsVerInfo->uMinorVer = (uint8_t)ulMinorVersion;
+ pOsVerInfo->uBuildNo = ulBuildNumber;
+#define MY_NIL_CSD 0x3f
+ pOsVerInfo->uCsdNo = MY_NIL_CSD;
+
+ if (g_pfnrtRtlGetVersion)
+ {
+ RTL_OSVERSIONINFOEXW VerInfo;
+ RT_ZERO(VerInfo);
+ VerInfo.dwOSVersionInfoSize = sizeof(VerInfo);
+
+ NTSTATUS rcNt = g_pfnrtRtlGetVersion(&VerInfo);
+ if (NT_SUCCESS(rcNt))
+ pOsVerInfo->uCsdNo = VerInfo.wServicePackMajor;
+ }
+
+ /* Note! We cannot quite say if something is MP or UNI. So, fSmp is
+ redefined to indicate that it must be MP. */
+ pOsVerInfo->fSmp = RTMpGetCount() > 1
+ || ulMajorVersion >= 6; /* Vista and later has no UNI kernel AFAIK. */
+}
+
+
+/**
+ * Tries a set against the current kernel.
+ *
+ * @retval @c true if it matched up, global variables are updated.
+ * @retval @c false otherwise (no globals updated).
+ * @param pSet The data set.
+ * @param pbPrcb Pointer to the processor control block.
+ * @param pszVendor Pointer to the processor vendor string.
+ * @param pOsVerInfo The OS version info.
+ */
+static bool rtR0NtTryMatchSymSet(PCRTNTSDBSET pSet, uint8_t *pbPrcb, const char *pszVendor, PCRTNTSDBOSVER pOsVerInfo)
+{
+ /*
+ * Don't bother trying stuff where the NT kernel version number differs, or
+ * if the build type or SMPness doesn't match up.
+ */
+ if ( pSet->OsVerInfo.uMajorVer != pOsVerInfo->uMajorVer
+ || pSet->OsVerInfo.uMinorVer != pOsVerInfo->uMinorVer
+ || pSet->OsVerInfo.fChecked != pOsVerInfo->fChecked
+ || (!pSet->OsVerInfo.fSmp && pOsVerInfo->fSmp /*must-be-smp*/) )
+ {
+ //DbgPrint("IPRT: #%d Version/type mismatch.\n", pSet - &g_artNtSdbSets[0]);
+ return false;
+ }
+
+ /*
+ * Do the CPU vendor test.
+ *
+ * Note! The MmIsAddressValid call is the real #PF security here as the
+ * __try/__except has limited/no ability to catch everything we need.
+ */
+ char *pszPrcbVendorString = (char *)&pbPrcb[pSet->KPRCB.offVendorString];
+ if (!MmIsAddressValid(&pszPrcbVendorString[4 * 3 - 1]))
+ {
+ //DbgPrint("IPRT: #%d invalid vendor string address.\n", pSet - &g_artNtSdbSets[0]);
+ return false;
+ }
+ __try
+ {
+ if (memcmp(pszPrcbVendorString, pszVendor, RT_MIN(4 * 3, pSet->KPRCB.cbVendorString)) != 0)
+ {
+ //DbgPrint("IPRT: #%d Vendor string mismatch.\n", pSet - &g_artNtSdbSets[0]);
+ return false;
+ }
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DbgPrint("IPRT: %#d Exception\n", pSet - &g_artNtSdbSets[0]);
+ return false;
+ }
+
+ /*
+ * Got a match, update the global variables and report succcess.
+ */
+ g_offrtNtPbQuantumEnd = pSet->KPRCB.offQuantumEnd;
+ g_cbrtNtPbQuantumEnd = pSet->KPRCB.cbQuantumEnd;
+ g_offrtNtPbDpcQueueDepth = pSet->KPRCB.offDpcQueueDepth;
+
+#if 0
+ DbgPrint("IPRT: Using data set #%u for %u.%usp%u build %u %s %s.\n",
+ pSet - &g_artNtSdbSets[0],
+ pSet->OsVerInfo.uMajorVer,
+ pSet->OsVerInfo.uMinorVer,
+ pSet->OsVerInfo.uCsdNo,
+ pSet->OsVerInfo.uBuildNo,
+ pSet->OsVerInfo.fSmp ? "smp" : "uni",
+ pSet->OsVerInfo.fChecked ? "checked" : "free");
+#endif
+ return true;
+}
+
DECLHIDDEN(int) rtR0InitNative(void)
{
@@ -91,6 +205,7 @@ DECLHIDDEN(int) rtR0InitNative(void)
g_pfnrtNtHalRequestIpi = NULL;
g_pfnrtNtHalSendSoftwareInterrupt = NULL;
g_pfnrtKeIpiGenericCall = NULL;
+ g_pfnrtRtlGetVersion = NULL;
#else
/*
* Initialize the function pointers.
@@ -110,35 +225,36 @@ DECLHIDDEN(int) rtR0InitNative(void)
RtlInitUnicodeString(&RoutineName, L"KeIpiGenericCall");
g_pfnrtKeIpiGenericCall = (PFNRTKEIPIGENERICCALL)MmGetSystemRoutineAddress(&RoutineName);
+
+ RtlInitUnicodeString(&RoutineName, L"RtlGetVersion");
+ g_pfnrtRtlGetVersion = (PFNRTRTLGETVERSION)MmGetSystemRoutineAddress(&RoutineName);
#endif
/*
- * Get some info that might come in handy below.
+ * HACK ALERT! (and déjà vu warning - remember win32k.sys?)
+ *
+ * Try find _KPRCB::QuantumEnd and _KPRCB::[DpcData.]DpcQueueDepth.
+ * For purpose of verification we use the VendorString member (12+1 chars).
+ *
+ * The offsets was initially derived by poking around with windbg
+ * (dt _KPRCB, !prcb ++, and such like). Systematic harvesting was then
+ * planned using dia2dump, grep and the symbol pack in a manner like this:
+ * dia2dump -type _KDPC_DATA -type _KPRCB EXE\ntkrnlmp.pdb | grep -wE "QuantumEnd|DpcData|DpcQueueDepth|VendorString"
+ *
+ * The final solution ended up using a custom harvester program called
+ * ntBldSymDb that recursively searches thru unpacked symbol packages for
+ * the desired structure offsets. The program assumes that the packages
+ * are unpacked into directories with the same name as the package, with
+ * exception of some of the w2k packages which requires a 'w2k' prefix to
+ * be distinguishable from another.
*/
- ULONG MajorVersion = 0;
- ULONG MinorVersion = 0;
- ULONG BuildNumber = 0;
- BOOLEAN fChecked = PsGetVersion(&MajorVersion, &MinorVersion, &BuildNumber, NULL);
- g_pfnrtSendIpi = rtMpSendIpiDummy;
-#ifndef IPRT_TARGET_NT4
- if ( g_pfnrtNtHalRequestIpi
- && MajorVersion == 6
- && MinorVersion == 0)
- {
- /* Vista or Windows Server 2008 */
- g_pfnrtSendIpi = rtMpSendIpiVista;
- }
- else
- if ( g_pfnrtNtHalSendSoftwareInterrupt
- && MajorVersion == 6
- && MinorVersion == 1)
- {
- /* Windows 7 or Windows Server 2008 R2 */
- g_pfnrtSendIpi = rtMpSendIpiWin7;
- }
- /* Windows XP should send always send an IPI -> VERIFY */
-#endif
+ RTNTSDBOSVER OsVerInfo;
+ rtR0NtGetOsVersionInfo(&OsVerInfo);
+
+ /*
+ * Gather consistent CPU vendor string and PRCB pointers.
+ */
KIRQL OldIrql;
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* make sure we stay on the same cpu */
@@ -150,115 +266,120 @@ DECLHIDDEN(int) rtR0InitNative(void)
ASMCpuId(0, &u.auRegs[3], &u.auRegs[0], &u.auRegs[2], &u.auRegs[1]);
u.szVendor[4*3] = '\0';
- /*
- * HACK ALERT (and déjà vu warning)!
- *
- * Try find _KPRCB::QuantumEnd and _KPRCB::[DpcData.]DpcQueueDepth.
- * For purpose of verification we use the VendorString member (12+1 chars).
- *
- * The offsets was initially derived by poking around with windbg
- * (dt _KPRCB, !prcb ++, and such like). Systematic harvesting is now done
- * by means of dia2dump, grep and the symbol packs. Typically:
- * dia2dump -type _KDPC_DATA -type _KPRCB EXE\ntkrnlmp.pdb | grep -wE "QuantumEnd|DpcData|DpcQueueDepth|VendorString"
- */
- /** @todo array w/ data + script for extracting a row. (save space + readability; table will be short.) */
- __try
+ uint8_t *pbPrcb;
+ __try /* Warning. This try/except statement may provide some false safety. */
{
#if defined(RT_ARCH_X86)
PKPCR pPcr = (PKPCR)__readfsdword(RT_OFFSETOF(KPCR,SelfPcr));
- uint8_t *pbPrcb = (uint8_t *)pPcr->Prcb;
-
- if ( BuildNumber == 2600 /* XP SP2 */
- && !memcmp(&pbPrcb[0x900], &u.szVendor[0], 4*3))
- {
- g_offrtNtPbQuantumEnd = 0x88c;
- g_cbrtNtPbQuantumEnd = 4;
- g_offrtNtPbDpcQueueDepth = 0x870;
- }
- /* WindowsVista.6002.090410-1830.x86fre.Symbols.exe
- WindowsVista.6002.090410-1830.x86chk.Symbols.exe
- WindowsVista.6002.090130-1715.x86fre.Symbols.exe
- WindowsVista.6002.090130-1715.x86chk.Symbols.exe */
- else if ( BuildNumber == 6002
- && !memcmp(&pbPrcb[0x1c2c], &u.szVendor[0], 4*3))
- {
- g_offrtNtPbQuantumEnd = 0x1a41;
- g_cbrtNtPbQuantumEnd = 1;
- g_offrtNtPbDpcQueueDepth = 0x19e0 + 0xc;
- }
- else if ( BuildNumber == 3790 /* Server 2003 SP2 */
- && !memcmp(&pbPrcb[0xb60], &u.szVendor[0], 4*3))
- {
- g_offrtNtPbQuantumEnd = 0x981;
- g_cbrtNtPbQuantumEnd = 1;
- g_offrtNtPbDpcQueueDepth = 0x920 + 0xc;
- }
-
- /** @todo more */
- //pbQuantumEnd = (uint8_t volatile *)pPcr->Prcb + 0x1a41;
-
+ pbPrcb = (uint8_t *)pPcr->Prcb;
#elif defined(RT_ARCH_AMD64)
PKPCR pPcr = (PKPCR)__readgsqword(RT_OFFSETOF(KPCR,Self));
- uint8_t *pbPrcb = (uint8_t *)pPcr->CurrentPrcb;
-
- if ( BuildNumber == 3790 /* XP64 / W2K3-AMD64 SP1 */
- && !memcmp(&pbPrcb[0x22b4], &u.szVendor[0], 4*3))
- {
- g_offrtNtPbQuantumEnd = 0x1f75;
- g_cbrtNtPbQuantumEnd = 1;
- g_offrtNtPbDpcQueueDepth = 0x1f00 + 0x18;
- }
- else if ( BuildNumber == 6000 /* Vista/AMD64 */
- && !memcmp(&pbPrcb[0x38bc], &u.szVendor[0], 4*3))
- {
- g_offrtNtPbQuantumEnd = 0x3375;
- g_cbrtNtPbQuantumEnd = 1;
- g_offrtNtPbDpcQueueDepth = 0x3300 + 0x18;
- }
- /* WindowsVista.6002.090410-1830.amd64fre.Symbols
- WindowsVista.6002.090130-1715.amd64fre.Symbols
- WindowsVista.6002.090410-1830.amd64chk.Symbols */
- else if ( BuildNumber == 6002
- && !memcmp(&pbPrcb[0x399c], &u.szVendor[0], 4*3))
- {
- g_offrtNtPbQuantumEnd = 0x3475;
- g_cbrtNtPbQuantumEnd = 1;
- g_offrtNtPbDpcQueueDepth = 0x3400 + 0x18;
- }
- /* Windows7.7600.16539.amd64fre.win7_gdr.100226-1909 */
- else if ( BuildNumber == 7600
- && !memcmp(&pbPrcb[0x4bb8], &u.szVendor[0], 4*3))
- {
- g_offrtNtPbQuantumEnd = 0x21d9;
- g_cbrtNtPbQuantumEnd = 1;
- g_offrtNtPbDpcQueueDepth = 0x2180 + 0x18;
- }
-
+ pbPrcb = (uint8_t *)pPcr->CurrentPrcb;
#else
# error "port me"
+ pbPrcb = NULL;
#endif
}
- __except(EXCEPTION_EXECUTE_HANDLER) /** @todo this handler doesn't seem to work... Because of Irql? */
+ __except(EXCEPTION_EXECUTE_HANDLER)
{
- g_offrtNtPbQuantumEnd = 0;
- g_cbrtNtPbQuantumEnd = 0;
- g_offrtNtPbDpcQueueDepth = 0;
+ pbPrcb = NULL;
}
- KeLowerIrql(OldIrql);
+ /*
+ * Search the database
+ */
+ if (pbPrcb)
+ {
+ /* Find the best matching kernel version based on build number. */
+ uint32_t iBest = UINT32_MAX;
+ int32_t iBestDelta = INT32_MAX;
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_artNtSdbSets); i++)
+ {
+ if (g_artNtSdbSets[i].OsVerInfo.fChecked != OsVerInfo.fChecked)
+ continue;
+ if (OsVerInfo.fSmp /*must-be-smp*/ && !g_artNtSdbSets[i].OsVerInfo.fSmp)
+ continue;
-#ifndef IN_GUEST /** @todo fix above for all Nt versions. */
+ int32_t iDelta = RT_ABS((int32_t)OsVerInfo.uBuildNo - (int32_t)g_artNtSdbSets[i].OsVerInfo.uBuildNo);
+ if ( iDelta == 0
+ && (g_artNtSdbSets[i].OsVerInfo.uCsdNo == OsVerInfo.uCsdNo || OsVerInfo.uCsdNo == MY_NIL_CSD))
+ {
+ /* prefect */
+ iBestDelta = iDelta;
+ iBest = i;
+ break;
+ }
+ if ( iDelta < iBestDelta
+ || iBest == UINT32_MAX
+ || ( iDelta == iBestDelta
+ && OsVerInfo.uCsdNo != MY_NIL_CSD
+ && RT_ABS(g_artNtSdbSets[i ].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo)
+ < RT_ABS(g_artNtSdbSets[iBest].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo)
+ )
+ )
+ {
+ iBestDelta = iDelta;
+ iBest = i;
+ }
+ }
+ if (iBest < RT_ELEMENTS(g_artNtSdbSets))
+ {
+ /* Try all sets: iBest -> End; iBest -> Start. */
+ bool fDone = false;
+ int32_t i = iBest;
+ while ( i < RT_ELEMENTS(g_artNtSdbSets)
+ && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo)))
+ i++;
+ if (!fDone)
+ {
+ i = (int32_t)iBest - 1;
+ while ( i >= 0
+ && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo)))
+ i--;
+ }
+ }
+ else
+ DbgPrint("IPRT: Failed to locate data set.\n");
+ }
+ else
+ DbgPrint("IPRT: Failed to get PCBR pointer.\n");
+
+ KeLowerIrql(OldIrql); /* Lowering the IRQL early in the hope that we may catch exceptions below. */
+
+#ifndef IN_GUEST
if (!g_offrtNtPbQuantumEnd && !g_offrtNtPbDpcQueueDepth)
DbgPrint("IPRT: Neither _KPRCB::QuantumEnd nor _KPRCB::DpcQueueDepth was not found! Kernel %u.%u %u %s\n",
- MajorVersion, MinorVersion, BuildNumber, fChecked ? "checked" : "free");
+ OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free");
# ifdef DEBUG
else
- DbgPrint("IPRT: _KPRCB:{.QuantumEnd=%x/%d, .DpcQueueDepth=%x/%d} Kernel %ul.%ul %ul %s\n",
+ DbgPrint("IPRT: _KPRCB:{.QuantumEnd=%x/%d, .DpcQueueDepth=%x/%d} Kernel %u.%u %u %s\n",
g_offrtNtPbQuantumEnd, g_cbrtNtPbQuantumEnd, g_offrtNtPbDpcQueueDepth,
- MajorVersion, MinorVersion, BuildNumber, fChecked ? "checked" : "free");
+ OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free");
# endif
#endif
+ /*
+ * Special IPI fun.
+ */
+ g_pfnrtSendIpi = rtMpSendIpiDummy;
+#ifndef IPRT_TARGET_NT4
+ if ( g_pfnrtNtHalRequestIpi
+ && OsVerInfo.uMajorVer == 6
+ && OsVerInfo.uMinorVer == 0)
+ {
+ /* Vista or Windows Server 2008 */
+ g_pfnrtSendIpi = rtMpSendIpiVista;
+ }
+ else if ( g_pfnrtNtHalSendSoftwareInterrupt
+ && OsVerInfo.uMajorVer == 6
+ && OsVerInfo.uMinorVer == 1)
+ {
+ /* Windows 7 or Windows Server 2008 R2 */
+ g_pfnrtSendIpi = rtMpSendIpiWin7;
+ }
+ /* Windows XP should send always send an IPI -> VERIFY */
+#endif
+
return VINF_SUCCESS;
}
diff --git a/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h b/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h
index e04230fa..a82c01f0 100644
--- a/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h
+++ b/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -40,6 +40,7 @@ typedef VOID (__stdcall *PFNHALREQUESTIPI)(KAFFINITY TargetSet);
typedef VOID (__stdcall *PFNHALSENDSOFTWAREINTERRUPT)(ULONG ProcessorNumber, KIRQL Irql);
typedef int (__stdcall *PFNRTSENDIPI)(RTCPUID idCpu);
typedef ULONG_PTR (__stdcall *PFNRTKEIPIGENERICCALL)(PKIPI_BROADCAST_WORKER BroadcastFunction, ULONG_PTR Context);
+typedef ULONG (__stdcall *PFNRTRTLGETVERSION)(PRTL_OSVERSIONINFOEXW pVerInfo);
/*******************************************************************************
* Global Variables *
@@ -51,6 +52,7 @@ extern PFNHALREQUESTIPI g_pfnrtNtHalRequestIpi;
extern PFNHALSENDSOFTWAREINTERRUPT g_pfnrtNtHalSendSoftwareInterrupt;
extern PFNRTSENDIPI g_pfnrtSendIpi;
extern PFNRTKEIPIGENERICCALL g_pfnrtKeIpiGenericCall;
+extern PFNRTRTLGETVERSION g_pfnrtRtlGetVersion;
extern uint32_t g_offrtNtPbQuantumEnd;
extern uint32_t g_cbrtNtPbQuantumEnd;
extern uint32_t g_offrtNtPbDpcQueueDepth;
diff --git a/src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp
index a1cbd1b5..a1c0d865 100644
--- a/src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/memuserkernel-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/memuserkernel-r0drv-nt.cpp
index 05c359d5..982afb8f 100644
--- a/src/VBox/Runtime/r0drv/nt/memuserkernel-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/memuserkernel-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp
index c606861f..643c34a1 100644
--- a/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/mpnotification-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/mpnotification-r0drv-nt.cpp
index e334c353..56506d27 100644
--- a/src/VBox/Runtime/r0drv/nt/mpnotification-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/mpnotification-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp b/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp
new file mode 100644
index 00000000..0ffd6ca9
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp
@@ -0,0 +1,1203 @@
+/* $Id: ntBldSymDb.cpp $ */
+/** @file
+ * IPRT - RTDirCreateUniqueNumbered, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <Windows.h>
+#include <Dbghelp.h>
+
+#include <iprt/alloca.h>
+#include <iprt/dir.h>
+#include <iprt/file.h>
+#include <iprt/getopt.h>
+#include <iprt/initterm.h>
+#include <iprt/list.h>
+#include <iprt/mem.h>
+#include <iprt/message.h>
+#include <iprt/path.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/err.h>
+
+#include "r0drv/nt/symdb.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/** A structure member we're interested in. */
+typedef struct MYMEMBER
+{
+ /** The member name. */
+ const char * const pszName;
+ /** Reserved. */
+ uint32_t const fFlags;
+ /** The offset of the member. UINT32_MAX if not found. */
+ uint32_t off;
+ /** The size of the member. */
+ uint32_t cb;
+ /** Alternative names, optional.
+ * This is a string of zero terminated strings, ending with an zero length
+ * string (or double '\\0' if you like). */
+ const char * const pszzAltNames;
+} MYMEMBER;
+/** Pointer to a member we're interested. */
+typedef MYMEMBER *PMYMEMBER;
+
+/** Members we're interested in. */
+typedef struct MYSTRUCT
+{
+ /** The structure name. */
+ const char * const pszName;
+ /** Array of members we're interested in. */
+ MYMEMBER *paMembers;
+ /** The number of members we're interested in. */
+ uint32_t const cMembers;
+ /** Reserved. */
+ uint32_t const fFlags;
+} MYSTRUCT;
+
+/** Architecture. */
+typedef enum MYARCH
+{
+ MYARCH_X86,
+ MYARCH_AMD64,
+ MYARCH_DETECT
+} MYARCH;
+
+/** Set of structures for one kernel. */
+typedef struct MYSET
+{
+ /** The list entry. */
+ RTLISTNODE ListEntry;
+ /** The source PDB. */
+ char *pszPdb;
+ /** The OS version we've harvested structs for */
+ RTNTSDBOSVER OsVerInfo;
+ /** The architecture. */
+ MYARCH enmArch;
+ /** The structures and their member. */
+ MYSTRUCT aStructs[1];
+} MYSET;
+/** Pointer a set of structures for one kernel. */
+typedef MYSET *PMYSET;
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** Verbosity level (-v, --verbose). */
+static uint32_t g_iOptVerbose = 1;
+/** Set if we should force ahead despite errors. */
+static bool g_fOptForce = false;
+
+/** The members of the KPRCB structure that we're interested in. */
+static MYMEMBER g_aKprcbMembers[] =
+{
+ { "QuantumEnd", 0, UINT32_MAX, UINT32_MAX, NULL },
+ { "DpcQueueDepth", 0, UINT32_MAX, UINT32_MAX, "DpcData[0].DpcQueueDepth\0" },
+ { "VendorString", 0, UINT32_MAX, UINT32_MAX, NULL },
+};
+
+/** The structures we're interested in. */
+static MYSTRUCT g_aStructs[] =
+{
+ { "_KPRCB", &g_aKprcbMembers[0], RT_ELEMENTS(g_aKprcbMembers), 0 },
+};
+
+/** List of data we've found. This is sorted by version info. */
+static RTLISTANCHOR g_SetList;
+
+
+
+
+
+/**
+ * For debug/verbose output.
+ *
+ * @param pszFormat The format string.
+ * @param ... The arguments referenced in the format string.
+ */
+static void MyDbgPrintf(const char *pszFormat, ...)
+{
+ if (g_iOptVerbose > 1)
+ {
+ va_list va;
+ va_start(va, pszFormat);
+ RTPrintf("debug: ");
+ RTPrintfV(pszFormat, va);
+ va_end(va);
+ }
+}
+
+
+/**
+ * Returns the name we wish to use in the C code.
+ * @returns Structure name.
+ * @param pStruct The structure descriptor.
+ */
+static const char *figureCStructName(MYSTRUCT const *pStruct)
+{
+ const char *psz = pStruct->pszName;
+ while (*psz == '_')
+ psz++;
+ return psz;
+}
+
+
+/**
+ * Returns the name we wish to use in the C code.
+ * @returns Member name.
+ * @param pStruct The member descriptor.
+ */
+static const char *figureCMemberName(MYMEMBER const *pMember)
+{
+ return pMember->pszName;
+}
+
+
+/**
+ * Creates a MYSET with copies of all the data and inserts it into the
+ * g_SetList in a orderly fashion.
+ *
+ * @param pOut The output stream.
+ */
+static void generateHeader(PRTSTREAM pOut)
+{
+ RTStrmPrintf(pOut,
+ "/* $" "I" "d" ": $ */\n" /* avoid it being expanded */
+ "/** @file\n"
+ " * IPRT - NT kernel type helpers - Autogenerated, do NOT edit.\n"
+ " */\n"
+ "\n"
+ "/*\n"
+ " * Copyright (C) 2013 Oracle Corporation\n"
+ " *\n"
+ " * This file is part of VirtualBox Open Source Edition (OSE), as\n"
+ " * available from http://www.virtualbox.org. This file is free software;\n"
+ " * you can redistribute it and/or modify it under the terms of the GNU\n"
+ " * General Public License (GPL) as published by the Free Software\n"
+ " * Foundation, in version 2 as it comes in the \"COPYING\" file of the\n"
+ " * VirtualBox OSE distribution. VirtualBox OSE is distributed in the\n"
+ " * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.\n"
+ " *\n"
+ " * The contents of this file may alternatively be used under the terms\n"
+ " * of the Common Development and Distribution License Version 1.0\n"
+ " * (CDDL) only, as it comes in the \"COPYING.CDDL\" file of the\n"
+ " * VirtualBox OSE distribution, in which case the provisions of the\n"
+ " * CDDL are applicable instead of those of the GPL.\n"
+ " *\n"
+ " * You may elect to license modified versions of this file under the\n"
+ " * terms and conditions of either the GPL or the CDDL or both.\n"
+ " */\n"
+ "\n"
+ "\n"
+ "#ifndef ___r0drv_nt_symdbdata_h\n"
+ "#define ___r0drv_nt_symdbdata_h\n"
+ "\n"
+ "#include \"r0drv/nt/symdb.h\"\n"
+ "\n"
+ );
+
+ /*
+ * Generate types.
+ */
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
+ {
+ const char *pszStructName = figureCStructName(&g_aStructs[i]);
+
+ RTStrmPrintf(pOut,
+ "typedef struct RTNTSDBTYPE_%s\n"
+ "{\n",
+ pszStructName);
+ PMYMEMBER paMembers = g_aStructs[i].paMembers;
+ for (uint32_t j = 0; j < g_aStructs->cMembers; j++)
+ {
+ const char *pszMemName = figureCMemberName(&paMembers[j]);
+ RTStrmPrintf(pOut,
+ " uint32_t off%s;\n"
+ " uint32_t cb%s;\n",
+ pszMemName, pszMemName);
+ }
+
+ RTStrmPrintf(pOut,
+ "} RTNTSDBTYPE_%s;\n"
+ "\n",
+ pszStructName);
+ }
+
+ RTStrmPrintf(pOut,
+ "\n"
+ "typedef struct RTNTSDBSET\n"
+ "{\n"
+ " RTNTSDBOSVER%-20s OsVerInfo;\n", "");
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
+ {
+ const char *pszStructName = figureCStructName(&g_aStructs[i]);
+ RTStrmPrintf(pOut, " RTNTSDBTYPE_%-20s %s;\n", pszStructName, pszStructName);
+ }
+ RTStrmPrintf(pOut,
+ "} RTNTSDBSET;\n"
+ "typedef RTNTSDBSET const *PCRTNTSDBSET;\n"
+ "\n");
+
+ /*
+ * Output the data.
+ */
+ RTStrmPrintf(pOut,
+ "\n"
+ "#ifndef RTNTSDB_NO_DATA\n"
+ "const RTNTSDBSET g_artNtSdbSets[] = \n"
+ "{\n");
+ PMYSET pSet;
+ RTListForEach(&g_SetList, pSet, MYSET, ListEntry)
+ {
+ const char *pszArch = pSet->enmArch == MYARCH_AMD64 ? "AMD64" : "X86";
+ RTStrmPrintf(pOut,
+ "# ifdef RT_ARCH_%s\n"
+ " { /* Source: %s */\n"
+ " /*.OsVerInfo = */\n"
+ " {\n"
+ " /* .uMajorVer = */ %u,\n"
+ " /* .uMinorVer = */ %u,\n"
+ " /* .fChecked = */ %s,\n"
+ " /* .fSmp = */ %s,\n"
+ " /* .uCsdNo = */ %u,\n"
+ " /* .uBuildNo = */ %u,\n"
+ " },\n",
+ pszArch,
+ pSet->pszPdb,
+ pSet->OsVerInfo.uMajorVer,
+ pSet->OsVerInfo.uMinorVer,
+ pSet->OsVerInfo.fChecked ? "true" : "false",
+ pSet->OsVerInfo.fSmp ? "true" : "false",
+ pSet->OsVerInfo.uCsdNo,
+ pSet->OsVerInfo.uBuildNo);
+ for (uint32_t i = 0; i < RT_ELEMENTS(pSet->aStructs); i++)
+ {
+ const char *pszStructName = figureCStructName(&pSet->aStructs[i]);
+ RTStrmPrintf(pOut,
+ " /* .%s = */\n"
+ " {\n", pszStructName);
+ PMYMEMBER paMembers = pSet->aStructs[i].paMembers;
+ for (uint32_t j = 0; j < pSet->aStructs[i].cMembers; j++)
+ {
+ const char *pszMemName = figureCMemberName(&paMembers[j]);
+ RTStrmPrintf(pOut,
+ " /* .off%-25s = */ %#06x,\n"
+ " /* .cb%-26s = */ %#06x,\n",
+ pszMemName, paMembers[j].off,
+ pszMemName, paMembers[j].cb);
+ }
+ RTStrmPrintf(pOut,
+ " },\n");
+ }
+ RTStrmPrintf(pOut,
+ " },\n"
+ "# endif\n"
+ );
+ }
+
+ RTStrmPrintf(pOut,
+ "};\n"
+ "#endif /* !RTNTSDB_NO_DATA */\n"
+ "\n");
+
+ RTStrmPrintf(pOut, "\n#endif\n\n");
+}
+
+
+/**
+ * Creates a MYSET with copies of all the data and inserts it into the
+ * g_SetList in a orderly fashion.
+ *
+ * @returns Fully complained exit code.
+ * @param pOsVerInfo The OS version info.
+ */
+static RTEXITCODE saveStructures(PRTNTSDBOSVER pOsVerInfo, MYARCH enmArch, const char *pszPdb)
+{
+ /*
+ * Allocate one big chunk, figure it's size once.
+ */
+ static size_t s_cbNeeded = 0;
+ if (s_cbNeeded == 0)
+ {
+ s_cbNeeded = RT_OFFSETOF(MYSET, aStructs[RT_ELEMENTS(g_aStructs)]);
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
+ s_cbNeeded += sizeof(MYMEMBER) * g_aStructs[i].cMembers;
+ }
+
+ size_t cbPdb = strlen(pszPdb) + 1;
+ PMYSET pSet = (PMYSET)RTMemAlloc(s_cbNeeded + cbPdb);
+ if (!pSet)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Out of memory!\n");
+
+ /*
+ * Copy over the data.
+ */
+ pSet->enmArch = enmArch;
+ memcpy(&pSet->OsVerInfo, pOsVerInfo, sizeof(pSet->OsVerInfo));
+ memcpy(&pSet->aStructs[0], g_aStructs, sizeof(g_aStructs));
+
+ PMYMEMBER pDst = (PMYMEMBER)&pSet->aStructs[RT_ELEMENTS(g_aStructs)];
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
+ {
+ pSet->aStructs[i].paMembers = pDst;
+ memcpy(pDst, g_aStructs[i].paMembers, g_aStructs[i].cMembers * sizeof(*pDst));
+ pDst += g_aStructs[i].cMembers;
+ }
+
+ pSet->pszPdb = (char *)pDst;
+ memcpy(pDst, pszPdb, cbPdb);
+
+ /*
+ * Link it.
+ */
+ PMYSET pInsertBefore;
+ RTListForEach(&g_SetList, pInsertBefore, MYSET, ListEntry)
+ {
+ int iDiff = rtNtOsVerInfoCompare(&pInsertBefore->OsVerInfo, &pSet->OsVerInfo);
+ if (iDiff >= 0)
+ {
+ if (iDiff > 0 || pInsertBefore->enmArch > pSet->enmArch)
+ {
+ RTListNodeInsertBefore(&pInsertBefore->ListEntry, &pSet->ListEntry);
+ return RTEXITCODE_SUCCESS;
+ }
+ }
+ }
+
+ RTListAppend(&g_SetList, &pSet->ListEntry);
+ return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Checks that we found everything.
+ *
+ * @returns Fully complained exit code.
+ */
+static RTEXITCODE checkThatWeFoundEverything(void)
+{
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
+ {
+ PMYMEMBER paMembers = g_aStructs[i].paMembers;
+ uint32_t j = g_aStructs[i].cMembers;
+ while (j-- > 0)
+ {
+ if (paMembers[j].off == UINT32_MAX)
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, " Missing %s::%s\n", g_aStructs[i].pszName, paMembers[j].pszName);
+ }
+ }
+ return rcExit;
+}
+
+
+/**
+ * Matches the member against what we're looking for.
+ *
+ * @returns Number of hits.
+ * @param cWantedMembers The number members in paWantedMembers.
+ * @param paWantedMembers The members we're looking for.
+ * @param pszPrefix The member name prefix.
+ * @param pszMember The member name.
+ * @param offMember The member offset.
+ * @param cbMember The member size.
+ */
+static uint32_t matchUpStructMembers(unsigned cWantedMembers, PMYMEMBER paWantedMembers,
+ const char *pszPrefix, const char *pszMember,
+ uint32_t offMember, uint32_t cbMember)
+{
+ size_t cchPrefix = strlen(pszPrefix);
+ uint32_t cHits = 0;
+ uint32_t iMember = cWantedMembers;
+ while (iMember-- > 0)
+ {
+ if ( !strncmp(pszPrefix, paWantedMembers[iMember].pszName, cchPrefix)
+ && !strcmp(pszMember, paWantedMembers[iMember].pszName + cchPrefix))
+ {
+ paWantedMembers[iMember].off = offMember;
+ paWantedMembers[iMember].cb = cbMember;
+ cHits++;
+ }
+ else if (paWantedMembers[iMember].pszzAltNames)
+ {
+ char const *pszCur = paWantedMembers[iMember].pszzAltNames;
+ while (*pszCur)
+ {
+ size_t cchCur = strlen(pszCur);
+ if ( !strncmp(pszPrefix, pszCur, cchPrefix)
+ && !strcmp(pszMember, pszCur + cchPrefix))
+ {
+ paWantedMembers[iMember].off = offMember;
+ paWantedMembers[iMember].cb = cbMember;
+ cHits++;
+ break;
+ }
+ pszCur += cchCur + 1;
+ }
+ }
+ }
+ return cHits;
+}
+
+
+/**
+ * Resets the writable structure members prior to processing a PDB.
+ *
+ * While processing the PDB, will fill in the sizes and offsets of what we find.
+ * Afterwards we'll use look for reset values to see that every structure and
+ * member was located successfully.
+ */
+static void resetMyStructs(void)
+{
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
+ {
+ PMYMEMBER paMembers = g_aStructs[i].paMembers;
+ uint32_t j = g_aStructs[i].cMembers;
+ while (j-- > 0)
+ {
+ paMembers[j].off = UINT32_MAX;
+ paMembers[j].cb = UINT32_MAX;
+ }
+ }
+}
+
+
+/**
+ * Find members in the specified structure type (@a idxType).
+ *
+ * @returns Fully bitched exit code.
+ * @param hFake Fake process handle.
+ * @param uModAddr The module address.
+ * @param idxType The type index of the structure which members we're
+ * going to process.
+ * @param cWantedMembers The number of wanted members.
+ * @param paWantedMembers The wanted members. This will be modified.
+ * @param offDisp Displacement when calculating member offsets.
+ * @param pszStructNm The top level structure name.
+ * @param pszPrefix The member name prefix.
+ * @param pszLogTag The log tag.
+ */
+static RTEXITCODE findMembers(HANDLE hFake, uint64_t uModAddr, uint32_t idxType,
+ uint32_t cWantedMembers, PMYMEMBER paWantedMembers,
+ uint32_t offDisp, const char *pszStructNm, const char *pszPrefix, const char *pszLogTag)
+{
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+
+ DWORD cChildren = 0;
+ if (!SymGetTypeInfo(hFake, uModAddr, idxType, TI_GET_CHILDRENCOUNT, &cChildren))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: TI_GET_CHILDRENCOUNT failed on _KPRCB: %u\n", pszLogTag, GetLastError());
+
+ MyDbgPrintf(" %s: cChildren=%u (%#x)\n", pszStructNm, cChildren);
+ TI_FINDCHILDREN_PARAMS *pChildren;
+ pChildren = (TI_FINDCHILDREN_PARAMS *)alloca(RT_OFFSETOF(TI_FINDCHILDREN_PARAMS, ChildId[cChildren]));
+ pChildren->Start = 0;
+ pChildren->Count = cChildren;
+ if (!SymGetTypeInfo(hFake, uModAddr, idxType, TI_FINDCHILDREN, pChildren))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: TI_FINDCHILDREN failed on _KPRCB: %u\n", pszLogTag, GetLastError());
+
+ for (uint32_t i = 0; i < cChildren; i++)
+ {
+ //MyDbgPrintf(" %s: child#%u: TypeIndex=%u\n", pszStructNm, i, pChildren->ChildId[i]);
+ IMAGEHLP_SYMBOL_TYPE_INFO enmErr;
+ PWCHAR pwszMember = NULL;
+ uint32_t idxRefType = 0;
+ uint32_t offMember = 0;
+ uint64_t cbMember = 0;
+ uint32_t cMemberChildren = 0;
+ if ( SymGetTypeInfo(hFake, uModAddr, pChildren->ChildId[i], enmErr = TI_GET_SYMNAME, &pwszMember)
+ && SymGetTypeInfo(hFake, uModAddr, pChildren->ChildId[i], enmErr = TI_GET_OFFSET, &offMember)
+ && SymGetTypeInfo(hFake, uModAddr, pChildren->ChildId[i], enmErr = TI_GET_TYPE, &idxRefType)
+ && SymGetTypeInfo(hFake, uModAddr, idxRefType, enmErr = TI_GET_LENGTH, &cbMember)
+ && SymGetTypeInfo(hFake, uModAddr, idxRefType, enmErr = TI_GET_CHILDRENCOUNT, &cMemberChildren)
+ )
+ {
+ offMember += offDisp;
+
+ char *pszMember;
+ int rc = RTUtf16ToUtf8(pwszMember, &pszMember);
+ if (RT_SUCCESS(rc))
+ {
+ matchUpStructMembers(cWantedMembers, paWantedMembers, pszPrefix, pszMember, offMember, cbMember);
+
+ /*
+ * Gather more info and do some debug printing. We'll use some
+ * of this info below when recursing into sub-structures
+ * and arrays.
+ */
+ uint32_t fNested = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_NESTED, &fNested);
+ uint32_t uDataKind = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_DATAKIND, &uDataKind);
+ uint32_t uBaseType = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_BASETYPE, &uBaseType);
+ uint32_t uMembTag = 0; SymGetTypeInfo(hFake, uModAddr, pChildren->ChildId[i], TI_GET_SYMTAG, &uMembTag);
+ uint32_t uBaseTag = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_SYMTAG, &uBaseTag);
+ uint32_t cElements = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_COUNT, &cElements);
+ uint32_t idxArrayType = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_ARRAYINDEXTYPEID, &idxArrayType);
+ MyDbgPrintf(" %#06x LB %#06llx %c%c %2d %2d %2d %2d %2d %4d %s::%s%s\n",
+ offMember, cbMember,
+ cMemberChildren > 0 ? 'c' : '-',
+ fNested != 0 ? 'n' : '-',
+ uDataKind,
+ uBaseType,
+ uMembTag,
+ uBaseTag,
+ cElements,
+ idxArrayType,
+ pszStructNm,
+ pszPrefix,
+ pszMember);
+
+ /*
+ * Recurse into children.
+ */
+ if (cMemberChildren > 0)
+ {
+ size_t cbNeeded = strlen(pszMember) + strlen(pszPrefix) + sizeof(".");
+ char *pszSubPrefix = (char *)RTMemTmpAlloc(cbNeeded);
+ if (pszSubPrefix)
+ {
+ strcat(strcat(strcpy(pszSubPrefix, pszPrefix), pszMember), ".");
+ RTEXITCODE rcExit2 = findMembers(hFake, uModAddr, idxRefType, cWantedMembers,
+ paWantedMembers, offMember,
+ pszStructNm,
+ pszSubPrefix,
+ pszLogTag);
+ if (rcExit2 != RTEXITCODE_SUCCESS)
+ rcExit = rcExit2;
+ RTMemTmpFree(pszSubPrefix);
+ }
+ else
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory\n");
+ }
+ /*
+ * Recurse into arrays too.
+ */
+ else if (cElements > 0 && idxArrayType > 0)
+ {
+ BOOL fRc;
+ uint32_t idxElementRefType = 0;
+ fRc = SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_TYPE, &idxElementRefType); Assert(fRc);
+ uint64_t cbElement = cbMember / cElements;
+ fRc = SymGetTypeInfo(hFake, uModAddr, idxElementRefType, TI_GET_LENGTH, &cbElement); Assert(fRc);
+ MyDbgPrintf("idxArrayType=%u idxElementRefType=%u cbElement=%u\n", idxArrayType, idxElementRefType, cbElement);
+
+ size_t cbNeeded = strlen(pszMember) + strlen(pszPrefix) + sizeof("[xxxxxxxxxxxxxxxx].");
+ char *pszSubPrefix = (char *)RTMemTmpAlloc(cbNeeded);
+ if (pszSubPrefix)
+ {
+ for (uint32_t iElement = 0; iElement < cElements; iElement++)
+ {
+ RTStrPrintf(pszSubPrefix, cbNeeded, "%s%s[%u].", pszPrefix, pszMember, iElement);
+ RTEXITCODE rcExit2 = findMembers(hFake, uModAddr, idxElementRefType, cWantedMembers,
+ paWantedMembers,
+ offMember + iElement * cbElement,
+ pszStructNm,
+ pszSubPrefix,
+ pszLogTag);
+ if (rcExit2 != RTEXITCODE_SUCCESS)
+ rcExit = rcExit2;
+ }
+ RTMemTmpFree(pszSubPrefix);
+ }
+ else
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory\n");
+ }
+
+ RTStrFree(pszMember);
+ }
+ else
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: RTUtf16ToUtf8 failed on %s child#%u: %Rrc\n",
+ pszLogTag, pszStructNm, i, rc);
+ }
+ /* TI_GET_OFFSET fails on bitfields, so just ignore+skip those. */
+ else if (enmErr != TI_GET_OFFSET || GetLastError() != ERROR_INVALID_FUNCTION)
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: SymGetTypeInfo(,,,%d,) failed on %s child#%u: %u\n",
+ pszLogTag, enmErr, pszStructNm, i, GetLastError());
+ LocalFree(pwszMember);
+ } /* For each child. */
+
+ return rcExit;
+}
+
+
+/**
+ * Lookup up structures and members in the given module.
+ *
+ * @returns Fully bitched exit code.
+ * @param hFake Fake process handle.
+ * @param uModAddr The module address.
+ * @param pszLogTag The log tag.
+ * @param pszPdb The full PDB path.
+ * @param pOsVerInfo The OS version info for altering the error handling
+ * for older OSes.
+ */
+static RTEXITCODE findStructures(HANDLE hFake, uint64_t uModAddr, const char *pszLogTag, const char *pszPdb,
+ PCRTNTSDBOSVER pOsVerInfo)
+{
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ PSYMBOL_INFO pSymInfo = (PSYMBOL_INFO)alloca(sizeof(*pSymInfo));
+ for (uint32_t iStruct = 0; iStruct < RT_ELEMENTS(g_aStructs); iStruct++)
+ {
+ pSymInfo->SizeOfStruct = sizeof(*pSymInfo);
+ pSymInfo->MaxNameLen = 0;
+ if (!SymGetTypeFromName(hFake, uModAddr, g_aStructs[iStruct].pszName, pSymInfo))
+ {
+ if (!(pOsVerInfo->uMajorVer == 5 && pOsVerInfo->uMinorVer == 0) /* w2k */)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to find _KPRCB: %u\n", pszPdb, GetLastError());
+ RTMsgInfo("%s: Skipping - failed to find _KPRCB: %u\n", pszPdb, GetLastError());
+ return RTEXITCODE_SKIPPED;
+ }
+
+ MyDbgPrintf(" %s: TypeIndex=%u\n", g_aStructs[iStruct].pszName, pSymInfo->TypeIndex);
+ MyDbgPrintf(" %s: Size=%u (%#x)\n", g_aStructs[iStruct].pszName, pSymInfo->Size, pSymInfo->Size);
+
+ rcExit = findMembers(hFake, uModAddr, pSymInfo->TypeIndex,
+ g_aStructs[iStruct].cMembers, g_aStructs[iStruct].paMembers, 0 /* offDisp */,
+ g_aStructs[iStruct].pszName, "", pszLogTag);
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return rcExit;
+ } /* for each struct we want */
+ return rcExit;
+}
+
+
+static bool strIEndsWith(const char *pszString, const char *pszSuffix)
+{
+ size_t cchString = strlen(pszString);
+ size_t cchSuffix = strlen(pszSuffix);
+ if (cchString < cchSuffix)
+ return false;
+ return RTStrICmp(pszString + cchString - cchSuffix, pszSuffix) == 0;
+}
+
+
+/**
+ * Use various hysterics to figure out the OS version details from the PDB path.
+ *
+ * This ASSUMES quite a bunch of things:
+ * -# Working on unpacked symbol packages. This does not work for
+ * windbg symbol stores/caches.
+ * -# The symbol package has been unpacked into a directory with the same
+ * name as the symbol package (sans suffixes).
+ *
+ * @returns Fully complained exit code.
+ * @param pszPdb The path to the PDB.
+ * @param pVerInfo Where to return the version info.
+ * @param penmArch Where to return the architecture.
+ */
+static RTEXITCODE FigurePdbVersionInfo(const char *pszPdb, PRTNTSDBOSVER pVerInfo, MYARCH *penmArch)
+{
+ /*
+ * Split the path.
+ */
+ union
+ {
+ RTPATHSPLIT Split;
+ uint8_t abPad[RTPATH_MAX + 1024];
+ } u;
+ int rc = RTPathSplit(pszPdb, &u.Split, sizeof(u), 0);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathSplit failed on '%s': %Rrc", pszPdb, rc);
+ if (!(u.Split.fProps & RTPATH_PROP_FILENAME))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPATH_PROP_FILENAME not set for: '%s'", pszPdb);
+ const char *pszFilename = u.Split.apszComps[u.Split.cComps - 1];
+
+ /*
+ * SMP or UNI kernel?
+ */
+ if ( !RTStrICmp(pszFilename, "ntkrnlmp.pdb")
+ || !RTStrICmp(pszFilename, "ntkrpamp.pdb")
+ )
+ pVerInfo->fSmp = true;
+ else if ( !RTStrICmp(pszFilename, "ntoskrnl.pdb")
+ || !RTStrICmp(pszFilename, "ntkrnlpa.pdb")
+ )
+ pVerInfo->fSmp = false;
+ else
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Doesn't recognize the filename '%s'...", pszFilename);
+
+ /*
+ * Look for symbol pack names in the path. This is stuff like:
+ * - WindowsVista.6002.090410-1830.x86fre
+ * - WindowsVista.6002.090410-1830.amd64chk
+ * - Windows_Win7.7600.16385.090713-1255.X64CHK
+ * - Windows_Win7SP1.7601.17514.101119-1850.AMD64FRE
+ * - Windows_Win8.9200.16384.120725-1247.X86CHK
+ * - en_windows_8_1_symbols_debug_checked_x64_2712568
+ */
+ bool fFound = false;
+ uint32_t i = u.Split.cComps - 1;
+ while (i-- > 0)
+ {
+ static struct
+ {
+ const char *pszPrefix;
+ size_t cchPrefix;
+ uint8_t uMajorVer;
+ uint8_t uMinorVer;
+ uint8_t uCsdNo;
+ uint32_t uBuildNo; /**< UINT32_MAX means the number immediately after the prefix. */
+ } const s_aSymPacks[] =
+ {
+ { RT_STR_TUPLE("w2kSP1SYM"), 5, 0, 1, 2195 },
+ { RT_STR_TUPLE("w2ksp2srp1"), 5, 0, 2, 2195 },
+ { RT_STR_TUPLE("w2ksp2sym"), 5, 0, 2, 2195 },
+ { RT_STR_TUPLE("w2ksp3sym"), 5, 0, 3, 2195 },
+ { RT_STR_TUPLE("w2ksp4sym"), 5, 0, 4, 2195 },
+ { RT_STR_TUPLE("Windows2000-KB891861"), 5, 0, 4, 2195 },
+ { RT_STR_TUPLE("windowsxp"), 5, 1, 0, 2600 },
+ { RT_STR_TUPLE("xpsp1sym"), 5, 1, 1, 2600 },
+ { RT_STR_TUPLE("WindowsXP-KB835935-SP2-"), 5, 1, 2, 2600 },
+ { RT_STR_TUPLE("WindowsXP-KB936929-SP3-"), 5, 1, 3, 2600 },
+ { RT_STR_TUPLE("Windows2003."), 5, 2, 0, 3790 },
+ { RT_STR_TUPLE("Windows2003_sp1."), 5, 2, 1, 3790 },
+ { RT_STR_TUPLE("WindowsServer2003-KB933548-v1"), 5, 2, 1, 3790 },
+ { RT_STR_TUPLE("WindowsVista.6000."), 6, 0, 0, 6000 },
+ { RT_STR_TUPLE("Windows_Longhorn.6001."), 6, 0, 1, 6001 }, /* incl w2k8 */
+ { RT_STR_TUPLE("WindowsVista.6002."), 6, 0, 2, 6002 }, /* incl w2k8 */
+ { RT_STR_TUPLE("Windows_Winmain.7000"), 6, 1, 0, 7000 }, /* Beta */
+ { RT_STR_TUPLE("Windows_Winmain.7100"), 6, 1, 0, 7100 }, /* RC */
+ { RT_STR_TUPLE("Windows_Win7.7600"), 6, 1, 0, 7600 }, /* RC */
+ { RT_STR_TUPLE("Windows_Win7SP1.7601"), 6, 1, 1, 7601 }, /* RC */
+ { RT_STR_TUPLE("Windows_Winmain.8102"), 6, 2, 0, 8102 }, /* preview */
+ { RT_STR_TUPLE("Windows_Winmain.8250"), 6, 2, 0, 8250 }, /* beta */
+ { RT_STR_TUPLE("Windows_Winmain.8400"), 6, 2, 0, 8400 }, /* RC */
+ { RT_STR_TUPLE("Windows_Win8.9200"), 6, 2, 0, 9200 }, /* RTM */
+ { RT_STR_TUPLE("en_windows_8_1"), 6, 3, 0, 9600 }, /* RTM */
+ };
+
+ const char *pszComp = u.Split.apszComps[i];
+ uint32_t iSymPack = RT_ELEMENTS(s_aSymPacks);
+ while (iSymPack-- > 0)
+ if (!RTStrNICmp(pszComp, s_aSymPacks[iSymPack].pszPrefix, s_aSymPacks[iSymPack].cchPrefix))
+ break;
+ if (iSymPack >= RT_ELEMENTS(s_aSymPacks))
+ continue;
+
+ pVerInfo->uMajorVer = s_aSymPacks[iSymPack].uMajorVer;
+ pVerInfo->uMinorVer = s_aSymPacks[iSymPack].uMinorVer;
+ pVerInfo->uCsdNo = s_aSymPacks[iSymPack].uCsdNo;
+ pVerInfo->fChecked = false;
+ pVerInfo->uBuildNo = s_aSymPacks[iSymPack].uBuildNo;
+
+ /* Parse build number if necessary. */
+ if (s_aSymPacks[iSymPack].uBuildNo == UINT32_MAX)
+ {
+ char *pszNext;
+ rc = RTStrToUInt32Ex(pszComp + s_aSymPacks[iSymPack].cchPrefix, &pszNext, 10, &pVerInfo->uBuildNo);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to decode build number in '%s': %Rrc", pszComp, rc);
+ if (*pszNext != '.' && *pszNext != '_' && *pszNext != '-')
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to decode build number in '%s': '%c'", pszComp, *pszNext);
+ }
+
+ /* Look for build arch and checked/free. */
+ if ( RTStrIStr(pszComp, ".x86.chk.")
+ || RTStrIStr(pszComp, ".x86chk.")
+ || RTStrIStr(pszComp, "_x86_chk_")
+ || RTStrIStr(pszComp, "_x86chk_")
+ || RTStrIStr(pszComp, "-x86-DEBUG")
+ || (RTStrIStr(pszComp, "-x86-") && RTStrIStr(pszComp, "-DEBUG"))
+ || RTStrIStr(pszComp, "_debug_checked_x86")
+ )
+ {
+ pVerInfo->fChecked = true;
+ *penmArch = MYARCH_X86;
+ }
+ else if ( RTStrIStr(pszComp, ".amd64.chk.")
+ || RTStrIStr(pszComp, ".amd64chk.")
+ || RTStrIStr(pszComp, ".x64.chk.")
+ || RTStrIStr(pszComp, ".x64chk.")
+ || RTStrIStr(pszComp, "_debug_checked_x64")
+ )
+ {
+ pVerInfo->fChecked = true;
+ *penmArch = MYARCH_AMD64;
+ }
+ else if ( RTStrIStr(pszComp, ".amd64.fre.")
+ || RTStrIStr(pszComp, ".amd64fre.")
+ || RTStrIStr(pszComp, ".x64.fre.")
+ || RTStrIStr(pszComp, ".x64fre.")
+ )
+ {
+ pVerInfo->fChecked = false;
+ *penmArch = MYARCH_AMD64;
+ }
+ else if ( RTStrIStr(pszComp, "DEBUG")
+ || RTStrIStr(pszComp, "_chk")
+ )
+ {
+ pVerInfo->fChecked = true;
+ *penmArch = MYARCH_X86;
+ }
+ else if (RTStrIStr(pszComp, "_x64"))
+ {
+ pVerInfo->fChecked = false;
+ *penmArch = MYARCH_AMD64;
+ }
+ else
+ {
+ pVerInfo->fChecked = false;
+ *penmArch = MYARCH_X86;
+ }
+ return RTEXITCODE_SUCCESS;
+ }
+
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Giving up on '%s'...\n", pszPdb);
+}
+
+
+/**
+ * Process one PDB.
+ *
+ * @returns Fully bitched exit code.
+ * @param pszPdb The path to the PDB.
+ */
+static RTEXITCODE processPdb(const char *pszPdb)
+{
+ /*
+ * We need the size later on, so get that now and present proper IPRT error
+ * info if the file is missing or inaccessible.
+ */
+ RTFSOBJINFO ObjInfo;
+ int rc = RTPathQueryInfoEx(pszPdb, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathQueryInfo fail on '%s': %Rrc\n", pszPdb, rc);
+
+ /*
+ * Figure the windows version details for the given PDB.
+ */
+ MYARCH enmArch;
+ RTNTSDBOSVER OsVerInfo;
+ RTEXITCODE rcExit = FigurePdbVersionInfo(pszPdb, &OsVerInfo, &enmArch);
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to figure the OS version info for '%s'.\n'", pszPdb);
+
+ /*
+ * Create a fake handle and open the PDB.
+ */
+ static uintptr_t s_iHandle = 0;
+ HANDLE hFake = (HANDLE)++s_iHandle;
+ if (!SymInitialize(hFake, NULL, FALSE))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "SymInitialied failed: %u\n", GetLastError());
+
+ uint64_t uModAddr = UINT64_C(0x1000000);
+ uModAddr = SymLoadModuleEx(hFake, NULL /*hFile*/, pszPdb, NULL /*pszModuleName*/,
+ uModAddr, ObjInfo.cbObject, NULL /*pData*/, 0 /*fFlags*/);
+ if (uModAddr != 0)
+ {
+ MyDbgPrintf("*** uModAddr=%#llx \"%s\" ***\n", uModAddr, pszPdb);
+
+ char szLogTag[32];
+ RTStrCopy(szLogTag, sizeof(szLogTag), RTPathFilename(pszPdb));
+
+ /*
+ * Find the structures.
+ */
+ rcExit = findStructures(hFake, uModAddr, szLogTag, pszPdb, &OsVerInfo);
+ if (rcExit == RTEXITCODE_SUCCESS)
+ rcExit = checkThatWeFoundEverything();
+ if (rcExit == RTEXITCODE_SUCCESS)
+ {
+ /*
+ * Save the details for later when we produce the header.
+ */
+ rcExit = saveStructures(&OsVerInfo, enmArch, pszPdb);
+ }
+ }
+ else
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymLoadModuleEx failed: %u\n", GetLastError());
+
+ if (!SymCleanup(hFake))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymCleanup failed: %u\n", GetLastError());
+
+ if (rcExit == RTEXITCODE_SKIPPED)
+ rcExit = RTEXITCODE_SUCCESS;
+ return rcExit;
+}
+
+
+/** The size of the directory entry buffer we're using. */
+#define MY_DIRENTRY_BUF_SIZE (sizeof(RTDIRENTRYEX) + RTPATH_MAX)
+
+/**
+ * Checks if the name is of interest to us.
+ *
+ * @returns true/false.
+ * @param pszName The name.
+ * @param cchName The length of the name.
+ */
+static bool isInterestingName(const char *pszName, size_t cchName)
+{
+ static struct { const char *psz; size_t cch; } const s_aNames[] =
+ {
+ RT_STR_TUPLE("ntoskrnl.pdb"),
+ RT_STR_TUPLE("ntkrnlmp.pdb"),
+ RT_STR_TUPLE("ntkrnlpa.pdb"),
+ RT_STR_TUPLE("ntkrpamp.pdb"),
+ };
+
+ if ( cchName == s_aNames[0].cch
+ && (pszName[0] == 'n' || pszName[0] == 'N')
+ && (pszName[1] == 't' || pszName[1] == 'T')
+ )
+ {
+ int i = RT_ELEMENTS(s_aNames);
+ while (i-- > 0)
+ if ( s_aNames[i].cch == cchName
+ && !RTStrICmp(s_aNames[i].psz, pszName))
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Recursively processes relevant files in the specified directory.
+ *
+ * @returns Fully complained exit code.
+ * @param pszDir Pointer to the directory buffer.
+ * @param cchDir The length of pszDir in pszDir.
+ * @param pDirEntry Pointer to the directory buffer.
+ */
+static RTEXITCODE processDirSub(char *pszDir, size_t cchDir, PRTDIRENTRYEX pDirEntry, int iLogDepth)
+{
+ Assert(cchDir > 0); Assert(pszDir[cchDir] == '\0');
+
+ /* Make sure we've got some room in the path, to save us extra work further down. */
+ if (cchDir + 3 >= RTPATH_MAX)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Path too long: '%s'\n", pszDir);
+
+ /* Open directory. */
+ PRTDIR pDir;
+ int rc = RTDirOpen(&pDir, pszDir);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirOpen failed on '%s': %Rrc\n", pszDir, rc);
+
+ /* Ensure we've got a trailing slash (there is space for it see above). */
+ if (!RTPATH_IS_SEP(pszDir[cchDir - 1]))
+ {
+ pszDir[cchDir++] = RTPATH_SLASH;
+ pszDir[cchDir] = '\0';
+ }
+
+ /*
+ * Process the files and subdirs.
+ */
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ for (;;)
+ {
+ /* Get the next directory. */
+ size_t cbDirEntry = MY_DIRENTRY_BUF_SIZE;
+ rc = RTDirReadEx(pDir, pDirEntry, &cbDirEntry, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
+ if (RT_FAILURE(rc))
+ break;
+
+ /* Skip the dot and dot-dot links. */
+ if ( (pDirEntry->cbName == 1 && pDirEntry->szName[0] == '.')
+ || (pDirEntry->cbName == 2 && pDirEntry->szName[0] == '.' && pDirEntry->szName[1] == '.'))
+ continue;
+
+ /* Check length. */
+ if (pDirEntry->cbName + cchDir + 3 >= RTPATH_MAX)
+ {
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Path too long: '%s' in '%.*s'\n", pDirEntry->szName, cchDir, pszDir);
+ break;
+ }
+
+ if (RTFS_IS_FILE(pDirEntry->Info.Attr.fMode))
+ {
+ /*
+ * Process debug info files of interest.
+ */
+ if (isInterestingName(pDirEntry->szName, pDirEntry->cbName))
+ {
+ memcpy(&pszDir[cchDir], pDirEntry->szName, pDirEntry->cbName + 1);
+ RTEXITCODE rcExit2 = processPdb(pszDir);
+ if (rcExit2 != RTEXITCODE_SUCCESS)
+ rcExit = rcExit2;
+ }
+ }
+ else if (RTFS_IS_DIRECTORY(pDirEntry->Info.Attr.fMode))
+ {
+ /*
+ * Recurse into the subdirectory. In order to speed up Win7+
+ * symbol pack traversals, we skip directories with ".pdb" suffixes
+ * unless they match any of the .pdb files we're looking for.
+ *
+ * Note! When we get back pDirEntry will be invalid.
+ */
+ if ( pDirEntry->cbName <= 4
+ || RTStrICmp(&pDirEntry->szName[pDirEntry->cbName - 4], ".pdb")
+ || isInterestingName(pDirEntry->szName, pDirEntry->cbName))
+ {
+ memcpy(&pszDir[cchDir], pDirEntry->szName, pDirEntry->cbName + 1);
+ if (iLogDepth > 0)
+ RTMsgInfo("%s%s ...\n", pszDir, RTPATH_SLASH_STR);
+ RTEXITCODE rcExit2 = processDirSub(pszDir, cchDir + pDirEntry->cbName, pDirEntry, iLogDepth - 1);
+ if (rcExit2 != RTEXITCODE_SUCCESS)
+ rcExit = rcExit2;
+ }
+ }
+ }
+ if (rc != VERR_NO_MORE_FILES)
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirReadEx failed: %Rrc\npszDir=%.*s", rc, cchDir, pszDir);
+
+ rc = RTDirClose(pDir);
+ if (RT_FAILURE(rc))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirClose failed: %Rrc\npszDir=%.*s", rc, cchDir, pszDir);
+ return rcExit;
+}
+
+
+/**
+ * Recursively processes relevant files in the specified directory.
+ *
+ * @returns Fully complained exit code.
+ * @param pszDir The directory to search.
+ */
+static RTEXITCODE processDir(const char *pszDir)
+{
+ char szPath[RTPATH_MAX];
+ int rc = RTPathAbs(pszDir, szPath, sizeof(szPath));
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed on '%s': %Rrc\n", pszDir, rc);
+
+ union
+ {
+ uint8_t abPadding[MY_DIRENTRY_BUF_SIZE];
+ RTDIRENTRYEX DirEntry;
+ } uBuf;
+ return processDirSub(szPath, strlen(szPath), &uBuf.DirEntry, g_iOptVerbose);
+}
+
+
+int main(int argc, char **argv)
+{
+ int rc = RTR3InitExe(argc, &argv, 0 /*fFlags*/);
+ if (RT_FAILURE(rc))
+ return RTMsgInitFailure(rc);
+
+ RTListInit(&g_SetList);
+
+ /*
+ * Parse options.
+ */
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ { "--force", 'f', RTGETOPT_REQ_NOTHING },
+ { "--output", 'o', RTGETOPT_REQ_STRING },
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+ { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
+ };
+
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ const char *pszOutput = "-";
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
+ RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
+ {
+ switch (ch)
+ {
+ case 'f':
+ g_fOptForce = true;
+ break;
+
+ case 'v':
+ g_iOptVerbose++;
+ break;
+
+ case 'q':
+ g_iOptVerbose++;
+ break;
+
+ case 'o':
+ pszOutput = ValueUnion.psz;
+ break;
+
+ case 'V':
+ RTPrintf("$Revision: 92629 $");
+ break;
+
+ case 'h':
+ RTPrintf("usage: %s [-v|--verbose] [-q|--quiet] [-f|--force] [-o|--output <file.h>] <dir1|pdb1> [...]\n"
+ " or: %s [-V|--version]\n"
+ " or: %s [-h|--help]\n",
+ argv[0], argv[0], argv[0]);
+ return RTEXITCODE_SUCCESS;
+
+ case VINF_GETOPT_NOT_OPTION:
+ {
+ RTEXITCODE rcExit2;
+ if (RTFileExists(ValueUnion.psz))
+ rcExit2 = processPdb(ValueUnion.psz);
+ else
+ rcExit2 = processDir(ValueUnion.psz);
+ if (rcExit2 != RTEXITCODE_SUCCESS)
+ {
+ if (!g_fOptForce)
+ return rcExit2;
+ rcExit = rcExit2;
+ }
+ break;
+ }
+
+ default:
+ return RTGetOptPrintError(ch, &ValueUnion);
+ }
+ }
+ if (RTListIsEmpty(&g_SetList))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "No usable debug files found.\n");
+
+ /*
+ * Generate the output.
+ */
+ PRTSTREAM pOut = g_pStdOut;
+ if (strcmp(pszOutput, "-"))
+ {
+ rc = RTStrmOpen(pszOutput, "w", &pOut);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening '%s' for writing: %Rrc\n", pszOutput, rc);
+ }
+
+ generateHeader(pOut);
+
+ if (pOut != g_pStdOut)
+ rc = RTStrmClose(pOut);
+ else
+ rc = RTStrmFlush(pOut);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error %s '%s': %Rrc\n", pszOutput,
+ pOut != g_pStdOut ? "closing" : "flushing", rc);
+ return rcExit;
+}
diff --git a/src/VBox/Runtime/r0drv/nt/process-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/process-r0drv-nt.cpp
index 93488765..ac45498b 100644
--- a/src/VBox/Runtime/r0drv/nt/process-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/process-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/semevent-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/semevent-r0drv-nt.cpp
index 8cda329e..46cd1d7a 100644
--- a/src/VBox/Runtime/r0drv/nt/semevent-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/semevent-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/semeventmulti-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/semeventmulti-r0drv-nt.cpp
index 50830f75..3d253c55 100644
--- a/src/VBox/Runtime/r0drv/nt/semeventmulti-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/semeventmulti-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/semfastmutex-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/semfastmutex-r0drv-nt.cpp
index bd3efc87..eabbc3e1 100644
--- a/src/VBox/Runtime/r0drv/nt/semfastmutex-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/semfastmutex-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/semmutex-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/semmutex-r0drv-nt.cpp
index 71e02e35..f7b68c4b 100644
--- a/src/VBox/Runtime/r0drv/nt/semmutex-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/semmutex-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/spinlock-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/spinlock-r0drv-nt.cpp
index d3dad434..00dbd3ed 100644
--- a/src/VBox/Runtime/r0drv/nt/spinlock-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/spinlock-r0drv-nt.cpp
@@ -74,7 +74,7 @@ typedef struct RTSPINLOCKINTERNAL
/** The saved IRQL. */
KIRQL volatile SavedIrql;
/** The saved interrupt flag. */
- uint32_t volatile fIntSaved;
+ RTCCUINTREG volatile fIntSaved;
/** The spinlock creation flags. */
uint32_t fFlags;
/** The NT spinlock structure. */
@@ -140,7 +140,7 @@ RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
{
#ifndef RTSPINLOCK_NT_HACK_NOIRQ
- uint32_t fIntSaved = ASMGetFlags();
+ RTCCUINTREG fIntSaved = ASMGetFlags();
ASMIntDisable();
KeAcquireSpinLock(&pThis->Spinlock, &SavedIrql);
#else
@@ -150,7 +150,7 @@ RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
KeRaiseIrql(DISPATCH_LEVEL, &SavedIrql);
Assert(SavedIrql < DISPATCH_LEVEL);
}
- uint32_t fIntSaved = ASMGetFlags();
+ RTCCUINTREG fIntSaved = ASMGetFlags();
ASMIntDisable();
if (!ASMAtomicCmpXchgU32(&pThis->u32Hack, RTSPINLOCK_NT_HACK_NOIRQ_TAKEN, RTSPINLOCK_NT_HACK_NOIRQ_FREE))
@@ -176,7 +176,7 @@ RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
KIRQL SavedIrql = pThis->SavedIrql;
if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
{
- uint32_t fIntSaved = pThis->fIntSaved;
+ RTCCUINTREG fIntSaved = pThis->fIntSaved;
pThis->fIntSaved = 0;
#ifndef RTSPINLOCK_NT_HACK_NOIRQ
diff --git a/src/VBox/Runtime/r0drv/nt/symdb.h b/src/VBox/Runtime/r0drv/nt/symdb.h
new file mode 100644
index 00000000..3a0f12d5
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/nt/symdb.h
@@ -0,0 +1,85 @@
+/* $Id: symdb.h $ */
+/** @file
+ * IPRT - Internal Header for the NT Ring-0 Driver Symbol DB.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_r0drv_nt_symdb_h
+#define ___internal_r0drv_nt_symdb_h
+
+#include <iprt/types.h>
+
+
+/**
+ * NT Version info.
+ */
+typedef struct RTNTSDBOSVER
+{
+ /** The major version number. */
+ uint8_t uMajorVer;
+ /** The minor version number. */
+ uint8_t uMinorVer;
+ /** Set if checked build, clear if free (retail) build. */
+ uint8_t fChecked : 1;
+ /** Set if multi processor kernel. */
+ uint8_t fSmp : 1;
+ /** The service pack number. */
+ uint8_t uCsdNo : 6;
+ /** The build number. */
+ uint32_t uBuildNo;
+} RTNTSDBOSVER;
+/** Pointer to NT version info. */
+typedef RTNTSDBOSVER *PRTNTSDBOSVER;
+/** Pointer to const NT version info. */
+typedef RTNTSDBOSVER const *PCRTNTSDBOSVER;
+
+
+/**
+ * Compare NT OS version structures.
+ *
+ * @retval 0 if equal
+ * @retval 1 if @a pInfo1 is newer/greater than @a pInfo2
+ * @retval -1 if @a pInfo1 is older/less than @a pInfo2
+ *
+ * @param pInfo1 The first version info structure.
+ * @param pInfo2 The second version info structure.
+ */
+DECLINLINE(int) rtNtOsVerInfoCompare(PCRTNTSDBOSVER pInfo1, PCRTNTSDBOSVER pInfo2)
+{
+ if (pInfo1->uMajorVer != pInfo2->uMajorVer)
+ return pInfo1->uMajorVer > pInfo2->uMajorVer ? 1 : -1;
+ if (pInfo1->uMinorVer != pInfo2->uMinorVer)
+ return pInfo1->uMinorVer > pInfo2->uMinorVer ? 1 : -1;
+ if (pInfo1->uBuildNo != pInfo2->uBuildNo)
+ return pInfo1->uBuildNo > pInfo2->uBuildNo ? 1 : -1;
+ if (pInfo1->uCsdNo != pInfo2->uCsdNo)
+ return pInfo1->uCsdNo > pInfo2->uCsdNo ? 1 : -1;
+ if (pInfo1->fSmp != pInfo2->fSmp)
+ return pInfo1->fSmp > pInfo2->fSmp ? 1 : -1;
+ if (pInfo1->fChecked != pInfo2->fChecked)
+ return pInfo1->fChecked > pInfo2->fChecked ? 1 : -1;
+ return 0;
+}
+
+#endif
+
diff --git a/src/VBox/Runtime/r0drv/nt/symdbdata.h b/src/VBox/Runtime/r0drv/nt/symdbdata.h
new file mode 100644
index 00000000..d23aca8d
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/nt/symdbdata.h
@@ -0,0 +1,2920 @@
+/* $Id: symdbdata.h $ */
+/** @file
+ * IPRT - NT kernel type helpers - Autogenerated, do NOT edit.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___r0drv_nt_symdbdata_h
+#define ___r0drv_nt_symdbdata_h
+
+#include "r0drv/nt/symdb.h"
+
+typedef struct RTNTSDBTYPE_KPRCB
+{
+ uint32_t offQuantumEnd;
+ uint32_t cbQuantumEnd;
+ uint32_t offDpcQueueDepth;
+ uint32_t cbDpcQueueDepth;
+ uint32_t offVendorString;
+ uint32_t cbVendorString;
+} RTNTSDBTYPE_KPRCB;
+
+
+typedef struct RTNTSDBSET
+{
+ RTNTSDBOSVER OsVerInfo;
+ RTNTSDBTYPE_KPRCB KPRCB;
+} RTNTSDBSET;
+typedef RTNTSDBSET const *PCRTNTSDBSET;
+
+
+#ifndef RTNTSDB_NO_DATA
+const RTNTSDBSET g_artNtSdbSets[] =
+{
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_nec98\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_en\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_en_chk\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_en_chk\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_nec98\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_nec98\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_en\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_en\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_en_chk\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp3sym_en_chk\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\Windows2000-KB891861-x86-Symbols-ENU\symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\Windows2000-KB891861-x86-Symbols-ENU\symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_en\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_nec98\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\Windows2000-KB891861-nec98-Symbols-JPN\symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\Windows2000-KB891861-nec98-Symbols-JPN\symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_en_chk\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_en_chk\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\Windows2000-KB891861-x86-Symbols-ENU\symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\Windows2000-KB891861-x86-Symbols-ENU\symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_en\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_en\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_nec98\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_nec98\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\Windows2000-KB891861-nec98-Symbols-JPN\symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\Windows2000-KB891861-nec98-Symbols-JPN\symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_en_chk\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\uold\w2ksp4sym_en_chk\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 4,
+ /* .uBuildNo = */ 2195,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0750,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x06e8,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x072d,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\windowsxp.x86.fre.rtm.symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\windowsxp.x86.fre.rtm.symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\windowsxp.x86.chk.rtm.symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\windowsxp.x86.chk.rtm.symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\windowsxp.x86.fre.rtm.symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\windowsxp.x86.fre.rtm.symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\windowsxp.x86.chk.rtm.symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\windowsxp.x86.chk.rtm.symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\xpsp1sym_x86\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\xpsp1sym_x86\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\xpsp1sym_x86_chk\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\xpsp1sym_x86_chk\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\xpsp1sym_x86\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\xpsp1sym_x86\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\xpsp1sym_x86_chk\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\xpsp1sym_x86_chk\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB835935-SP2-slp-Symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB835935-SP2-slp-Symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB835935-SP2-Debug-slp-Symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB835935-SP2-Debug-slp-Symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB835935-SP2-slp-Symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB835935-SP2-slp-Symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB835935-SP2-Debug-slp-Symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB835935-SP2-Debug-slp-Symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB936929-SP3-x86-symbols-full-ENU\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB936929-SP3-x86-symbols-full-ENU\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB936929-SP3-x86-DEBUG-symbols-full-ENU-DEBUG\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB936929-SP3-x86-DEBUG-symbols-full-ENU-DEBUG\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB936929-SP3-x86-symbols-full-ENU\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB936929-SP3-x86-symbols-full-ENU\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB936929-SP3-x86-DEBUG-symbols-full-ENU-DEBUG\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsXP-KB936929-SP3-x86-DEBUG-symbols-full-ENU-DEBUG\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 3,
+ /* .uBuildNo = */ 2600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x088c,
+ /* .cbQuantumEnd = */ 0x0004,
+ /* .offDpcQueueDepth = */ 0x0870,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0900,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003.x86.fre.rtm.symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x08c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x086c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0a78,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003.x86.fre.rtm.symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x08c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x086c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0a78,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003.x86.chk.rtm.symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x08c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x086c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0a78,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003.x86.chk.rtm.symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x08c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x086c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0a78,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003.x86.fre.rtm.symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x08c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x086c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0a78,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003.x86.fre.rtm.symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x08c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x086c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0a78,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003.x86.chk.rtm.symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x08c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x086c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0a78,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003.x86.chk.rtm.symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x08c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x086c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0a78,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x64-symbols-NRL-ENU\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1f75,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x1f18,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x22b4,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.x86.fre.rtm.symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.x86.fre.rtm.symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x86-symbols-NRL-ENU\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x86-symbols-NRL-ENU\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.amd64.fre.rtm.symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1f75,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x1f18,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x22b4,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x86-symbols-NRL-ENU-DEBUG\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x86-symbols-NRL-ENU-DEBUG\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x64-symbols-NRL-ENU-DEBUG\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1f75,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x1f18,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x22b4,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.x86.chk.rtm.symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.x86.chk.rtm.symbols\exe\ntkrnlpa.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.amd64.chk.rtm.symbols\exe\ntoskrnl.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ false,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1f75,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x1f18,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x22b4,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x64-symbols-NRL-ENU\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1f75,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x1f18,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x22b4,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.x86.fre.rtm.symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.x86.fre.rtm.symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x86-symbols-NRL-ENU\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x86-symbols-NRL-ENU\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.amd64.fre.rtm.symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1f75,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x1f18,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x22b4,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x86-symbols-NRL-ENU-DEBUG\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x86-symbols-NRL-ENU-DEBUG\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsServer2003-KB933548-v1-x64-symbols-NRL-ENU-DEBUG\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1f75,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x1f18,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x22b4,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.x86.chk.rtm.symbols\exe\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.x86.chk.rtm.symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x0981,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x092c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x0b60,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows2003_sp1.amd64.chk.rtm.symbols\exe\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 5,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 3790,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1f75,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x1f18,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x22b4,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsVista.6000.061101-2205.x86fre.Symbols\EXE\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 6000,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x19c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x196c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1bac,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsVista.6000.061101-2205.x86fre.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 6000,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x19c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x196c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1bac,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\WindowsVista.6000.061101-2205.amd64fre.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 6000,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x3375,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x3318,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x38bc,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsVista.6000.061101-2205.x86chk.Symbols\EXE\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 6000,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x19c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x196c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1bac,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsVista.6000.061101-2205.x86chk.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 6000,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x19c1,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x196c,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1bac,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\WindowsVista.6000.061101-2205.amd64chk.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 6000,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x3375,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x3318,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x38bc,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Longhorn.6001.080118-1840.x86fre.Symbols\EXE\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 6001,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1a41,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x19ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1c2c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Longhorn.6001.080118-1840.x86fre.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 6001,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1a41,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x19ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1c2c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows_Longhorn.6001.080118-1840.amd64fre.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 6001,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x3475,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x3418,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x399c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Longhorn.6001.080118-1840.x86chk.Symbols\EXE\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 6001,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1a41,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x19ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1c2c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Longhorn.6001.080118-1840.x86chk.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 6001,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1a41,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x19ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1c2c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows_Longhorn.6001.080118-1840.amd64chk.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 6001,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x3475,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x3418,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x399c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsVista.6002.090410-1830.x86fre.Symbols\EXE\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 6002,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1a41,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x19ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1c2c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsVista.6002.090410-1830.x86fre.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 6002,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1a41,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x19ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1c2c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\WindowsVista.6002.090410-1830.amd64fre.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 6002,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x3475,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x3418,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x399c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsVista.6002.090410-1830.x86chk.Symbols\EXE\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 6002,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1a41,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x19ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1c2c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\WindowsVista.6002.090410-1830.x86chk.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 6002,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1a41,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x19ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x1c2c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\WindowsVista.6002.090410-1830.amd64chk.Symbols\EXE\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 2,
+ /* .uBuildNo = */ 6002,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x3475,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x3418,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x399c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win7.7600.16385.090713-1255.X86FRE.Symbols\Symbols\ntkrpamp.pdb\5B308B4ED6464159B87117C711E7340C2\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 7600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1931,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x18ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x336c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win7.7600.16385.090713-1255.X86FRE.Symbols\Symbols\ntkrnlmp.pdb\998A3472EEA6405CB8C089DE868F26222\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 7600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1931,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x18ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x336c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows_Win7.7600.16385.090713-1255.X64FRE.Symbols\Symbols\ntkrnlmp.pdb\F8E2A8B5C9B74BF4A6E4A48F180099942\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 7600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x21d9,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x2198,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x4bb8,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win7.7600.16385.090713-1255.X86CHK.Symbols\Symbols\ntkrnlmp.pdb\9E7882E37C3E4AC9BB60F4EAD9DB492A1\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 7600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1931,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x18ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x336c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win7.7600.16385.090713-1255.X86CHK.Symbols\Symbols\ntkrpamp.pdb\3269AC66C11B41FC995991F129E95D5C1\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 7600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1931,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x18ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x336c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows_Win7.7600.16385.090713-1255.X64CHK.Symbols\Symbols\ntkrnlmp.pdb\C491E3167994497FA91338D08A7787041\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 7600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x21d9,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x2198,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x4bb8,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win7SP1.7601.17514.101119-1850.X86FRE.Symbols\Symbols\ntkrpamp.pdb\684DA42A30CC450F81C535B4D18944B12\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 7601,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1931,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x18ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x336c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win7SP1.7601.17514.101119-1850.X86FRE.Symbols\Symbols\ntkrnlmp.pdb\00625D7D36754CBEBA4533BA9A0F3FE22\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 7601,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1931,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x18ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x336c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows_Win7SP1.7601.17514.101119-1850.AMD64FRE.Symbols\Symbols\ntkrnlmp.pdb\3844DBB920174967BE7AA4A2C20430FA2\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 7601,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x21d9,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x2198,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x4bb8,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win7SP1.7601.17514.101119-1850.X86CHK.Symbols\Symbols\ntkrpamp.pdb\C3355A163C47464183D85DE0B836F83A1\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 7601,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1931,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x18ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x336c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win7SP1.7601.17514.101119-1850.X86CHK.Symbols\Symbols\ntkrnlmp.pdb\1477BEA3E003427CB248D5233B0601951\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 7601,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x1931,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x18ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x336c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows_Win7SP1.7601.17514.101119-1850.AMD64CHK.Symbols\Symbols\ntkrnlmp.pdb\FF0DE75C807A4B85A7668D2113A62EF11\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 1,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 1,
+ /* .uBuildNo = */ 7601,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x21d9,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x2198,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x4bb8,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win8.9200.16384.120725-1247.X86FRE.Symbols\Symbols\ntkrpamp.pdb\E2342527EA214C109CD28A19ED4FBCCE2\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 9200,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2231,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x21ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x3c7c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows_Win8.9200.16384.120725-1247.x64FRE.Symbols\Symbols\ntkrnlmp.pdb\724821001C1C4A03AED8C4C71C2E8D1D2\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 9200,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2dd9,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x2d98,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x5948,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\Windows_Win8.9200.16384.120725-1247.X86CHK.Symbols\Symbols\ntkrpamp.pdb\C4F414C9D1854DE495BDAD814A722C4D1\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 9200,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2231,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x21ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x3c7c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\Windows_Win8.9200.16384.120725-1247.x64CHK.Symbols\Symbols\ntkrnlmp.pdb\FC0361C3243D459496EE02EF1A7ACD271\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 2,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 9200,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2dd9,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x2d98,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x5948,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\en_windows_8_1_symbols_x86_2712593\ntkrpamp.pdb\9DC1F995475C456C8D1AA9606E3106931\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 3,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 9600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2239,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x21ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x3c7c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\en_windows_8_1_symbols_x64_2712576\ntkrnlmp.pdb\A9BBA3C139724A738BE17665DB4393CA1\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 3,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 9600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2de9,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x2d98,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x5958,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\en_windows_8_1_symbols_debug_checked_x86_2712583\ntkrpamp.pdb\77DAB075113647B5888133D3F79B7B171\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 3,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 9600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2239,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x21ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x3c7c,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\en_windows_8_1_symbols_debug_checked_x64_2712568\ntkrnlmp.pdb\4C5FFE3E839647C5B9471D0C8F9710E11\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 6,
+ /* .uMinorVer = */ 3,
+ /* .fChecked = */ true,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 9600,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2de9,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x2d98,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x5958,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+};
+#endif /* !RTNTSDB_NO_DATA */
+
+
+#endif
+
diff --git a/src/VBox/Runtime/r0drv/nt/the-nt-kernel.h b/src/VBox/Runtime/r0drv/nt/the-nt-kernel.h
index f84e515b..44a805ba 100644
--- a/src/VBox/Runtime/r0drv/nt/the-nt-kernel.h
+++ b/src/VBox/Runtime/r0drv/nt/the-nt-kernel.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/thread-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/thread-r0drv-nt.cpp
index 6bd17558..e16a0f8f 100644
--- a/src/VBox/Runtime/r0drv/nt/thread-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/thread-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -106,6 +106,7 @@ RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread)
/*
* Read the globals and check if they are useful.
*/
+/** @todo Should we check KPRCB.InterruptRequest and KPRCB.DpcInterruptRequested (older kernels). */
uint32_t const offQuantumEnd = g_offrtNtPbQuantumEnd;
uint32_t const cbQuantumEnd = g_cbrtNtPbQuantumEnd;
uint32_t const offDpcQueueDepth = g_offrtNtPbDpcQueueDepth;
@@ -159,10 +160,14 @@ RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread)
RTDECL(bool) RTThreadPreemptIsPendingTrusty(void)
{
+#if 0 /** @todo RTThreadPreemptIsPending isn't good enough on w7 and possibly elsewhere. */
/* RTThreadPreemptIsPending is only reliable if we've got both offsets and size. */
return g_offrtNtPbQuantumEnd != 0
&& g_cbrtNtPbQuantumEnd != 0
&& g_offrtNtPbDpcQueueDepth != 0;
+#else
+ return false;
+#endif
}
diff --git a/src/VBox/Runtime/r0drv/nt/thread2-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/thread2-r0drv-nt.cpp
index 855a8549..4863194b 100644
--- a/src/VBox/Runtime/r0drv/nt/thread2-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/thread2-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/nt/time-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/time-r0drv-nt.cpp
index 965f2cbb..938cc7c1 100644
--- a/src/VBox/Runtime/r0drv/nt/time-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/time-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -35,10 +35,24 @@
DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void)
{
-#ifndef IPRT_TARGET_NT4
+ /*
+ * Note! The time source we use here must be exactly the same as in
+ * the ring-3 code!
+ *
+ * Using interrupt time is the simplest and requires the least calculation.
+ * It is also accounting for suspended time. Unfortuantely, there is no
+ * ring-3 for reading it... but that won't stop us.
+ *
+ * Using the tick count is problematic in ring-3 on older windows version
+ * as we can only get the 32-bit tick value, i.e. we'll roll over sooner or
+ * later.
+ */
+#if 1
+ /* Interrupt time. (NT4 doesn't have an API for it.) */
+# ifndef IPRT_TARGET_NT4
ULONGLONG InterruptTime = KeQueryInterruptTime();
return (uint64_t)InterruptTime * 100; /* The value is in 100ns, convert to ns units. */
-#else
+# else
LARGE_INTEGER InterruptTime;
do
{
@@ -47,6 +61,12 @@ DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void)
} while (((KUSER_SHARED_DATA volatile *)SharedUserData)->InterruptTime.High2Time != InterruptTime.HighPart);
return (uint64_t)InterruptTime.QuadPart * 100;
+# endif
+#else
+ /* Tick Count (NT4 SP1 has these APIs, haven't got SP0 to check). */
+ LARGE_INTEGER Tick;
+ KeQueryTickCount(&Tick);
+ return (uint64_t)Tick.QuadPart * KeQueryTimeIncrement() * 100;
#endif
}
diff --git a/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp b/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp
index ee014310..67764b62 100644
--- a/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp
+++ b/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -121,7 +121,11 @@ static void _stdcall rtTimerNtSimpleCallback(IN PKDPC pDpc, IN PVOID pvUser, IN
*/
if ( !ASMAtomicUoReadBool(&pTimer->fSuspended)
&& pTimer->u32Magic == RTTIMER_MAGIC)
+ {
+ if (!pTimer->u64NanoInterval)
+ ASMAtomicWriteBool(&pTimer->fSuspended, true);
pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->aSubTimers[0].iTick);
+ }
NOREF(pDpc); NOREF(SystemArgument1); NOREF(SystemArgument2);
}
@@ -154,7 +158,11 @@ static void _stdcall rtTimerNtOmniSlaveCallback(IN PKDPC pDpc, IN PVOID pvUser,
*/
if ( !ASMAtomicUoReadBool(&pTimer->fSuspended)
&& pTimer->u32Magic == RTTIMER_MAGIC)
+ {
+ if (!pTimer->u64NanoInterval)
+ ASMAtomicWriteBool(&pTimer->fSuspended, true);
pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
+ }
NOREF(pDpc); NOREF(SystemArgument1); NOREF(SystemArgument2);
}
@@ -199,6 +207,8 @@ static void _stdcall rtTimerNtOmniMasterCallback(IN PKDPC pDpc, IN PVOID pvUser,
&& iCpuSelf != iCpu)
KeInsertQueueDpc(&pTimer->aSubTimers[iCpu].NtDpc, 0, 0);
+ if (!pTimer->u64NanoInterval)
+ ASMAtomicWriteBool(&pTimer->fSuspended, true);
pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
}
@@ -237,9 +247,12 @@ RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
LARGE_INTEGER DueTime;
DueTime.QuadPart = -(int64_t)(u64First / 100); /* Relative, NT time. */
- if (DueTime.QuadPart)
+ if (!DueTime.QuadPart)
DueTime.QuadPart = -1;
+ unsigned cSubTimers = pTimer->fOmniTimer ? pTimer->cSubTimers : 1;
+ for (unsigned iCpu = 0; iCpu < cSubTimers; iCpu++)
+ pTimer->aSubTimers[iCpu].iTick = 0;
ASMAtomicWriteBool(&pTimer->fSuspended, false);
KeSetTimerEx(&pTimer->NtTimer, DueTime, ulInterval, pMasterDpc);
return VINF_SUCCESS;
diff --git a/src/VBox/Runtime/r0drv/os2/memuserkernel-r0drv-os2.cpp b/src/VBox/Runtime/r0drv/os2/memuserkernel-r0drv-os2.cpp
index ea58e623..0a596bbd 100644
--- a/src/VBox/Runtime/r0drv/os2/memuserkernel-r0drv-os2.cpp
+++ b/src/VBox/Runtime/r0drv/os2/memuserkernel-r0drv-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/os2/semevent-r0drv-os2.cpp b/src/VBox/Runtime/r0drv/os2/semevent-r0drv-os2.cpp
index e597ad45..0dc74266 100644
--- a/src/VBox/Runtime/r0drv/os2/semevent-r0drv-os2.cpp
+++ b/src/VBox/Runtime/r0drv/os2/semevent-r0drv-os2.cpp
@@ -181,8 +181,8 @@ static int rtR0SemEventOs2Wait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint6
ULONG fBlock = BLOCK_SPINLOCK;
if (!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE))
fBlock |= BLOCK_UNINTERRUPTABLE;
-
- /*
+
+ /*
* Do the job.
*/
KernAcquireSpinLock(&pThis->Spinlock);
diff --git a/src/VBox/Runtime/r0drv/os2/semeventmulti-r0drv-os2.cpp b/src/VBox/Runtime/r0drv/os2/semeventmulti-r0drv-os2.cpp
index ea0bda5d..ae06e211 100644
--- a/src/VBox/Runtime/r0drv/os2/semeventmulti-r0drv-os2.cpp
+++ b/src/VBox/Runtime/r0drv/os2/semeventmulti-r0drv-os2.cpp
@@ -192,8 +192,8 @@ static int rtR0SemEventMultiOs2Wait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFl
ULONG fBlock = BLOCK_SPINLOCK;
if (!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE))
fBlock |= BLOCK_UNINTERRUPTABLE;
-
- /*
+
+ /*
* Do the job.
*/
KernAcquireSpinLock(&pThis->Spinlock);
diff --git a/src/VBox/Runtime/r0drv/os2/spinlock-r0drv-os2.cpp b/src/VBox/Runtime/r0drv/os2/spinlock-r0drv-os2.cpp
index 531e88f6..39be522a 100644
--- a/src/VBox/Runtime/r0drv/os2/spinlock-r0drv-os2.cpp
+++ b/src/VBox/Runtime/r0drv/os2/spinlock-r0drv-os2.cpp
@@ -38,6 +38,9 @@
#include <iprt/alloc.h>
#include <iprt/assert.h>
#include <iprt/asm.h>
+#ifdef RT_STRICT
+# include <iprt/asm-amd64-x86.h>
+#endif
#include "internal/magics.h"
diff --git a/src/VBox/Runtime/r0drv/power-r0drv.h b/src/VBox/Runtime/r0drv/power-r0drv.h
index a10c4c1e..ba1ada04 100644
--- a/src/VBox/Runtime/r0drv/power-r0drv.h
+++ b/src/VBox/Runtime/r0drv/power-r0drv.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/powernotification-r0drv.c b/src/VBox/Runtime/r0drv/powernotification-r0drv.c
index 138e5c4b..87d73d0f 100644
--- a/src/VBox/Runtime/r0drv/powernotification-r0drv.c
+++ b/src/VBox/Runtime/r0drv/powernotification-r0drv.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/RTLogWriteDebugger-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/RTLogWriteDebugger-r0drv-solaris.c
index 0414bcd4..34718740 100644
--- a/src/VBox/Runtime/r0drv/solaris/RTLogWriteDebugger-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/RTLogWriteDebugger-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -37,6 +37,7 @@
# include <iprt/asm-amd64-x86.h>
#endif
#include <iprt/assert.h>
+#include <iprt/thread.h>
@@ -44,6 +45,11 @@ RTDECL(void) RTLogWriteDebugger(const char *pch, size_t cb)
{
if (pch[cb] != '\0')
AssertBreakpoint();
+
+ /* cmn_err() acquires adaptive mutexes. Not preemption safe, see @bugref{6657}. */
+ if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+ return;
+
if ( !g_frtSolSplSetsEIF
#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
|| ASMIntAreEnabled()
@@ -51,7 +57,10 @@ RTDECL(void) RTLogWriteDebugger(const char *pch, size_t cb)
/* PORTME: Check if interrupts are enabled, if applicable. */
#endif
)
+ {
cmn_err(CE_CONT, pch);
+ }
+
return;
}
diff --git a/src/VBox/Runtime/r0drv/solaris/RTMpPokeCpu-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/RTMpPokeCpu-r0drv-solaris.c
index 60e75765..eb49b625 100644
--- a/src/VBox/Runtime/r0drv/solaris/RTMpPokeCpu-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/RTMpPokeCpu-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/alloc-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/alloc-r0drv-solaris.c
index 83013b8b..fc31009d 100644
--- a/src/VBox/Runtime/r0drv/solaris/alloc-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/alloc-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -73,7 +73,7 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
#ifdef RT_ARCH_AMD64
if (fFlags & RTMEMHDR_FLAG_EXEC)
{
- AssertReturn(!(fFlags & RTMEMHDR_FLAG_ANY_CTX), NULL);
+ AssertReturn(!(fFlags & RTMEMHDR_FLAG_ANY_CTX), VERR_NOT_SUPPORTED);
cbAllocated = RT_ALIGN_Z(cb + sizeof(*pHdr), PAGE_SIZE) - sizeof(*pHdr);
pHdr = (PRTMEMHDR)segkmem_alloc(heaptext_arena, cbAllocated + sizeof(*pHdr), KM_SLEEP);
}
diff --git a/src/VBox/Runtime/r0drv/solaris/assert-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/assert-r0drv-solaris.c
index ce6fe0dd..823c18aa 100644
--- a/src/VBox/Runtime/r0drv/solaris/assert-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/assert-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/initterm-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/initterm-r0drv-solaris.c
index 3fa8dbea..0d435364 100644
--- a/src/VBox/Runtime/r0drv/solaris/initterm-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/initterm-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -66,6 +66,10 @@ bool g_frtSolOldIPI = false;
bool g_frtSolOldIPIUlong = false;
/** The xc_call callout table structure. */
RTR0FNSOLXCCALL g_rtSolXcCall;
+/** Whether to use the old-style installctx()/removectx() routines. */
+bool g_frtSolOldThreadCtx = false;
+/** The thread-context hooks callout table structure. */
+RTR0FNSOLTHREADCTX g_rtSolThreadCtx;
/** Thread preemption offset. */
size_t g_offrtSolThreadPreempt;
/** Host scheduler preemption offset. */
@@ -126,9 +130,9 @@ DECLHIDDEN(int) rtR0InitNative(void)
cmn_err(CE_NOTE, "Failed to find kthread_t::t_preempt!\n");
goto errorbail;
}
- cmn_err(CE_CONT, "!cpu_t::cpu_runrun @ 0x%lx\n", g_offrtSolCpuPreempt);
- cmn_err(CE_CONT, "!cpu_t::cpu_kprunrun @ 0x%lx\n", g_offrtSolCpuForceKernelPreempt);
- cmn_err(CE_CONT, "!kthread_t::t_preempt @ 0x%lx\n", g_offrtSolThreadPreempt);
+ cmn_err(CE_CONT, "!cpu_t::cpu_runrun @ 0x%lx (%ld)\n", g_offrtSolCpuPreempt, g_offrtSolCpuPreempt);
+ cmn_err(CE_CONT, "!cpu_t::cpu_kprunrun @ 0x%lx (%ld)\n", g_offrtSolCpuForceKernelPreempt, g_offrtSolCpuForceKernelPreempt);
+ cmn_err(CE_CONT, "!kthread_t::t_preempt @ 0x%lx (%ld)\n", g_offrtSolThreadPreempt, g_offrtSolThreadPreempt);
/*
* Mandatory: CPU cross call infrastructure. Refer the-solaris-kernel.h for details.
@@ -163,6 +167,22 @@ DECLHIDDEN(int) rtR0InitNative(void)
}
/*
+ * Mandatory: Thread-context hooks.
+ */
+ rc = RTR0DbgKrnlInfoQuerySymbol(g_hKrnlDbgInfo, NULL /* pszModule */, "exitctx", NULL /* ppvSymbol */);
+ if (RT_SUCCESS(rc))
+ {
+ g_rtSolThreadCtx.Install.pfnSol_installctx = (void *)installctx;
+ g_rtSolThreadCtx.Remove.pfnSol_removectx = (void *)removectx;
+ }
+ else
+ {
+ g_frtSolOldThreadCtx = true;
+ g_rtSolThreadCtx.Install.pfnSol_installctx_old = (void *)installctx;
+ g_rtSolThreadCtx.Remove.pfnSol_removectx_old = (void *)removectx;
+ }
+
+ /*
* Optional: Timeout hooks.
*/
RTR0DbgKrnlInfoQuerySymbol(g_hKrnlDbgInfo, NULL /* pszModule */, "timeout_generic",
diff --git a/src/VBox/Runtime/r0drv/solaris/memobj-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/memobj-r0drv-solaris.c
index 68741df0..b5e0ee6f 100644
--- a/src/VBox/Runtime/r0drv/solaris/memobj-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/memobj-r0drv-solaris.c
@@ -143,6 +143,10 @@ static page_t *rtR0MemObjSolPageAlloc(caddr_t virtAddr)
u_offset_t offPage;
seg_t KernelSeg;
+ /*
+ * 16777215 terabytes of total memory for all VMs or
+ * restart 8000 1GB VMs 2147483 times until wraparound!
+ */
mutex_enter(&g_OffsetMtx);
AssertCompileSize(u_offset_t, sizeof(uint64_t)); NOREF(RTASSERTVAR);
g_offPage = RT_ALIGN_64(g_offPage, PAGE_SIZE) + PAGE_SIZE;
@@ -968,7 +972,7 @@ DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ
size_t off = 0;
while (off < cbSub)
{
- RTHCPHYS HCPhys = rtR0MemObjNativeGetPagePhysAddr(pMemToMap, (offSub + offSub) >> PAGE_SHIFT);
+ RTHCPHYS HCPhys = RTR0MemObjGetPagePhysAddr(pMemToMap, (offSub + offSub) >> PAGE_SHIFT);
AssertBreakStmt(HCPhys != NIL_RTHCPHYS, rc = VERR_INTERNAL_ERROR_2);
pfn_t pfn = HCPhys >> PAGE_SHIFT;
AssertBreakStmt(((RTHCPHYS)pfn << PAGE_SHIFT) == HCPhys, rc = VERR_INTERNAL_ERROR_3);
diff --git a/src/VBox/Runtime/r0drv/solaris/memuserkernel-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/memuserkernel-r0drv-solaris.c
index bb16c9b0..4e1e8183 100644
--- a/src/VBox/Runtime/r0drv/solaris/memuserkernel-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/memuserkernel-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/mp-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/mp-r0drv-solaris.c
index fb3b8c28..3a9dce99 100644
--- a/src/VBox/Runtime/r0drv/solaris/mp-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/mp-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -136,9 +136,9 @@ RTDECL(RTCPUID) RTMpGetOnlineCount(void)
/**
* Wrapper to Solaris IPI infrastructure.
*
- * @param pCpuSet Pointer to Solaris CPU set.
- * @param pfnSolWorker Function to execute on target CPU(s).
- * @param pArgs Pointer to RTMPARGS to pass to @a pfnSolWorker.
+ * @param pCpuSet Pointer to Solaris CPU set.
+ * @param pfnSolWorker Function to execute on target CPU(s).
+ * @param pArgs Pointer to RTMPARGS to pass to @a pfnSolWorker.
*
* @returns Solaris error code.
*/
diff --git a/src/VBox/Runtime/r0drv/solaris/mpnotification-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/mpnotification-r0drv-solaris.c
index fcfb286d..a7c1f9b6 100644
--- a/src/VBox/Runtime/r0drv/solaris/mpnotification-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/mpnotification-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/process-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/process-r0drv-solaris.c
index f5c46121..2b4a96af 100644
--- a/src/VBox/Runtime/r0drv/solaris/process-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/process-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/semevent-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/semevent-r0drv-solaris.c
index f52bd57c..5c902bfa 100644
--- a/src/VBox/Runtime/r0drv/solaris/semevent-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/semevent-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c
index bec1b4ef..00aa7f00 100644
--- a/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/semeventwait-r0drv-solaris.h b/src/VBox/Runtime/r0drv/solaris/semeventwait-r0drv-solaris.h
index 2e68644a..042cfd8d 100644
--- a/src/VBox/Runtime/r0drv/solaris/semeventwait-r0drv-solaris.h
+++ b/src/VBox/Runtime/r0drv/solaris/semeventwait-r0drv-solaris.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/semfastmutex-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/semfastmutex-r0drv-solaris.c
index baeaec2f..3329a562 100644
--- a/src/VBox/Runtime/r0drv/solaris/semfastmutex-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/semfastmutex-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/semmutex-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/semmutex-r0drv-solaris.c
index ceb0f21f..2a7925d5 100644
--- a/src/VBox/Runtime/r0drv/solaris/semmutex-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/semmutex-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/spinlock-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/spinlock-r0drv-solaris.c
index 3b671ffb..bae81d1d 100644
--- a/src/VBox/Runtime/r0drv/solaris/spinlock-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/spinlock-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/the-solaris-kernel.h b/src/VBox/Runtime/r0drv/solaris/the-solaris-kernel.h
index 2ab935f5..0a5a1ad0 100644
--- a/src/VBox/Runtime/r0drv/solaris/the-solaris-kernel.h
+++ b/src/VBox/Runtime/r0drv/solaris/the-solaris-kernel.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -57,6 +57,7 @@
#include <sys/kobj.h>
#include <sys/ctf_api.h>
#include <sys/modctl.h>
+#include <sys/proc.h>
#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
@@ -146,6 +147,52 @@ extern RTR0FNSOLXCCALL g_rtSolXcCall;
extern bool g_frtSolOldIPI;
extern bool g_frtSolOldIPIUlong;
+/*
+ * Thread-context hooks.
+ * Workarounds for older Solaris versions that did not have the exitctx() callback.
+ */
+typedef struct RTR0FNSOLTHREADCTX
+{
+ union
+ {
+ void *(*pfnSol_installctx) (kthread_t *pThread, void *pvArg,
+ void (*pfnSave)(void *pvArg),
+ void (*pfnRestore)(void *pvArg),
+ void (*pfnFork)(void *pvThread, void *pvThreadFork),
+ void (*pfnLwpCreate)(void *pvThread, void *pvThreadCreate),
+ void (*pfnExit)(void *pvThread),
+ void (*pfnFree)(void *pvArg, int fIsExec));
+
+ void *(*pfnSol_installctx_old) (kthread_t *pThread, void *pvArg,
+ void (*pfnSave)(void *pvArg),
+ void (*pfnRestore)(void *pvArg),
+ void (*pfnFork)(void *pvThread, void *pvThreadFork),
+ void (*pfnLwpCreate)(void *pvThread, void *pvThreadCreate),
+ void (*pfnFree)(void *pvArg, int fIsExec));
+ } Install;
+
+ union
+ {
+ int (*pfnSol_removectx) (kthread_t *pThread, void *pvArg,
+ void (*pfnSave)(void *pvArg),
+ void (*pfnRestore)(void *pvArg),
+ void (*pfnFork)(void *pvThread, void *pvThreadFork),
+ void (*pfnLwpCreate)(void *pvThread, void *pvThreadCreate),
+ void (*pfnExit)(void *pvThread),
+ void (*pfnFree)(void *pvArg, int fIsExec));
+
+ int (*pfnSol_removectx_old) (kthread_t *pThread, void *pvArg,
+ void (*pfnSave)(void *pvArg),
+ void (*pfnRestore)(void *pvArg),
+ void (*pfnFork)(void *pvThread, void *pvThreadFork),
+ void (*pfnLwpCreate)(void *pvThread, void *pvThreadCreate),
+ void (*pfnFree)(void *pvArg, int fIsExec));
+ } Remove;
+} RTR0FNSOLTHREADCTX;
+typedef RTR0FNSOLTHREADCTX *PRTR0FNSOLTHREADCTX;
+
+extern RTR0FNSOLTHREADCTX g_rtSolThreadCtx;
+extern bool g_frtSolOldThreadCtx;
/* Solaris globals. */
extern uintptr_t kernelbase;
diff --git a/src/VBox/Runtime/r0drv/solaris/thread-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/thread-r0drv-solaris.c
index c495133b..9983ba28 100644
--- a/src/VBox/Runtime/r0drv/solaris/thread-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/thread-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/thread2-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/thread2-r0drv-solaris.c
index 4200aaef..d8f04b11 100644
--- a/src/VBox/Runtime/r0drv/solaris/thread2-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/thread2-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/threadctxhooks-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/threadctxhooks-r0drv-solaris.c
new file mode 100644
index 00000000..3f5b507c
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/solaris/threadctxhooks-r0drv-solaris.c
@@ -0,0 +1,337 @@
+/* $Id: threadctxhooks-r0drv-solaris.c $ */
+/** @file
+ * IPRT - Thread-Context Hook, Ring-0 Driver, Solaris.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-solaris-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/mem.h>
+#include <iprt/assert.h>
+#include <iprt/thread.h>
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include <iprt/log.h>
+#include "internal/thread.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * The internal thread-context object.
+ */
+typedef struct RTTHREADCTXINT
+{
+ /** Magic value (RTTHREADCTXINT_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** The thread handle (owner) for which the context-hooks are registered. */
+ RTNATIVETHREAD hOwner;
+ /** Pointer to the registered thread-context hook. */
+ PFNRTTHREADCTXHOOK pfnThreadCtxHook;
+ /** User argument passed to the thread-context hook. */
+ void *pvUser;
+ /** Whether this handle has any hooks registered or not. */
+ bool volatile fRegistered;
+ /** Number of references to this object. */
+ uint32_t volatile cRefs;
+} RTTHREADCTXINT, *PRTTHREADCTXINT;
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** Validates a thread-context hook handle and returns rc if not valid. */
+#define RTTHREADCTX_VALID_RETURN_RC(pThis, rc) \
+ do { \
+ AssertPtrReturn((pThis), (rc)); \
+ AssertReturn((pThis)->u32Magic == RTTHREADCTXINT_MAGIC, (rc)); \
+ AssertReturn((pThis)->cRefs > 0, (rc)); \
+ } while (0)
+
+
+/**
+ * Hook function for the thread-preempting event.
+ *
+ * @param pvThreadCtxInt Opaque pointer to the internal thread-context
+ * object.
+ *
+ * @remarks Called with the with preemption disabled!
+ */
+static void rtThreadCtxHooksSolPreempting(void *pvThreadCtxInt)
+{
+ PRTTHREADCTXINT pThis = (PRTTHREADCTXINT)pvThreadCtxInt;
+ AssertPtr(pThis);
+ Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
+ if (pThis->fRegistered)
+ {
+ Assert(pThis->pfnThreadCtxHook);
+ pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_PREEMPTING, pThis->pvUser);
+ }
+}
+
+
+/**
+ * Hook function for the thread-resumed event.
+ *
+ * @param pvThreadCtxInt Opaque pointer to the internal thread-context
+ * object.
+ */
+static void rtThreadCtxHooksSolResumed(void *pvThreadCtxInt)
+{
+ PRTTHREADCTXINT pThis = (PRTTHREADCTXINT)pvThreadCtxInt;
+ AssertPtr(pThis);
+ Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
+ if (pThis->fRegistered)
+ {
+ Assert(pThis->pfnThreadCtxHook);
+ pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_RESUMED, pThis->pvUser);
+ }
+}
+
+
+/**
+ * Hook function for the thread-free event.
+ *
+ * @param pvThreadCtxInt Opaque pointer to the internal thread-context
+ * object.
+ * @param fIsExec Whether this event is triggered due to exec().
+ */
+static void rtThreadCtxHooksSolFree(void *pvThreadCtxInt, int fIsExec)
+{
+ PRTTHREADCTXINT pThis = (PRTTHREADCTXINT)pvThreadCtxInt;
+ AssertPtrReturnVoid(pThis);
+ AssertMsgReturnVoid(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
+
+ uint32_t cRefs = ASMAtomicReadU32(&pThis->cRefs);
+ if (RT_UNLIKELY(!cRefs))
+ {
+ /* Should never happen. */
+ AssertMsgFailed(("rtThreadCtxHooksSolFree with cRefs=0 pThis=%p\n", pThis));
+ return;
+ }
+
+ cRefs = ASMAtomicDecU32(&pThis->cRefs);
+ if (!cRefs)
+ {
+ Assert(!pThis->fRegistered);
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
+ RTMemFree(pThis);
+ }
+}
+
+
+RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
+{
+ PRTTHREADCTXINT pThis;
+ Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
+ pThis = (PRTTHREADCTXINT)RTMemAllocZ(sizeof(*pThis));
+ if (RT_UNLIKELY(!pThis))
+ return VERR_NO_MEMORY;
+ pThis->u32Magic = RTTHREADCTXINT_MAGIC;
+ pThis->hOwner = RTThreadNativeSelf();
+ pThis->fRegistered = false;
+ pThis->cRefs = 2; /* One reference for the thread, one for the hook object. */
+
+ /*
+ * installctx() allocates memory and thus cannot be used in RTThreadCtxHooksRegister() which can be used
+ * with preemption disabled. We allocate the context-hooks here and use 'fRegistered' to determine if we can
+ * invoke the consumer's hook or not.
+ */
+ if (g_frtSolOldThreadCtx)
+ {
+ g_rtSolThreadCtx.Install.pfnSol_installctx_old(curthread,
+ pThis,
+ rtThreadCtxHooksSolPreempting,
+ rtThreadCtxHooksSolResumed,
+ NULL, /* fork */
+ NULL, /* lwp_create */
+ rtThreadCtxHooksSolFree);
+ }
+ else
+ {
+ g_rtSolThreadCtx.Install.pfnSol_installctx(curthread,
+ pThis,
+ rtThreadCtxHooksSolPreempting,
+ rtThreadCtxHooksSolResumed,
+ NULL, /* fork */
+ NULL, /* lwp_create */
+ NULL, /* exit */
+ rtThreadCtxHooksSolFree);
+ }
+
+ *phThreadCtx = pThis;
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
+{
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ RTTHREADCTX_VALID_RETURN_RC(hThreadCtx, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs < UINT32_MAX / 2);
+ return cRefs;
+}
+
+
+RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
+{
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ if (pThis == NIL_RTTHREADCTX)
+ return 0;
+
+ RTTHREADCTX_VALID_RETURN_RC(hThreadCtx, UINT32_MAX);
+ Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
+ ASMAtomicWriteBool(&pThis->fRegistered, false);
+ uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+
+ if ( cRefs == 1
+ && pThis->hOwner == RTThreadNativeSelf())
+ {
+ /*
+ * removectx() will invoke rtThreadCtxHooksSolFree() and there is no way to bypass it and still use
+ * rtThreadCtxHooksSolFree() at the same time. Hence the convulated reference counting.
+ *
+ * When this function is called from the owner thread and is the last reference, we call removectx() which
+ * will invoke rtThreadCtxHooksSolFree() with cRefs = 1 and that will then free the hook object.
+ *
+ * When the function is called from a different thread, we simply decrement the reference. Whenever the
+ * ring-0 thread dies, Solaris will call rtThreadCtxHooksSolFree() which will free the hook object.
+ */
+ int rc;
+ if (g_frtSolOldThreadCtx)
+ {
+ rc = g_rtSolThreadCtx.Remove.pfnSol_removectx_old(curthread,
+ pThis,
+ rtThreadCtxHooksSolPreempting,
+ rtThreadCtxHooksSolResumed,
+ NULL, /* fork */
+ NULL, /* lwp_create */
+ rtThreadCtxHooksSolFree);
+ }
+ else
+ {
+ rc = g_rtSolThreadCtx.Remove.pfnSol_removectx(curthread,
+ pThis,
+ rtThreadCtxHooksSolPreempting,
+ rtThreadCtxHooksSolResumed,
+ NULL, /* fork */
+ NULL, /* lwp_create */
+ NULL, /* exit */
+ rtThreadCtxHooksSolFree);
+ }
+ AssertMsg(rc, ("removectx() failed. rc=%d\n", rc));
+ NOREF(rc);
+
+#ifdef VBOX_STRICT
+ cRefs = ASMAtomicReadU32(&pThis->cRefs);
+ Assert(!cRefs);
+#endif
+ cRefs = 0;
+ }
+ else if (!cRefs)
+ {
+ /*
+ * The ring-0 thread for this hook object has already died. Free up the object as we have no more references.
+ */
+ Assert(pThis->hOwner != RTThreadNativeSelf());
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
+ RTMemFree(pThis);
+ }
+
+ return cRefs;
+}
+
+
+RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
+{
+ /*
+ * Validate input.
+ */
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ if (pThis == NIL_RTTHREADCTX)
+ return VERR_INVALID_HANDLE;
+ AssertPtr(pThis);
+ AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
+ VERR_INVALID_HANDLE);
+ Assert(pThis->hOwner == RTThreadNativeSelf());
+
+ /*
+ * Register the callback.
+ */
+ pThis->pvUser = pvUser;
+ pThis->pfnThreadCtxHook = pfnThreadCtxHook;
+ pThis->fRegistered = true;
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
+{
+ /*
+ * Validate input.
+ */
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ if (pThis == NIL_RTTHREADCTX)
+ return VERR_INVALID_HANDLE;
+ AssertPtr(pThis);
+ AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
+ VERR_INVALID_HANDLE);
+ Assert(pThis->hOwner == RTThreadNativeSelf());
+ Assert(pThis->fRegistered);
+
+ /*
+ * Deregister the callback.
+ */
+ pThis->fRegistered = false;
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
+{
+ /*
+ * Validate input.
+ */
+ PRTTHREADCTXINT pThis = hThreadCtx;
+ if (pThis == NIL_RTTHREADCTX)
+ return false;
+ AssertPtr(pThis);
+ AssertMsg(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
+
+ return pThis->fRegistered;
+}
+
diff --git a/src/VBox/Runtime/r0drv/solaris/time-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/time-r0drv-solaris.c
index 263c59ac..d4113ace 100644
--- a/src/VBox/Runtime/r0drv/solaris/time-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/time-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c b/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c
index 2fec4db6..dd612015 100644
--- a/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c
+++ b/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -124,6 +124,36 @@ typedef struct RTTIMER
/**
+ * Callback wrapper for specific timers if they happened to have been fired on
+ * the wrong CPU. See rtTimerSolCallbackWrapper().
+ *
+ * @param idCpu The CPU this is fired on.
+ * @param pvUser1 Opaque pointer to the timer.
+ * @param pvUser2 Not used, NULL.
+ */
+static void rtTimerSolMpCallbackWrapper(RTCPUID idCpu, void *pvUser1, void *pvUser2)
+{
+ PRTTIMER pTimer = (PRTTIMER)pvUser1;
+ AssertPtrReturnVoid(pTimer);
+ Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+ Assert(pTimer->iCpu == RTMpCpuId()); /* ASSUMES: index == cpuid */
+ Assert(pTimer->pSingleTimer);
+ NOREF(pvUser2);
+
+ /* Make sure one-shots do not fire another time. */
+ Assert( !pTimer->fSuspended
+ || pTimer->interval != 0);
+
+ /* For one-shot specific timers, allow RTTimer to restart them. */
+ if (pTimer->interval == 0)
+ pTimer->fSuspended = true;
+
+ uint64_t u64Tick = ++pTimer->pSingleTimer->u64Tick;
+ pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
+}
+
+
+/**
* Callback wrapper for Omni-CPU and single-CPU timers.
*
* @param pvArg Opaque pointer to the timer.
@@ -136,9 +166,27 @@ static void rtTimerSolCallbackWrapper(void *pvArg)
{
PRTTIMER pTimer = (PRTTIMER)pvArg;
AssertPtrReturnVoid(pTimer);
+ Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
if (pTimer->pSingleTimer)
{
+ /* Make sure one-shots do not fire another time. */
+ Assert( !pTimer->fSuspended
+ || pTimer->interval != 0);
+
+ /* For specific timers, we might fire on the wrong CPU between cyclic_add() and cyclic_bind().
+ Redirect these shots to the right CPU as we are temporarily rebinding to the right CPU. */
+ if ( pTimer->fSpecificCpu
+ && pTimer->iCpu != RTMpCpuId()) /* ASSUMES: index == cpuid */
+ {
+ RTMpOnSpecific(pTimer->iCpu, rtTimerSolMpCallbackWrapper, pTimer, NULL);
+ return;
+ }
+
+ /* For one-shot any-cpu timers, allow RTTimer to restart them. */
+ if (pTimer->interval == 0)
+ pTimer->fSuspended = true;
+
uint64_t u64Tick = ++pTimer->pSingleTimer->u64Tick;
pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
}
@@ -202,8 +250,12 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
&& !RTMpIsCpuPossible(RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)))
return VERR_CPU_NOT_FOUND;
- if ((fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL && u64NanoInterval == 0)
+ /* One-shot omni timers are not supported by the cyclic system. */
+ if ( (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL
+ && u64NanoInterval == 0)
+ {
return VERR_NOT_SUPPORTED;
+ }
/*
* Allocate and initialize the timer handle.
@@ -269,13 +321,10 @@ RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
if (!pTimer->fSuspended)
return VERR_TIMER_ACTIVE;
- /* One-shot timers are not supported by the cyclic system. */
- if (pTimer->interval == 0)
- return VERR_NOT_SUPPORTED;
-
pTimer->fSuspended = false;
if (pTimer->fAllCpu)
{
+ Assert(pTimer->interval);
PRTR0OMNITIMERSOL pOmniTimer = RTMemAllocZ(sizeof(RTR0OMNITIMERSOL));
if (RT_UNLIKELY(!pOmniTimer))
return VERR_NO_MEMORY;
@@ -323,7 +372,8 @@ RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
pSingleTimer->hHandler.cyh_level = CY_LOCK_LEVEL;
mutex_enter(&cpu_lock);
- if (iCpu != SOL_TIMER_ANY_CPU && !cpu_is_online(cpu[iCpu]))
+ if ( iCpu != SOL_TIMER_ANY_CPU
+ && !cpu_is_online(cpu[iCpu]))
{
mutex_exit(&cpu_lock);
RTMemFree(pSingleTimer);
@@ -334,9 +384,12 @@ RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
pSingleTimer->hFireTime.cyt_when = u64First + RTTimeNanoTS();
if (pTimer->interval == 0)
{
- /** @todo use gethrtime_max instead of LLONG_MAX? */
- AssertCompileSize(pSingleTimer->hFireTime.cyt_interval, sizeof(long long));
- pSingleTimer->hFireTime.cyt_interval = LLONG_MAX - pSingleTimer->hFireTime.cyt_when;
+ /*
+ * cylic_add() comment: "The caller is responsible for assuring that cyt_when + cyt_interval <= INT64_MAX"
+ * but it contradicts itself because cyclic_reprogram() updates only the interval and accepts CY_INFINITY as
+ * a valid, special value. See cyclic_fire().
+ */
+ pSingleTimer->hFireTime.cyt_interval = CY_INFINITY;
}
else
pSingleTimer->hFireTime.cyt_interval = pTimer->interval;
diff --git a/src/VBox/Runtime/r3/alloc-ef-cpp.cpp b/src/VBox/Runtime/r3/alloc-ef-cpp.cpp
index 7aa12880..eb8614e3 100644
--- a/src/VBox/Runtime/r3/alloc-ef-cpp.cpp
+++ b/src/VBox/Runtime/r3/alloc-ef-cpp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/alloc-ef.cpp b/src/VBox/Runtime/r3/alloc-ef.cpp
index 16892e29..570800be 100644
--- a/src/VBox/Runtime/r3/alloc-ef.cpp
+++ b/src/VBox/Runtime/r3/alloc-ef.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/alloc.cpp b/src/VBox/Runtime/r3/alloc.cpp
index 94889c10..98892aaa 100644
--- a/src/VBox/Runtime/r3/alloc.cpp
+++ b/src/VBox/Runtime/r3/alloc.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -39,6 +39,10 @@
# undef RTMEMALLOC_USE_TRACKER
#endif
+#if defined(RTMEMALLOC_USE_TRACKER) && defined(RTALLOC_USE_EFENCE)
+# error "Cannot define both RTMEMALLOC_USE_TRACKER and RTALLOC_USE_EFENCE!"
+#endif
+
/*******************************************************************************
* Header Files *
diff --git a/src/VBox/Runtime/r3/allocex.cpp b/src/VBox/Runtime/r3/allocex.cpp
new file mode 100644
index 00000000..c1bd6a40
--- /dev/null
+++ b/src/VBox/Runtime/r3/allocex.cpp
@@ -0,0 +1,126 @@
+/* $Id: allocex.cpp $ */
+/** @file
+ * IPRT - Memory Allocation, Extended Alloc and Free Functions for Ring-3, posix.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define RTMEM_NO_WRAP_TO_EF_APIS
+#include <iprt/mem.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include "internal/magics.h"
+#include "allocex.h"
+
+
+RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv) RT_NO_THROW
+{
+ /*
+ * Validate and adjust input.
+ */
+ AssertMsgReturn(!(fFlags & ~RTMEMALLOCEX_FLAGS_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(RT_IS_POWER_OF_TWO(cbAlignment), VERR_INVALID_PARAMETER);
+ AssertMsgReturn(cbAlignment <= sizeof(void *), ("%zu (%#x)\n", cbAlignment, cbAlignment), VERR_UNSUPPORTED_ALIGNMENT);
+
+ if (fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX)
+ return VERR_NOT_SUPPORTED;
+
+ /*
+ * Align the request.
+ */
+ size_t cbAligned = cb;
+ if (cbAlignment)
+ cbAligned = RT_ALIGN_Z(cb, cbAlignment);
+ else
+ cbAligned = RT_ALIGN_Z(cb, sizeof(uint64_t));
+ AssertMsgReturn(cbAligned >= cb && cbAligned <= ~(size_t)0, ("cbAligned=%#zx cb=%#zx", cbAligned, cb),
+ VERR_INVALID_PARAMETER);
+
+ /*
+ * Allocate the requested memory.
+ */
+ void *pv;
+ if (fFlags & (RTMEMALLOCEX_FLAGS_16BIT_REACH | RTMEMALLOCEX_FLAGS_32BIT_REACH))
+ {
+ int rc;
+ if (fFlags & RTMEMALLOCEX_FLAGS_16BIT_REACH)
+ rc = rtMemAllocEx16BitReach(cbAligned + sizeof(RTMEMHDRR3), fFlags, &pv);
+ else
+ rc = rtMemAllocEx32BitReach(cbAligned + sizeof(RTMEMHDRR3), fFlags, &pv);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+ else if (fFlags & RTMEMALLOCEX_FLAGS_EXEC)
+ {
+ pv = RTMemExecAlloc(cbAligned + sizeof(RTMEMHDRR3));
+ if ((fFlags & RTMEMALLOCEX_FLAGS_ZEROED) && pv)
+ RT_BZERO(pv, cbAligned + sizeof(RTMEMHDRR3));
+ }
+ else if (fFlags & RTMEMALLOCEX_FLAGS_ZEROED)
+ pv = RTMemAllocZ(cbAligned + sizeof(RTMEMHDRR3));
+ else
+ pv = RTMemAlloc(cbAligned + sizeof(RTMEMHDRR3));
+ if (!pv)
+ return VERR_NO_MEMORY;
+
+ /*
+ * Fill in the header and return.
+ */
+ PRTMEMHDRR3 pHdr = (PRTMEMHDRR3)pv;
+ pHdr->u32Magic = RTMEMHDR_MAGIC;
+ pHdr->fFlags = fFlags;
+ pHdr->cb = (uint32_t)cbAligned;
+ pHdr->cbReq = (uint32_t)cb;
+
+ *ppv = pHdr + 1;
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTMemAllocExTag);
+
+
+RTDECL(void) RTMemFreeEx(void *pv, size_t cb) RT_NO_THROW
+{
+ if (!pv)
+ return;
+ AssertPtr(pv);
+
+ PRTMEMHDRR3 pHdr = (PRTMEMHDRR3)pv - 1;
+ AssertMsg(pHdr->u32Magic == RTMEMHDR_MAGIC, ("pHdr->u32Magic=%RX32 pv=%p cb=%#x\n", pHdr->u32Magic, pv, cb));
+ pHdr->u32Magic = RTMEMHDR_MAGIC_DEAD;
+ Assert(pHdr->cbReq == cb);
+
+ if (pHdr->fFlags & (RTMEMALLOCEX_FLAGS_16BIT_REACH | RTMEMALLOCEX_FLAGS_32BIT_REACH))
+ rtMemFreeExYyBitReach(pHdr, pHdr->cb + sizeof(*pHdr), pHdr->fFlags);
+ else if (pHdr->fFlags & RTMEMALLOCEX_FLAGS_EXEC)
+ RTMemExecFree(pHdr, pHdr->cb + sizeof(*pHdr));
+ else
+ RTMemFree(pHdr);
+}
+RT_EXPORT_SYMBOL(RTMemFreeEx);
+
diff --git a/src/VBox/Runtime/r3/allocex.h b/src/VBox/Runtime/r3/allocex.h
new file mode 100644
index 00000000..2724335c
--- /dev/null
+++ b/src/VBox/Runtime/r3/allocex.h
@@ -0,0 +1,84 @@
+/* $Id: allocex.h $ */
+/** @file
+ * IPRT - Memory Allocation, Extended Alloc and Free Functions for Ring-3.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___r3_allocex_h
+#define ___r3_allocex_h
+
+#include <iprt/types.h>
+
+/**
+ * Heading for extended memory allocations in ring-3.
+ */
+typedef struct RTMEMHDRR3
+{
+ /** Magic (RTMEMHDR_MAGIC). */
+ uint32_t u32Magic;
+ /** Block flags (RTMEMALLOCEX_FLAGS_*). */
+ uint32_t fFlags;
+ /** The actual size of the block, header not included. */
+ uint32_t cb;
+ /** The requested allocation size. */
+ uint32_t cbReq;
+} RTMEMHDRR3;
+/** Pointer to a ring-3 extended memory header. */
+typedef RTMEMHDRR3 *PRTMEMHDRR3;
+
+
+/**
+ * Allocate memory in below 64KB.
+ *
+ * @returns IPRT status code.
+ * @param cbAlloc Number of bytes to allocate (including the
+ * header if the caller needs one).
+ * @param fFlags Allocation flags.
+ * @param ppv Where to return the pointer to the memory.
+ */
+DECLHIDDEN(int) rtMemAllocEx16BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv);
+
+/**
+ * Allocate memory in below 4GB.
+ *
+ * @returns IPRT status code.
+ * @param cbAlloc Number of bytes to allocate (including the
+ * header if the caller needs one).
+ * @param fFlags Allocation flags.
+ * @param ppv Where to return the pointer to the memory.
+ */
+DECLHIDDEN(int) rtMemAllocEx32BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv);
+
+
+/**
+ * Frees memory allocated by rtMemAllocEx16BitReach and rtMemAllocEx32BitReach.
+ *
+ * @param pv Start of allocation.
+ * @param cb Allocation size.
+ * @param fFlags Allocation flags.
+ */
+DECLHIDDEN(void) rtMemFreeExYyBitReach(void *pv, size_t cb, uint32_t fFlags);
+
+#endif
+
diff --git a/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp b/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp
index 2b033b2f..aae99908 100644
--- a/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp
+++ b/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,10 +28,18 @@
* Header Files *
*******************************************************************************/
#include <iprt/path.h>
-#include <iprt/err.h>
+#include "internal/iprt.h"
+
#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <iprt/err.h>
+
+#include <NSSystemDirectories.h>
+#include <sys/syslimits.h>
+#ifdef IPRT_USE_CORE_SERVICE_FOR_USER_DOCUMENTS
+# include <CoreServices/CoreServices.h>
+#endif
-#include <CoreServices/CoreServices.h>
RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath)
{
@@ -41,15 +49,50 @@ RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath)
AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
AssertReturn(cchPath, VERR_INVALID_PARAMETER);
- FSRef ref;
- OSErr err = FSFindFolder(kOnAppropriateDisk, kDocumentsFolderType, false /* createFolder */, &ref);
- if (err != noErr)
- return VERR_PATH_NOT_FOUND;
+ /*
+ * Try NSSystemDirectories first since that works for directories that doesn't exist.
+ */
+ int rc = VERR_PATH_NOT_FOUND;
+ NSSearchPathEnumerationState EnmState = NSStartSearchPathEnumeration(NSDocumentDirectory, NSUserDomainMask);
+ if (EnmState != 0)
+ {
+ char szTmp[PATH_MAX];
+ szTmp[0] = szTmp[PATH_MAX - 1] = '\0';
+ EnmState = NSGetNextSearchPathEnumeration(EnmState, szTmp);
+ if (EnmState != 0)
+ {
+ size_t cchTmp = strlen(szTmp);
+ if (cchTmp >= cchPath)
+ return VERR_BUFFER_OVERFLOW;
- err = FSRefMakePath(&ref, (UInt8*)pszPath, cchPath);
- if (err != noErr)
- return VERR_PATH_NOT_FOUND;
+ if (szTmp[0] == '~' && szTmp[1] == '/')
+ {
+ /* Expand tilde. */
+ rc = RTPathUserHome(pszPath, cchPath - cchTmp + 2);
+ if (RT_FAILURE(rc))
+ return rc;
+ rc = RTPathAppend(pszPath, cchPath, &szTmp[2]);
+ }
+ else
+ rc = RTStrCopy(pszPath, cchPath, szTmp);
+ return rc;
+ }
+ }
- return VINF_SUCCESS;
+#ifdef IPRT_USE_CORE_SERVICE_FOR_USER_DOCUMENTS
+ /*
+ * Fall back on FSFindFolder in case the above should fail...
+ */
+ FSRef ref;
+ OSErr err = FSFindFolder(kOnAppropriateDisk, kDocumentsFolderType, false /* createFolder */, &ref);
+ if (err == noErr)
+ {
+ err = FSRefMakePath(&ref, (UInt8*)pszPath, cchPath);
+ if (err == noErr)
+ return VINF_SUCCESS;
+ }
+#endif
+ Assert(RT_FAILURE_NP(rc));
+ return rc;
}
diff --git a/src/VBox/Runtime/r3/darwin/mp-darwin.cpp b/src/VBox/Runtime/r3/darwin/mp-darwin.cpp
index 9942686a..bfdeb0d4 100644
--- a/src/VBox/Runtime/r3/darwin/mp-darwin.cpp
+++ b/src/VBox/Runtime/r3/darwin/mp-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -46,18 +46,63 @@
/**
- * Internal worker that determines the max possible CPU count.
+ * Internal worker that determines the max possible logical CPU count (hyperthreads).
*
* @returns Max cpus.
*/
-static RTCPUID rtMpDarwinMaxCpus(void)
+static RTCPUID rtMpDarwinMaxLogicalCpus(void)
{
- int aiMib[2];
- aiMib[0] = CTL_HW;
- aiMib[1] = HW_NCPU;
int cCpus = -1;
size_t cb = sizeof(cCpus);
- int rc = sysctl(aiMib, RT_ELEMENTS(aiMib), &cCpus, &cb, NULL, 0);
+ int rc = sysctlbyname("hw.logicalcpu_max", &cCpus, &cb, NULL, 0);
+ if (rc != -1 && cCpus >= 1)
+ return cCpus;
+ AssertFailed();
+ return 1;
+}
+
+/**
+ * Internal worker that determines the max possible physical core count.
+ *
+ * @returns Max cpus.
+ */
+static RTCPUID rtMpDarwinMaxPhysicalCpus(void)
+{
+ int cCpus = -1;
+ size_t cb = sizeof(cCpus);
+ int rc = sysctlbyname("hw.physicalcpu_max", &cCpus, &cb, NULL, 0);
+ if (rc != -1 && cCpus >= 1)
+ return cCpus;
+ AssertFailed();
+ return 1;
+}
+
+/**
+ * Internal worker that determines the current number of logical CPUs (hyperthreads).
+ *
+ * @returns Max cpus.
+ */
+static RTCPUID rtMpDarwinOnlineLogicalCpus(void)
+{
+ int cCpus = -1;
+ size_t cb = sizeof(cCpus);
+ int rc = sysctlbyname("hw.logicalcpu", &cCpus, &cb, NULL, 0);
+ if (rc != -1 && cCpus >= 1)
+ return cCpus;
+ AssertFailed();
+ return 1;
+}
+
+/**
+ * Internal worker that determines the current number of physical CPUs.
+ *
+ * @returns Max cpus.
+ */
+static RTCPUID rtMpDarwinOnlinePhysicalCpus(void)
+{
+ int cCpus = -1;
+ size_t cb = sizeof(cCpus);
+ int rc = sysctlbyname("hw.physicalcpu", &cCpus, &cb, NULL, 0);
if (rc != -1 && cCpus >= 1)
return cCpus;
AssertFailed();
@@ -69,19 +114,19 @@ static RTCPUID rtMpDarwinMaxCpus(void)
RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
{
- return idCpu < RTCPUSET_MAX_CPUS && idCpu < rtMpDarwinMaxCpus() ? idCpu : -1;
+ return idCpu < RTCPUSET_MAX_CPUS && idCpu < rtMpDarwinMaxLogicalCpus() ? idCpu : -1;
}
RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
{
- return (unsigned)iCpu < rtMpDarwinMaxCpus() ? iCpu : NIL_RTCPUID;
+ return (unsigned)iCpu < rtMpDarwinMaxLogicalCpus() ? iCpu : NIL_RTCPUID;
}
RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
{
- return rtMpDarwinMaxCpus() - 1;
+ return rtMpDarwinMaxLogicalCpus() - 1;
}
@@ -97,7 +142,7 @@ RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
kern_return_t krc = host_processor_info(mach_host_self(),
PROCESSOR_BASIC_INFO, &nCpus, (processor_info_array_t*)&pinfo, &count);
AssertReturn (krc == KERN_SUCCESS, true);
- bool isOnline = idCpu < nCpus ? pinfo[idCpu].running : true;
+ bool isOnline = idCpu < nCpus ? pinfo[idCpu].running : false;
vm_deallocate(mach_task_self(), (vm_address_t)pinfo, count * sizeof(*pinfo));
return isOnline;
#endif
@@ -107,19 +152,19 @@ RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
{
return idCpu != NIL_RTCPUID
- && idCpu < rtMpDarwinMaxCpus();
+ && idCpu < rtMpDarwinMaxLogicalCpus();
}
RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
{
#if 0
- RTCPUID cCpus = rtMpDarwinMaxCpus();
+ RTCPUID cCpus = rtMpDarwinMaxLogicalCpus();
return RTCpuSetFromU64(RT_BIT_64(cCpus) - 1);
#else
RTCpuSetEmpty(pSet);
- RTCPUID cMax = rtMpDarwinMaxCpus();
+ RTCPUID cMax = rtMpDarwinMaxLogicalCpus();
for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
if (RTMpIsCpuPossible(idCpu))
RTCpuSetAdd(pSet, idCpu);
@@ -130,7 +175,13 @@ RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
RTDECL(RTCPUID) RTMpGetCount(void)
{
- return rtMpDarwinMaxCpus();
+ return rtMpDarwinMaxLogicalCpus();
+}
+
+
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ return rtMpDarwinMaxPhysicalCpus();
}
@@ -140,7 +191,7 @@ RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
return RTMpGetSet(pSet);
#else
RTCpuSetEmpty(pSet);
- RTCPUID cMax = rtMpDarwinMaxCpus();
+ RTCPUID cMax = rtMpDarwinMaxLogicalCpus();
for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
if (RTMpIsCpuOnline(idCpu))
RTCpuSetAdd(pSet, idCpu);
diff --git a/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp b/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp
index 103e70b4..922bd41e 100644
--- a/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp
+++ b/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -32,6 +32,9 @@
# include <mach-o/dyld.h>
#endif
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
#include <iprt/string.h>
#include <iprt/assert.h>
#include <iprt/err.h>
@@ -48,7 +51,13 @@ DECLHIDDEN(int) rtProcInitExePath(char *pszPath, size_t cchPath)
const char *pszImageName = _dyld_get_image_name(0);
AssertReturn(pszImageName, VERR_INTERNAL_ERROR);
- int rc = rtPathFromNativeCopy(pszPath, cchPath, pszImageName, NULL);
+ char szTmpPath[PATH_MAX + 1];
+ const char *psz = realpath(pszImageName, szTmpPath);
+ int rc;
+ if (psz)
+ rc = rtPathFromNativeCopy(pszPath, cchPath, szTmpPath, NULL);
+ else
+ rc = RTErrConvertFromErrno(errno);
AssertMsgRCReturn(rc, ("rc=%Rrc pszLink=\"%s\"\nhex: %.*Rhxs\n", rc, pszPath, strlen(pszImageName), pszPath), rc);
return VINF_SUCCESS;
diff --git a/src/VBox/Runtime/r3/darwin/sched-darwin.cpp b/src/VBox/Runtime/r3/darwin/sched-darwin.cpp
index ad47cdbb..3879db8c 100644
--- a/src/VBox/Runtime/r3/darwin/sched-darwin.cpp
+++ b/src/VBox/Runtime/r3/darwin/sched-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/darwin/time-darwin.cpp b/src/VBox/Runtime/r3/darwin/time-darwin.cpp
index 38878c63..a737d01b 100644
--- a/src/VBox/Runtime/r3/darwin/time-darwin.cpp
+++ b/src/VBox/Runtime/r3/darwin/time-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/dir.cpp b/src/VBox/Runtime/r3/dir.cpp
index 16f2577e..1cfa50d7 100644
--- a/src/VBox/Runtime/r3/dir.cpp
+++ b/src/VBox/Runtime/r3/dir.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -29,14 +29,6 @@
* Header Files *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_DIR
-#ifdef RT_OS_WINDOWS /* PORTME: Assumes everyone else is using dir-posix.cpp */
-# include <Windows.h>
-#else
-# include <dirent.h>
-# include <unistd.h>
-# include <limits.h>
-#endif
-
#include <iprt/dir.h>
#include "internal/iprt.h"
@@ -49,6 +41,7 @@
#include <iprt/path.h>
#include <iprt/string.h>
#include <iprt/uni.h>
+#define RTDIR_AGNOSTIC
#include "internal/dir.h"
#include "internal/path.h"
@@ -533,7 +526,7 @@ static int rtDirOpenCommon(PRTDIR *ppDir, const char *pszPath, const char *pszFi
if (!pszFilter)
{
cbFilter = cucFilter0 = 0;
- rc = RTPathReal(pszPath, szRealPath, sizeof(szRealPath) - 1);
+ rc = RTPathAbs(pszPath, szRealPath, sizeof(szRealPath) - 1);
}
else
{
@@ -547,7 +540,7 @@ static int rtDirOpenCommon(PRTDIR *ppDir, const char *pszPath, const char *pszFi
if (!pszTmp)
return VERR_NO_MEMORY;
pszTmp[pszFilter - pszPath] = '\0';
- rc = RTPathReal(pszTmp, szRealPath, sizeof(szRealPath) - 1);
+ rc = RTPathAbs(pszTmp, szRealPath, sizeof(szRealPath) - 1);
RTStrFree(pszTmp);
}
else
@@ -570,34 +563,19 @@ static int rtDirOpenCommon(PRTDIR *ppDir, const char *pszPath, const char *pszFi
* The posix definition of Data.d_name allows it to be < NAME_MAX + 1,
* thus the horrible ugliness here. Solaris uses d_name[1] for instance.
*/
-#ifndef RT_OS_WINDOWS
- long cbNameMax = pathconf(szRealPath, _PC_NAME_MAX);
-# ifdef NAME_MAX
- if (cbNameMax < NAME_MAX) /* This is plain paranoia, but it doesn't hurt. */
- cbNameMax = NAME_MAX;
-# endif
-# ifdef _XOPEN_NAME_MAX
- if (cbNameMax < _XOPEN_NAME_MAX) /* Ditto. */
- cbNameMax = _XOPEN_NAME_MAX;
-# endif
- size_t cbDir = RT_OFFSETOF(RTDIR, Data.d_name[cbNameMax + 1]);
- if (cbDir < sizeof(RTDIR)) /* Ditto. */
- cbDir = sizeof(RTDIR);
- cbDir = RT_ALIGN_Z(cbDir, 8);
-#else
- size_t cbDir = sizeof(RTDIR);
-#endif
+ size_t cbDir = rtDirNativeGetStructSize(szRealPath);
size_t const cbAllocated = cbDir
+ cucFilter0 * sizeof(RTUNICP)
+ cbFilter
+ cchRealPath + 1 + 4;
- PRTDIR pDir = (PRTDIR)RTMemAlloc(cbAllocated);
+ PRTDIR pDir = (PRTDIR)RTMemAllocZ(cbAllocated);
if (!pDir)
return VERR_NO_MEMORY;
uint8_t *pb = (uint8_t *)pDir + cbDir;
/* initialize it */
pDir->u32Magic = RTDIR_MAGIC;
+ pDir->cbSelf = cbDir;
if (cbFilter)
{
pDir->puszFilter = (PRTUNICP)pb;
@@ -638,9 +616,6 @@ static int rtDirOpenCommon(PRTDIR *ppDir, const char *pszPath, const char *pszFi
pDir->fDataUnread = false;
pDir->pszName = NULL;
pDir->cchName = 0;
-#ifndef RT_OS_WINDOWS
- pDir->cbMaxName = cbDir - RT_OFFSETOF(RTDIR, Data.d_name);
-#endif
/*
* Hand it over to the native part.
@@ -730,3 +705,70 @@ RTDECL(int) RTDirFlushParent(const char *pszChild)
return rc;
}
+
+RTDECL(int) RTDirQueryUnknownTypeEx(const char *pszComposedName, bool fFollowSymlinks,
+ RTDIRENTRYTYPE *penmType, PRTFSOBJINFO pObjInfo)
+{
+ int rc = RTPathQueryInfoEx(pszComposedName, pObjInfo, RTFSOBJATTRADD_NOTHING,
+ fFollowSymlinks ? RTPATH_F_FOLLOW_LINK : RTPATH_F_ON_LINK);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ if (RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
+ *penmType = RTDIRENTRYTYPE_DIRECTORY;
+ else if (RTFS_IS_FILE(pObjInfo->Attr.fMode))
+ *penmType = RTDIRENTRYTYPE_FILE;
+ else if (RTFS_IS_SYMLINK(pObjInfo->Attr.fMode))
+ *penmType = RTDIRENTRYTYPE_SYMLINK;
+ else if (RTFS_IS_FIFO(pObjInfo->Attr.fMode))
+ *penmType = RTDIRENTRYTYPE_FIFO;
+ else if (RTFS_IS_DEV_CHAR(pObjInfo->Attr.fMode))
+ *penmType = RTDIRENTRYTYPE_DEV_CHAR;
+ else if (RTFS_IS_DEV_BLOCK(pObjInfo->Attr.fMode))
+ *penmType = RTDIRENTRYTYPE_DEV_BLOCK;
+ else if (RTFS_IS_SOCKET(pObjInfo->Attr.fMode))
+ *penmType = RTDIRENTRYTYPE_SOCKET;
+ else if (RTFS_IS_WHITEOUT(pObjInfo->Attr.fMode))
+ *penmType = RTDIRENTRYTYPE_WHITEOUT;
+ else
+ *penmType = RTDIRENTRYTYPE_UNKNOWN;
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTDirQueryUnknownType(const char *pszComposedName, bool fFollowSymlinks, RTDIRENTRYTYPE *penmType)
+{
+ if ( *penmType != RTDIRENTRYTYPE_UNKNOWN
+ && ( !fFollowSymlinks
+ || *penmType != RTDIRENTRYTYPE_SYMLINK))
+ return VINF_SUCCESS;
+
+ RTFSOBJINFO ObjInfo;
+ return RTDirQueryUnknownTypeEx(pszComposedName, fFollowSymlinks, penmType, &ObjInfo);
+}
+
+
+RTDECL(bool) RTDirEntryIsStdDotLink(PRTDIRENTRY pDirEntry)
+{
+ if (pDirEntry->szName[0] != '.')
+ return false;
+ if (pDirEntry->cbName == 1)
+ return true;
+ if (pDirEntry->cbName != 2)
+ return false;
+ return pDirEntry->szName[1] == '.';
+}
+
+
+RTDECL(bool) RTDirEntryExIsStdDotLink(PCRTDIRENTRYEX pDirEntryEx)
+{
+ if (pDirEntryEx->szName[0] != '.')
+ return false;
+ if (pDirEntryEx->cbName == 1)
+ return true;
+ if (pDirEntryEx->cbName != 2)
+ return false;
+ return pDirEntryEx->szName[1] == '.';
+}
+
diff --git a/src/VBox/Runtime/r3/dir2.cpp b/src/VBox/Runtime/r3/dir2.cpp
index bec029de..f01f42c1 100644
--- a/src/VBox/Runtime/r3/dir2.cpp
+++ b/src/VBox/Runtime/r3/dir2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/fileio.cpp b/src/VBox/Runtime/r3/fileio.cpp
index 5b4e8873..fd1a2898 100644
--- a/src/VBox/Runtime/r3/fileio.cpp
+++ b/src/VBox/Runtime/r3/fileio.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -208,6 +208,49 @@ RTR3DECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRea
/**
+ * Read bytes from a file at a given offset into a S/G buffer.
+ * This function may modify the file position.
+ *
+ * @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.
+ */
+RTR3DECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)
+{
+ int rc = VINF_SUCCESS;
+ size_t cbRead = 0;
+
+ while (cbToRead)
+ {
+ size_t cbThisRead = 0;
+ size_t cbBuf = cbToRead;
+ void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
+
+ rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL);
+ if (RT_SUCCESS(rc))
+ cbRead += cbThisRead;
+
+ if ( RT_FAILURE(rc)
+ || ( cbThisRead < cbBuf
+ && pcbRead))
+ break;
+
+ cbToRead -= cbBuf;
+ off += cbBuf;
+ }
+
+ if (pcbRead)
+ *pcbRead = cbRead;
+
+ return rc;
+}
+
+
+/**
* Write bytes to a file at a given offset.
* This function may modify the file position.
*
@@ -229,6 +272,49 @@ RTR3DECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t
/**
+ * Write bytes from a S/G buffer 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 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.
+ */
+RTR3DECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)
+{
+ int rc = VINF_SUCCESS;
+ size_t cbWritten = 0;
+
+ while (cbToWrite)
+ {
+ size_t cbThisWritten = 0;
+ size_t cbBuf = cbToWrite;
+ void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
+
+ rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL);
+ if (RT_SUCCESS(rc))
+ cbWritten += cbThisWritten;
+
+ if ( RT_FAILURE(rc)
+ || ( cbThisWritten < cbBuf
+ && pcbWritten))
+ break;
+
+ cbToWrite -= cbBuf;
+ off += cbBuf;
+ }
+
+ if (pcbWritten)
+ *pcbWritten = cbWritten;
+
+ return rc;
+}
+
+
+/**
* Gets the current file position.
*
* @returns File offset.
diff --git a/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp b/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp
index 1d47c759..b5ddfcca 100644
--- a/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp
+++ b/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -66,6 +66,8 @@ typedef struct RTFILEAIOCTXINTERNAL
volatile bool fWokenUp;
/** Flag whether the thread is currently waiting in the syscall. */
volatile bool fWaiting;
+ /** Flags given during creation. */
+ uint32_t fFlags;
/** Magic value (RTFILEAIOCTX_MAGIC). */
uint32_t u32Magic;
} RTFILEAIOCTXINTERNAL;
@@ -299,11 +301,13 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered)
return pReqInt->Rc;
}
-RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
+RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax,
+ uint32_t fFlags)
{
int rc = VINF_SUCCESS;
PRTFILEAIOCTXINTERNAL pCtxInt;
AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER);
+ AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL));
if (RT_UNLIKELY(!pCtxInt))
@@ -313,6 +317,7 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
pCtxInt->iKQueue = kqueue();
if (RT_LIKELY(pCtxInt->iKQueue > 0))
{
+ pCtxInt->fFlags = fFlags;
pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC;
*phAioCtx = (RTFILEAIOCTX)pCtxInt;
}
@@ -498,7 +503,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL
AssertReturn(cReqs != 0, VERR_INVALID_PARAMETER);
AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE);
- if (RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0))
+ if ( RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0)
+ && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS))
return VERR_FILE_AIO_NO_REQUEST;
/*
diff --git a/src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp b/src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp
index 8296025b..8475dd04 100644
--- a/src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp
+++ b/src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/freebsd/rtProcInitExePath-freebsd.cpp b/src/VBox/Runtime/r3/freebsd/rtProcInitExePath-freebsd.cpp
index 55112775..216c1004 100644
--- a/src/VBox/Runtime/r3/freebsd/rtProcInitExePath-freebsd.cpp
+++ b/src/VBox/Runtime/r3/freebsd/rtProcInitExePath-freebsd.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/fs.cpp b/src/VBox/Runtime/r3/fs.cpp
index dac1a5cc..b79e43d2 100644
--- a/src/VBox/Runtime/r3/fs.cpp
+++ b/src/VBox/Runtime/r3/fs.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -205,6 +205,7 @@ RTDECL(const char *) RTFsTypeName(RTFSTYPE enmType)
case RTFSTYPE_SYSFS: return "sysfs";
case RTFSTYPE_PROC: return "proc";
case RTFSTYPE_OCFS2: return "ocfs2";
+ case RTFSTYPE_BTRFS: return "btrfs";
case RTFSTYPE_NTFS: return "ntfs";
case RTFSTYPE_FAT: return "fat";
diff --git a/src/VBox/Runtime/r3/os2/poll-os2.cpp b/src/VBox/Runtime/r3/generic/allocex-r3-generic.cpp
index 890cdc8c..dd1dea61 100644
--- a/src/VBox/Runtime/r3/os2/poll-os2.cpp
+++ b/src/VBox/Runtime/r3/generic/allocex-r3-generic.cpp
@@ -1,10 +1,10 @@
-/* $Id: poll-os2.cpp $ */
+/* $Id: allocex-r3-generic.cpp $ */
/** @file
- * IPRT - Polling I/O Handles, OS/2 Implementation.
+ * IPRT - Memory Allocation, Extended Alloc Workers, generic.
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,58 +28,30 @@
/*******************************************************************************
* Header Files *
*******************************************************************************/
-#include <iprt/poll.h>
+#define RTMEM_NO_WRAP_TO_EF_APIS
+#include <iprt/mem.h>
#include "internal/iprt.h"
#include <iprt/assert.h>
#include <iprt/err.h>
-#include "internal/magics.h"
+#include "../allocex.h"
-RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
-{
- return VERR_NOT_IMPLEMENTED;
-}
-
-
-RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
-{
- return VERR_NOT_IMPLEMENTED;
-}
-
-
-RTDECL(int) RTPollSetCreate(PRTPOLLSET hPollSet)
-{
- return VERR_NOT_IMPLEMENTED;
-}
-
-
-RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet)
-{
- return VERR_NOT_IMPLEMENTED;
-}
-
-
-RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id)
-{
- return VERR_NOT_IMPLEMENTED;
-}
-
-RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id)
+DECLHIDDEN(int) rtMemAllocEx16BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv)
{
- return VERR_NOT_IMPLEMENTED;
+ return VERR_NOT_SUPPORTED;
}
-RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle)
+DECLHIDDEN(int) rtMemAllocEx32BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv)
{
- return VERR_NOT_IMPLEMENTED;
+ return VERR_NOT_SUPPORTED;
}
-RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet)
+DECLHIDDEN(void) rtMemFreeExYyBitReach(void *pv, size_t cb, uint32_t fFlags)
{
- return UINT32_MAX;
+ AssertFailed();
}
diff --git a/src/VBox/Runtime/r3/generic/semspinmutex-r3-generic.cpp b/src/VBox/Runtime/r3/generic/semspinmutex-r3-generic.cpp
index 1c0e4603..e6edca4f 100644
--- a/src/VBox/Runtime/r3/generic/semspinmutex-r3-generic.cpp
+++ b/src/VBox/Runtime/r3/generic/semspinmutex-r3-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/haiku/rtProcInitExePath-haiku.cpp b/src/VBox/Runtime/r3/haiku/rtProcInitExePath-haiku.cpp
new file mode 100644
index 00000000..7a41e9f1
--- /dev/null
+++ b/src/VBox/Runtime/r3/haiku/rtProcInitExePath-haiku.cpp
@@ -0,0 +1,60 @@
+/* $Id: rtProcInitExePath-haiku.cpp $ */
+/** @file
+ * IPRT - rtProcInitName, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PROCESS
+#ifdef RT_OS_HAIKU
+# include <image.h>
+#endif
+
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/path.h>
+#include "internal/process.h"
+#include "internal/path.h"
+
+
+DECLHIDDEN(int) rtProcInitExePath(char *pszPath, size_t cchPath)
+{
+ image_info ImageInfo;
+ int32 Cookie = 0;
+ status_t status;
+
+ /*
+ * Query the image name from the OS, convert and return it.
+ */
+ status = get_next_image_info(0, &Cookie, &ImageInfo);
+ AssertReturn((status == B_OK), VERR_INTERNAL_ERROR);
+
+ int rc = rtPathFromNativeCopy(pszPath, MIN(cchPath, MAXPATHLEN), ImageInfo.name, NULL);
+ AssertMsgRCReturn(rc, ("rc=%Rrc pszLink=\"%s\"\nhex: %.*Rhxs\n", rc, pszPath, MIN(cchPath, MAXPATHLEN), pszPath), rc);
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/r3/haiku/time-haiku.cpp b/src/VBox/Runtime/r3/haiku/time-haiku.cpp
new file mode 100644
index 00000000..269b4b2c
--- /dev/null
+++ b/src/VBox/Runtime/r3/haiku/time-haiku.cpp
@@ -0,0 +1,84 @@
+/* $Id: time-haiku.cpp $ */
+/** @file
+ * IPRT - Time, Haiku.
+ */
+
+/*
+ * Copyright (C) 2012-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_TIME
+#define RTTIME_INCL_TIMEVAL
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <OS.h>
+
+#include <iprt/time.h>
+#include <iprt/err.h>
+#include "internal/time.h"
+
+
+DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void)
+{
+ return (uint64_t)system_time() * 1000;
+}
+
+
+/**
+ * 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)
+{
+ return rtTimeGetSystemNanoTS();
+}
+
+
+/**
+ * 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)
+{
+ return rtTimeGetSystemNanoTS() / 1000000;
+}
+
+
+RTDECL(int) RTTimeSet(PCRTTIMESPEC pTime)
+{
+ struct timeval tv;
+ RTTimeSpecGetTimeval(pTime, &tv);
+ set_real_time_clock(tv.tv_sec);
+ return VINF_SUCCESS;
+}
diff --git a/src/VBox/Runtime/r3/init.cpp b/src/VBox/Runtime/r3/init.cpp
index 8c3699d1..1f680bf2 100644
--- a/src/VBox/Runtime/r3/init.cpp
+++ b/src/VBox/Runtime/r3/init.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -66,11 +66,11 @@
#endif
#include <stdlib.h>
+#include "init.h"
#include "internal/alignmentchecks.h"
#include "internal/path.h"
#include "internal/process.h"
#include "internal/thread.h"
-#include "internal/thread.h"
#include "internal/time.h"
@@ -92,6 +92,9 @@ DECLHIDDEN(size_t) g_cchrtProcDir;
/** The offset of the process name into g_szrtProcExePath. */
DECLHIDDEN(size_t) g_offrtProcName;
+/** The IPRT init flags. */
+static uint32_t g_fInitFlags;
+
/** The argument count of the program. */
static int g_crtArgs = -1;
/** The arguments of the program (UTF-8). This is "leaked". */
@@ -139,6 +142,15 @@ RTDATADECL(bool) g_fRTAlignmentChecks = false;
#endif
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_HAIKU) \
+ || defined(RT_OS_LINUX) || defined(RT_OS_OS2) || defined(RT_OS_SOLARIS) /** @todo add host init hooks everywhere. */
+/* Stubs */
+DECLHIDDEN(int) rtR3InitNativeFirst(uint32_t fFlags) { return VINF_SUCCESS; }
+DECLHIDDEN(int) rtR3InitNativeFinal(uint32_t fFlags) { return VINF_SUCCESS; }
+DECLHIDDEN(void) rtR3InitNativeObtrusive(void) { }
+#endif
+
+
/**
* atexit callback.
*
@@ -228,7 +240,7 @@ static int rtR3InitProgramPath(const char *pszProgramPath)
* Parse the name.
*/
ssize_t offName;
- g_cchrtProcExePath = RTPathParse(g_szrtProcExePath, &g_cchrtProcDir, &offName, NULL);
+ g_cchrtProcExePath = RTPathParseSimple(g_szrtProcExePath, &g_cchrtProcDir, &offName, NULL);
g_offrtProcName = offName;
return VINF_SUCCESS;
}
@@ -265,31 +277,74 @@ static int rtR3InitArgv(uint32_t fFlags, int cArgs, char ***ppapszArgs)
return VINF_SUCCESS;
}
- /*
- * Convert the arguments.
- */
- char **papszArgs = (char **)RTMemAllocZ((cArgs + 1) * sizeof(char *));
- if (!papszArgs)
- return VERR_NO_MEMORY;
-
- for (int i = 0; i < cArgs; i++)
+ if (!(fFlags & RTR3INIT_FLAGS_UTF8_ARGV))
{
- int rc = RTStrCurrentCPToUtf8(&papszArgs[i], papszOrgArgs[i]);
- if (RT_FAILURE(rc))
+ /*
+ * Convert the arguments.
+ */
+ char **papszArgs = (char **)RTMemAllocZ((cArgs + 1) * sizeof(char *));
+ if (!papszArgs)
+ return VERR_NO_MEMORY;
+
+#ifdef RT_OS_WINDOWS
+ /* HACK ALERT! Try convert from unicode versions if possible.
+ Unfortunately for us, __wargv is only initialized if we have a
+ unicode main function. So, we have to use CommandLineToArgvW to get
+ something similar. It should do the same conversion... :-) */
+ int cArgsW = -1;
+ PWSTR *papwszArgs = NULL;
+ if ( papszOrgArgs == __argv
+ && cArgs == __argc
+ && (papwszArgs = CommandLineToArgvW(GetCommandLineW(), &cArgsW)) != NULL )
{
- while (i--)
- RTStrFree(papszArgs[i]);
- RTMemFree(papszArgs);
- return rc;
+ AssertMsg(cArgsW == cArgs, ("%d vs %d\n", cArgsW, cArgs));
+ for (int i = 0; i < cArgs; i++)
+ {
+ int rc = RTUtf16ToUtf8(papwszArgs[i], &papszArgs[i]);
+ if (RT_FAILURE(rc))
+ {
+ while (i--)
+ RTStrFree(papszArgs[i]);
+ RTMemFree(papszArgs);
+ LocalFree(papwszArgs);
+ return rc;
+ }
+ }
+ LocalFree(papwszArgs);
+ }
+ else
+#endif
+ {
+ for (int i = 0; i < cArgs; i++)
+ {
+ int rc = RTStrCurrentCPToUtf8(&papszArgs[i], papszOrgArgs[i]);
+ if (RT_FAILURE(rc))
+ {
+ while (i--)
+ RTStrFree(papszArgs[i]);
+ RTMemFree(papszArgs);
+ return rc;
+ }
+ }
}
- }
- papszArgs[cArgs] = NULL;
- g_papszrtOrgArgs = papszOrgArgs;
- g_papszrtArgs = papszArgs;
- g_crtArgs = cArgs;
+ papszArgs[cArgs] = NULL;
- *ppapszArgs = papszArgs;
+ g_papszrtOrgArgs = papszOrgArgs;
+ g_papszrtArgs = papszArgs;
+ g_crtArgs = cArgs;
+
+ *ppapszArgs = papszArgs;
+ }
+ else
+ {
+ /*
+ * The arguments are already UTF-8, no conversion needed.
+ */
+ g_papszrtOrgArgs = papszOrgArgs;
+ g_papszrtArgs = papszOrgArgs;
+ g_crtArgs = cArgs;
+ }
}
return VINF_SUCCESS;
@@ -316,6 +371,19 @@ static void rtR3SigChildHandler(int iSignal)
static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath)
{
/*
+ * Early native initialization.
+ */
+ int rc = rtR3InitNativeFirst(fFlags);
+ AssertMsgRCReturn(rc, ("rtR3InitNativeFirst failed with %Rrc\n", rc), rc);
+
+ /*
+ * Disable error popups.
+ */
+#if defined(RT_OS_OS2) /** @todo move to private code. */
+ DosError(FERR_DISABLEHARDERR);
+#endif
+
+ /*
* Init C runtime locale before we do anything that may end up converting
* paths or we'll end up using the "C" locale for path conversion.
*/
@@ -331,14 +399,9 @@ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const cha
#endif
/*
- * Disable error popups.
+ * Save the init flags.
*/
-#ifdef RT_OS_WINDOWS
- UINT fOldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX | fOldErrMode);
-#elif defined(RT_OS_OS2)
- DosError(FERR_DISABLEHARDERR);
-#endif
+ g_fInitFlags |= fFlags;
#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
# ifdef VBOX
@@ -363,7 +426,7 @@ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const cha
* This must be done before everything else or else we'll call into threading
* without having initialized TLS entries and suchlike.
*/
- int rc = rtThreadInit();
+ rc = rtThreadInit();
AssertMsgRCReturn(rc, ("Failed to initialize threads, rc=%Rrc!\n", rc), rc);
#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
@@ -465,6 +528,12 @@ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const cha
IPRT_ALIGNMENT_CHECKS_ENABLE();
#endif
+ /*
+ * Final native initialization.
+ */
+ rc = rtR3InitNativeFinal(fFlags);
+ AssertMsgRCReturn(rc, ("rtR3InitNativeFinal failed with %Rrc\n", rc), rc);
+
return VINF_SUCCESS;
}
@@ -483,7 +552,10 @@ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const cha
static int rtR3Init(uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath)
{
/* no entry log flow, because prefixes and thread may freak out. */
- Assert(!(fFlags & ~(RTR3INIT_FLAGS_DLL | RTR3INIT_FLAGS_SUPLIB)));
+ Assert(!(fFlags & ~( RTR3INIT_FLAGS_DLL
+ | RTR3INIT_FLAGS_SUPLIB
+ | RTR3INIT_FLAGS_UNOBTRUSIVE
+ | RTR3INIT_FLAGS_UTF8_ARGV)));
Assert(!(fFlags & RTR3INIT_FLAGS_DLL) || cArgs == 0);
/*
@@ -499,12 +571,23 @@ static int rtR3Init(uint32_t fFlags, int cArgs, char ***papszArgs, const char *p
Assert(!g_fInitializing);
#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
if (fFlags & RTR3INIT_FLAGS_SUPLIB)
+ {
SUPR3Init(NULL);
+ g_fInitFlags |= RTR3INIT_FLAGS_SUPLIB;
+ }
#endif
- if (!pszProgramPath)
- return VINF_SUCCESS;
- int rc = rtR3InitProgramPath(pszProgramPath);
+ if ( !(fFlags & RTR3INIT_FLAGS_UNOBTRUSIVE)
+ && (g_fInitFlags & RTR3INIT_FLAGS_UNOBTRUSIVE))
+ {
+ g_fInitFlags &= ~RTR3INIT_FLAGS_UNOBTRUSIVE;
+ rtR3InitNativeObtrusive();
+ rtThreadReInitObtrusive();
+ }
+
+ int rc = VINF_SUCCESS;
+ if (pszProgramPath)
+ rc = rtR3InitProgramPath(pszProgramPath);
if (RT_SUCCESS(rc))
rc = rtR3InitArgv(fFlags, cArgs, papszArgs);
return rc;
@@ -557,6 +640,10 @@ RTR3DECL(int) RTR3InitEx(uint32_t iVersion, uint32_t fFlags, int cArgs, char ***
return rtR3Init(fFlags, cArgs, papszArgs, pszProgramPath);
}
+RTR3DECL(bool) RTR3InitIsUnobtrusive(void)
+{
+ return RT_BOOL(g_fInitFlags & RTR3INIT_FLAGS_UNOBTRUSIVE);
+}
#if 0 /** @todo implement RTR3Term. */
RTR3DECL(void) RTR3Term(void)
diff --git a/src/VBox/Runtime/r3/init.h b/src/VBox/Runtime/r3/init.h
new file mode 100644
index 00000000..fae5c41f
--- /dev/null
+++ b/src/VBox/Runtime/r3/init.h
@@ -0,0 +1,38 @@
+/* $Id: init.h $ */
+/** @file
+ * IPRT - Ring-3 initialization.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___r3_init_h
+#define ___r3_init_h
+
+#include <iprt/types.h>
+
+DECLHIDDEN(int) rtR3InitNativeFirst(uint32_t fFlags);
+DECLHIDDEN(int) rtR3InitNativeFinal(uint32_t fFlags);
+DECLHIDDEN(void) rtR3InitNativeObtrusive(void);
+
+#endif
+
diff --git a/src/VBox/Runtime/r3/isofs.cpp b/src/VBox/Runtime/r3/isofs.cpp
index 05f5da9d..16d0334f 100644
--- a/src/VBox/Runtime/r3/isofs.cpp
+++ b/src/VBox/Runtime/r3/isofs.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/linux/RTProcIsRunningByName-linux.cpp b/src/VBox/Runtime/r3/linux/RTProcIsRunningByName-linux.cpp
index 5582cef9..64edf958 100644
--- a/src/VBox/Runtime/r3/linux/RTProcIsRunningByName-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/RTProcIsRunningByName-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/linux/RTSystemShutdown-linux.cpp b/src/VBox/Runtime/r3/linux/RTSystemShutdown-linux.cpp
index a1da642c..e58365ac 100644
--- a/src/VBox/Runtime/r3/linux/RTSystemShutdown-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/RTSystemShutdown-linux.cpp
@@ -47,20 +47,24 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char
* Assemble the argument vector.
*/
int iArg = 0;
- const char *apszArgs[5];
+ const char *apszArgs[6];
+
+ RT_BZERO(apszArgs, sizeof(apszArgs));
apszArgs[iArg++] = "/sbin/shutdown";
switch (fFlags & RTSYSTEM_SHUTDOWN_ACTION_MASK)
{
case RTSYSTEM_SHUTDOWN_HALT:
- apszArgs[iArg++] = "--halt";
+ apszArgs[iArg++] = "-h";
+ apszArgs[iArg++] = "-H";
break;
case RTSYSTEM_SHUTDOWN_REBOOT:
- apszArgs[iArg++] = "--reboot";
+ apszArgs[iArg++] = "-r";
break;
case RTSYSTEM_SHUTDOWN_POWER_OFF:
case RTSYSTEM_SHUTDOWN_POWER_OFF_HALT:
- apszArgs[iArg++] = "--poweroff";
+ apszArgs[iArg++] = "-h";
+ apszArgs[iArg++] = "-P";
break;
}
@@ -95,4 +99,3 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char
}
RT_EXPORT_SYMBOL(RTSystemShutdown);
-
diff --git a/src/VBox/Runtime/r3/linux/fileaio-linux.cpp b/src/VBox/Runtime/r3/linux/fileaio-linux.cpp
index 51215de6..2cc8feb1 100644
--- a/src/VBox/Runtime/r3/linux/fileaio-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/fileaio-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -183,6 +183,8 @@ typedef struct RTFILEAIOCTXINTERNAL
volatile bool fWokenUp;
/** Flag whether the thread is currently waiting in the syscall. */
volatile bool fWaiting;
+ /** Flags given during creation. */
+ uint32_t fFlags;
/** Magic value (RTFILEAIOCTX_MAGIC). */
uint32_t u32Magic;
} RTFILEAIOCTXINTERNAL;
@@ -472,10 +474,12 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered)
}
-RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
+RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax,
+ uint32_t fFlags)
{
PRTFILEAIOCTXINTERNAL pCtxInt;
AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER);
+ AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
/* The kernel interface needs a maximum. */
if (cAioReqsMax == RTFILEAIO_UNLIMITED_REQS)
@@ -493,6 +497,7 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
pCtxInt->fWaiting = false;
pCtxInt->hThreadWait = NIL_RTTHREAD;
pCtxInt->cRequestsMax = cAioReqsMax;
+ pCtxInt->fFlags = fFlags;
pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC;
*phAioCtx = (RTFILEAIOCTX)pCtxInt;
}
@@ -658,7 +663,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL
/*
* Can't wait if there are not requests around.
*/
- if (RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0))
+ if ( RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0)
+ && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS))
return VERR_FILE_AIO_NO_REQUEST;
/*
diff --git a/src/VBox/Runtime/r3/linux/mp-linux.cpp b/src/VBox/Runtime/r3/linux/mp-linux.cpp
index 54304aba..210f75a7 100644
--- a/src/VBox/Runtime/r3/linux/mp-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/mp-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,6 +33,9 @@
#include <errno.h>
#include <iprt/mp.h>
+#include "internal/iprt.h"
+
+#include <iprt/alloca.h>
#include <iprt/cpuset.h>
#include <iprt/assert.h>
#include <iprt/string.h>
@@ -82,7 +85,7 @@ static uint32_t rtMpLinuxGetFrequency(RTCPUID idCpu)
while (fgets(sz, sizeof(sz), pFile))
{
char *psz;
- if ( !strncmp(sz, "processor", 9)
+ if ( !strncmp(sz, RT_STR_TUPLE("processor"))
&& (sz[10] == ' ' || sz[10] == '\t' || sz[10] == ':')
&& (psz = strchr(sz, ':')))
{
@@ -93,7 +96,7 @@ static uint32_t rtMpLinuxGetFrequency(RTCPUID idCpu)
idCpuFound = iCpu;
}
else if ( idCpu == idCpuFound
- && !strncmp(sz, "cpu MHz", 7)
+ && !strncmp(sz, RT_STR_TUPLE("cpu MHz"))
&& (sz[10] == ' ' || sz[10] == '\t' || sz[10] == ':')
&& (psz = strchr(sz, ':')))
{
@@ -177,6 +180,36 @@ RTDECL(RTCPUID) RTMpGetCount(void)
}
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ RTCPUID cMax = rtMpLinuxMaxCpus();
+ uint32_t *paidCores = (uint32_t *)alloca(sizeof(paidCores[0]) * (cMax + 1));
+ uint32_t *paidPckgs = (uint32_t *)alloca(sizeof(paidPckgs[0]) * (cMax + 1));
+ uint32_t cCores = 0;
+ for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
+ {
+ if (RTMpIsCpuPossible(idCpu))
+ {
+ uint32_t idCore = (uint32_t)RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/topology/core_id", (int)idCpu);
+ uint32_t idPckg = (uint32_t)RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/topology/physical_package_id", (int)idCpu);
+ uint32_t i;
+ for (i = 0; i < cCores; i++)
+ if ( paidCores[i] == idCore
+ && paidPckgs[i] == idPckg)
+ break;
+ if (i >= cCores)
+ {
+ paidCores[cCores] = idCore;
+ paidPckgs[cCores] = idPckg;
+ cCores++;
+ }
+ }
+ }
+ Assert(cCores > 0);
+ return cCores;
+}
+
+
RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
{
RTCpuSetEmpty(pSet);
@@ -196,6 +229,37 @@ RTDECL(RTCPUID) RTMpGetOnlineCount(void)
}
+RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void)
+{
+ RTCPUID cMax = rtMpLinuxMaxCpus();
+ uint32_t *paidCores = (uint32_t *)alloca(sizeof(paidCores[0]) * (cMax + 1));
+ uint32_t *paidPckgs = (uint32_t *)alloca(sizeof(paidPckgs[0]) * (cMax + 1));
+ uint32_t cCores = 0;
+ for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
+ {
+ if (RTMpIsCpuOnline(idCpu))
+ {
+ uint32_t idCore = (uint32_t)RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/topology/core_id", (int)idCpu);
+ uint32_t idPckg = (uint32_t)RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/topology/physical_package_id", (int)idCpu);
+ uint32_t i;
+ for (i = 0; i < cCores; i++)
+ if ( paidCores[i] == idCore
+ && paidPckgs[i] == idPckg)
+ break;
+ if (i >= cCores)
+ {
+ paidCores[cCores] = idCore;
+ paidPckgs[cCores] = idPckg;
+ cCores++;
+ }
+ }
+ }
+ Assert(cCores > 0);
+ return cCores;
+}
+
+
+
RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu)
{
int64_t kHz = RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq", (int)idCpu);
diff --git a/src/VBox/Runtime/r3/linux/rtProcInitExePath-linux.cpp b/src/VBox/Runtime/r3/linux/rtProcInitExePath-linux.cpp
index 3ab0860b..cb43d9d0 100644
--- a/src/VBox/Runtime/r3/linux/rtProcInitExePath-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/rtProcInitExePath-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/linux/sched-linux.cpp b/src/VBox/Runtime/r3/linux/sched-linux.cpp
index 3972a6af..1e85af5b 100644
--- a/src/VBox/Runtime/r3/linux/sched-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/sched-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp b/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp
index 01094187..b623c846 100644
--- a/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/linux/semmutex-linux.cpp b/src/VBox/Runtime/r3/linux/semmutex-linux.cpp
index 1be76f4e..60abc1ed 100644
--- a/src/VBox/Runtime/r3/linux/semmutex-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/semmutex-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/linux/sysfs.cpp b/src/VBox/Runtime/r3/linux/sysfs.cpp
index aa1060ac..15309330 100644
--- a/src/VBox/Runtime/r3/linux/sysfs.cpp
+++ b/src/VBox/Runtime/r3/linux/sysfs.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -53,8 +53,7 @@
* Constructs the path of a sysfs file from the format parameters passed,
* prepending a prefix if the path is relative.
*
- * @returns The number of characters returned, or -1 and errno set to ERANGE on
- * failure.
+ * @returns The number of characters returned, or an iprt error code on failure.
*
* @param pszPrefix The prefix to prepend if the path is relative. Must end
* in '/'.
@@ -70,8 +69,8 @@ static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf,
const char *pszFormat, va_list va)
{
size_t cchPrefix = strlen(pszPrefix);
- AssertReturnStmt(pszPrefix[cchPrefix - 1] == '/', errno = ERANGE, -1);
- AssertReturnStmt(cchBuf > cchPrefix + 1, errno = ERANGE, -1);
+ AssertReturn(pszPrefix[cchPrefix - 1] == '/', VERR_INVALID_PARAMETER);
+ AssertReturn(cchBuf > cchPrefix + 1, VERR_INVALID_PARAMETER);
/** @todo While RTStrPrintfV prevents overflows, it doesn't make it easy to
* check for truncations. RTPath should provide some formatters and
@@ -80,7 +79,7 @@ static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf,
size_t cch = RTStrPrintfV(pszBuf, cchBuf, pszFormat, va);
if (*pszBuf != '/')
{
- AssertReturnStmt(cchBuf >= cch + cchPrefix + 1, errno = ERANGE, -1);
+ AssertReturn(cchBuf >= cch + cchPrefix + 1, VERR_BUFFER_OVERFLOW);
memmove(pszBuf + cchPrefix, pszBuf, cch + 1);
memcpy(pszBuf, pszPrefix, cchPrefix);
cch += cchPrefix;
@@ -93,8 +92,8 @@ static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf,
* Constructs the path of a sysfs file from the format parameters passed,
* prepending a prefix if the path is relative.
*
- * @returns The number of characters returned, or -1 and errno set to ERANGE on
- * failure.
+ * @returns The number of characters returned, or an iprt error code on failure.
+ * @note Unused.
*
* @param pszPrefix The prefix to prepend if the path is relative. Must end
* in '/'.
@@ -131,7 +130,11 @@ static ssize_t rtLinuxConstructPath(char *pszBuf, size_t cchBuf,
*/
static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
{
- return rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va);
+ ssize_t rc = rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va);
+ if (rc >= 0)
+ return rc;
+ errno = ERANGE;
+ return -1;
}
@@ -409,125 +412,118 @@ RTDECL(ssize_t) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char
}
-static ssize_t rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode, const char *pszBasePath,
- char *pszBuf, size_t cchBuf)
+/** Search for a device node with the number @a DevNum and the type (character
+ * or block) @a fMode below the path @a pszPath. @a pszPath MUST point to a
+ * buffer of size at least RTPATH_MAX which will be modified during the function
+ * execution. On successful return it will contain the path to the device node
+ * found. */
+/** @note This function previously used a local stack buffer of size RTPATH_MAX
+ * to construct the path passed to the next recursive call, which used up 4K
+ * of stack space per iteration and caused a stack overflow on a path with
+ * too many components. */
+static int rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode,
+ char *pszPath)
{
+ int rc;
+ PRTDIR pDir;
+ size_t const cchPath = strlen(pszPath);
+
/*
* Check assumptions made by the code below.
*/
- size_t const cchBasePath = strlen(pszBasePath);
- AssertReturnStmt(cchBasePath < RTPATH_MAX - 10U, errno = ENAMETOOLONG, -1);
-
- ssize_t rcRet;
- PRTDIR pDir;
- int rc = RTDirOpen(&pDir, pszBasePath);
+ AssertReturn(cchPath < RTPATH_MAX - 10U, VERR_BUFFER_OVERFLOW);
+ rc = RTDirOpen(&pDir, pszPath);
if (RT_SUCCESS(rc))
{
- char szPath[RTPATH_MAX]; /** @todo 4K per recursion - can easily be optimized away by passing it along pszBasePath
- and only remember the length. */
- memcpy(szPath, pszBasePath, cchBasePath + 1);
-
for (;;)
{
RTDIRENTRYEX Entry;
- rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
+ rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX,
+ RTPATH_F_ON_LINK);
if (RT_FAILURE(rc))
- {
- errno = rc == VERR_NO_MORE_FILES
- ? ENOENT
- : rc == VERR_BUFFER_OVERFLOW
- ? EOVERFLOW
- : EIO;
- rcRet = -1;
break;
- }
if (RTFS_IS_SYMLINK(Entry.Info.Attr.fMode))
continue;
-
+ pszPath[cchPath] = '\0';
+ rc = RTPathAppend(pszPath, RTPATH_MAX, Entry.szName);
+ if (RT_FAILURE(rc))
+ break;
/* Do the matching. */
if ( Entry.Info.Attr.u.Unix.Device == DevNum
&& (Entry.Info.Attr.fMode & RTFS_TYPE_MASK) == fMode)
- {
- rcRet = rtLinuxConstructPath(pszBuf, cchBuf, pszBasePath, "%s", Entry.szName);
break;
- }
-
/* Recurse into subdirectories. */
if (!RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode))
continue;
if (Entry.szName[0] == '.')
continue;
-
- szPath[cchBasePath] = '\0';
- rc = RTPathAppend(szPath, sizeof(szPath) - 1, Entry.szName); /* -1: for slash */
- if (RT_FAILURE(rc))
- {
- errno = ENAMETOOLONG;
- rcRet = -1;
- break;
- }
- strcat(&szPath[cchBasePath], "/");
- rcRet = rtLinuxFindDevicePathRecursive(DevNum, fMode, szPath, pszBuf, cchBuf);
- if (rcRet >= 0 || errno != ENOENT)
+ rc = rtLinuxFindDevicePathRecursive(DevNum, fMode, pszPath);
+ if (RT_SUCCESS(rc) || rc != VERR_NO_MORE_FILES)
break;
}
RTDirClose(pDir);
}
- else
- {
- rcRet = -1;
- errno = RTErrConvertToErrno(rc);
- }
- return rcRet;
+ return rc;
}
-RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf,
- const char *pszSuggestion, va_list va)
+RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf,
+ size_t cchBuf, const char *pszSuggestion,
+ va_list va)
{
- AssertReturnStmt(cchBuf >= 2, errno = EINVAL, -1);
- AssertReturnStmt( fMode == RTFS_TYPE_DEV_CHAR
- || fMode == RTFS_TYPE_DEV_BLOCK,
- errno = EINVAL, -1);
+ char szFilename[RTPATH_MAX];
+ int rc = VINF_TRY_AGAIN;
+ AssertReturn(cchBuf >= 2, VERR_INVALID_PARAMETER);
+ AssertReturn( fMode == RTFS_TYPE_DEV_CHAR
+ || fMode == RTFS_TYPE_DEV_BLOCK,
+ VERR_INVALID_PARAMETER);
if (pszSuggestion)
{
/*
* Construct the filename and read the link.
*/
- char szFilename[RTPATH_MAX];
- int rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/", pszSuggestion, va);
- if (rc == -1)
- return -1;
-
- /*
- * Check whether the caller's suggestion was right.
- */
- RTFSOBJINFO Info;
- rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX);
- if ( RT_SUCCESS(rc)
- && Info.Attr.u.Unix.Device == DevNum
- && (Info.Attr.fMode & RTFS_TYPE_MASK) == fMode)
+ rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/",
+ pszSuggestion, va);
+ if (rc > 0)
{
- size_t cchPath = strlen(szFilename);
- if (cchPath >= cchBuf)
- {
- errno = EOVERFLOW;
- return -1;
- }
- memcpy(pszBuf, szFilename, cchPath + 1);
- return cchPath;
+ /*
+ * Check whether the caller's suggestion was right.
+ */
+ RTFSOBJINFO Info;
+ rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX);
+ if ( rc == VERR_PATH_NOT_FOUND
+ || rc == VERR_FILE_NOT_FOUND
+ || ( RT_SUCCESS(rc)
+ && ( Info.Attr.u.Unix.Device != DevNum
+ || (Info.Attr.fMode & RTFS_TYPE_MASK) != fMode)))
+ /* The suggestion was wrong, fall back on the brute force attack. */
+ rc = VINF_TRY_AGAIN;
}
-
- /* The suggestion was wrong, fall back on the brute force attack. */
}
- return rtLinuxFindDevicePathRecursive(DevNum, fMode, "/dev/", pszBuf, cchBuf);
+ if (rc == VINF_TRY_AGAIN)
+ {
+ RTStrCopy(szFilename, sizeof(szFilename), "/dev/");
+ rc = rtLinuxFindDevicePathRecursive(DevNum, fMode, szFilename);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ size_t cchPath = strlen(szFilename);
+ if (cchPath >= cchBuf)
+ return VERR_BUFFER_OVERFLOW;
+ memcpy(pszBuf, szFilename, cchPath + 1);
+ return cchPath;
+ }
+ return rc;
}
-RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf,
- const char *pszSuggestion, ...)
+/** @todo Do we really need to return the string length? If the caller is
+ * interested (the current ones aren't) they can check themselves. */
+RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf,
+ size_t cchBuf, const char *pszSuggestion,
+ ...)
{
va_list va;
va_start(va, pszSuggestion);
diff --git a/src/VBox/Runtime/r3/linux/systemmem-linux.cpp b/src/VBox/Runtime/r3/linux/systemmem-linux.cpp
index f3234403..23fe70b8 100644
--- a/src/VBox/Runtime/r3/linux/systemmem-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/systemmem-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2012 Oracle Corporation
+ * Copyright (C) 2012-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,7 +33,9 @@
#include <iprt/err.h>
#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <stdio.h>
#include <errno.h>
/* Satisfy compiller warning */
@@ -50,7 +52,7 @@ RTDECL(int) RTSystemQueryTotalRam(uint64_t *pcb)
int rc = sysinfo(&info);
if (rc == 0)
{
- *pcb = (uint64_t)(info.totalram * (unsigned long)info.mem_unit);
+ *pcb = (uint64_t)info.totalram * info.mem_unit;
return VINF_SUCCESS;
}
return RTErrConvertFromErrno(errno);
@@ -61,11 +63,45 @@ RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb)
{
AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+ FILE *pFile = fopen("/proc/meminfo", "r");
+ if (pFile)
+ {
+ int rc = VERR_NOT_FOUND;
+ uint64_t cbTotal = 0;
+ uint64_t cbFree = 0;
+ uint64_t cbBuffers = 0;
+ uint64_t cbCached = 0;
+ char sz[256];
+ while (fgets(sz, sizeof(sz), pFile))
+ {
+ if (!strncmp(sz, RT_STR_TUPLE("MemTotal:")))
+ rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("MemTotal:")]), NULL, 0, &cbTotal);
+ else if (!strncmp(sz, RT_STR_TUPLE("MemFree:")))
+ rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("MemFree:")]), NULL, 0, &cbFree);
+ else if (!strncmp(sz, RT_STR_TUPLE("Buffers:")))
+ rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("Buffers:")]), NULL, 0, &cbBuffers);
+ else if (!strncmp(sz, RT_STR_TUPLE("Cached:")))
+ rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("Cached:")]), NULL, 0, &cbCached);
+ if (RT_FAILURE(rc))
+ break;
+ }
+ fclose(pFile);
+ if (RT_SUCCESS(rc))
+ {
+ *pcb = (cbFree + cbBuffers + cbCached) * _1K;
+ return VINF_SUCCESS;
+ }
+ }
+ /*
+ * Fallback (e.g. /proc not mapped) to sysinfo. Less accurat because there
+ * is no information about the cached memory. 'Cached:' from above is only
+ * accessible through proc :-(
+ */
struct sysinfo info;
int rc = sysinfo(&info);
if (rc == 0)
{
- *pcb = (uint64_t)(info.freeram * (unsigned long)info.mem_unit);
+ *pcb = ((uint64_t)info.freeram + info.bufferram) * info.mem_unit;
return VINF_SUCCESS;
}
return RTErrConvertFromErrno(errno);
diff --git a/src/VBox/Runtime/r3/linux/time-linux.cpp b/src/VBox/Runtime/r3/linux/time-linux.cpp
index a9de927e..ab9c0e5a 100644
--- a/src/VBox/Runtime/r3/linux/time-linux.cpp
+++ b/src/VBox/Runtime/r3/linux/time-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/nt/Makefile.kup b/src/VBox/Runtime/r3/nt/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/Runtime/r3/nt/Makefile.kup
diff --git a/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp b/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
new file mode 100644
index 00000000..f93f6e4e
--- /dev/null
+++ b/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
@@ -0,0 +1,697 @@
+/* $Id: direnum-r3-nt.cpp $ */
+/** @file
+ * IPRT - Directory Enumeration, Native NT.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DIR
+#include "internal-r3-nt.h"
+
+#include <iprt/dir.h>
+#include <iprt/path.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/log.h>
+#include "internal/fs.h"
+#include "internal/dir.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** Whether to return a single record (TRUE) or multiple (FALSE)o. */
+#define RTDIR_NT_SINGLE_RECORD FALSE
+
+/** Go hard on record chaining (has slight performance impact). */
+#ifdef RT_STRICT
+# define RTDIR_NT_STRICT
+#endif
+
+
+/* ASSUMES FileID comes after ShortName and the structus are identical up to that point. */
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, NextEntryOffset, FILE_ID_BOTH_DIR_INFORMATION, NextEntryOffset);
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileIndex , FILE_ID_BOTH_DIR_INFORMATION, FileIndex );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, CreationTime , FILE_ID_BOTH_DIR_INFORMATION, CreationTime );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, LastAccessTime , FILE_ID_BOTH_DIR_INFORMATION, LastAccessTime );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, LastWriteTime , FILE_ID_BOTH_DIR_INFORMATION, LastWriteTime );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ChangeTime , FILE_ID_BOTH_DIR_INFORMATION, ChangeTime );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, EndOfFile , FILE_ID_BOTH_DIR_INFORMATION, EndOfFile );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, AllocationSize , FILE_ID_BOTH_DIR_INFORMATION, AllocationSize );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileAttributes , FILE_ID_BOTH_DIR_INFORMATION, FileAttributes );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileNameLength , FILE_ID_BOTH_DIR_INFORMATION, FileNameLength );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, EaSize , FILE_ID_BOTH_DIR_INFORMATION, EaSize );
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ShortNameLength, FILE_ID_BOTH_DIR_INFORMATION, ShortNameLength);
+AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ShortName , FILE_ID_BOTH_DIR_INFORMATION, ShortName );
+
+
+
+size_t rtDirNativeGetStructSize(const char *pszPath)
+{
+ NOREF(pszPath);
+ return sizeof(RTDIR);
+}
+
+
+int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
+{
+ /*
+ * Convert the filter to UTF-16.
+ */
+ int rc;
+ pDir->pNtFilterStr = NULL;
+ if ( pDir->cchFilter > 0
+ && pDir->enmFilter == RTDIRFILTER_WINNT)
+ {
+ PRTUTF16 pwszTmp;
+ rc = RTStrToUtf16(pDir->pszFilter, &pwszTmp);
+ if (RT_FAILURE(rc))
+ return rc;
+ pDir->NtFilterStr.Buffer = pwszTmp;
+ pDir->NtFilterStr.Length = pDir->NtFilterStr.MaximumLength = (uint16_t)(RTUtf16Len(pwszTmp) * sizeof(RTUTF16));
+ pDir->pNtFilterStr = &pDir->NtFilterStr;
+ }
+
+ /*
+ * Try open the directory
+ */
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ bool fObjDir;
+#endif
+ rc = rtNtPathOpenDir(pszPathBuf,
+ FILE_READ_DATA | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
+ OBJ_CASE_INSENSITIVE,
+ &pDir->hDir,
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ &fObjDir
+#else
+ NULL
+#endif
+ );
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Init data.
+ */
+ pDir->fDataUnread = false; /* spelling it out */
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ if (fObjDir)
+ pDir->enmInfoClass = FileMaximumInformation; /* object directory. */
+#endif
+ }
+ return rc;
+}
+
+
+RTDECL(int) RTDirClose(PRTDIR pDir)
+{
+ /*
+ * Validate input.
+ */
+ if (!pDir)
+ return VERR_INVALID_PARAMETER;
+ if (pDir->u32Magic != RTDIR_MAGIC)
+ {
+ AssertMsgFailed(("Invalid pDir=%p\n", pDir));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Close the handle.
+ */
+ pDir->u32Magic = ~RTDIR_MAGIC;
+ if (pDir->hDir != MY_INVALID_HANDLE_VALUE)
+ {
+ int rc = rtNtPathClose(pDir->hDir);
+ AssertRC(rc);
+ pDir->hDir = MY_INVALID_HANDLE_VALUE;
+ }
+ RTStrFree(pDir->pszName);
+ pDir->pszName = NULL;
+ RTUtf16Free(pDir->NtFilterStr.Buffer);
+ pDir->NtFilterStr.Buffer = NULL;
+ RTMemFree(pDir->pabBuffer);
+ pDir->pabBuffer = NULL;
+ RTMemFree(pDir);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Checks the validity of the current record.
+ *
+ * @returns IPRT status code
+ * @param pThis The directory instance data.
+ */
+static int rtDirNtCheckRecord(PRTDIR pThis)
+{
+#ifdef RTDIR_NT_STRICT
+# ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ if (pThis->enmInfoClass != FileMaximumInformation)
+# endif
+ {
+ uintptr_t uEndAddr;
+ if (pThis->enmInfoClass == FileIdBothDirectoryInformation)
+ uEndAddr = (uintptr_t)&pThis->uCurData.pBothId->FileName[0];
+ else
+ uEndAddr = (uintptr_t)&pThis->uCurData.pBoth->FileName[0];
+ AssertReturn(uEndAddr < (uintptr_t)&pThis->pabBuffer[pThis->cbBuffer], VERR_IO_GEN_FAILURE);
+
+ AssertReturn(pThis->uCurData.pBoth->FileNameLength < _64K, VERR_FILENAME_TOO_LONG);
+ AssertReturn((pThis->uCurData.pBoth->FileNameLength & 1) == 0, VERR_IO_GEN_FAILURE);
+
+ uEndAddr += pThis->uCurData.pBoth->FileNameLength;
+ AssertReturn(uEndAddr <= (uintptr_t)&pThis->pabBuffer[pThis->cbBuffer], VERR_IO_GEN_FAILURE);
+
+ AssertReturn((unsigned)pThis->uCurData.pBoth->ShortNameLength <= sizeof(pThis->uCurData.pBoth->ShortName),
+ VERR_IO_GEN_FAILURE);
+ }
+#endif
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Advances the buffer pointer.
+ *
+ * @param pThis The directory instance data.
+ */
+static int rtDirNtAdvanceBuffer(PRTDIR pThis)
+{
+ int rc;
+
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ if (pThis->enmInfoClass == FileMaximumInformation)
+ {
+ pThis->uCurData.pObjDir++;
+ pThis->fDataUnread = pThis->uCurData.pObjDir->Name.Length != 0;
+ return VINF_SUCCESS;
+ }
+#endif
+
+ pThis->fDataUnread = false;
+
+ uint32_t const offNext = pThis->uCurData.pBoth->NextEntryOffset;
+ if (offNext == 0)
+ return VINF_SUCCESS;
+
+#ifdef RTDIR_NT_STRICT
+ /* Make sure the next-record offset is beyond the current record. */
+ size_t cbRec;
+ if (pThis->enmInfoClass == FileIdBothDirectoryInformation)
+ cbRec = RT_UOFFSETOF(FILE_ID_BOTH_DIR_INFORMATION, FileName);
+ else
+ cbRec = RT_UOFFSETOF(FILE_BOTH_DIR_INFORMATION, FileName);
+ cbRec += pThis->uCurData.pBoth->FileNameLength;
+ AssertReturn(offNext >= cbRec, VERR_IO_GEN_FAILURE);
+#endif
+ pThis->uCurData.u += offNext;
+
+ rc = rtDirNtCheckRecord(pThis);
+ pThis->fDataUnread = RT_SUCCESS(rc);
+ return rc;
+}
+
+
+/**
+ * Fetches more data from the file system.
+ *
+ * @returns IPRT status code
+ * @param pThis The directory instance data.
+ */
+static int rtDirNtFetchMore(PRTDIR pThis)
+{
+ Assert(!pThis->fDataUnread);
+
+ /*
+ * Allocate the buffer the first time around.
+ * We do this in lazy fashion as some users of RTDirOpen will not actually
+ * list any files, just open it for various reasons.
+ */
+ bool fFirst = false;
+ if (!pThis->pabBuffer)
+ {
+ fFirst = false;
+ pThis->cbBufferAlloc = _256K;
+ pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
+ if (!pThis->pabBuffer)
+ {
+ do
+ {
+ pThis->cbBufferAlloc /= 4;
+ pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
+ } while (pThis->pabBuffer == NULL && pThis->cbBufferAlloc > _4K);
+ if (!pThis->pabBuffer)
+ return VERR_NO_MEMORY;
+ }
+ }
+
+ /*
+ * Read more.
+ */
+ NTSTATUS rcNt;
+ IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0)
+ {
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ if (pThis->enmInfoClass == FileMaximumInformation)
+ {
+ Ios.Information = 0;
+ Ios.Status = rcNt = NtQueryDirectoryObject(pThis->hDir,
+ pThis->pabBuffer,
+ pThis->cbBufferAlloc,
+ RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
+ FALSE /*RestartScan*/,
+ &pThis->uObjDirCtx,
+ (PULONG)&Ios.Information);
+ }
+ else
+#endif
+ rcNt = NtQueryDirectoryFile(pThis->hDir,
+ NULL /* Event */,
+ NULL /* ApcRoutine */,
+ NULL /* ApcContext */,
+ &Ios,
+ pThis->pabBuffer,
+ pThis->cbBufferAlloc,
+ pThis->enmInfoClass,
+ RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
+ pThis->pNtFilterStr,
+ FALSE /*RestartScan */);
+ }
+ else
+ {
+ /*
+ * The first time around we have figure which info class we can use.
+ * We prefer one which gives us file IDs, but we'll settle for less.
+ */
+ pThis->enmInfoClass = FileIdBothDirectoryInformation;
+ rcNt = NtQueryDirectoryFile(pThis->hDir,
+ NULL /* Event */,
+ NULL /* ApcRoutine */,
+ NULL /* ApcContext */,
+ &Ios,
+ pThis->pabBuffer,
+ pThis->cbBufferAlloc,
+ pThis->enmInfoClass,
+ RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
+ pThis->pNtFilterStr,
+ FALSE /*RestartScan */);
+ if (!NT_SUCCESS(rcNt))
+ {
+ pThis->enmInfoClass = FileBothDirectoryInformation;
+ rcNt = NtQueryDirectoryFile(pThis->hDir,
+ NULL /* Event */,
+ NULL /* ApcRoutine */,
+ NULL /* ApcContext */,
+ &Ios,
+ pThis->pabBuffer,
+ pThis->cbBufferAlloc,
+ pThis->enmInfoClass,
+ RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
+ pThis->pNtFilterStr,
+ FALSE /*RestartScan */);
+ }
+ }
+ if (!NT_SUCCESS(rcNt))
+ {
+ if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES)
+ return VERR_NO_MORE_FILES;
+ return RTErrConvertFromNtStatus(rcNt);
+ }
+ Assert(Ios.Information > sizeof(*pThis->uCurData.pBoth));
+
+ /*
+ * Set up the data members.
+ */
+ pThis->uCurData.u = (uintptr_t)pThis->pabBuffer;
+ pThis->cbBuffer = Ios.Information;
+
+ int rc = rtDirNtCheckRecord(pThis);
+ pThis->fDataUnread = RT_SUCCESS(rc);
+
+ return rc;
+}
+
+
+/**
+ * Converts the name from UTF-16 to UTF-8.
+ *
+ * Fortunately, the names are relative to the directory, so we won't have to do
+ * any sweaty path style coversion. :-)
+ *
+ * @returns IPRT status code
+ * @param pThis The directory instance data.
+ * @param cbName The file name length in bytes.
+ * @param pwsName The file name, not terminated.
+ */
+static int rtDirNtConvertName(PRTDIR pThis, uint32_t cbName, PCRTUTF16 pwsName)
+{
+ int rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName);
+ if (RT_SUCCESS(rc))
+ {
+ if (!pThis->cbNameAlloc)
+ pThis->cbNameAlloc = pThis->cchName + 1;
+ }
+ else if (rc == VERR_BUFFER_OVERFLOW)
+ {
+ RTStrFree(pThis->pszName);
+ pThis->pszName = NULL;
+ pThis->cbNameAlloc = 0;
+
+ rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName);
+ if (RT_SUCCESS(rc))
+ pThis->cbNameAlloc = pThis->cchName + 1;
+ }
+ Assert(RT_SUCCESS(rc) ? pThis->pszName != NULL : pThis->pszName == NULL);
+ return rc;
+}
+
+
+/**
+ * Converts the name of the current record.
+ *
+ * @returns IPRT status code.
+ * @param pThis The directory instance data.
+ */
+static int rtDirNtConvertCurName(PRTDIR pThis)
+{
+ switch (pThis->enmInfoClass)
+ {
+ case FileIdBothDirectoryInformation:
+ return rtDirNtConvertName(pThis, pThis->uCurData.pBothId->FileNameLength, pThis->uCurData.pBothId->FileName);
+ case FileBothDirectoryInformation:
+ return rtDirNtConvertName(pThis, pThis->uCurData.pBoth->FileNameLength, pThis->uCurData.pBoth->FileName);
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ case FileMaximumInformation:
+ return rtDirNtConvertName(pThis, pThis->uCurData.pObjDir->Name.Length, pThis->uCurData.pObjDir->Name.Buffer);
+#endif
+
+ default:
+ AssertFailedReturn(VERR_INTERNAL_ERROR_3);
+ }
+}
+
+
+RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
+{
+ int rc;
+
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(pDir, VERR_INVALID_POINTER);
+ AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
+ size_t cbDirEntry = sizeof(*pDirEntry);
+ if (pcbDirEntry)
+ {
+ cbDirEntry = *pcbDirEntry;
+ AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRY, szName[2]),
+ ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])),
+ VERR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Fetch data?
+ */
+ if (!pDir->fDataUnread)
+ {
+ rc = rtDirNtFetchMore(pDir);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ /*
+ * Convert the filename to UTF-8.
+ */
+ rc = rtDirNtConvertCurName(pDir);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Check if we've got enough space to return the data.
+ */
+ const char *pszName = pDir->pszName;
+ const size_t cchName = pDir->cchName;
+ const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName;
+ if (pcbDirEntry)
+ *pcbDirEntry = cbRequired;
+ if (cbRequired > cbDirEntry)
+ return VERR_BUFFER_OVERFLOW;
+
+ /*
+ * Setup the returned data.
+ */
+ pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName);
+ memcpy(pDirEntry->szName, pszName, cchName + 1);
+
+ pDirEntry->INodeId = pDir->enmInfoClass == FileIdBothDirectoryInformation
+ ? pDir->uCurData.pBothId->FileId.QuadPart : 0;
+
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ if (pDir->enmInfoClass != FileMaximumInformation)
+#endif
+ {
+ switch ( pDir->uCurData.pBoth->FileAttributes
+ & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
+ {
+ default:
+ AssertFailed();
+ case 0:
+ pDirEntry->enmType = RTDIRENTRYTYPE_FILE;
+ break;
+
+ case FILE_ATTRIBUTE_DIRECTORY:
+ pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
+ break;
+
+ case FILE_ATTRIBUTE_REPARSE_POINT:
+ case FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY:
+ pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
+ break;
+ }
+ }
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ else
+ {
+ pDirEntry->enmType = RTDIRENTRYTYPE_UNKNOWN;
+ if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
+ RT_STR_TUPLE("Directory")))
+ pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
+ else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
+ RT_STR_TUPLE("SymbolicLink")))
+ pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
+ }
+#endif
+
+ return rtDirNtAdvanceBuffer(pDir);
+}
+
+
+RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
+ RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
+ int rc;
+
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(pDir, VERR_INVALID_POINTER);
+ AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
+
+ AssertReturn(enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
+ VERR_INVALID_PARAMETER);
+ AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
+
+ size_t cbDirEntry = sizeof(*pDirEntry);
+ if (pcbDirEntry)
+ {
+ cbDirEntry = *pcbDirEntry;
+ AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
+ ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
+ VERR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Fetch data?
+ */
+ if (!pDir->fDataUnread)
+ {
+ rc = rtDirNtFetchMore(pDir);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ /*
+ * Convert the filename to UTF-8.
+ */
+ rc = rtDirNtConvertCurName(pDir);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Check if we've got enough space to return the data.
+ */
+ const char *pszName = pDir->pszName;
+ const size_t cchName = pDir->cchName;
+ const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName;
+ if (pcbDirEntry)
+ *pcbDirEntry = cbRequired;
+ if (cbRequired > cbDirEntry)
+ return VERR_BUFFER_OVERFLOW;
+
+ /*
+ * Setup the returned data.
+ */
+ PFILE_BOTH_DIR_INFORMATION pBoth = pDir->uCurData.pBoth;
+
+ pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName);
+ memcpy(pDirEntry->szName, pszName, cchName + 1);
+ memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ if (pDir->enmInfoClass != FileMaximumInformation)
+#endif
+ {
+ uint8_t cbShort = pBoth->ShortNameLength;
+ if (cbShort > 0)
+ {
+ AssertStmt(cbShort < sizeof(pDirEntry->wszShortName), cbShort = sizeof(pDirEntry->wszShortName) - 2);
+ memcpy(pDirEntry->wszShortName, pBoth->ShortName, cbShort);
+ pDirEntry->cwcShortName = cbShort / 2;
+ }
+ else
+ pDirEntry->cwcShortName = 0;
+
+ pDirEntry->Info.cbObject = pBoth->EndOfFile.QuadPart;
+ pDirEntry->Info.cbAllocated = pBoth->AllocationSize.QuadPart;
+
+ Assert(sizeof(uint64_t) == sizeof(pBoth->CreationTime));
+ RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, pBoth->CreationTime.QuadPart);
+ RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, pBoth->LastAccessTime.QuadPart);
+ RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, pBoth->LastWriteTime.QuadPart);
+ RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime, pBoth->ChangeTime.QuadPart);
+
+ pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pBoth->FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
+ pszName, cchName);
+ }
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ else
+ {
+ pDirEntry->cwcShortName = 0;
+ pDirEntry->Info.cbObject = 0;
+ pDirEntry->Info.cbAllocated = 0;
+ RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, 0);
+ RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, 0);
+ RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, 0);
+ RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime, 0);
+
+ if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
+ RT_STR_TUPLE("Directory")))
+ pDirEntry->Info.Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777;
+ else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
+ RT_STR_TUPLE("SymbolicLink")))
+ pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_REPARSE_POINT | RTFS_TYPE_SYMLINK | 0777;
+ else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
+ RT_STR_TUPLE("Device")))
+ pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_DEVICE | RTFS_TYPE_DEV_CHAR | 0666;
+ else
+ pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0666;
+ }
+#endif
+
+ /*
+ * Requested attributes (we cannot provide anything actually).
+ */
+ switch (enmAdditionalAttribs)
+ {
+ case RTFSOBJATTRADD_EASIZE:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ if (pDir->enmInfoClass == FileMaximumInformation)
+ pDirEntry->Info.Attr.u.EASize.cb = 0;
+ else
+#endif
+ pDirEntry->Info.Attr.u.EASize.cb = pBoth->EaSize;
+ break;
+
+ case RTFSOBJATTRADD_UNIX:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
+ pDirEntry->Info.Attr.u.Unix.uid = ~0U;
+ pDirEntry->Info.Attr.u.Unix.gid = ~0U;
+ pDirEntry->Info.Attr.u.Unix.cHardlinks = 1;
+ pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */
+ pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */
+ pDirEntry->Info.Attr.u.Unix.fFlags = 0;
+ pDirEntry->Info.Attr.u.Unix.GenerationId = 0;
+ pDirEntry->Info.Attr.u.Unix.Device = 0;
+ break;
+
+ case RTFSOBJATTRADD_NOTHING:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
+ break;
+
+ case RTFSOBJATTRADD_UNIX_OWNER:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
+ pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U;
+ pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
+ break;
+
+ case RTFSOBJATTRADD_UNIX_GROUP:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
+ pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U;
+ pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0';
+ break;
+
+ default:
+ AssertMsgFailed(("Impossible!\n"));
+ return VERR_INTERNAL_ERROR;
+ }
+
+ /*
+ * Follow links if requested.
+ */
+ if ( (fFlags & RTPATH_F_FOLLOW_LINK)
+ && RTFS_IS_SYMLINK(fFlags))
+ {
+ /** @todo Symlinks: Find[First|Next]FileW will return info about
+ the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */
+ }
+
+ /*
+ * Finally advance the buffer.
+ */
+ return rtDirNtAdvanceBuffer(pDir);
+}
+
diff --git a/src/VBox/Runtime/r3/nt/fs-nt.cpp b/src/VBox/Runtime/r3/nt/fs-nt.cpp
new file mode 100644
index 00000000..314059de
--- /dev/null
+++ b/src/VBox/Runtime/r3/nt/fs-nt.cpp
@@ -0,0 +1,284 @@
+/* $Id: fs-nt.cpp $ */
+/** @file
+ * IPRT - File System, Native NT.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_FS
+#include "internal-r3-nt.h"
+
+#include <iprt/fs.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/param.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/assert.h>
+#include "internal/fs.h"
+
+
+
+
+RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pcbFree,
+ uint32_t *pcbBlock, uint32_t *pcbSector)
+{
+ AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER);
+
+ /*
+ * Open the file/dir/whatever.
+ */
+ HANDLE hFile;
+ int rc = rtNtPathOpen(pszFsPath,
+ GENERIC_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_OPEN_FOR_BACKUP_INTENT,
+ OBJ_CASE_INSENSITIVE,
+ &hFile,
+ NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Get the volume information.
+ */
+ FILE_FS_SIZE_INFORMATION FsSizeInfo;
+ IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &FsSizeInfo, sizeof(FsSizeInfo), FileFsSizeInformation);
+ if (NT_SUCCESS(rcNt))
+ {
+ /*
+ * Calculate the return values.
+ */
+ if (pcbTotal)
+ {
+ *pcbTotal = FsSizeInfo.TotalAllocationUnits.QuadPart
+ * FsSizeInfo.SectorsPerAllocationUnit
+ * FsSizeInfo.BytesPerSector;
+ if ( *pcbTotal / FsSizeInfo.SectorsPerAllocationUnit / FsSizeInfo.BytesPerSector
+ != FsSizeInfo.TotalAllocationUnits.QuadPart)
+ *pcbTotal = UINT64_MAX;
+ }
+
+ if (pcbFree)
+ {
+ *pcbFree = FsSizeInfo.AvailableAllocationUnits.QuadPart
+ * FsSizeInfo.SectorsPerAllocationUnit
+ * FsSizeInfo.BytesPerSector;
+ if ( *pcbFree / FsSizeInfo.SectorsPerAllocationUnit / FsSizeInfo.BytesPerSector
+ != FsSizeInfo.AvailableAllocationUnits.QuadPart)
+ *pcbFree = UINT64_MAX;
+ }
+
+ if (pcbBlock)
+ {
+ *pcbBlock = FsSizeInfo.SectorsPerAllocationUnit * FsSizeInfo.BytesPerSector;
+ if (*pcbBlock / FsSizeInfo.BytesPerSector != FsSizeInfo.SectorsPerAllocationUnit)
+ rc = VERR_OUT_OF_RANGE;
+ }
+
+ if (pcbSector)
+ *pcbSector = FsSizeInfo.BytesPerSector;
+ }
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+
+ rtNtPathClose(hFile);
+ }
+ return rc;
+}
+
+
+RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
+{
+ /*
+ * Validate & get valid root path.
+ */
+ AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER);
+ AssertPtrReturn(pu32Serial, VERR_INVALID_POINTER);
+
+ /*
+ * Open the file/dir/whatever.
+ */
+ HANDLE hFile;
+ int rc = rtNtPathOpen(pszFsPath,
+ GENERIC_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_OPEN_FOR_BACKUP_INTENT,
+ OBJ_CASE_INSENSITIVE,
+ &hFile,
+ NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Get the volume information.
+ */
+ union
+ {
+ FILE_FS_VOLUME_INFORMATION FsVolInfo;
+ uint8_t abBuf[sizeof(FILE_FS_VOLUME_INFORMATION) + 4096];
+ } u;
+ IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsVolumeInformation);
+ if (NT_SUCCESS(rcNt))
+ *pu32Serial = u.FsVolInfo.VolumeSerialNumber;
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+
+ rtNtPathClose(hFile);
+ }
+ return rc;
+}
+
+
+RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties)
+{
+ /*
+ * Validate & get valid root path.
+ */
+ AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER);
+ AssertPtrReturn(pProperties, VERR_INVALID_POINTER);
+
+ /*
+ * Open the file/dir/whatever.
+ */
+ HANDLE hFile;
+ int rc = rtNtPathOpen(pszFsPath,
+ GENERIC_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_OPEN_FOR_BACKUP_INTENT,
+ OBJ_CASE_INSENSITIVE,
+ &hFile,
+ NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Get the volume information.
+ */
+ union
+ {
+ FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
+ uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096];
+ } u;
+ IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation);
+ if (NT_SUCCESS(rcNt))
+ {
+ FILE_FS_DEVICE_INFORMATION FsDevInfo;
+ rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &FsDevInfo, sizeof(FsDevInfo), FileFsDeviceInformation);
+ if (NT_SUCCESS(rcNt))
+ {
+ /*
+ * Fill in the return structure.
+ */
+ memset(pProperties, 0, sizeof(*pProperties));
+ pProperties->cbMaxComponent = u.FsAttrInfo.MaximumComponentNameLength;
+ pProperties->fFileCompression = !!(u.FsAttrInfo.FileSystemAttributes & FILE_FILE_COMPRESSION);
+ pProperties->fCompressed = !!(u.FsAttrInfo.FileSystemAttributes & FILE_VOLUME_IS_COMPRESSED);
+ pProperties->fReadOnly = !!(u.FsAttrInfo.FileSystemAttributes & FILE_READ_ONLY_VOLUME);
+ pProperties->fSupportsUnicode = !!(u.FsAttrInfo.FileSystemAttributes & FILE_UNICODE_ON_DISK);
+ pProperties->fCaseSensitive = false; /* win32 is case preserving only */
+ /** @todo r=bird: What about FILE_CASE_SENSITIVE_SEARCH ? Is this set for NTFS
+ * as well perchance? If so, better mention it instead of just setting
+ * fCaseSensitive to false. */
+
+ /* figure the remote stuff */
+ pProperties->fRemote = RT_BOOL(FsDevInfo.Characteristics & FILE_REMOTE_DEVICE);
+ }
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+ }
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+
+ rtNtPathClose(hFile);
+ }
+ return rc;
+}
+
+
+
+RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
+{
+ /*
+ * Validate input.
+ */
+ *penmType = RTFSTYPE_UNKNOWN;
+ AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER);
+ AssertReturn(*pszFsPath, VERR_INVALID_PARAMETER);
+
+ /*
+ * Open the file/dir/whatever.
+ */
+ HANDLE hFile;
+ int rc = rtNtPathOpen(pszFsPath,
+ GENERIC_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_OPEN_FOR_BACKUP_INTENT,
+ OBJ_CASE_INSENSITIVE,
+ &hFile,
+ NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Get the file system name.
+ */
+ union
+ {
+ FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
+ uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096];
+ } u;
+ IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation);
+ if (NT_SUCCESS(rcNt))
+ {
+#define IS_FS(a_szName) \
+ rtNtCompWideStrAndAscii(u.FsAttrInfo.FileSystemName, u.FsAttrInfo.FileSystemNameLength, RT_STR_TUPLE(a_szName))
+ if (IS_FS("NTFS"))
+ *penmType = RTFSTYPE_NTFS;
+ else if (IS_FS("FAT"))
+ *penmType = RTFSTYPE_FAT;
+ else if (IS_FS("FAT32"))
+ *penmType = RTFSTYPE_FAT;
+ else if (IS_FS("VBoxSharedFolderFS"))
+ *penmType = RTFSTYPE_VBOXSHF;
+#undef IS_FS
+ }
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+
+ rtNtPathClose(hFile);
+ }
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/nt/internal-r3-nt.h b/src/VBox/Runtime/r3/nt/internal-r3-nt.h
new file mode 100644
index 00000000..0a970965
--- /dev/null
+++ b/src/VBox/Runtime/r3/nt/internal-r3-nt.h
@@ -0,0 +1,140 @@
+/* $Id: internal-r3-nt.h $ */
+/** @file
+ * IPRT - Internal Header for the Native NT code.
+ */
+
+/*
+ * Copyright (C) 2010-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___internal_r3_nt_h___
+#define ___internal_r3_nt_h___
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <ntstatus.h>
+#ifdef IPRT_NT_USE_WINTERNL
+# define WIN32_NO_STATUS
+# include <windef.h>
+# include <winnt.h>
+# include <winternl.h>
+# define IPRT_NT_NEED_API_GROUP_1
+
+#elif defined(IPRT_NT_USE_WDM)
+# include <wdm.h>
+# define IPRT_NT_NEED_API_GROUP_1
+
+#else
+# include <ntifs.h>
+#endif
+#include "internal/iprt.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** Indicates that we're targetting native NT in the current source. */
+#define RT_USE_NATIVE_NT 1
+/** Initializes a IO_STATUS_BLOCK. */
+#define MY_IO_STATUS_BLOCK_INITIALIZER { STATUS_FAILED_DRIVER_ENTRY, ~(uintptr_t)42 }
+/** Similar to INVALID_HANDLE_VALUE in the Windows environment. */
+#define MY_INVALID_HANDLE_VALUE ( (HANDLE)~(uintptr_t)0 )
+
+#ifdef DEBUG_bird
+/** Enables the "\\!\" NT path pass thru as well as hacks for listing NT object
+ * directories. */
+# define IPRT_WITH_NT_PATH_PASSTHRU 1
+#endif
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+int rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
+ ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
+ PHANDLE phHandle, PULONG_PTR puDisposition);
+int rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
+ ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir);
+int rtNtPathClose(HANDLE hHandle);
+
+
+/**
+ * Internal helper for comparing a WCHAR string with a char string.
+ *
+ * @returns @c true if equal, @c false if not.
+ * @param pwsz1 The first string.
+ * @param cb1 The length of the first string, in bytes.
+ * @param psz2 The second string.
+ * @param cch2 The length of the second string.
+ */
+DECLINLINE(bool) rtNtCompWideStrAndAscii(WCHAR const *pwsz1, size_t cch1, const char *psz2, size_t cch2)
+{
+ if (cch1 != cch2 * 2)
+ return false;
+ while (cch2-- > 0)
+ {
+ unsigned ch1 = *pwsz1++;
+ unsigned ch2 = (unsigned char)*psz2++;
+ if (ch1 != ch2)
+ return false;
+ }
+ return true;
+}
+
+
+/*******************************************************************************
+* NT APIs *
+*******************************************************************************/
+
+RT_C_DECLS_BEGIN
+
+#ifdef IPRT_NT_NEED_API_GROUP_1
+
+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;
+extern "C" NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS);
+
+#endif
+
+NTSTATUS NTAPI 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;
+
+NTSTATUS NTAPI NtQueryDirectoryObject(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
+
+
+RT_C_DECLS_END
+
+#endif
+
diff --git a/src/VBox/Runtime/r3/nt/pathint-nt.cpp b/src/VBox/Runtime/r3/nt/pathint-nt.cpp
new file mode 100644
index 00000000..a68f0597
--- /dev/null
+++ b/src/VBox/Runtime/r3/nt/pathint-nt.cpp
@@ -0,0 +1,356 @@
+/* $Id: pathint-nt.cpp $ */
+/** @file
+ * IPRT - Native NT, Internal Path stuff.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_FS
+#include "internal-r3-nt.h"
+
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/err.h>
+#include <iprt/assert.h>
+
+
+
+/**
+ * Handles the pass thru case.
+ *
+ * @returns IPRT status code.
+ * @param pNtName Where to return the NT name.
+ * @param phRootDir Where to return the root handle, if applicable.
+ * @param pszPath The UTF-8 path.
+ */
+static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+{
+ PRTUTF16 pwszPath = NULL;
+ size_t cwcLen;
+ int rc = RTStrToUtf16Ex(pszPath + 1, RTSTR_MAX, &pwszPath, 0, &cwcLen);
+ if (RT_SUCCESS(rc))
+ {
+ if (cwcLen < _32K - 1)
+ {
+ pwszPath[0] = '\\';
+ pwszPath[1] = '.';
+ pwszPath[2] = '\\';
+
+ pNtName->Buffer = pwszPath;
+ pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
+ *phRootDir = NULL;
+ return VINF_SUCCESS;
+ }
+
+ RTUtf16Free(pwszPath);
+ rc = VERR_FILENAME_TOO_LONG;
+ }
+ return rc;
+}
+
+
+/**
+ * Converts the path to UTF-16 and sets all the return values.
+ *
+ * @returns IPRT status code.
+ * @param pNtName Where to return the NT name.
+ * @param phRootDir Where to return the root handle, if applicable.
+ * @param pszPath The UTF-8 path.
+ */
+static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+{
+ PRTUTF16 pwszPath = NULL;
+ size_t cwcLen;
+ int rc = RTStrToUtf16Ex(pszPath, RTSTR_MAX, &pwszPath, 0, &cwcLen);
+ if (RT_SUCCESS(rc))
+ {
+ if (cwcLen < _32K - 1)
+ {
+ pNtName->Buffer = pwszPath;
+ pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
+ *phRootDir = NULL;
+ return VINF_SUCCESS;
+ }
+
+ RTUtf16Free(pwszPath);
+ rc = VERR_FILENAME_TOO_LONG;
+ }
+ return rc;
+}
+
+
+/**
+ * Converts a path to NT format and encoding.
+ *
+ * @returns IPRT status code.
+ * @param pNtName Where to return the NT name.
+ * @param phRootDir Where to return the root handle, if applicable.
+ * @param pszPath The UTF-8 path.
+ */
+static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+{
+ static char const s_szPrefixUnc[] = "\\??\\UNC\\";
+ static char const s_szPrefix[] = "\\??\\";
+
+ /*
+ * Very simple conversion of a win32-like path into an NT path.
+ */
+ const char *pszPrefix = s_szPrefix;
+ size_t cchPrefix = sizeof(s_szPrefix) - 1;
+ size_t cchSkip = 0;
+
+ if ( RTPATH_IS_SLASH(pszPath[0])
+ && RTPATH_IS_SLASH(pszPath[1])
+ && !RTPATH_IS_SLASH(pszPath[2])
+ && pszPath[2])
+ {
+ if ( pszPath[2] == '?'
+ && RTPATH_IS_SLASH(pszPath[3]))
+ return rtNtPathToNativePassThruWin(pNtName, phRootDir, pszPath);
+
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
+ if ( pszPath[2] == '!'
+ && RTPATH_IS_SLASH(pszPath[3]))
+ return rtNtPathToNativeToUtf16(pNtName, phRootDir, pszPath + 3);
+#endif
+
+ if ( pszPath[2] == '.'
+ && RTPATH_IS_SLASH(pszPath[3]))
+ {
+ /*
+ * Device path.
+ * Note! I suspect \\.\stuff\..\otherstuff may be handled differently by windows.
+ */
+ cchSkip = 4;
+ }
+ else
+ {
+ /* UNC */
+ pszPrefix = s_szPrefixUnc;
+ cchPrefix = sizeof(s_szPrefixUnc) - 1;
+ cchSkip = 2;
+ }
+ }
+
+ /*
+ * Straighten out all .. and uncessary . references and convert slashes.
+ */
+ char szPath[RTPATH_MAX];
+ int rc = RTPathAbs(pszPath, &szPath[cchPrefix - cchSkip], sizeof(szPath) - (cchPrefix - cchSkip));
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Add prefix and convert it to UTF16.
+ */
+ memcpy(szPath, pszPrefix, cchPrefix);
+ return rtNtPathToNativeToUtf16(pNtName, phRootDir, szPath);
+}
+
+
+/**
+ * Frees the native path and root handle.
+ *
+ * @param pNtName The NT path after a successful rtNtPathToNative
+ * call.
+ * @param phRootDir The root handle variable after a
+ * rtNtPathToNative.
+ */
+void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
+{
+ RTUtf16Free(pNtName->Buffer);
+ pNtName->Buffer = NULL;
+}
+
+
+/**
+ * Wrapper around NtCreateFile.
+ *
+ * @returns IPRT status code.
+ * @param pszPath The UTF-8 path.
+ * @param fDesiredAccess See NtCreateFile.
+ * @param fFileAttribs See NtCreateFile.
+ * @param fShareAccess See NtCreateFile.
+ * @param fCreateDisposition See NtCreateFile.
+ * @param fCreateOptions See NtCreateFile.
+ * @param fObjAttribs The OBJECT_ATTRIBUTES::Attributes value, see
+ * NtCreateFile and InitializeObjectAttributes.
+ * @param phHandle Where to return the handle.
+ * @param puAction Where to return the action taken. Optional.
+ */
+int rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
+ ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
+ PHANDLE phHandle, PULONG_PTR puAction)
+{
+ *phHandle = MY_INVALID_HANDLE_VALUE;
+
+ HANDLE hRootDir;
+ UNICODE_STRING NtName;
+ int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
+ if (RT_SUCCESS(rc))
+ {
+ HANDLE hFile = MY_INVALID_HANDLE_VALUE;
+ IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
+
+ NTSTATUS rcNt = NtCreateFile(&hFile,
+ fDesiredAccess,
+ &ObjAttr,
+ &Ios,
+ NULL /* AllocationSize*/,
+ fFileAttribs,
+ fShareAccess,
+ fCreateDisposition,
+ fCreateOptions,
+ NULL /*EaBuffer*/,
+ 0 /*EaLength*/);
+ if (NT_SUCCESS(rcNt))
+ {
+ if (puAction)
+ *puAction = Ios.Information;
+ *phHandle = hFile;
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+ rtNtPathFreeNative(&NtName, &hRootDir);
+ }
+ return rc;
+}
+
+
+/**
+ * Wrapper around NtCreateFile.
+ *
+ * @returns IPRT status code.
+ * @param pszPath The UTF-8 path.
+ * @param fDesiredAccess See NtCreateFile.
+ * @param fFileAttribs See NtCreateFile.
+ * @param fShareAccess See NtCreateFile.
+ * @param fCreateDisposition See NtCreateFile.
+ * @param fCreateOptions See NtCreateFile.
+ * @param fObjAttribs The OBJECT_ATTRIBUTES::Attributes value, see
+ * NtCreateFile and InitializeObjectAttributes.
+ * @param phHandle Where to return the handle.
+ * @param pfObjDir If not NULL, the variable pointed to will be set
+ * to @c true if we opened an object directory and
+ * @c false if we opened an directory file (normal
+ * directory).
+ */
+int rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
+ ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir)
+{
+ *phHandle = MY_INVALID_HANDLE_VALUE;
+
+ HANDLE hRootDir;
+ UNICODE_STRING NtName;
+ int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
+ if (RT_SUCCESS(rc))
+ {
+ HANDLE hFile = MY_INVALID_HANDLE_VALUE;
+ IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
+
+ NTSTATUS rcNt = NtCreateFile(&hFile,
+ fDesiredAccess,
+ &ObjAttr,
+ &Ios,
+ NULL /* AllocationSize*/,
+ FILE_ATTRIBUTE_NORMAL,
+ fShareAccess,
+ FILE_OPEN,
+ fCreateOptions,
+ NULL /*EaBuffer*/,
+ 0 /*EaLength*/);
+ if (NT_SUCCESS(rcNt))
+ {
+ if (pfObjDir)
+ *pfObjDir = false;
+ *phHandle = hFile;
+ rc = VINF_SUCCESS;
+ }
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ else if ( pfObjDir
+ && (rcNt == STATUS_OBJECT_NAME_INVALID || rcNt == STATUS_OBJECT_TYPE_MISMATCH)
+ && RTPATH_IS_SLASH(pszPath[0])
+ && RTPATH_IS_SLASH(pszPath[1])
+ && pszPath[2] == '!'
+ && RTPATH_IS_SLASH(pszPath[3]))
+ {
+ /* Strip trailing slash. */
+ if ( NtName.Length > 2
+ && RTPATH_IS_SLASH(NtName.Buffer[(NtName.Length / 2) - 1]))
+ NtName.Length -= 2;
+
+ /* Rought conversion of the access flags. */
+ ULONG fObjDesiredAccess = 0;
+ if (fDesiredAccess & (GENERIC_ALL | STANDARD_RIGHTS_ALL))
+ fObjDesiredAccess = DIRECTORY_ALL_ACCESS;
+ else
+ {
+ if (fDesiredAccess & (FILE_GENERIC_WRITE | GENERIC_WRITE | STANDARD_RIGHTS_WRITE))
+ fObjDesiredAccess |= DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_OBJECT;
+ if ( (fDesiredAccess & (FILE_LIST_DIRECTORY | FILE_GENERIC_READ | GENERIC_READ | STANDARD_RIGHTS_READ))
+ || !fObjDesiredAccess)
+ fObjDesiredAccess |= DIRECTORY_QUERY | FILE_LIST_DIRECTORY;
+ }
+
+ rcNt = NtOpenDirectoryObject(&hFile, fObjDesiredAccess, &ObjAttr);
+ if (NT_SUCCESS(rcNt))
+ {
+ *pfObjDir = true;
+ *phHandle = hFile;
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+ }
+#endif
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+ rtNtPathFreeNative(&NtName, &hRootDir);
+ }
+ return rc;
+}
+
+
+/**
+ * Closes an handled open by rtNtPathOpen.
+ *
+ * @returns IPRT status code
+ * @param hHandle The handle value.
+ */
+int rtNtPathClose(HANDLE hHandle)
+{
+ NTSTATUS rcNt = NtClose(hHandle);
+ if (NT_SUCCESS(rcNt))
+ return VINF_SUCCESS;
+ return RTErrConvertFromNtStatus(rcNt);
+}
+
diff --git a/src/VBox/Runtime/r3/os2/filelock-os2.cpp b/src/VBox/Runtime/r3/os2/filelock-os2.cpp
index 8646ecba..21839947 100644
--- a/src/VBox/Runtime/r3/os2/filelock-os2.cpp
+++ b/src/VBox/Runtime/r3/os2/filelock-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/os2/mp-os2.cpp b/src/VBox/Runtime/r3/os2/mp-os2.cpp
index 00260ca0..78e22a87 100644
--- a/src/VBox/Runtime/r3/os2/mp-os2.cpp
+++ b/src/VBox/Runtime/r3/os2/mp-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/os2/pipe-os2.cpp b/src/VBox/Runtime/r3/os2/pipe-os2.cpp
index 729f09b3..e5832c4e 100644
--- a/src/VBox/Runtime/r3/os2/pipe-os2.cpp
+++ b/src/VBox/Runtime/r3/os2/pipe-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,75 +28,1005 @@
/*******************************************************************************
* Header Files *
*******************************************************************************/
+#define INCL_ERRORS
+#define INCL_DOSSEMAPHORES
+#include <os2.h>
+
#include <iprt/pipe.h>
#include "internal/iprt.h"
+#include <iprt/asm.h>
#include <iprt/assert.h>
+#include <iprt/critsect.h>
#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/poll.h>
+#include <iprt/process.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+#include "internal/pipe.h"
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** The pipe buffer size we prefer. */
+#define RTPIPE_OS2_SIZE _32K
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+typedef struct RTPIPEINTERNAL
+{
+ /** Magic value (RTPIPE_MAGIC). */
+ uint32_t u32Magic;
+ /** The pipe handle. */
+ HPIPE hPipe;
+ /** Set if this is the read end, clear if it's the write end. */
+ bool fRead;
+ /** Whether the pipe is in blocking or non-blocking mode. */
+ bool fBlocking;
+ /** Set if the pipe is broken. */
+ bool fBrokenPipe;
+ /** Usage counter. */
+ uint32_t cUsers;
+
+ /** The event semaphore associated with the pipe. */
+ HEV hev;
+ /** The handle of the poll set currently polling on this pipe.
+ * We can only have one poller at the time (lazy bird). */
+ RTPOLLSET hPollSet;
+ /** Critical section protecting the above members.
+ * (Taking the lazy/simple approach.) */
+ RTCRITSECT CritSect;
+
+} RTPIPEINTERNAL;
+
+
+/**
+ * Ensures that the pipe has a semaphore associated with it.
+ *
+ * @returns VBox status code.
+ * @param pThis The pipe.
+ */
+static int rtPipeOs2EnsureSem(RTPIPEINTERNAL *pThis)
+{
+ if (pThis->hev != NULLHANDLE)
+ return VINF_SUCCESS;
+
+ HEV hev;
+ APIRET orc = DosCreateEventSem(NULL, &hev, DC_SEM_SHARED, FALSE);
+ if (orc == NO_ERROR)
+ {
+ orc = DosSetNPipeSem(pThis->hPipe, (HSEM)hev, 1);
+ if (orc == NO_ERROR)
+ {
+ pThis->hev = hev;
+ return VINF_SUCCESS;
+ }
+
+ DosCloseEventSem(hev);
+ }
+ return RTErrConvertFromOS2(orc);
+}
RTDECL(int) RTPipeCreate(PRTPIPE phPipeRead, PRTPIPE phPipeWrite, uint32_t fFlags)
{
- return VERR_NOT_IMPLEMENTED;
+ AssertPtrReturn(phPipeRead, VERR_INVALID_POINTER);
+ AssertPtrReturn(phPipeWrite, VERR_INVALID_POINTER);
+ AssertReturn(!(fFlags & ~RTPIPE_C_VALID_MASK), VERR_INVALID_PARAMETER);
+
+ /*
+ * Try create and connect a pipe pair.
+ */
+ APIRET orc;
+ HPIPE hPipeR;
+ HFILE hPipeW;
+ int rc;
+ for (;;)
+ {
+ static volatile uint32_t g_iNextPipe = 0;
+ char szName[128];
+ RTStrPrintf(szName, sizeof(szName), "\\pipe\\iprt-pipe-%u-%u", RTProcSelf(), ASMAtomicIncU32(&g_iNextPipe));
+
+ /*
+ * Create the read end of the pipe.
+ */
+ ULONG fPipeMode = 1 /*instance*/ | NP_TYPE_BYTE | NP_READMODE_BYTE | NP_NOWAIT;
+ ULONG fOpenMode = NP_ACCESS_DUPLEX | NP_WRITEBEHIND;
+ if (fFlags & RTPIPE_C_INHERIT_READ)
+ fOpenMode |= NP_INHERIT;
+ else
+ fOpenMode |= NP_NOINHERIT;
+ orc = DosCreateNPipe((PSZ)szName, &hPipeR, fOpenMode, fPipeMode, RTPIPE_OS2_SIZE, RTPIPE_OS2_SIZE, NP_DEFAULT_WAIT);
+ if (orc == NO_ERROR)
+ {
+ orc = DosConnectNPipe(hPipeR);
+ if (orc == ERROR_PIPE_NOT_CONNECTED || orc == NO_ERROR)
+ {
+ /*
+ * Connect to the pipe (the write end), attach sem below.
+ */
+ ULONG ulAction = 0;
+ ULONG fOpenW = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
+ ULONG fModeW = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_FAIL_ON_ERROR;
+ if (!(fFlags & RTPIPE_C_INHERIT_WRITE))
+ fModeW |= OPEN_FLAGS_NOINHERIT;
+ orc = DosOpen((PSZ)szName, &hPipeW, &ulAction, 0 /*cbFile*/, FILE_NORMAL,
+ fOpenW, fModeW, NULL /*peaop2*/);
+ if (orc == NO_ERROR)
+ break;
+ }
+ DosClose(hPipeR);
+ }
+ if ( orc != ERROR_PIPE_BUSY /* already exist - compatible */
+ && orc != ERROR_ACCESS_DENIED /* already exist - incompatible (?) */)
+ return RTErrConvertFromOS2(orc);
+ /* else: try again with a new name */
+ }
+
+ /*
+ * Create the two handles.
+ */
+ RTPIPEINTERNAL *pThisR = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
+ if (pThisR)
+ {
+ RTPIPEINTERNAL *pThisW = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
+ if (pThisW)
+ {
+ /* Crit sects. */
+ rc = RTCritSectInit(&pThisR->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCritSectInit(&pThisW->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ /* Initialize the structures. */
+ pThisR->u32Magic = RTPIPE_MAGIC;
+ pThisW->u32Magic = RTPIPE_MAGIC;
+ pThisR->hPipe = hPipeR;
+ pThisW->hPipe = hPipeW;
+ pThisR->hev = NULLHANDLE;
+ pThisW->hev = NULLHANDLE;
+ pThisR->fRead = true;
+ pThisW->fRead = false;
+ pThisR->fBlocking = false;
+ pThisW->fBlocking = true;
+ //pThisR->fBrokenPipe = false;
+ //pThisW->fBrokenPipe = false;
+ //pThisR->cUsers = 0;
+ //pThisW->cUsers = 0;
+ pThisR->hPollSet = NIL_RTPOLLSET;
+ pThisW->hPollSet = NIL_RTPOLLSET;
+
+ *phPipeRead = pThisR;
+ *phPipeWrite = pThisW;
+ return VINF_SUCCESS;
+ }
+
+ RTCritSectDelete(&pThisR->CritSect);
+ }
+ RTMemFree(pThisW);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ RTMemFree(pThisR);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ /* Don't call DosDisConnectNPipe! */
+ DosClose(hPipeW);
+ DosClose(hPipeR);
+ return rc;
}
RTDECL(int) RTPipeClose(RTPIPE hPipe)
{
- return VERR_NOT_IMPLEMENTED;
+ RTPIPEINTERNAL *pThis = hPipe;
+ if (pThis == NIL_RTPIPE)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+
+ /*
+ * Do the cleanup.
+ */
+ AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTPIPE_MAGIC, RTPIPE_MAGIC), VERR_INVALID_HANDLE);
+ RTCritSectEnter(&pThis->CritSect);
+ Assert(pThis->cUsers == 0);
+
+ /* Don't call DosDisConnectNPipe! */
+ DosClose(pThis->hPipe);
+ pThis->hPipe = (HPIPE)-1;
+
+ if (pThis->hev != NULLHANDLE)
+ {
+ DosCloseEventSem(pThis->hev);
+ pThis->hev = NULLHANDLE;
+ }
+
+ RTCritSectLeave(&pThis->CritSect);
+ RTCritSectDelete(&pThis->CritSect);
+
+ RTMemFree(pThis);
+
+ return VINF_SUCCESS;
}
RTDECL(int) RTPipeFromNative(PRTPIPE phPipe, RTHCINTPTR hNativePipe, uint32_t fFlags)
{
- return VERR_NOT_IMPLEMENTED;
-}
+ AssertPtrReturn(phPipe, VERR_INVALID_POINTER);
+ AssertReturn(!(fFlags & ~RTPIPE_N_VALID_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(!!(fFlags & RTPIPE_N_READ) != !!(fFlags & RTPIPE_N_WRITE), VERR_INVALID_PARAMETER);
+
+ /*
+ * Get and validate the pipe handle info.
+ */
+ HPIPE hNative = (HPIPE)hNativePipe;
+ ULONG ulType = 0;
+ ULONG ulAttr = 0;
+ APIRET orc = DosQueryHType(hNative, &ulType, &ulAttr);
+ AssertMsgReturn(orc == NO_ERROR, ("%d\n", orc), RTErrConvertFromOS2(orc));
+ AssertReturn((ulType & 0x7) == HANDTYPE_PIPE, VERR_INVALID_HANDLE);
+#if 0
+ union
+ {
+ PIPEINFO PipeInfo;
+ uint8_t abPadding[sizeof(PIPEINFO) + 127];
+ } Buf;
+ orc = DosQueryNPipeInfo(hNative, 1, &Buf, sizeof(Buf));
+ if (orc != NO_ERROR)
+ {
+ /* Sorry, anonymous pips are not supported. */
+ AssertMsgFailed(("%d\n", orc));
+ return VERR_INVALID_HANDLE;
+ }
+ AssertReturn(Buf.PipeInfo.cbMaxInst == 1, VERR_INVALID_HANDLE);
+#endif
+
+ ULONG fPipeState = 0;
+ orc = DosQueryNPHState(hNative, &fPipeState);
+ if (orc != NO_ERROR)
+ {
+ /* Sorry, anonymous pips are not supported. */
+ AssertMsgFailed(("%d\n", orc));
+ return VERR_INVALID_HANDLE;
+ }
+ AssertReturn(!(fPipeState & NP_TYPE_MESSAGE), VERR_INVALID_HANDLE);
+ AssertReturn(!(fPipeState & NP_READMODE_MESSAGE), VERR_INVALID_HANDLE);
+ AssertReturn((fPipeState & 0xff) == 1, VERR_INVALID_HANDLE);
+
+ ULONG fFileState = 0;
+ orc = DosQueryFHState(hNative, &fFileState);
+ AssertMsgReturn(orc == NO_ERROR, ("%d\n", orc), VERR_INVALID_HANDLE);
+ AssertMsgReturn( (fFileState & 0x3) == (fFlags & RTPIPE_N_READ ? OPEN_ACCESS_READONLY : OPEN_ACCESS_WRITEONLY)
+ || (fFileState & 0x3) == OPEN_ACCESS_READWRITE
+ , ("%#x\n", fFileState), VERR_INVALID_HANDLE);
+
+ /*
+ * Looks kind of OK. Fix the inherit flag.
+ */
+ orc = DosSetFHState(hNative, (fFileState & (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE))
+ | (fFlags & RTPIPE_N_INHERIT ? 0 : OPEN_FLAGS_NOINHERIT));
+ AssertMsgReturn(orc == NO_ERROR, ("%d\n", orc), RTErrConvertFromOS2(orc));
+
+
+ /*
+ * Create a handle so we can try rtPipeQueryInfo on it
+ * and see if we need to duplicate it to make that call work.
+ */
+ RTPIPEINTERNAL *pThis = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+ int rc = RTCritSectInit(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->u32Magic = RTPIPE_MAGIC;
+ pThis->hPipe = hNative;
+ pThis->hev = NULLHANDLE;
+ pThis->fRead = !!(fFlags & RTPIPE_N_READ);
+ pThis->fBlocking = !(fPipeState & NP_NOWAIT);
+ //pThis->fBrokenPipe = false;
+ //pThis->cUsers = 0;
+ pThis->hPollSet = NIL_RTPOLLSET;
+
+ *phPipe = pThis;
+ return VINF_SUCCESS;
+
+ //RTCritSectDelete(&pThis->CritSect);
+ }
+ RTMemFree(pThis);
+ return rc;
+}
RTDECL(RTHCINTPTR) RTPipeToNative(RTPIPE hPipe)
{
- return -1;
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, -1);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, -1);
+
+ return (RTHCINTPTR)pThis->hPipe;
+}
+
+/**
+ * Prepare blocking mode.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_WRONG_ORDER if simultaneous non-blocking and blocking access is
+ * attempted.
+ *
+ * @param pThis The pipe handle.
+ *
+ * @remarks Caller owns the critical section.
+ */
+static int rtPipeTryBlocking(RTPIPEINTERNAL *pThis)
+{
+ if (!pThis->fBlocking)
+ {
+ if (pThis->cUsers != 0)
+ return VERR_WRONG_ORDER;
+
+ APIRET orc = DosSetNPHState(pThis->hPipe, NP_WAIT | NP_READMODE_BYTE);
+ if (orc != NO_ERROR)
+ {
+ if (orc != ERROR_BROKEN_PIPE && orc != ERROR_PIPE_NOT_CONNECTED)
+ return RTErrConvertFromOS2(orc);
+ pThis->fBrokenPipe = true;
+ }
+ pThis->fBlocking = true;
+ }
+
+ pThis->cUsers++;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Prepare non-blocking mode.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_WRONG_ORDER if simultaneous non-blocking and blocking access is
+ * attempted.
+ *
+ * @param pThis The pipe handle.
+ */
+static int rtPipeTryNonBlocking(RTPIPEINTERNAL *pThis)
+{
+ if (pThis->fBlocking)
+ {
+ if (pThis->cUsers != 0)
+ return VERR_WRONG_ORDER;
+
+ APIRET orc = DosSetNPHState(pThis->hPipe, NP_NOWAIT | NP_READMODE_BYTE);
+ if (orc != NO_ERROR)
+ {
+ if (orc != ERROR_BROKEN_PIPE && orc != ERROR_PIPE_NOT_CONNECTED)
+ return RTErrConvertFromOS2(orc);
+ pThis->fBrokenPipe = true;
+ }
+ pThis->fBlocking = false;
+ }
+
+ pThis->cUsers++;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Checks if the read pipe has been broken.
+ *
+ * @returns true if broken, false if no.
+ * @param pThis The pipe handle (read).
+ */
+static bool rtPipeOs2IsBroken(RTPIPEINTERNAL *pThis)
+{
+ Assert(pThis->fRead);
+
+#if 0
+ /*
+ * Query it via the semaphore. Not sure how fast this is...
+ */
+ PIPESEMSTATE aStates[3]; RT_ZERO(aStates);
+ APIRET orc = DosQueryNPipeSemState(pThis->hev, &aStates[0], sizeof(aStates));
+ if (orc == NO_ERROR)
+ {
+ if (aStates[0].fStatus == NPSS_CLOSE)
+ return true;
+ if (aStates[0].fStatus == NPSS_RDATA)
+ return false;
+ }
+ AssertMsgFailed(("%d / %d\n", orc, aStates[0].fStatus));
+
+ /*
+ * Fall back / alternative method.
+ */
+#endif
+ ULONG cbActual = 0;
+ ULONG ulState = 0;
+ AVAILDATA Avail = { 0, 0 };
+ APIRET orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState);
+ if (orc != NO_ERROR)
+ {
+ if (orc != ERROR_PIPE_BUSY)
+ AssertMsgFailed(("%d\n", orc));
+ return false;
+ }
+
+ return ulState != NP_STATE_CONNECTED;
}
RTDECL(int) RTPipeRead(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
{
- return VERR_NOT_IMPLEMENTED;
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
+ AssertPtr(pcbRead);
+ AssertPtr(pvBuf);
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtPipeTryNonBlocking(pThis);
+ if (RT_SUCCESS(rc))
+ {
+ RTCritSectLeave(&pThis->CritSect);
+
+ ULONG cbActual = 0;
+ APIRET orc = DosRead(pThis->hPipe, pvBuf, cbToRead, &cbActual);
+ if (orc == NO_ERROR)
+ {
+ if (cbActual || !cbToRead || !rtPipeOs2IsBroken(pThis))
+ *pcbRead = cbActual;
+ else
+ rc = VERR_BROKEN_PIPE;
+ }
+ else if (orc == ERROR_NO_DATA)
+ {
+ *pcbRead = 0;
+ rc = VINF_TRY_AGAIN;
+ }
+ else
+ rc = RTErrConvertFromOS2(orc);
+
+ RTCritSectEnter(&pThis->CritSect);
+ if (rc == VERR_BROKEN_PIPE)
+ pThis->fBrokenPipe = true;
+ pThis->cUsers--;
+ }
+ else
+ rc = VERR_WRONG_ORDER;
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ return rc;
}
RTDECL(int) RTPipeReadBlocking(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
{
- return VERR_NOT_IMPLEMENTED;
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
+ AssertPtr(pvBuf);
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtPipeTryBlocking(pThis);
+ if (RT_SUCCESS(rc))
+ {
+ RTCritSectLeave(&pThis->CritSect);
+
+ size_t cbTotalRead = 0;
+ while (cbToRead > 0)
+ {
+ ULONG cbActual = 0;
+ APIRET orc = DosRead(pThis->hPipe, pvBuf, cbToRead, &cbActual);
+ if (orc != NO_ERROR)
+ {
+ rc = RTErrConvertFromOS2(orc);
+ break;
+ }
+ if (!cbActual && rtPipeOs2IsBroken(pThis))
+ {
+ rc = VERR_BROKEN_PIPE;
+ break;
+ }
+
+ /* advance */
+ pvBuf = (char *)pvBuf + cbActual;
+ cbTotalRead += cbActual;
+ cbToRead -= cbActual;
+ }
+
+ if (pcbRead)
+ {
+ *pcbRead = cbTotalRead;
+ if ( RT_FAILURE(rc)
+ && cbTotalRead)
+ rc = VINF_SUCCESS;
+ }
+
+ RTCritSectEnter(&pThis->CritSect);
+ if (rc == VERR_BROKEN_PIPE)
+ pThis->fBrokenPipe = true;
+ pThis->cUsers--;
+ }
+ else
+ rc = VERR_WRONG_ORDER;
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ return rc;
+}
+
+
+/**
+ * Gets the available write buffer size of the pipe.
+ *
+ * @returns Number of bytes, 1 on failure.
+ * @param pThis The pipe handle.
+ */
+static ULONG rtPipeOs2GetSpace(RTPIPEINTERNAL *pThis)
+{
+ Assert(!pThis->fRead);
+
+#if 0 /* Not sure which is more efficient, neither are really optimal, I fear. */
+ /*
+ * Query via semaphore state.
+ * This will walk the list of active named pipes...
+ */
+ /** @todo Check how hev and hpipe are associated, if complicated, use the
+ * alternative method below. */
+ PIPESEMSTATE aStates[3]; RT_ZERO(aStates);
+ APIRET orc = DosQueryNPipeSemState((HSEM)pThis->hev, &aStates[0], sizeof(aStates));
+ if (orc == NO_ERROR)
+ {
+ if (aStates[0].fStatus == NPSS_WSPACE)
+ return aStates[0].usAvail;
+ if (aStates[1].fStatus == NPSS_WSPACE)
+ return aStates[1].usAvail;
+ return 0;
+ }
+ AssertMsgFailed(("%d / %d\n", orc, aStates[0].fStatus));
+
+#else
+ /*
+ * Query via the pipe info.
+ * This will have to lookup and store the pipe name.
+ */
+ union
+ {
+ PIPEINFO PipeInfo;
+ uint8_t abPadding[sizeof(PIPEINFO) + 127];
+ } Buf;
+ APIRET orc = DosQueryNPipeInfo(pThis->hPipe, 1, &Buf, sizeof(Buf));
+ if (orc == NO_ERROR)
+ return Buf.PipeInfo.cbOut;
+ AssertMsgFailed(("%d\n", orc));
+#endif
+
+ return 1;
}
RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
{
- return VERR_NOT_IMPLEMENTED;
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
+ AssertPtr(pcbWritten);
+ AssertPtr(pvBuf);
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtPipeTryNonBlocking(pThis);
+ if (RT_SUCCESS(rc))
+ {
+ if (cbToWrite > 0)
+ {
+ ULONG cbActual = 0;
+ APIRET orc = DosWrite(pThis->hPipe, pvBuf, cbToWrite, &cbActual);
+ if (orc == NO_ERROR && cbActual == 0)
+ {
+ /* Retry with the request adjusted to the available buffer space. */
+ ULONG cbAvail = rtPipeOs2GetSpace(pThis);
+ orc = DosWrite(pThis->hPipe, pvBuf, RT_MIN(cbAvail, cbToWrite), &cbActual);
+ }
+
+ if (orc == NO_ERROR)
+ {
+ *pcbWritten = cbActual;
+ if (cbActual == 0)
+ rc = VINF_TRY_AGAIN;
+ }
+ else
+ {
+ rc = RTErrConvertFromOS2(orc);
+ if (rc == VERR_PIPE_NOT_CONNECTED)
+ rc = VERR_BROKEN_PIPE;
+ }
+ }
+ else
+ *pcbWritten = 0;
+
+ if (rc == VERR_BROKEN_PIPE)
+ pThis->fBrokenPipe = true;
+ pThis->cUsers--;
+ }
+ else
+ rc = VERR_WRONG_ORDER;
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ return rc;
}
RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
{
- return VERR_NOT_IMPLEMENTED;
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
+ AssertPtr(pvBuf);
+ AssertPtrNull(pcbWritten);
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtPipeTryBlocking(pThis);
+ if (RT_SUCCESS(rc))
+ {
+ RTCritSectLeave(&pThis->CritSect);
+
+ size_t cbTotalWritten = 0;
+ while (cbToWrite > 0)
+ {
+ ULONG cbActual = 0;
+ APIRET orc = DosWrite(pThis->hPipe, pvBuf, cbToWrite, &cbActual);
+ if (orc != NO_ERROR)
+ {
+ rc = RTErrConvertFromOS2(orc);
+ if (rc == VERR_PIPE_NOT_CONNECTED)
+ rc = VERR_BROKEN_PIPE;
+ break;
+ }
+ pvBuf = (char const *)pvBuf + cbActual;
+ cbToWrite -= cbActual;
+ cbTotalWritten += cbActual;
+ }
+
+ if (pcbWritten)
+ {
+ *pcbWritten = cbTotalWritten;
+ if ( RT_FAILURE(rc)
+ && cbTotalWritten)
+ rc = VINF_SUCCESS;
+ }
+
+ RTCritSectEnter(&pThis->CritSect);
+ if (rc == VERR_BROKEN_PIPE)
+ pThis->fBrokenPipe = true;
+ pThis->cUsers--;
+ }
+ else
+ rc = VERR_WRONG_ORDER;
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ return rc;
}
RTDECL(int) RTPipeFlush(RTPIPE hPipe)
{
- return VERR_NOT_IMPLEMENTED;
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
+
+ APIRET orc = DosResetBuffer(pThis->hPipe);
+ if (orc != NO_ERROR)
+ {
+ int rc = RTErrConvertFromOS2(orc);
+ if (rc == VERR_BROKEN_PIPE)
+ {
+ RTCritSectEnter(&pThis->CritSect);
+ pThis->fBrokenPipe = true;
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ return rc;
+ }
+ return VINF_SUCCESS;
}
RTDECL(int) RTPipeSelectOne(RTPIPE hPipe, RTMSINTERVAL cMillies)
{
- return VERR_NOT_IMPLEMENTED;
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+
+ uint64_t const StartMsTS = RTTimeMilliTS();
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ rc = rtPipeOs2EnsureSem(pThis);
+ if (RT_SUCCESS(rc) && cMillies > 0)
+ {
+ /* Stop polling attempts if we might block. */
+ if (pThis->hPollSet == NIL_RTPOLLSET)
+ pThis->hPollSet = (RTPOLLSET)(uintptr_t)0xbeef0042;
+ else
+ rc = VERR_WRONG_ORDER;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ for (unsigned iLoop = 0;; iLoop++)
+ {
+ /*
+ * Check the handle state.
+ */
+ APIRET orc;
+ if (cMillies > 0)
+ {
+ ULONG ulIgnore;
+ orc = DosResetEventSem(pThis->hev, &ulIgnore);
+ AssertMsg(orc == NO_ERROR || orc == ERROR_ALREADY_RESET, ("%d\n", orc));
+ }
+
+ PIPESEMSTATE aStates[4]; RT_ZERO(aStates);
+ orc = DosQueryNPipeSemState((HSEM)pThis->hev, &aStates[0], sizeof(aStates));
+ if (orc != NO_ERROR)
+ {
+ rc = RTErrConvertFromOS2(orc);
+ break;
+ }
+ int i = 0;
+ if (pThis->fRead)
+ while (aStates[i].fStatus == NPSS_WSPACE)
+ i++;
+ else
+ while (aStates[i].fStatus == NPSS_RDATA)
+ i++;
+ if (aStates[i].fStatus == NPSS_CLOSE)
+ break;
+ Assert(aStates[i].fStatus == NPSS_WSPACE || aStates[i].fStatus == NPSS_RDATA || aStates[i].fStatus == NPSS_EOI);
+ if ( aStates[i].fStatus != NPSS_EOI
+ && aStates[i].usAvail > 0)
+ break;
+
+ /*
+ * Check for timeout.
+ */
+ ULONG cMsMaxWait = SEM_INDEFINITE_WAIT;
+ if (cMillies != RT_INDEFINITE_WAIT)
+ {
+ uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
+ if (cElapsed >= cMillies)
+ {
+ rc = VERR_TIMEOUT;
+ break;
+ }
+ cMsMaxWait = cMillies - (uint32_t)cElapsed;
+ }
+
+ /*
+ * Wait.
+ */
+ RTCritSectLeave(&pThis->CritSect);
+ orc = DosWaitEventSem(pThis->hev, cMsMaxWait);
+ RTCritSectEnter(&pThis->CritSect);
+ if (orc != NO_ERROR && orc != ERROR_TIMEOUT && orc != ERROR_SEM_TIMEOUT )
+ {
+ rc = RTErrConvertFromOS2(orc);
+ break;
+ }
+ }
+
+ if (rc == VERR_BROKEN_PIPE)
+ pThis->fBrokenPipe = true;
+ if (cMillies > 0)
+ pThis->hPollSet = NIL_RTPOLLSET;
+ }
+
+ RTCritSectLeave(&pThis->CritSect);
+ return rc;
}
RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable)
{
- return VERR_NOT_IMPLEMENTED;
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->fRead, VERR_PIPE_NOT_READ);
+ AssertPtrReturn(pcbReadable, VERR_INVALID_POINTER);
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ ULONG cbActual = 0;
+ ULONG ulState = 0;
+ AVAILDATA Avail = { 0, 0 };
+ APIRET orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState);
+ if (orc == NO_ERROR)
+ {
+ if (Avail.cbpipe > 0 || ulState == NP_STATE_CONNECTED)
+ *pcbReadable = Avail.cbpipe;
+ else
+ rc = VERR_PIPE_NOT_CONNECTED; /*??*/
+ }
+ else
+ rc = RTErrConvertFromOS2(orc);
+
+ RTCritSectLeave(&pThis->CritSect);
+ return rc;
}
+
+int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative)
+{
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+
+ AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER);
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtPipeOs2EnsureSem(pThis);
+ if (RT_SUCCESS(rc))
+ *phNative = (RTHCINTPTR)pThis->hev;
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ return rc;
+}
+
+
+/**
+ * Checks for pending events.
+ *
+ * @returns Event mask or 0.
+ * @param pThis The pipe handle.
+ * @param fEvents The desired events.
+ * @param fResetEvtSem Whether to reset the event semaphore.
+ */
+static uint32_t rtPipePollCheck(RTPIPEINTERNAL *pThis, uint32_t fEvents, bool fResetEvtSem)
+{
+ /*
+ * Reset the event semaphore if we're gonna wait.
+ */
+ APIRET orc;
+ ULONG ulIgnore;
+ if (fResetEvtSem)
+ {
+ orc = DosResetEventSem(pThis->hev, &ulIgnore);
+ AssertMsg(orc == NO_ERROR || orc == ERROR_ALREADY_RESET, ("%d\n", orc));
+ }
+
+ /*
+ * Check for events.
+ */
+ uint32_t fRetEvents = 0;
+ if (pThis->fBrokenPipe)
+ fRetEvents |= RTPOLL_EVT_ERROR;
+ else if (pThis->fRead)
+ {
+ ULONG cbActual = 0;
+ ULONG ulState = 0;
+ AVAILDATA Avail = { 0, 0 };
+ orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState);
+ if (orc != NO_ERROR)
+ {
+ fRetEvents |= RTPOLL_EVT_ERROR;
+ if (orc == ERROR_BROKEN_PIPE || orc == ERROR_PIPE_NOT_CONNECTED)
+ pThis->fBrokenPipe = true;
+ }
+ else if (Avail.cbpipe > 0)
+ fRetEvents |= RTPOLL_EVT_READ;
+ else if (ulState != NP_STATE_CONNECTED)
+ {
+ fRetEvents |= RTPOLL_EVT_ERROR;
+ pThis->fBrokenPipe = true;
+ }
+ }
+ else
+ {
+ PIPESEMSTATE aStates[4]; RT_ZERO(aStates);
+ orc = DosQueryNPipeSemState((HSEM)pThis->hev, &aStates[0], sizeof(aStates));
+ if (orc == NO_ERROR)
+ {
+ int i = 0;
+ while (aStates[i].fStatus == NPSS_RDATA)
+ i++;
+ if (aStates[i].fStatus == NPSS_CLOSE)
+ {
+ fRetEvents |= RTPOLL_EVT_ERROR;
+ pThis->fBrokenPipe = true;
+ }
+ else if ( aStates[i].fStatus == NPSS_WSPACE
+ && aStates[i].usAvail > 0)
+ fRetEvents |= RTPOLL_EVT_WRITE;
+ }
+ else
+ {
+ fRetEvents |= RTPOLL_EVT_ERROR;
+ if (orc == ERROR_BROKEN_PIPE || orc == ERROR_PIPE_NOT_CONNECTED)
+ pThis->fBrokenPipe = true;
+ }
+ }
+
+ return fRetEvents & (fEvents | RTPOLL_EVT_ERROR);
+}
+
+
+uint32_t rtPipePollStart(RTPIPE hPipe, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
+{
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, UINT32_MAX);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, UINT32_MAX);
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ AssertRCReturn(rc, UINT32_MAX);
+
+ /* Check that this is the only current use of this pipe. */
+ uint32_t fRetEvents;
+ if ( pThis->cUsers == 0
+ || pThis->hPollSet == NIL_RTPOLLSET)
+ {
+ fRetEvents = rtPipePollCheck(pThis, fEvents, fNoWait);
+ if (!fRetEvents && !fNoWait)
+ {
+ /* Mark the set busy while waiting. */
+ pThis->cUsers++;
+ pThis->hPollSet = hPollSet;
+ }
+ }
+ else
+ {
+ AssertFailed();
+ fRetEvents = UINT32_MAX;
+ }
+
+ RTCritSectLeave(&pThis->CritSect);
+ return fRetEvents;
+}
+
+
+uint32_t rtPipePollDone(RTPIPE hPipe, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents)
+{
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, 0);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0);
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ AssertRCReturn(rc, 0);
+
+ Assert(pThis->cUsers > 0);
+
+ /* harvest events. */
+ uint32_t fRetEvents = rtPipePollCheck(pThis, fEvents, false);
+
+ /* update counters. */
+ pThis->cUsers--;
+ pThis->hPollSet = NIL_RTPOLLSET;
+
+ RTCritSectLeave(&pThis->CritSect);
+ return fRetEvents;
+}
diff --git a/src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp b/src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp
index 26ee5b49..3ee59bfc 100644
--- a/src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp
+++ b/src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/os2/sched-os2.cpp b/src/VBox/Runtime/r3/os2/sched-os2.cpp
index 02a4bbd3..d6e5bce7 100644
--- a/src/VBox/Runtime/r3/os2/sched-os2.cpp
+++ b/src/VBox/Runtime/r3/os2/sched-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/os2/sems-os2.cpp b/src/VBox/Runtime/r3/os2/sems-os2.cpp
index d19a3246..a7ca3097 100644
--- a/src/VBox/Runtime/r3/os2/sems-os2.cpp
+++ b/src/VBox/Runtime/r3/os2/sems-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/os2/systemmem-os2.cpp b/src/VBox/Runtime/r3/os2/systemmem-os2.cpp
new file mode 100644
index 00000000..0f95ab24
--- /dev/null
+++ b/src/VBox/Runtime/r3/os2/systemmem-os2.cpp
@@ -0,0 +1,70 @@
+/* $Id: systemmem-os2.cpp $ */
+/** @file
+ * IPRT - RTSystemQueryTotalRam, OS/2 ring-3.
+ */
+
+/*
+ * Copyright (C) 2010-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define INCL_DOSMISC
+#define INCL_ERRORS
+#include <os2.h>
+#undef RT_MAX
+
+#include <iprt/system.h>
+#include "internal/iprt.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTSystemQueryTotalRam(uint64_t *pcb)
+{
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+
+ ULONG cbMem;
+ APIRET rc = DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, &cbMem, sizeof(cbMem));
+ if (rc != NO_ERROR)
+ return RTErrConvertFromOS2(rc);
+
+ *pcb = cbMem;
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb)
+{
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+
+ ULONG cbAvailMem;
+ APIRET rc = DosQuerySysInfo(QSV_TOTAVAILMEM, QSV_TOTAVAILMEM, &cbAvailMem, sizeof(cbAvailMem));
+ if (rc != NO_ERROR)
+ return RTErrConvertFromOS2(rc);
+
+ *pcb = cbAvailMem;
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/r3/os2/thread-os2.cpp b/src/VBox/Runtime/r3/os2/thread-os2.cpp
index e2efa01f..e6f20213 100644
--- a/src/VBox/Runtime/r3/os2/thread-os2.cpp
+++ b/src/VBox/Runtime/r3/os2/thread-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -78,7 +78,7 @@ DECLHIDDEN(int) rtThreadNativeInit(void)
}
-DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
+static void rtThreadOs2BlockSigAlarm(void)
{
/*
* Block SIGALRM - required for timer-posix.cpp.
@@ -89,6 +89,17 @@ DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
sigemptyset(&SigSet);
sigaddset(&SigSet, SIGALRM);
sigprocmask(SIG_BLOCK, &SigSet, NULL);
+}
+
+
+DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void)
+{
+ rtThreadOs2BlockSigAlarm();
+}
+
+
+DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
+{
*g_ppCurThread = pThread;
return VINF_SUCCESS;
@@ -107,15 +118,7 @@ DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread)
*/
static void rtThreadNativeMain(void *pvArgs)
{
- /*
- * Block SIGALRM - required for timer-posix.cpp.
- * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
- * It will not help much if someone creates threads directly using pthread_create. :/
- */
- sigset_t SigSet;
- sigemptyset(&SigSet);
- sigaddset(&SigSet, SIGALRM);
- sigprocmask(SIG_BLOCK, &SigSet, NULL);
+ rtThreadOs2BlockSigAlarm();
/*
* Call common main.
diff --git a/src/VBox/Runtime/r3/path.cpp b/src/VBox/Runtime/r3/path.cpp
index 591f0556..e43f5d95 100644
--- a/src/VBox/Runtime/r3/path.cpp
+++ b/src/VBox/Runtime/r3/path.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/poll.cpp b/src/VBox/Runtime/r3/poll.cpp
new file mode 100644
index 00000000..ea71cb43
--- /dev/null
+++ b/src/VBox/Runtime/r3/poll.cpp
@@ -0,0 +1,1109 @@
+/* $Id: poll.cpp $ */
+/** @file
+ * IPRT - Polling I/O Handles, Windows+Posix Implementation.
+ */
+
+/*
+ * Copyright (C) 2010-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/cdefs.h>
+#ifdef RT_OS_WINDOWS
+# include <Windows.h>
+
+#elif defined(RT_OS_OS2)
+# define INCL_BASE
+# include <os2.h>
+# include <limits.h>
+# include <sys/socket.h>
+
+#else
+# include <limits.h>
+# include <errno.h>
+# include <sys/poll.h>
+#endif
+
+#include <iprt/poll.h>
+#include "internal/iprt.h"
+
+#include <iprt/alloca.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/pipe.h>
+#include <iprt/socket.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+#include "internal/pipe.h"
+#define IPRT_INTERNAL_SOCKET_POLLING_ONLY
+#include "internal/socket.h"
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** The maximum poll set size.
+ * @remarks To help portability, we set this to the Windows limit. We can lift
+ * this restriction later if it becomes necessary. */
+#define RTPOLL_SET_MAX 64
+
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Handle entry in a poll set.
+ */
+typedef struct RTPOLLSETHNDENT
+{
+ /** The handle type. */
+ RTHANDLETYPE enmType;
+ /** The handle ID. */
+ uint32_t id;
+ /** The events we're waiting for here. */
+ uint32_t fEvents;
+ /** Set if this is the final entry for this handle.
+ * If the handle is entered more than once, this will be clear for all but
+ * the last entry. */
+ bool fFinalEntry;
+ /** The handle union. */
+ RTHANDLEUNION u;
+} RTPOLLSETHNDENT;
+/** Pointer to a handle entry. */
+typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT;
+
+
+/**
+ * Poll set data.
+ */
+typedef struct RTPOLLSETINTERNAL
+{
+ /** The magic value (RTPOLLSET_MAGIC). */
+ uint32_t u32Magic;
+ /** Set when someone is polling or making changes. */
+ bool volatile fBusy;
+
+ /** The number of allocated handles. */
+ uint16_t cHandlesAllocated;
+ /** The number of valid handles in the set. */
+ uint16_t cHandles;
+
+#ifdef RT_OS_WINDOWS
+ /** Pointer to an array of native handles. */
+ HANDLE *pahNative;
+#elif defined(RT_OS_OS2)
+ /** The semaphore records. */
+ PSEMRECORD paSemRecs;
+ /** The multiple wait semaphore used for non-socket waits. */
+ HMUX hmux;
+ /** os2_select template. */
+ int *pafdSelect;
+ /** The number of sockets to monitor for read. */
+ uint16_t cReadSockets;
+ /** The number of sockets to monitor for write. */
+ uint16_t cWriteSockets;
+ /** The number of sockets to monitor for exceptions. */
+ uint16_t cXcptSockets;
+ /** The number of pipes. */
+ uint16_t cPipes;
+ /** Pointer to an array of native handles. */
+ PRTHCINTPTR pahNative;
+#else
+ /** Pointer to an array of pollfd structures. */
+ struct pollfd *paPollFds;
+#endif
+ /** Pointer to an array of handles and IDs. */
+ PRTPOLLSETHNDENT paHandles;
+} RTPOLLSETINTERNAL;
+
+
+
+/**
+ * Common worker for RTPoll and RTPollNoResume
+ */
+static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, uint64_t MsStart, RTMSINTERVAL cMillies,
+ uint32_t *pfEvents, uint32_t *pid)
+{
+ int rc;
+
+ if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT))
+ return VERR_DEADLOCK;
+
+ /*
+ * Check for special case, RTThreadSleep...
+ */
+ uint32_t const cHandles = pThis->cHandles;
+ if (cHandles == 0)
+ {
+ rc = RTThreadSleep(cMillies);
+ if (RT_SUCCESS(rc))
+ rc = VERR_TIMEOUT;
+ return rc;
+ }
+
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ /*
+ * Check + prepare the handles before waiting.
+ */
+ uint32_t fEvents = 0;
+ bool const fNoWait = cMillies == 0;
+ uint32_t i;
+ for (i = 0; i < cHandles; i++)
+ {
+ switch (pThis->paHandles[i].enmType)
+ {
+ case RTHANDLETYPE_PIPE:
+ fEvents = rtPipePollStart(pThis->paHandles[i].u.hPipe, pThis, pThis->paHandles[i].fEvents,
+ pThis->paHandles[i].fFinalEntry, fNoWait);
+ break;
+
+ case RTHANDLETYPE_SOCKET:
+ fEvents = rtSocketPollStart(pThis->paHandles[i].u.hSocket, pThis, pThis->paHandles[i].fEvents,
+ pThis->paHandles[i].fFinalEntry, fNoWait);
+ break;
+
+ default:
+ AssertFailed();
+ fEvents = UINT32_MAX;
+ break;
+ }
+ if (fEvents)
+ break;
+ }
+ if ( fEvents
+ || fNoWait)
+ {
+
+ if (pid)
+ *pid = pThis->paHandles[i].id;
+ if (pfEvents)
+ *pfEvents = fEvents;
+ rc = !fEvents
+ ? VERR_TIMEOUT
+ : fEvents != UINT32_MAX
+ ? VINF_SUCCESS
+ : VERR_INTERNAL_ERROR_4;
+
+ /* clean up */
+ if (!fNoWait)
+ while (i-- > 0)
+ {
+ switch (pThis->paHandles[i].enmType)
+ {
+ case RTHANDLETYPE_PIPE:
+ rtPipePollDone(pThis->paHandles[i].u.hPipe, pThis->paHandles[i].fEvents,
+ pThis->paHandles[i].fFinalEntry, false);
+ break;
+
+ case RTHANDLETYPE_SOCKET:
+ rtSocketPollDone(pThis->paHandles[i].u.hSocket, pThis->paHandles[i].fEvents,
+ pThis->paHandles[i].fFinalEntry, false);
+ break;
+
+ default:
+ AssertFailed();
+ break;
+ }
+ }
+
+ return rc;
+ }
+
+
+ /*
+ * Wait.
+ */
+# ifdef RT_OS_WINDOWS
+ DWORD dwRc = WaitForMultipleObjectsEx(cHandles, pThis->pahNative,
+ FALSE /*fWaitAll */,
+ cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies,
+ TRUE /*fAlertable*/);
+ if ( dwRc >= WAIT_OBJECT_0
+ && dwRc < WAIT_OBJECT_0 + cHandles)
+ rc = VERR_INTERRUPTED;
+ else if (dwRc == WAIT_TIMEOUT)
+ rc = VERR_TIMEOUT;
+ else if (dwRc == WAIT_IO_COMPLETION)
+ rc = VERR_INTERRUPTED;
+ else if (dwRc == WAIT_FAILED)
+ rc = RTErrConvertFromWin32(GetLastError());
+ else
+ {
+ AssertMsgFailed(("%u (%#x)\n", dwRc, dwRc));
+ rc = VERR_INTERNAL_ERROR_5;
+ }
+
+# else /* RT_OS_OS2 */
+ APIRET orc;
+ ULONG ulUser = 0;
+ uint16_t cSockets = pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets;
+ if (cSockets == 0)
+ {
+ /* Only pipes. */
+ AssertReturn(pThis->cPipes > 0, VERR_INTERNAL_ERROR_2);
+ orc = DosWaitMuxWaitSem(pThis->hmux,
+ cMillies == RT_INDEFINITE_WAIT ? SEM_INDEFINITE_WAIT : RT_MIN(cMillies, SEM_INDEFINITE_WAIT - 1),
+ &ulUser);
+ rc = RTErrConvertFromOS2(orc);
+ }
+ else
+ {
+ int *pafdSelect = (int *)alloca(cSockets + 1);
+ if (pThis->cPipes == 0)
+ {
+ /* Only sockets. */
+ memcpy(pafdSelect, pThis->pafdSelect, sizeof(pThis->pafdSelect[0]) * (cSockets + 1));
+ rc = os2_select(pafdSelect, pThis->cReadSockets, pThis->cWriteSockets, pThis->cXcptSockets,
+ cMillies == RT_INDEFINITE_WAIT ? -1 : (long)RT_MIN(cMillies, LONG_MAX));
+ if (rc > 0)
+ rc = VINF_SUCCESS;
+ else if (rc == 0)
+ rc = VERR_TIMEOUT;
+ else
+ rc = RTErrConvertFromErrno(sock_errno());
+ }
+ else
+ {
+ /* Mix of both - taking the easy way out, not optimal, but whatever... */
+ do
+ {
+ orc = DosWaitMuxWaitSem(pThis->hmux, 8, &ulUser);
+ if (orc != ERROR_TIMEOUT && orc != ERROR_SEM_TIMEOUT)
+ {
+ rc = RTErrConvertFromOS2(orc);
+ break;
+ }
+
+ memcpy(pafdSelect, pThis->pafdSelect, sizeof(pThis->pafdSelect[0]) * (cSockets + 1));
+ rc = os2_select(pafdSelect, pThis->cReadSockets, pThis->cWriteSockets, pThis->cXcptSockets, 8);
+ if (rc != 0)
+ {
+ if (rc > 0)
+ rc = VINF_SUCCESS;
+ else
+ rc = RTErrConvertFromErrno(sock_errno());
+ break;
+ }
+ } while (cMillies == RT_INDEFINITE_WAIT || RTTimeMilliTS() - MsStart < cMillies);
+ }
+ }
+# endif /* RT_OS_OS2 */
+
+ /*
+ * Get event (if pending) and do wait cleanup.
+ */
+ bool fHarvestEvents = true;
+ for (i = 0; i < cHandles; i++)
+ {
+ fEvents = 0;
+ switch (pThis->paHandles[i].enmType)
+ {
+ case RTHANDLETYPE_PIPE:
+ fEvents = rtPipePollDone(pThis->paHandles[i].u.hPipe, pThis->paHandles[i].fEvents,
+ pThis->paHandles[i].fFinalEntry, fHarvestEvents);
+ break;
+
+ case RTHANDLETYPE_SOCKET:
+ fEvents = rtSocketPollDone(pThis->paHandles[i].u.hSocket, pThis->paHandles[i].fEvents,
+ pThis->paHandles[i].fFinalEntry, fHarvestEvents);
+ break;
+
+ default:
+ AssertFailed();
+ break;
+ }
+ if ( fEvents
+ && fHarvestEvents)
+ {
+ Assert(fEvents != UINT32_MAX);
+ fHarvestEvents = false;
+ if (pfEvents)
+ *pfEvents = fEvents;
+ if (pid)
+ *pid = pThis->paHandles[i].id;
+ rc = VINF_SUCCESS;
+ }
+ }
+
+#else /* POSIX */
+
+ /* clear the revents. */
+ uint32_t i = pThis->cHandles;
+ while (i-- > 0)
+ pThis->paPollFds[i].revents = 0;
+
+ rc = poll(&pThis->paPollFds[0], pThis->cHandles,
+ cMillies == RT_INDEFINITE_WAIT || cMillies >= INT_MAX
+ ? -1
+ : (int)cMillies);
+ if (rc == 0)
+ return VERR_TIMEOUT;
+ if (rc < 0)
+ return RTErrConvertFromErrno(errno);
+ for (i = 0; i < pThis->cHandles; i++)
+ if (pThis->paPollFds[i].revents)
+ {
+ if (pfEvents)
+ {
+ *pfEvents = 0;
+ if (pThis->paPollFds[i].revents & (POLLIN
+# ifdef POLLRDNORM
+ | POLLRDNORM /* just in case */
+# endif
+# ifdef POLLRDBAND
+ | POLLRDBAND /* ditto */
+# endif
+# ifdef POLLPRI
+ | POLLPRI /* ditto */
+# endif
+# ifdef POLLMSG
+ | POLLMSG /* ditto */
+# endif
+# ifdef POLLWRITE
+ | POLLWRITE /* ditto */
+# endif
+# ifdef POLLEXTEND
+ | POLLEXTEND /* ditto */
+# endif
+ )
+ )
+ *pfEvents |= RTPOLL_EVT_READ;
+
+ if (pThis->paPollFds[i].revents & (POLLOUT
+# ifdef POLLWRNORM
+ | POLLWRNORM /* just in case */
+# endif
+# ifdef POLLWRBAND
+ | POLLWRBAND /* ditto */
+# endif
+ )
+ )
+ *pfEvents |= RTPOLL_EVT_WRITE;
+
+ if (pThis->paPollFds[i].revents & (POLLERR | POLLHUP | POLLNVAL
+# ifdef POLLRDHUP
+ | POLLRDHUP
+# endif
+ )
+ )
+ *pfEvents |= RTPOLL_EVT_ERROR;
+ }
+ if (pid)
+ *pid = pThis->paHandles[i].id;
+ return VINF_SUCCESS;
+ }
+
+ AssertFailed();
+ RTThreadYield();
+ rc = VERR_INTERRUPTED;
+
+#endif /* POSIX */
+
+ return rc;
+}
+
+
+RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
+{
+ RTPOLLSETINTERNAL *pThis = hPollSet;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtrNull(pfEvents);
+ AssertPtrNull(pid);
+
+ /*
+ * Set the busy flag and do the job.
+ */
+ AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
+
+ int rc;
+ if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0)
+ {
+ do rc = rtPollNoResumeWorker(pThis, 0, cMillies, pfEvents, pid);
+ while (rc == VERR_INTERRUPTED);
+ }
+ else
+ {
+ uint64_t MsStart = RTTimeMilliTS();
+ rc = rtPollNoResumeWorker(pThis, MsStart, cMillies, pfEvents, pid);
+ while (RT_UNLIKELY(rc == VERR_INTERRUPTED))
+ {
+ if (RTTimeMilliTS() - MsStart >= cMillies)
+ {
+ rc = VERR_TIMEOUT;
+ break;
+ }
+ rc = rtPollNoResumeWorker(pThis, MsStart, cMillies, pfEvents, pid);
+ }
+ }
+
+ ASMAtomicWriteBool(&pThis->fBusy, false);
+
+ return rc;
+}
+
+
+RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
+{
+ RTPOLLSETINTERNAL *pThis = hPollSet;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtrNull(pfEvents);
+ AssertPtrNull(pid);
+
+ /*
+ * Set the busy flag and do the job.
+ */
+ AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
+
+ int rc;
+ if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0)
+ rc = rtPollNoResumeWorker(pThis, 0, cMillies, pfEvents, pid);
+ else
+ rc = rtPollNoResumeWorker(pThis, RTTimeMilliTS(), cMillies, pfEvents, pid);
+
+ ASMAtomicWriteBool(&pThis->fBusy, false);
+
+ return rc;
+}
+
+
+RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet)
+{
+ AssertPtrReturn(phPollSet, VERR_INVALID_POINTER);
+ RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAlloc(sizeof(RTPOLLSETINTERNAL));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ pThis->fBusy = false;
+ pThis->cHandles = 0;
+ pThis->cHandlesAllocated = 0;
+#ifdef RT_OS_WINDOWS
+ pThis->pahNative = NULL;
+#elif defined(RT_OS_OS2)
+ pThis->hmux = NULLHANDLE;
+ APIRET orc = DosCreateMuxWaitSem(NULL, &pThis->hmux, 0, NULL, DCMW_WAIT_ANY);
+ if (orc != NO_ERROR)
+ {
+ RTMemFree(pThis);
+ return RTErrConvertFromOS2(orc);
+ }
+ pThis->pafdSelect = NULL;
+ pThis->cReadSockets = 0;
+ pThis->cWriteSockets = 0;
+ pThis->cXcptSockets = 0;
+ pThis->cPipes = 0;
+ pThis->pahNative = NULL;
+#else
+ pThis->paPollFds = NULL;
+#endif
+ pThis->paHandles = NULL;
+ pThis->u32Magic = RTPOLLSET_MAGIC;
+
+ *phPollSet = pThis;
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet)
+{
+ RTPOLLSETINTERNAL *pThis = hPollSet;
+ if (pThis == NIL_RTPOLLSET)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
+
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC);
+#ifdef RT_OS_WINDOWS
+ RTMemFree(pThis->pahNative);
+ pThis->pahNative = NULL;
+#elif defined(RT_OS_OS2)
+ DosCloseMuxWaitSem(pThis->hmux);
+ pThis->hmux = NULLHANDLE;
+ RTMemFree(pThis->pafdSelect);
+ pThis->pafdSelect = NULL;
+ RTMemFree(pThis->pahNative);
+ pThis->pahNative = NULL;
+#else
+ RTMemFree(pThis->paPollFds);
+ pThis->paPollFds = NULL;
+#endif
+ RTMemFree(pThis->paHandles);
+ pThis->paHandles = NULL;
+ RTMemFree(pThis);
+
+ return VINF_SUCCESS;
+}
+
+#ifdef RT_OS_OS2
+
+/**
+ * Checks if @a fd is in the specific socket subset.
+ *
+ * @returns true / false.
+ * @param pThis The poll set instance.
+ * @param iStart The index to start at.
+ * @param cFds The number of sockets to check.
+ * @param fd The socket to look for.
+ */
+static bool rtPollSetOs2IsSocketInSet(RTPOLLSETINTERNAL *pThis, uint16_t iStart, uint16_t cFds, int fd)
+{
+ int const *pfd = pThis->pafdSelect + iStart;
+ while (cFds-- > 0)
+ {
+ if (*pfd == fd)
+ return true;
+ pfd++;
+ }
+ return false;
+}
+
+
+/**
+ * Removes a socket from a select template subset.
+ *
+ * @param pThis The poll set instance.
+ * @param iStart The index to start at.
+ * @param pcSubSet The subset counter to decrement.
+ * @param fd The socket to remove.
+ */
+static void rtPollSetOs2RemoveSocket(RTPOLLSETINTERNAL *pThis, uint16_t iStart, uint16_t *pcFds, int fd)
+{
+ uint16_t cFds = *pcFds;
+ while (cFds-- > 0)
+ {
+ if (pThis->pafdSelect[iStart] == fd)
+ break;
+ iStart++;
+ }
+ AssertReturnVoid(iStart != UINT16_MAX);
+
+ /* Note! We keep a -1 entry at the end of the set, thus the + 1. */
+ memmove(&pThis->pafdSelect[iStart],
+ &pThis->pafdSelect[iStart + 1],
+ pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets + 1 - 1 - iStart);
+ *pcFds -= 1;
+
+ Assert(pThis->pafdSelect[pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets] == -1);
+}
+
+
+/**
+ * Adds a socket to a select template subset.
+ *
+ * @param pThis The poll set instance.
+ * @param iInsert The insertion point.
+ * ASSUMED to be at the end of the subset.
+ * @param pcSubSet The subset counter to increment.
+ * @param fd The socket to add.
+ */
+static void rtPollSetOs2AddSocket(RTPOLLSETINTERNAL *pThis, uint16_t iInsert, uint16_t *pcFds, int fd)
+{
+ Assert(!rtPollSetOs2IsSocketInSet(pThis, iInsert - *pcFds, *pcFds, fd));
+
+ /* Note! We keep a -1 entry at the end of the set, thus the + 1. */
+ memmove(&pThis->pafdSelect[iInsert + 1],
+ &pThis->pafdSelect[iInsert],
+ pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets + 1 - iInsert);
+ pThis->pafdSelect[iInsert] = fd;
+ *pcFds += 1;
+
+ Assert(pThis->pafdSelect[pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets] == -1);
+}
+
+
+/**
+ * OS/2 specific RTPollSetAdd worker.
+ *
+ * @returns IPRT status code.
+ * @param pThis The poll set instance.
+ * @param i The index of the new handle (not committed).
+ * @param fEvents The events to poll for.
+ */
+static int rtPollSetOs2Add(RTPOLLSETINTERNAL *pThis, unsigned i, uint32_t fEvents)
+{
+ if (pThis->paHandles[i].enmType == RTHANDLETYPE_SOCKET)
+ {
+ int const fdSocket = pThis->pahNative[i];
+ if ( (fEvents & RTPOLL_EVT_READ)
+ && rtPollSetOs2IsSocketInSet(pThis, 0, pThis->cReadSockets, fdSocket))
+ rtPollSetOs2AddSocket(pThis, pThis->cReadSockets, &pThis->cReadSockets, fdSocket);
+
+ if ( (fEvents & RTPOLL_EVT_WRITE)
+ && rtPollSetOs2IsSocketInSet(pThis, pThis->cReadSockets, pThis->cWriteSockets, fdSocket))
+ rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, &pThis->cWriteSockets, fdSocket);
+
+ if ( (fEvents & RTPOLL_EVT_ERROR)
+ && rtPollSetOs2IsSocketInSet(pThis, pThis->cReadSockets + pThis->cWriteSockets, pThis->cXcptSockets, fdSocket))
+ rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets,
+ &pThis->cXcptSockets, fdSocket);
+ }
+ else if (pThis->paHandles[i].enmType == RTHANDLETYPE_PIPE)
+ {
+ SEMRECORD Rec = { (HSEM)pThis->pahNative[i], pThis->paHandles[i].id };
+ APIRET orc = DosAddMuxWaitSem(pThis->hmux, &Rec);
+ if (orc != NO_ERROR && orc != ERROR_DUPLICATE_HANDLE)
+ return RTErrConvertFromOS2(orc);
+ pThis->cPipes++;
+ }
+ else
+ AssertFailedReturn(VERR_INTERNAL_ERROR_2);
+ return VINF_SUCCESS;
+}
+
+#endif /* RT_OS_OS2 */
+
+/**
+ * Grows the poll set.
+ *
+ * @returns VINF_SUCCESS or VERR_NO_MEMORY.
+ * @param pThis The poll set instance.
+ * @param cHandlesNew The new poll set size.
+ */
+static int rtPollSetGrow(RTPOLLSETINTERNAL *pThis, uint32_t cHandlesNew)
+{
+ Assert(cHandlesNew > pThis->cHandlesAllocated);
+
+ /* The common array. */
+ void *pvNew = RTMemRealloc(pThis->paHandles, cHandlesNew * sizeof(pThis->paHandles[0]));
+ if (!pvNew)
+ return VERR_NO_MEMORY;
+ pThis->paHandles = (PRTPOLLSETHNDENT)pvNew;
+
+
+ /* OS specific handles */
+#if defined(RT_OS_WINDOWS)
+ pvNew = RTMemRealloc(pThis->pahNative, cHandlesNew * sizeof(pThis->pahNative[0]));
+ if (!pvNew)
+ return VERR_NO_MEMORY;
+ pThis->pahNative = (HANDLE *)pvNew;
+
+#elif defined(RT_OS_OS2)
+ pvNew = RTMemRealloc(pThis->pahNative, cHandlesNew * sizeof(pThis->pahNative[0]));
+ if (!pvNew)
+ return VERR_NO_MEMORY;
+ pThis->pahNative = (PRTHCINTPTR)pvNew;
+
+ pvNew = RTMemRealloc(pThis->pafdSelect, (cHandlesNew * 3 + 1) * sizeof(pThis->pafdSelect[0]));
+ if (!pvNew)
+ return VERR_NO_MEMORY;
+ pThis->pafdSelect = (int *)pvNew;
+ if (pThis->cHandlesAllocated == 0)
+ pThis->pafdSelect[0] = -1;
+
+#else
+ pvNew = RTMemRealloc(pThis->paPollFds, cHandlesNew * sizeof(pThis->paPollFds[0]));
+ if (!pvNew)
+ return VERR_NO_MEMORY;
+ pThis->paPollFds = (struct pollfd *)pvNew;
+
+#endif
+
+ pThis->cHandlesAllocated = (uint16_t)cHandlesNew;
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id)
+{
+ /*
+ * Validate the input (tedious).
+ */
+ RTPOLLSETINTERNAL *pThis = hPollSet;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(fEvents, VERR_INVALID_PARAMETER);
+ AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
+
+ if (!pHandle)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pHandle, VERR_INVALID_POINTER);
+ AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER);
+
+ /*
+ * Set the busy flag and do the job.
+ */
+
+ int rc = VINF_SUCCESS;
+ RTHCINTPTR hNative = -1;
+ RTHANDLEUNION uh;
+ uh.uInt = 0;
+ switch (pHandle->enmType)
+ {
+ case RTHANDLETYPE_PIPE:
+ uh.hPipe = pHandle->u.hPipe;
+ if (uh.hPipe == NIL_RTPIPE)
+ return VINF_SUCCESS;
+ rc = rtPipePollGetHandle(uh.hPipe, fEvents, &hNative);
+ break;
+
+ case RTHANDLETYPE_SOCKET:
+ uh.hSocket = pHandle->u.hSocket;
+ if (uh.hSocket == NIL_RTSOCKET)
+ return VINF_SUCCESS;
+ rc = rtSocketPollGetHandle(uh.hSocket, fEvents, &hNative);
+ break;
+
+ case RTHANDLETYPE_FILE:
+ AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n"));
+ rc = VERR_POLL_HANDLE_NOT_POLLABLE;
+ break;
+
+ case RTHANDLETYPE_THREAD:
+ AssertMsgFailed(("Thread handles are currently not pollable\n"));
+ rc = VERR_POLL_HANDLE_NOT_POLLABLE;
+ break;
+
+ default:
+ AssertMsgFailed(("\n"));
+ rc = VERR_POLL_HANDLE_NOT_POLLABLE;
+ break;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
+
+ uint32_t const i = pThis->cHandles;
+
+ /* Check that the handle ID doesn't exist already. */
+ uint32_t iPrev = UINT32_MAX;
+ uint32_t j = i;
+ while (j-- > 0)
+ {
+ if (pThis->paHandles[j].id == id)
+ {
+ rc = VERR_POLL_HANDLE_ID_EXISTS;
+ break;
+ }
+ if ( pThis->paHandles[j].enmType == pHandle->enmType
+ && pThis->paHandles[j].u.uInt == uh.uInt)
+ iPrev = j;
+ }
+
+ /* Check that we won't overflow the poll set now. */
+ if ( RT_SUCCESS(rc)
+ && i + 1 > RTPOLL_SET_MAX)
+ rc = VERR_POLL_SET_IS_FULL;
+
+ /* Grow the tables if necessary. */
+ if (RT_SUCCESS(rc) && i + 1 > pThis->cHandlesAllocated)
+ rc = rtPollSetGrow(pThis, pThis->cHandlesAllocated + 32);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Add the handles to the two parallel arrays.
+ */
+#ifdef RT_OS_WINDOWS
+ pThis->pahNative[i] = (HANDLE)hNative;
+#elif defined(RT_OS_OS2)
+ pThis->pahNative[i] = hNative;
+#else
+ pThis->paPollFds[i].fd = (int)hNative;
+ pThis->paPollFds[i].revents = 0;
+ pThis->paPollFds[i].events = 0;
+ if (fEvents & RTPOLL_EVT_READ)
+ pThis->paPollFds[i].events |= POLLIN;
+ if (fEvents & RTPOLL_EVT_WRITE)
+ pThis->paPollFds[i].events |= POLLOUT;
+ if (fEvents & RTPOLL_EVT_ERROR)
+ pThis->paPollFds[i].events |= POLLERR;
+#endif
+ pThis->paHandles[i].enmType = pHandle->enmType;
+ pThis->paHandles[i].u = uh;
+ pThis->paHandles[i].id = id;
+ pThis->paHandles[i].fEvents = fEvents;
+ pThis->paHandles[i].fFinalEntry = true;
+
+ if (iPrev != UINT32_MAX)
+ {
+ Assert(pThis->paHandles[i].fFinalEntry);
+ pThis->paHandles[i].fFinalEntry = false;
+ }
+
+ /*
+ * Validations and OS specific updates.
+ */
+#ifdef RT_OS_WINDOWS
+ /* none */
+#elif defined(RT_OS_OS2)
+ rc = rtPollSetOs2Add(pThis, i, fEvents);
+#else /* POSIX */
+ if (poll(&pThis->paPollFds[i], 1, 0) < 0)
+ {
+ rc = RTErrConvertFromErrno(errno);
+ pThis->paPollFds[i].fd = -1;
+ }
+#endif /* POSIX */
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Commit it to the set.
+ */
+ pThis->cHandles++; Assert(pThis->cHandles == i + 1);
+ rc = VINF_SUCCESS;
+ }
+ }
+ }
+
+ ASMAtomicWriteBool(&pThis->fBusy, false);
+ return rc;
+}
+
+
+RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id)
+{
+ /*
+ * Validate the input.
+ */
+ RTPOLLSETINTERNAL *pThis = hPollSet;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
+
+ /*
+ * Set the busy flag and do the job.
+ */
+ AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
+
+ int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
+ uint32_t i = pThis->cHandles;
+ while (i-- > 0)
+ if (pThis->paHandles[i].id == id)
+ {
+ /* Save some details for the duplicate searching. */
+ bool const fFinalEntry = pThis->paHandles[i].fFinalEntry;
+ RTHANDLETYPE const enmType = pThis->paHandles[i].enmType;
+ RTHANDLEUNION const uh = pThis->paHandles[i].u;
+#ifdef RT_OS_OS2
+ uint32_t fRemovedEvents = pThis->paHandles[i].fEvents;
+ RTHCINTPTR const hNative = pThis->pahNative[i];
+#endif
+
+ /* Remove the entry. */
+ pThis->cHandles--;
+ size_t const cToMove = pThis->cHandles - i;
+ if (cToMove)
+ {
+ memmove(&pThis->paHandles[i], &pThis->paHandles[i + 1], cToMove * sizeof(pThis->paHandles[i]));
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ memmove(&pThis->pahNative[i], &pThis->pahNative[i + 1], cToMove * sizeof(pThis->pahNative[i]));
+#else
+ memmove(&pThis->paPollFds[i], &pThis->paPollFds[i + 1], cToMove * sizeof(pThis->paPollFds[i]));
+#endif
+ }
+
+ /* Check for duplicate and set the fFinalEntry flag. */
+ if (fFinalEntry)
+ while (i-- > 0)
+ if ( pThis->paHandles[i].u.uInt == uh.uInt
+ && pThis->paHandles[i].enmType == enmType)
+ {
+ Assert(!pThis->paHandles[i].fFinalEntry);
+ pThis->paHandles[i].fFinalEntry = true;
+ break;
+ }
+
+#ifdef RT_OS_OS2
+ /*
+ * Update OS/2 wait structures.
+ */
+ uint32_t fNewEvents = 0;
+ i = pThis->cHandles;
+ while (i-- > 0)
+ if ( pThis->paHandles[i].u.uInt == uh.uInt
+ && pThis->paHandles[i].enmType == enmType)
+ fNewEvents |= pThis->paHandles[i].fEvents;
+ if (enmType == RTHANDLETYPE_PIPE)
+ {
+ pThis->cPipes--;
+ if (fNewEvents == 0)
+ {
+ APIRET orc = DosDeleteMuxWaitSem(pThis->hmux, (HSEM)hNative);
+ AssertMsg(orc == NO_ERROR, ("%d\n", orc));
+ }
+ }
+ else if ( fNewEvents != (fNewEvents | fRemovedEvents)
+ && enmType == RTHANDLETYPE_SOCKET)
+ {
+ fRemovedEvents = fNewEvents ^ (fNewEvents | fRemovedEvents);
+ if (fRemovedEvents & RTPOLL_EVT_ERROR)
+ rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, &pThis->cXcptSockets, (int)hNative);
+ if (fRemovedEvents & RTPOLL_EVT_WRITE)
+ rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets, &pThis->cWriteSockets, (int)hNative);
+ if (fRemovedEvents & RTPOLL_EVT_READ)
+ rtPollSetOs2RemoveSocket(pThis, 0, &pThis->cReadSockets, (int)hNative);
+ }
+#endif /* RT_OS_OS2 */
+ rc = VINF_SUCCESS;
+ break;
+ }
+
+ ASMAtomicWriteBool(&pThis->fBusy, false);
+ return rc;
+}
+
+
+RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle)
+{
+ /*
+ * Validate the input.
+ */
+ RTPOLLSETINTERNAL *pThis = hPollSet;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
+ AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER);
+
+ /*
+ * Set the busy flag and do the job.
+ */
+ AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
+
+ int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
+ uint32_t i = pThis->cHandles;
+ while (i-- > 0)
+ if (pThis->paHandles[i].id == id)
+ {
+ if (pHandle)
+ {
+ pHandle->enmType = pThis->paHandles[i].enmType;
+ pHandle->u = pThis->paHandles[i].u;
+ }
+ rc = VINF_SUCCESS;
+ break;
+ }
+
+ ASMAtomicWriteBool(&pThis->fBusy, false);
+ return rc;
+}
+
+
+RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet)
+{
+ /*
+ * Validate the input.
+ */
+ RTPOLLSETINTERNAL *pThis = hPollSet;
+ AssertPtrReturn(pThis, UINT32_MAX);
+ AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX);
+
+ /*
+ * Set the busy flag and do the job.
+ */
+ AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX);
+ uint32_t cHandles = pThis->cHandles;
+ ASMAtomicWriteBool(&pThis->fBusy, false);
+
+ return cHandles;
+}
+
+RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents)
+{
+ /*
+ * Validate the input.
+ */
+ RTPOLLSETINTERNAL *pThis = hPollSet;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(fEvents, VERR_INVALID_PARAMETER);
+
+ /*
+ * Set the busy flag and do the job.
+ */
+ AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
+
+ int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
+ uint32_t i = pThis->cHandles;
+ while (i-- > 0)
+ if (pThis->paHandles[i].id == id)
+ {
+ if (pThis->paHandles[i].fEvents != fEvents)
+ {
+#if defined(RT_OS_WINDOWS)
+ /*nothing*/
+#elif defined(RT_OS_OS2)
+ if (pThis->paHandles[i].enmType == RTHANDLETYPE_SOCKET)
+ {
+ uint32_t fOldEvents = 0;
+ uint32_t j = pThis->cHandles;
+ while (j-- > 0)
+ if ( pThis->paHandles[j].enmType == RTHANDLETYPE_SOCKET
+ && pThis->paHandles[j].u.uInt == pThis->paHandles[i].u.uInt
+ && j != i)
+ fOldEvents |= pThis->paHandles[j].fEvents;
+ uint32_t fNewEvents = fOldEvents | fEvents;
+ fOldEvents |= pThis->paHandles[i].fEvents;
+ if (fOldEvents != fEvents)
+ {
+ int const fdSocket = pThis->pahNative[i];
+ uint32_t const fChangedEvents = fOldEvents ^ fNewEvents;
+
+ if ((fChangedEvents & RTPOLL_EVT_READ) && (fNewEvents & RTPOLL_EVT_READ))
+ rtPollSetOs2AddSocket(pThis, pThis->cReadSockets, &pThis->cReadSockets, fdSocket);
+ else if (fChangedEvents & RTPOLL_EVT_READ)
+ rtPollSetOs2RemoveSocket(pThis, 0, &pThis->cReadSockets, fdSocket);
+
+ if ((fChangedEvents & RTPOLL_EVT_WRITE) && (fNewEvents & RTPOLL_EVT_WRITE))
+ rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets,
+ &pThis->cWriteSockets, fdSocket);
+ else if (fChangedEvents & RTPOLL_EVT_WRITE)
+ rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets, &pThis->cWriteSockets, fdSocket);
+
+ if ((fChangedEvents & RTPOLL_EVT_ERROR) && (fNewEvents & RTPOLL_EVT_ERROR))
+ rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets,
+ &pThis->cXcptSockets, fdSocket);
+ else if (fChangedEvents & RTPOLL_EVT_ERROR)
+ rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, &pThis->cXcptSockets,
+ fdSocket);
+ }
+ }
+#else
+ pThis->paPollFds[i].events = 0;
+ if (fEvents & RTPOLL_EVT_READ)
+ pThis->paPollFds[i].events |= POLLIN;
+ if (fEvents & RTPOLL_EVT_WRITE)
+ pThis->paPollFds[i].events |= POLLOUT;
+ if (fEvents & RTPOLL_EVT_ERROR)
+ pThis->paPollFds[i].events |= POLLERR;
+#endif
+ pThis->paHandles[i].fEvents = fEvents;
+ }
+ rc = VINF_SUCCESS;
+ break;
+ }
+
+ ASMAtomicWriteBool(&pThis->fBusy, false);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp b/src/VBox/Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp
index 1536d2cb..1e74477f 100644
--- a/src/VBox/Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/RTHandleGetStandard-posix.cpp b/src/VBox/Runtime/r3/posix/RTHandleGetStandard-posix.cpp
index aa12323b..ef5b4bc9 100644
--- a/src/VBox/Runtime/r3/posix/RTHandleGetStandard-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/RTHandleGetStandard-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -32,7 +32,6 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <sys/fcntl.h>
#include <fcntl.h>
#ifdef _MSC_VER
# include <io.h>
diff --git a/src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp b/src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp
index 4e2e116d..12fff20f 100644
--- a/src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp b/src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp
index d39fd6c6..144f54a7 100644
--- a/src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp b/src/VBox/Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp
index b37d921e..6fe59a63 100644
--- a/src/VBox/Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp b/src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp
index 96915fea..5f75e60e 100644
--- a/src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/allocex-r3-posix.cpp b/src/VBox/Runtime/r3/posix/allocex-r3-posix.cpp
new file mode 100644
index 00000000..2aca436c
--- /dev/null
+++ b/src/VBox/Runtime/r3/posix/allocex-r3-posix.cpp
@@ -0,0 +1,109 @@
+/* $Id: allocex-r3-posix.cpp $ */
+/** @file
+ * IPRT - Memory Allocation, Extended Alloc Workers, posix.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define RTMEM_NO_WRAP_TO_EF_APIS
+#include <iprt/mem.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "../allocex.h"
+
+#include <sys/mman.h>
+
+
+DECLHIDDEN(int) rtMemAllocEx16BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv)
+{
+ AssertReturn(cbAlloc < _64K, VERR_NO_MEMORY);
+
+ /*
+ * Try with every possible address hint since the possible range is very limited.
+ */
+ int fProt = PROT_READ | PROT_WRITE | (fFlags & RTMEMALLOCEX_FLAGS_EXEC ? PROT_EXEC : 0);
+ uintptr_t uAddr = 0x1000;
+ uintptr_t uAddrLast = _64K - uAddr - cbAlloc;
+ while (uAddr <= uAddrLast)
+ {
+ void *pv = mmap((void *)uAddr, cbAlloc, fProt, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (pv && (uintptr_t)pv <= uAddrLast)
+ {
+ *ppv = pv;
+ return VINF_SUCCESS;
+ }
+
+ if (pv)
+ {
+ munmap(pv, cbAlloc);
+ pv = NULL;
+ }
+ uAddr += _4K;
+ }
+
+ return VERR_NO_MEMORY;
+}
+
+
+DECLHIDDEN(int) rtMemAllocEx32BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv)
+{
+ int fProt = PROT_READ | PROT_WRITE | (fFlags & RTMEMALLOCEX_FLAGS_EXEC ? PROT_EXEC : 0);
+#if ARCH_BITS == 32
+ void *pv = mmap(NULL, cbAlloc, fProt, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (pv)
+ {
+ *ppv = pv;
+ return VINF_SUCCESS;
+ }
+ return VERR_NO_MEMORY;
+
+#elif defined(RT_OS_LINUX)
+# ifdef MAP_32BIT
+ void *pv = mmap(NULL, cbAlloc, fProt, MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
+ if (pv)
+ {
+ *ppv = pv;
+ return VINF_SUCCESS;
+ }
+# endif
+
+ /** @todo On linux, we need an accurate hint. Since I don't need this branch of
+ * the code right now, I won't bother starting to parse
+ * /proc/curproc/mmap right now... */
+#else
+#endif
+ return VERR_NOT_SUPPORTED;
+}
+
+
+DECLHIDDEN(void) rtMemFreeExYyBitReach(void *pv, size_t cb, uint32_t fFlags)
+{
+ munmap(pv, cb);
+}
+
diff --git a/src/VBox/Runtime/r3/posix/dir-posix.cpp b/src/VBox/Runtime/r3/posix/dir-posix.cpp
index d12cee31..db402d9e 100644
--- a/src/VBox/Runtime/r3/posix/dir-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/dir-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,7 +33,6 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/fcntl.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdio.h>
@@ -53,7 +52,7 @@
#include "internal/fs.h"
#include "internal/path.h"
-#if !defined(RT_OS_SOLARIS)
+#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_HAIKU)
# define HAVE_DIRENT_D_TYPE 1
#endif
@@ -193,6 +192,26 @@ RTDECL(int) RTDirFlush(const char *pszPath)
}
+size_t rtDirNativeGetStructSize(const char *pszPath)
+{
+ long cbNameMax = pathconf(pszPath, _PC_NAME_MAX);
+# ifdef NAME_MAX
+ if (cbNameMax < NAME_MAX) /* This is plain paranoia, but it doesn't hurt. */
+ cbNameMax = NAME_MAX;
+# endif
+# ifdef _XOPEN_NAME_MAX
+ if (cbNameMax < _XOPEN_NAME_MAX) /* Ditto. */
+ cbNameMax = _XOPEN_NAME_MAX;
+# endif
+ size_t cbDir = RT_OFFSETOF(RTDIR, Data.d_name[cbNameMax + 1]);
+ if (cbDir < sizeof(RTDIR)) /* Ditto. */
+ cbDir = sizeof(RTDIR);
+ cbDir = RT_ALIGN_Z(cbDir, 8);
+
+ return cbDir;
+}
+
+
int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
{
NOREF(pszPathBuf); /* only used on windows */
@@ -208,11 +227,9 @@ int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
if (pDir->pDir)
{
/*
- * Init data.
+ * Init data (allocated as all zeros).
*/
- pDir->fDataUnread = false;
- memset(&pDir->Data, 0, RT_OFFSETOF(RTDIR, Data.d_name)); /* not strictly necessary */
- memset(&pDir->Data.d_name[0], 0, pDir->cbMaxName);
+ pDir->fDataUnread = false; /* spelling it out */
}
else
rc = RTErrConvertFromErrno(errno);
diff --git a/src/VBox/Runtime/r3/posix/env-posix.cpp b/src/VBox/Runtime/r3/posix/env-posix.cpp
index 3134d764..cd4fdb16 100644
--- a/src/VBox/Runtime/r3/posix/env-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/env-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -46,13 +46,19 @@
#include "internal/alignmentchecks.h"
+RTDECL(bool) RTEnvExistsBad(const char *pszVar)
+{
+ return RTEnvGetBad(pszVar) != NULL;
+}
+
+
RTDECL(bool) RTEnvExist(const char *pszVar)
{
- return RTEnvGet(pszVar) != NULL;
+ return RTEnvExistsBad(pszVar);
}
-RTDECL(const char *) RTEnvGet(const char *pszVar)
+RTDECL(const char *) RTEnvGetBad(const char *pszVar)
{
IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc causes trouble */
const char *pszValue = getenv(pszVar);
@@ -61,7 +67,13 @@ RTDECL(const char *) RTEnvGet(const char *pszVar)
}
-RTDECL(int) RTEnvPut(const char *pszVarEqualValue)
+RTDECL(const char *) RTEnvGet(const char *pszVar)
+{
+ return RTEnvGetBad(pszVar);
+}
+
+
+RTDECL(int) RTEnvPutBad(const char *pszVarEqualValue)
{
/** @todo putenv is a source memory leaks. deal with this on a per system basis. */
if (!putenv((char *)pszVarEqualValue))
@@ -69,7 +81,14 @@ RTDECL(int) RTEnvPut(const char *pszVarEqualValue)
return RTErrConvertFromErrno(errno);
}
-RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue)
+
+RTDECL(int) RTEnvPut(const char *pszVarEqualValue)
+{
+ return RTEnvPutBad(pszVarEqualValue);
+}
+
+
+RTDECL(int) RTEnvSetBad(const char *pszVar, const char *pszValue)
{
#if defined(_MSC_VER)
/* make a local copy and feed it to putenv. */
@@ -98,7 +117,12 @@ RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue)
}
-RTDECL(int) RTEnvUnset(const char *pszVar)
+RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue)
+{
+ return RTEnvSetBad(pszVar, pszValue);
+}
+
+RTDECL(int) RTEnvUnsetBad(const char *pszVar)
{
AssertReturn(!strchr(pszVar, '='), VERR_INVALID_PARAMETER);
@@ -131,3 +155,8 @@ RTDECL(int) RTEnvUnset(const char *pszVar)
return RTErrConvertFromErrno(errno);
}
+RTDECL(int) RTEnvUnset(const char *pszVar)
+{
+ return RTEnvUnsetBad(pszVar);
+}
+
diff --git a/src/VBox/Runtime/r3/posix/fileaio-posix.cpp b/src/VBox/Runtime/r3/posix/fileaio-posix.cpp
index fe7b8d05..f14e800e 100644
--- a/src/VBox/Runtime/r3/posix/fileaio-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/fileaio-posix.cpp
@@ -122,6 +122,8 @@ typedef struct RTFILEAIOCTXINTERNAL
volatile bool fWokenUp;
/** Flag whether the thread is currently waiting in the syscall. */
volatile bool fWaiting;
+ /** Flags given during creation. */
+ uint32_t fFlags;
/** Magic value (RTFILEAIOCTX_MAGIC). */
uint32_t u32Magic;
/** Flag whether the thread was woken up due to a internal event. */
@@ -522,12 +524,14 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered)
}
-RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
+RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax,
+ uint32_t fFlags)
{
PRTFILEAIOCTXINTERNAL pCtxInt;
unsigned cReqsWaitMax;
AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER);
+ AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
if (cAioReqsMax == RTFILEAIO_UNLIMITED_REQS)
return VERR_OUT_OF_RANGE;
@@ -550,6 +554,7 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC;
pCtxInt->cMaxRequests = cAioReqsMax;
pCtxInt->cReqsWaitMax = cReqsWaitMax;
+ pCtxInt->fFlags = fFlags;
*phAioCtx = (RTFILEAIOCTX)pCtxInt;
return VINF_SUCCESS;
@@ -871,7 +876,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL
int32_t cRequestsWaiting = ASMAtomicReadS32(&pCtxInt->cRequests);
- if (RT_UNLIKELY(cRequestsWaiting <= 0))
+ if ( RT_UNLIKELY(cRequestsWaiting <= 0)
+ && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS))
return VERR_FILE_AIO_NO_REQUEST;
if (RT_UNLIKELY(cMinReqs > (uint32_t)cRequestsWaiting))
diff --git a/src/VBox/Runtime/r3/posix/fileio-posix.cpp b/src/VBox/Runtime/r3/posix/fileio-posix.cpp
index b77ff050..1af29184 100644
--- a/src/VBox/Runtime/r3/posix/fileio-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/fileio-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -34,7 +34,6 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <sys/fcntl.h>
#include <fcntl.h>
#ifdef _MSC_VER
# include <io.h>
@@ -712,6 +711,19 @@ RTR3DECL(int) RTFileSetMode(RTFILE hFile, RTFMODE fMode)
}
+RTDECL(int) RTFileSetOwner(RTFILE hFile, uint32_t uid, uint32_t gid)
+{
+ uid_t uidNative = uid != NIL_RTUID ? (uid_t)uid : (uid_t)-1;
+ AssertReturn(uid == uidNative, VERR_INVALID_PARAMETER);
+ gid_t gidNative = gid != NIL_RTGID ? (gid_t)gid : (gid_t)-1;
+ AssertReturn(gid == gidNative, VERR_INVALID_PARAMETER);
+
+ if (fchown(RTFileToNative(hFile), uidNative, gidNative))
+ return RTErrConvertFromErrno(errno);
+ return VINF_SUCCESS;
+}
+
+
RTR3DECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename)
{
/*
diff --git a/src/VBox/Runtime/r3/posix/fileio2-posix.cpp b/src/VBox/Runtime/r3/posix/fileio2-posix.cpp
index 47c13697..33e10e35 100644
--- a/src/VBox/Runtime/r3/posix/fileio2-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/fileio2-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -46,16 +46,15 @@
#if defined(RT_OS_OS2) && (!defined(__INNOTEK_LIBC__) || __INNOTEK_LIBC__ < 0x006)
# include <io.h>
#endif
-#ifdef RT_OS_L4
-/* This is currently ifdef'ed out in the relevant L4 header file */
-/* Same as `utimes', but takes an open file descriptor instead of a name. */
-extern int futimes(int __fd, __const struct timeval __tvp[2]) __THROW;
-#endif
#ifdef RT_OS_SOLARIS
# define futimes(filedes, timeval) futimesat(filedes, NULL, timeval)
#endif
+#ifdef RT_OS_HAIKU
+# define USE_FUTIMENS
+#endif
+
#include <iprt/file.h>
#include <iprt/path.h>
#include <iprt/assert.h>
@@ -143,6 +142,30 @@ RTR3DECL(int) RTFileSetTimes(RTFILE hFile, PCRTTIMESPEC pAccessTime, PCRTTIMESPE
if (!pAccessTime && !pModificationTime)
return VINF_SUCCESS;
+#ifdef USE_FUTIMENS
+ struct timespec aTimespecs[2];
+ if (pAccessTime && pModificationTime)
+ {
+ memcpy(&aTimespecs[0], pAccessTime, sizeof(struct timespec));
+ memcpy(&aTimespecs[1], pModificationTime, sizeof(struct timespec));
+ }
+ else
+ {
+ RTFSOBJINFO ObjInfo;
+ int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_UNIX);
+ if (RT_FAILURE(rc))
+ return rc;
+ memcpy(&aTimespecs[0], pAccessTime ? pAccessTime : &ObjInfo.AccessTime, sizeof(struct timespec));
+ memcpy(&aTimespecs[1], pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, sizeof(struct timespec));
+ }
+
+ if (futimens(RTFileToNative(hFile), aTimespecs))
+ {
+ int rc = RTErrConvertFromErrno(errno);
+ Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", hFile, pAccessTime, pModificationTime, rc));
+ return rc;
+ }
+#else
/*
* Convert the input to timeval, getting the missing one if necessary,
* and call the API which does the change.
@@ -171,6 +194,7 @@ RTR3DECL(int) RTFileSetTimes(RTFILE hFile, PCRTTIMESPEC pAccessTime, PCRTTIMESPE
Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", hFile, pAccessTime, pModificationTime, rc));
return rc;
}
+#endif
return VINF_SUCCESS;
}
diff --git a/src/VBox/Runtime/r3/posix/filelock-posix.cpp b/src/VBox/Runtime/r3/posix/filelock-posix.cpp
index 266297f2..67734d63 100644
--- a/src/VBox/Runtime/r3/posix/filelock-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/filelock-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,7 +33,6 @@
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <sys/fcntl.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
diff --git a/src/VBox/Runtime/r3/posix/fs-posix.cpp b/src/VBox/Runtime/r3/posix/fs-posix.cpp
index fdb991b1..d5e982e0 100644
--- a/src/VBox/Runtime/r3/posix/fs-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/fs-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -216,6 +216,8 @@ RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
*penmType = RTFSTYPE_JFS;
else if (!strcmp("xfs", mntEnt.mnt_type))
*penmType = RTFSTYPE_XFS;
+ else if (!strcmp("btrfs", mntEnt.mnt_type))
+ *penmType = RTFSTYPE_BTRFS;
else if ( !strcmp("vfat", mntEnt.mnt_type)
|| !strcmp("msdos", mntEnt.mnt_type))
*penmType = RTFSTYPE_FAT;
diff --git a/src/VBox/Runtime/r3/posix/fs2-posix.cpp b/src/VBox/Runtime/r3/posix/fs2-posix.cpp
index 38dafcf1..5eae05a1 100644
--- a/src/VBox/Runtime/r3/posix/fs2-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/fs2-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,6 +33,9 @@
#include <sys/param.h>
#ifndef DEV_BSIZE
# include <sys/stat.h>
+# if defined(RT_OS_HAIKU) && !defined(S_BLKSIZE)
+# define S_BLKSIZE 512
+# endif
# define DEV_BSIZE S_BLKSIZE /** @todo bird: add DEV_BSIZE to sys/param.h on OS/2. */
#endif
diff --git a/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp b/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp
index 61ce3578..4028eb5d 100644
--- a/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -108,7 +108,8 @@ DECLCALLBACK(int) rtldrNativeGetSymbol(PRTLDRMODINTERNAL pMod, const char *pszSy
DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod)
{
PRTLDRMODNATIVE pModNative = (PRTLDRMODNATIVE)pMod;
- if (!dlclose((void *)pModNative->hNative))
+ if ( (pModNative->fFlags & RTLDRLOAD_FLAGS_NO_UNLOAD)
+ || !dlclose((void *)pModNative->hNative))
{
pModNative->hNative = (uintptr_t)0;
return VINF_SUCCESS;
@@ -117,3 +118,10 @@ DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod)
return VERR_GENERAL_FAILURE;
}
+
+int rtldrNativeLoadSystem(const char *pszFilename, const char *pszExt, uint32_t fFlags, PRTLDRMOD phLdrMod)
+{
+ /** @todo implement this in some sensible fashion. */
+ return VERR_NOT_SUPPORTED;
+}
+
diff --git a/src/VBox/Runtime/r3/posix/path-posix.cpp b/src/VBox/Runtime/r3/posix/path-posix.cpp
index 7ad6b028..2b7adf9f 100644
--- a/src/VBox/Runtime/r3/posix/path-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/path-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -49,11 +49,6 @@
#include "internal/process.h"
#include "internal/fs.h"
-#ifdef RT_OS_L4
-# include <l4/vboxserver/vboxserver.h>
-#endif
-
-
RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath)
diff --git a/src/VBox/Runtime/r3/posix/path2-posix.cpp b/src/VBox/Runtime/r3/posix/path2-posix.cpp
index abc2ce29..856424d7 100644
--- a/src/VBox/Runtime/r3/posix/path2-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/path2-posix.cpp
@@ -48,10 +48,6 @@
#include "internal/process.h"
#include "internal/fs.h"
-#ifdef RT_OS_L4
-# include <l4/vboxserver/vboxserver.h>
-#endif
-
RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
{
diff --git a/src/VBox/Runtime/r3/posix/pathhost-posix.cpp b/src/VBox/Runtime/r3/posix/pathhost-posix.cpp
index 5390fe57..6f75c27b 100644
--- a/src/VBox/Runtime/r3/posix/pathhost-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/pathhost-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -134,7 +134,7 @@ static bool rtPathConvInitIsUtf8(const char *pszCodeset)
* @param pvUser1 Unused.
* @param pvUser2 Unused.
*/
-static DECLCALLBACK(int32_t) rtPathConvInitOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int32_t) rtPathConvInitOnce(void *pvUser)
{
/*
* Read the environment variable, no mercy on misconfigs here except that
@@ -172,7 +172,7 @@ static DECLCALLBACK(int32_t) rtPathConvInitOnce(void *pvUser1, void *pvUser2)
g_enmUtf8ToFsIdx = RTSTRICONV_UTF8_TO_LOCALE;
}
- NOREF(pvUser1); NOREF(pvUser2);
+ NOREF(pvUser);
return VINF_SUCCESS;
}
@@ -181,7 +181,7 @@ int rtPathToNative(char const **ppszNativePath, const char *pszPath, const char
{
*ppszNativePath = NULL;
- int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL, NULL);
+ int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL);
if (RT_SUCCESS(rc))
{
if (g_fPassthruUtf8 || !*pszPath)
@@ -208,7 +208,7 @@ int rtPathFromNative(const char **ppszPath, const char *pszNativePath, const cha
{
*ppszPath = NULL;
- int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL, NULL);
+ int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL);
if (RT_SUCCESS(rc))
{
if (g_fPassthruUtf8 || !*pszNativePath)
@@ -246,7 +246,7 @@ void rtPathFreeIprt(const char *pszPath, const char *pszNativePath)
int rtPathFromNativeCopy(char *pszPath, size_t cbPath, const char *pszNativePath, const char *pszBasePath)
{
- int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL, NULL);
+ int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL);
if (RT_SUCCESS(rc))
{
if (g_fPassthruUtf8 || !*pszNativePath)
@@ -266,7 +266,7 @@ int rtPathFromNativeCopy(char *pszPath, size_t cbPath, const char *pszNativePath
int rtPathFromNativeDup(char **ppszPath, const char *pszNativePath, const char *pszBasePath)
{
- int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL, NULL);
+ int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL);
if (RT_SUCCESS(rc))
{
if (g_fPassthruUtf8 || !*pszNativePath)
diff --git a/src/VBox/Runtime/r3/posix/pipe-posix.cpp b/src/VBox/Runtime/r3/posix/pipe-posix.cpp
index 2e006cb3..9d950de9 100644
--- a/src/VBox/Runtime/r3/posix/pipe-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/pipe-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -35,6 +35,7 @@
#include <iprt/assert.h>
#include <iprt/err.h>
#include <iprt/mem.h>
+#include <iprt/poll.h>
#include <iprt/string.h>
#include <iprt/thread.h>
#include "internal/magics.h"
@@ -54,6 +55,8 @@
# include <sys/filio.h>
#endif
+#include "internal/pipe.h"
+
/*******************************************************************************
* Structures and Typedefs *
@@ -667,3 +670,17 @@ RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable)
return rc;
}
+
+int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative)
+{
+ RTPIPEINTERNAL *pThis = hPipe;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
+
+ AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER);
+
+ *phNative = pThis->fd;
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/r3/posix/poll-posix.cpp b/src/VBox/Runtime/r3/posix/poll-posix.cpp
deleted file mode 100644
index ff124968..00000000
--- a/src/VBox/Runtime/r3/posix/poll-posix.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/* $Id: poll-posix.cpp $ */
-/** @file
- * IPRT - Polling I/O Handles, POSIX Implementation.
- */
-
-/*
- * Copyright (C) 2010 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-#include <iprt/poll.h>
-#include "internal/iprt.h"
-
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/err.h>
-#include <iprt/mem.h>
-#include <iprt/pipe.h>
-#include <iprt/socket.h>
-#include <iprt/string.h>
-#include <iprt/thread.h>
-#include <iprt/time.h>
-#include "internal/magics.h"
-
-#include <limits.h>
-#include <errno.h>
-#include <sys/poll.h>
-
-
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
-/**
- * Handle entry in a poll set.
- */
-typedef struct RTPOLLSETHNDENT
-{
- /** The handle type. */
- RTHANDLETYPE enmType;
- /** The handle ID. */
- uint32_t id;
- /** The handle union. */
- RTHANDLEUNION u;
-} RTPOLLSETHNDENT;
-/** Pointer to a handle entry. */
-typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT;
-
-/**
- * Poll set data, POSIX.
- */
-typedef struct RTPOLLSETINTERNAL
-{
- /** The magic value (RTPOLLSET_MAGIC). */
- uint32_t u32Magic;
- /** Set when someone is polling or making changes. */
- bool volatile fBusy;
-
- /** The number of valid handles in the set. */
- uint32_t cHandles;
- /** The number of allocated handles. */
- uint32_t cHandlesAllocated;
-
- /** Pointer to an array of pollfd structures. */
- struct pollfd *paPollFds;
- /** Pointer to an array of handles and IDs. */
- PRTPOLLSETHNDENT paHandles;
-} RTPOLLSETINTERNAL;
-
-
-/**
- * Common worker for RTPoll and RTPollNoResume
- */
-static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
-{
- if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT))
- return VERR_DEADLOCK;
-
- /* clear the revents. */
- uint32_t i = pThis->cHandles;
- while (i-- > 0)
- pThis->paPollFds[i].revents = 0;
-
- int rc = poll(&pThis->paPollFds[0], pThis->cHandles,
- cMillies == RT_INDEFINITE_WAIT || cMillies >= INT_MAX
- ? -1
- : (int)cMillies);
- if (rc == 0)
- return VERR_TIMEOUT;
- if (rc < 0)
- return RTErrConvertFromErrno(errno);
-
- for (i = 0; i < pThis->cHandles; i++)
- if (pThis->paPollFds[i].revents)
- {
- if (pfEvents)
- {
- *pfEvents = 0;
- if (pThis->paPollFds[i].revents & (POLLIN
-#ifdef POLLRDNORM
- | POLLRDNORM /* just in case */
-#endif
-#ifdef POLLRDBAND
- | POLLRDBAND /* ditto */
-#endif
-#ifdef POLLPRI
- | POLLPRI /* ditto */
-#endif
-#ifdef POLLMSG
- | POLLMSG /* ditto */
-#endif
-#ifdef POLLWRITE
- | POLLWRITE /* ditto */
-#endif
-#ifdef POLLEXTEND
- | POLLEXTEND /* ditto */
-#endif
- )
- )
- *pfEvents |= RTPOLL_EVT_READ;
-
- if (pThis->paPollFds[i].revents & (POLLOUT
-#ifdef POLLWRNORM
- | POLLWRNORM /* just in case */
-#endif
-#ifdef POLLWRBAND
- | POLLWRBAND /* ditto */
-#endif
- )
- )
- *pfEvents |= RTPOLL_EVT_WRITE;
-
- if (pThis->paPollFds[i].revents & (POLLERR | POLLHUP | POLLNVAL
-#ifdef POLLRDHUP
- | POLLRDHUP
-#endif
- )
- )
- *pfEvents |= RTPOLL_EVT_ERROR;
- }
- if (pid)
- *pid = pThis->paHandles[i].id;
- return VINF_SUCCESS;
- }
-
- AssertFailed();
- RTThreadYield();
- return VERR_INTERRUPTED;
-}
-
-
-RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
-{
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertPtrNull(pfEvents);
- AssertPtrNull(pid);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc;
- if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0)
- {
- do rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
- while (rc == VERR_INTERRUPTED);
- }
- else
- {
- uint64_t MsStart = RTTimeMilliTS();
- rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
- while (RT_UNLIKELY(rc == VERR_INTERRUPTED))
- {
- if (RTTimeMilliTS() - MsStart >= cMillies)
- {
- rc = VERR_TIMEOUT;
- break;
- }
- rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
- }
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
-
- return rc;
-}
-
-
-RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
-{
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertPtrNull(pfEvents);
- AssertPtrNull(pid);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
-
- return rc;
-}
-
-
-RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet)
-{
- AssertPtrReturn(phPollSet, VERR_INVALID_POINTER);
- RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAlloc(sizeof(RTPOLLSETINTERNAL));
- if (!pThis)
- return VERR_NO_MEMORY;
-
- pThis->u32Magic = RTPOLLSET_MAGIC;
- pThis->fBusy = false;
- pThis->cHandles = 0;
- pThis->cHandlesAllocated = 0;
- pThis->paPollFds = NULL;
- pThis->paHandles = NULL;
-
- *phPollSet = pThis;
- return VINF_SUCCESS;
-}
-
-
-RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet)
-{
- RTPOLLSETINTERNAL *pThis = hPollSet;
- if (pThis == NIL_RTPOLLSET)
- return VINF_SUCCESS;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC);
- RTMemFree(pThis->paPollFds);
- pThis->paPollFds = NULL;
- RTMemFree(pThis->paHandles);
- pThis->paHandles = NULL;
- RTMemFree(pThis);
-
- return VINF_SUCCESS;
-}
-
-
-RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id)
-{
- /*
- * Validate the input (tedious).
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
- AssertReturn(fEvents, VERR_INVALID_PARAMETER);
- AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
-
- if (!pHandle)
- return VINF_SUCCESS;
- AssertPtrReturn(pHandle, VERR_INVALID_POINTER);
- AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = VINF_SUCCESS;
- int fd = -1;
- switch (pHandle->enmType)
- {
- case RTHANDLETYPE_PIPE:
- if (pHandle->u.hPipe != NIL_RTPIPE)
- fd = (int)RTPipeToNative(pHandle->u.hPipe);
- break;
-
- case RTHANDLETYPE_SOCKET:
- if (pHandle->u.hSocket != NIL_RTSOCKET)
- fd = (int)RTSocketToNative(pHandle->u.hSocket);
- break;
-
- case RTHANDLETYPE_FILE:
- AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n"));
- rc = VERR_POLL_HANDLE_NOT_POLLABLE;
- break;
-
- case RTHANDLETYPE_THREAD:
- AssertMsgFailed(("Thread handles are currently not pollable\n"));
- rc = VERR_POLL_HANDLE_NOT_POLLABLE;
- break;
-
- default:
- AssertMsgFailed(("\n"));
- rc = VERR_POLL_HANDLE_NOT_POLLABLE;
- break;
- }
- if (fd != -1)
- {
- uint32_t const i = pThis->cHandles;
-
- /* Check that the handle ID doesn't exist already. */
- uint32_t j = i;
- while (j-- > 0)
- if (pThis->paHandles[j].id == id)
- {
- rc = VERR_POLL_HANDLE_ID_EXISTS;
- break;
- }
- if (RT_SUCCESS(rc))
- {
- /* Grow the tables if necessary. */
- if (i + 1 > pThis->cHandlesAllocated)
- {
- uint32_t const c = pThis->cHandlesAllocated + 32;
- void *pvNew;
- pvNew = RTMemRealloc(pThis->paHandles, c * sizeof(pThis->paHandles[0]));
- if (pvNew)
- {
- pThis->paHandles = (PRTPOLLSETHNDENT)pvNew;
- pvNew = RTMemRealloc(pThis->paPollFds, c * sizeof(pThis->paPollFds[0]));
- if (pvNew)
- pThis->paPollFds = (struct pollfd *)pvNew;
- else
- rc = VERR_NO_MEMORY;
- }
- else
- rc = VERR_NO_MEMORY;
- }
- if (RT_SUCCESS(rc))
- {
- /* Add it to the poll file descriptor array and call poll to
- validate the event flags. */
- pThis->paPollFds[i].fd = fd;
- pThis->paPollFds[i].revents = 0;
- pThis->paPollFds[i].events = 0;
- if (fEvents & RTPOLL_EVT_READ)
- pThis->paPollFds[i].events |= POLLIN;
- if (fEvents & RTPOLL_EVT_WRITE)
- pThis->paPollFds[i].events |= POLLOUT;
- if (fEvents & RTPOLL_EVT_ERROR)
- pThis->paPollFds[i].events |= POLLERR;
-
- if (poll(&pThis->paPollFds[i], 1, 0) >= 0)
- {
- /* Add the handle info and close the transaction. */
- pThis->paHandles[i].enmType = pHandle->enmType;
- pThis->paHandles[i].u = pHandle->u;
- pThis->paHandles[i].id = id;
-
- pThis->cHandles = i + 1;
- rc = VINF_SUCCESS;
- }
- else
- {
- rc = RTErrConvertFromErrno(errno);
- pThis->paPollFds[i].fd = -1;
- }
- }
- }
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
- return rc;
-}
-
-
-RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id)
-{
- /*
- * Validate the input.
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
- uint32_t i = pThis->cHandles;
- while (i-- > 0)
- if (pThis->paHandles[i].id == id)
- {
- pThis->cHandles--;
- size_t const cToMove = pThis->cHandles - i;
- if (cToMove)
- {
- memmove(&pThis->paHandles[i], &pThis->paHandles[i + 1], cToMove * sizeof(pThis->paHandles[i]));
- memmove(&pThis->paPollFds[i], &pThis->paPollFds[i + 1], cToMove * sizeof(pThis->paPollFds[i]));
- }
- rc = VINF_SUCCESS;
- break;
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
- return rc;
-}
-
-
-RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle)
-{
- /*
- * Validate the input.
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
- AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
- uint32_t i = pThis->cHandles;
- while (i-- > 0)
- if (pThis->paHandles[i].id == id)
- {
- if (pHandle)
- {
- pHandle->enmType = pThis->paHandles[i].enmType;
- pHandle->u = pThis->paHandles[i].u;
- }
- rc = VINF_SUCCESS;
- break;
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
- return rc;
-}
-
-
-RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet)
-{
- /*
- * Validate the input.
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, UINT32_MAX);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX);
- uint32_t cHandles = pThis->cHandles;
- ASMAtomicWriteBool(&pThis->fBusy, false);
-
- return cHandles;
-}
-
-
-RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents)
-{
- /*
- * Validate the input.
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
- AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
- AssertReturn(fEvents, VERR_INVALID_PARAMETER);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
- uint32_t i = pThis->cHandles;
- while (i-- > 0)
- if (pThis->paHandles[i].id == id)
- {
- pThis->paPollFds[i].events = 0;
- if (fEvents & RTPOLL_EVT_READ)
- pThis->paPollFds[i].events |= POLLIN;
- if (fEvents & RTPOLL_EVT_WRITE)
- pThis->paPollFds[i].events |= POLLOUT;
- if (fEvents & RTPOLL_EVT_ERROR)
- pThis->paPollFds[i].events |= POLLERR;
- rc = VINF_SUCCESS;
- break;
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
- return rc;
-}
-
diff --git a/src/VBox/Runtime/r3/posix/process-creation-posix.cpp b/src/VBox/Runtime/r3/posix/process-creation-posix.cpp
index 2f8841c4..4fd2d0e2 100644
--- a/src/VBox/Runtime/r3/posix/process-creation-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/process-creation-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -29,6 +29,8 @@
* Header Files *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_PROCESS
+#include <iprt/cdefs.h>
+
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
@@ -37,20 +39,28 @@
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
+#include <grp.h>
#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
# include <crypt.h>
# include <pwd.h>
# include <shadow.h>
#endif
+
#if defined(RT_OS_LINUX) || defined(RT_OS_OS2)
/* While Solaris has posix_spawn() of course we don't want to use it as
* we need to have the child in a different process contract, no matter
* whether it is started detached or not. */
# define HAVE_POSIX_SPAWN 1
#endif
+#if defined(RT_OS_DARWIN) && defined(MAC_OS_X_VERSION_MIN_REQUIRED)
+# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+# define HAVE_POSIX_SPAWN 1
+# endif
+#endif
#ifdef HAVE_POSIX_SPAWN
# include <spawn.h>
#endif
+
#ifdef RT_OS_DARWIN
# include <mach-o/dyld.h>
#endif
@@ -297,6 +307,10 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER);
AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER);
AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER);
+#if defined(RT_OS_OS2)
+ if (fFlags & RTPROC_FLAGS_DETACHED)
+ return VERR_PROC_DETACH_NOT_SUPPORTED;
+#endif
/*
* Get the file descriptors for the handles we've been passed.
@@ -462,20 +476,30 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
rc = posix_spawnattr_init(&Attr);
if (!rc)
{
-# ifndef RT_OS_OS2 /* We don't need this on OS/2 and I don't recall if it's actually implemented. */
- rc = posix_spawnattr_setflags(&Attr, POSIX_SPAWN_SETPGROUP);
+ /* Indicate that process group and signal mask are to be changed,
+ and that the child should use default signal actions. */
+ rc = posix_spawnattr_setflags(&Attr, POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF);
Assert(rc == 0);
+
+ /* The child starts in its own process group. */
if (!rc)
{
rc = posix_spawnattr_setpgroup(&Attr, 0 /* pg == child pid */);
Assert(rc == 0);
}
-# endif
+
+ /* Unmask all signals. */
+ if (!rc)
+ {
+ sigset_t SigMask;
+ sigemptyset(&SigMask);
+ rc = posix_spawnattr_setsigmask(&Attr, &SigMask); Assert(rc == 0);
+ }
/* File changes. */
posix_spawn_file_actions_t FileActions;
posix_spawn_file_actions_t *pFileActions = NULL;
- if (aStdFds[0] != -1 || aStdFds[1] != -1 || aStdFds[2] != -1)
+ if ((aStdFds[0] != -1 || aStdFds[1] != -1 || aStdFds[2] != -1) && !rc)
{
rc = posix_spawn_file_actions_init(&FileActions);
if (!rc)
@@ -525,7 +549,7 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
/* For a detached process this happens in the temp process, so
* it's not worth doing anything as this process must exit. */
if (fFlags & RTPROC_FLAGS_DETACHED)
- _Exit(0);
+ _Exit(0);
if (phProcess)
*phProcess = pid;
return VINF_SUCCESS;
@@ -540,15 +564,20 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
#endif
{
#ifdef RT_OS_SOLARIS
- int templateFd = rtSolarisContractPreFork();
- if (templateFd == -1)
- return VERR_OPEN_FAILED;
+ int templateFd = -1;
+ if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
+ {
+ templateFd = rtSolarisContractPreFork();
+ if (templateFd == -1)
+ return VERR_OPEN_FAILED;
+ }
#endif /* RT_OS_SOLARIS */
pid = fork();
if (!pid)
{
#ifdef RT_OS_SOLARIS
- rtSolarisContractPostForkChild(templateFd);
+ if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
+ rtSolarisContractPostForkChild(templateFd);
#endif /* RT_OS_SOLARIS */
if (!(fFlags & RTPROC_FLAGS_DETACHED))
setpgid(0, 0); /* see comment above */
@@ -557,6 +586,17 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
* Change group and user if requested.
*/
#if 1 /** @todo This needs more work, see suplib/hardening. */
+ if (pszAsUser)
+ {
+ int ret = initgroups(pszAsUser, gid);
+ if (ret)
+ {
+ if (fFlags & RTPROC_FLAGS_DETACHED)
+ _Exit(126);
+ else
+ exit(126);
+ }
+ }
if (gid != ~(gid_t)0)
{
if (setgid(gid))
@@ -581,6 +621,14 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
#endif
/*
+ * Unset the signal mask.
+ */
+ sigset_t SigMask;
+ sigemptyset(&SigMask);
+ rc = sigprocmask(SIG_SETMASK, &SigMask, NULL);
+ Assert(rc == 0);
+
+ /*
* Apply changes to the standard file descriptor and stuff.
*/
for (int i = 0; i < 3; i++)
@@ -627,7 +675,8 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
exit(127);
}
#ifdef RT_OS_SOLARIS
- rtSolarisContractPostForkParent(templateFd, pid);
+ if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
+ rtSolarisContractPostForkParent(templateFd, pid);
#endif /* RT_OS_SOLARIS */
if (pid > 0)
{
diff --git a/src/VBox/Runtime/r3/posix/process-posix.cpp b/src/VBox/Runtime/r3/posix/process-posix.cpp
index 7b823163..01631f6d 100644
--- a/src/VBox/Runtime/r3/posix/process-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/process-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -188,4 +188,3 @@ RTR3DECL(int) RTProcQueryUsername(RTPROCESS hProcess, char *pszUser, size_t cbUs
return rc;
}
-
diff --git a/src/VBox/Runtime/r3/posix/rand-posix.cpp b/src/VBox/Runtime/r3/posix/rand-posix.cpp
index f394d149..1d1725f1 100644
--- a/src/VBox/Runtime/r3/posix/rand-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/rand-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -32,7 +32,6 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <sys/fcntl.h>
#include <fcntl.h>
#ifdef _MSC_VER
# include <io.h>
@@ -57,7 +56,10 @@ static DECLCALLBACK(void) rtRandAdvPosixGetBytes(PRTRANDINT pThis, uint8_t *pb,
ssize_t cbRead = read(pThis->u.File.hFile, pb, cb);
if ((size_t)cbRead != cb)
{
- ssize_t cTries = RT_MIN(cb, 256);
+ /* S10 has been observed returning 1040 bytes at the time from /dev/urandom.
+ Which means we need to do than 256 rounds to reach 668171 bytes if
+ that's what demanded by the caller (like tstRTMemWipe.cpp). */
+ ssize_t cTries = RT_MAX(256, cb / 64);
do
{
if (cbRead > 0)
diff --git a/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp b/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp
index 73f925c2..c72cd22f 100644
--- a/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp
@@ -146,20 +146,20 @@ static RTHEAPPAGE g_MemExecPosixHeap;
#ifdef RT_OS_OS2
/*
- * A quick mmap/munmap mockup for avoid duplicating lots of good code.
+ * A quick mmap/munmap mockup for avoid duplicating lots of good code.
*/
# define INCL_BASE
# include <os2.h>
-# undef MAP_PRIVATE
+# undef MAP_PRIVATE
# define MAP_PRIVATE 0
-# undef MAP_ANONYMOUS
+# undef MAP_ANONYMOUS
# define MAP_ANONYMOUS 0
# undef MAP_FAILED
# define MAP_FAILED (void *)-1
# undef mmap
-# define mmap iprt_mmap
+# define mmap iprt_mmap
# undef munmap
-# define munmap iprt_munmap
+# define munmap iprt_munmap
static void *mmap(void *pvWhere, size_t cb, int fProt, int fFlags, int fd, off_t off)
{
@@ -605,12 +605,11 @@ int RTHeapPageFree(PRTHEAPPAGE pHeap, void *pv, size_t cPages)
* Initializes the heap.
*
* @returns IPRT status code
- * @param pvUser1 Unused.
- * @param pvUser2 Unused.
+ * @param pvUser Unused.
*/
-static DECLCALLBACK(int) rtMemPagePosixInitOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int) rtMemPagePosixInitOnce(void *pvUser)
{
- NOREF(pvUser1); NOREF(pvUser2);
+ NOREF(pvUser);
int rc = RTHeapPageInit(&g_MemPagePosixHeap, false /*fExec*/);
if (RT_SUCCESS(rc))
{
@@ -663,7 +662,7 @@ static void *rtMemPagePosixAlloc(size_t cb, const char *pszTag, bool fZero, PRTH
}
else
{
- int rc = RTOnce(&g_MemPagePosixInitOnce, rtMemPagePosixInitOnce, NULL, NULL);
+ int rc = RTOnce(&g_MemPagePosixInitOnce, rtMemPagePosixInitOnce, NULL);
if (RT_SUCCESS(rc))
rc = RTHeapPageAlloc(pHeap, cb >> PAGE_SHIFT, pszTag, fZero, &pv);
if (RT_FAILURE(rc))
diff --git a/src/VBox/Runtime/r3/posix/sched-posix.cpp b/src/VBox/Runtime/r3/posix/sched-posix.cpp
index 6fbf2f9f..4fa2bb9a 100644
--- a/src/VBox/Runtime/r3/posix/sched-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/sched-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/semevent-posix.cpp b/src/VBox/Runtime/r3/posix/semevent-posix.cpp
index f2c40f3f..67d69cbb 100644
--- a/src/VBox/Runtime/r3/posix/semevent-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/semevent-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -48,7 +48,7 @@
# define pthread_yield() pthread_yield_np()
#endif
-#ifdef RT_OS_SOLARIS
+#if defined(RT_OS_SOLARIS) || defined(RT_OS_HAIKU)
# include <sched.h>
# define pthread_yield() sched_yield()
#endif
@@ -397,7 +397,7 @@ DECL_FORCE_INLINE(int) rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillie
* Get current time and calc end of wait time.
*/
struct timespec ts = {0,0};
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)
struct timeval tv = {0,0};
gettimeofday(&tv, NULL);
ts.tv_sec = tv.tv_sec;
diff --git a/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp b/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp
index 8a1d066b..2875a9a0 100644
--- a/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -481,7 +481,7 @@ static int rtSemEventMultiPosixWaitTimed(struct RTSEMEVENTMULTIINTERNAL *pThis,
struct timespec ts = {0,0};
if (!pThis->fMonotonicClock)
{
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)
struct timeval tv = {0,0};
gettimeofday(&tv, NULL);
ts.tv_sec = tv.tv_sec;
diff --git a/src/VBox/Runtime/r3/posix/semmutex-posix.cpp b/src/VBox/Runtime/r3/posix/semmutex-posix.cpp
index e1e82558..89fa962c 100644
--- a/src/VBox/Runtime/r3/posix/semmutex-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/semmutex-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -65,6 +65,43 @@ struct RTSEMMUTEXINTERNAL
#endif
};
+#ifdef RT_OS_DARWIN
+/**
+ * This function emulate pthread_mutex_timedlock on Mac OS X
+ */
+static int DarwinPthreadMutexTimedlock(pthread_mutex_t * mutex, const struct timespec * pTsAbsTimeout)
+{
+ int rc = 0;
+ struct timeval tv;
+ timespec ts = {0, 0};
+ do
+ {
+ rc = pthread_mutex_trylock(mutex);
+ if (rc == EBUSY)
+ {
+ gettimeofday(&tv, NULL);
+
+ ts.tv_sec = pTsAbsTimeout->tv_sec - tv.tv_sec;
+ ts.tv_nsec = pTsAbsTimeout->tv_nsec - tv.tv_sec;
+
+ if (ts.tv_nsec < 0)
+ {
+ ts.tv_sec--;
+ ts.tv_nsec += 1000000000;
+ }
+
+ if ( ts.tv_sec > 0
+ && ts.tv_nsec > 0)
+ nanosleep(&ts, &ts);
+ }
+ else
+ break;
+ } while ( rc != 0
+ || ts.tv_sec > 0);
+ return rc;
+}
+#endif
+
#undef RTSemMutexCreate
RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem)
@@ -241,15 +278,16 @@ DECL_FORCE_INLINE(int) rtSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMil
}
else
{
-#ifdef RT_OS_DARWIN
- AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
- return VERR_NOT_IMPLEMENTED;
-#else /* !RT_OS_DARWIN */
- /*
- * Get current time and calc end of wait time.
- */
struct timespec ts = {0,0};
+#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)
+
+ struct timeval tv = {0,0};
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+#else
clock_gettime(CLOCK_REALTIME, &ts);
+#endif
if (cMillies != 0)
{
ts.tv_nsec += (cMillies % 1000) * 1000000;
@@ -262,14 +300,17 @@ DECL_FORCE_INLINE(int) rtSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMil
}
/* take mutex */
+#ifndef RT_OS_DARWIN
int rc = pthread_mutex_timedlock(&pThis->Mutex, &ts);
+#else
+ int rc = DarwinPthreadMutexTimedlock(&pThis->Mutex, &ts);
+#endif
RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_MUTEX);
if (rc)
{
AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", hMutexSem, rc)); NOREF(rc);
return RTErrConvertFromErrno(rc);
}
-#endif /* !RT_OS_DARWIN */
}
/*
diff --git a/src/VBox/Runtime/r3/posix/semrw-posix.cpp b/src/VBox/Runtime/r3/posix/semrw-posix.cpp
index 81f71ef1..c6dfeb2f 100644
--- a/src/VBox/Runtime/r3/posix/semrw-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/semrw-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/symlink-posix.cpp b/src/VBox/Runtime/r3/posix/symlink-posix.cpp
index f2c05da2..b3e10877 100644
--- a/src/VBox/Runtime/r3/posix/symlink-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/symlink-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/thread-posix.cpp b/src/VBox/Runtime/r3/posix/thread-posix.cpp
index b212181a..66ccafb0 100644
--- a/src/VBox/Runtime/r3/posix/thread-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/thread-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -47,17 +47,22 @@
# include <mach/mach_init.h>
# include <mach/mach_host.h>
#endif
-#if defined(RT_OS_DARWIN) /*|| defined(RT_OS_FREEBSD) - later */ || defined(RT_OS_LINUX) \
+#if defined(RT_OS_DARWIN) /*|| defined(RT_OS_FREEBSD) - later */ \
+ || (defined(RT_OS_LINUX) && !defined(IN_RT_STATIC) /* static + dlsym = trouble */) \
|| defined(IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP)
# define IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
# include <dlfcn.h>
#endif
+#if defined(RT_OS_HAIKU)
+# include <OS.h>
+#endif
#include <iprt/thread.h>
#include <iprt/log.h>
#include <iprt/assert.h>
#include <iprt/asm.h>
#include <iprt/err.h>
+#include <iprt/initterm.h>
#include <iprt/string.h>
#include "internal/thread.h"
@@ -115,20 +120,14 @@ static void rtThreadKeyDestruct(void *pvValue);
static void rtThreadPosixPokeSignal(int iSignal);
-DECLHIDDEN(int) rtThreadNativeInit(void)
-{
- /*
- * Allocate the TLS (key in posix terms) where we store the pointer to
- * a threads RTTHREADINT structure.
- */
- int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct);
- if (rc)
- return VERR_NO_TLS_FOR_SELF;
-
#ifdef RTTHREAD_POSIX_WITH_POKE
+/**
+ * Try register the dummy signal handler for RTThreadPoke.
+ */
+static void rtThreadPosixSelectPokeSignal(void)
+{
/*
- * Try register the dummy signal handler for RTThreadPoke.
- * Avoid SIGRTMIN thru SIGRTMIN+2 because of LinuxThreads.
+ * Note! Avoid SIGRTMIN thru SIGRTMIN+2 because of LinuxThreads.
*/
static const int s_aiSigCandidates[] =
{
@@ -144,34 +143,53 @@ DECLHIDDEN(int) rtThreadNativeInit(void)
};
g_iSigPokeThread = -1;
- for (unsigned iSig = 0; iSig < RT_ELEMENTS(s_aiSigCandidates); iSig++)
+ if (!RTR3InitIsUnobtrusive())
{
- struct sigaction SigActOld;
- if (!sigaction(s_aiSigCandidates[iSig], NULL, &SigActOld))
+ for (unsigned iSig = 0; iSig < RT_ELEMENTS(s_aiSigCandidates); iSig++)
{
- if ( SigActOld.sa_handler == SIG_DFL
- || SigActOld.sa_handler == rtThreadPosixPokeSignal)
+ struct sigaction SigActOld;
+ if (!sigaction(s_aiSigCandidates[iSig], NULL, &SigActOld))
{
- struct sigaction SigAct;
- RT_ZERO(SigAct);
- SigAct.sa_handler = rtThreadPosixPokeSignal;
- SigAct.sa_flags = 0;
- sigfillset(&SigAct.sa_mask);
-
- /* ASSUMES no sigaction race... (lazy bird) */
- if (!sigaction(s_aiSigCandidates[iSig], &SigAct, NULL))
+ if ( SigActOld.sa_handler == SIG_DFL
+ || SigActOld.sa_handler == rtThreadPosixPokeSignal)
{
- g_iSigPokeThread = s_aiSigCandidates[iSig];
- break;
+ struct sigaction SigAct;
+ RT_ZERO(SigAct);
+ SigAct.sa_handler = rtThreadPosixPokeSignal;
+ SigAct.sa_flags = 0;
+ sigfillset(&SigAct.sa_mask);
+
+ /* ASSUMES no sigaction race... (lazy bird) */
+ if (!sigaction(s_aiSigCandidates[iSig], &SigAct, NULL))
+ {
+ g_iSigPokeThread = s_aiSigCandidates[iSig];
+ break;
+ }
+ AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
}
- AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
}
+ else
+ AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
}
- else
- AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
}
+}
#endif /* RTTHREAD_POSIX_WITH_POKE */
+
+DECLHIDDEN(int) rtThreadNativeInit(void)
+{
+ /*
+ * Allocate the TLS (key in posix terms) where we store the pointer to
+ * a threads RTTHREADINT structure.
+ */
+ int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct);
+ if (rc)
+ return VERR_NO_TLS_FOR_SELF;
+
+#ifdef RTTHREAD_POSIX_WITH_POKE
+ rtThreadPosixSelectPokeSignal();
+#endif
+
#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
if (RT_SUCCESS(rc))
g_pfnThreadSetName = (PFNPTHREADSETNAME)(uintptr_t)dlsym(RTLD_DEFAULT, "pthread_setname_np");
@@ -179,6 +197,35 @@ DECLHIDDEN(int) rtThreadNativeInit(void)
return rc;
}
+static void rtThreadPosixBlockSignals(void)
+{
+ /*
+ * Block SIGALRM - required for timer-posix.cpp.
+ * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
+ * It will not help much if someone creates threads directly using pthread_create. :/
+ */
+ if (!RTR3InitIsUnobtrusive())
+ {
+ sigset_t SigSet;
+ sigemptyset(&SigSet);
+ sigaddset(&SigSet, SIGALRM);
+ sigprocmask(SIG_BLOCK, &SigSet, NULL);
+ }
+#ifdef RTTHREAD_POSIX_WITH_POKE
+ if (g_iSigPokeThread != -1)
+ siginterrupt(g_iSigPokeThread, 1);
+#endif
+}
+
+DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void)
+{
+#ifdef RTTHREAD_POSIX_WITH_POKE
+ Assert(!RTR3InitIsUnobtrusive());
+ rtThreadPosixSelectPokeSignal();
+#endif
+ rtThreadPosixBlockSignals();
+}
+
/**
* Destructor called when a thread terminates.
@@ -221,19 +268,7 @@ static void rtThreadPosixPokeSignal(int iSignal)
*/
DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
{
- /*
- * Block SIGALRM - required for timer-posix.cpp.
- * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
- * It will not help much if someone creates threads directly using pthread_create. :/
- */
- sigset_t SigSet;
- sigemptyset(&SigSet);
- sigaddset(&SigSet, SIGALRM);
- sigprocmask(SIG_BLOCK, &SigSet, NULL);
-#ifdef RTTHREAD_POSIX_WITH_POKE
- if (g_iSigPokeThread != -1)
- siginterrupt(g_iSigPokeThread, 1);
-#endif
+ rtThreadPosixBlockSignals();
int rc = pthread_setspecific(g_SelfKey, pThread);
if (!rc)
@@ -266,19 +301,7 @@ static void *rtThreadNativeMain(void *pvArgs)
ASMMemoryFence();
#endif
- /*
- * Block SIGALRM - required for timer-posix.cpp.
- * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
- * It will not help much if someone creates threads directly using pthread_create. :/
- */
- sigset_t SigSet;
- sigemptyset(&SigSet);
- sigaddset(&SigSet, SIGALRM);
- sigprocmask(SIG_BLOCK, &SigSet, NULL);
-#ifdef RTTHREAD_POSIX_WITH_POKE
- if (g_iSigPokeThread != -1)
- siginterrupt(g_iSigPokeThread, 1);
-#endif
+ rtThreadPosixBlockSignals();
/*
* Set the TLS entry and, if possible, the thread name.
@@ -412,6 +435,15 @@ RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUs
*pUserTime = ThreadInfo.user_time.seconds * 1000 + ThreadInfo.user_time.microseconds / 1000;
return VINF_SUCCESS;
+#elif defined(RT_OS_HAIKU)
+ thread_info ThreadInfo;
+ status_t status = get_thread_info(find_thread(NULL), &ThreadInfo);
+ AssertReturn(status == B_OK, RTErrConvertFromErrno(status));
+
+ *pKernelTime = ThreadInfo.kernel_time / 1000;
+ *pUserTime = ThreadInfo.user_time / 1000;
+
+ return VINF_SUCCESS;
#else
return VERR_NOT_IMPLEMENTED;
#endif
diff --git a/src/VBox/Runtime/r3/posix/thread2-posix.cpp b/src/VBox/Runtime/r3/posix/thread2-posix.cpp
index b0402ed0..bd7e030e 100644
--- a/src/VBox/Runtime/r3/posix/thread2-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/thread2-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -62,7 +62,7 @@ RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies)
pthread_yield_np();
#elif defined(RT_OS_FREEBSD) /* void pthread_yield */
pthread_yield();
-#elif defined(RT_OS_SOLARIS)
+#elif defined(RT_OS_SOLARIS) || defined(RT_OS_HAIKU)
sched_yield();
#else
if (!pthread_yield())
@@ -101,7 +101,7 @@ RTDECL(int) RTThreadSleepNoLog(RTMSINTERVAL cMillies)
pthread_yield_np();
#elif defined(RT_OS_FREEBSD) /* void pthread_yield */
pthread_yield();
-#elif defined(RT_OS_SOLARIS)
+#elif defined(RT_OS_SOLARIS) || defined(RT_OS_HAIKU)
sched_yield();
#else
if (!pthread_yield())
@@ -130,7 +130,7 @@ RTDECL(bool) RTThreadYield(void)
#endif
#ifdef RT_OS_DARWIN
pthread_yield_np();
-#elif defined(RT_OS_SOLARIS)
+#elif defined(RT_OS_SOLARIS) || defined(RT_OS_HAIKU)
sched_yield();
#else
pthread_yield();
diff --git a/src/VBox/Runtime/r3/posix/time-posix.cpp b/src/VBox/Runtime/r3/posix/time-posix.cpp
index bdb3dcb7..6f313afd 100644
--- a/src/VBox/Runtime/r3/posix/time-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/time-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/timelocal-posix.cpp b/src/VBox/Runtime/r3/posix/timelocal-posix.cpp
index d65c0167..ce60f751 100644
--- a/src/VBox/Runtime/r3/posix/timelocal-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/timelocal-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/timer-posix.cpp b/src/VBox/Runtime/r3/posix/timer-posix.cpp
index f6e75492..043709a1 100644
--- a/src/VBox/Runtime/r3/posix/timer-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/timer-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -57,6 +57,7 @@
#include <iprt/string.h>
#include <iprt/once.h>
#include <iprt/err.h>
+#include <iprt/initterm.h>
#include <iprt/critsect.h>
#include "internal/magics.h"
@@ -152,14 +153,12 @@ typedef struct RTTIMER
* RTOnce callback that initializes the critical section.
*
* @returns RTCritSectInit return code.
- * @param pvUser1 NULL, ignored.
- * @param pvUser2 NULL, ignored.
+ * @param pvUser NULL, ignored.
*
*/
-static DECLCALLBACK(int) rtTimerOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int) rtTimerOnce(void *pvUser)
{
- NOREF(pvUser1);
- NOREF(pvUser2);
+ NOREF(pvUser);
return RTCritSectInit(&g_TimerCritSect);
}
#endif
@@ -406,6 +405,13 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
return VERR_NOT_SUPPORTED;
+ /*
+ * We need the signal masks to be set correctly, which they won't be in
+ * unobtrusive mode.
+ */
+ if (RTR3InitIsUnobtrusive())
+ return VERR_NOT_SUPPORTED;
+
#ifndef IPRT_WITH_POSIX_TIMERS
/*
* Check if timer is busy.
@@ -539,7 +545,7 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
/*
* Do the global init first.
*/
- int rc = RTOnce(&g_TimerOnce, rtTimerOnce, NULL, NULL);
+ int rc = RTOnce(&g_TimerOnce, rtTimerOnce, NULL);
if (RT_FAILURE(rc))
return rc;
diff --git a/src/VBox/Runtime/r3/posix/tls-posix.cpp b/src/VBox/Runtime/r3/posix/tls-posix.cpp
index c8005a59..c79e6e22 100644
--- a/src/VBox/Runtime/r3/posix/tls-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/tls-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/posix/utf8-posix.cpp b/src/VBox/Runtime/r3/posix/utf8-posix.cpp
index 35ae6f3d..cb723eb7 100644
--- a/src/VBox/Runtime/r3/posix/utf8-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/utf8-posix.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -193,11 +193,13 @@ static int rtstrConvertCached(const void *pvInput, size_t cbInput, const char *p
size_t cbOutLeft = cbOutput2;
const void *pvInputLeft = pvInput;
void *pvOutputLeft = pvOutput;
-#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */
- if (iconv(hIconv, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1)
+ size_t cchNonRev;
+#if defined(RT_OS_LINUX) || defined(RT_OS_HAIKU) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */
+ cchNonRev = iconv(hIconv, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft);
#else
- if (iconv(hIconv, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1)
+ cchNonRev = iconv(hIconv, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft);
#endif
+ if (cchNonRev != (size_t)-1)
{
if (!cbInLeft)
{
@@ -209,7 +211,9 @@ static int rtstrConvertCached(const void *pvInput, size_t cbInput, const char *p
if (fUcs2Term)
((char *)pvOutputLeft)[1] = '\0';
*ppvOutput = pvOutput;
- return VINF_SUCCESS;
+ if (cchNonRev == 0)
+ return VINF_SUCCESS;
+ return VWRN_NO_TRANSLATION;
}
errno = E2BIG;
}
@@ -319,11 +323,13 @@ static int rtStrConvertUncached(const void *pvInput, size_t cbInput, const char
size_t cbOutLeft = cbOutput2;
const void *pvInputLeft = pvInput;
void *pvOutputLeft = pvOutput;
-#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */
- if (iconv(icHandle, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1)
+ size_t cchNonRev;
+#if defined(RT_OS_LINUX) || defined(RT_OS_HAIKU) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */
+ cchNonRev = iconv(icHandle, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft);
#else
- if (iconv(icHandle, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1)
+ cchNonRev = iconv(icHandle, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft);
#endif
+ if (cchNonRev != (size_t)-1)
{
if (!cbInLeft)
{
@@ -336,7 +342,9 @@ static int rtStrConvertUncached(const void *pvInput, size_t cbInput, const char
if (fUcs2Term)
((char *)pvOutputLeft)[1] = '\0';
*ppvOutput = pvOutput;
- return VINF_SUCCESS;
+ if (cchNonRev == 0)
+ return VINF_SUCCESS;
+ return VWRN_NO_TRANSLATION;
}
errno = E2BIG;
}
diff --git a/src/VBox/Runtime/r3/process.cpp b/src/VBox/Runtime/r3/process.cpp
index 7be307f3..9f47814d 100644
--- a/src/VBox/Runtime/r3/process.cpp
+++ b/src/VBox/Runtime/r3/process.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/socket.cpp b/src/VBox/Runtime/r3/socket.cpp
index 42d42883..8678c37b 100644
--- a/src/VBox/Runtime/r3/socket.cpp
+++ b/src/VBox/Runtime/r3/socket.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,6 +33,7 @@
# include <ws2tcpip.h>
#else /* !RT_OS_WINDOWS */
# include <errno.h>
+# include <sys/select.h>
# include <sys/stat.h>
# include <sys/socket.h>
# include <netinet/in.h>
@@ -110,6 +111,15 @@
/** How many pending connection. */
#define RTTCP_SERVER_BACKLOG 10
+/* Limit read and write sizes on Windows and OS/2. */
+#ifdef RT_OS_WINDOWS
+# define RTSOCKET_MAX_WRITE (INT_MAX / 2)
+# define RTSOCKET_MAX_READ (INT_MAX / 2)
+#elif defined(RT_OS_OS2)
+# define RTSOCKET_MAX_WRITE 0x10000
+# define RTSOCKET_MAX_READ 0x10000
+#endif
+
/*******************************************************************************
* Structures and Typedefs *
@@ -135,13 +145,15 @@ typedef struct RTSOCKETINT
/** Indicates whether the socket is operating in blocking or non-blocking mode
* currently. */
bool fBlocking;
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ /** The pollset currently polling this socket. This is NIL if no one is
+ * polling. */
+ RTPOLLSET hPollSet;
+#endif
#ifdef RT_OS_WINDOWS
/** The event semaphore we've associated with the socket handle.
* This is WSA_INVALID_EVENT if not done. */
WSAEVENT hEvent;
- /** The pollset currently polling this socket. This is NIL if no one is
- * polling. */
- RTPOLLSET hPollSet;
/** The events we're polling for. */
uint32_t fPollEvts;
/** The events we're currently subscribing to with WSAEventSelect.
@@ -397,9 +409,11 @@ int rtSocketCreateForNative(RTSOCKETINT **ppSocket, RTSOCKETNATIVE hNative)
pThis->hNative = hNative;
pThis->fClosed = false;
pThis->fBlocking = true;
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ pThis->hPollSet = NIL_RTPOLLSET;
+#endif
#ifdef RT_OS_WINDOWS
pThis->hEvent = WSA_INVALID_EVENT;
- pThis->hPollSet = NIL_RTPOLLSET;
pThis->fPollEvts = 0;
pThis->fSubscribedEvts = 0;
#endif
@@ -853,8 +867,8 @@ RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size
for (;;)
{
rtSocketErrorReset();
-#ifdef RT_OS_WINDOWS
- int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead;
+#ifdef RTSOCKET_MAX_READ
+ int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead;
#else
size_t cbNow = cbToRead;
#endif
@@ -920,8 +934,8 @@ RTDECL(int) RTSocketReadFrom(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer,
size_t cbToRead = cbBuffer;
rtSocketErrorReset();
RTSOCKADDRUNION u;
-#ifdef RT_OS_WINDOWS
- int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead;
+#ifdef RTSOCKET_MAX_READ
+ int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead;
int cbAddr = sizeof(u);
#else
size_t cbNow = cbToRead;
@@ -967,8 +981,8 @@ RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffe
/*
* Try write all at once.
*/
-#ifdef RT_OS_WINDOWS
- int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
+#ifdef RTSOCKET_MAX_WRITE
+ int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
#else
size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
#endif
@@ -994,8 +1008,8 @@ RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffe
pvBuffer = (char const *)pvBuffer + cbWritten;
/* send */
-#ifdef RT_OS_WINDOWS
- cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
+#ifdef RTSOCKET_MAX_WRITE
+ cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
#else
cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
#endif
@@ -1056,7 +1070,7 @@ RTDECL(int) RTSocketWriteTo(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuf
* Must write all at once, otherwise it is a failure.
*/
#ifdef RT_OS_WINDOWS
- int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
+ int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
#else
size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
#endif
@@ -1201,9 +1215,13 @@ RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, si
return rc;
rtSocketErrorReset();
-#ifdef RT_OS_WINDOWS
- int cbNow = cbBuffer >= INT_MAX/2 ? INT_MAX/2 : (int)cbBuffer;
+#ifdef RTSOCKET_MAX_READ
+ int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
+#else
+ size_t cbNow = cbBuffer;
+#endif
+#ifdef RT_OS_WINDOWS
int cbRead = recv(pThis->hNative, (char *)pvBuffer, cbNow, MSG_NOSIGNAL);
if (cbRead >= 0)
{
@@ -1216,7 +1234,7 @@ RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, si
if (rc == VERR_TRY_AGAIN)
rc = VINF_TRY_AGAIN;
#else
- ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbBuffer, MSG_NOSIGNAL);
+ ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbNow, MSG_NOSIGNAL);
if (cbRead >= 0)
*pcbRead = cbRead;
else if (errno == EAGAIN)
@@ -1249,11 +1267,14 @@ RTDECL(int) RTSocketWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuf
return rc;
rtSocketErrorReset();
-#ifdef RT_OS_WINDOWS
- int cbNow = RT_MIN((int)cbBuffer, INT_MAX/2);
+#ifdef RTSOCKET_MAX_WRITE
+ int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
+#else
+ size_t cbNow = cbBuffer;
+#endif
+#ifdef RT_OS_WINDOWS
int cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
-
if (cbWritten >= 0)
{
*pcbWritten = cbWritten;
@@ -1752,7 +1773,6 @@ int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValu
return rc;
}
-#ifdef RT_OS_WINDOWS
/**
* Internal RTPollSetAdd helper that returns the handle that should be added to
@@ -1761,29 +1781,37 @@ int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValu
* @returns Valid handle on success, INVALID_HANDLE_VALUE on failure.
* @param hSocket The socket handle.
* @param fEvents The events we're polling for.
- * @param ph where to put the primary handle.
+ * @param phNative Where to put the primary handle.
*/
-int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PHANDLE ph)
+int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PRTHCINTPTR phNative)
{
RTSOCKETINT *pThis = hSocket;
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
+#ifdef RT_OS_WINDOWS
AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
int rc = VINF_SUCCESS;
if (pThis->hEvent != WSA_INVALID_EVENT)
- *ph = pThis->hEvent;
+ *phNative = (RTHCINTPTR)pThis->hEvent;
else
{
- *ph = pThis->hEvent = WSACreateEvent();
+ pThis->hEvent = WSACreateEvent();
+ *phNative = (RTHCINTPTR)pThis->hEvent;
if (pThis->hEvent == WSA_INVALID_EVENT)
rc = rtSocketError();
}
rtSocketUnlock(pThis);
return rc;
+
+#else /* !RT_OS_WINDOWS */
+ *phNative = (RTHCUINTPTR)pThis->hNative;
+ return VINF_SUCCESS;
+#endif /* !RT_OS_WINDOWS */
}
+#ifdef RT_OS_WINDOWS
/**
* Undos the harm done by WSAEventSelect.
@@ -1853,6 +1881,10 @@ static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
return rc;
}
+#endif /* RT_OS_WINDOWS */
+
+
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
/**
* Checks for pending events.
@@ -1863,12 +1895,13 @@ static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
*/
static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents)
{
- int rc = VINF_SUCCESS;
- uint32_t fRetEvents = 0;
+ uint32_t fRetEvents = 0;
LogFlowFunc(("pThis=%#p fEvents=%#x\n", pThis, fEvents));
+# ifdef RT_OS_WINDOWS
/* Make sure WSAEnumNetworkEvents returns what we want. */
+ int rc = VINF_SUCCESS;
if ((pThis->fSubscribedEvts & fEvents) != fEvents)
rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
@@ -1904,8 +1937,23 @@ static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents)
/* Fall back on select if we hit an error above. */
if (RT_FAILURE(rc))
{
- /** @todo */
+
+ }
+
+#else /* RT_OS_OS2 */
+ int aFds[4] = { pThis->hNative, pThis->hNative, pThis->hNative, -1 };
+ int rc = os2_select(aFds, 1, 1, 1, 0);
+ if (rc > 0)
+ {
+ if (aFds[0] == pThis->hNative)
+ fRetEvents |= RTPOLL_EVT_READ;
+ if (aFds[1] == pThis->hNative)
+ fRetEvents |= RTPOLL_EVT_WRITE;
+ if (aFds[2] == pThis->hNative)
+ fRetEvents |= RTPOLL_EVT_ERROR;
+ fRetEvents &= fEvents;
}
+#endif /* RT_OS_OS2 */
LogFlowFunc(("fRetEvents=%#x\n", fRetEvents));
return fRetEvents;
@@ -1939,6 +1987,8 @@ uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvent
RTSOCKETINT *pThis = hSocket;
AssertPtrReturn(pThis, UINT32_MAX);
AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
+ /** @todo This isn't quite sane. Replace by critsect and open up concurrent
+ * reads and writes! */
if (rtSocketTryLock(pThis))
pThis->hPollSet = hPollSet;
else
@@ -1948,6 +1998,7 @@ uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvent
}
/* (rtSocketPollCheck will reset the event object). */
+# ifdef RT_OS_WINDOWS
uint32_t fRetEvents = pThis->fEventsSaved;
pThis->fEventsSaved = 0; /* Reset */
fRetEvents |= rtSocketPollCheck(pThis, fEvents);
@@ -1967,12 +2018,17 @@ uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvent
}
}
}
+# else
+ uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
+# endif
if (fRetEvents || fNoWait)
{
if (pThis->cUsers == 1)
{
+# ifdef RT_OS_WINDOWS
rtSocketPollClearEventAndRestoreBlocking(pThis);
+# endif
pThis->hPollSet = NIL_RTPOLLSET;
}
ASMAtomicDecU32(&pThis->cUsers);
@@ -2008,6 +2064,7 @@ uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry,
/* Harvest events and clear the event mask for the next round of polling. */
uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
+# ifdef RT_OS_WINDOWS
pThis->fPollEvts = 0;
/*
@@ -2021,15 +2078,19 @@ uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry,
pThis->fEventsSaved = fRetEvents;
fRetEvents = 0;
}
+# endif
/* Make the socket blocking again and unlock the handle. */
if (pThis->cUsers == 1)
{
+# ifdef RT_OS_WINDOWS
rtSocketPollClearEventAndRestoreBlocking(pThis);
+# endif
pThis->hPollSet = NIL_RTPOLLSET;
}
ASMAtomicDecU32(&pThis->cUsers);
return fRetEvents;
}
-#endif /* RT_OS_WINDOWS */
+#endif /* RT_OS_WINDOWS || RT_OS_OS2 */
+
diff --git a/src/VBox/Runtime/r3/solaris/Makefile.kup b/src/VBox/Runtime/r3/solaris/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/Runtime/r3/solaris/Makefile.kup
diff --git a/src/VBox/Runtime/r3/solaris/RTSystemShutdown-solaris.cpp b/src/VBox/Runtime/r3/solaris/RTSystemShutdown-solaris.cpp
new file mode 100644
index 00000000..44906788
--- /dev/null
+++ b/src/VBox/Runtime/r3/solaris/RTSystemShutdown-solaris.cpp
@@ -0,0 +1,102 @@
+/* $Id: RTSystemShutdown-solaris.cpp $ */
+/** @file
+ * IPRT - RTSystemShutdown, linux implementation.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/system.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/env.h>
+#include <iprt/err.h>
+#include <iprt/process.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char *pszLogMsg)
+{
+ AssertPtrReturn(pszLogMsg, VERR_INVALID_POINTER);
+ AssertReturn(!(fFlags & ~RTSYSTEM_SHUTDOWN_VALID_MASK), VERR_INVALID_PARAMETER);
+
+ /*
+ * Assemble the argument vector.
+ */
+ int iArg = 0;
+ const char *apszArgs[8];
+
+ RT_BZERO(apszArgs, sizeof(apszArgs));
+
+ apszArgs[iArg++] = "/usr/sbin/shutdown";
+ apszArgs[iArg++] = "-y"; /* Pre-answer confirmation question. */
+ apszArgs[iArg++] = "-i"; /* Change to the following state. */
+ switch (fFlags & RTSYSTEM_SHUTDOWN_ACTION_MASK)
+ {
+ case RTSYSTEM_SHUTDOWN_HALT:
+ apszArgs[iArg++] = "0";
+ break;
+ case RTSYSTEM_SHUTDOWN_REBOOT:
+ apszArgs[iArg++] = "6";
+ break;
+ case RTSYSTEM_SHUTDOWN_POWER_OFF:
+ case RTSYSTEM_SHUTDOWN_POWER_OFF_HALT:
+ apszArgs[iArg++] = "5";
+ break;
+ }
+
+ apszArgs[iArg++] = "-g"; /* Grace period. */
+
+ char szWhen[80];
+ if (cMsDelay < 500)
+ strcpy(szWhen, "0");
+ else
+ RTStrPrintf(szWhen, sizeof(szWhen), "%u", (unsigned)((cMsDelay + 499) / 1000));
+ apszArgs[iArg++] = szWhen;
+
+ apszArgs[iArg++] = pszLogMsg;
+
+
+ /*
+ * Start the shutdown process and wait for it to complete.
+ */
+ RTPROCESS hProc;
+ int rc = RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &hProc);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ RTPROCSTATUS ProcStatus;
+ rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus);
+ if (RT_SUCCESS(rc))
+ {
+ if ( ProcStatus.enmReason != RTPROCEXITREASON_NORMAL
+ || ProcStatus.iStatus != 0)
+ rc = VERR_SYS_SHUTDOWN_FAILED;
+ }
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp b/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp
index 39726eda..66ef5286 100644
--- a/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp
+++ b/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010-2011 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -162,7 +162,7 @@ static int ReadFileNoIntr(int fd, void *pv, size_t cbToRead)
*
* @param fd Handle to the file to write to.
* @param pv Pointer to what to write.
- * @param cbToWrite Size of data to write.
+ * @param cbToWrite Size of data to write.
*
* @return IPRT status code.
*/
@@ -191,9 +191,9 @@ static int WriteFileNoIntr(int fd, const void *pv, size_t cbToWrite)
* Read from a given offset in the process' address space.
*
* @param pSolProc Pointer to the solaris process.
- * @param pv Where to read the data into.
- * @param cb Size of the read buffer.
- * @param off Offset to read from.
+ * @param off The offset to read from.
+ * @param pvBuf Where to read the data into.
+ * @param cbToRead Number of bytes to read.
*
* @return VINF_SUCCESS, if all the given bytes was read in, otherwise VERR_READ_ERROR.
*/
@@ -1263,51 +1263,8 @@ static int rtCoreDumperResumeThreads(PRTSOLCORE pSolCore)
{
AssertReturn(pSolCore, VERR_INVALID_POINTER);
-#if 1
uint64_t cThreads;
return rtCoreDumperForEachThread(pSolCore, &cThreads, resumeThread);
-#else
- PRTSOLCOREPROCESS pSolProc = &pSolCore->SolProc;
-
- char szCurThread[128];
- char szPath[PATH_MAX];
- PRTDIR pDir = NULL;
-
- RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/lwp", (int)pSolProc->Process);
- RTStrPrintf(szCurThread, sizeof(szCurThread), "%d", (int)pSolProc->hCurThread);
-
- int32_t cRunningThreads = 0;
- int rc = RTDirOpen(&pDir, szPath);
- if (RT_SUCCESS(rc))
- {
- /*
- * Loop through all our threads & resume them.
- */
- RTDIRENTRY DirEntry;
- while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
- {
- if ( !strcmp(DirEntry.szName, ".")
- || !strcmp(DirEntry.szName, ".."))
- continue;
-
- if ( !strcmp(DirEntry.szName, szCurThread))
- continue;
-
- int32_t ThreadId = RTStrToInt32(DirEntry.szName);
- _lwp_continue((lwpid_t)ThreadId);
- ++cRunningThreads;
- }
-
- CORELOG((CORELOG_NAME "ResumeAllThreads: resumed %d threads\n", cRunningThreads));
- RTDirClose(pDir);
- }
- else
- {
- CORELOGRELSYS((CORELOG_NAME "ResumeAllThreads: Failed to open %s\n", szPath));
- rc = VERR_READ_ERROR;
- }
- return rc;
-#endif
}
@@ -2116,8 +2073,7 @@ static int rtCoreDumperDestroyCore(PRTSOLCORE pSolCore)
/**
- * Takes a core dump. This function has no other parameters than the context
- * because it can be called from signal handlers.
+ * Takes a core dump.
*
* @param pContext The context of the caller.
* @param pszOutputFile Path of the core file. If NULL is passed, the
diff --git a/src/VBox/Runtime/r3/solaris/coredumper-solaris.h b/src/VBox/Runtime/r3/solaris/coredumper-solaris.h
index 127fd9be..662effc6 100644
--- a/src/VBox/Runtime/r3/solaris/coredumper-solaris.h
+++ b/src/VBox/Runtime/r3/solaris/coredumper-solaris.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010-2011 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp b/src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp
index 2b6d60b8..2f218305 100644
--- a/src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp
+++ b/src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -55,6 +55,8 @@ typedef struct RTFILEAIOCTXINTERNAL
int iPort;
/** Current number of requests active on this context. */
volatile int32_t cRequests;
+ /** Flags given during creation. */
+ uint32_t fFlags;
/** Magic value (RTFILEAIOCTX_MAGIC). */
uint32_t u32Magic;
} RTFILEAIOCTXINTERNAL;
@@ -270,11 +272,13 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered)
return RTErrConvertFromErrno(rcSol);
}
-RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
+RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax,
+ uint32_t fFlags)
{
int rc = VINF_SUCCESS;
PRTFILEAIOCTXINTERNAL pCtxInt;
AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER);
+ AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL));
if (RT_UNLIKELY(!pCtxInt))
@@ -284,7 +288,8 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
pCtxInt->iPort = port_create();
if (RT_LIKELY(pCtxInt->iPort > 0))
{
- pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC;
+ pCtxInt->fFlags = fFlags;
+ pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC;
*phAioCtx = (RTFILEAIOCTX)pCtxInt;
}
else
@@ -448,7 +453,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL
AssertReturn(cReqs != 0, VERR_INVALID_PARAMETER);
AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE);
- if (RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0))
+ if ( RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0)
+ && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS))
return VERR_FILE_AIO_NO_REQUEST;
/*
diff --git a/src/VBox/Runtime/r3/solaris/mp-solaris.cpp b/src/VBox/Runtime/r3/solaris/mp-solaris.cpp
index 0f2c6fdf..d21bbb42 100644
--- a/src/VBox/Runtime/r3/solaris/mp-solaris.cpp
+++ b/src/VBox/Runtime/r3/solaris/mp-solaris.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -57,19 +57,77 @@ static kstat_ctl_t *g_pKsCtl;
static kstat_t **g_papCpuInfo;
/** The number of entries in g_papCpuInfo */
static RTCPUID g_capCpuInfo;
+/** Array of core ids. */
+static uint64_t *g_pu64CoreIds;
+/** Number of entries in g_pu64CoreIds. */
+static size_t g_cu64CoreIds;
+/** Number of cores in the system. */
+static size_t g_cCores;
+
+
+/**
+ * Helper for getting the core ID for a given CPU/strand/hyperthread.
+ *
+ * @returns The core ID.
+ * @param idCpu The CPU ID instance.
+ */
+static inline uint64_t rtMpSolarisGetCoreId(RTCPUID idCpu)
+{
+ kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char *)"core_id");
+ Assert(pStat->data_type == KSTAT_DATA_LONG);
+ Assert(pStat->value.l >= 0);
+ AssertCompile(sizeof(uint64_t) >= sizeof(long)); /* Paranoia. */
+ return (uint64_t)pStat->value.l;
+}
+
+
+/**
+ * Populates 'g_pu64CoreIds' array with unique core identifiers in the system.
+ *
+ * @returns VBox status code.
+ */
+static int rtMpSolarisGetCoreIds(void)
+{
+ for (RTCPUID idCpu = 0; idCpu < g_capCpuInfo; idCpu++)
+ {
+ if (kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0) != -1)
+ {
+ /* Strands/Hyperthreads share the same core ID. */
+ uint64_t u64CoreId = rtMpSolarisGetCoreId(idCpu);
+ bool fAddedCore = false;
+ for (RTCPUID i = 0; i < g_cCores; i++)
+ {
+ if (g_pu64CoreIds[i] == u64CoreId)
+ {
+ fAddedCore = true;
+ break;
+ }
+ }
+
+ if (!fAddedCore)
+ {
+ g_pu64CoreIds[g_cCores] = u64CoreId;
+ ++g_cCores;
+ }
+ }
+ else
+ return VERR_INTERNAL_ERROR_2;
+ }
+
+ return VINF_SUCCESS;
+}
/**
* Run once function that initializes the kstats we need here.
*
* @returns IPRT status code.
- * @param pvUser1 Unused.
- * @param pvUser2 Unused.
+ * @param pvUser Unused.
*/
-static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser)
{
int rc = VINF_SUCCESS;
- NOREF(pvUser1); NOREF(pvUser2);
+ NOREF(pvUser);
/*
* Open kstat and find the cpu_info entries for each of the CPUs.
@@ -81,25 +139,40 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2)
g_papCpuInfo = (kstat_t **)RTMemAllocZ(g_capCpuInfo * sizeof(kstat_t *));
if (g_papCpuInfo)
{
- rc = RTCritSectInit(&g_MpSolarisCritSect);
- if (RT_SUCCESS(rc))
+ g_cu64CoreIds = g_capCpuInfo;
+ g_pu64CoreIds = (uint64_t *)RTMemAllocZ(g_cu64CoreIds * sizeof(uint64_t));
+ if (g_pu64CoreIds)
{
- RTCPUID i = 0;
- for (kstat_t *pKsp = g_pKsCtl->kc_chain; pKsp != NULL; pKsp = pKsp->ks_next)
+ rc = RTCritSectInit(&g_MpSolarisCritSect);
+ if (RT_SUCCESS(rc))
{
- if (!strcmp(pKsp->ks_module, "cpu_info"))
+ RTCPUID i = 0;
+ for (kstat_t *pKsp = g_pKsCtl->kc_chain; pKsp != NULL; pKsp = pKsp->ks_next)
{
- AssertBreak(i < g_capCpuInfo);
- g_papCpuInfo[i++] = pKsp;
- /** @todo ks_instance == cpu_id (/usr/src/uts/common/os/cpu.c)? Check this and fix it ASAP. */
+ if (!RTStrCmp(pKsp->ks_module, "cpu_info"))
+ {
+ AssertBreak(i < g_capCpuInfo);
+ g_papCpuInfo[i++] = pKsp;
+ /** @todo ks_instance == cpu_id (/usr/src/uts/common/os/cpu.c)? Check this and fix it ASAP. */
+ }
}
+
+ rc = rtMpSolarisGetCoreIds();
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+ else
+ Log(("rtMpSolarisGetCoreIds failed. rc=%Rrc\n", rc));
}
- return VINF_SUCCESS;
+ RTMemFree(g_pu64CoreIds);
+ g_pu64CoreIds = NULL;
}
+ else
+ rc = VERR_NO_MEMORY;
/* bail out, we failed. */
RTMemFree(g_papCpuInfo);
+ g_papCpuInfo = NULL;
}
else
rc = VERR_NO_MEMORY;
@@ -119,6 +192,21 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2)
/**
+ * RTOnceEx() cleanup function.
+ *
+ * @param pvUser Unused.
+ * @param fLazyCleanUpOk Whether lazy cleanup is okay or not.
+ */
+static DECLCALLBACK(void) rtMpSolarisCleanUp(void *pvUser, bool fLazyCleanUpOk)
+{
+ if (g_pKsCtl)
+ kstat_close(g_pKsCtl);
+ RTMemFree(g_pu64CoreIds);
+ RTMemFree(g_papCpuInfo);
+}
+
+
+/**
* Worker for RTMpGetCurFrequency and RTMpGetMaxFrequency.
*
* @returns The desired frequency on success, 0 on failure.
@@ -126,10 +214,10 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2)
* @param idCpu The CPU ID.
* @param pszStatName The cpu_info stat name.
*/
-static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, char *pszStatName)
+static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, const char *pszStatName)
{
uint64_t u64 = 0;
- int rc = RTOnce(&g_MpSolarisOnce, rtMpSolarisOnce, NULL, NULL);
+ int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */);
if (RT_SUCCESS(rc))
{
if ( idCpu < g_capCpuInfo
@@ -141,7 +229,8 @@ static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, char *pszStatName)
{
if (kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0) != -1)
{
- kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], pszStatName);
+ /* Solaris really need to fix their APIs. Explicitly cast for now. */
+ kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char*)pszStatName);
if (pStat)
{
Assert(pStat->data_type == KSTAT_DATA_UINT64 || pStat->data_type == KSTAT_DATA_LONG);
@@ -280,7 +369,7 @@ RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
RTDECL(PRTCPUSET) RTMpGetPresentSet(PRTCPUSET pSet)
{
#ifdef RT_STRICT
- long cCpusPresent = 0;
+ RTCPUID cCpusPresent = 0;
#endif
RTCpuSetEmpty(pSet);
RTCPUID cCpus = RTMpGetCount();
@@ -305,3 +394,60 @@ RTDECL(RTCPUID) RTMpGetPresentCount(void)
return sysconf(_SC_NPROCESSORS_CONF);
}
+
+RTDECL(RTCPUID) RTMpGetPresentCoreCount(void)
+{
+ return RTMpGetCoreCount();
+}
+
+
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */);
+ if (RT_SUCCESS(rc))
+ return g_cCores;
+
+ return 0;
+}
+
+
+RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void)
+{
+ RTCPUID uOnlineCores = 0;
+ int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCritSectEnter(&g_MpSolarisCritSect);
+ AssertRC(rc);
+
+ /*
+ * For each core in the system, count how many are currently online.
+ */
+ for (RTCPUID j = 0; j < g_cCores; j++)
+ {
+ uint64_t u64CoreId = g_pu64CoreIds[j];
+ for (RTCPUID idCpu = 0; idCpu < g_capCpuInfo; idCpu++)
+ {
+ rc = kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0);
+ AssertReturn(rc != -1, 0 /* rc */);
+ uint64_t u64ThreadCoreId = rtMpSolarisGetCoreId(idCpu);
+ if (u64ThreadCoreId == u64CoreId)
+ {
+ kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char *)"state");
+ Assert(pStat->data_type == KSTAT_DATA_CHAR);
+ if( !RTStrNCmp(pStat->value.c, PS_ONLINE, sizeof(PS_ONLINE) - 1)
+ || !RTStrNCmp(pStat->value.c, PS_NOINTR, sizeof(PS_NOINTR) - 1))
+ {
+ uOnlineCores++;
+ break; /* Move to the next core. We have at least 1 hyperthread online in the current core. */
+ }
+ }
+ }
+ }
+
+ RTCritSectLeave(&g_MpSolarisCritSect);
+ }
+
+ return uOnlineCores;
+}
+
diff --git a/src/VBox/Runtime/r3/solaris/rtProcInitExePath-solaris.cpp b/src/VBox/Runtime/r3/solaris/rtProcInitExePath-solaris.cpp
index 40baf8c2..ffaad258 100644
--- a/src/VBox/Runtime/r3/solaris/rtProcInitExePath-solaris.cpp
+++ b/src/VBox/Runtime/r3/solaris/rtProcInitExePath-solaris.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/solaris/systemmem-solaris.cpp b/src/VBox/Runtime/r3/solaris/systemmem-solaris.cpp
new file mode 100644
index 00000000..e5efe631
--- /dev/null
+++ b/src/VBox/Runtime/r3/solaris/systemmem-solaris.cpp
@@ -0,0 +1,172 @@
+/* $Id: systemmem-solaris.cpp $ */
+/** @file
+ * IPRT - RTSystemQueryTotalRam, Solaris ring-3.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/system.h>
+#include "internal/iprt.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/once.h>
+#include <iprt/param.h>
+
+#include <errno.h>
+#include <kstat.h>
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** Initialize globals once. */
+static RTONCE g_rtSysMemSolInitOnce = RTONCE_INITIALIZER;
+/** Critical section serializing access to g_pKStatCtl and the other handles. */
+static RTCRITSECT g_rtSysMemSolCritSect;
+/** The kstate control handle. */
+static kstat_ctl_t *g_pKStatCtl = NULL;
+/** The unix.system_pages handle. */
+static kstat_t *g_pUnixSysPages = NULL;
+/** The zfs.archstats handle. */
+static kstat_t *g_pZfsArcStats = NULL;
+
+
+/** @callback_method_impl{FNRTONCE} */
+static DECLCALLBACK(int) rtSysMemSolInit(void *pvUser)
+{
+ int rc = RTCritSectInit(&g_rtSysMemSolCritSect);
+ if (RT_SUCCESS(rc))
+ {
+ g_pKStatCtl = kstat_open();
+ if (g_pKStatCtl)
+ {
+ g_pUnixSysPages = kstat_lookup(g_pKStatCtl, (char *)"unix", 0, (char *)"system_pages");
+ if (g_pUnixSysPages)
+ {
+ g_pZfsArcStats = kstat_lookup(g_pKStatCtl, (char *)"zfs", 0, (char *)"arcstats"); /* allow NULL */
+ return VINF_SUCCESS;
+ }
+
+ rc = RTErrConvertFromErrno(errno);
+ kstat_close(g_pKStatCtl);
+ g_pKStatCtl = NULL;
+ }
+ else
+ rc = RTErrConvertFromErrno(errno);
+ }
+ return rc;
+}
+
+
+/** @callback_method_impl{FNRTONCECLEANUP} */
+static DECLCALLBACK(void) rtSysMemSolCleanUp(void *pvUser, bool fLazyCleanUpOk)
+{
+ RTCritSectDelete(&g_rtSysMemSolCritSect);
+
+ kstat_close(g_pKStatCtl);
+ g_pKStatCtl = NULL;
+ g_pUnixSysPages = NULL;
+ g_pZfsArcStats = NULL;
+
+ NOREF(pvUser); NOREF(fLazyCleanUpOk);
+}
+
+
+
+RTDECL(int) RTSystemQueryTotalRam(uint64_t *pcb)
+{
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+
+ int rc = RTOnceEx(&g_rtSysMemSolInitOnce, rtSysMemSolInit, rtSysMemSolCleanUp, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCritSectEnter(&g_rtSysMemSolCritSect);
+ if (RT_SUCCESS(rc))
+ {
+ if (kstat_read(g_pKStatCtl, g_pUnixSysPages, NULL) != -1)
+ {
+ kstat_named_t *pData = (kstat_named_t *)kstat_data_lookup(g_pUnixSysPages, (char *)"physmem");
+ if (pData)
+ *pcb = (uint64_t)pData->value.ul * PAGE_SIZE;
+ else
+ rc = RTErrConvertFromErrno(errno);
+ }
+ else
+ rc = RTErrConvertFromErrno(errno);
+ RTCritSectLeave(&g_rtSysMemSolCritSect);
+ }
+ }
+ return rc;
+}
+
+
+RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb)
+{
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+
+ int rc = RTOnceEx(&g_rtSysMemSolInitOnce, rtSysMemSolInit, rtSysMemSolCleanUp, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCritSectEnter(&g_rtSysMemSolCritSect);
+ if (RT_SUCCESS(rc))
+ {
+ if (kstat_read(g_pKStatCtl, g_pUnixSysPages, NULL) != -1)
+ {
+ kstat_named_t *pData = (kstat_named_t *)kstat_data_lookup(g_pUnixSysPages, (char *)"freemem");
+ if (pData)
+ {
+ *pcb = (uint64_t)pData->value.ul * PAGE_SIZE;
+
+ /*
+ * Adjust for ZFS greedyness if possible.
+ * (c_min is the target minimum size of the cache, it is not
+ * an absolute minimum.)
+ */
+ if ( g_pZfsArcStats
+ && kstat_read(g_pKStatCtl, g_pZfsArcStats, NULL) != -1)
+ {
+ kstat_named_t *pCurSize = (kstat_named_t *)kstat_data_lookup(g_pZfsArcStats, (char *)"size");
+ kstat_named_t *pMinSize = (kstat_named_t *)kstat_data_lookup(g_pZfsArcStats, (char *)"c_min");
+ if ( pCurSize
+ && pMinSize
+ && pCurSize->value.ul > pMinSize->value.ul)
+ {
+ *pcb += pCurSize->value.ul - pMinSize->value.ul;
+ }
+ }
+ }
+ else
+ rc = RTErrConvertFromErrno(errno);
+ }
+
+ RTCritSectLeave(&g_rtSysMemSolCritSect);
+ }
+ }
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/stream.cpp b/src/VBox/Runtime/r3/stream.cpp
index e220e5c7..d8b90ccb 100644
--- a/src/VBox/Runtime/r3/stream.cpp
+++ b/src/VBox/Runtime/r3/stream.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -311,6 +311,7 @@ RTR3DECL(int) RTStrmOpen(const char *pszFilename, const char *pszMode, PRTSTREAM
pStream->i32Error = VINF_SUCCESS;
pStream->fCurrentCodeSet = false;
pStream->fBinary = fBinary;
+ pStream->fRecheckMode = false;
#ifndef HAVE_FWRITE_UNLOCKED
pStream->pCritSect = NULL;
#endif /* HAVE_FWRITE_UNLOCKED */
diff --git a/src/VBox/Runtime/r3/tcp.cpp b/src/VBox/Runtime/r3/tcp.cpp
index 151dee86..7c6b2ef4 100644
--- a/src/VBox/Runtime/r3/tcp.cpp
+++ b/src/VBox/Runtime/r3/tcp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -805,11 +805,19 @@ RTR3DECL(int) RTTcpServerDestroy(PRTTCPSERVER pServer)
RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
{
+ return RTTcpClientConnectEx(pszAddress, uPort, pSock, NULL);
+}
+
+
+RTR3DECL(int) RTTcpClientConnectEx(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock,
+ PRTTCPCLIENTCONNECTCANCEL volatile *ppCancelCookie)
+{
/*
* Validate input.
*/
AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(ppCancelCookie, VERR_INVALID_POINTER);
/*
* Resolve the address.
@@ -828,7 +836,25 @@ RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCK
{
RTSocketSetInheritance(Sock, false /*fInheritable*/);
- rc = rtSocketConnect(Sock, &Addr);
+ if (!ppCancelCookie)
+ rc = rtSocketConnect(Sock, &Addr);
+ else
+ {
+ RTSocketRetain(Sock);
+ if (ASMAtomicCmpXchgPtr(ppCancelCookie, (PRTTCPCLIENTCONNECTCANCEL)Sock, NULL))
+ {
+ rc = rtSocketConnect(Sock, &Addr);
+ if (ASMAtomicCmpXchgPtr(ppCancelCookie, NULL, (PRTTCPCLIENTCONNECTCANCEL)Sock))
+ RTSocketRelease(Sock);
+ else
+ rc = VERR_CANCELLED;
+ }
+ else
+ {
+ RTSocketRelease(Sock);
+ rc = VERR_CANCELLED;
+ }
+ }
if (RT_SUCCESS(rc))
{
*pSock = Sock;
@@ -837,10 +863,28 @@ RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCK
rtTcpClose(Sock, "RTTcpClientConnect", false /*fTryGracefulShutdown*/);
}
+ if (ppCancelCookie)
+ *ppCancelCookie = NULL;
return rc;
}
+RTR3DECL(int) RTTcpClientCancelConnect(PRTTCPCLIENTCONNECTCANCEL volatile *ppCancelCookie)
+{
+ AssertPtrReturn(ppCancelCookie, VERR_INVALID_POINTER);
+
+ AssertCompile(NIL_RTSOCKET == NULL);
+ RTSOCKET hSock = (RTSOCKET)ASMAtomicXchgPtr((void * volatile *)ppCancelCookie, (void *)(uintptr_t)0xdead9999);
+ if (hSock != NIL_RTSOCKET)
+ {
+ int rc = rtTcpClose(hSock, "RTTcpClientCancelConnect", false /*fTryGracefulShutdown*/);
+ AssertRCReturn(rc, rc);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
RTR3DECL(int) RTTcpClientClose(RTSOCKET Sock)
{
return rtTcpClose(Sock, "RTTcpClientClose", true /*fTryGracefulShutdown*/);
diff --git a/src/VBox/Runtime/r3/test.cpp b/src/VBox/Runtime/r3/test.cpp
index 6c9abcc3..5688dc6c 100644
--- a/src/VBox/Runtime/r3/test.cpp
+++ b/src/VBox/Runtime/r3/test.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -91,6 +91,8 @@ typedef struct RTTESTINT
uint32_t cbGuard;
/** The verbosity level. */
RTTESTLVL enmMaxLevel;
+ /** The creation flags. */
+ uint32_t fFlags;
/** Critical section serializing output. */
@@ -111,6 +113,8 @@ typedef struct RTTESTINT
const char *pszSubTest;
/** The length of the sub-test name. */
size_t cchSubTest;
+ /** Whether the current subtest should figure as 'SKIPPED'. */
+ bool fSubTestSkipped;
/** Whether we've reported the sub-test result or not. */
bool fSubTestReported;
/** The start error count of the current subtest. */
@@ -123,6 +127,10 @@ typedef struct RTTESTINT
/** Set if XML output is enabled. */
bool fXmlEnabled;
+ /** Set if we omit the top level test in the XML report. */
+ bool fXmlOmitTopTest;
+ /** Set if we've reported the top test (for RTTEST_C_XML_DELAY_TOP_TEST). */
+ bool fXmlTopTestDone;
enum {
kXmlPos_ValueStart,
kXmlPos_Value,
@@ -185,8 +193,6 @@ static void rtTestXmlElemV(PRTTESTINT pTest, const char *pszTag, const char *psz
static void rtTestXmlElem(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...);
static void rtTestXmlElemStartV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va);
static void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...);
-static void rtTestXmlElemValueV(PRTTESTINT pTest, const char *pszFormat, va_list va);
-static void rtTestXmlElemValue(PRTTESTINT pTest, const char *pszFormat, ...);
static void rtTestXmlElemEnd(PRTTESTINT pTest, const char *pszTag);
static void rtTestXmlEnd(PRTTESTINT pTest);
@@ -205,31 +211,28 @@ static RTTLS g_iTestTls = NIL_RTTLS;
* Init TLS index once.
*
* @returns IPRT status code.
- * @param pvUser1 Ignored.
- * @param pvUser2 Ignored.
+ * @param pvUser Ignored.
*/
-static DECLCALLBACK(int32_t) rtTestInitOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int32_t) rtTestInitOnce(void *pvUser)
{
- NOREF(pvUser1);
- NOREF(pvUser2);
+ NOREF(pvUser);
return RTTlsAllocEx(&g_iTestTls, NULL);
}
-
-/**
- * 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)
+RTR3DECL(int) RTTestCreateEx(const char *pszTest, uint32_t fFlags, RTTESTLVL enmMaxLevel,
+ RTHCINTPTR iNativeTestPipe, const char *pszXmlFile, PRTTEST phTest)
{
+ AssertReturn(!(fFlags & ~RTTEST_C_VALID_MASK), VERR_INVALID_PARAMETER);
+ AssertPtrNull(phTest);
+ AssertPtrNull(pszXmlFile);
+ /* RTTESTLVL_INVALID is valid! */
+ AssertReturn(enmMaxLevel >= RTTESTLVL_INVALID && enmMaxLevel < RTTESTLVL_END, VERR_INVALID_PARAMETER);
+
/*
* Global init.
*/
- int rc = RTOnce(&g_TestInitOnce, rtTestInitOnce, NULL, NULL);
+ int rc = RTOnce(&g_TestInitOnce, rtTestInitOnce, NULL);
if (RT_FAILURE(rc))
return rc;
@@ -243,7 +246,8 @@ RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest)
pTest->pszTest = RTStrDup(pszTest);
pTest->cchTest = strlen(pszTest);
pTest->cbGuard = PAGE_SIZE * 7;
- pTest->enmMaxLevel = RTTESTLVL_SUB_TEST;
+ pTest->enmMaxLevel = enmMaxLevel == RTTESTLVL_INVALID ? RTTESTLVL_INFO : enmMaxLevel;
+ pTest->fFlags = fFlags;
pTest->pOutStrm = g_pStdOut;
pTest->fNewLine = true;
@@ -252,12 +256,14 @@ RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest)
pTest->pszSubTest = NULL;
pTest->cchSubTest = 0;
+ pTest->fSubTestSkipped = false;
pTest->fSubTestReported = true;
pTest->cSubTestAtErrors = 0;
pTest->cSubTests = 0;
pTest->cSubTestsFailed = 0;
pTest->fXmlEnabled = false;
+ pTest->fXmlTopTestDone = false;
pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
pTest->hXmlPipe = NIL_RTPIPE;
pTest->hXmlFile = NIL_RTFILE;
@@ -273,82 +279,109 @@ RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest)
* Associate it with our TLS entry unless there is already
* an instance there.
*/
- if (!RTTlsGet(g_iTestTls))
+ if ( !(fFlags & RTTEST_C_NO_TLS)
+ && !RTTlsGet(g_iTestTls))
rc = RTTlsSet(g_iTestTls, pTest);
if (RT_SUCCESS(rc))
{
/*
- * Pick up overrides from the environment.
+ * Output level override?
*/
char szEnvVal[RTPATH_MAX];
- rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_MAX_LEVEL", szEnvVal, sizeof(szEnvVal), NULL);
- if (RT_SUCCESS(rc))
+ if ((fFlags & RTTEST_C_USE_ENV) && enmMaxLevel == RTTESTLVL_INVALID)
{
- char *pszMaxLevel = RTStrStrip(szEnvVal);
- if (!strcmp(pszMaxLevel, "all"))
- pTest->enmMaxLevel = RTTESTLVL_DEBUG;
- if (!strcmp(pszMaxLevel, "quiet"))
- pTest->enmMaxLevel = RTTESTLVL_FAILURE;
- else if (!strcmp(pszMaxLevel, "debug"))
- pTest->enmMaxLevel = RTTESTLVL_DEBUG;
- else if (!strcmp(pszMaxLevel, "info"))
- pTest->enmMaxLevel = RTTESTLVL_INFO;
- else if (!strcmp(pszMaxLevel, "sub_test"))
- pTest->enmMaxLevel = RTTESTLVL_SUB_TEST;
- else if (!strcmp(pszMaxLevel, "failure"))
- pTest->enmMaxLevel = RTTESTLVL_FAILURE;
+ rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_MAX_LEVEL", szEnvVal, sizeof(szEnvVal), NULL);
+ if (RT_SUCCESS(rc))
+ {
+ char *pszMaxLevel = RTStrStrip(szEnvVal);
+ if (!strcmp(pszMaxLevel, "all"))
+ pTest->enmMaxLevel = RTTESTLVL_DEBUG;
+ if (!strcmp(pszMaxLevel, "quiet"))
+ pTest->enmMaxLevel = RTTESTLVL_FAILURE;
+ else if (!strcmp(pszMaxLevel, "debug"))
+ pTest->enmMaxLevel = RTTESTLVL_DEBUG;
+ else if (!strcmp(pszMaxLevel, "info"))
+ pTest->enmMaxLevel = RTTESTLVL_INFO;
+ else if (!strcmp(pszMaxLevel, "sub_test"))
+ pTest->enmMaxLevel = RTTESTLVL_SUB_TEST;
+ else if (!strcmp(pszMaxLevel, "failure"))
+ pTest->enmMaxLevel = RTTESTLVL_FAILURE;
+ }
+ else if (rc != VERR_ENV_VAR_NOT_FOUND)
+ RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_MAX_LEVEL) -> %Rrc\n", pszTest, rc);
}
/*
* Any test driver we are connected or should connect to?
*/
- rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_PIPE", szEnvVal, sizeof(szEnvVal), NULL);
- if (RT_SUCCESS(rc))
+ if ((fFlags & RTTEST_C_USE_ENV) && iNativeTestPipe == -1)
{
- RTHCINTPTR hNative = -1;
+ rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_PIPE", szEnvVal, sizeof(szEnvVal), NULL);
+ if (RT_SUCCESS(rc))
+ {
#if ARCH_BITS == 64
- rc = RTStrToInt64Full(szEnvVal, 0, &hNative);
+ rc = RTStrToInt64Full(szEnvVal, 0, &iNativeTestPipe);
#else
- rc = RTStrToInt32Full(szEnvVal, 0, &hNative);
+ rc = RTStrToInt32Full(szEnvVal, 0, &iNativeTestPipe);
#endif
- if (RT_SUCCESS(rc))
- {
- rc = RTPipeFromNative(&pTest->hXmlPipe, hNative, RTPIPE_N_WRITE);
- if (RT_SUCCESS(rc))
- pTest->fXmlEnabled = true;
- else
+ if (RT_FAILURE(rc))
{
- RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTPipeFromNative(,\"%s\",WRITE) -> %Rrc\n", pszTest, szEnvVal, rc);
- pTest->hXmlPipe = NIL_RTPIPE;
+ RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTStrToInt32Full(\"%s\") -> %Rrc\n",
+ pszTest, szEnvVal, rc);
+ iNativeTestPipe = -1;
}
}
+ else if (rc != VERR_ENV_VAR_NOT_FOUND)
+ RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_PIPE) -> %Rrc\n", pszTest, rc);
+ }
+ if (iNativeTestPipe != -1)
+ {
+ rc = RTPipeFromNative(&pTest->hXmlPipe, iNativeTestPipe, RTPIPE_N_WRITE);
+ if (RT_SUCCESS(rc))
+ pTest->fXmlEnabled = true;
else
- RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTStrToInt32Full(\"%s\") -> %Rrc\n", pszTest, szEnvVal, rc);
+ {
+ RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTPipeFromNative(,%p,WRITE) -> %Rrc\n",
+ pszTest, iNativeTestPipe, rc);
+ pTest->hXmlPipe = NIL_RTPIPE;
+ }
}
- else if (rc != VERR_ENV_VAR_NOT_FOUND)
- RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_PIPE) -> %Rrc\n", pszTest, rc);
/*
* Any test file we should write the test report to?
*/
- rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_FILE", szEnvVal, sizeof(szEnvVal), NULL);
- if (RT_SUCCESS(rc))
+ if ((fFlags & RTTEST_C_USE_ENV) && pszXmlFile == NULL)
{
- rc = RTFileOpen(&pTest->hXmlFile, szEnvVal, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE);
+ rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_FILE", szEnvVal, sizeof(szEnvVal), NULL);
+ if (RT_SUCCESS(rc))
+ pszXmlFile = szEnvVal;
+ else if (rc != VERR_ENV_VAR_NOT_FOUND)
+ RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_MAX_LEVEL) -> %Rrc\n", pszTest, rc);
+ }
+ if (pszXmlFile && *pszXmlFile)
+ {
+ rc = RTFileOpen(&pTest->hXmlFile, pszXmlFile,
+ RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE);
if (RT_SUCCESS(rc))
pTest->fXmlEnabled = true;
else
{
- RTStrmPrintf(g_pStdErr, "%s: test file error: RTFileOpen(,\"%s\",) -> %Rrc\n", pszTest, szEnvVal, rc);
+ RTStrmPrintf(g_pStdErr, "%s: test file error: RTFileOpen(,\"%s\",) -> %Rrc\n", pszTest, pszXmlFile, rc);
pTest->hXmlFile = NIL_RTFILE;
}
}
else if (rc != VERR_ENV_VAR_NOT_FOUND)
RTStrmPrintf(g_pStdErr, "%s: test file error: RTEnvGetEx(IPRT_TEST_FILE) -> %Rrc\n", pszTest, rc);
+ /*
+ * What do we report in the XML stream/file.?
+ */
+ pTest->fXmlOmitTopTest = (fFlags & RTTEST_C_XML_OMIT_TOP_TEST)
+ || ( (fFlags & RTTEST_C_USE_ENV)
+ && RTEnvExistEx(RTENV_DEFAULT, "IPRT_TEST_OMIT_TOP_TEST"));
/*
- * Tell the test driver that we're up.
+ * Tell the test driver that we're up to.
*/
rtTestXmlStart(pTest, pszTest);
@@ -368,6 +401,12 @@ RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest)
}
+RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest)
+{
+ return RTTestCreateEx(pszTest, RTTEST_C_USE_ENV, RTTESTLVL_INVALID, -1 /*iNativeTestPipe*/, NULL /*pszXmlFile*/, phTest);
+}
+
+
RTR3DECL(RTEXITCODE) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest)
{
int rc = RTR3InitExeNoArguments(0);
@@ -376,6 +415,30 @@ RTR3DECL(RTEXITCODE) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest)
RTStrmPrintf(g_pStdErr, "%s: fatal error: RTR3InitExeNoArguments failed with rc=%Rrc\n", pszTest, rc);
return RTEXITCODE_INIT;
}
+
+ rc = RTTestCreate(pszTest, phTest);
+ if (RT_FAILURE(rc))
+ {
+ RTStrmPrintf(g_pStdErr, "%s: fatal error: RTTestCreate failed with rc=%Rrc\n", pszTest, rc);
+ return RTEXITCODE_INIT;
+ }
+ return RTEXITCODE_SUCCESS;
+}
+
+
+RTR3DECL(RTEXITCODE) RTTestInitExAndCreate(int cArgs, char ***papszArgs, uint32_t fRtInit, const char *pszTest, PRTTEST phTest)
+{
+ int rc;
+ if (cArgs <= 0 && papszArgs == NULL)
+ rc = RTR3InitExeNoArguments(fRtInit);
+ else
+ rc = RTR3InitExe(cArgs, papszArgs, fRtInit);
+ if (RT_FAILURE(rc))
+ {
+ RTStrmPrintf(g_pStdErr, "%s: fatal error: RTR3InitExe(,,%#x) failed with rc=%Rrc\n", pszTest, fRtInit, rc);
+ return RTEXITCODE_INIT;
+ }
+
rc = RTTestCreate(pszTest, phTest);
if (RT_FAILURE(rc))
{
@@ -454,6 +517,34 @@ RTR3DECL(int) RTTestSetDefault(RTTEST hNewDefaultTest, PRTTEST phOldTest)
}
+RTR3DECL(int) RTTestChangeName(RTTEST hTest, const char *pszName)
+{
+ PRTTESTINT pTest = hTest;
+ RTTEST_GET_VALID_RETURN(pTest);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertReturn(*pszName, VERR_INVALID_PARAMETER);
+
+ size_t cchName = strlen(pszName);
+ AssertReturn(cchName < 128, VERR_INVALID_PARAMETER);
+ char *pszDupName = RTStrDup(pszName);
+ if (!pszDupName)
+ return VERR_NO_STR_MEMORY;
+
+ RTCritSectEnter(&pTest->Lock);
+ RTCritSectEnter(&pTest->OutputLock);
+
+ char *pszOldName = (char *)pTest->pszTest;
+ pTest->pszTest = pszDupName;
+ pTest->cchTest = cchName;
+
+ RTCritSectLeave(&pTest->OutputLock);
+ RTCritSectLeave(&pTest->Lock);
+
+ RTStrFree(pszOldName);
+ return VINF_SUCCESS;
+}
+
+
/**
* Allocate a block of guarded memory.
*
@@ -683,7 +774,9 @@ static void rtTestXmlStart(PRTTESTINT pTest, const char *pszTest)
{
rtTestXmlOutput(pTest, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
- rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszTest);
+ pTest->fXmlTopTestDone = !(pTest->fFlags & RTTEST_C_XML_DELAY_TOP_TEST) || pTest->fXmlOmitTopTest;
+ if (pTest->fXmlTopTestDone && !pTest->fXmlOmitTopTest)
+ rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszTest);
}
}
@@ -795,43 +888,6 @@ static void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char
/**
- * Writes an element value, or a part of one, taking care of all the escaping.
- *
- * The caller must own the instance lock.
- *
- * @param pTest The test instance.
- * @param pszFormat The value format string.
- * @param va The format arguments.
- */
-static void rtTestXmlElemValueV(PRTTESTINT pTest, const char *pszFormat, va_list va)
-{
- if (pTest->fXmlEnabled)
- {
- char *pszValue;
- RTStrAPrintfV(&pszValue, pszFormat, va);
- if (pszValue)
- {
- rtTestXmlOutput(pTest, "%RMes", pszValue);
- RTStrFree(pszValue);
- }
- pTest->eXmlState = RTTESTINT::kXmlPos_Value;
- }
-}
-
-
-/**
- * Wrapper around rtTestXmlElemValueV.
- */
-static void rtTestXmlElemValue(PRTTESTINT pTest, const char *pszFormat, ...)
-{
- va_list va;
- va_start(va, pszFormat);
- rtTestXmlElemValueV(pTest, pszFormat, va);
- va_end(va);
-}
-
-
-/**
* Ends the current element.
*
* The caller must own the instance lock.
@@ -879,7 +935,7 @@ static void rtTestXmlEnd(PRTTESTINT pTest)
* final timestamp and some certainty that the XML is valid.
*/
size_t i = pTest->cXmlElements;
- AssertReturnVoid(i > 0);
+ AssertReturnVoid(i > 0 || pTest->fXmlOmitTopTest || !pTest->fXmlTopTestDone);
while (i-- > 1)
{
const char *pszTag = pTest->apszXmlElements[pTest->cXmlElements];
@@ -891,9 +947,13 @@ static void rtTestXmlEnd(PRTTESTINT pTest)
rtTestXmlOutput(pTest, "</%s>\n", pszTag);
pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
}
- rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"",
- pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors);
- rtTestXmlOutput(pTest, "</Test>\n");
+
+ if (!pTest->fXmlOmitTopTest && pTest->fXmlTopTestDone)
+ {
+ rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"",
+ pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors);
+ rtTestXmlOutput(pTest, "</Test>\n");
+ }
/*
* Close the XML outputs.
@@ -1130,15 +1190,24 @@ static int rtTestSubTestReport(PRTTESTINT pTest)
uint32_t cErrors = ASMAtomicUoReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
if (!cErrors)
{
- rtTestXmlElem(pTest, "Passed", NULL);
- rtTestXmlElemEnd(pTest, "SubTest");
- cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: PASSED\n", pTest->pszSubTest);
+ if (!pTest->fSubTestSkipped)
+ {
+ rtTestXmlElem(pTest, "Passed", NULL);
+ rtTestXmlElemEnd(pTest, "Test");
+ cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: PASSED\n", pTest->pszSubTest);
+ }
+ else
+ {
+ rtTestXmlElem(pTest, "Skipped", NULL);
+ rtTestXmlElemEnd(pTest, "Test");
+ cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: SKIPPED\n", pTest->pszSubTest);
+ }
}
else
{
pTest->cSubTestsFailed++;
rtTestXmlElem(pTest, "Failed", "errors=\"%u\"", cErrors);
- rtTestXmlElemEnd(pTest, "SubTest");
+ rtTestXmlElemEnd(pTest, "Test");
cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: FAILED (%u errors)\n",
pTest->pszSubTest, cErrors);
}
@@ -1267,13 +1336,20 @@ RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest)
pTest->cSubTestAtErrors = ASMAtomicUoReadU32(&pTest->cErrors);
pTest->pszSubTest = RTStrDup(pszSubTest);
pTest->cchSubTest = strlen(pszSubTest);
+ pTest->fSubTestSkipped = false;
pTest->fSubTestReported = false;
int cch = 0;
if (pTest->enmMaxLevel >= RTTESTLVL_DEBUG)
cch = RTTestPrintfNl(hTest, RTTESTLVL_DEBUG, "debug: Starting sub-test '%s'\n", pszSubTest);
- rtTestXmlElemStart(pTest, "SubTest", "name=%RMas", pszSubTest);
+ if (!pTest->fXmlTopTestDone)
+ {
+ pTest->fXmlTopTestDone = true;
+ rtTestXmlElemStart(pTest, "Test", "name=%RMas", pTest->pszTest);
+ }
+
+ rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszSubTest);
RTCritSectLeave(&pTest->Lock);
@@ -1337,7 +1413,7 @@ RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va)
RTR3DECL(int) RTTestSubDone(RTTEST hTest)
{
PRTTESTINT pTest = hTest;
- RTTEST_GET_VALID_RETURN_RC(pTest, -1);
+ RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
RTCritSectEnter(&pTest->Lock);
int cch = rtTestSubCleanup(pTest);
@@ -1361,7 +1437,8 @@ RTR3DECL(int) RTTestSubDone(RTTEST hTest)
RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va)
{
PRTTESTINT pTest = hTest;
- RTTEST_GET_VALID_RETURN_RC(pTest, -1);
+ AssertPtr(pszFormat);
+ RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
int cch = 0;
if (pTest->enmMaxLevel >= RTTESTLVL_INFO)
@@ -1404,6 +1481,44 @@ RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...)
}
+RTR3DECL(int) RTTestSkippedV(RTTEST hTest, const char *pszFormat, va_list va)
+{
+ PRTTESTINT pTest = hTest;
+ AssertPtrNull(pszFormat);
+ RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
+
+ pTest->fSubTestSkipped = true;
+
+ int cch = 0;
+ if (pszFormat && *pszFormat && pTest->enmMaxLevel >= RTTESTLVL_INFO)
+ {
+ va_list va2;
+ va_copy(va2, va);
+
+ RTCritSectEnter(&pTest->OutputLock);
+ cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
+ RTCritSectLeave(&pTest->OutputLock);
+
+ va_end(va2);
+ }
+
+ return cch;
+}
+
+
+RTR3DECL(int) RTTestSkipped(RTTEST hTest, const char *pszFormat, ...)
+{
+ va_list va;
+
+ va_start(va, pszFormat);
+ int cch = RTTestSkippedV(hTest, pszFormat, va);
+ va_end(va);
+
+ return cch;
+}
+
+
+
/**
* Gets the unit name.
*
@@ -1438,6 +1553,13 @@ static const char *rtTestUnitName(RTTESTUNIT enmUnit)
case RTTESTUNIT_NS_PER_OCCURRENCE: return "ns/occurrences";
case RTTESTUNIT_NS_PER_PACKET: return "ns/packet";
case RTTESTUNIT_NS_PER_ROUND_TRIP: return "ns/roundtrips";
+ case RTTESTUNIT_INSTRS: return "ins";
+ case RTTESTUNIT_INSTRS_PER_SEC: return "ins/sec";
+ case RTTESTUNIT_NONE: return "";
+ case RTTESTUNIT_PP1K: return "pp1k";
+ case RTTESTUNIT_PP10K: return "pp10k";
+ case RTTESTUNIT_PPM: return "ppm";
+ case RTTESTUNIT_PPB: return "ppb";
/* No default so gcc helps us keep this up to date. */
case RTTESTUNIT_INVALID:
@@ -1457,9 +1579,7 @@ RTR3DECL(int) RTTestValue(RTTEST hTest, const char *pszName, uint64_t u64Value,
const char *pszUnit = rtTestUnitName(enmUnit);
RTCritSectEnter(&pTest->Lock);
- rtTestXmlElemStart(pTest, "Value", "name=%RMas unit=%RMas", pszName, pszUnit);
- rtTestXmlElemValue(pTest, "%llu", u64Value);
- rtTestXmlElemEnd(pTest, "Value");
+ rtTestXmlElem(pTest, "Value", "name=%RMas unit=%RMas value=\"%llu\"", pszName, pszUnit, u64Value);
RTCritSectLeave(&pTest->Lock);
RTCritSectEnter(&pTest->OutputLock);
@@ -1510,6 +1630,7 @@ RTR3DECL(int) RTTestErrorInc(RTTEST hTest)
}
+
/**
* Get the current error count.
*
@@ -1526,6 +1647,15 @@ RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest)
}
+RTR3DECL(uint32_t) RTTestSubErrorCount(RTTEST hTest)
+{
+ PRTTESTINT pTest = hTest;
+ RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX);
+
+ return ASMAtomicReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
+}
+
+
/**
* Increments the error counter and prints a failure message.
*
@@ -1538,7 +1668,7 @@ RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest)
RTR3DECL(int) RTTestFailedV(RTTEST hTest, const char *pszFormat, va_list va)
{
PRTTESTINT pTest = hTest;
- RTTEST_GET_VALID_RETURN_RC(pTest, -1);
+ RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
RTTestErrorInc(pTest);
diff --git a/src/VBox/Runtime/r3/testi.cpp b/src/VBox/Runtime/r3/testi.cpp
index e143e3c1..b0c78828 100644
--- a/src/VBox/Runtime/r3/testi.cpp
+++ b/src/VBox/Runtime/r3/testi.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/udp.cpp b/src/VBox/Runtime/r3/udp.cpp
index a5a2cc22..5e46b959 100644
--- a/src/VBox/Runtime/r3/udp.cpp
+++ b/src/VBox/Runtime/r3/udp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/RTHandleGetStandard-win.cpp b/src/VBox/Runtime/r3/win/RTHandleGetStandard-win.cpp
index 683d6ee4..8c3d86b5 100644
--- a/src/VBox/Runtime/r3/win/RTHandleGetStandard-win.cpp
+++ b/src/VBox/Runtime/r3/win/RTHandleGetStandard-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp b/src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp
index 2f3c16c0..69d028a0 100644
--- a/src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp
+++ b/src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/RTSystemQueryDmiString-win.cpp b/src/VBox/Runtime/r3/win/RTSystemQueryDmiString-win.cpp
index 57831910..8621a36b 100644
--- a/src/VBox/Runtime/r3/win/RTSystemQueryDmiString-win.cpp
+++ b/src/VBox/Runtime/r3/win/RTSystemQueryDmiString-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -165,8 +165,11 @@ RTDECL(int) RTSystemQueryDmiString(RTSYSDMISTR enmString, char *pszBuf, size_t c
/*
* Before we do anything with COM, we have to initialize it.
*/
+ bool fUninit = true;
HRESULT hrc = rtSystemDmiWinInitialize();
- if (FAILED(hrc))
+ if (hrc == RPC_E_CHANGED_MODE)
+ fUninit = false; /* don't fail if already initialized */
+ else if (FAILED(hrc))
return VERR_NOT_SUPPORTED;
int rc = VERR_NOT_SUPPORTED;
@@ -246,7 +249,8 @@ RTDECL(int) RTSystemQueryDmiString(RTSYSDMISTR enmString, char *pszBuf, size_t c
}
else
hrc = E_OUTOFMEMORY;
- rtSystemDmiWinTerminate();
+ if (fUninit)
+ rtSystemDmiWinTerminate();
if (FAILED(hrc) && rc == VERR_NOT_SUPPORTED)
rc = VERR_NOT_SUPPORTED;
return rc;
diff --git a/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp b/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp
index 50dee1aa..28c34625 100644
--- a/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp
+++ b/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -27,9 +27,11 @@
/*******************************************************************************
* Header Files *
*******************************************************************************/
+#include "internal/iprt.h"
#include <Windows.h>
#include <WinUser.h>
+#include "internal-r3-win.h"
#include <iprt/system.h>
#include <iprt/assert.h>
#include <iprt/string.h>
@@ -39,35 +41,6 @@
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
-/**
- * Windows OS type as determined by rtSystemWinOSType().
- */
-typedef enum RTWINOSTYPE
-{
- kRTWinOSType_UNKNOWN = 0,
- kRTWinOSType_9XFIRST = 1,
- kRTWinOSType_95 = kRTWinOSType_9XFIRST,
- kRTWinOSType_95SP1,
- kRTWinOSType_95OSR2,
- kRTWinOSType_98,
- kRTWinOSType_98SP1,
- kRTWinOSType_98SE,
- kRTWinOSType_ME,
- kRTWinOSType_9XLAST = 99,
- kRTWinOSType_NTFIRST = 100,
- kRTWinOSType_NT31 = kRTWinOSType_NTFIRST,
- kRTWinOSType_NT351,
- kRTWinOSType_NT4,
- kRTWinOSType_2K,
- kRTWinOSType_XP,
- kRTWinOSType_2003,
- kRTWinOSType_VISTA,
- kRTWinOSType_2008,
- kRTWinOSType_7,
- kRTWinOSType_8,
- kRTWinOSType_NT_UNKNOWN = 199,
- kRTWinOSType_NT_LAST = kRTWinOSType_UNKNOWN
-} RTWINOSTYPE;
/**
* These are the PRODUCT_* defines found in the Vista Platform SDK and returned
@@ -111,112 +84,6 @@ typedef enum RTWINPRODTYPE
/**
- * Translates OSVERSIONINOFEX into a Windows OS type.
- *
- * @returns The Windows OS type.
- * @param pOSInfoEx The OS info returned by Windows.
- *
- * @remarks This table has been assembled from Usenet postings, personal
- * observations, and reading other people's code. Please feel
- * free to add to it or correct it.
- * <pre>
- dwPlatFormID dwMajorVersion dwMinorVersion dwBuildNumber
-95 1 4 0 950
-95 SP1 1 4 0 >950 && <=1080
-95 OSR2 1 4 <10 >1080
-98 1 4 10 1998
-98 SP1 1 4 10 >1998 && <2183
-98 SE 1 4 10 >=2183
-ME 1 4 90 3000
-
-NT 3.51 2 3 51 1057
-NT 4 2 4 0 1381
-2000 2 5 0 2195
-XP 2 5 1 2600
-2003 2 5 2 3790
-Vista 2 6 0
-
-CE 1.0 3 1 0
-CE 2.0 3 2 0
-CE 2.1 3 2 1
-CE 3.0 3 3 0
-</pre>
- */
-static RTWINOSTYPE rtSystemWinOSType(OSVERSIONINFOEX const *pOSInfoEx)
-{
- RTWINOSTYPE enmVer = kRTWinOSType_UNKNOWN;
- BYTE const bProductType = pOSInfoEx->wProductType;
- DWORD const dwPlatformId = pOSInfoEx->dwPlatformId;
- DWORD const dwMinorVersion = pOSInfoEx->dwMinorVersion;
- DWORD const dwMajorVersion = pOSInfoEx->dwMajorVersion;
- DWORD const dwBuildNumber = pOSInfoEx->dwBuildNumber & 0xFFFF; /* Win 9x needs this. */
-
- if ( dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
- && dwMajorVersion == 4)
- {
- if ( dwMinorVersion < 10
- && dwBuildNumber == 950)
- enmVer = kRTWinOSType_95;
- else if ( dwMinorVersion < 10
- && dwBuildNumber > 950
- && dwBuildNumber <= 1080)
- enmVer = kRTWinOSType_95SP1;
- else if ( dwMinorVersion < 10
- && dwBuildNumber > 1080)
- enmVer = kRTWinOSType_95OSR2;
- else if ( dwMinorVersion == 10
- && dwBuildNumber == 1998)
- enmVer = kRTWinOSType_98;
- else if ( dwMinorVersion == 10
- && dwBuildNumber > 1998
- && dwBuildNumber < 2183)
- enmVer = kRTWinOSType_98SP1;
- else if ( dwMinorVersion == 10
- && dwBuildNumber >= 2183)
- enmVer = kRTWinOSType_98SE;
- else if (dwMinorVersion == 90)
- enmVer = kRTWinOSType_ME;
- }
- else if (dwPlatformId == VER_PLATFORM_WIN32_NT)
- {
- if ( dwMajorVersion == 3
- && dwMinorVersion == 51)
- enmVer = kRTWinOSType_NT351;
- else if ( dwMajorVersion == 4
- && dwMinorVersion == 0)
- enmVer = kRTWinOSType_NT4;
- else if ( dwMajorVersion == 5
- && dwMinorVersion == 0)
- enmVer = kRTWinOSType_2K;
- else if ( dwMajorVersion == 5
- && dwMinorVersion == 1)
- enmVer = kRTWinOSType_XP;
- else if ( dwMajorVersion == 5
- && dwMinorVersion == 2)
- enmVer = kRTWinOSType_2003;
- else if ( dwMajorVersion == 6
- && dwMinorVersion == 0)
- {
- if (bProductType != VER_NT_WORKSTATION)
- enmVer = kRTWinOSType_2008;
- else
- enmVer = kRTWinOSType_VISTA;
- }
- else if ( dwMajorVersion == 6
- && dwMinorVersion == 1)
- enmVer = kRTWinOSType_7;
- else if ( dwMajorVersion == 6
- && dwMinorVersion == 2)
- enmVer = kRTWinOSType_8;
- else
- enmVer = kRTWinOSType_NT_UNKNOWN;
- }
-
- return enmVer;
-}
-
-
-/**
* Wrapper around the GetProductInfo API.
*
* @returns The vista type.
@@ -224,7 +91,7 @@ static RTWINOSTYPE rtSystemWinOSType(OSVERSIONINFOEX const *pOSInfoEx)
static RTWINPRODTYPE rtSystemWinGetProductInfo(DWORD dwOSMajorVersion, DWORD dwOSMinorVersion, DWORD dwSpMajorVersion, DWORD dwSpMinorVersion)
{
BOOL (WINAPI *pfnGetProductInfo)(DWORD, DWORD, DWORD, DWORD, PDWORD);
- pfnGetProductInfo = (BOOL (WINAPI *)(DWORD, DWORD, DWORD, DWORD, PDWORD))GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "GetProductInfo");
+ pfnGetProductInfo = (BOOL (WINAPI *)(DWORD, DWORD, DWORD, DWORD, PDWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "GetProductInfo");
if (pfnGetProductInfo)
{
DWORD dwProductType = kRTWinProdType_UNDEFINED;
@@ -291,48 +158,21 @@ static void rtSystemWinAppendProductType(char *pszTmp)
*/
static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t cchInfo)
{
- int rc;
-
/*
* Make sure it's terminated correctly in case of error.
*/
*pszInfo = '\0';
/*
- * Query the Windows version.
- *
- * ASSUMES OSVERSIONINFOEX starts with the exact same layout as OSVERSIONINFO (safe).
+ * Check that we got the windows version at init time.
*/
- OSVERSIONINFOEX OSInfoEx;
- memset(&OSInfoEx, '\0', sizeof(OSInfoEx));
- OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (!GetVersionEx((LPOSVERSIONINFO) &OSInfoEx))
- {
- DWORD err = GetLastError();
- rc = RTErrConvertFromWin32(err);
- AssertMsgFailedReturn(("err=%d\n", err), rc == VERR_BUFFER_OVERFLOW ? VERR_INTERNAL_ERROR : rc);
- }
-
- /* Get extended version info for 2000 and later. */
- if ( OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT
- && OSInfoEx.dwMajorVersion >= 5)
- {
- ZeroMemory(&OSInfoEx, sizeof(OSInfoEx));
- OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
- if (!GetVersionEx((LPOSVERSIONINFO) &OSInfoEx))
- {
- DWORD err = GetLastError();
- rc = RTErrConvertFromWin32(err);
- AssertMsgFailedReturn(("err=%d\n", err), rc == VERR_BUFFER_OVERFLOW ? VERR_INTERNAL_ERROR : rc);
- }
- }
+ AssertReturn(g_WinOsInfoEx.dwOSVersionInfoSize, VERR_WRONG_ORDER);
/*
* Service the request.
*/
char szTmp[512];
szTmp[0] = '\0';
- rc = VINF_SUCCESS;
switch (enmInfo)
{
/*
@@ -340,8 +180,7 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t
*/
case RTSYSOSINFO_PRODUCT:
{
- RTWINOSTYPE enmVer = rtSystemWinOSType(&OSInfoEx);
- switch (enmVer)
+ switch (g_enmWinVer)
{
case kRTWinOSType_95: strcpy(szTmp, "Windows 95"); break;
case kRTWinOSType_95SP1: strcpy(szTmp, "Windows 95 (Service Pack 1)"); break;
@@ -355,10 +194,10 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t
case kRTWinOSType_2K: strcpy(szTmp, "Windows 2000"); break;
case kRTWinOSType_XP:
strcpy(szTmp, "Windows XP");
- if (OSInfoEx.wSuiteMask & VER_SUITE_PERSONAL)
+ if (g_WinOsInfoEx.wSuiteMask & VER_SUITE_PERSONAL)
strcat(szTmp, " Home");
- if ( OSInfoEx.wProductType == VER_NT_WORKSTATION
- && !(OSInfoEx.wSuiteMask & VER_SUITE_PERSONAL))
+ if ( g_WinOsInfoEx.wProductType == VER_NT_WORKSTATION
+ && !(g_WinOsInfoEx.wSuiteMask & VER_SUITE_PERSONAL))
strcat(szTmp, " Professional");
#if 0 /** @todo fixme */
if (GetSystemMetrics(SM_MEDIACENTER))
@@ -376,15 +215,18 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t
case kRTWinOSType_2008: strcpy(szTmp, "Windows 2008"); break;
case kRTWinOSType_7: strcpy(szTmp, "Windows 7"); break;
case kRTWinOSType_8: strcpy(szTmp, "Windows 8"); break;
+ case kRTWinOSType_81: strcpy(szTmp, "Windows 8.1"); break;
case kRTWinOSType_NT_UNKNOWN:
- RTStrPrintf(szTmp, sizeof(szTmp), "Unknown NT v%u.%u", OSInfoEx.dwMajorVersion, OSInfoEx.dwMinorVersion);
+ RTStrPrintf(szTmp, sizeof(szTmp), "Unknown NT v%u.%u",
+ g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion);
break;
default:
AssertFailed();
case kRTWinOSType_UNKNOWN:
- RTStrPrintf(szTmp, sizeof(szTmp), "Unknown %d v%u.%u", OSInfoEx.dwPlatformId, OSInfoEx.dwMajorVersion, OSInfoEx.dwMinorVersion);
+ RTStrPrintf(szTmp, sizeof(szTmp), "Unknown %d v%u.%u",
+ g_WinOsInfoEx.dwPlatformId, g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion);
break;
}
break;
@@ -395,8 +237,8 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t
*/
case RTSYSOSINFO_RELEASE:
{
- RTWINOSTYPE enmVer = rtSystemWinOSType(&OSInfoEx);
- RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u.%u", OSInfoEx.dwMajorVersion, OSInfoEx.dwMinorVersion, OSInfoEx.dwBuildNumber);
+ RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u.%u",
+ g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion, g_WinOsInfoEx.dwBuildNumber);
break;
}
@@ -406,24 +248,25 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t
*/
case RTSYSOSINFO_SERVICE_PACK:
{
- if (OSInfoEx.wServicePackMajor)
+ if (g_WinOsInfoEx.wServicePackMajor)
{
- if (OSInfoEx.wServicePackMinor)
- RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u", (unsigned)OSInfoEx.wServicePackMajor, (unsigned)OSInfoEx.wServicePackMinor);
+ if (g_WinOsInfoEx.wServicePackMinor)
+ RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u",
+ (unsigned)g_WinOsInfoEx.wServicePackMajor, (unsigned)g_WinOsInfoEx.wServicePackMinor);
else
- RTStrPrintf(szTmp, sizeof(szTmp), "%u", (unsigned)OSInfoEx.wServicePackMajor);
+ RTStrPrintf(szTmp, sizeof(szTmp), "%u",
+ (unsigned)g_WinOsInfoEx.wServicePackMajor);
}
- else if (OSInfoEx.szCSDVersion[0])
+ else if (g_WinOsInfoEx.szCSDVersion[0])
{
/* just copy the entire string. */
- memcpy(szTmp, OSInfoEx.szCSDVersion, sizeof(OSInfoEx.szCSDVersion));
- szTmp[sizeof(OSInfoEx.szCSDVersion)] = '\0';
- AssertCompile(sizeof(szTmp) > sizeof(OSInfoEx.szCSDVersion));
+ memcpy(szTmp, g_WinOsInfoEx.szCSDVersion, sizeof(g_WinOsInfoEx.szCSDVersion));
+ szTmp[sizeof(g_WinOsInfoEx.szCSDVersion)] = '\0';
+ AssertCompile(sizeof(szTmp) > sizeof(g_WinOsInfoEx.szCSDVersion));
}
else
{
- RTWINOSTYPE enmVer = rtSystemWinOSType(&OSInfoEx);
- switch (enmVer)
+ switch (g_enmWinVer)
{
case kRTWinOSType_95SP1: strcpy(szTmp, "1"); break;
case kRTWinOSType_98SP1: strcpy(szTmp, "1"); break;
@@ -444,15 +287,13 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t
size_t cchTmp = strlen(szTmp);
Assert(cchTmp < sizeof(szTmp));
if (cchTmp < cchInfo)
- memcpy(pszInfo, szTmp, cchTmp + 1);
- else
{
- memcpy(pszInfo, szTmp, cchInfo - 1);
- pszInfo[cchInfo - 1] = '\0';
- if (RT_SUCCESS(rc))
- rc = VERR_BUFFER_OVERFLOW;
+ memcpy(pszInfo, szTmp, cchTmp + 1);
+ return VINF_SUCCESS;
}
- return VINF_SUCCESS;
+ memcpy(pszInfo, szTmp, cchInfo - 1);
+ pszInfo[cchInfo - 1] = '\0';
+ return VERR_BUFFER_OVERFLOW;
}
@@ -481,7 +322,8 @@ RTDECL(int) RTSystemQueryOSInfo(RTSYSOSINFO enmInfo, char *pszInfo, size_t cchIn
case RTSYSOSINFO_VERSION:
default:
*pszInfo = '\0';
- return VERR_NOT_SUPPORTED;
}
+
+ return VERR_NOT_SUPPORTED;
}
diff --git a/src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp b/src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp
index 62a25bc3..2ddb96c8 100644
--- a/src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp
+++ b/src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp
@@ -53,9 +53,9 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char
BOOL fForceAppsClosed = fFlags & RTSYSTEM_SHUTDOWN_FORCE ? TRUE : FALSE;
/*
- * Do the
+ * Do the
*/
- if (InitiateSystemShutdownW(NULL /*pwszMachineName = NULL = localhost*/,
+ if (InitiateSystemShutdownW(NULL /*pwszMachineName = NULL = localhost*/,
pwszLogMsg,
cSecsTimeout,
fForceAppsClosed,
@@ -70,7 +70,7 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char
if (dwErr == ERROR_ACCESS_DENIED)
{
HANDLE hToken = NULL;
- if (OpenThreadToken(GetCurrentThread(),
+ if (OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES,
TRUE /*OpenAsSelf*/,
&hToken))
@@ -80,7 +80,7 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char
dwErr = GetLastError();
if (dwErr == ERROR_NO_TOKEN)
{
- if (OpenProcessToken(GetCurrentProcess(),
+ if (OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
&hToken))
dwErr = NO_ERROR;
@@ -91,7 +91,7 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char
if (dwErr == NO_ERROR)
{
- union
+ union
{
TOKEN_PRIVILEGES TokenPriv;
char ab[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
@@ -107,7 +107,7 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char
NULL,
NULL) )
{
- if (InitiateSystemShutdownW(NULL /*pwszMachineName = NULL = localhost*/,
+ if (InitiateSystemShutdownW(NULL /*pwszMachineName = NULL = localhost*/,
pwszLogMsg,
cSecsTimeout,
fForceAppsClosed,
diff --git a/src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp b/src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp
index 8083f98d..7792b794 100644
--- a/src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp
+++ b/src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def b/src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def
index fc314a4d..e1ac857f 100644
--- a/src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def
+++ b/src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def
@@ -32,8 +32,8 @@
;
; OpenSSL symbols
;
- _CONF_get_section
- _CONF_get_string
+;; _CONF_get_section
+;; _CONF_get_string
a2d_ASN1_OBJECT
a2i_ASN1_INTEGER
a2i_ASN1_STRING
@@ -442,10 +442,10 @@
CRYPTO_dbg_free
CRYPTO_dbg_get_options
CRYPTO_dbg_malloc
- CRYPTO_dbg_pop_info
- CRYPTO_dbg_push_info
+;; CRYPTO_dbg_pop_info
+;; CRYPTO_dbg_push_info
CRYPTO_dbg_realloc
- CRYPTO_dbg_remove_all_info
+;; CRYPTO_dbg_remove_all_info
CRYPTO_dbg_set_options
CRYPTO_destroy_dynlockid
CRYPTO_dup_ex_data
@@ -474,7 +474,7 @@
CRYPTO_is_mem_check_on
CRYPTO_lock
CRYPTO_malloc
- CRYPTO_malloc_debug_init
+;; CRYPTO_malloc_debug_init
CRYPTO_malloc_locked
CRYPTO_mem_ctrl
CRYPTO_mem_leaks
@@ -502,7 +502,7 @@
CRYPTO_set_mem_debug_options
CRYPTO_set_mem_ex_functions
CRYPTO_set_mem_functions
- CRYPTO_set_mem_info_functions
+;; CRYPTO_set_mem_info_functions
CRYPTO_strdup
CRYPTO_thread_id
d2i_ACCESS_DESCRIPTION
@@ -1123,8 +1123,8 @@
NOTICEREF_new
o2i_ECPublicKey
OBJ_add_object
- OBJ_bsearch
- OBJ_bsearch_ex
+;; OBJ_bsearch
+;; OBJ_bsearch_ex
OBJ_cleanup
OBJ_cmp
OBJ_create
@@ -1283,7 +1283,7 @@
RSA_size
RSA_up_ref
RSA_verify
- RSAPrivateKey_asn1_meth
+;; RSAPrivateKey_asn1_meth
RSAPrivateKey_dup
RSAPublicKey_dup
s2i_ASN1_INTEGER
@@ -1428,7 +1428,7 @@
X509_ALGOR_set0
X509_alias_get0
X509_alias_set1
- X509_asn1_meth
+;; X509_asn1_meth
X509_ATTRIBUTE_count
X509_ATTRIBUTE_create
X509_ATTRIBUTE_create_by_NID
diff --git a/src/VBox/Runtime/r3/win/VBoxRT-openssl.def b/src/VBox/Runtime/r3/win/VBoxRT-openssl.def
index 01e269b5..f872e71c 100644
--- a/src/VBox/Runtime/r3/win/VBoxRT-openssl.def
+++ b/src/VBox/Runtime/r3/win/VBoxRT-openssl.def
@@ -9,7 +9,7 @@
;
;
-; Copyright (C) 2009-2012 Oracle Corporation
+; Copyright (C) 2009-2013 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -476,11 +476,6 @@
c2i_ASN1_OBJECT
CERTIFICATEPOLICIES_free
CERTIFICATEPOLICIES_new
- COMP_compress_block
- COMP_CTX_free
- COMP_CTX_new
- COMP_expand_block
- COMP_zlib
CONF_dump_bio
CONF_dump_fp
CONF_free
@@ -961,7 +956,6 @@
ERR_get_state
ERR_get_string_table
ERR_lib_error_string
- ERR_load_ERR_strings
ERR_load_strings
ERR_peek_error
ERR_peek_error_line
@@ -1690,7 +1684,6 @@
SSLeay
SSLeay_version
string_to_hex
- stub_VBOX_BIO_printf
SXNET_add_id_asc
SXNET_add_id_INTEGER
SXNET_add_id_ulong
@@ -2234,7 +2227,8 @@
ssl_cert_inst
ssl_cert_new
ssl_cert_type
- ssl_check_clienthello_tlsext
+ ssl_check_clienthello_tlsext_early
+ ssl_check_clienthello_tlsext_late
SSL_check_private_key
ssl_check_serverhello_tlsext
SSL_CIPHER_description
diff --git a/src/VBox/Runtime/r3/win/VBoxRT-win32.def b/src/VBox/Runtime/r3/win/VBoxRT-win32.def
index 8764142a..e36769fd 100644
--- a/src/VBox/Runtime/r3/win/VBoxRT-win32.def
+++ b/src/VBox/Runtime/r3/win/VBoxRT-win32.def
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2012 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/VBoxRT-win64.def b/src/VBox/Runtime/r3/win/VBoxRT-win64.def
index 4a1eb1de..434c7be3 100644
--- a/src/VBox/Runtime/r3/win/VBoxRT-win64.def
+++ b/src/VBox/Runtime/r3/win/VBoxRT-win64.def
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2012 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/alloc-win.cpp b/src/VBox/Runtime/r3/win/alloc-win.cpp
index 7e052673..25879154 100644
--- a/src/VBox/Runtime/r3/win/alloc-win.cpp
+++ b/src/VBox/Runtime/r3/win/alloc-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/allocex-win.cpp b/src/VBox/Runtime/r3/win/allocex-win.cpp
new file mode 100644
index 00000000..30de9aa7
--- /dev/null
+++ b/src/VBox/Runtime/r3/win/allocex-win.cpp
@@ -0,0 +1,120 @@
+/* $Id: allocex-win.cpp $ */
+/** @file
+ * IPRT - Memory Allocation, Extended Alloc Workers, Windows.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define RTMEM_NO_WRAP_TO_EF_APIS
+#include <iprt/mem.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <iprt/param.h>
+#include "../allocex.h"
+
+#include <Windows.h>
+
+
+static int rtMemAllocExInRange(size_t cbAlloc, uint32_t fFlags, void **ppv, uintptr_t uAddr, uintptr_t uAddrLast)
+{
+ /*
+ * Try with every possible address hint since the possible range is very limited.
+ */
+ DWORD fPageProt = (fFlags & RTMEMALLOCEX_FLAGS_EXEC ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
+ while (uAddr <= uAddrLast)
+ {
+ MEMORY_BASIC_INFORMATION MemInfo;
+ SIZE_T cbRange = VirtualQuery((void *)uAddr, &MemInfo, sizeof(MemInfo));
+ AssertReturn(cbRange == sizeof(MemInfo), VERR_NOT_SUPPORTED);
+ Assert(MemInfo.RegionSize > 0);
+
+ if ( MemInfo.State == MEM_FREE
+ && MemInfo.RegionSize >= cbAlloc)
+ {
+ void *pv = VirtualAlloc((void *)uAddr, cbAlloc, MEM_RESERVE | MEM_COMMIT, fPageProt);
+ if ((uintptr_t)pv == uAddr)
+ {
+ *ppv = pv;
+ return VINF_SUCCESS;
+ }
+ AssertStmt(!pv, VirtualFree(pv, cbAlloc, MEM_RELEASE));
+ }
+
+ /* skip ahead */
+ uintptr_t uAddrNext = (uintptr_t)MemInfo.BaseAddress + MemInfo.RegionSize;
+ if (uAddrNext <= uAddr)
+ break;
+ uAddr += uAddrNext;
+ }
+
+ return VERR_NO_MEMORY;
+}
+
+
+DECLHIDDEN(int) rtMemAllocEx16BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv)
+{
+ cbAlloc = RT_ALIGN_Z(cbAlloc, PAGE_SIZE);
+ AssertReturn(cbAlloc <= _64K - PAGE_SIZE, VERR_NO_MEMORY);
+
+ /* Seems this doesn't work on W7/64... */
+ return rtMemAllocExInRange(cbAlloc, fFlags, ppv, PAGE_SIZE, _64K - cbAlloc);
+}
+
+
+DECLHIDDEN(int) rtMemAllocEx32BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv)
+{
+ cbAlloc = RT_ALIGN_Z(cbAlloc, PAGE_SIZE);
+ AssertReturn(cbAlloc <= _2G+_1G, VERR_NO_MEMORY);
+
+ /*
+ * Just try first.
+ */
+ DWORD fPageProt = (fFlags & RTMEMALLOCEX_FLAGS_EXEC ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
+ void *pv = VirtualAlloc(NULL, cbAlloc, MEM_RESERVE | MEM_COMMIT, fPageProt);
+ if (!pv)
+ return VERR_NO_MEMORY;
+ if ((uintptr_t)pv + cbAlloc - 1 < _4G)
+ {
+ *ppv = pv;
+ return VINF_SUCCESS;
+ }
+ VirtualFree(pv, cbAlloc, MEM_RELEASE);
+
+ /*
+ * No luck, do address scan based allocation.
+ */
+ return rtMemAllocExInRange(cbAlloc, fFlags, ppv, _64K, _4G - cbAlloc);
+}
+
+
+DECLHIDDEN(void) rtMemFreeExYyBitReach(void *pv, size_t cb, uint32_t fFlags)
+{
+ BOOL fRc = VirtualFree(pv, cb, MEM_RELEASE);
+ Assert(fRc);
+}
+
diff --git a/src/VBox/Runtime/r3/win/dir-win.cpp b/src/VBox/Runtime/r3/win/dir-win.cpp
index 2494b8b4..5c57315f 100644
--- a/src/VBox/Runtime/r3/win/dir-win.cpp
+++ b/src/VBox/Runtime/r3/win/dir-win.cpp
@@ -1,10 +1,10 @@
/* $Id: dir-win.cpp $ */
/** @file
- * IPRT - Directory, win32.
+ * IPRT - Directory, Windows.
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,20 +30,17 @@
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_DIR
#include <Windows.h>
-#include <io.h>
#include <iprt/dir.h>
#include <iprt/path.h>
-#include <iprt/alloc.h>
+#include <iprt/mem.h>
#include <iprt/string.h>
#include <iprt/assert.h>
-#include <iprt/param.h>
#include <iprt/err.h>
#include <iprt/file.h>
#include <iprt/log.h>
#include "internal/fs.h"
#include "internal/path.h"
-#include "internal/dir.h"
@@ -129,339 +126,6 @@ RTDECL(int) RTDirFlush(const char *pszPath)
}
-int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
-{
- /*
- * Setup the search expression.
- *
- * pszPathBuf is pointing to the return 4K return buffer for the RTPathReal()
- * call in rtDirOpenCommon(), so all we gota do is check that we don't overflow
- * it when adding the wildcard expression.
- */
- size_t cchExpr;
- const char *pszExpr;
- if (pDir->enmFilter == RTDIRFILTER_WINNT)
- {
- pszExpr = pDir->pszFilter;
- cchExpr = pDir->cchFilter + 1;
- }
- else
- {
- pszExpr = "*";
- cchExpr = sizeof("*");
- }
- if (pDir->cchPath + cchExpr > RTPATH_MAX)
- return VERR_FILENAME_TOO_LONG;
- memcpy(pszPathBuf + pDir->cchPath, pszExpr, cchExpr);
-
-
- /*
- * Attempt opening the search.
- */
- int rc = VINF_SUCCESS;
- PRTUTF16 pwszName;
- rc = RTStrToUtf16(pszPathBuf, &pwszName);
- if (RT_SUCCESS(rc))
- {
- pDir->hDir = FindFirstFileW((LPCWSTR)pwszName, &pDir->Data);
- if (pDir->hDir != INVALID_HANDLE_VALUE)
- pDir->fDataUnread = true;
- /* theoretical case of an empty directory. */
- else if (GetLastError() == ERROR_NO_MORE_FILES)
- pDir->fDataUnread = false;
- else
- rc = RTErrConvertFromWin32(GetLastError());
- RTUtf16Free(pwszName);
- }
-
- return rc;
-}
-
-
-RTDECL(int) RTDirClose(PRTDIR pDir)
-{
- /*
- * Validate input.
- */
- if (!pDir)
- return VERR_INVALID_PARAMETER;
- if (pDir->u32Magic != RTDIR_MAGIC)
- {
- AssertMsgFailed(("Invalid pDir=%p\n", pDir));
- return VERR_INVALID_PARAMETER;
- }
-
- /*
- * Close the handle.
- */
- pDir->u32Magic++;
- if (pDir->hDir != INVALID_HANDLE_VALUE)
- {
- BOOL fRc = FindClose(pDir->hDir);
- Assert(fRc);
- pDir->hDir = INVALID_HANDLE_VALUE;
- }
- RTStrFree(pDir->pszName);
- pDir->pszName = NULL;
- RTMemFree(pDir);
-
- return VINF_SUCCESS;
-}
-
-
-RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
-{
- /*
- * Validate input.
- */
- if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
- {
- AssertMsgFailed(("Invalid pDir=%p\n", pDir));
- return VERR_INVALID_PARAMETER;
- }
- if (!pDirEntry)
- {
- AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
- return VERR_INVALID_PARAMETER;
- }
- size_t cbDirEntry = sizeof(*pDirEntry);
- if (pcbDirEntry)
- {
- cbDirEntry = *pcbDirEntry;
- if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRY, szName[2]))
- {
- AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])));
- return VERR_INVALID_PARAMETER;
- }
- }
-
- /*
- * Fetch data?
- */
- if (!pDir->fDataUnread)
- {
- RTStrFree(pDir->pszName);
- pDir->pszName = NULL;
-
- BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
- if (!fRc)
- {
- int iErr = GetLastError();
- if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
- return VERR_NO_MORE_FILES;
- return RTErrConvertFromWin32(iErr);
- }
- }
-
- /*
- * Convert the filename to UTF-8.
- */
- if (!pDir->pszName)
- {
- int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
- if (RT_FAILURE(rc))
- {
- pDir->pszName = NULL;
- return rc;
- }
- pDir->cchName = strlen(pDir->pszName);
- }
-
- /*
- * Check if we've got enough space to return the data.
- */
- const char *pszName = pDir->pszName;
- const size_t cchName = pDir->cchName;
- const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName;
- if (pcbDirEntry)
- *pcbDirEntry = cbRequired;
- if (cbRequired > cbDirEntry)
- return VERR_BUFFER_OVERFLOW;
-
- /*
- * Setup the returned data.
- */
- pDir->fDataUnread = false;
- pDirEntry->INodeId = 0; /** @todo we can use the fileid here if we must (see GetFileInformationByHandle). */
- pDirEntry->enmType = pDir->Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
- ? RTDIRENTRYTYPE_DIRECTORY : RTDIRENTRYTYPE_FILE;
- pDirEntry->cbName = (uint16_t)cchName;
- Assert(pDirEntry->cbName == cchName);
- memcpy(pDirEntry->szName, pszName, cchName + 1);
-
- return VINF_SUCCESS;
-}
-
-
-RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
-{
- /** @todo Symlinks: Find[First|Next]FileW will return info about
- the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */
- /*
- * Validate input.
- */
- if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
- {
- AssertMsgFailed(("Invalid pDir=%p\n", pDir));
- return VERR_INVALID_PARAMETER;
- }
- if (!pDirEntry)
- {
- AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
- return VERR_INVALID_PARAMETER;
- }
- if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
- || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
- {
- AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
- return VERR_INVALID_PARAMETER;
- }
- AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
- size_t cbDirEntry = sizeof(*pDirEntry);
- if (pcbDirEntry)
- {
- cbDirEntry = *pcbDirEntry;
- if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRYEX, szName[2]))
- {
- AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])));
- return VERR_INVALID_PARAMETER;
- }
- }
-
- /*
- * Fetch data?
- */
- if (!pDir->fDataUnread)
- {
- RTStrFree(pDir->pszName);
- pDir->pszName = NULL;
-
- BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
- if (!fRc)
- {
- int iErr = GetLastError();
- if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
- return VERR_NO_MORE_FILES;
- return RTErrConvertFromWin32(iErr);
- }
- }
-
- /*
- * Convert the filename to UTF-8.
- */
- if (!pDir->pszName)
- {
- int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
- if (RT_FAILURE(rc))
- {
- pDir->pszName = NULL;
- return rc;
- }
- pDir->cchName = strlen(pDir->pszName);
- }
-
- /*
- * Check if we've got enough space to return the data.
- */
- const char *pszName = pDir->pszName;
- const size_t cchName = pDir->cchName;
- const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName;
- if (pcbDirEntry)
- *pcbDirEntry = cbRequired;
- if (cbRequired > cbDirEntry)
- return VERR_BUFFER_OVERFLOW;
-
- /*
- * Setup the returned data.
- */
- pDir->fDataUnread = false;
- pDirEntry->cbName = (uint16_t)cchName;
- Assert(pDirEntry->cbName == cchName);
- memcpy(pDirEntry->szName, pszName, cchName + 1);
- if (pDir->Data.cAlternateFileName[0])
- {
- /* copy and calc length */
- PCRTUTF16 pwszSrc = (PCRTUTF16)pDir->Data.cAlternateFileName;
- PRTUTF16 pwszDst = pDirEntry->wszShortName;
- uint32_t off = 0;
- while (pwszSrc[off] && off < RT_ELEMENTS(pDirEntry->wszShortName) - 1U)
- {
- pwszDst[off] = pwszSrc[off];
- off++;
- }
- pDirEntry->cwcShortName = (uint16_t)off;
-
- /* zero the rest */
- do
- pwszDst[off++] = '\0';
- while (off < RT_ELEMENTS(pDirEntry->wszShortName));
- }
- else
- {
- memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
- pDirEntry->cwcShortName = 0;
- }
-
- pDirEntry->Info.cbObject = ((uint64_t)pDir->Data.nFileSizeHigh << 32)
- | (uint64_t)pDir->Data.nFileSizeLow;
- pDirEntry->Info.cbAllocated = pDirEntry->Info.cbObject;
-
- Assert(sizeof(uint64_t) == sizeof(pDir->Data.ftCreationTime));
- RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, *(uint64_t *)&pDir->Data.ftCreationTime);
- RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, *(uint64_t *)&pDir->Data.ftLastAccessTime);
- RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, *(uint64_t *)&pDir->Data.ftLastWriteTime);
- pDirEntry->Info.ChangeTime = pDirEntry->Info.ModificationTime;
-
- pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pDir->Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
- pszName, cchName);
-
- /*
- * Requested attributes (we cannot provide anything actually).
- */
- switch (enmAdditionalAttribs)
- {
- case RTFSOBJATTRADD_EASIZE:
- pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
- pDirEntry->Info.Attr.u.EASize.cb = 0;
- break;
-
- case RTFSOBJATTRADD_UNIX:
- pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
- pDirEntry->Info.Attr.u.Unix.uid = ~0U;
- pDirEntry->Info.Attr.u.Unix.gid = ~0U;
- pDirEntry->Info.Attr.u.Unix.cHardlinks = 1;
- pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */
- pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */
- pDirEntry->Info.Attr.u.Unix.fFlags = 0;
- pDirEntry->Info.Attr.u.Unix.GenerationId = 0;
- pDirEntry->Info.Attr.u.Unix.Device = 0;
- break;
-
- case RTFSOBJATTRADD_NOTHING:
- pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
- break;
-
- case RTFSOBJATTRADD_UNIX_OWNER:
- pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
- pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U;
- pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
- break;
-
- case RTFSOBJATTRADD_UNIX_GROUP:
- pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
- pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U;
- pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0';
- break;
-
- default:
- AssertMsgFailed(("Impossible!\n"));
- return VERR_INTERNAL_ERROR;
- }
-
- return VINF_SUCCESS;
-}
-
-
RTDECL(int) RTDirRename(const char *pszSrc, const char *pszDst, unsigned fRename)
{
/*
diff --git a/src/VBox/Runtime/r3/win/direnum-win.cpp b/src/VBox/Runtime/r3/win/direnum-win.cpp
new file mode 100644
index 00000000..acc98de3
--- /dev/null
+++ b/src/VBox/Runtime/r3/win/direnum-win.cpp
@@ -0,0 +1,389 @@
+/* $Id: direnum-win.cpp $ */
+/** @file
+ * IPRT - Directory Enumeration, Windows.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DIR
+#include <Windows.h>
+
+#include <iprt/dir.h>
+#include <iprt/path.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/log.h>
+#include "internal/fs.h"
+#include "internal/dir.h"
+
+
+size_t rtDirNativeGetStructSize(const char *pszPath)
+{
+ NOREF(pszPath);
+ return sizeof(RTDIR);
+}
+
+
+int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
+{
+ /*
+ * Setup the search expression.
+ *
+ * pszPathBuf is pointing to the return 4K return buffer for the RTPathReal()
+ * call in rtDirOpenCommon(), so all we gota do is check that we don't overflow
+ * it when adding the wildcard expression.
+ */
+ size_t cbExpr;
+ const char *pszExpr;
+ if (pDir->enmFilter == RTDIRFILTER_WINNT)
+ {
+ pszExpr = pDir->pszFilter;
+ cbExpr = pDir->cchFilter + 1;
+ }
+ else
+ {
+ pszExpr = "*";
+ cbExpr = sizeof("*");
+ }
+ if (pDir->cchPath + cbExpr > RTPATH_MAX)
+ return VERR_FILENAME_TOO_LONG;
+ memcpy(pszPathBuf + pDir->cchPath, pszExpr, cbExpr);
+
+
+ /*
+ * Attempt opening the search.
+ */
+ int rc = VINF_SUCCESS;
+ PRTUTF16 pwszName;
+ rc = RTStrToUtf16(pszPathBuf, &pwszName);
+ if (RT_SUCCESS(rc))
+ {
+ pDir->hDir = FindFirstFileW((LPCWSTR)pwszName, &pDir->Data);
+ if (pDir->hDir != INVALID_HANDLE_VALUE)
+ pDir->fDataUnread = true;
+ else
+ {
+ DWORD dwErr = GetLastError();
+ /* Theoretical case of an empty directory or more normal case of no matches. */
+ if ( dwErr == ERROR_FILE_NOT_FOUND
+ || dwErr == ERROR_NO_MORE_FILES /* ???*/)
+ pDir->fDataUnread = false;
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
+ }
+ RTUtf16Free(pwszName);
+ }
+
+ return rc;
+}
+
+
+RTDECL(int) RTDirClose(PRTDIR pDir)
+{
+ /*
+ * Validate input.
+ */
+ if (!pDir)
+ return VERR_INVALID_PARAMETER;
+ if (pDir->u32Magic != RTDIR_MAGIC)
+ {
+ AssertMsgFailed(("Invalid pDir=%p\n", pDir));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Close the handle.
+ */
+ pDir->u32Magic++;
+ if (pDir->hDir != INVALID_HANDLE_VALUE)
+ {
+ BOOL fRc = FindClose(pDir->hDir);
+ Assert(fRc);
+ pDir->hDir = INVALID_HANDLE_VALUE;
+ }
+ RTStrFree(pDir->pszName);
+ pDir->pszName = NULL;
+ RTMemFree(pDir);
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
+{
+ /*
+ * Validate input.
+ */
+ if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
+ {
+ AssertMsgFailed(("Invalid pDir=%p\n", pDir));
+ return VERR_INVALID_PARAMETER;
+ }
+ if (!pDirEntry)
+ {
+ AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
+ return VERR_INVALID_PARAMETER;
+ }
+ size_t cbDirEntry = sizeof(*pDirEntry);
+ if (pcbDirEntry)
+ {
+ cbDirEntry = *pcbDirEntry;
+ if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRY, szName[2]))
+ {
+ AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])));
+ return VERR_INVALID_PARAMETER;
+ }
+ }
+
+ /*
+ * Fetch data?
+ */
+ if (!pDir->fDataUnread)
+ {
+ RTStrFree(pDir->pszName);
+ pDir->pszName = NULL;
+
+ BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
+ if (!fRc)
+ {
+ int iErr = GetLastError();
+ if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
+ return VERR_NO_MORE_FILES;
+ return RTErrConvertFromWin32(iErr);
+ }
+ }
+
+ /*
+ * Convert the filename to UTF-8.
+ */
+ if (!pDir->pszName)
+ {
+ int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
+ if (RT_FAILURE(rc))
+ {
+ pDir->pszName = NULL;
+ return rc;
+ }
+ pDir->cchName = strlen(pDir->pszName);
+ }
+
+ /*
+ * Check if we've got enough space to return the data.
+ */
+ const char *pszName = pDir->pszName;
+ const size_t cchName = pDir->cchName;
+ const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName;
+ if (pcbDirEntry)
+ *pcbDirEntry = cbRequired;
+ if (cbRequired > cbDirEntry)
+ return VERR_BUFFER_OVERFLOW;
+
+ /*
+ * Setup the returned data.
+ */
+ pDir->fDataUnread = false;
+ pDirEntry->INodeId = 0; /** @todo we can use the fileid here if we must (see GetFileInformationByHandle). */
+ pDirEntry->enmType = pDir->Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
+ ? RTDIRENTRYTYPE_DIRECTORY : RTDIRENTRYTYPE_FILE;
+ pDirEntry->cbName = (uint16_t)cchName;
+ Assert(pDirEntry->cbName == cchName);
+ memcpy(pDirEntry->szName, pszName, cchName + 1);
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
+ /** @todo Symlinks: Find[First|Next]FileW will return info about
+ the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */
+ /*
+ * Validate input.
+ */
+ if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
+ {
+ AssertMsgFailed(("Invalid pDir=%p\n", pDir));
+ return VERR_INVALID_PARAMETER;
+ }
+ if (!pDirEntry)
+ {
+ AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
+ return VERR_INVALID_PARAMETER;
+ }
+ if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
+ || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
+ {
+ AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
+ return VERR_INVALID_PARAMETER;
+ }
+ AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
+ size_t cbDirEntry = sizeof(*pDirEntry);
+ if (pcbDirEntry)
+ {
+ cbDirEntry = *pcbDirEntry;
+ if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRYEX, szName[2]))
+ {
+ AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])));
+ return VERR_INVALID_PARAMETER;
+ }
+ }
+
+ /*
+ * Fetch data?
+ */
+ if (!pDir->fDataUnread)
+ {
+ RTStrFree(pDir->pszName);
+ pDir->pszName = NULL;
+
+ BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
+ if (!fRc)
+ {
+ int iErr = GetLastError();
+ if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
+ return VERR_NO_MORE_FILES;
+ return RTErrConvertFromWin32(iErr);
+ }
+ }
+
+ /*
+ * Convert the filename to UTF-8.
+ */
+ if (!pDir->pszName)
+ {
+ int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
+ if (RT_FAILURE(rc))
+ {
+ pDir->pszName = NULL;
+ return rc;
+ }
+ pDir->cchName = strlen(pDir->pszName);
+ }
+
+ /*
+ * Check if we've got enough space to return the data.
+ */
+ const char *pszName = pDir->pszName;
+ const size_t cchName = pDir->cchName;
+ const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName;
+ if (pcbDirEntry)
+ *pcbDirEntry = cbRequired;
+ if (cbRequired > cbDirEntry)
+ return VERR_BUFFER_OVERFLOW;
+
+ /*
+ * Setup the returned data.
+ */
+ pDir->fDataUnread = false;
+ pDirEntry->cbName = (uint16_t)cchName;
+ Assert(pDirEntry->cbName == cchName);
+ memcpy(pDirEntry->szName, pszName, cchName + 1);
+ if (pDir->Data.cAlternateFileName[0])
+ {
+ /* copy and calc length */
+ PCRTUTF16 pwszSrc = (PCRTUTF16)pDir->Data.cAlternateFileName;
+ PRTUTF16 pwszDst = pDirEntry->wszShortName;
+ uint32_t off = 0;
+ while (pwszSrc[off] && off < RT_ELEMENTS(pDirEntry->wszShortName) - 1U)
+ {
+ pwszDst[off] = pwszSrc[off];
+ off++;
+ }
+ pDirEntry->cwcShortName = (uint16_t)off;
+
+ /* zero the rest */
+ do
+ pwszDst[off++] = '\0';
+ while (off < RT_ELEMENTS(pDirEntry->wszShortName));
+ }
+ else
+ {
+ memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
+ pDirEntry->cwcShortName = 0;
+ }
+
+ pDirEntry->Info.cbObject = ((uint64_t)pDir->Data.nFileSizeHigh << 32)
+ | (uint64_t)pDir->Data.nFileSizeLow;
+ pDirEntry->Info.cbAllocated = pDirEntry->Info.cbObject;
+
+ Assert(sizeof(uint64_t) == sizeof(pDir->Data.ftCreationTime));
+ RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, *(uint64_t *)&pDir->Data.ftCreationTime);
+ RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, *(uint64_t *)&pDir->Data.ftLastAccessTime);
+ RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, *(uint64_t *)&pDir->Data.ftLastWriteTime);
+ pDirEntry->Info.ChangeTime = pDirEntry->Info.ModificationTime;
+
+ pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pDir->Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
+ pszName, cchName);
+
+ /*
+ * Requested attributes (we cannot provide anything actually).
+ */
+ switch (enmAdditionalAttribs)
+ {
+ case RTFSOBJATTRADD_EASIZE:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
+ pDirEntry->Info.Attr.u.EASize.cb = 0;
+ break;
+
+ case RTFSOBJATTRADD_UNIX:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
+ pDirEntry->Info.Attr.u.Unix.uid = ~0U;
+ pDirEntry->Info.Attr.u.Unix.gid = ~0U;
+ pDirEntry->Info.Attr.u.Unix.cHardlinks = 1;
+ pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */
+ pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */
+ pDirEntry->Info.Attr.u.Unix.fFlags = 0;
+ pDirEntry->Info.Attr.u.Unix.GenerationId = 0;
+ pDirEntry->Info.Attr.u.Unix.Device = 0;
+ break;
+
+ case RTFSOBJATTRADD_NOTHING:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
+ break;
+
+ case RTFSOBJATTRADD_UNIX_OWNER:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
+ pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U;
+ pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
+ break;
+
+ case RTFSOBJATTRADD_UNIX_GROUP:
+ pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
+ pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U;
+ pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0';
+ break;
+
+ default:
+ AssertMsgFailed(("Impossible!\n"));
+ return VERR_INTERNAL_ERROR;
+ }
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/r3/win/dllmain-win.cpp b/src/VBox/Runtime/r3/win/dllmain-win.cpp
index 1646b39e..6efb702a 100644
--- a/src/VBox/Runtime/r3/win/dllmain-win.cpp
+++ b/src/VBox/Runtime/r3/win/dllmain-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/env-win.cpp b/src/VBox/Runtime/r3/win/env-win.cpp
new file mode 100644
index 00000000..030c6cd7
--- /dev/null
+++ b/src/VBox/Runtime/r3/win/env-win.cpp
@@ -0,0 +1,268 @@
+/* $Id: env-win.cpp $ */
+/** @file
+ * IPRT - Environment, Posix.
+ */
+
+/*
+ * Copyright (C) 2006-2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/env.h>
+
+#include <iprt/alloca.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <iprt/mem.h>
+
+#include <stdlib.h>
+#include <errno.h>
+
+
+RTDECL(bool) RTEnvExistsBad(const char *pszVar)
+{
+ return RTEnvGetBad(pszVar) != NULL;
+}
+
+
+RTDECL(bool) RTEnvExist(const char *pszVar)
+{
+ return RTEnvExistsBad(pszVar);
+}
+
+
+RTDECL(bool) RTEnvExistsUtf8(const char *pszVar)
+{
+ PRTUTF16 pwszVar;
+ int rc = RTStrToUtf16(pszVar, &pwszVar);
+ AssertRCReturn(rc, false);
+ bool fRet = _wgetenv(pwszVar) != NULL;
+ RTUtf16Free(pwszVar);
+ return fRet;
+}
+
+
+RTDECL(const char *) RTEnvGetBad(const char *pszVar)
+{
+ return getenv(pszVar);
+}
+
+
+RTDECL(const char *) RTEnvGet(const char *pszVar)
+{
+ return RTEnvGetBad(pszVar);
+}
+
+RTDECL(int) RTEnvGetUtf8(const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual)
+{
+ AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pszValue, VERR_INVALID_POINTER);
+ AssertReturn(pszValue || !cbValue, VERR_INVALID_PARAMETER);
+ AssertPtrNullReturn(pcchActual, VERR_INVALID_POINTER);
+ AssertReturn(pcchActual || (pszValue && cbValue), VERR_INVALID_PARAMETER);
+
+ if (pcchActual)
+ *pcchActual = 0;
+
+ PRTUTF16 pwszVar;
+ int rc = RTStrToUtf16(pszVar, &pwszVar);
+ AssertRCReturn(rc, false);
+
+ /** @todo Consider _wgetenv_s or GetEnvironmentVariableW here to avoid the
+ * potential race with a concurrent _wputenv/_putenv. */
+ PCRTUTF16 pwszValue = _wgetenv(pwszVar);
+ RTUtf16Free(pwszVar);
+ if (pwszValue)
+ {
+ if (cbValue)
+ rc = RTUtf16ToUtf8Ex(pwszValue, RTSTR_MAX, &pszValue, cbValue, pcchActual);
+ else
+ rc = RTUtf16CalcUtf8LenEx(pwszValue, RTSTR_MAX, pcchActual);
+ }
+ else
+ rc = VERR_ENV_VAR_NOT_FOUND;
+ return rc;
+}
+
+
+RTDECL(int) RTEnvPutBad(const char *pszVarEqualValue)
+{
+ /** @todo putenv is a source memory leaks. deal with this on a per system basis. */
+ if (!putenv((char *)pszVarEqualValue))
+ return 0;
+ return RTErrConvertFromErrno(errno);
+}
+
+
+RTDECL(int) RTEnvPut(const char *pszVarEqualValue)
+{
+ return RTEnvPutBad(pszVarEqualValue);
+}
+
+
+RTDECL(int) RTEnvPutUtf8(const char *pszVarEqualValue)
+{
+ PRTUTF16 pwszVarEqualValue;
+ int rc = RTStrToUtf16(pszVarEqualValue, &pwszVarEqualValue);
+ if (RT_SUCCESS(rc))
+ {
+ if (!_wputenv(pwszVarEqualValue))
+ rc = VINF_SUCCESS;
+ else
+ rc = RTErrConvertFromErrno(errno);
+ RTUtf16Free(pwszVarEqualValue);
+ }
+ return rc;
+}
+
+
+
+RTDECL(int) RTEnvSetBad(const char *pszVar, const char *pszValue)
+{
+ /* make a local copy and feed it to putenv. */
+ const size_t cchVar = strlen(pszVar);
+ const size_t cchValue = strlen(pszValue);
+ char *pszTmp = (char *)alloca(cchVar + cchValue + 2 + !*pszValue);
+ memcpy(pszTmp, pszVar, cchVar);
+ pszTmp[cchVar] = '=';
+ if (*pszValue)
+ memcpy(pszTmp + cchVar + 1, pszValue, cchValue + 1);
+ else
+ {
+ pszTmp[cchVar + 1] = ' '; /* wrong, but putenv will remove it otherwise. */
+ pszTmp[cchVar + 2] = '\0';
+ }
+
+ if (!putenv(pszTmp))
+ return 0;
+ return RTErrConvertFromErrno(errno);
+}
+
+
+RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue)
+{
+ return RTEnvSetBad(pszVar, pszValue);
+}
+
+RTDECL(int) RTEnvSetUtf8(const char *pszVar, const char *pszValue)
+{
+ size_t cwcVar;
+ int rc = RTStrCalcUtf16LenEx(pszVar, RTSTR_MAX, &cwcVar);
+ if (RT_SUCCESS(rc))
+ {
+ size_t cwcValue;
+ rc = RTStrCalcUtf16LenEx(pszVar, RTSTR_MAX, &cwcValue);
+ if (RT_SUCCESS(rc))
+ {
+ PRTUTF16 pwszTmp = (PRTUTF16)RTMemTmpAlloc((cwcVar + 1 + cwcValue + 1) * sizeof(RTUTF16));
+ if (pwszTmp)
+ {
+ rc = RTStrToUtf16Ex(pszVar, RTSTR_MAX, &pwszTmp, cwcVar + 1, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ PRTUTF16 pwszTmpValue = &pwszTmp[cwcVar];
+ *pwszTmpValue++ = '=';
+ rc = RTStrToUtf16Ex(pszValue, RTSTR_MAX, &pwszTmpValue, cwcValue + 1, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ if (!_wputenv(pwszTmp))
+ rc = VINF_SUCCESS;
+ else
+ rc = RTErrConvertFromErrno(errno);
+ }
+ }
+ RTMemTmpFree(pwszTmp);
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+ }
+ }
+ return rc;
+}
+
+
+RTDECL(int) RTEnvUnsetBad(const char *pszVar)
+{
+ AssertReturn(!strchr(pszVar, '='), VERR_INVALID_PARAMETER);
+
+ /*
+ * Check that it exists first.
+ */
+ if (!RTEnvExist(pszVar))
+ return VINF_ENV_VAR_NOT_FOUND;
+
+ /*
+ * Ok, try remove it.
+ */
+#ifdef RT_OS_WINDOWS
+ /* Use putenv(var=) since Windows does not have unsetenv(). */
+ size_t cchVar = strlen(pszVar);
+ char *pszBuf = (char *)alloca(cchVar + 2);
+ memcpy(pszBuf, pszVar, cchVar);
+ pszBuf[cchVar] = '=';
+ pszBuf[cchVar + 1] = '\0';
+
+ if (!putenv(pszBuf))
+ return VINF_SUCCESS;
+
+#else
+ /* This is the preferred function as putenv() like used above does neither work on Solaris nor on Darwin. */
+ if (!unsetenv((char*)pszVar))
+ return VINF_SUCCESS;
+#endif
+
+ return RTErrConvertFromErrno(errno);
+}
+
+
+RTDECL(int) RTEnvUnset(const char *pszVar)
+{
+ return RTEnvUnsetBad(pszVar);
+}
+
+
+RTDECL(int) RTEnvUnsetUtf8(const char *pszVar)
+{
+ size_t cwcVar;
+ int rc = RTStrCalcUtf16LenEx(pszVar, RTSTR_MAX, &cwcVar);
+ if (RT_SUCCESS(rc))
+ {
+ PRTUTF16 pwszTmp = (PRTUTF16)RTMemTmpAlloc((cwcVar + 1 + 1) * sizeof(RTUTF16));
+ if (pwszTmp)
+ {
+ rc = RTStrToUtf16Ex(pszVar, RTSTR_MAX, &pwszTmp, cwcVar + 1, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ pwszTmp[cwcVar] = '=';
+ pwszTmp[cwcVar + 1] = '\0';
+ if (!_wputenv(pwszTmp))
+ rc = VINF_SUCCESS;
+ else
+ rc = RTErrConvertFromErrno(errno);
+ }
+ RTMemTmpFree(pwszTmp);
+ }
+ }
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/win/fileaio-win.cpp b/src/VBox/Runtime/r3/win/fileaio-win.cpp
index 95e20e12..73c99a7e 100644
--- a/src/VBox/Runtime/r3/win/fileaio-win.cpp
+++ b/src/VBox/Runtime/r3/win/fileaio-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -72,6 +72,8 @@ typedef struct RTFILEAIOCTXINTERNAL
volatile bool fWokenUp;
/** Flag whether the thread is currently waiting. */
volatile bool fWaiting;
+ /** Flags given during creation. */
+ uint32_t fFlags;
/** Magic value (RTFILEAIOCTX_MAGIC). */
uint32_t u32Magic;
} RTFILEAIOCTXINTERNAL;
@@ -266,10 +268,12 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered)
return rc;
}
-RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
+RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax,
+ uint32_t fFlags)
{
PRTFILEAIOCTXINTERNAL pCtxInt;
AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER);
+ AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL));
if (RT_UNLIKELY(!pCtxInt))
@@ -285,7 +289,8 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
return VERR_NO_MEMORY;
}
- pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC;
+ pCtxInt->fFlags = fFlags;
+ pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC;
*phAioCtx = (RTFILEAIOCTX)pCtxInt;
@@ -398,7 +403,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL
/*
* Can't wait if there are no requests around.
*/
- if (RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0))
+ if ( RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0)
+ && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS))
return VERR_FILE_AIO_NO_REQUEST;
/* Wait for at least one. */
diff --git a/src/VBox/Runtime/r3/win/fs-win.cpp b/src/VBox/Runtime/r3/win/fs-win.cpp
index c0fa65c3..586444e4 100644
--- a/src/VBox/Runtime/r3/win/fs-win.cpp
+++ b/src/VBox/Runtime/r3/win/fs-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -319,6 +319,9 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
pProperties->fReadOnly = !!(dwFlags & FILE_READ_ONLY_VOLUME);
pProperties->fSupportsUnicode = !!(dwFlags & FILE_UNICODE_ON_DISK);
pProperties->fCaseSensitive = false; /* win32 is case preserving only */
+ /** @todo r=bird: What about FILE_CASE_SENSITIVE_SEARCH ? Is this set for NTFS
+ * as well perchance? If so, better mention it instead of just setting
+ * fCaseSensitive to false. */
pProperties->fRemote = false; /* no idea yet */
}
else
diff --git a/src/VBox/Runtime/r3/win/init-win.cpp b/src/VBox/Runtime/r3/win/init-win.cpp
new file mode 100644
index 00000000..e40adf6a
--- /dev/null
+++ b/src/VBox/Runtime/r3/win/init-win.cpp
@@ -0,0 +1,273 @@
+/* $Id: init-win.cpp $ */
+/** @file
+ * IPRT - Init Ring-3, Windows Specific Code.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DEFAULT
+#include <Windows.h>
+#ifndef LOAD_LIBRARY_SEARCH_APPLICATION_DIR
+# define LOAD_LIBRARY_SEARCH_APPLICATION_DIR 0x200
+# define LOAD_LIBRARY_SEARCH_SYSTEM32 0x800
+#endif
+
+#include "internal-r3-win.h"
+#include <iprt/initterm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "../init.h"
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** Windows DLL loader protection level. */
+DECLHIDDEN(RTR3WINLDRPROT) g_enmWinLdrProt = RTR3WINLDRPROT_NONE;
+/** Our simplified windows version. */
+DECLHIDDEN(RTWINOSTYPE) g_enmWinVer = kRTWinOSType_UNKNOWN;
+/** Extended windows version information. */
+DECLHIDDEN(OSVERSIONINFOEX) g_WinOsInfoEx;
+/** The native kernel32.dll handle. */
+DECLHIDDEN(HMODULE) g_hModKernel32 = NULL;
+/** The native ntdll.dll handle. */
+DECLHIDDEN(HMODULE) g_hModNtDll = NULL;
+
+
+
+/**
+ * Translates OSVERSIONINOFEX into a Windows OS type.
+ *
+ * @returns The Windows OS type.
+ * @param pOSInfoEx The OS info returned by Windows.
+ *
+ * @remarks This table has been assembled from Usenet postings, personal
+ * observations, and reading other people's code. Please feel
+ * free to add to it or correct it.
+ * <pre>
+ dwPlatFormID dwMajorVersion dwMinorVersion dwBuildNumber
+95 1 4 0 950
+95 SP1 1 4 0 >950 && <=1080
+95 OSR2 1 4 <10 >1080
+98 1 4 10 1998
+98 SP1 1 4 10 >1998 && <2183
+98 SE 1 4 10 >=2183
+ME 1 4 90 3000
+
+NT 3.51 2 3 51 1057
+NT 4 2 4 0 1381
+2000 2 5 0 2195
+XP 2 5 1 2600
+2003 2 5 2 3790
+Vista 2 6 0
+
+CE 1.0 3 1 0
+CE 2.0 3 2 0
+CE 2.1 3 2 1
+CE 3.0 3 3 0
+</pre>
+ */
+static RTWINOSTYPE rtR3InitWinSimplifiedVersion(OSVERSIONINFOEX const *pOSInfoEx)
+{
+ RTWINOSTYPE enmVer = kRTWinOSType_UNKNOWN;
+ BYTE const bProductType = pOSInfoEx->wProductType;
+ DWORD const dwPlatformId = pOSInfoEx->dwPlatformId;
+ DWORD const dwMinorVersion = pOSInfoEx->dwMinorVersion;
+ DWORD const dwMajorVersion = pOSInfoEx->dwMajorVersion;
+ DWORD const dwBuildNumber = pOSInfoEx->dwBuildNumber & 0xFFFF; /* Win 9x needs this. */
+
+ if ( dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
+ && dwMajorVersion == 4)
+ {
+ if ( dwMinorVersion < 10
+ && dwBuildNumber == 950)
+ enmVer = kRTWinOSType_95;
+ else if ( dwMinorVersion < 10
+ && dwBuildNumber > 950
+ && dwBuildNumber <= 1080)
+ enmVer = kRTWinOSType_95SP1;
+ else if ( dwMinorVersion < 10
+ && dwBuildNumber > 1080)
+ enmVer = kRTWinOSType_95OSR2;
+ else if ( dwMinorVersion == 10
+ && dwBuildNumber == 1998)
+ enmVer = kRTWinOSType_98;
+ else if ( dwMinorVersion == 10
+ && dwBuildNumber > 1998
+ && dwBuildNumber < 2183)
+ enmVer = kRTWinOSType_98SP1;
+ else if ( dwMinorVersion == 10
+ && dwBuildNumber >= 2183)
+ enmVer = kRTWinOSType_98SE;
+ else if (dwMinorVersion == 90)
+ enmVer = kRTWinOSType_ME;
+ }
+ else if (dwPlatformId == VER_PLATFORM_WIN32_NT)
+ {
+ if ( dwMajorVersion == 3
+ && dwMinorVersion == 51)
+ enmVer = kRTWinOSType_NT351;
+ else if ( dwMajorVersion == 4
+ && dwMinorVersion == 0)
+ enmVer = kRTWinOSType_NT4;
+ else if ( dwMajorVersion == 5
+ && dwMinorVersion == 0)
+ enmVer = kRTWinOSType_2K;
+ else if ( dwMajorVersion == 5
+ && dwMinorVersion == 1)
+ enmVer = kRTWinOSType_XP;
+ else if ( dwMajorVersion == 5
+ && dwMinorVersion == 2)
+ enmVer = kRTWinOSType_2003;
+ else if ( dwMajorVersion == 6
+ && dwMinorVersion == 0)
+ {
+ if (bProductType != VER_NT_WORKSTATION)
+ enmVer = kRTWinOSType_2008;
+ else
+ enmVer = kRTWinOSType_VISTA;
+ }
+ else if ( dwMajorVersion == 6
+ && dwMinorVersion == 1)
+ enmVer = kRTWinOSType_7;
+ else if ( dwMajorVersion == 6
+ && dwMinorVersion == 2)
+ enmVer = kRTWinOSType_8;
+ else if ( dwMajorVersion == 6
+ && dwMinorVersion == 3)
+ enmVer = kRTWinOSType_81;
+ else
+ enmVer = kRTWinOSType_NT_UNKNOWN;
+ }
+
+ return enmVer;
+}
+
+
+DECLHIDDEN(int) rtR3InitNativeObtrusiveWorker(void)
+{
+ /*
+ * Disable error popups.
+ */
+ UINT fOldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX | fOldErrMode);
+
+ /*
+ * Query the Windows version.
+ * ASSUMES OSVERSIONINFOEX starts with the exact same layout as OSVERSIONINFO (safe).
+ */
+ AssertCompileMembersSameSizeAndOffset(OSVERSIONINFOEX, szCSDVersion, OSVERSIONINFO, szCSDVersion);
+ AssertCompileMemberOffset(OSVERSIONINFOEX, wServicePackMajor, sizeof(OSVERSIONINFO));
+ RT_ZERO(g_WinOsInfoEx);
+ g_WinOsInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ if (!GetVersionExA((POSVERSIONINFOA)&g_WinOsInfoEx))
+ {
+ /* Fallback, just get the basic info. */
+ RT_ZERO(g_WinOsInfoEx);
+ g_WinOsInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (GetVersionExA((POSVERSIONINFOA)&g_WinOsInfoEx))
+ Assert(g_WinOsInfoEx.dwPlatformId != VER_PLATFORM_WIN32_NT || g_WinOsInfoEx.dwMajorVersion < 5);
+ else
+ {
+ AssertBreakpoint();
+ RT_ZERO(g_WinOsInfoEx);
+ }
+ }
+ if (g_WinOsInfoEx.dwOSVersionInfoSize)
+ g_enmWinVer = rtR3InitWinSimplifiedVersion(&g_WinOsInfoEx);
+
+ /*
+ * Restrict DLL searching for the process on windows versions which allow
+ * us to do so.
+ * - The first trick works on XP SP1+ and disables the searching of the
+ * current directory.
+ * - The second trick is W7 w/ KB2533623 and W8+, it restrict the DLL
+ * searching to the application directory and the System32 directory.
+ */
+ int rc = VINF_SUCCESS;
+
+ typedef BOOL (WINAPI *PFNSETDLLDIRECTORY)(LPCWSTR);
+ PFNSETDLLDIRECTORY pfnSetDllDir = (PFNSETDLLDIRECTORY)GetProcAddress(g_hModKernel32, "SetDllDirectoryW");
+ if (pfnSetDllDir)
+ {
+ if (pfnSetDllDir(L""))
+ g_enmWinLdrProt = RTR3WINLDRPROT_NO_CWD;
+ else
+ rc = VERR_INTERNAL_ERROR_3;
+ }
+
+ /** @bugref 6861: Observed GUI issues on Vista (32-bit and 64-bit). */
+ if (g_enmWinVer > kRTWinOSType_VISTA)
+ {
+ typedef BOOL(WINAPI *PFNSETDEFAULTDLLDIRECTORIES)(DWORD);
+ PFNSETDEFAULTDLLDIRECTORIES pfnSetDefDllDirs;
+ pfnSetDefDllDirs = (PFNSETDEFAULTDLLDIRECTORIES)GetProcAddress(g_hModKernel32, "SetDefaultDllDirectories");
+ if (pfnSetDefDllDirs)
+ {
+ if (pfnSetDefDllDirs(LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32))
+ g_enmWinLdrProt = RTR3WINLDRPROT_SAFE;
+ else if (RT_SUCCESS(rc))
+ rc = VERR_INTERNAL_ERROR_4;
+ }
+ }
+
+ return rc;
+}
+
+
+DECLHIDDEN(int) rtR3InitNativeFirst(uint32_t fFlags)
+{
+ /*
+ * Make sure we've got the handles of the two main Windows NT dlls.
+ */
+ g_hModKernel32 = GetModuleHandleW(L"kernel32.dll");
+ if (g_hModKernel32 == NULL)
+ return VERR_INTERNAL_ERROR_2;
+ g_hModNtDll = GetModuleHandleW(L"ntdll.dll");
+ if (g_hModNtDll == NULL)
+ return VERR_INTERNAL_ERROR_2;
+
+ int rc = VINF_SUCCESS;
+ if (!(fFlags & RTR3INIT_FLAGS_UNOBTRUSIVE))
+ rc = rtR3InitNativeObtrusiveWorker();
+
+ return rc;
+}
+
+
+DECLHIDDEN(void) rtR3InitNativeObtrusive(void)
+{
+ rtR3InitNativeObtrusiveWorker();
+}
+
+
+DECLHIDDEN(int) rtR3InitNativeFinal(uint32_t fFlags)
+{
+ /* Nothing to do here. */
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/r3/win/internal-r3-win.h b/src/VBox/Runtime/r3/win/internal-r3-win.h
new file mode 100644
index 00000000..efec00a1
--- /dev/null
+++ b/src/VBox/Runtime/r3/win/internal-r3-win.h
@@ -0,0 +1,72 @@
+
+#ifndef ___internal_r3_win_h
+#define ___internal_r3_win_h
+
+#include "internal/iprt.h"
+#include <iprt/types.h>
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Windows OS type as determined by rtSystemWinOSType().
+ *
+ * @note ASSUMPTIONS are made regarding ordering. Win 9x should come first, then
+ * NT. The Win9x and NT versions should internally be ordered in ascending
+ * version/code-base order.
+ */
+typedef enum RTWINOSTYPE
+{
+ kRTWinOSType_UNKNOWN = 0,
+ kRTWinOSType_9XFIRST = 1,
+ kRTWinOSType_95 = kRTWinOSType_9XFIRST,
+ kRTWinOSType_95SP1,
+ kRTWinOSType_95OSR2,
+ kRTWinOSType_98,
+ kRTWinOSType_98SP1,
+ kRTWinOSType_98SE,
+ kRTWinOSType_ME,
+ kRTWinOSType_9XLAST = 99,
+ kRTWinOSType_NTFIRST = 100,
+ kRTWinOSType_NT31 = kRTWinOSType_NTFIRST,
+ kRTWinOSType_NT351,
+ kRTWinOSType_NT4,
+ kRTWinOSType_2K,
+ kRTWinOSType_XP,
+ kRTWinOSType_2003,
+ kRTWinOSType_VISTA,
+ kRTWinOSType_2008,
+ kRTWinOSType_7,
+ kRTWinOSType_8,
+ kRTWinOSType_81,
+ kRTWinOSType_NT_UNKNOWN = 199,
+ kRTWinOSType_NT_LAST = kRTWinOSType_UNKNOWN
+} RTWINOSTYPE;
+
+/**
+ * Windows loader protection level.
+ */
+typedef enum RTR3WINLDRPROT
+{
+ RTR3WINLDRPROT_INVALID = 0,
+ RTR3WINLDRPROT_NONE,
+ RTR3WINLDRPROT_NO_CWD,
+ RTR3WINLDRPROT_SAFE
+} RTR3WINLDRPROT;
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+extern DECLHIDDEN(RTR3WINLDRPROT) g_enmWinLdrProt;
+extern DECLHIDDEN(RTWINOSTYPE) g_enmWinVer;
+#ifdef _WINDEF_
+extern DECLHIDDEN(HMODULE) g_hModKernel32;
+extern DECLHIDDEN(HMODULE) g_hModNtDll;
+extern DECLHIDDEN(OSVERSIONINFOEX) g_WinOsInfoEx;
+#endif
+
+
+#endif
+
diff --git a/src/VBox/Runtime/r3/win/ldrNative-win.cpp b/src/VBox/Runtime/r3/win/ldrNative-win.cpp
index 54016958..8b26ab2c 100644
--- a/src/VBox/Runtime/r3/win/ldrNative-win.cpp
+++ b/src/VBox/Runtime/r3/win/ldrNative-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,10 +31,17 @@
#include <Windows.h>
#include <iprt/ldr.h>
+#include "internal/iprt.h"
+
+#include <iprt/alloca.h>
#include <iprt/assert.h>
-#include <iprt/path.h>
#include <iprt/err.h>
-#include <iprt/alloca.h>
+#include <iprt/file.h>
+#include <iprt/log.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+
+#include <iprt/once.h>
#include <iprt/string.h>
#include "internal/ldr.h"
@@ -42,7 +49,10 @@
int rtldrNativeLoad(const char *pszFilename, uintptr_t *phHandle, uint32_t fFlags, PRTERRINFO pErrInfo)
{
Assert(sizeof(*phHandle) >= sizeof(HMODULE));
- AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
+ AssertReturn(fFlags == 0 || fFlags == RTLDRLOAD_FLAGS_NO_UNLOAD, VERR_INVALID_PARAMETER);
+ AssertLogRelMsgReturn(RTPathStartsWithRoot(pszFilename), /* Relative names will still be applied to the search path. */
+ ("pszFilename='%s'\n", pszFilename),
+ VERR_INTERNAL_ERROR_2);
/*
* Do we need to add an extension?
@@ -72,7 +82,7 @@ int rtldrNativeLoad(const char *pszFilename, uintptr_t *phHandle, uint32_t fFlag
* Try figure why it failed to load.
*/
DWORD dwErr = GetLastError();
- int rc = RTErrConvertFromWin32(dwErr);
+ int rc = RTErrConvertFromWin32(dwErr);
return RTErrInfoSetF(pErrInfo, rc, "GetLastError=%u", dwErr);
}
@@ -94,7 +104,8 @@ DECLCALLBACK(int) rtldrNativeGetSymbol(PRTLDRMODINTERNAL pMod, const char *pszSy
DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod)
{
PRTLDRMODNATIVE pModNative = (PRTLDRMODNATIVE)pMod;
- if (FreeLibrary((HMODULE)pModNative->hNative))
+ if ( (pModNative->fFlags & RTLDRLOAD_FLAGS_NO_UNLOAD)
+ || FreeLibrary((HMODULE)pModNative->hNative))
{
pModNative->hNative = (uintptr_t)INVALID_HANDLE_VALUE;
return VINF_SUCCESS;
@@ -102,3 +113,34 @@ DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod)
return RTErrConvertFromWin32(GetLastError());
}
+
+int rtldrNativeLoadSystem(const char *pszFilename, const char *pszExt, uint32_t fFlags, PRTLDRMOD phLdrMod)
+{
+ /*
+ * We only try the System32 directory.
+ */
+ WCHAR wszSysDir[MAX_PATH];
+ UINT cwcSysDir = GetSystemDirectoryW(wszSysDir, MAX_PATH);
+ if (cwcSysDir >= MAX_PATH)
+ return VERR_FILENAME_TOO_LONG;
+
+ char szPath[RTPATH_MAX];
+ char *pszPath = szPath;
+ int rc = RTUtf16ToUtf8Ex(wszSysDir, RTSTR_MAX, &pszPath, sizeof(szPath), NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTPathAppend(szPath, sizeof(szPath), pszFilename);
+ if (pszExt && RT_SUCCESS(rc))
+ rc = RTStrCat(szPath, sizeof(szPath), pszExt);
+ if (RT_SUCCESS(rc))
+ {
+ if (RTFileExists(szPath))
+ rc = RTLdrLoadEx(szPath, phLdrMod, fFlags, NULL);
+ else
+ rc = VERR_MODULE_NOT_FOUND;
+ }
+ }
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/win/localipc-win.cpp b/src/VBox/Runtime/r3/win/localipc-win.cpp
index 15ff6f8b..a25b9cac 100644
--- a/src/VBox/Runtime/r3/win/localipc-win.cpp
+++ b/src/VBox/Runtime/r3/win/localipc-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -41,15 +41,17 @@
#include <Windows.h>
#include <sddl.h>
-#include <iprt/localipc.h>
-#include <iprt/thread.h>
-#include <iprt/critsect.h>
#include <iprt/alloc.h>
+#include <iprt/asm.h>
#include <iprt/assert.h>
-#include <iprt/param.h>
+#include <iprt/critsect.h>
#include <iprt/err.h>
+#include <iprt/ldr.h>
+#include <iprt/localipc.h>
+#include <iprt/param.h>
#include <iprt/string.h>
-#include <iprt/asm.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
#include "internal/magics.h"
@@ -66,7 +68,9 @@
*
* Note! FILE_GENERIC_WRITE (SDDL_FILE_WRITE) is evil here because it includes
* the FILE_CREATE_PIPE_INSTANCE(=FILE_APPEND_DATA) flag. Thus the hardcoded
- * value 0x0012019b in the 2nd ACE. It expands to:
+ * value 0x0012019b in the client ACE. The server-side still needs
+ * setting FILE_CREATE_PIPE_INSTANCE although.
+ * It expands to:
* 0x00000001 - FILE_READ_DATA
* 0x00000008 - FILE_READ_EA
* 0x00000080 - FILE_READ_ATTRIBUTES
@@ -75,11 +79,12 @@
* 0x00000002 - FILE_WRITE_DATA
* 0x00000010 - FILE_WRITE_EA
* 0x00000100 - FILE_WRITE_ATTRIBUTES
- * 0x0012019b
- * or FILE_GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_CREATE_PIPE_INSTANCE)
+ * = 0x0012019b (client)
+ * + (only for server):
+ * 0x00000004 - FILE_CREATE_PIPE_INSTANCE
+ * = 0x0012019f
*
- * @todo Double check this!
- * @todo Drop the EA rights too? Since they doesn't mean anything to PIPS according to the docs.
+ * @todo Triple check this!
* @todo EVERYONE -> AUTHENTICATED USERS or something more appropriate?
* @todo Have trouble allowing the owner FILE_CREATE_PIPE_INSTANCE access, so for now I'm hacking
* it just to get progress - the service runs as local system.
@@ -88,12 +93,19 @@
* is to go the annoying route of OpenProcessToken, QueryTokenInformation,
* ConvertSidToStringSid and then use the result... Suggestions are very welcome
*/
-#define RTLOCALIPC_WIN_SDDL \
- SDDL_DACL SDDL_DELIMINATOR \
+#define RTLOCALIPC_WIN_SDDL_BASE \
+ SDDL_DACL SDDL_DELIMINATOR \
SDDL_ACE_BEGIN SDDL_ACCESS_DENIED ";;" SDDL_GENERIC_ALL ";;;" SDDL_NETWORK SDDL_ACE_END \
- SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b" ";;;" SDDL_EVERYONE SDDL_ACE_END \
SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL ";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
+#define RTLOCALIPC_WIN_SDDL_SERVER \
+ RTLOCALIPC_WIN_SDDL_BASE \
+ SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019f" ";;;" SDDL_EVERYONE SDDL_ACE_END
+
+#define RTLOCALIPC_WIN_SDDL_CLIENT \
+ RTLOCALIPC_WIN_SDDL_BASE \
+ SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b" ";;;" SDDL_EVERYONE SDDL_ACE_END
+
// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_GENERIC_ALL ";;;" SDDL_PERSONAL_SELF SDDL_ACE_END \
// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";CIOI;" SDDL_GENERIC_ALL ";;;" SDDL_CREATOR_OWNER SDDL_ACE_END
// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b" ";;;" SDDL_EVERYONE SDDL_ACE_END
@@ -138,24 +150,41 @@ typedef RTLOCALIPCSERVERINT *PRTLOCALIPCSERVERINT;
typedef struct RTLOCALIPCSESSIONINT
{
/** The magic (RTLOCALIPCSESSION_MAGIC). */
- uint32_t u32Magic;
+ uint32_t u32Magic;
/** Critical section protecting the structure. */
- RTCRITSECT CritSect;
+ RTCRITSECT CritSect;
/** The number of references to the instance.
* @remarks The reference counting isn't race proof. */
- uint32_t volatile cRefs;
+ uint32_t volatile cRefs;
+ /** Set if there is already pending I/O. */
+ bool fIOPending;
+ /** Set if the zero byte read that the poll code using is pending. */
+ bool fZeroByteRead;
/** Indicates that there is a pending cancel request. */
- bool volatile fCancelled;
+ bool volatile fCancelled;
/** The name pipe handle. */
- HANDLE hNmPipe;
+ HANDLE hNmPipe;
/** The handle to the event object we're using for overlapped I/O. */
- HANDLE hEvent;
+ HANDLE hEvent;
/** The overlapped I/O structure. */
- OVERLAPPED OverlappedIO;
+ OVERLAPPED OverlappedIO;
+ /** Bounce buffer for writes. */
+ uint8_t *pbBounceBuf;
+ /** Amount of used buffer space. */
+ size_t cbBounceBufUsed;
+ /** Amount of allocated buffer space. */
+ size_t cbBounceBufAlloc;
+ /** Buffer for the zero byte read.
+ * Used in RTLocalIpcSessionWaitForData(). */
+ uint8_t abBuf[8];
} RTLOCALIPCSESSIONINT;
/** Pointer to a local IPC session instance (Windows). */
typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT;
+typedef BOOL WINAPI FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR(LPCTSTR, DWORD, PSECURITY_DESCRIPTOR, PULONG);
+typedef FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR
+ *PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR; /* No, nobody fell on the keyboard, really! */
+
/*******************************************************************************
* Internal Functions *
@@ -164,52 +193,124 @@ static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE
/**
+ * Builds and allocates the security descriptor required for securing the local pipe.
+ *
+ * @return IPRT status code.
+ * @param ppDesc Where to store the allocated security descriptor on success.
+ * Must be free'd using LocalFree().
+ */
+static int rtLocalIpcServerWinAllocSecurityDescriptior(PSECURITY_DESCRIPTOR *ppDesc, bool fServer)
+{
+ /** @todo Stuff this into RTInitOnce? Later. */
+ PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR
+ pfnConvertStringSecurityDescriptorToSecurityDescriptor = NULL;
+
+ RTLDRMOD hAdvApi32 = NIL_RTLDRMOD;
+ int rc = RTLdrLoadSystem("Advapi32.dll", true /*fNoUnload*/, &hAdvApi32);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbol(hAdvApi32, "ConvertStringSecurityDescriptorToSecurityDescriptorW",
+ (void**)&pfnConvertStringSecurityDescriptorToSecurityDescriptor);
+
+ PSECURITY_DESCRIPTOR pSecDesc = NULL;
+ if (RT_SUCCESS(rc))
+ {
+ AssertPtr(pfnConvertStringSecurityDescriptorToSecurityDescriptor);
+
+ /*
+ * We'll create a security descriptor from a SDDL that denies
+ * access to network clients (this is local IPC after all), it
+ * makes some further restrictions to prevent non-authenticated
+ * users from screwing around.
+ */
+ PRTUTF16 pwszSDDL;
+ rc = RTStrToUtf16(fServer
+ ? RTLOCALIPC_WIN_SDDL_SERVER : RTLOCALIPC_WIN_SDDL_CLIENT, &pwszSDDL);
+ if (RT_SUCCESS(rc))
+ {
+ if (!pfnConvertStringSecurityDescriptorToSecurityDescriptor((LPCTSTR)pwszSDDL,
+ SDDL_REVISION_1,
+ &pSecDesc,
+ NULL))
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ }
+
+ RTUtf16Free(pwszSDDL);
+ }
+ }
+ else
+ {
+ /* Windows OSes < W2K SP2 not supported for now, bail out. */
+ /** @todo Implement me! */
+ rc = VERR_NOT_SUPPORTED;
+ }
+
+ if (hAdvApi32 != NIL_RTLDRMOD)
+ RTLdrClose(hAdvApi32);
+
+ if (RT_SUCCESS(rc))
+ {
+ AssertPtr(pSecDesc);
+ *ppDesc = pSecDesc;
+ }
+
+ return rc;
+}
+
+/**
* Creates a named pipe instance.
*
* This is used by both RTLocalIpcServerCreate and RTLocalIpcServerListen.
*
- * @returns Windows error code, that is NO_ERROR and *phNmPipe on success and some ERROR_* on failure.
- *
+ * @return IPRT status code.
* @param phNmPipe Where to store the named pipe handle on success. This
* will be set to INVALID_HANDLE_VALUE on failure.
* @param pszFullPipeName The full named pipe name.
* @param fFirst Set on the first call (from RTLocalIpcServerCreate), otherwise clear.
* Governs the FILE_FLAG_FIRST_PIPE_INSTANCE flag.
*/
-static DWORD rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst)
+static int rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst)
{
*phNmPipe = INVALID_HANDLE_VALUE;
- /*
- * We'll create a security descriptor from a SDDL that denies
- * access to network clients (this is local IPC after all), it
- * makes some further restrictions to prevent non-authenticated
- * users from screwing around.
- */
- DWORD err;
- PSECURITY_DESCRIPTOR pSecDesc = NULL;
-#if 0 /** @todo dynamically resolve this as it is the only thing that prevents
- * loading IPRT on NT4. */
- if (ConvertStringSecurityDescriptorToSecurityDescriptor(RTLOCALIPC_WIN_SDDL,
- SDDL_REVISION_1,
- &pSecDesc,
- NULL))
-#else
- AssertFatalFailed();
- SetLastError(-1);
- if (0)
-#endif
+ PSECURITY_DESCRIPTOR pSecDesc;
+ int rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc, fFirst /* Server? */);
+ if (RT_SUCCESS(rc))
{
SECURITY_ATTRIBUTES SecAttrs;
- SecAttrs.nLength = sizeof(SecAttrs);
+ SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
SecAttrs.lpSecurityDescriptor = pSecDesc;
SecAttrs.bInheritHandle = FALSE;
DWORD fOpenMode = PIPE_ACCESS_DUPLEX
| PIPE_WAIT
| FILE_FLAG_OVERLAPPED;
- if (fFirst)
- fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; /* Note! Requires W2K SP2+. */
+
+ bool fSupportsFirstInstance = false;
+
+ OSVERSIONINFOEX OSInfoEx;
+ RT_ZERO(OSInfoEx);
+ OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ if ( GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)
+ && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ {
+ if ( /* Vista+. */
+ OSInfoEx.dwMajorVersion >= 6
+ /* Windows XP+. */
+ || ( OSInfoEx.dwMajorVersion == 5
+ && OSInfoEx.dwMinorVersion > 0)
+ /* Windows 2000. */
+ || ( OSInfoEx.dwMajorVersion == 5
+ && OSInfoEx.dwMinorVersion == 0
+ && OSInfoEx.wServicePackMajor >= 2))
+ {
+ /* Requires at least W2K (5.0) SP2+. This is non-fatal. */
+ fSupportsFirstInstance = true;
+ }
+ }
+
+ if (fFirst && fSupportsFirstInstance)
+ fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
HANDLE hNmPipe = CreateNamedPipe(pszFullPipeName, /* lpName */
fOpenMode, /* dwOpenMode */
@@ -219,19 +320,16 @@ static DWORD rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char
PAGE_SIZE, /* nInBufferSize (ditto) */
30*1000, /* nDefaultTimeOut = 30 sec */
&SecAttrs); /* lpSecurityAttributes */
- err = GetLastError();
LocalFree(pSecDesc);
if (hNmPipe != INVALID_HANDLE_VALUE)
{
*phNmPipe = hNmPipe;
- return NO_ERROR;
}
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
}
- else
- err = GetLastError();
- AssertReturn(err != NO_ERROR, ERROR_GEN_FAILURE);
- return err;
+ return rc;
}
@@ -244,8 +342,7 @@ RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszNa
AssertPtrReturn(pszName, VERR_INVALID_POINTER);
AssertReturn(*pszName, VERR_INVALID_PARAMETER);
AssertReturn(!(fFlags & ~(RTLOCALIPC_FLAGS_VALID_MASK)), VERR_INVALID_PARAMETER);
-
- AssertReturn(fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION, VERR_NOT_IMPLEMENTED); /** @todo implement !RTLOCALIPC_FLAGS_MULTI_SESSION */
+ AssertReturn((fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION), VERR_INVALID_PARAMETER); /** @todo Implement !RTLOCALIPC_FLAGS_MULTI_SESSION */
/*
* Allocate and initialize the instance data.
@@ -263,24 +360,30 @@ RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszNa
int rc = RTCritSectInit(&pThis->CritSect);
if (RT_SUCCESS(rc))
{
- DWORD err = NO_ERROR;
- pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL /*lpName*/);
+ pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
+ FALSE /*bInitialState*/, NULL /*lpName*/);
if (pThis->hEvent != NULL)
{
- memset(&pThis->OverlappedIO, 0, sizeof(pThis->OverlappedIO));
+ RT_ZERO(pThis->OverlappedIO);
pThis->OverlappedIO.Internal = STATUS_PENDING;
pThis->OverlappedIO.hEvent = pThis->hEvent;
- err = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe, pThis->szName, true /* fFirst */);
- if (err == NO_ERROR)
+ rc = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe,
+ pThis->szName, true /* fFirst */);
+ if (RT_SUCCESS(rc))
{
*phServer = pThis;
return VINF_SUCCESS;
}
+
+ BOOL fRc = CloseHandle(pThis->hEvent);
+ AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
}
else
- err = GetLastError();
- rc = RTErrConvertFromWin32(err);
+ rc = RTErrConvertFromWin32(GetLastError());
+
+ int rc2 = RTCritSectDelete(&pThis->CritSect);
+ AssertRC(rc2);
}
RTMemFree(pThis);
return rc;
@@ -327,9 +430,10 @@ RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer)
RTCritSectEnter(&pThis->CritSect);
ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC);
ASMAtomicUoWriteBool(&pThis->fCancelled, true);
+ Assert(pThis->cRefs);
pThis->cRefs--;
- if (pThis->cRefs > 0)
+ if (pThis->cRefs)
{
BOOL fRc = SetEvent(pThis->hEvent);
AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
@@ -371,23 +475,23 @@ RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION
/*
* Try connect a client. We need to use overlapped I/O here because
- * of the cancellation a by RTLocalIpcServerCancel and RTLocalIpcServerDestroy.
+ * of the cancellation done by RTLocalIpcServerCancel and RTLocalIpcServerDestroy.
*/
SetLastError(NO_ERROR);
BOOL fRc = ConnectNamedPipe(pThis->hNmPipe, &pThis->OverlappedIO);
- DWORD err = fRc ? NO_ERROR : GetLastError();
+ DWORD dwErr = fRc ? NO_ERROR : GetLastError();
if ( !fRc
- && err == ERROR_IO_PENDING)
+ && dwErr == ERROR_IO_PENDING)
{
WaitForSingleObject(pThis->hEvent, INFINITE);
DWORD dwIgnored;
fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &dwIgnored, FALSE /* bWait*/);
- err = fRc ? NO_ERROR : GetLastError();
+ dwErr = fRc ? NO_ERROR : GetLastError();
}
RTCritSectEnter(&pThis->CritSect);
- if ( !pThis->fCancelled
- && pThis->u32Magic == RTLOCALIPCSERVER_MAGIC)
+ if ( !pThis->fCancelled /* Event signalled but not cancelled? */
+ && pThis->u32Magic == RTLOCALIPCSERVER_MAGIC)
{
/*
* Still alive, some error or an actual client.
@@ -396,12 +500,12 @@ RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION
* replaces the current one for the server. The current pipe instance
* will be assigned to the client session.
*/
- if ( fRc
- || err == ERROR_PIPE_CONNECTED)
+ if ( fRc
+ || dwErr == ERROR_PIPE_CONNECTED)
{
HANDLE hNmPipe;
- DWORD err = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->szName, false /* fFirst */);
- if (err == NO_ERROR)
+ rc = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->szName, false /* fFirst */);
+ if (RT_SUCCESS(rc))
{
HANDLE hNmPipeSession = pThis->hNmPipe; /* consumed */
pThis->hNmPipe = hNmPipe;
@@ -413,13 +517,12 @@ RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION
* We failed to create a new instance for the server, disconnect
* the client and fail. Don't try service the client here.
*/
- rc = RTErrConvertFromWin32(err);
fRc = DisconnectNamedPipe(pThis->hNmPipe);
AssertMsg(fRc, ("%d\n", GetLastError()));
}
}
else
- rc = RTErrConvertFromWin32(err);
+ rc = RTErrConvertFromWin32(dwErr);
}
else
{
@@ -430,9 +533,9 @@ RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION
* in the this thread) or disconnect the client.
*/
if ( fRc
- || err == ERROR_PIPE_CONNECTED)
+ || dwErr == ERROR_PIPE_CONNECTED)
fRc = DisconnectNamedPipe(pThis->hNmPipe);
- else if (err == ERROR_IO_PENDING)
+ else if (dwErr == ERROR_IO_PENDING)
fRc = CancelIo(pThis->hNmPipe);
else
fRc = TRUE;
@@ -464,15 +567,17 @@ RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer)
* Enter the critical section, then set the cancellation flag
* and signal the event (to wake up anyone in/at WaitForSingleObject).
*/
- RTCritSectEnter(&pThis->CritSect);
-
- ASMAtomicUoWriteBool(&pThis->fCancelled, true);
- BOOL fRc = SetEvent(pThis->hEvent);
- AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ ASMAtomicUoWriteBool(&pThis->fCancelled, true);
+ BOOL fRc = SetEvent(pThis->hEvent);
+ AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
- RTCritSectLeave(&pThis->CritSect);
+ rc = RTCritSectLeave(&pThis->CritSect);
+ }
- return VINF_SUCCESS;
+ return rc;
}
@@ -487,6 +592,9 @@ RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer)
*/
static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession)
{
+ AssertPtrReturn(phClientSession, VERR_INVALID_POINTER);
+ AssertReturn(hNmPipeSession != INVALID_HANDLE_VALUE, VERR_INVALID_HANDLE);
+
int rc;
/*
@@ -498,15 +606,18 @@ static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE
pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
pThis->cRefs = 1; /* our ref */
pThis->fCancelled = false;
+ pThis->fIOPending = false;
+ pThis->fZeroByteRead = false;
pThis->hNmPipe = hNmPipeSession;
rc = RTCritSectInit(&pThis->CritSect);
if (RT_SUCCESS(rc))
{
- pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL /*lpName*/);
+ pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
+ FALSE /*bInitialState*/, NULL /*lpName*/);
if (pThis->hEvent != NULL)
{
- memset(&pThis->OverlappedIO, 0, sizeof(pThis->OverlappedIO));
+ RT_ZERO(pThis->OverlappedIO);
pThis->OverlappedIO.Internal = STATUS_PENDING;
pThis->OverlappedIO.hEvent = pThis->hEvent;
@@ -528,10 +639,88 @@ static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE
return rc;
}
-
RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
{
- return VINF_SUCCESS;
+ AssertPtrReturn(phSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertReturn(*pszName, VERR_INVALID_PARAMETER);
+ AssertReturn(!fFlags, VERR_INVALID_PARAMETER); /* Flags currently unused, must be 0. */
+
+ PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAlloc(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
+ pThis->cRefs = 1; /* The one we return. */
+ pThis->fIOPending = false;
+ pThis->fZeroByteRead = false;
+ pThis->fCancelled = false;
+ pThis->pbBounceBuf = NULL;
+ pThis->cbBounceBufAlloc = 0;
+ pThis->cbBounceBufUsed = 0;
+
+ int rc = RTCritSectInit(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
+ FALSE /*bInitialState*/, NULL /*lpName*/);
+ if (pThis->hEvent != NULL)
+ {
+ RT_ZERO(pThis->OverlappedIO);
+ pThis->OverlappedIO.Internal = STATUS_PENDING;
+ pThis->OverlappedIO.hEvent = pThis->hEvent;
+
+ PSECURITY_DESCRIPTOR pSecDesc;
+ rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc, false /* Client */);
+ if (RT_SUCCESS(rc))
+ {
+ char *pszPipe;
+ if (RTStrAPrintf(&pszPipe, "%s%s", RTLOCALIPC_WIN_PREFIX, pszName))
+ {
+ SECURITY_ATTRIBUTES SecAttrs;
+ SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
+ SecAttrs.lpSecurityDescriptor = pSecDesc;
+ SecAttrs.bInheritHandle = FALSE;
+
+ HANDLE hPipe = CreateFile(pszPipe, /* pipe name */
+ GENERIC_READ /* read and write access */
+ | GENERIC_WRITE,
+ 0, /* no sharing */
+ &SecAttrs, /* lpSecurityAttributes */
+ OPEN_EXISTING, /* opens existing pipe */
+ FILE_FLAG_OVERLAPPED, /* default attributes */
+ NULL); /* no template file */
+ RTStrFree(pszPipe);
+
+ if (hPipe != INVALID_HANDLE_VALUE)
+ {
+ LocalFree(pSecDesc);
+
+ pThis->hNmPipe = hPipe;
+ *phSession = pThis;
+ return VINF_SUCCESS;
+ }
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ LocalFree(pSecDesc);
+ }
+
+ BOOL fRc = CloseHandle(pThis->hEvent);
+ AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
+ }
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
+
+ int rc2 = RTCritSectDelete(&pThis->CritSect);
+ AssertRC(rc2);
+ }
+
+ RTMemFree(pThis);
+ return rc;
}
@@ -564,9 +753,9 @@ RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession)
*/
if (hSession == NIL_RTLOCALIPCSESSION)
return VINF_SUCCESS;
- PRTLOCALIPCSESSIONINT pThis = (RTLOCALIPCSESSION)hSession;
+ PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic != RTLOCALIPCSESSION_MAGIC, VERR_INVALID_MAGIC);
+ AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_MAGIC);
/*
* Cancel any thread currently busy using the session,
@@ -593,32 +782,437 @@ RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession)
RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
{
- return VINF_SUCCESS;
+ PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
+ /* pcbRead is optional. */
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ /* No concurrent readers, sorry. */
+ if (pThis->cRefs == 1)
+ {
+ pThis->cRefs++;
+
+ /*
+ * If pcbRead is non-NULL this indicates the maximum number of bytes to read.
+ * If pcbRead is NULL then this is the exact number of bytes to read.
+ */
+ size_t cbToRead = pcbRead ? *pcbRead : cbBuffer;
+ size_t cbTotalRead = 0;
+ while (cbToRead > 0)
+ {
+ /*
+ * Kick of a an overlapped read. It should return immediately if
+ * there is bytes in the buffer. If not, we'll cancel it and see
+ * what we get back.
+ */
+ rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
+ DWORD cbRead = 0;
+ pThis->fIOPending = true;
+ RTCritSectLeave(&pThis->CritSect);
+
+ if (ReadFile(pThis->hNmPipe, pvBuffer,
+ cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
+ &cbRead, &pThis->OverlappedIO))
+ rc = VINF_SUCCESS;
+ else if (GetLastError() == ERROR_IO_PENDING)
+ {
+ WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
+ if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO,
+ &cbRead, TRUE /*fWait*/))
+ rc = VINF_SUCCESS;
+ else
+ {
+ DWORD dwErr = GetLastError();
+ AssertMsgFailed(("err=%ld\n", dwErr));
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+ }
+ else
+ {
+ DWORD dwErr = GetLastError();
+ AssertMsgFailed(("err2=%ld\n", dwErr));
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+
+ RTCritSectEnter(&pThis->CritSect);
+ pThis->fIOPending = false;
+ if (RT_FAILURE(rc))
+ break;
+
+ /* Advance. */
+ cbToRead -= cbRead;
+ cbTotalRead += cbRead;
+ pvBuffer = (uint8_t *)pvBuffer + cbRead;
+ }
+
+ if (pcbRead)
+ {
+ *pcbRead = cbTotalRead;
+ if ( RT_FAILURE(rc)
+ && cbTotalRead
+ && rc != VERR_INVALID_POINTER)
+ rc = VINF_SUCCESS;
+ }
+
+ pThis->cRefs--;
+ }
+ else
+ rc = VERR_WRONG_ORDER;
+ RTCritSectLeave(&pThis->CritSect);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Common worker for handling I/O completion.
+ *
+ * This is used by RTLocalIpcSessionClose and RTLocalIpcSessionWrite.
+ *
+ * @returns IPRT status code.
+ * @param pThis The pipe instance handle.
+ */
+static int rtLocalIpcSessionWriteCheckCompletion(PRTLOCALIPCSESSIONINT pThis)
+{
+ int rc;
+ DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, 0);
+ if (dwRc == WAIT_OBJECT_0)
+ {
+ DWORD cbWritten = 0;
+ if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE))
+ {
+ for (;;)
+ {
+ if (cbWritten >= pThis->cbBounceBufUsed)
+ {
+ pThis->fIOPending = false;
+ rc = VINF_SUCCESS;
+ break;
+ }
+
+ /* resubmit the remainder of the buffer - can this actually happen? */
+ memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten);
+ rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
+ if (!WriteFile(pThis->hNmPipe, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
+ &cbWritten, &pThis->OverlappedIO))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == ERROR_IO_PENDING)
+ rc = VINF_TRY_AGAIN;
+ else
+ {
+ pThis->fIOPending = false;
+ if (dwErr == ERROR_NO_DATA)
+ rc = VERR_BROKEN_PIPE;
+ else
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+ break;
+ }
+ Assert(cbWritten > 0);
+ }
+ }
+ else
+ {
+ pThis->fIOPending = false;
+ rc = RTErrConvertFromWin32(GetLastError());
+ }
+ }
+ else if (dwRc == WAIT_TIMEOUT)
+ rc = VINF_TRY_AGAIN;
+ else
+ {
+ pThis->fIOPending = false;
+ if (dwRc == WAIT_ABANDONED)
+ rc = VERR_INVALID_HANDLE;
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
+ }
+ return rc;
}
RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuffer, size_t cbBuffer)
{
- return VINF_SUCCESS;
+ PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
+ AssertReturn(cbBuffer, VERR_INVALID_PARAMETER);
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ /* No concurrent writers, sorry. */
+ if (pThis->cRefs == 1)
+ {
+ pThis->cRefs++;
+
+ /*
+ * If I/O is pending, wait for it to complete.
+ */
+ if (pThis->fIOPending)
+ {
+ rc = rtLocalIpcSessionWriteCheckCompletion(pThis);
+ while (rc == VINF_TRY_AGAIN)
+ {
+ Assert(pThis->fIOPending);
+ HANDLE hEvent = pThis->OverlappedIO.hEvent;
+ RTCritSectLeave(&pThis->CritSect);
+ WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
+ RTCritSectEnter(&pThis->CritSect);
+ }
+ }
+ if (RT_SUCCESS(rc))
+ {
+ Assert(!pThis->fIOPending);
+
+ /*
+ * Try write everything.
+ * No bounce buffering, cUsers protects us.
+ */
+ size_t cbTotalWritten = 0;
+ while (cbBuffer > 0)
+ {
+ BOOL fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE);
+ pThis->fIOPending = true;
+ RTCritSectLeave(&pThis->CritSect);
+
+ DWORD cbWritten = 0;
+ fRc = WriteFile(pThis->hNmPipe, pvBuffer,
+ cbBuffer <= ~(DWORD)0 ? (DWORD)cbBuffer : ~(DWORD)0,
+ &cbWritten, &pThis->OverlappedIO);
+ if (fRc)
+ {
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == ERROR_IO_PENDING)
+ {
+ DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
+ if (dwRc == WAIT_OBJECT_0)
+ {
+ if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE /*fWait*/))
+ rc = VINF_SUCCESS;
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
+ }
+ else if (dwRc == WAIT_TIMEOUT)
+ rc = VERR_TIMEOUT;
+ else if (dwRc == WAIT_ABANDONED)
+ rc = VERR_INVALID_HANDLE;
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
+ }
+ else if (dwErr == ERROR_NO_DATA)
+ rc = VERR_BROKEN_PIPE;
+ else
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+
+ RTCritSectEnter(&pThis->CritSect);
+ pThis->fIOPending = false;
+ if (RT_FAILURE(rc))
+ break;
+
+ /* Advance. */
+ pvBuffer = (char const *)pvBuffer + cbWritten;
+ cbTotalWritten += cbWritten;
+ cbBuffer -= cbWritten;
+ }
+ }
+
+ pThis->cRefs--;
+ }
+ else
+ rc = VERR_WRONG_ORDER;
+ RTCritSectLeave(&pThis->CritSect);
+ }
+
+ return rc;
}
RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
{
+ /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until
+ * all data was written (or an error occurred). */
+ /** @todo Implement this as soon as we want an explicit asynchronous version of
+ * RTLocalIpcSessionWrite on Windows. */
return VINF_SUCCESS;
}
RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
{
- RTThreadSleep(1000);
- return VINF_SUCCESS;
+ PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
+
+ uint64_t const StartMsTS = RTTimeMilliTS();
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ return rc;
+ for (unsigned iLoop = 0;; iLoop++)
+ {
+ HANDLE hWait = INVALID_HANDLE_VALUE;
+
+ if (pThis->fIOPending)
+ hWait = pThis->OverlappedIO.hEvent;
+ else
+ {
+ /* Peek at the pipe buffer and see how many bytes it contains. */
+ DWORD cbAvailable;
+ BOOL fRc = PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL);
+ if ( fRc
+ && cbAvailable)
+ {
+ rc = VINF_SUCCESS;
+ break;
+ }
+ else if (!fRc)
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ break;
+ }
+
+ /* Start a zero byte read operation that we can wait on. */
+ if (cMillies == 0)
+ {
+ rc = VERR_TIMEOUT;
+ break;
+ }
+ AssertBreakStmt(pThis->cRefs == 1, rc = VERR_WRONG_ORDER);
+ fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE);
+ DWORD cbRead = 0;
+ if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0, &cbRead, &pThis->OverlappedIO))
+ {
+ rc = VINF_SUCCESS;
+ if (iLoop > 10)
+ RTThreadYield();
+ }
+ else if (GetLastError() == ERROR_IO_PENDING)
+ {
+ pThis->cRefs++;
+ pThis->fIOPending = true;
+ pThis->fZeroByteRead = true;
+ hWait = pThis->OverlappedIO.hEvent;
+ }
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
+ }
+
+ if (RT_FAILURE(rc))
+ break;
+
+ /*
+ * Check for timeout.
+ */
+ DWORD cMsMaxWait = INFINITE;
+ if ( cMillies != RT_INDEFINITE_WAIT
+ && ( hWait != INVALID_HANDLE_VALUE
+ || iLoop > 10)
+ )
+ {
+ uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
+ if (cElapsed >= cMillies)
+ {
+ rc = VERR_TIMEOUT;
+ break;
+ }
+ cMsMaxWait = cMillies - (uint32_t)cElapsed;
+ }
+
+ /*
+ * Wait.
+ */
+ if (hWait != INVALID_HANDLE_VALUE)
+ {
+ RTCritSectLeave(&pThis->CritSect);
+
+ DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait);
+ if (dwRc == WAIT_OBJECT_0)
+ rc = VINF_SUCCESS;
+ else if (dwRc == WAIT_TIMEOUT)
+ rc = VERR_TIMEOUT;
+ else if (dwRc == WAIT_ABANDONED)
+ rc = VERR_INVALID_HANDLE;
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
+
+ if ( RT_FAILURE(rc)
+ && pThis->u32Magic != RTLOCALIPCSESSION_MAGIC)
+ return rc;
+
+ int rc2 = RTCritSectEnter(&pThis->CritSect);
+ AssertRC(rc2);
+ if (pThis->fZeroByteRead)
+ {
+ Assert(pThis->cRefs);
+ pThis->cRefs--;
+ pThis->fIOPending = false;
+
+ if (rc != VINF_SUCCESS)
+ {
+ BOOL fRc = CancelIo(pThis->hNmPipe);
+ Assert(fRc == TRUE);
+ }
+
+ DWORD cbRead = 0;
+ BOOL fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbRead, TRUE /*fWait*/);
+ if ( !fRc
+ && RT_SUCCESS(rc))
+ {
+ DWORD dwRc = GetLastError();
+ if (dwRc == ERROR_OPERATION_ABORTED)
+ rc = VERR_CANCELLED;
+ else
+ rc = RTErrConvertFromWin32(dwRc);
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ break;
+ }
+ }
+
+ int rc2 = RTCritSectLeave(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+
+ return rc;
}
RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession)
{
- return VINF_SUCCESS;
+ PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
+
+ /*
+ * Enter the critical section, then set the cancellation flag
+ * and signal the event (to wake up anyone in/at WaitForSingleObject).
+ */
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ ASMAtomicUoWriteBool(&pThis->fCancelled, true);
+ BOOL fRc = SetEvent(pThis->hEvent);
+ AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
+
+ RTCritSectLeave(&pThis->CritSect);
+ }
+
+ return rc;
}
diff --git a/src/VBox/Runtime/r3/win/mp-win.cpp b/src/VBox/Runtime/r3/win/mp-win.cpp
index fed1152b..dce41d19 100644
--- a/src/VBox/Runtime/r3/win/mp-win.cpp
+++ b/src/VBox/Runtime/r3/win/mp-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,9 +30,14 @@
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_SYSTEM
#include <Windows.h>
+
#include <iprt/mp.h>
-#include <iprt/cpuset.h>
+#include "internal/iprt.h"
+
#include <iprt/assert.h>
+#include <iprt/cpuset.h>
+#include <iprt/ldr.h>
+#include <iprt/mem.h>
AssertCompile(MAXIMUM_PROCESSORS <= RTCPUSET_MAX_CPUS);
@@ -91,6 +96,59 @@ RTDECL(RTCPUID) RTMpGetCount(void)
}
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ /*
+ * Resolve the API dynamically (one try) as it requires XP w/ sp3 or later.
+ */
+ typedef BOOL (WINAPI *PFNGETLOGICALPROCINFO)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
+ static PFNGETLOGICALPROCINFO s_pfnGetLogicalProcInfo = (PFNGETLOGICALPROCINFO)~(uintptr_t)0;
+ if (s_pfnGetLogicalProcInfo == (PFNGETLOGICALPROCINFO)~(uintptr_t)0)
+ s_pfnGetLogicalProcInfo = (PFNGETLOGICALPROCINFO)RTLdrGetSystemSymbol("kernel32.dll", "GetLogicalProcessorInformation");
+
+ if (s_pfnGetLogicalProcInfo)
+ {
+ /*
+ * Query the information. This unfortunately requires a buffer, so we
+ * start with a guess and let windows advice us if it's too small.
+ */
+ DWORD cbSysProcInfo = _4K;
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION paSysInfo = NULL;
+ BOOL fRc = FALSE;
+ do
+ {
+ cbSysProcInfo = RT_ALIGN_32(cbSysProcInfo, 256);
+ void *pv = RTMemRealloc(paSysInfo, cbSysProcInfo);
+ if (!pv)
+ break;
+ paSysInfo = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)pv;
+ fRc = s_pfnGetLogicalProcInfo(paSysInfo, &cbSysProcInfo);
+ } while (!fRc && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
+ if (fRc)
+ {
+ /*
+ * Parse the result.
+ */
+ uint32_t cCores = 0;
+ uint32_t i = cbSysProcInfo / sizeof(paSysInfo[0]);
+ while (i-- > 0)
+ if (paSysInfo[i].Relationship == RelationProcessorCore)
+ cCores++;
+
+ RTMemFree(paSysInfo);
+ Assert(cCores > 0);
+ return cCores;
+ }
+
+ RTMemFree(paSysInfo);
+ }
+
+ /* If we don't have the necessary API or if it failed, return the same
+ value as the generic implementation. */
+ return RTMpGetCount();
+}
+
+
RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
{
SYSTEM_INFO SysInfo;
@@ -107,3 +165,10 @@ RTDECL(RTCPUID) RTMpGetOnlineCount(void)
return RTCpuSetCount(&Set);
}
+
+RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void)
+{
+ /** @todo this isn't entirely correct. */
+ return RTMpGetCoreCount();
+}
+
diff --git a/src/VBox/Runtime/r3/win/ntdll-mini-implib.c b/src/VBox/Runtime/r3/win/ntdll-mini-implib.c
index 74094221..a3eeef7b 100644
--- a/src/VBox/Runtime/r3/win/ntdll-mini-implib.c
+++ b/src/VBox/Runtime/r3/win/ntdll-mini-implib.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -34,13 +34,23 @@ typedef LONG NTSTATUS;
typedef PVOID PIO_STATUS_BLOCK;
typedef INT FILE_INFORMATION_CLASS;
typedef INT FS_INFORMATION_CLASS;
+typedef INT MEMORY_INFORMATION_CLASS;
+typedef INT PROCESSINFOCLASS;
+typedef PVOID POBJECT_ATTRIBUTES;
+typedef PVOID PIO_APC_ROUTINE;
+typedef PVOID PUNICODE_STRING;
+/* Error/status conversion: */
+
NTSYSAPI ULONG NTAPI RtlNtStatusToDosError(IN NTSTATUS Status)
{
return 1;
}
+
+/* Queries: */
+
NTSYSAPI LONG NTAPI NtQueryTimerResolution(OUT PULONG MaximumResolution,
OUT PULONG MinimumResolution,
OUT PULONG CurrentResolution)
@@ -48,15 +58,72 @@ NTSYSAPI LONG NTAPI NtQueryTimerResolution(OUT PULONG MaximumResolution,
return -1;
}
-NTSYSAPI NTSTATUS WINAPI NtQueryInformationFile(HANDLE h,
- PIO_STATUS_BLOCK b,
- PVOID c,
- LONG d,
- FILE_INFORMATION_CLASS e)
+NTSYSAPI LONG NTAPI NtQueryDirectoryFile(IN HANDLE FileHandle,
+ IN HANDLE Event OPTIONAL,
+ IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ IN PVOID ApcContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ OUT PVOID FileInformation,
+ IN ULONG Length,
+ IN FILE_INFORMATION_CLASS FileInformationClass,
+ IN BOOLEAN ReturnSingleEntry,
+ IN PUNICODE_STRING FileName OPTIONAL,
+ IN BOOLEAN RestartScan)
+{
+ return -1;
+}
+
+NTSYSAPI LONG NTAPI NtQueryDirectoryObject(IN HANDLE ObjectHandle,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ IN BOOLEAN ReturnSingleEntry,
+ IN BOOLEAN RestartScan,
+ IN OUT PULONG Context,
+ OUT PULONG ReturneLength)
+{
+ return -1;
+}
+
+NTSYSAPI NTSTATUS WINAPI NtQueryInformationFile(IN HANDLE h,
+ OUT PIO_STATUS_BLOCK b,
+ OUT PVOID pvBuf,
+ IN LONG cbBuf,
+ IN FILE_INFORMATION_CLASS e)
+{
+ return -1;
+}
+
+NTSYSAPI NTSTATUS NTAPI NtQueryInformationProcess(IN HANDLE hProcess,
+ IN PROCESSINFOCLASS enmProcInfo,
+ OUT PVOID pvBuf,
+ IN SIZE_T cbBuf,
+ OUT PSIZE_T pcbReturned OPTIONAL)
+{
+ return -1;
+}
+
+NTSYSAPI NTSTATUS NTAPI NtQueryVolumeInformationFile(IN HANDLE hFile,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ OUT PVOID pvBuf,
+ IN ULONG cbBuf,
+ IN FS_INFORMATION_CLASS FsInformationClass)
+{
+ return -1;
+}
+
+NTSYSAPI NTSTATUS NTAPI NtQueryVirtualMemory(IN HANDLE hProcess,
+ IN LPCVOID pvWhere,
+ IN MEMORY_INFORMATION_CLASS MemoryInfo,
+ OUT PVOID pvBuf,
+ IN SIZE_T cbBuf,
+ OUT PSIZE_T pcbReturned OPTIONAL)
{
return -1;
}
+
+/* Setters: */
+
NTSYSAPI NTSTATUS NTAPI NtSetInformationFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FileInformation,
@@ -73,11 +140,33 @@ NTSYSAPI LONG NTAPI NtSetTimerResolution(IN ULONG DesiredResolution,
return -1;
}
-NTSYSAPI NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE h,
- PIO_STATUS_BLOCK IoStatusBlock,
- PVOID pvBuf,
- ULONG cbBuf,
- FS_INFORMATION_CLASS FsInformationClass)
+
+
+/* Handles: */
+
+NTSYSAPI NTSTATUS NTAPI NtCreateFile(OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PLARGE_INTEGER AllocationSize OPTIONAL,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN PVOID EaBuffer,
+ IN ULONG EaLength)
+{
+ return -1;
+}
+
+NTSYSAPI NTSTATUS NTAPI NtOpenDirectoryObject(OUT PHANDLE ObjectHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes)
+{
+ return -1;
+}
+
+NTSYSAPI NTSTATUS NTAPI NtClose(IN HANDLE Handle)
{
return -1;
}
diff --git a/src/VBox/Runtime/r3/win/ntdll-mini-implib.def b/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
index a0d39ee4..64bc9328 100644
--- a/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
+++ b/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2010 Oracle Corporation
+; Copyright (C) 2010-2013 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -28,8 +28,13 @@ LIBRARY ntdll.dll
EXPORTS
RtlNtStatusToDosError
NtQueryTimerResolution
+ NtQueryDirectoryFile
NtQueryInformationFile
+ NtQueryInformationProcess
NtSetInformationFile
NtSetTimerResolution
NtQueryVolumeInformationFile
-
+ NtQueryVirtualMemory
+ NtCreateFile
+ NtClose
+ NtOpenDirectoryObject
diff --git a/src/VBox/Runtime/r3/win/path-win.cpp b/src/VBox/Runtime/r3/win/path-win.cpp
index aacf7d5f..0245b778 100644
--- a/src/VBox/Runtime/r3/win/path-win.cpp
+++ b/src/VBox/Runtime/r3/win/path-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -195,7 +195,7 @@ RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath)
AssertReturn(cchPath, VERR_INVALID_PARAMETER);
RTLDRMOD hShell32;
- int rc = RTLdrLoad("Shell32.dll", &hShell32);
+ int rc = RTLdrLoadSystem("Shell32.dll", true /*fNoUnload*/, &hShell32);
if (RT_SUCCESS(rc))
{
PFNSHGETFOLDERPATHW pfnSHGetFolderPathW;
diff --git a/src/VBox/Runtime/r3/win/pipe-win.cpp b/src/VBox/Runtime/r3/win/pipe-win.cpp
index 5abe809e..11f8b432 100644
--- a/src/VBox/Runtime/r3/win/pipe-win.cpp
+++ b/src/VBox/Runtime/r3/win/pipe-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -724,7 +724,7 @@ RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_
int rc = RTCritSectEnter(&pThis->CritSect);
if (RT_SUCCESS(rc))
{
- /* No concurrent readers, sorry. */
+ /* No concurrent writers, sorry. */
if (pThis->cUsers == 0)
{
pThis->cUsers++;
@@ -839,7 +839,7 @@ RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrit
int rc = RTCritSectEnter(&pThis->CritSect);
if (RT_SUCCESS(rc))
{
- /* No concurrent readers, sorry. */
+ /* No concurrent writers, sorry. */
if (pThis->cUsers == 0)
{
pThis->cUsers++;
@@ -1170,28 +1170,19 @@ RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable)
}
-/**
- * Internal RTPollSetAdd helper that returns the handle that should be added to
- * the pollset.
- *
- * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure.
- * @param hPipe The pipe handle.
- * @param fEvents The events we're polling for.
- * @param ph where to put the primary handle.
- */
-int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PHANDLE ph)
+int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative)
{
RTPIPEINTERNAL *pThis = hPipe;
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER);
AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER);
/* Later: Try register an event handle with the pipe like on OS/2, there is
a file control for doing this obviously intended for the OS/2 subsys.
The question is whether this still exists on Vista and W7. */
- *ph = pThis->Overlapped.hEvent;
+ *phNative = (RTHCINTPTR)pThis->Overlapped.hEvent;
return VINF_SUCCESS;
}
@@ -1397,6 +1388,7 @@ uint32_t rtPipePollDone(RTPIPE hPipe, uint32_t fEvents, bool fFinalEntry, bool f
/* update counters. */
pThis->cUsers--;
+ /** @todo This isn't sane, or is it? See OS/2 impl. */
if (!pThis->cUsers)
pThis->hPollSet = NIL_RTPOLLSET;
diff --git a/src/VBox/Runtime/r3/win/poll-win.cpp b/src/VBox/Runtime/r3/win/poll-win.cpp
deleted file mode 100644
index 0f3b187f..00000000
--- a/src/VBox/Runtime/r3/win/poll-win.cpp
+++ /dev/null
@@ -1,586 +0,0 @@
-/* $Id: poll-win.cpp $ */
-/** @file
- * IPRT - Polling I/O Handles, Windows Implementation.
- *
- * @todo merge poll-win.cpp and poll-posix.cpp, there is lots of common code.
- */
-
-/*
- * Copyright (C) 2010 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-#include <Windows.h>
-
-#include <iprt/poll.h>
-#include "internal/iprt.h"
-
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/err.h>
-#include <iprt/mem.h>
-#include <iprt/pipe.h>
-#include <iprt/string.h>
-#include <iprt/thread.h>
-#include <iprt/time.h>
-
-#include "internal/pipe.h"
-#define IPRT_INTERNAL_SOCKET_POLLING_ONLY
-#include "internal/socket.h"
-#include "internal/magics.h"
-
-
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
-/**
- * Handle entry in a poll set.
- */
-typedef struct RTPOLLSETHNDENT
-{
- /** The handle type. */
- RTHANDLETYPE enmType;
- /** The handle ID. */
- uint32_t id;
- /** The events we're waiting for here. */
- uint32_t fEvents;
- /** Set if this is the final entry for this handle.
- * If the handle is entered more than once, this will be clear for all but
- * the last entry. */
- bool fFinalEntry;
- /** The handle union. */
- RTHANDLEUNION u;
-} RTPOLLSETHNDENT;
-/** Pointer to a handle entry. */
-typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT;
-
-
-/**
- * Poll set data, Windows.
- */
-typedef struct RTPOLLSETINTERNAL
-{
- /** The magic value (RTPOLLSET_MAGIC). */
- uint32_t u32Magic;
- /** Set when someone is polling or making changes. */
- bool volatile fBusy;
-
- /** The number of valid handles in the set. */
- uint32_t cHandles;
- /** The native handles. */
- HANDLE ahNative[MAXIMUM_WAIT_OBJECTS];
- /** Array of handles and IDs. */
- RTPOLLSETHNDENT aHandles[MAXIMUM_WAIT_OBJECTS];
-} RTPOLLSETINTERNAL;
-
-
-/**
- * Common worker for RTPoll and RTPollNoResume
- */
-static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
-{
- int rc;
-
- if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT))
- return VERR_DEADLOCK;
-
- /*
- * Check for special case, RTThreadSleep...
- */
- uint32_t const cHandles = pThis->cHandles;
- if (cHandles == 0)
- {
- rc = RTThreadSleep(cMillies);
- if (RT_SUCCESS(rc))
- rc = VERR_TIMEOUT;
- return rc;
- }
-
- /*
- * Check + prepare the handles before waiting.
- */
- uint32_t fEvents = 0;
- bool const fNoWait = cMillies == 0;
- uint32_t i;
- for (i = 0; i < cHandles; i++)
- {
- switch (pThis->aHandles[i].enmType)
- {
- case RTHANDLETYPE_PIPE:
- fEvents = rtPipePollStart(pThis->aHandles[i].u.hPipe, pThis, pThis->aHandles[i].fEvents,
- pThis->aHandles[i].fFinalEntry, fNoWait);
- break;
-
- case RTHANDLETYPE_SOCKET:
- fEvents = rtSocketPollStart(pThis->aHandles[i].u.hSocket, pThis, pThis->aHandles[i].fEvents,
- pThis->aHandles[i].fFinalEntry, fNoWait);
- break;
-
- default:
- AssertFailed();
- fEvents = UINT32_MAX;
- break;
- }
- if (fEvents)
- break;
- }
- if ( fEvents
- || fNoWait)
- {
-
- if (pid)
- *pid = pThis->aHandles[i].id;
- if (pfEvents)
- *pfEvents = fEvents;
- rc = !fEvents
- ? VERR_TIMEOUT
- : fEvents != UINT32_MAX
- ? VINF_SUCCESS
- : VERR_INTERNAL_ERROR_4;
-
- /* clean up */
- if (!fNoWait)
- while (i-- > 0)
- {
- switch (pThis->aHandles[i].enmType)
- {
- case RTHANDLETYPE_PIPE:
- rtPipePollDone(pThis->aHandles[i].u.hPipe, pThis->aHandles[i].fEvents,
- pThis->aHandles[i].fFinalEntry, false);
- break;
-
- case RTHANDLETYPE_SOCKET:
- rtSocketPollDone(pThis->aHandles[i].u.hSocket, pThis->aHandles[i].fEvents,
- pThis->aHandles[i].fFinalEntry, false);
- break;
-
- default:
- AssertFailed();
- break;
- }
- }
-
- return rc;
- }
-
- /*
- * Wait.
- */
- DWORD dwRc = WaitForMultipleObjectsEx(cHandles, &pThis->ahNative[0],
- FALSE /*fWaitAll */,
- cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies,
- TRUE /*fAlertable*/);
- if ( dwRc >= WAIT_OBJECT_0
- && dwRc < WAIT_OBJECT_0 + cHandles)
- rc = VERR_INTERRUPTED;
- else if (dwRc == WAIT_TIMEOUT)
- rc = VERR_TIMEOUT;
- else if (dwRc == WAIT_IO_COMPLETION)
- rc = VERR_INTERRUPTED;
- else if (dwRc == WAIT_FAILED)
- rc = RTErrConvertFromWin32(GetLastError());
- else
- {
- AssertMsgFailed(("%u (%#x)\n", dwRc, dwRc));
- rc = VERR_INTERNAL_ERROR_5;
- }
-
- /*
- * Get event (if pending) and do wait cleanup.
- */
- bool fHarvestEvents = true;
- for (i = 0; i < cHandles; i++)
- {
- fEvents = 0;
- switch (pThis->aHandles[i].enmType)
- {
- case RTHANDLETYPE_PIPE:
- fEvents = rtPipePollDone(pThis->aHandles[i].u.hPipe, pThis->aHandles[i].fEvents,
- pThis->aHandles[i].fFinalEntry, fHarvestEvents);
- break;
-
- case RTHANDLETYPE_SOCKET:
- fEvents = rtSocketPollDone(pThis->aHandles[i].u.hSocket, pThis->aHandles[i].fEvents,
- pThis->aHandles[i].fFinalEntry, fHarvestEvents);
- break;
-
- default:
- AssertFailed();
- break;
- }
- if ( fEvents
- && fHarvestEvents)
- {
- Assert(fEvents != UINT32_MAX);
- fHarvestEvents = false;
- if (pfEvents)
- *pfEvents = fEvents;
- if (pid)
- *pid = pThis->aHandles[i].id;
- rc = VINF_SUCCESS;
- }
- }
-
- return rc;
-}
-
-
-RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
-{
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertPtrNull(pfEvents);
- AssertPtrNull(pid);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc;
- if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0)
- {
- do rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
- while (rc == VERR_INTERRUPTED);
- }
- else
- {
- uint64_t MsStart = RTTimeMilliTS();
- rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
- while (RT_UNLIKELY(rc == VERR_INTERRUPTED))
- {
- if (RTTimeMilliTS() - MsStart >= cMillies)
- {
- rc = VERR_TIMEOUT;
- break;
- }
- rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
- }
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
-
- return rc;
-}
-
-
-RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
-{
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertPtrNull(pfEvents);
- AssertPtrNull(pid);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
-
- return rc;
-}
-
-
-RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet)
-{
- AssertPtrReturn(phPollSet, VERR_INVALID_POINTER);
- RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAllocZ(sizeof(RTPOLLSETINTERNAL));
- if (!pThis)
- return VERR_NO_MEMORY;
-
- pThis->u32Magic = RTPOLLSET_MAGIC;
- pThis->fBusy = false;
- pThis->cHandles = 0;
- for (size_t i = 0; i < RT_ELEMENTS(pThis->ahNative); i++)
- pThis->ahNative[i] = INVALID_HANDLE_VALUE;
-
- *phPollSet = pThis;
- return VINF_SUCCESS;
-}
-
-
-RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet)
-{
- RTPOLLSETINTERNAL *pThis = hPollSet;
- if (pThis == NIL_RTPOLLSET)
- return VINF_SUCCESS;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC);
- RTMemFree(pThis);
-
- return VINF_SUCCESS;
-}
-
-
-RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id)
-{
- /*
- * Validate the input (tedious).
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
- AssertReturn(fEvents, VERR_INVALID_PARAMETER);
- AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
-
- if (!pHandle)
- return VINF_SUCCESS;
- AssertPtrReturn(pHandle, VERR_INVALID_POINTER);
- AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = VINF_SUCCESS;
- HANDLE hNative = INVALID_HANDLE_VALUE;
- RTHANDLEUNION uh;
- uh.uInt = 0;
- switch (pHandle->enmType)
- {
- case RTHANDLETYPE_PIPE:
- uh.hPipe = pHandle->u.hPipe;
- if (uh.hPipe != NIL_RTPIPE)
- rc = rtPipePollGetHandle(uh.hPipe, fEvents, &hNative);
- break;
-
- case RTHANDLETYPE_SOCKET:
- uh.hSocket = pHandle->u.hSocket;
- if (uh.hSocket != NIL_RTSOCKET)
- rc = rtSocketPollGetHandle(uh.hSocket, fEvents, &hNative);
- break;
-
- case RTHANDLETYPE_FILE:
- AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n"));
- rc = VERR_POLL_HANDLE_NOT_POLLABLE;
- break;
-
- case RTHANDLETYPE_THREAD:
- AssertMsgFailed(("Thread handles are currently not pollable\n"));
- rc = VERR_POLL_HANDLE_NOT_POLLABLE;
- break;
-
- default:
- AssertMsgFailed(("\n"));
- rc = VERR_POLL_HANDLE_NOT_POLLABLE;
- break;
- }
- if ( RT_SUCCESS(rc)
- && hNative != INVALID_HANDLE_VALUE)
- {
- uint32_t const i = pThis->cHandles;
-
- /* Check that the handle ID doesn't exist already. */
- uint32_t iPrev = UINT32_MAX;
- uint32_t j = i;
- while (j-- > 0)
- {
- if (pThis->aHandles[j].id == id)
- {
- rc = VERR_POLL_HANDLE_ID_EXISTS;
- break;
- }
- if ( pThis->aHandles[j].enmType == pHandle->enmType
- && pThis->aHandles[j].u.uInt == uh.uInt)
- iPrev = j;
- }
-
- /* Check that we won't overflow the poll set now. */
- if ( RT_SUCCESS(rc)
- && i + 1 > RT_ELEMENTS(pThis->ahNative))
- rc = VERR_POLL_SET_IS_FULL;
- if (RT_SUCCESS(rc))
- {
- /* Add the handles to the two parallel arrays. */
- pThis->ahNative[i] = hNative;
- pThis->aHandles[i].enmType = pHandle->enmType;
- pThis->aHandles[i].u = uh;
- pThis->aHandles[i].id = id;
- pThis->aHandles[i].fEvents = fEvents;
- pThis->aHandles[i].fFinalEntry = true;
- pThis->cHandles = i + 1;
-
- if (iPrev != UINT32_MAX)
- {
- Assert(pThis->aHandles[i].fFinalEntry);
- pThis->aHandles[i].fFinalEntry = false;
- }
-
- rc = VINF_SUCCESS;
- }
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
- return rc;
-}
-
-
-RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id)
-{
- /*
- * Validate the input.
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
- uint32_t i = pThis->cHandles;
- while (i-- > 0)
- if (pThis->aHandles[i].id == id)
- {
- /* Save some details for the duplicate searching. */
- bool fFinalEntry = pThis->aHandles[i].fFinalEntry;
- RTHANDLETYPE enmType = pThis->aHandles[i].enmType;
- RTHANDLEUNION uh = pThis->aHandles[i].u;
-
- /* Remove the entry. */
- pThis->cHandles--;
- size_t const cToMove = pThis->cHandles - i;
- if (cToMove)
- {
- memmove(&pThis->aHandles[i], &pThis->aHandles[i + 1], cToMove * sizeof(pThis->aHandles[i]));
- memmove(&pThis->ahNative[i], &pThis->ahNative[i + 1], cToMove * sizeof(pThis->ahNative[i]));
- }
-
- /* Check for duplicate and set the fFinalEntry flag. */
- if (fFinalEntry)
- while (i-- > 0)
- if ( pThis->aHandles[i].u.uInt == uh.uInt
- && pThis->aHandles[i].enmType == enmType)
- {
- Assert(!pThis->aHandles[i].fFinalEntry);
- pThis->aHandles[i].fFinalEntry = true;
- break;
- }
-
- rc = VINF_SUCCESS;
- break;
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
- return rc;
-}
-
-
-RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle)
-{
- /*
- * Validate the input.
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
- AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
- uint32_t i = pThis->cHandles;
- while (i-- > 0)
- if (pThis->aHandles[i].id == id)
- {
- if (pHandle)
- {
- pHandle->enmType = pThis->aHandles[i].enmType;
- pHandle->u = pThis->aHandles[i].u;
- }
- rc = VINF_SUCCESS;
- break;
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
- return rc;
-}
-
-
-RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet)
-{
- /*
- * Validate the input.
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, UINT32_MAX);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX);
- uint32_t cHandles = pThis->cHandles;
- ASMAtomicWriteBool(&pThis->fBusy, false);
-
- return cHandles;
-}
-
-RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents)
-{
- /*
- * Validate the input.
- */
- RTPOLLSETINTERNAL *pThis = hPollSet;
- AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
- AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
- AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
- AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
- AssertReturn(fEvents, VERR_INVALID_PARAMETER);
-
- /*
- * Set the busy flag and do the job.
- */
- AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
-
- int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
- uint32_t i = pThis->cHandles;
- while (i-- > 0)
- if (pThis->aHandles[i].id == id)
- {
- pThis->aHandles[i].fEvents = fEvents;
- rc = VINF_SUCCESS;
- break;
- }
-
- ASMAtomicWriteBool(&pThis->fBusy, false);
- return rc;
-}
-
diff --git a/src/VBox/Runtime/r3/win/process-win.cpp b/src/VBox/Runtime/r3/win/process-win.cpp
index 47f6d9eb..41a8cbf8 100644
--- a/src/VBox/Runtime/r3/win/process-win.cpp
+++ b/src/VBox/Runtime/r3/win/process-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -40,7 +40,7 @@
#include <Lmcons.h>
#include <iprt/process.h>
-#include "internal/iprt.h"
+#include "internal-r3-win.h"
#include <iprt/assert.h>
#include <iprt/critsect.h>
@@ -50,6 +50,7 @@
#include <iprt/getopt.h>
#include <iprt/initterm.h>
#include <iprt/ldr.h>
+#include <iprt/log.h>
#include <iprt/mem.h>
#include <iprt/once.h>
#include <iprt/path.h>
@@ -58,6 +59,7 @@
#include <iprt/socket.h>
+
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
@@ -157,12 +159,11 @@ static DECLCALLBACK(void) rtProcWinTerm(RTTERMREASON enmReason, int32_t iStatus,
* Initialize the globals.
*
* @returns IPRT status code.
- * @param pvUser1 Ignored.
- * @param pvUser2 Ignored.
+ * @param pvUser Ignored.
*/
-static DECLCALLBACK(int32_t) rtProcWinInitOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int32_t) rtProcWinInitOnce(void *pvUser)
{
- NOREF(pvUser1); NOREF(pvUser2);
+ NOREF(pvUser);
g_cProcesses = 0;
g_cProcessesAlloc = 0;
@@ -294,7 +295,8 @@ static int rtProcWinMapErrorCodes(DWORD dwError)
case ERROR_PASSWORD_EXPIRED:
case ERROR_ACCOUNT_RESTRICTION: /* See: http://support.microsoft.com/kb/303846/ */
case ERROR_PASSWORD_RESTRICTION:
- rc = VERR_AUTHENTICATION_FAILURE;
+ case ERROR_ACCOUNT_DISABLED: /* See: http://support.microsoft.com/kb/263936 */
+ rc = VERR_ACCOUNT_RESTRICTED;
break;
case ERROR_FILE_CORRUPT:
@@ -420,77 +422,73 @@ static bool rtProcWinFindTokenByProcessAndPsApi(const char * const *papszNames,
/*
* Load PSAPI.DLL and resolve the two symbols we need.
*/
- RTLDRMOD hPsApi;
- int rc = RTLdrLoad("PSAPI.dll", &hPsApi);
- if (RT_FAILURE_NP(rc))
+ PFNGETMODULEBASENAME pfnGetModuleBaseName = (PFNGETMODULEBASENAME)RTLdrGetSystemSymbol("psapi.dll", "GetModuleBaseName");
+ if (!pfnGetModuleBaseName)
return false;
- PFNGETMODULEBASENAME pfnGetModuleBaseName;
- PFNENUMPROCESSES pfnEnumProcesses;
- rc = RTLdrGetSymbol(hPsApi, "EnumProcesses", (void**)&pfnEnumProcesses);
- if (RT_SUCCESS(rc))
- rc = RTLdrGetSymbol(hPsApi, "GetModuleBaseName", (void**)&pfnGetModuleBaseName);
+ PFNENUMPROCESSES pfnEnumProcesses = (PFNENUMPROCESSES)RTLdrGetSystemSymbol("psapi.dll", "EnumProcesses");
+ if (!pfnEnumProcesses)
+ return false;
+
+ /*
+ * Get a list of PID. We retry if it looks like there are more PIDs
+ * to be returned than what we supplied buffer space for.
+ */
+ int rc = VINF_SUCCESS;
+ DWORD cbPidsAllocated = 4096;
+ DWORD cbPidsReturned = 0;
+ DWORD *paPids;
+ for (;;)
+ {
+ paPids = (DWORD *)RTMemTmpAlloc(cbPidsAllocated);
+ AssertBreakStmt(paPids, rc = VERR_NO_TMP_MEMORY);
+ if (!pfnEnumProcesses(paPids, cbPidsAllocated, &cbPidsReturned))
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ AssertMsgFailedBreak(("%Rrc\n", rc));
+ }
+ if ( cbPidsReturned < cbPidsAllocated
+ || cbPidsAllocated >= _512K)
+ break;
+ RTMemTmpFree(paPids);
+ cbPidsAllocated *= 2;
+ }
if (RT_SUCCESS(rc))
{
/*
- * Get a list of PID. We retry if it looks like there are more PIDs
- * to be returned than what we supplied buffer space for.
+ * Search for the process.
+ *
+ * We ASSUME that the caller won't be specifying any names longer
+ * than RTPATH_MAX.
*/
- DWORD cbPidsAllocated = 4096;
- DWORD cbPidsReturned = 0;
- DWORD *paPids;
- for (;;)
- {
- paPids = (DWORD *)RTMemTmpAlloc(cbPidsAllocated);
- AssertBreakStmt(paPids, rc = VERR_NO_TMP_MEMORY);
- if (!pfnEnumProcesses(paPids, cbPidsAllocated, &cbPidsReturned))
- {
- rc = RTErrConvertFromWin32(GetLastError());
- AssertMsgFailedBreak(("%Rrc\n", rc));
- }
- if ( cbPidsReturned < cbPidsAllocated
- || cbPidsAllocated >= _512K)
- break;
- RTMemTmpFree(paPids);
- cbPidsAllocated *= 2;
- }
- if (RT_SUCCESS(rc))
+ DWORD cbProcName = RTPATH_MAX;
+ char *pszProcName = (char *)RTMemTmpAlloc(RTPATH_MAX);
+ if (pszProcName)
{
- /*
- * Search for the process.
- *
- * We ASSUME that the caller won't be specifying any names longer
- * than RTPATH_MAX.
- */
- DWORD cbProcName = RTPATH_MAX;
- char *pszProcName = (char *)RTMemTmpAlloc(RTPATH_MAX);
- if (pszProcName)
+ for (size_t i = 0; papszNames[i] && !fFound; i++)
{
- for (size_t i = 0; papszNames[i] && !fFound; i++)
+ const DWORD cPids = cbPidsReturned / sizeof(DWORD);
+ for (DWORD iPid = 0; iPid < cPids && !fFound; iPid++)
{
- const DWORD cPids = cbPidsReturned / sizeof(DWORD);
- for (DWORD iPid = 0; iPid < cPids && !fFound; iPid++)
+ HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, paPids[iPid]);
+ if (hProc)
{
- HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, paPids[iPid]);
- if (hProc)
- {
- *pszProcName = '\0';
- DWORD cbRet = pfnGetModuleBaseName(hProc, 0 /*hModule = exe */, pszProcName, cbProcName);
- if ( cbRet > 0
- && _stricmp(pszProcName, papszNames[i]) == 0
- && RT_SUCCESS(rtProcWinGetProcessTokenHandle(paPids[iPid], pSid, phToken)))
- fFound = true;
- CloseHandle(hProc);
- }
+ *pszProcName = '\0';
+ DWORD cbRet = pfnGetModuleBaseName(hProc, 0 /*hModule = exe */, pszProcName, cbProcName);
+ if ( cbRet > 0
+ && _stricmp(pszProcName, papszNames[i]) == 0
+ && RT_SUCCESS(rtProcWinGetProcessTokenHandle(paPids[iPid], pSid, phToken)))
+ fFound = true;
+ CloseHandle(hProc);
}
}
- RTMemTmpFree(pszProcName);
}
- else
- rc = VERR_NO_TMP_MEMORY;
+ RTMemTmpFree(pszProcName);
}
- RTMemTmpFree(paPids);
+ else
+ rc = VERR_NO_TMP_MEMORY;
}
- RTLdrClose(hPsApi);
+ RTMemTmpFree(paPids);
+
return fFound;
}
@@ -517,59 +515,48 @@ static bool rtProcWinFindTokenByProcess(const char * const *papszNames, PSID pSi
* On modern systems (W2K+) try the Toolhelp32 API first; this is more stable
* and reliable. Fallback to EnumProcess on NT4.
*/
- RTLDRMOD hKernel32;
- int rc = RTLdrLoad("Kernel32.dll", &hKernel32);
- if (RT_SUCCESS(rc))
+ PFNCREATETOOLHELP32SNAPSHOT pfnCreateToolhelp32Snapshot;
+ pfnCreateToolhelp32Snapshot = (PFNCREATETOOLHELP32SNAPSHOT)GetProcAddress(g_hModKernel32, "CreateToolhelp32Snapshot");
+ PFNPROCESS32FIRST pfnProcess32First = (PFNPROCESS32FIRST)GetProcAddress(g_hModKernel32, "Process32First");
+ PFNPROCESS32NEXT pfnProcess32Next = (PFNPROCESS32NEXT )GetProcAddress(g_hModKernel32, "Process32Next");
+ bool fFallback = true;
+ if (pfnProcess32Next && pfnProcess32First && pfnCreateToolhelp32Snapshot)
{
- PFNCREATETOOLHELP32SNAPSHOT pfnCreateToolhelp32Snapshot;
- PFNPROCESS32FIRST pfnProcess32First;
- PFNPROCESS32NEXT pfnProcess32Next;
- rc = RTLdrGetSymbol(hKernel32, "CreateToolhelp32Snapshot", (void **)&pfnCreateToolhelp32Snapshot);
- if (RT_SUCCESS(rc))
- rc = RTLdrGetSymbol(hKernel32, "Process32First", (void**)&pfnProcess32First);
- if (RT_SUCCESS(rc))
- rc = RTLdrGetSymbol(hKernel32, "Process32Next", (void**)&pfnProcess32Next);
-
- if (RT_SUCCESS(rc))
+ HANDLE hSnap = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hSnap != INVALID_HANDLE_VALUE)
{
- HANDLE hSnap = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if (hSnap != INVALID_HANDLE_VALUE)
+ fFallback = false;
+ for (size_t i = 0; papszNames[i] && !fFound; i++)
{
- for (size_t i = 0; papszNames[i] && !fFound; i++)
+ PROCESSENTRY32 procEntry;
+ procEntry.dwSize = sizeof(PROCESSENTRY32);
+ if (pfnProcess32First(hSnap, &procEntry))
{
- PROCESSENTRY32 procEntry;
- procEntry.dwSize = sizeof(PROCESSENTRY32);
- if (pfnProcess32First(hSnap, &procEntry))
+ do
{
- do
+ if ( _stricmp(procEntry.szExeFile, papszNames[i]) == 0
+ && RT_SUCCESS(rtProcWinGetProcessTokenHandle(procEntry.th32ProcessID, pSid, phToken)))
{
- if ( _stricmp(procEntry.szExeFile, papszNames[i]) == 0
- && RT_SUCCESS(rtProcWinGetProcessTokenHandle(procEntry.th32ProcessID, pSid, phToken)))
- {
- fFound = true;
- break;
- }
- } while (pfnProcess32Next(hSnap, &procEntry));
- }
+ fFound = true;
+ break;
+ }
+ } while (pfnProcess32Next(hSnap, &procEntry));
+ }
#ifdef RT_STRICT
- else
- {
- DWORD dwErr = GetLastError();
- AssertMsgFailed(("dwErr=%u (%x)\n", dwErr, dwErr));
- }
-#endif
+ else
+ {
+ DWORD dwErr = GetLastError();
+ AssertMsgFailed(("dwErr=%u (%x)\n", dwErr, dwErr));
}
- CloseHandle(hSnap);
+#endif
}
- else /* hSnap == INVALID_HANDLE_VALUE */
- rc = RTErrConvertFromWin32(GetLastError());
+ CloseHandle(hSnap);
}
- RTLdrClose(hKernel32);
}
/* If we couldn't take a process snapshot for some reason or another, fall
back on the NT4 compatible API. */
- if (RT_FAILURE(rc))
+ if (fFallback)
return rtProcWinFindTokenByProcessAndPsApi(papszNames, pSid, phToken);
return fFound;
}
@@ -602,7 +589,13 @@ static int rtProcWinUserLogon(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16
LOGON32_PROVIDER_DEFAULT,
phToken);
if (!fRc)
- return rtProcWinMapErrorCodes(GetLastError());
+ {
+ DWORD dwErr = GetLastError();
+ int rc = rtProcWinMapErrorCodes(dwErr);
+ if (rc == VERR_UNRESOLVED_ERROR)
+ LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc));
+ return rc;
+ }
return VINF_SUCCESS;
}
@@ -651,8 +644,10 @@ static int rtProcWinEnvironmentCreateInternal(VOID *pvBlock, RTENV hEnv, PRTUTF1
RTStrFree(pszEntry);
}
}
+ else
+ break;
pwch += RTUtf16Len(pwch) + 1;
- if (*pwch)
+ if (!*pwch)
break;
}
@@ -680,8 +675,11 @@ static int rtProcWinEnvironmentCreateInternal(VOID *pvBlock, RTENV hEnv, PRTUTF1
*/
static int rtProcWinCreateEnvFromToken(HANDLE hToken, RTENV hEnv, PRTUTF16 *ppwszBlock)
{
+ Assert(hToken);
+ Assert(hEnv != NIL_RTENV);
+
RTLDRMOD hUserenv;
- int rc = RTLdrLoad("Userenv.dll", &hUserenv);
+ int rc = RTLdrLoadSystem("Userenv.dll", true /*fNoUnload*/, &hUserenv);
if (RT_SUCCESS(rc))
{
PFNCREATEENVIRONMENTBLOCK pfnCreateEnvironmentBlock;
@@ -729,7 +727,7 @@ static int rtProcWinCreateEnvFromToken(HANDLE hToken, RTENV hEnv, PRTUTF16 *ppws
* @param ppwszBlock Pointer to a pointer of the final UTF16 environment block.
*/
static int rtProcWinCreateEnvFromAccount(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszDomain,
- RTENV hEnv, PRTUTF16 *ppwszBlock)
+ RTENV hEnv, PRTUTF16 *ppwszBlock)
{
HANDLE hToken;
int rc = rtProcWinUserLogon(pwszUser, pwszPassword, pwszDomain, &hToken);
@@ -873,7 +871,7 @@ static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTU
*/
phToken = fFound ? &hTokenUserDesktop : &hTokenLogon;
RTLDRMOD hUserenv;
- int rc = RTLdrLoad("Userenv.dll", &hUserenv);
+ rc = RTLdrLoadSystem("Userenv.dll", true /*fNoUnload*/, &hUserenv);
if (RT_SUCCESS(rc))
{
PFNLOADUSERPROFILEW pfnLoadUserProfileW;
@@ -915,7 +913,9 @@ static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTU
NULL, /* pThreadAttributes */
TRUE, /* fInheritHandles */
dwCreationFlags,
- pwszzBlock,
+ /** @todo Warn about exceeding 8192 bytes
+ * on XP and up. */
+ pwszzBlock, /* lpEnvironment */
NULL, /* pCurrentDirectory */
pStartupInfo,
pProcInfo);
@@ -951,7 +951,11 @@ static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTU
if ( RT_SUCCESS(rc)
&& dwErr != NO_ERROR)
+ {
rc = rtProcWinMapErrorCodes(dwErr);
+ if (rc == VERR_UNRESOLVED_ERROR)
+ LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc));
+ }
return rc;
}
@@ -967,36 +971,36 @@ static int rtProcWinCreateAsUser1(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTU
RTENV hEnv, DWORD dwCreationFlags,
STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo, uint32_t fFlags)
{
- RTLDRMOD hAdvAPI32;
- int rc = RTLdrLoad("Advapi32.dll", &hAdvAPI32);
+ PFNCREATEPROCESSWITHLOGON pfnCreateProcessWithLogonW;
+ pfnCreateProcessWithLogonW = (PFNCREATEPROCESSWITHLOGON)RTLdrGetSystemSymbol("Advapi32.dll", "CreateProcessWithLogonW");
+ if (!pfnCreateProcessWithLogonW)
+ return VERR_SYMBOL_NOT_FOUND;
+
+ PRTUTF16 pwszzBlock;
+ int rc = rtProcWinCreateEnvFromAccount(pwszUser, pwszPassword, NULL /* Domain */,
+ hEnv, &pwszzBlock);
if (RT_SUCCESS(rc))
{
- PFNCREATEPROCESSWITHLOGON pfnCreateProcessWithLogonW;
- rc = RTLdrGetSymbol(hAdvAPI32, "CreateProcessWithLogonW", (void **)&pfnCreateProcessWithLogonW);
- if (RT_SUCCESS(rc))
+ BOOL fRc = pfnCreateProcessWithLogonW(pwszUser,
+ NULL, /* lpDomain*/
+ pwszPassword,
+ 1 /*LOGON_WITH_PROFILE*/, /* dwLogonFlags */
+ pwszExec,
+ pwszCmdLine,
+ dwCreationFlags,
+ pwszzBlock,
+ NULL, /* pCurrentDirectory */
+ pStartupInfo,
+ pProcInfo);
+ if (!fRc)
{
- PRTUTF16 pwszzBlock;
- rc = rtProcWinCreateEnvFromAccount(pwszUser, pwszPassword, NULL /* Domain */,
- hEnv, &pwszzBlock);
- if (RT_SUCCESS(rc))
- {
- BOOL fRc = pfnCreateProcessWithLogonW(pwszUser,
- NULL, /* lpDomain*/
- pwszPassword,
- 1 /*LOGON_WITH_PROFILE*/, /* dwLogonFlags */
- pwszExec,
- pwszCmdLine,
- dwCreationFlags,
- pwszzBlock,
- NULL, /* pCurrentDirectory */
- pStartupInfo,
- pProcInfo);
- if (!fRc)
- rc = rtProcWinMapErrorCodes(GetLastError());
- rtProcWinDestroyEnv(pwszzBlock);
- }
+ DWORD dwErr = GetLastError();
+ rc = rtProcWinMapErrorCodes(dwErr);
+ if (rc == VERR_UNRESOLVED_ERROR)
+ LogRelFunc(("pfnCreateProcessWithLogonW (%p) failed: dwErr=%u (%#x), rc=%Rrc\n",
+ pfnCreateProcessWithLogonW, dwErr, dwErr, rc));
}
- RTLdrClose(hAdvAPI32);
+ rtProcWinDestroyEnv(pwszzBlock);
}
return rc;
}
@@ -1060,12 +1064,11 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER);
AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER);
AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER);
- /** @todo search the PATH (add flag for this). */
/*
* Initialize the globals.
*/
- int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL);
+ int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL);
AssertRCReturn(rc, rc);
/*
@@ -1197,7 +1200,7 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
*/
PROCESS_INFORMATION ProcInfo;
RT_ZERO(ProcInfo);
- DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
+ DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
if (fFlags & RTPROC_FLAGS_DETACHED)
dwCreationFlags |= DETACHED_PROCESS;
if (fFlags & RTPROC_FLAGS_NO_WINDOW)
@@ -1288,7 +1291,7 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg
RTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
{
AssertReturn(!(fFlags & ~(RTPROCWAIT_FLAGS_BLOCK | RTPROCWAIT_FLAGS_NOBLOCK)), VERR_INVALID_PARAMETER);
- int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL);
+ int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL);
AssertRCReturn(rc, rc);
/*
@@ -1384,7 +1387,7 @@ RTR3DECL(int) RTProcTerminate(RTPROCESS Process)
if (Process == NIL_RTPROCESS)
return VINF_SUCCESS;
- int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL);
+ int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL);
AssertRCReturn(rc, rc);
/*
diff --git a/src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp b/src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp
index 3b056cde..ab7ff7fc 100644
--- a/src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp
+++ b/src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/sched-win.cpp b/src/VBox/Runtime/r3/win/sched-win.cpp
index 935bd651..54b8154b 100644
--- a/src/VBox/Runtime/r3/win/sched-win.cpp
+++ b/src/VBox/Runtime/r3/win/sched-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/semmutex-win.cpp b/src/VBox/Runtime/r3/win/semmutex-win.cpp
index 7cdab20b..e3ec555e 100644
--- a/src/VBox/Runtime/r3/win/semmutex-win.cpp
+++ b/src/VBox/Runtime/r3/win/semmutex-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/symlink-win.cpp b/src/VBox/Runtime/r3/win/symlink-win.cpp
index 30332539..52f5c410 100644
--- a/src/VBox/Runtime/r3/win/symlink-win.cpp
+++ b/src/VBox/Runtime/r3/win/symlink-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -29,8 +29,10 @@
* Header Files *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_SYMLINK
+#include <Windows.h>
#include <iprt/symlink.h>
+#include "internal-r3-win.h"
#include <iprt/assert.h>
#include <iprt/err.h>
@@ -40,7 +42,6 @@
#include <iprt/string.h>
#include "internal/path.h"
-#include <Windows.h>
/*******************************************************************************
@@ -133,13 +134,9 @@ RTDECL(int) RTSymlinkCreate(const char *pszSymlink, const char *pszTarget, RTSYM
static bool s_fTried = FALSE;
if (!s_fTried)
{
- HMODULE hmod = LoadLibrary("KERNEL32.DLL");
- if (hmod)
- {
- PFNCREATESYMBOLICLINKW pfn = (PFNCREATESYMBOLICLINKW)GetProcAddress(hmod, "CreateSymbolicLinkW");
- if (pfn)
- s_pfnCreateSymbolicLinkW = pfn;
- }
+ PFNCREATESYMBOLICLINKW pfn = (PFNCREATESYMBOLICLINKW)GetProcAddress(g_hModKernel32, "CreateSymbolicLinkW");
+ if (pfn)
+ s_pfnCreateSymbolicLinkW = pfn;
s_fTried = true;
}
if (!s_pfnCreateSymbolicLinkW)
diff --git a/src/VBox/Runtime/r3/win/thread-win.cpp b/src/VBox/Runtime/r3/win/thread-win.cpp
index 788a616a..dab8cb70 100644
--- a/src/VBox/Runtime/r3/win/thread-win.cpp
+++ b/src/VBox/Runtime/r3/win/thread-win.cpp
@@ -68,6 +68,12 @@ DECLHIDDEN(int) rtThreadNativeInit(void)
}
+DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void)
+{
+ /* nothing to do here. */
+}
+
+
DECLHIDDEN(void) rtThreadNativeDetach(void)
{
/*
@@ -167,7 +173,7 @@ static void rtThreadNativeUninitComAndOle(void)
AssertMsgFailed(("cComInits=%u (%#x) cOleInits=%u (%#x) - dangling COM/OLE inits!\n",
cComInits, cComInits, cOleInits, cOleInits));
- HMODULE hOle32 = GetModuleHandle("OLE32");
+ HMODULE hOle32 = GetModuleHandle("ole32.dll");
AssertReturnVoid(hOle32 != NULL);
typedef void (WINAPI *PFNOLEUNINITIALIZE)(void);
@@ -251,7 +257,7 @@ static int rtThreadGetCurrentProcessorNumber(void)
static DWORD (WINAPI *pfnGetCurrentProcessorNumber)(void) = NULL;
if (!fInitialized)
{
- HMODULE hmodKernel32 = GetModuleHandle("KERNEL32.DLL");
+ HMODULE hmodKernel32 = GetModuleHandle("kernel32.dll");
if (hmodKernel32)
pfnGetCurrentProcessorNumber = (DWORD (WINAPI*)(void))GetProcAddress(hmodKernel32, "GetCurrentProcessorNumber");
fInitialized = true;
diff --git a/src/VBox/Runtime/r3/win/time-win.cpp b/src/VBox/Runtime/r3/win/time-win.cpp
index bd4e768a..44dea140 100644
--- a/src/VBox/Runtime/r3/win/time-win.cpp
+++ b/src/VBox/Runtime/r3/win/time-win.cpp
@@ -39,13 +39,17 @@
#include <iprt/err.h>
#include "internal/time.h"
-#define USE_TICK_COUNT
+/*
+ * Note! The selected time source be the exact same one as we use in kernel land!
+ */
+//#define USE_TICK_COUNT
//#define USE_PERFORMANCE_COUNTER
-#if 0//defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
-# define USE_INTERRUPT_TIME
-#else
//# define USE_FILE_TIME
-#endif
+//#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
+# define USE_INTERRUPT_TIME
+//#else
+//# define USE_TICK_COUNT
+//#endif
#ifdef USE_INTERRUPT_TIME
@@ -104,6 +108,7 @@ DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void)
return u64 * 100;
#elif defined USE_INTERRUPT_TIME
+# if 0 /* ASSUME 0x7ffe0000 is set in stone */
/*
* This is exactly what we want, but we have to obtain it by non-official
* means.
@@ -114,16 +119,18 @@ DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void)
/** @todo find official way of getting this or some more clever
* detection algorithm if necessary. The com debugger class
* exports this too, windbg knows it too... */
- s_pUserSharedData = (MY_ KUSER_SHARED_DATA *)(uintptr_t)0x7ffe0000;
+ s_pUserSharedData = (PMY_KUSER_SHARED_DATA)(uintptr_t)0x7ffe0000;
}
+# endif
+ PMY_KUSER_SHARED_DATA pUserSharedData = (PMY_KUSER_SHARED_DATA)(uintptr_t)0x7ffe0000;
/* use interrupt time */
LARGE_INTEGER Time;
do
{
- Time.HighPart = s_pUserSharedData->InterruptTime.High1Time;
- Time.LowPart = s_pUserSharedData->InterruptTime.LowPart;
- } while (s_pUserSharedData->InterruptTime.High2Time != Time.HighPart);
+ Time.HighPart = pUserSharedData->InterruptTime.High1Time;
+ Time.LowPart = pUserSharedData->InterruptTime.LowPart;
+ } while (pUserSharedData->InterruptTime.High2Time != Time.HighPart);
return (uint64_t)Time.QuadPart * 100;
diff --git a/src/VBox/Runtime/r3/win/timer-win.cpp b/src/VBox/Runtime/r3/win/timer-win.cpp
index 08ed4ec1..a23aa17a 100644
--- a/src/VBox/Runtime/r3/win/timer-win.cpp
+++ b/src/VBox/Runtime/r3/win/timer-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/tls-win.cpp b/src/VBox/Runtime/r3/win/tls-win.cpp
index 2bc332b7..51e0b23b 100644
--- a/src/VBox/Runtime/r3/win/tls-win.cpp
+++ b/src/VBox/Runtime/r3/win/tls-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/utf16locale-win.cpp b/src/VBox/Runtime/r3/win/utf16locale-win.cpp
index 40d99bb2..ccb51ade 100644
--- a/src/VBox/Runtime/r3/win/utf16locale-win.cpp
+++ b/src/VBox/Runtime/r3/win/utf16locale-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/win/uuid-win.cpp b/src/VBox/Runtime/r3/win/uuid-win.cpp
index 0d91df79..ef1a42bc 100644
--- a/src/VBox/Runtime/r3/win/uuid-win.cpp
+++ b/src/VBox/Runtime/r3/win/uuid-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/r3/xml.cpp b/src/VBox/Runtime/r3/xml.cpp
index a753f34c..708e41fb 100644
--- a/src/VBox/Runtime/r3/xml.cpp
+++ b/src/VBox/Runtime/r3/xml.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2011 Oracle Corporation
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -24,6 +24,10 @@
* terms and conditions of either the GPL or the CDDL or both.
*/
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
#include <iprt/dir.h>
#include <iprt/file.h>
#include <iprt/err.h>
@@ -42,14 +46,11 @@
#include <libxml/xmlschemas.h>
#include <map>
-#include <boost/shared_ptr.hpp>
-////////////////////////////////////////////////////////////////////////////////
-//
-// globals
-//
-////////////////////////////////////////////////////////////////////////////////
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
/**
* Global module initialization structure. This is to wrap non-reentrant bits
* of libxml, among other things.
@@ -58,8 +59,7 @@
* module initialization and cleanup. There must be only one global variable of
* this structure.
*/
-static
-class Global
+static class Global
{
public:
@@ -93,8 +93,7 @@ public:
RTCLockMtx lock;
}
sxml; /* XXX naming this xml will break with gcc-3.3 */
-}
-gGlobal;
+} gGlobal;
@@ -131,8 +130,7 @@ XmlError::XmlError(xmlErrorPtr aErr)
* Composes a single message for the given error. The caller must free the
* returned string using RTStrFree() when no more necessary.
*/
-// static
-char *XmlError::Format(xmlErrorPtr aErr)
+/* static */ char *XmlError::Format(xmlErrorPtr aErr)
{
const char *msg = aErr->message ? aErr->message : "<none>";
size_t msgLen = strlen(msg);
@@ -156,7 +154,7 @@ EIPRTFailure::EIPRTFailure(int aRC, const char *pcszContext, ...)
va_start(args, pcszContext);
RTStrAPrintfV(&pszContext2, pcszContext, args);
char *newMsg;
- RTStrAPrintf(&newMsg, "%s: %d (%s)", pszContext2, aRC, RTErrGetShort(aRC));
+ RTStrAPrintf(&newMsg, "%s: %d(%s)", pszContext2, aRC, RTErrGetShort(aRC));
setWhat(newMsg);
RTStrFree(newMsg);
RTStrFree(pszContext2);
@@ -241,7 +239,7 @@ File::~File()
delete m;
}
-const char* File::uri() const
+const char *File::uri() const
{
return m->strFileName.c_str();
}
@@ -291,19 +289,17 @@ int File::read(char *aBuf, int aLen)
int File::write(const char *aBuf, int aLen)
{
size_t len = aLen;
- int vrc = RTFileWrite (m->handle, aBuf, len, &len);
- if (RT_SUCCESS (vrc))
+ int vrc = RTFileWrite(m->handle, aBuf, len, &len);
+ if (RT_SUCCESS(vrc))
return (int)len;
throw EIPRTFailure(vrc, "Runtime error writing to file '%s'", m->strFileName.c_str());
-
- return -1 /* failure */;
}
void File::truncate()
{
- int vrc = RTFileSetSize (m->handle, pos());
- if (RT_SUCCESS (vrc))
+ int vrc = RTFileSetSize(m->handle, pos());
+ if (RT_SUCCESS(vrc))
return;
throw EIPRTFailure(vrc, "Runtime error truncating file '%s'", m->strFileName.c_str());
@@ -318,7 +314,7 @@ void File::truncate()
struct MemoryBuf::Data
{
Data()
- : buf (NULL), len (0), uri (NULL), pos (0) {}
+ : buf(NULL), len(0), uri(NULL), pos(0) {}
const char *buf;
size_t len;
@@ -327,20 +323,20 @@ struct MemoryBuf::Data
size_t pos;
};
-MemoryBuf::MemoryBuf (const char *aBuf, size_t aLen, const char *aURI /* = NULL */)
- : m (new Data())
+MemoryBuf::MemoryBuf(const char *aBuf, size_t aLen, const char *aURI /* = NULL */)
+ : m(new Data())
{
if (aBuf == NULL)
- throw EInvalidArg (RT_SRC_POS);
+ throw EInvalidArg(RT_SRC_POS);
m->buf = aBuf;
m->len = aLen;
- m->uri = RTStrDup (aURI);
+ m->uri = RTStrDup(aURI);
}
MemoryBuf::~MemoryBuf()
{
- RTStrFree (m->uri);
+ RTStrFree(m->uri);
}
const char *MemoryBuf::uri() const
@@ -353,9 +349,9 @@ uint64_t MemoryBuf::pos() const
return m->pos;
}
-void MemoryBuf::setPos (uint64_t aPos)
+void MemoryBuf::setPos(uint64_t aPos)
{
- size_t off = (size_t) aPos;
+ size_t off = (size_t)aPos;
if ((uint64_t) off != aPos)
throw EInvalidArg();
@@ -365,13 +361,13 @@ void MemoryBuf::setPos (uint64_t aPos)
m->pos = off;
}
-int MemoryBuf::read (char *aBuf, int aLen)
+int MemoryBuf::read(char *aBuf, int aLen)
{
if (m->pos >= m->len)
return 0 /* nothing to read */;
size_t len = m->pos + aLen < m->len ? aLen : m->len - m->pos;
- memcpy (aBuf, m->buf + m->pos, len);
+ memcpy(aBuf, m->buf + m->pos, len);
m->pos += len;
return (int)len;
@@ -422,90 +418,43 @@ xmlParserInput* GlobalLock::callDefaultLoader(const char *aURI,
return gGlobal.sxml.defaultEntityLoader(aURI, aID, aCtxt);
}
+
+
////////////////////////////////////////////////////////////////////////////////
//
// Node class
//
////////////////////////////////////////////////////////////////////////////////
-struct Node::Data
-{
- struct compare_const_char
- {
- bool operator()(const char* s1, const char* s2) const
- {
- return strcmp(s1, s2) < 0;
- }
- };
-
- // attributes, if this is an element; can be empty
- typedef std::map<const char*, boost::shared_ptr<AttributeNode>, compare_const_char > AttributesMap;
- AttributesMap attribs;
-
- // child elements, if this is an element; can be empty
- typedef std::list< boost::shared_ptr<Node> > InternalNodesList;
- InternalNodesList children;
-};
-
Node::Node(EnumType type,
Node *pParent,
- xmlNode *plibNode,
- xmlAttr *plibAttr)
- : m_Type(type),
- m_pParent(pParent),
- m_plibNode(plibNode),
- m_plibAttr(plibAttr),
- m_pcszNamespacePrefix(NULL),
- m_pcszNamespaceHref(NULL),
- m_pcszName(NULL),
- m(new Data)
+ PRTLISTANCHOR pListAnchor,
+ xmlNode *pLibNode,
+ xmlAttr *pLibAttr)
+ : m_Type(type)
+ , m_pParent(pParent)
+ , m_pLibNode(pLibNode)
+ , m_pLibAttr(pLibAttr)
+ , m_pcszNamespacePrefix(NULL)
+ , m_pcszNamespaceHref(NULL)
+ , m_pcszName(NULL)
+ , m_pParentListAnchor(pListAnchor)
{
+ RTListInit(&m_listEntry);
}
Node::~Node()
{
- delete m;
}
/**
- * Private implementation.
- * @param elmRoot
+ * Returns the name of the node, which is either the element name or
+ * the attribute name. For other node types it probably returns NULL.
+ * @return
*/
-void Node::buildChildren(const ElementNode &elmRoot) // private
+const char *Node::getName() const
{
- // go thru this element's attributes
- xmlAttr *plibAttr = m_plibNode->properties;
- while (plibAttr)
- {
- const char *pcszKey;
- boost::shared_ptr<AttributeNode> pNew(new AttributeNode(elmRoot, this, plibAttr, &pcszKey));
- // store
- m->attribs[pcszKey] = pNew;
-
- plibAttr = plibAttr->next;
- }
-
- // go thru this element's child elements
- xmlNodePtr plibNode = m_plibNode->children;
- while (plibNode)
- {
- boost::shared_ptr<Node> pNew;
-
- if (plibNode->type == XML_ELEMENT_NODE)
- pNew = boost::shared_ptr<Node>(new ElementNode(&elmRoot, this, plibNode));
- else if (plibNode->type == XML_TEXT_NODE)
- pNew = boost::shared_ptr<Node>(new ContentNode(this, plibNode));
- if (pNew)
- {
- // store
- m->children.push_back(pNew);
-
- // recurse for this child element to get its own children
- pNew->buildChildren(elmRoot);
- }
-
- plibNode = plibNode->next;
- }
+ return m_pcszName;
}
/**
@@ -513,9 +462,19 @@ void Node::buildChildren(const ElementNode &elmRoot) // private
* the attribute name. For other node types it probably returns NULL.
* @return
*/
-const char* Node::getName() const
+const char *Node::getPrefix() const
{
- return m_pcszName;
+ return m_pcszNamespacePrefix;
+}
+
+/**
+ * Returns the XML namespace URI, which is the attribute name. For other node types it probably
+ * returns NULL.
+ * @return
+ */
+const char *Node::getNamespaceURI() const
+{
+ return m_pcszNamespaceHref;
}
/**
@@ -524,7 +483,7 @@ const char* Node::getName() const
* @param pcsz
* @return
*/
-bool Node::nameEquals(const char *pcszNamespace, const char *pcsz) const
+bool Node::nameEqualsNS(const char *pcszNamespace, const char *pcsz) const
{
if (m_pcszName == pcsz)
return true;
@@ -546,24 +505,52 @@ bool Node::nameEquals(const char *pcszNamespace, const char *pcsz) const
}
/**
+ * Variant of nameEquals that checks the namespace as well.
+ *
+ * @returns true if equal, false if not.
+ * @param pcsz The element name.
+ * @param cchMax The maximum number of character from @a pcsz to
+ * match.
+ * @param pcszNamespace The name space prefix or NULL (default).
+ */
+bool Node::nameEqualsN(const char *pcsz, size_t cchMax, const char *pcszNamespace /* = NULL*/) const
+{
+ /* Match the name. */
+ if (!m_pcszName)
+ return false;
+ if (!pcsz || cchMax == 0)
+ return false;
+ if (strncmp(m_pcszName, pcsz, cchMax))
+ return false;
+ if (strlen(m_pcszName) > cchMax)
+ return false;
+
+ /* Match name space. */
+ if (!pcszNamespace)
+ return true; /* NULL, anything goes. */
+ if (!m_pcszNamespacePrefix)
+ return false; /* Element has no namespace. */
+ return !strcmp(m_pcszNamespacePrefix, pcszNamespace);
+}
+
+/**
* Returns the value of a node. If this node is an attribute, returns
* the attribute value; if this node is an element, then this returns
* the element text content.
* @return
*/
-const char* Node::getValue() const
+const char *Node::getValue() const
{
- if ( (m_plibAttr)
- && (m_plibAttr->children)
- )
+ if ( m_pLibAttr
+ && m_pLibAttr->children
+ )
// libxml hides attribute values in another node created as a
// single child of the attribute node, and it's in the content field
- return (const char*)m_plibAttr->children->content;
+ return (const char *)m_pLibAttr->children->content;
- if ( (m_plibNode)
- && (m_plibNode->children)
- )
- return (const char*)m_plibNode->children->content;
+ if ( m_pLibNode
+ && m_pLibNode->children)
+ return (const char *)m_pLibNode->children->content;
return NULL;
}
@@ -643,39 +630,132 @@ bool Node::copyValue(uint64_t &i) const
*/
int Node::getLineNumber() const
{
- if (m_plibAttr)
- return m_pParent->m_plibNode->line;
+ if (m_pLibAttr)
+ return m_pParent->m_pLibNode->line;
- return m_plibNode->line;
+ return m_pLibNode->line;
}
/**
* Private element constructor.
- * @param pelmRoot
- * @param pParent
- * @param plibNode
+ *
+ * @param pElmRoot Pointer to the root element.
+ * @param pParent Pointer to the parent element (always an ElementNode,
+ * despite the type). NULL for the root node.
+ * @param pListAnchor Pointer to the m_children member of the parent. NULL
+ * for the root node.
+ * @param pLibNode Pointer to the libxml2 node structure.
*/
-ElementNode::ElementNode(const ElementNode *pelmRoot,
+ElementNode::ElementNode(const ElementNode *pElmRoot,
Node *pParent,
- xmlNode *plibNode)
+ PRTLISTANCHOR pListAnchor,
+ xmlNode *pLibNode)
: Node(IsElement,
pParent,
- plibNode,
+ pListAnchor,
+ pLibNode,
NULL)
{
- if (!(m_pelmRoot = pelmRoot))
- // NULL passed, then this is the root element
- m_pelmRoot = this;
+ m_pElmRoot = pElmRoot ? pElmRoot : this; // If NULL is passed, then this is the root element.
+ m_pcszName = (const char *)pLibNode->name;
- m_pcszName = (const char*)plibNode->name;
+ if (pLibNode->ns)
+ {
+ m_pcszNamespacePrefix = (const char *)m_pLibNode->ns->prefix;
+ m_pcszNamespaceHref = (const char *)m_pLibNode->ns->href;
+ }
- if (plibNode->ns)
+ RTListInit(&m_children);
+ RTListInit(&m_attributes);
+}
+
+ElementNode::~ElementNode()
+{
+ Node *pCur, *pNext;
+ RTListForEachSafeCpp(&m_children, pCur, pNext, Node, m_listEntry)
{
- m_pcszNamespacePrefix = (const char*)m_plibNode->ns->prefix;
- m_pcszNamespaceHref = (const char*)m_plibNode->ns->href;
+ delete pCur;
}
+ RTListInit(&m_children);
+
+ RTListForEachSafeCpp(&m_attributes, pCur, pNext, Node, m_listEntry)
+ {
+ delete pCur;
+ }
+ RTListInit(&m_attributes);
}
+
+/**
+ * Gets the next tree element in a full tree enumeration.
+ *
+ * @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 *ElementNode::getNextTreeElement(ElementNode const *pElmRoot /*= NULL */) const
+{
+ /*
+ * Consider children first.
+ */
+ ElementNode const *pChild = getFirstChildElement();
+ if (pChild)
+ return pChild;
+
+ /*
+ * Then siblings, aunts and uncles.
+ */
+ ElementNode const *pCur = this;
+ do
+ {
+ ElementNode const *pSibling = pCur->getNextSibilingElement();
+ if (pSibling != NULL)
+ return pSibling;
+
+ pCur = static_cast<const xml::ElementNode *>(pCur->m_pParent);
+ Assert(pCur || pCur == pElmRoot);
+ } while (pCur != pElmRoot);
+
+ return NULL;
+}
+
+
+/**
+ * Private implementation.
+ *
+ * @param pElmRoot The root element.
+ */
+/*static*/ void ElementNode::buildChildren(ElementNode *pElmRoot) // protected
+{
+ for (ElementNode *pCur = pElmRoot; pCur; pCur = pCur->getNextTreeElement(pElmRoot))
+ {
+ /*
+ * Go thru this element's attributes creating AttributeNodes for them.
+ */
+ for (xmlAttr *pLibAttr = pCur->m_pLibNode->properties; pLibAttr; pLibAttr = pLibAttr->next)
+ {
+ AttributeNode *pNew = new AttributeNode(pElmRoot, pCur, &pCur->m_attributes, pLibAttr);
+ RTListAppend(&pCur->m_attributes, &pNew->m_listEntry);
+ }
+
+ /*
+ * Go thru this element's child elements (element and text nodes).
+ */
+ for (xmlNodePtr pLibNode = pCur->m_pLibNode->children; pLibNode; pLibNode = pLibNode->next)
+ {
+ Node *pNew;
+ if (pLibNode->type == XML_ELEMENT_NODE)
+ pNew = new ElementNode(pElmRoot, pCur, &pCur->m_children, pLibNode);
+ else if (pLibNode->type == XML_TEXT_NODE)
+ pNew = new ContentNode(pCur, &pCur->m_children, pLibNode);
+ else
+ continue;
+ RTListAppend(&pCur->m_children, &pNew->m_listEntry);
+ }
+ }
+}
+
+
/**
* Builds a list of direct child elements of the current element that
* match the given string; if pcszMatch is NULL, all direct child
@@ -689,18 +769,16 @@ int ElementNode::getChildElements(ElementNodesList &children,
const
{
int i = 0;
- for (Data::InternalNodesList::iterator it = m->children.begin();
- it != m->children.end();
- ++it)
+ Node *p;
+ RTListForEachCpp(&m_children, p, Node, m_listEntry)
{
// export this child node if ...
- Node *p = it->get();
if (p->isElement())
- if ( (!pcszMatch) // the caller wants all nodes or
- || (!strcmp(pcszMatch, p->getName())) // the element name matches
+ if ( !pcszMatch // ... the caller wants all nodes or ...
+ || !strcmp(pcszMatch, p->getName()) // ... the element name matches.
)
{
- children.push_back(static_cast<ElementNode*>(p));
+ children.push_back(static_cast<ElementNode *>(p));
++i;
}
}
@@ -714,25 +792,18 @@ int ElementNode::getChildElements(ElementNodesList &children,
* @param pcszMatch Element name to match.
* @return
*/
-const ElementNode* ElementNode::findChildElement(const char *pcszNamespace,
- const char *pcszMatch)
- const
+const ElementNode *ElementNode::findChildElementNS(const char *pcszNamespace, const char *pcszMatch) const
{
- Data::InternalNodesList::const_iterator
- it,
- last = m->children.end();
- for (it = m->children.begin();
- it != last;
- ++it)
+ Node *p;
+ RTListForEachCpp(&m_children, p, Node, m_listEntry)
{
- if ((**it).isElement())
+ if (p->isElement())
{
- ElementNode *pelm = static_cast<ElementNode*>((*it).get());
- if (pelm->nameEquals(pcszNamespace, pcszMatch))
+ ElementNode *pelm = static_cast<ElementNode*>(p);
+ if (pelm->nameEqualsNS(pcszNamespace, pcszMatch))
return pelm;
}
}
-
return NULL;
}
@@ -741,58 +812,154 @@ const ElementNode* ElementNode::findChildElement(const char *pcszNamespace,
* @param pcszId identifier to look for.
* @return child element or NULL if not found.
*/
-const ElementNode* ElementNode::findChildElementFromId(const char *pcszId) const
-{
- Data::InternalNodesList::const_iterator
- it,
- last = m->children.end();
- for (it = m->children.begin();
- it != last;
- ++it)
+const ElementNode *ElementNode::findChildElementFromId(const char *pcszId) const
+{
+ const Node *p;
+ RTListForEachCpp(&m_children, p, Node, m_listEntry)
{
- if ((**it).isElement())
+ if (p->isElement())
{
- ElementNode *pelm = static_cast<ElementNode*>((*it).get());
- const AttributeNode *pAttr;
- if ( ((pAttr = pelm->findAttribute("id")))
- && (!strcmp(pAttr->getValue(), pcszId))
- )
- return pelm;
+ const ElementNode *pElm = static_cast<const ElementNode *>(p);
+ const AttributeNode *pAttr = pElm->findAttribute("id");
+ if (pAttr && !strcmp(pAttr->getValue(), pcszId))
+ return pElm;
}
}
+ return NULL;
+}
+
+const ElementNode *ElementNode::findChildElementP(const char *pcszPath, const char *pcszNamespace /*= NULL*/) const
+{
+ size_t cchThis = strchr(pcszPath, '/') - pcszPath;
+ if (cchThis == (size_t)((const char *)0 - pcszPath))
+ return findChildElementNS(pcszNamespace, pcszPath);
+
+ /** @todo Can be done without recursion as we have both sibling lists and parent
+ * pointers in this variant. */
+ const Node *p;
+ RTListForEachCpp(&m_children, p, Node, m_listEntry)
+ {
+ if (p->isElement())
+ {
+ const ElementNode *pElm = static_cast<const ElementNode *>(p);
+ if (pElm->nameEqualsN(pcszPath, cchThis, pcszNamespace))
+ {
+ pElm = findChildElementP(pcszPath + cchThis, pcszNamespace);
+ if (pElm)
+ return pElm;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+const ElementNode *ElementNode::getFirstChildElement() const
+{
+ const Node *p;
+ RTListForEachCpp(&m_children, p, Node, m_listEntry)
+ {
+ if (p->isElement())
+ return static_cast<const ElementNode *>(p);
+ }
+ return NULL;
+}
+
+const ElementNode *ElementNode::getLastChildElement() const
+{
+ const Node *p;
+ RTListForEachReverseCpp(&m_children, p, Node, m_listEntry)
+ {
+ if (p->isElement())
+ return static_cast<const ElementNode *>(p);
+ }
return NULL;
}
+const ElementNode *ElementNode::getPrevSibilingElement() const
+{
+ if (!m_pParent)
+ return NULL;
+ const Node *pSibling = this;
+ for (;;)
+ {
+ pSibling = RTListGetPrevCpp(m_pParentListAnchor, pSibling, const Node, m_listEntry);
+ if (!pSibling)
+ return NULL;
+ if (pSibling->isElement())
+ return static_cast<const ElementNode *>(pSibling);
+ }
+}
+
+const ElementNode *ElementNode::getNextSibilingElement() const
+{
+ if (!m_pParent)
+ return NULL;
+ const Node *pSibling = this;
+ for (;;)
+ {
+ pSibling = RTListGetNextCpp(m_pParentListAnchor, pSibling, const Node, m_listEntry);
+ if (!pSibling)
+ return NULL;
+ if (pSibling->isElement())
+ return static_cast<const ElementNode *>(pSibling);
+ }
+}
+
+const ElementNode *ElementNode::findPrevSibilingElement(const char *pcszMatch, const char *pcszNamespace /*= NULL*/) const
+{
+ if (!m_pParent)
+ return NULL;
+ const Node *pSibling = this;
+ for (;;)
+ {
+ pSibling = RTListGetPrevCpp(m_pParentListAnchor, pSibling, const Node, m_listEntry);
+ if (!pSibling)
+ return NULL;
+ if (pSibling->isElement())
+ {
+ const ElementNode *pElem = static_cast<const ElementNode *>(pSibling);
+ if (pElem->nameEqualsNS(pcszNamespace, pcszMatch))
+ return pElem;
+ }
+ }
+}
+
+const ElementNode *ElementNode::findNextSibilingElement(const char *pcszMatch, const char *pcszNamespace /*= NULL*/) const
+{
+ if (!m_pParent)
+ return NULL;
+ const Node *pSibling = this;
+ for (;;)
+ {
+ pSibling = RTListGetNextCpp(m_pParentListAnchor, pSibling, const Node, m_listEntry);
+ if (!pSibling)
+ return NULL;
+ if (pSibling->isElement())
+ {
+ const ElementNode *pElem = static_cast<const ElementNode *>(pSibling);
+ if (pElem->nameEqualsNS(pcszNamespace, pcszMatch))
+ return pElem;
+ }
+ }
+}
+
+
/**
* Looks up the given attribute node in this element's attribute map.
*
- * With respect to namespaces, the internal attributes map stores namespace
- * prefixes with attribute names only if the attribute uses a non-default
- * namespace. As a result, the following rules apply:
- *
- * -- To find attributes from a non-default namespace, pcszMatch must not
- * be prefixed with a namespace.
- *
- * -- To find attributes from the default namespace (or if the document does
- * not use namespaces), pcszMatch must be prefixed with the namespace
- * prefix and a colon.
- *
- * For example, if the document uses the "vbox:" namespace by default, you
- * must omit "vbox:" from pcszMatch to find such attributes, whether they
- * are specifed in the xml or not.
- *
- * @param pcszMatch
- * @return
+ * @param pcszMatch The name of the attribute to find.
+ * @param pcszNamespace The attribute name space prefix or NULL.
*/
-const AttributeNode* ElementNode::findAttribute(const char *pcszMatch) const
+const AttributeNode *ElementNode::findAttribute(const char *pcszMatch, const char *pcszNamespace /*= NULL*/) const
{
- Data::AttributesMap::const_iterator it;
-
- it = m->attribs.find(pcszMatch);
- if (it != m->attribs.end())
- return it->second.get();
-
+ AttributeNode *p;
+ RTListForEachCpp(&m_attributes, p, AttributeNode, m_listEntry)
+ {
+ if (p->nameEqualsNS(pcszNamespace, pcszMatch))
+ return p;
+ }
return NULL;
}
@@ -800,19 +967,19 @@ const AttributeNode* ElementNode::findAttribute(const char *pcszMatch) const
* Convenience method which attempts to find the attribute with the given
* name and returns its value as a string.
*
- * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks)
- * @param ppcsz out: attribute value
- * @return TRUE if attribute was found and str was thus updated.
+ * @param pcszMatch Name of attribute to find.
+ * @param ppcsz Where to return the attribute.
+ * @param pcszNamespace The attribute name space prefix or NULL.
+ * @returns Boolean success indicator.
*/
-bool ElementNode::getAttributeValue(const char *pcszMatch, const char *&ppcsz) const
+bool ElementNode::getAttributeValue(const char *pcszMatch, const char **ppcsz, const char *pcszNamespace /*= NULL*/) const
{
- const Node* pAttr;
- if ((pAttr = findAttribute(pcszMatch)))
+ const AttributeNode *pAttr = findAttribute(pcszMatch, pcszNamespace);
+ if (pAttr)
{
- ppcsz = pAttr->getValue();
+ *ppcsz = pAttr->getValue();
return true;
}
-
return false;
}
@@ -820,16 +987,20 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, const char *&ppcsz) c
* Convenience method which attempts to find the attribute with the given
* name and returns its value as a string.
*
- * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks)
- * @param str out: attribute value; overwritten only if attribute was found
- * @return TRUE if attribute was found and str was thus updated.
+ * @param pcszMatch Name of attribute to find.
+ * @param pStr Pointer to the string object that should receive the
+ * attribute value.
+ * @param pcszNamespace The attribute name space prefix or NULL.
+ * @returns Boolean success indicator.
+ *
+ * @throws Whatever the string class may throw on assignment.
*/
-bool ElementNode::getAttributeValue(const char *pcszMatch, RTCString &str) const
+bool ElementNode::getAttributeValue(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace /*= NULL*/) const
{
- const Node* pAttr;
- if ((pAttr = findAttribute(pcszMatch)))
+ const AttributeNode *pAttr = findAttribute(pcszMatch, pcszNamespace);
+ if (pAttr)
{
- str = pAttr->getValue();
+ *pStr = pAttr->getValue();
return true;
}
@@ -839,15 +1010,18 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, RTCString &str) const
/**
* Like getAttributeValue (ministring variant), but makes sure that all backslashes
* are converted to forward slashes.
- * @param pcszMatch
- * @param str
- * @return
+ *
+ * @param pcszMatch Name of attribute to find.
+ * @param pStr Pointer to the string object that should
+ * receive the attribute path value.
+ * @param pcszNamespace The attribute name space prefix or NULL.
+ * @returns Boolean success indicator.
*/
-bool ElementNode::getAttributeValuePath(const char *pcszMatch, RTCString &str) const
+bool ElementNode::getAttributeValuePath(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace /*= NULL*/) const
{
- if (getAttributeValue(pcszMatch, str))
+ if (getAttributeValue(pcszMatch, pStr, pcszNamespace))
{
- str.findReplace('\\', '/');
+ pStr->findReplace('\\', '/');
return true;
}
@@ -856,85 +1030,85 @@ bool ElementNode::getAttributeValuePath(const char *pcszMatch, RTCString &str) c
/**
* Convenience method which attempts to find the attribute with the given
- * name and returns its value as a signed integer. This calls
- * RTStrToInt32Ex internally and will only output the integer if that
- * function returns no error.
+ * name and returns its value as a signed 32-bit integer.
*
- * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks)
- * @param i out: attribute value; overwritten only if attribute was found
- * @return TRUE if attribute was found and str was thus updated.
+ * @param pcszMatch Name of attribute to find.
+ * @param piValue Where to return the value.
+ * @param pcszNamespace The attribute name space prefix or NULL.
+ * @returns Boolean success indicator.
*/
-bool ElementNode::getAttributeValue(const char *pcszMatch, int32_t &i) const
+bool ElementNode::getAttributeValue(const char *pcszMatch, int32_t *piValue, const char *pcszNamespace /*= NULL*/) const
{
- const char *pcsz;
- if ( (getAttributeValue(pcszMatch, pcsz))
- && (VINF_SUCCESS == RTStrToInt32Ex(pcsz, NULL, 0, &i))
- )
- return true;
-
+ const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace);
+ if (pcsz)
+ {
+ int rc = RTStrToInt32Ex(pcsz, NULL, 0, piValue);
+ if (rc == VINF_SUCCESS)
+ return true;
+ }
return false;
}
/**
* Convenience method which attempts to find the attribute with the given
- * name and returns its value as an unsigned integer.This calls
- * RTStrToUInt32Ex internally and will only output the integer if that
- * function returns no error.
+ * name and returns its value as an unsigned 32-bit integer.
*
- * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks)
- * @param i out: attribute value; overwritten only if attribute was found
- * @return TRUE if attribute was found and str was thus updated.
+ * @param pcszMatch Name of attribute to find.
+ * @param puValue Where to return the value.
+ * @param pcszNamespace The attribute name space prefix or NULL.
+ * @returns Boolean success indicator.
*/
-bool ElementNode::getAttributeValue(const char *pcszMatch, uint32_t &i) const
+bool ElementNode::getAttributeValue(const char *pcszMatch, uint32_t *puValue, const char *pcszNamespace /*= NULL*/) const
{
- const char *pcsz;
- if ( (getAttributeValue(pcszMatch, pcsz))
- && (VINF_SUCCESS == RTStrToUInt32Ex(pcsz, NULL, 0, &i))
- )
- return true;
-
+ const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace);
+ if (pcsz)
+ {
+ int rc = RTStrToUInt32Ex(pcsz, NULL, 0, puValue);
+ if (rc == VINF_SUCCESS)
+ return true;
+ }
return false;
}
/**
* Convenience method which attempts to find the attribute with the given
- * name and returns its value as a signed long integer. This calls
- * RTStrToInt64Ex internally and will only output the integer if that
- * function returns no error.
+ * name and returns its value as a signed 64-bit integer.
*
- * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks)
- * @param i out: attribute value
- * @return TRUE if attribute was found and str was thus updated.
+ * @param pcszMatch Name of attribute to find.
+ * @param piValue Where to return the value.
+ * @param pcszNamespace The attribute name space prefix or NULL.
+ * @returns Boolean success indicator.
*/
-bool ElementNode::getAttributeValue(const char *pcszMatch, int64_t &i) const
+bool ElementNode::getAttributeValue(const char *pcszMatch, int64_t *piValue, const char *pcszNamespace /*= NULL*/) const
{
- const char *pcsz;
- if ( (getAttributeValue(pcszMatch, pcsz))
- && (VINF_SUCCESS == RTStrToInt64Ex(pcsz, NULL, 0, &i))
- )
- return true;
-
+ const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace);
+ if (pcsz)
+ {
+ int rc = RTStrToInt64Ex(pcsz, NULL, 0, piValue);
+ if (rc == VINF_SUCCESS)
+ return true;
+ }
return false;
}
/**
* Convenience method which attempts to find the attribute with the given
- * name and returns its value as an unsigned long integer.This calls
- * RTStrToUInt64Ex internally and will only output the integer if that
- * function returns no error.
+ * name and returns its value as an unsigned 64-bit integer.
*
- * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks)
- * @param i out: attribute value; overwritten only if attribute was found
- * @return TRUE if attribute was found and str was thus updated.
+ * @param pcszMatch Name of attribute to find.
+ * @param puValue Where to return the value.
+ * @param pcszNamespace The attribute name space prefix or NULL.
+ * @returns Boolean success indicator.
*/
-bool ElementNode::getAttributeValue(const char *pcszMatch, uint64_t &i) const
+bool ElementNode::getAttributeValue(const char *pcszMatch, uint64_t *puValue, const char *pcszNamespace /*= NULL*/) const
{
- const char *pcsz;
- if ( (getAttributeValue(pcszMatch, pcsz))
- && (VINF_SUCCESS == RTStrToUInt64Ex(pcsz, NULL, 0, &i))
- )
- return true;
-
+ const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace);
+ if (pcsz)
+ {
+ int rc = RTStrToUInt64Ex(pcsz, NULL, 0, puValue);
+ if (rc == VINF_SUCCESS)
+ return true;
+ }
return false;
}
@@ -943,29 +1117,30 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, uint64_t &i) const
* name and returns its value as a boolean. This accepts "true", "false",
* "yes", "no", "1" or "0" as valid values.
*
- * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks)
- * @param f out: attribute value; overwritten only if attribute was found
- * @return TRUE if attribute was found and str was thus updated.
+ * @param pcszMatch Name of attribute to find.
+ * @param pfValue Where to return the value.
+ * @param pcszNamespace The attribute name space prefix or NULL.
+ * @returns Boolean success indicator.
*/
-bool ElementNode::getAttributeValue(const char *pcszMatch, bool &f) const
+bool ElementNode::getAttributeValue(const char *pcszMatch, bool *pfValue, const char *pcszNamespace /*= NULL*/) const
{
- const char *pcsz;
- if (getAttributeValue(pcszMatch, pcsz))
+ const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace);
+ if (pcsz)
{
- if ( (!strcmp(pcsz, "true"))
- || (!strcmp(pcsz, "yes"))
- || (!strcmp(pcsz, "1"))
+ if ( !strcmp(pcsz, "true")
+ || !strcmp(pcsz, "yes")
+ || !strcmp(pcsz, "1")
)
{
- f = true;
+ *pfValue = true;
return true;
}
- if ( (!strcmp(pcsz, "false"))
- || (!strcmp(pcsz, "no"))
- || (!strcmp(pcsz, "0"))
+ if ( !strcmp(pcsz, "false")
+ || !strcmp(pcsz, "no")
+ || !strcmp(pcsz, "0")
)
{
- f = false;
+ *pfValue = false;
return true;
}
}
@@ -973,6 +1148,81 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, bool &f) const
return false;
}
+
+bool ElementNode::getElementValue(int32_t *piValue) const
+{
+ const char *pszValue = getValue();
+ if (pszValue)
+ {
+ int rc = RTStrToInt32Ex(pszValue, NULL, 0, piValue);
+ if (rc == VINF_SUCCESS)
+ return true;
+ }
+ return false;
+}
+
+bool ElementNode::getElementValue(uint32_t *puValue) const
+{
+ const char *pszValue = getValue();
+ if (pszValue)
+ {
+ int rc = RTStrToUInt32Ex(pszValue, NULL, 0, puValue);
+ if (rc == VINF_SUCCESS)
+ return true;
+ }
+ return false;
+}
+
+bool ElementNode::getElementValue(int64_t *piValue) const
+{
+ const char *pszValue = getValue();
+ if (pszValue)
+ {
+ int rc = RTStrToInt64Ex(pszValue, NULL, 0, piValue);
+ if (rc == VINF_SUCCESS)
+ return true;
+ }
+ return false;
+}
+
+bool ElementNode::getElementValue(uint64_t *puValue) const
+{
+ const char *pszValue = getValue();
+ if (pszValue)
+ {
+ int rc = RTStrToUInt64Ex(pszValue, NULL, 0, puValue);
+ if (rc == VINF_SUCCESS)
+ return true;
+ }
+ return false;
+}
+
+bool ElementNode::getElementValue(bool *pfValue) const
+{
+ const char *pszValue = getValue();
+ if (pszValue)
+ {
+ if ( !strcmp(pszValue, "true")
+ || !strcmp(pszValue, "yes")
+ || !strcmp(pszValue, "1")
+ )
+ {
+ *pfValue = true;
+ return true;
+ }
+ if ( !strcmp(pszValue, "false")
+ || !strcmp(pszValue, "no")
+ || !strcmp(pszValue, "0")
+ )
+ {
+ *pfValue = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+
/**
* Creates a new child element node and appends it to the list
* of children in "this".
@@ -980,23 +1230,22 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, bool &f) const
* @param pcszElementName
* @return
*/
-ElementNode* ElementNode::createChild(const char *pcszElementName)
+ElementNode *ElementNode::createChild(const char *pcszElementName)
{
// we must be an element, not an attribute
- if (!m_plibNode)
+ if (!m_pLibNode)
throw ENodeIsNotElement(RT_SRC_POS);
// libxml side: create new node
- xmlNode *plibNode;
- if (!(plibNode = xmlNewNode(NULL, // namespace
+ xmlNode *pLibNode;
+ if (!(pLibNode = xmlNewNode(NULL, // namespace
(const xmlChar*)pcszElementName)))
throw std::bad_alloc();
- xmlAddChild(m_plibNode, plibNode);
+ xmlAddChild(m_pLibNode, pLibNode);
// now wrap this in C++
- ElementNode *p = new ElementNode(m_pelmRoot, this, plibNode);
- boost::shared_ptr<ElementNode> pNew(p);
- m->children.push_back(pNew);
+ ElementNode *p = new ElementNode(m_pElmRoot, this, &m_children, pLibNode);
+ RTListAppend(&m_children, &p->m_listEntry);
return p;
}
@@ -1009,18 +1258,17 @@ ElementNode* ElementNode::createChild(const char *pcszElementName)
* @param pcszContent
* @return
*/
-ContentNode* ElementNode::addContent(const char *pcszContent)
+ContentNode *ElementNode::addContent(const char *pcszContent)
{
// libxml side: create new node
- xmlNode *plibNode;
- if (!(plibNode = xmlNewText((const xmlChar*)pcszContent)))
+ xmlNode *pLibNode = xmlNewText((const xmlChar*)pcszContent);
+ if (!pLibNode)
throw std::bad_alloc();
- xmlAddChild(m_plibNode, plibNode);
+ xmlAddChild(m_pLibNode, pLibNode);
// now wrap this in C++
- ContentNode *p = new ContentNode(this, plibNode);
- boost::shared_ptr<ContentNode> pNew(p);
- m->children.push_back(pNew);
+ ContentNode *p = new ContentNode(this, &m_children, pLibNode);
+ RTListAppend(&m_children, &p->m_listEntry);
return p;
}
@@ -1032,42 +1280,40 @@ ContentNode* ElementNode::addContent(const char *pcszContent)
* otherwise a new attribute is created. Returns the attribute node
* that was either created or changed.
*
- * @param pcszName
- * @param pcszValue
- * @return
+ * @param pcszName The attribute name.
+ * @param pcszValue The attribute value.
+ * @return Pointer to the attribute node that was created or modified.
*/
-AttributeNode* ElementNode::setAttribute(const char *pcszName, const char *pcszValue)
+AttributeNode *ElementNode::setAttribute(const char *pcszName, const char *pcszValue)
{
- AttributeNode *pattrReturn;
- Data::AttributesMap::const_iterator it;
-
- it = m->attribs.find(pcszName);
- if (it == m->attribs.end())
- {
- // libxml side: xmlNewProp creates an attribute
- xmlAttr *plibAttr = xmlNewProp(m_plibNode, (xmlChar*)pcszName, (xmlChar*)pcszValue);
-
- // C++ side: create an attribute node around it
- const char *pcszKey;
- boost::shared_ptr<AttributeNode> pNew(new AttributeNode(*m_pelmRoot, this, plibAttr, &pcszKey));
- // store
- m->attribs[pcszKey] = pNew;
- pattrReturn = pNew.get();
- }
- else
+ /*
+ * Do we already have an attribute and should we just update it?
+ */
+ AttributeNode *pAttr;
+ RTListForEachCpp(&m_attributes, pAttr, AttributeNode, m_listEntry)
{
- // overwrite existing libxml attribute node
- xmlAttrPtr plibAttr = xmlSetProp(m_plibNode, (xmlChar*)pcszName, (xmlChar*)pcszValue);
-
- // and fix our existing C++ side around it
- boost::shared_ptr<AttributeNode> pattr = it->second;
- pattr->m_plibAttr = plibAttr; // in case the xmlAttrPtr is different, I'm not sure
+ if (pAttr->nameEquals(pcszName))
+ {
+ /* Overwrite existing libxml attribute node ... */
+ xmlAttrPtr pLibAttr = xmlSetProp(m_pLibNode, (xmlChar *)pcszName, (xmlChar *)pcszValue);
- pattrReturn = pattr.get();
+ /* ... and update our C++ wrapper in case the attrib pointer changed. */
+ pAttr->m_pLibAttr = pLibAttr;
+ return pAttr;
+ }
}
- return pattrReturn;
+ /*
+ * No existing attribute, create a new one.
+ */
+ /* libxml side: xmlNewProp creates an attribute. */
+ xmlAttr *pLibAttr = xmlNewProp(m_pLibNode, (xmlChar *)pcszName, (xmlChar *)pcszValue);
+
+ /* C++ side: Create an attribute node around it. */
+ pAttr = new AttributeNode(m_pElmRoot, this, &m_attributes, pLibAttr);
+ RTListAppend(&m_attributes, &pAttr->m_listEntry);
+ return pAttr;
}
/**
@@ -1196,53 +1442,41 @@ AttributeNode* ElementNode::setAttribute(const char *pcszName, bool f)
}
/**
- * Private constructor for a new attribute node. This one is special:
- * in ppcszKey, it returns a pointer to a string buffer that should be
- * used to index the attribute correctly with namespaces.
+ * Private constructor for a new attribute node.
*
- * @param pParent
- * @param elmRoot
- * @param plibAttr
- * @param ppcszKey
+ * @param pElmRoot Pointer to the root element. Needed for getting the
+ * default name space.
+ * @param pParent Pointer to the parent element (always an ElementNode,
+ * despite the type). NULL for the root node.
+ * @param pListAnchor Pointer to the m_children member of the parent. NULL
+ * for the root node.
+ * @param pLibNode Pointer to the libxml2 node structure.
*/
-AttributeNode::AttributeNode(const ElementNode &elmRoot,
+AttributeNode::AttributeNode(const ElementNode *pElmRoot,
Node *pParent,
- xmlAttr *plibAttr,
- const char **ppcszKey)
+ PRTLISTANCHOR pListAnchor,
+ xmlAttr *pLibAttr)
: Node(IsAttribute,
pParent,
+ pListAnchor,
NULL,
- plibAttr)
+ pLibAttr)
{
- m_pcszName = (const char*)plibAttr->name;
+ m_pcszName = (const char *)pLibAttr->name;
- *ppcszKey = m_pcszName;
-
- if ( plibAttr->ns
- && plibAttr->ns->prefix
- )
+ if ( pLibAttr->ns
+ && pLibAttr->ns->prefix)
{
- m_pcszNamespacePrefix = (const char*)plibAttr->ns->prefix;
- m_pcszNamespaceHref = (const char*)plibAttr->ns->href;
-
- if ( !elmRoot.m_pcszNamespaceHref
- || (strcmp(m_pcszNamespaceHref, elmRoot.m_pcszNamespaceHref))
- )
- {
- // not default namespace:
- m_strKey = m_pcszNamespacePrefix;
- m_strKey.append(':');
- m_strKey.append(m_pcszName);
-
- *ppcszKey = m_strKey.c_str();
- }
+ m_pcszNamespacePrefix = (const char *)pLibAttr->ns->prefix;
+ m_pcszNamespaceHref = (const char *)pLibAttr->ns->href;
}
}
-ContentNode::ContentNode(Node *pParent, xmlNode *plibNode)
+ContentNode::ContentNode(Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode)
: Node(IsContent,
pParent,
- plibNode,
+ pListAnchor,
+ pLibNode,
NULL)
{
}
@@ -1380,9 +1614,9 @@ Document::~Document()
*/
void Document::refreshInternals() // private
{
- m->pRootElement = new ElementNode(NULL, NULL, xmlDocGetRootElement(m->plibDocument));
+ m->pRootElement = new ElementNode(NULL, NULL, NULL, xmlDocGetRootElement(m->plibDocument));
- m->pRootElement->buildChildren(*m->pRootElement);
+ ElementNode::buildChildren(m->pRootElement);
}
/**
@@ -1390,7 +1624,7 @@ void Document::refreshInternals() // private
* Const variant.
* @return
*/
-const ElementNode* Document::getRootElement() const
+const ElementNode *Document::getRootElement() const
{
return m->pRootElement;
}
@@ -1400,41 +1634,43 @@ const ElementNode* Document::getRootElement() const
* Non-const variant.
* @return
*/
-ElementNode* Document::getRootElement()
+ElementNode *Document::getRootElement()
{
return m->pRootElement;
}
/**
- * Creates a new element node and sets it as the root element. This will
- * only work if the document is empty; otherwise EDocumentNotEmpty is thrown.
+ * Creates a new element node and sets it as the root element.
+ *
+ * This will only work if the document is empty; otherwise EDocumentNotEmpty is
+ * thrown.
*/
-ElementNode* Document::createRootElement(const char *pcszRootElementName,
+ElementNode *Document::createRootElement(const char *pcszRootElementName,
const char *pcszComment /* = NULL */)
{
if (m->pRootElement || m->plibDocument)
throw EDocumentNotEmpty(RT_SRC_POS);
// libxml side: create document, create root node
- m->plibDocument = xmlNewDoc((const xmlChar*)"1.0");
- xmlNode *plibRootNode;
- if (!(plibRootNode = xmlNewNode(NULL, // namespace
- (const xmlChar*)pcszRootElementName)))
+ m->plibDocument = xmlNewDoc((const xmlChar *)"1.0");
+ xmlNode *plibRootNode = xmlNewNode(NULL /*namespace*/ , (const xmlChar *)pcszRootElementName);
+ if (!plibRootNode)
throw std::bad_alloc();
xmlDocSetRootElement(m->plibDocument, plibRootNode);
+
// now wrap this in C++
- m->pRootElement = new ElementNode(NULL, NULL, plibRootNode);
+ m->pRootElement = new ElementNode(NULL, NULL, NULL, plibRootNode);
// add document global comment if specified
if (pcszComment != NULL)
{
- xmlNode *pComment;
- if (!(pComment = xmlNewDocComment(m->plibDocument,
- (const xmlChar *)pcszComment)))
+ xmlNode *pComment = xmlNewDocComment(m->plibDocument, (const xmlChar *)pcszComment);
+ if (!pComment)
throw std::bad_alloc();
xmlAddPrevSibling(plibRootNode, pComment);
+
// now wrap this in C++
- m->pComment = new ElementNode(NULL, NULL, pComment);
+ m->pComment = new ElementNode(NULL, NULL, NULL, pComment);
}
return m->pRootElement;
@@ -1480,12 +1716,13 @@ XmlMemParser::~XmlMemParser()
*
* The document that is passed in will be reset before being filled if not empty.
*
- * @param pvBuf in: memory buffer to parse.
- * @param cbSize in: size of the memory buffer.
- * @param strFilename in: name fo file to parse.
- * @param doc out: document to be reset and filled with data according to file contents.
+ * @param pvBuf Memory buffer to parse.
+ * @param cbSize Size of the memory buffer.
+ * @param strFilename Refernece to the name of the file we're parsing.
+ * @param doc Reference to the output document. This will be reset
+ * and filled with data according to file contents.
*/
-void XmlMemParser::read(const void* pvBuf, size_t cbSize,
+void XmlMemParser::read(const void *pvBuf, size_t cbSize,
const RTCString &strFilename,
Document &doc)
{
diff --git a/src/VBox/Runtime/testcase/Makefile.kmk b/src/VBox/Runtime/testcase/Makefile.kmk
index 212d9022..3ceb9f04 100644
--- a/src/VBox/Runtime/testcase/Makefile.kmk
+++ b/src/VBox/Runtime/testcase/Makefile.kmk
@@ -4,7 +4,7 @@
#
#
-# Copyright (C) 2006-2012 Oracle Corporation
+# Copyright (C) 2006-2013 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
@@ -50,6 +50,7 @@ PROGRAMS += \
tstRTBitOperations \
tstRTCidr \
tstRTCritSect \
+ tstRTCritSectRw \
tstRTCType \
tstRTDigest \
tstDir \
@@ -62,6 +63,7 @@ PROGRAMS += \
tstRTFileAio \
tstRTFileAppend-1 \
tstRTFileGetSize-1 \
+ tstRTFileModeStringToFlags \
tstFileLock \
tstFork \
tstRTFsQueries \
@@ -85,7 +87,7 @@ PROGRAMS += \
tstRTMemPool \
tstRTMemWipe \
tstMove \
- tstMp-1 \
+ tstRTMp-1 \
tstOnce \
tstRTPath \
tstRTPipe \
@@ -120,7 +122,7 @@ PROGRAMS += \
tstThread-1 \
tstRTThreadPoke \
tstRTThreadExecutionTime \
- tstTime \
+ tstRTTime \
tstTime-2 \
tstTime-3 \
tstTime-4 \
@@ -135,8 +137,9 @@ PROGRAMS += \
tstVector
PROGRAMS.win += \
- tstRTProcWait \
tstRTCritSectW32 \
+ tstRTLocalIpc \
+ tstRTProcWait \
tstFileAppendWin-1 \
ntGetTimerResolution
PROGRAMS.linux += \
@@ -147,13 +150,12 @@ PROGRAMS.linux += \
tstRTInlineAsmPIC3
PROGRAMS.solaris += \
tstRTCoreDump
-PROGRAMS.l4 += \
- tstIoCtl
PROGRAMS.darwin += \
tstDarwinSched \
tstRTDarwinMachKernel
ifdef VBOX_WITH_LIBCURL
PROGRAMS += \
+ tstRTHttp \
tstRTS3
endif
if1of ($(KBUILD_TARGET_ARCH), amd64 x86)
@@ -215,6 +217,9 @@ tstRTCidr_SOURCES = tstRTCidr.cpp
tstRTCritSect_TEMPLATE = VBOXR3TSTEXE
tstRTCritSect_SOURCES = tstRTCritSect.cpp
+tstRTCritSectRw_TEMPLATE = VBOXR3TSTEXE
+tstRTCritSectRw_SOURCES = tstRTCritSectRw.cpp
+
tstRTCritSectW32_TEMPLATE = VBOXR3TSTEXE
tstRTCritSectW32_SOURCES = tstRTCritSect.cpp
tstRTCritSectW32_DEFS = TRY_WIN32_CRIT
@@ -224,6 +229,12 @@ tstRTCType_SOURCES = tstRTCType.cpp
tstRTDigest_SOURCES = tstRTDigest.cpp
+ifdef VBOX_WITH_LIBCURL
+tstRTHttp_TEMPLATE = VBOXR3TSTEXE
+tstRTHttp_SOURCES = tstRTHttp.cpp
+tstRTHttp_SDKS = VBOX_LIBCURL
+endif
+
tstDir_TEMPLATE = VBOXR3TSTEXE
tstDir_SOURCES = tstDir.cpp
@@ -255,6 +266,9 @@ tstRTFileAppend-1_SOURCES = tstRTFileAppend-1.cpp
tstRTFileGetSize-1_TEMPLATE = VBOXR3TSTEXE
tstRTFileGetSize-1_SOURCES = tstRTFileGetSize-1.cpp
+tstRTFileModeStringToFlags_TEMPLATE = VBOXR3TSTEXE
+tstRTFileModeStringToFlags_SOURCES = tstRTFileModeStringToFlags.cpp
+
tstFileAppendWin-1_TEMPLATE = VBOXR3TSTEXE
tstFileAppendWin-1_SOURCES = tstFileAppendWin-1.cpp
@@ -284,9 +298,6 @@ tstRTHeapOffset_SOURCES = tstRTHeapOffset.cpp
tstRTHeapSimple_TEMPLATE = VBOXR3TSTEXE
tstRTHeapSimple_SOURCES = tstRTHeapSimple.cpp
-tstIoCtl_TEMPLATE = VBOXR3TSTEXE
-tstIoCtl_SOURCES = tstIoCtl.cpp
-
tstRTInlineAsm_TEMPLATE = VBOXR3TSTEXE
tstRTInlineAsm_SOURCES = tstRTInlineAsm.cpp
@@ -393,6 +404,9 @@ tstLdrLoad_SOURCES = tstLdrLoad.cpp
tstRTList_TEMPLATE = VBOXR3TSTEXE
tstRTList_SOURCES = tstRTList.cpp
+tstRTLocalIpc_TEMPLATE = VBOXR3TSTEXE
+tstRTLocalIpc_SOURCES = tstRTLocalIpc.cpp
+
tstRTLockValidator_TEMPLATE = VBOXR3TSTEXE
tstRTLockValidator_SOURCES = tstRTLockValidator.cpp
@@ -417,8 +431,8 @@ tstRTMemWipe_SOURCES = tstRTMemWipe.cpp
tstMove_TEMPLATE = VBOXR3TSTEXE
tstMove_SOURCES = tstMove.cpp
-tstMp-1_TEMPLATE = VBOXR3TSTEXE
-tstMp-1_SOURCES = tstMp-1.cpp
+tstRTMp-1_TEMPLATE = VBOXR3TSTEXE
+tstRTMp-1_SOURCES = tstRTMp-1.cpp
tstNoCrt-1_TEMPLATE = VBOXR3TSTEXE
tstNoCrt-1_DEFS = RT_WITHOUT_NOCRT_WRAPPER_ALIASES
@@ -546,8 +560,8 @@ tstRTThreadPoke_SOURCES = tstRTThreadPoke.cpp
tstRTThreadExecutionTime_TEMPLATE = VBOXR3TSTEXE
tstRTThreadExecutionTime_SOURCES = tstRTThreadExecutionTime.cpp
-tstTime_TEMPLATE = VBOXR3TSTEXE
-tstTime_SOURCES = tstTime.cpp
+tstRTTime_TEMPLATE = VBOXR3TSTEXE
+tstRTTime_SOURCES = tstRTTime.cpp
tstTime-2_TEMPLATE = VBOXR3TSTEXE
tstTime-2_SOURCES = tstTime-2.cpp
diff --git a/src/VBox/Runtime/testcase/ioctl.h b/src/VBox/Runtime/testcase/ioctl.h
deleted file mode 100644
index f9a5273e..00000000
--- a/src/VBox/Runtime/testcase/ioctl.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* $Id: ioctl.h $ */
-/** @file
- * VBox L4/OSS audio - header for Linux IoCtls.
- */
-
-/*
- * Copyright (C) 2006-2007 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-#ifndef ___VBOX_L4_OSS_IOCTL
-#define ___VBOX_L4_OSS_IOCTL
-
-#define IOCPARM_MASK 0x3fff /* parameters must be < 16383 bytes */
-#define IOC_VOID 0U << 30 /* no parameters */
-#define IOC_IN 1U << 30 /* copy out parameters */
-#define IOC_OUT 2U << 30 /* copy in parameters */
-#define IOC_INOUT (IOC_IN|IOC_OUT)
-/* the 0x20000000 is so we can distinguish new ioctl's from old */
-#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y))
-#define _IOR(x,y,t) ((int)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-#define _IOW(x,y,t) ((int)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-/* this should be _IORW, but stdio got there first */
-#define _IOWR(x,y,t) ((int)(IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-#define _IOC_SIZE(x) ((x>>16)&IOCPARM_MASK)
-#define _IOC_DIR(x) (x & 0xf0000000)
-#define _IOC_NONE IOC_VOID
-#define _IOC_READ IOC_OUT
-#define _IOC_WRITE IOC_IN
-
-#endif /* !___VBOX_L4_OSS_IOCTL */
-
diff --git a/src/VBox/Runtime/testcase/ntGetTimerResolution.cpp b/src/VBox/Runtime/testcase/ntGetTimerResolution.cpp
index 7e12327c..96ccfa63 100644
--- a/src/VBox/Runtime/testcase/ntGetTimerResolution.cpp
+++ b/src/VBox/Runtime/testcase/ntGetTimerResolution.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/soundcard.h b/src/VBox/Runtime/testcase/soundcard.h
deleted file mode 100644
index b3fda91a..00000000
--- a/src/VBox/Runtime/testcase/soundcard.h
+++ /dev/null
@@ -1,1300 +0,0 @@
-#ifndef SOUNDCARD_H
-#define SOUNDCARD_H
-/*
- * Copyright by Hannu Savolainen 1993-1997
- *
- * 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.
- */
-/* Minor modification for L4VM */
-
-
-/*
- * OSS interface version. With versions earlier than 3.6 this value is
- * an integer with value less than 361. In versions 3.6 and later
- * it's a six digit hexadecimal value. For example value
- * of 0x030600 represents OSS version 3.6.0.
- * Use ioctl(fd, OSS_GETVERSION, &int) to get the version number of
- * the currently active driver.
- */
-#define SOUND_VERSION 0x030802
-#define OPEN_SOUND_SYSTEM
-
-/* In Linux we need to be prepared for cross compiling */
-/* Our own local version of linux/ioctl.h. */
-#include "ioctl.h"
-
-/*
- * Supported card ID numbers (Should be somewhere else?)
- */
-
-#define SNDCARD_ADLIB 1
-#define SNDCARD_SB 2
-#define SNDCARD_PAS 3
-#define SNDCARD_GUS 4
-#define SNDCARD_MPU401 5
-#define SNDCARD_SB16 6
-#define SNDCARD_SB16MIDI 7
-#define SNDCARD_UART6850 8
-#define SNDCARD_GUS16 9
-#define SNDCARD_MSS 10
-#define SNDCARD_PSS 11
-#define SNDCARD_SSCAPE 12
-#define SNDCARD_PSS_MPU 13
-#define SNDCARD_PSS_MSS 14
-#define SNDCARD_SSCAPE_MSS 15
-#define SNDCARD_TRXPRO 16
-#define SNDCARD_TRXPRO_SB 17
-#define SNDCARD_TRXPRO_MPU 18
-#define SNDCARD_MAD16 19
-#define SNDCARD_MAD16_MPU 20
-#define SNDCARD_CS4232 21
-#define SNDCARD_CS4232_MPU 22
-#define SNDCARD_MAUI 23
-#define SNDCARD_PSEUDO_MSS 24
-#define SNDCARD_GUSPNP 25
-#define SNDCARD_UART401 26
-/* Sound card numbers 27 to N are reserved. Don't add more numbers here. */
-
-/***********************************
- * IOCTL Commands for /dev/sequencer
- */
-
-#ifndef _SIOWR
-#if defined(_IOWR) && (defined(_AIX) || (!defined(sun) && !defined(sparc) && !defined(__sparc__) && !defined(__INCioctlh) && !defined(__Lynx__)))
-/* Use already defined ioctl defines if they exist (except with Sun or Sparc) */
-#define SIOCPARM_MASK IOCPARM_MASK
-#define SIOC_VOID IOC_VOID
-#define SIOC_OUT IOC_OUT
-#define SIOC_IN IOC_IN
-#define SIOC_INOUT IOC_INOUT
-#define _SIOC_SIZE _IOC_SIZE
-#define _SIOC_DIR _IOC_DIR
-#define _SIOC_NONE _IOC_NONE
-#define _SIOC_READ _IOC_READ
-#define _SIOC_WRITE _IOC_WRITE
-#define _SIO _IO
-#define _SIOR _IOR
-#define _SIOW _IOW
-#define _SIOWR _IOWR
-#else
-
-/* Ioctl's have the command encoded in the lower word,
- * and the size of any in or out parameters in the upper
- * word. The high 2 bits of the upper word are used
- * to encode the in/out status of the parameter; for now
- * we restrict parameters to at most 8191 bytes.
- */
-/* #define SIOCTYPE (0xff<<8) */
-#define SIOCPARM_MASK 0x1fff /* parameters must be < 8192 bytes */
-#define SIOC_VOID 0x00000000 /* no parameters */
-#define SIOC_OUT 0x20000000 /* copy out parameters */
-#define SIOC_IN 0x40000000 /* copy in parameters */
-#define SIOC_INOUT (SIOC_IN|SIOC_OUT)
-/* the 0x20000000 is so we can distinguish new ioctl's from old */
-#define _SIO(x,y) ((int)(SIOC_VOID|(x<<8)|y))
-#define _SIOR(x,y,t) ((int)(SIOC_OUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
-#define _SIOW(x,y,t) ((int)(SIOC_IN|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
-/* this should be _SIORW, but stdio got there first */
-#define _SIOWR(x,y,t) ((int)(SIOC_INOUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
-#define _SIOC_SIZE(x) ((x>>16)&SIOCPARM_MASK)
-#define _SIOC_DIR(x) (x & 0xf0000000)
-#define _SIOC_NONE SIOC_VOID
-#define _SIOC_READ SIOC_OUT
-#define _SIOC_WRITE SIOC_IN
-# endif /* _IOWR */
-#endif /* !_SIOWR */
-
-#define SNDCTL_SEQ_RESET _SIO ('Q', 0)
-#define SNDCTL_SEQ_SYNC _SIO ('Q', 1)
-#define SNDCTL_SYNTH_INFO _SIOWR('Q', 2, struct synth_info)
-#define SNDCTL_SEQ_CTRLRATE _SIOWR('Q', 3, int) /* Set/get timer resolution (HZ) */
-#define SNDCTL_SEQ_GETOUTCOUNT _SIOR ('Q', 4, int)
-#define SNDCTL_SEQ_GETINCOUNT _SIOR ('Q', 5, int)
-#define SNDCTL_SEQ_PERCMODE _SIOW ('Q', 6, int)
-#define SNDCTL_FM_LOAD_INSTR _SIOW ('Q', 7, struct sbi_instrument) /* Obsolete. Don't use!!!!!! */
-#define SNDCTL_SEQ_TESTMIDI _SIOW ('Q', 8, int)
-#define SNDCTL_SEQ_RESETSAMPLES _SIOW ('Q', 9, int)
-#define SNDCTL_SEQ_NRSYNTHS _SIOR ('Q',10, int)
-#define SNDCTL_SEQ_NRMIDIS _SIOR ('Q',11, int)
-#define SNDCTL_MIDI_INFO _SIOWR('Q',12, struct midi_info)
-#define SNDCTL_SEQ_THRESHOLD _SIOW ('Q',13, int)
-#define SNDCTL_SYNTH_MEMAVL _SIOWR('Q',14, int) /* in=dev#, out=memsize */
-#define SNDCTL_FM_4OP_ENABLE _SIOW ('Q',15, int) /* in=dev# */
-#define SNDCTL_SEQ_PANIC _SIO ('Q',17)
-#define SNDCTL_SEQ_OUTOFBAND _SIOW ('Q',18, struct seq_event_rec)
-#define SNDCTL_SEQ_GETTIME _SIOR ('Q',19, int)
-#define SNDCTL_SYNTH_ID _SIOWR('Q',20, struct synth_info)
-#define SNDCTL_SYNTH_CONTROL _SIOWR('Q',21, struct synth_control)
-#define SNDCTL_SYNTH_REMOVESAMPLE _SIOWR('Q',22, struct remove_sample)
-
-typedef struct synth_control
-{
- int devno; /* Synthesizer # */
- char data[4000]; /* Device specific command/data record */
-}synth_control;
-
-typedef struct remove_sample
-{
- int devno; /* Synthesizer # */
- int bankno; /* MIDI bank # (0=General MIDI) */
- int instrno; /* MIDI instrument number */
-} remove_sample;
-
-typedef struct seq_event_rec {
- unsigned char arr[8];
-} seq_event_rec;
-
-#define SNDCTL_TMR_TIMEBASE _SIOWR('T', 1, int)
-#define SNDCTL_TMR_START _SIO ('T', 2)
-#define SNDCTL_TMR_STOP _SIO ('T', 3)
-#define SNDCTL_TMR_CONTINUE _SIO ('T', 4)
-#define SNDCTL_TMR_TEMPO _SIOWR('T', 5, int)
-#define SNDCTL_TMR_SOURCE _SIOWR('T', 6, int)
-# define TMR_INTERNAL 0x00000001
-# define TMR_EXTERNAL 0x00000002
-# define TMR_MODE_MIDI 0x00000010
-# define TMR_MODE_FSK 0x00000020
-# define TMR_MODE_CLS 0x00000040
-# define TMR_MODE_SMPTE 0x00000080
-#define SNDCTL_TMR_METRONOME _SIOW ('T', 7, int)
-#define SNDCTL_TMR_SELECT _SIOW ('T', 8, int)
-
-/*
- * Some big endian/little endian handling macros
- */
-
-#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(__sparc__) || defined(HPPA) || defined(PPC) || defined(__powerpc64__) || defined(__mc68000__)
-/* Big endian machines */
-# define _PATCHKEY(id) (0xfd00|id)
-# define AFMT_S16_NE AFMT_S16_BE
-#else
-# define _PATCHKEY(id) ((id<<8)|0xfd)
-# define AFMT_S16_NE AFMT_S16_LE
-#endif
-
-/*
- * Sample loading mechanism for internal synthesizers (/dev/sequencer)
- * The following patch_info structure has been designed to support
- * Gravis UltraSound. It tries to be universal format for uploading
- * sample based patches but is probably too limited.
- *
- * (PBD) As Hannu guessed, the GUS structure is too limited for
- * the WaveFront, but this is the right place for a constant definition.
- */
-
-struct patch_info {
- unsigned short key; /* Use WAVE_PATCH here */
-#define WAVE_PATCH _PATCHKEY(0x04)
-#define GUS_PATCH WAVE_PATCH
-#define WAVEFRONT_PATCH _PATCHKEY(0x06)
-
- short device_no; /* Synthesizer number */
- short instr_no; /* Midi pgm# */
-
- unsigned int mode;
-/*
- * The least significant byte has the same format than the GUS .PAT
- * files
- */
-#define WAVE_16_BITS 0x01 /* bit 0 = 8 or 16 bit wave data. */
-#define WAVE_UNSIGNED 0x02 /* bit 1 = Signed - Unsigned data. */
-#define WAVE_LOOPING 0x04 /* bit 2 = looping enabled-1. */
-#define WAVE_BIDIR_LOOP 0x08 /* bit 3 = Set is bidirectional looping. */
-#define WAVE_LOOP_BACK 0x10 /* bit 4 = Set is looping backward. */
-#define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3)*/
-#define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */
-#define WAVE_FAST_RELEASE 0x80 /* bit 7 = Shut off immediately after note off */
- /* (use the env_rate/env_offs fields). */
-/* Linux specific bits */
-#define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */
-#define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */
-#define WAVE_SCALE 0x00040000 /* The scaling info is valid */
-#define WAVE_FRACTIONS 0x00080000 /* Fraction information is valid */
-/* Reserved bits */
-#define WAVE_ROM 0x40000000 /* For future use */
-#define WAVE_MULAW 0x20000000 /* For future use */
-/* Other bits must be zeroed */
-
- int len; /* Size of the wave data in bytes */
- int loop_start, loop_end; /* Byte offsets from the beginning */
-
-/*
- * The base_freq and base_note fields are used when computing the
- * playback speed for a note. The base_note defines the tone frequency
- * which is heard if the sample is played using the base_freq as the
- * playback speed.
- *
- * The low_note and high_note fields define the minimum and maximum note
- * frequencies for which this sample is valid. It is possible to define
- * more than one samples for an instrument number at the same time. The
- * low_note and high_note fields are used to select the most suitable one.
- *
- * The fields base_note, high_note and low_note should contain
- * the note frequency multiplied by 1000. For example value for the
- * middle A is 440*1000.
- */
-
- unsigned int base_freq;
- unsigned int base_note;
- unsigned int high_note;
- unsigned int low_note;
- int panning; /* -128=left, 127=right */
- int detuning;
-
-/* New fields introduced in version 1.99.5 */
-
- /* Envelope. Enabled by mode bit WAVE_ENVELOPES */
- unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */
- unsigned char env_offset[ 6 ]; /* 255 == 100% */
-
- /*
- * The tremolo, vibrato and scale info are not supported yet.
- * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or
- * WAVE_SCALE
- */
-
- unsigned char tremolo_sweep;
- unsigned char tremolo_rate;
- unsigned char tremolo_depth;
-
- unsigned char vibrato_sweep;
- unsigned char vibrato_rate;
- unsigned char vibrato_depth;
-
- int scale_frequency;
- unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */
-
- int volume;
- int fractions;
- int reserved1;
- int spare[2];
- char data[1]; /* The waveform data starts here */
- };
-
-struct sysex_info {
- short key; /* Use SYSEX_PATCH or MAUI_PATCH here */
-#define SYSEX_PATCH _PATCHKEY(0x05)
-#define MAUI_PATCH _PATCHKEY(0x06)
- short device_no; /* Synthesizer number */
- int len; /* Size of the sysex data in bytes */
- unsigned char data[1]; /* Sysex data starts here */
- };
-
-/*
- * /dev/sequencer input events.
- *
- * The data written to the /dev/sequencer is a stream of events. Events
- * are records of 4 or 8 bytes. The first byte defines the size.
- * Any number of events can be written with a write call. There
- * is a set of macros for sending these events. Use these macros if you
- * want to maximize portability of your program.
- *
- * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events.
- * (All input events are currently 4 bytes long. Be prepared to support
- * 8 byte events also. If you receive any event having first byte >= 128,
- * it's a 8 byte event.
- *
- * The events are documented at the end of this file.
- *
- * Normal events (4 bytes)
- * There is also a 8 byte version of most of the 4 byte events. The
- * 8 byte one is recommended.
- */
-#define SEQ_NOTEOFF 0
-#define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */
-#define SEQ_NOTEON 1
-#define SEQ_FMNOTEON SEQ_NOTEON
-#define SEQ_WAIT TMR_WAIT_ABS
-#define SEQ_PGMCHANGE 3
-#define SEQ_FMPGMCHANGE SEQ_PGMCHANGE
-#define SEQ_SYNCTIMER TMR_START
-#define SEQ_MIDIPUTC 5
-#define SEQ_DRUMON 6 /*** OBSOLETE ***/
-#define SEQ_DRUMOFF 7 /*** OBSOLETE ***/
-#define SEQ_ECHO TMR_ECHO /* For syncing programs with output */
-#define SEQ_AFTERTOUCH 9
-#define SEQ_CONTROLLER 10
-
-/*******************************************
- * Midi controller numbers
- *******************************************
- * Controllers 0 to 31 (0x00 to 0x1f) and
- * 32 to 63 (0x20 to 0x3f) are continuous
- * controllers.
- * In the MIDI 1.0 these controllers are sent using
- * two messages. Controller numbers 0 to 31 are used
- * to send the MSB and the controller numbers 32 to 63
- * are for the LSB. Note that just 7 bits are used in MIDI bytes.
- */
-
-#define CTL_BANK_SELECT 0x00
-#define CTL_MODWHEEL 0x01
-#define CTL_BREATH 0x02
-/* undefined 0x03 */
-#define CTL_FOOT 0x04
-#define CTL_PORTAMENTO_TIME 0x05
-#define CTL_DATA_ENTRY 0x06
-#define CTL_MAIN_VOLUME 0x07
-#define CTL_BALANCE 0x08
-/* undefined 0x09 */
-#define CTL_PAN 0x0a
-#define CTL_EXPRESSION 0x0b
-/* undefined 0x0c */
-/* undefined 0x0d */
-/* undefined 0x0e */
-/* undefined 0x0f */
-#define CTL_GENERAL_PURPOSE1 0x10
-#define CTL_GENERAL_PURPOSE2 0x11
-#define CTL_GENERAL_PURPOSE3 0x12
-#define CTL_GENERAL_PURPOSE4 0x13
-/* undefined 0x14 - 0x1f */
-
-/* undefined 0x20 */
-/* The controller numbers 0x21 to 0x3f are reserved for the */
-/* least significant bytes of the controllers 0x00 to 0x1f. */
-/* These controllers are not recognised by the driver. */
-
-/* Controllers 64 to 69 (0x40 to 0x45) are on/off switches. */
-/* 0=OFF and 127=ON (intermediate values are possible) */
-#define CTL_DAMPER_PEDAL 0x40
-#define CTL_SUSTAIN 0x40 /* Alias */
-#define CTL_HOLD 0x40 /* Alias */
-#define CTL_PORTAMENTO 0x41
-#define CTL_SOSTENUTO 0x42
-#define CTL_SOFT_PEDAL 0x43
-/* undefined 0x44 */
-#define CTL_HOLD2 0x45
-/* undefined 0x46 - 0x4f */
-
-#define CTL_GENERAL_PURPOSE5 0x50
-#define CTL_GENERAL_PURPOSE6 0x51
-#define CTL_GENERAL_PURPOSE7 0x52
-#define CTL_GENERAL_PURPOSE8 0x53
-/* undefined 0x54 - 0x5a */
-#define CTL_EXT_EFF_DEPTH 0x5b
-#define CTL_TREMOLO_DEPTH 0x5c
-#define CTL_CHORUS_DEPTH 0x5d
-#define CTL_DETUNE_DEPTH 0x5e
-#define CTL_CELESTE_DEPTH 0x5e /* Alias for the above one */
-#define CTL_PHASER_DEPTH 0x5f
-#define CTL_DATA_INCREMENT 0x60
-#define CTL_DATA_DECREMENT 0x61
-#define CTL_NONREG_PARM_NUM_LSB 0x62
-#define CTL_NONREG_PARM_NUM_MSB 0x63
-#define CTL_REGIST_PARM_NUM_LSB 0x64
-#define CTL_REGIST_PARM_NUM_MSB 0x65
-/* undefined 0x66 - 0x78 */
-/* reserved 0x79 - 0x7f */
-
-/* Pseudo controllers (not midi compatible) */
-#define CTRL_PITCH_BENDER 255
-#define CTRL_PITCH_BENDER_RANGE 254
-#define CTRL_EXPRESSION 253 /* Obsolete */
-#define CTRL_MAIN_VOLUME 252 /* Obsolete */
-#define SEQ_BALANCE 11
-#define SEQ_VOLMODE 12
-
-/*
- * Volume mode decides how volumes are used
- */
-
-#define VOL_METHOD_ADAGIO 1
-#define VOL_METHOD_LINEAR 2
-
-/*
- * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as
- * input events.
- */
-
-/*
- * Event codes 0xf0 to 0xfc are reserved for future extensions.
- */
-
-#define SEQ_FULLSIZE 0xfd /* Long events */
-/*
- * SEQ_FULLSIZE events are used for loading patches/samples to the
- * synthesizer devices. These events are passed directly to the driver
- * of the associated synthesizer device. There is no limit to the size
- * of the extended events. These events are not queued but executed
- * immediately when the write() is called (execution can take several
- * seconds of time).
- *
- * When a SEQ_FULLSIZE message is written to the device, it must
- * be written using exactly one write() call. Other events cannot
- * be mixed to the same write.
- *
- * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the
- * /dev/sequencer. Don't write other data together with the instrument structure
- * Set the key field of the structure to FM_PATCH. The device field is used to
- * route the patch to the corresponding device.
- *
- * For wave table use struct patch_info. Initialize the key field
- * to WAVE_PATCH.
- */
-#define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */
-#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) OBSOLETE */
-
-/*
- * Record for FM patches
- */
-
-typedef unsigned char sbi_instr_data[32];
-
-struct sbi_instrument {
- unsigned short key; /* FM_PATCH or OPL3_PATCH */
-#define FM_PATCH _PATCHKEY(0x01)
-#define OPL3_PATCH _PATCHKEY(0x03)
- short device; /* Synth# (0-4) */
- int channel; /* Program# to be initialized */
- sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */
- };
-
-struct synth_info { /* Read only */
- char name[30];
- int device; /* 0-N. INITIALIZE BEFORE CALLING */
- int synth_type;
-#define SYNTH_TYPE_FM 0
-#define SYNTH_TYPE_SAMPLE 1
-#define SYNTH_TYPE_MIDI 2 /* Midi interface */
-
- int synth_subtype;
-#define FM_TYPE_ADLIB 0x00
-#define FM_TYPE_OPL3 0x01
-#define MIDI_TYPE_MPU401 0x401
-
-#define SAMPLE_TYPE_BASIC 0x10
-#define SAMPLE_TYPE_GUS SAMPLE_TYPE_BASIC
-#define SAMPLE_TYPE_WAVEFRONT 0x11
-
- int perc_mode; /* No longer supported */
- int nr_voices;
- int nr_drums; /* Obsolete field */
- int instr_bank_size;
- unsigned int capabilities;
-#define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */
-#define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */
-#define SYNTH_CAP_INPUT 0x00000004 /* Input (MIDI) device */
- int dummies[19]; /* Reserve space */
- };
-
-struct sound_timer_info {
- char name[32];
- int caps;
- };
-
-#define MIDI_CAP_MPU401 1 /* MPU-401 intelligent mode */
-
-struct midi_info {
- char name[30];
- int device; /* 0-N. INITIALIZE BEFORE CALLING */
- unsigned int capabilities; /* To be defined later */
- int dev_type;
- int dummies[18]; /* Reserve space */
- };
-
-/********************************************
- * ioctl commands for the /dev/midi##
- */
-typedef struct {
- unsigned char cmd;
- char nr_args, nr_returns;
- unsigned char data[30];
- } mpu_command_rec;
-
-#define SNDCTL_MIDI_PRETIME _SIOWR('m', 0, int)
-#define SNDCTL_MIDI_MPUMODE _SIOWR('m', 1, int)
-#define SNDCTL_MIDI_MPUCMD _SIOWR('m', 2, mpu_command_rec)
-
-/********************************************
- * IOCTL commands for /dev/dsp and /dev/audio
- */
-
-#define SNDCTL_DSP_RESET _SIO ('P', 0)
-#define SNDCTL_DSP_SYNC _SIO ('P', 1)
-#define SNDCTL_DSP_SPEED _SIOWR('P', 2, int)
-#define SNDCTL_DSP_STEREO _SIOWR('P', 3, int)
-#define SNDCTL_DSP_GETBLKSIZE _SIOWR('P', 4, int)
-#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT
-#define SNDCTL_DSP_CHANNELS _SIOWR('P', 6, int)
-#define SOUND_PCM_WRITE_CHANNELS SNDCTL_DSP_CHANNELS
-#define SOUND_PCM_WRITE_FILTER _SIOWR('P', 7, int)
-#define SNDCTL_DSP_POST _SIO ('P', 8)
-#define SNDCTL_DSP_SUBDIVIDE _SIOWR('P', 9, int)
-#define SNDCTL_DSP_SETFRAGMENT _SIOWR('P',10, int)
-
-/* Audio data formats (Note! U8=8 and S16_LE=16 for compatibility) */
-#define SNDCTL_DSP_GETFMTS _SIOR ('P',11, int) /* Returns a mask */
-#define SNDCTL_DSP_SETFMT _SIOWR('P',5, int) /* Selects ONE fmt*/
-# define AFMT_QUERY 0x00000000 /* Return current fmt */
-# define AFMT_MU_LAW 0x00000001
-# define AFMT_A_LAW 0x00000002
-# define AFMT_IMA_ADPCM 0x00000004
-# define AFMT_U8 0x00000008
-# define AFMT_S16_LE 0x00000010 /* Little endian signed 16*/
-# define AFMT_S16_BE 0x00000020 /* Big endian signed 16 */
-# define AFMT_S8 0x00000040
-# define AFMT_U16_LE 0x00000080 /* Little endian U16 */
-# define AFMT_U16_BE 0x00000100 /* Big endian U16 */
-# define AFMT_MPEG 0x00000200 /* MPEG (2) audio */
-# define AFMT_AC3 0x00000400 /* Dolby Digital AC3 */
-
-/*
- * Buffer status queries.
- */
-typedef struct audio_buf_info {
- int fragments; /* # of available fragments (partially usend ones not counted) */
- int fragstotal; /* Total # of fragments allocated */
- int fragsize; /* Size of a fragment in bytes */
-
- int bytes; /* Available space in bytes (includes partially used fragments) */
- /* Note! 'bytes' could be more than fragments*fragsize */
- } audio_buf_info;
-
-#define SNDCTL_DSP_GETOSPACE _SIOR ('P',12, audio_buf_info)
-#define SNDCTL_DSP_GETISPACE _SIOR ('P',13, audio_buf_info)
-#define SNDCTL_DSP_NONBLOCK _SIO ('P',14)
-#define SNDCTL_DSP_GETCAPS _SIOR ('P',15, int)
-# define DSP_CAP_REVISION 0x000000ff /* Bits for revision level (0 to 255) */
-# define DSP_CAP_DUPLEX 0x00000100 /* Full duplex record/playback */
-# define DSP_CAP_REALTIME 0x00000200 /* Real time capability */
-# define DSP_CAP_BATCH 0x00000400 /* Device has some kind of */
- /* internal buffers which may */
- /* cause some delays and */
- /* decrease precision of timing */
-# define DSP_CAP_COPROC 0x00000800 /* Has a coprocessor */
- /* Sometimes it's a DSP */
- /* but usually not */
-# define DSP_CAP_TRIGGER 0x00001000 /* Supports SETTRIGGER */
-# define DSP_CAP_MMAP 0x00002000 /* Supports mmap() */
-# define DSP_CAP_MULTI 0x00004000 /* support multiple open */
-# define DSP_CAP_BIND 0x00008000 /* channel binding to front/rear/cneter/lfe */
-
-
-#define SNDCTL_DSP_GETTRIGGER _SIOR ('P',16, int)
-#define SNDCTL_DSP_SETTRIGGER _SIOW ('P',16, int)
-# define PCM_ENABLE_INPUT 0x00000001
-# define PCM_ENABLE_OUTPUT 0x00000002
-
-typedef struct count_info {
- int bytes; /* Total # of bytes processed */
- int blocks; /* # of fragment transitions since last time */
- int ptr; /* Current DMA pointer value */
- } count_info;
-
-#define SNDCTL_DSP_GETIPTR _SIOR ('P',17, count_info)
-#define SNDCTL_DSP_GETOPTR _SIOR ('P',18, count_info)
-
-typedef struct buffmem_desc {
- unsigned *buffer;
- int size;
- } buffmem_desc;
-#define SNDCTL_DSP_MAPINBUF _SIOR ('P', 19, buffmem_desc)
-#define SNDCTL_DSP_MAPOUTBUF _SIOR ('P', 20, buffmem_desc)
-#define SNDCTL_DSP_SETSYNCRO _SIO ('P', 21)
-#define SNDCTL_DSP_SETDUPLEX _SIO ('P', 22)
-#define SNDCTL_DSP_GETODELAY _SIOR ('P', 23, int)
-
-#define SNDCTL_DSP_GETCHANNELMASK _SIOWR('P', 64, int)
-#define SNDCTL_DSP_BIND_CHANNEL _SIOWR('P', 65, int)
-# define DSP_BIND_QUERY 0x00000000
-# define DSP_BIND_FRONT 0x00000001
-# define DSP_BIND_SURR 0x00000002
-# define DSP_BIND_CENTER_LFE 0x00000004
-# define DSP_BIND_HANDSET 0x00000008
-# define DSP_BIND_MIC 0x00000010
-# define DSP_BIND_MODEM1 0x00000020
-# define DSP_BIND_MODEM2 0x00000040
-# define DSP_BIND_I2S 0x00000080
-# define DSP_BIND_SPDIF 0x00000100
-
-#define SNDCTL_DSP_SETSPDIF _SIOW ('P', 66, int)
-#define SNDCTL_DSP_GETSPDIF _SIOR ('P', 67, int)
-# define SPDIF_PRO 0x0001
-# define SPDIF_N_AUD 0x0002
-# define SPDIF_COPY 0x0004
-# define SPDIF_PRE 0x0008
-# define SPDIF_CC 0x07f0
-# define SPDIF_L 0x0800
-# define SPDIF_DRS 0x4000
-# define SPDIF_V 0x8000
-
-/*
- * Application's profile defines the way how playback underrun situations should be handled.
- *
- * APF_NORMAL (the default) and APF_NETWORK make the driver to cleanup the
- * playback buffer whenever an underrun occurs. This consumes some time
- * prevents looping the existing buffer.
- * APF_CPUINTENS is intended to be set by CPU intensive applications which
- * are likely to run out of time occasionally. In this mode the buffer cleanup is
- * disabled which saves CPU time but also let's the previous buffer content to
- * be played during the "pause" after the underrun.
- */
-#define SNDCTL_DSP_PROFILE _SIOW ('P', 23, int)
-#define APF_NORMAL 0 /* Normal applications */
-#define APF_NETWORK 1 /* Underruns probably caused by an "external" delay */
-#define APF_CPUINTENS 2 /* Underruns probably caused by "overheating" the CPU */
-
-#define SOUND_PCM_READ_RATE _SIOR ('P', 2, int)
-#define SOUND_PCM_READ_CHANNELS _SIOR ('P', 6, int)
-#define SOUND_PCM_READ_BITS _SIOR ('P', 5, int)
-#define SOUND_PCM_READ_FILTER _SIOR ('P', 7, int)
-
-/* Some alias names */
-#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SETFMT
-#define SOUND_PCM_WRITE_RATE SNDCTL_DSP_SPEED
-#define SOUND_PCM_POST SNDCTL_DSP_POST
-#define SOUND_PCM_RESET SNDCTL_DSP_RESET
-#define SOUND_PCM_SYNC SNDCTL_DSP_SYNC
-#define SOUND_PCM_SUBDIVIDE SNDCTL_DSP_SUBDIVIDE
-#define SOUND_PCM_SETFRAGMENT SNDCTL_DSP_SETFRAGMENT
-#define SOUND_PCM_GETFMTS SNDCTL_DSP_GETFMTS
-#define SOUND_PCM_SETFMT SNDCTL_DSP_SETFMT
-#define SOUND_PCM_GETOSPACE SNDCTL_DSP_GETOSPACE
-#define SOUND_PCM_GETISPACE SNDCTL_DSP_GETISPACE
-#define SOUND_PCM_NONBLOCK SNDCTL_DSP_NONBLOCK
-#define SOUND_PCM_GETCAPS SNDCTL_DSP_GETCAPS
-#define SOUND_PCM_GETTRIGGER SNDCTL_DSP_GETTRIGGER
-#define SOUND_PCM_SETTRIGGER SNDCTL_DSP_SETTRIGGER
-#define SOUND_PCM_SETSYNCRO SNDCTL_DSP_SETSYNCRO
-#define SOUND_PCM_GETIPTR SNDCTL_DSP_GETIPTR
-#define SOUND_PCM_GETOPTR SNDCTL_DSP_GETOPTR
-#define SOUND_PCM_MAPINBUF SNDCTL_DSP_MAPINBUF
-#define SOUND_PCM_MAPOUTBUF SNDCTL_DSP_MAPOUTBUF
-
-/*
- * ioctl calls to be used in communication with coprocessors and
- * DSP chips.
- */
-
-typedef struct copr_buffer {
- int command; /* Set to 0 if not used */
- int flags;
-#define CPF_NONE 0x0000
-#define CPF_FIRST 0x0001 /* First block */
-#define CPF_LAST 0x0002 /* Last block */
- int len;
- int offs; /* If required by the device (0 if not used) */
-
- unsigned char data[4000]; /* NOTE! 4000 is not 4k */
- } copr_buffer;
-
-typedef struct copr_debug_buf {
- int command; /* Used internally. Set to 0 */
- int parm1;
- int parm2;
- int flags;
- int len; /* Length of data in bytes */
- } copr_debug_buf;
-
-typedef struct copr_msg {
- int len;
- unsigned char data[4000];
- } copr_msg;
-
-#define SNDCTL_COPR_RESET _SIO ('C', 0)
-#define SNDCTL_COPR_LOAD _SIOWR('C', 1, copr_buffer)
-#define SNDCTL_COPR_RDATA _SIOWR('C', 2, copr_debug_buf)
-#define SNDCTL_COPR_RCODE _SIOWR('C', 3, copr_debug_buf)
-#define SNDCTL_COPR_WDATA _SIOW ('C', 4, copr_debug_buf)
-#define SNDCTL_COPR_WCODE _SIOW ('C', 5, copr_debug_buf)
-#define SNDCTL_COPR_RUN _SIOWR('C', 6, copr_debug_buf)
-#define SNDCTL_COPR_HALT _SIOWR('C', 7, copr_debug_buf)
-#define SNDCTL_COPR_SENDMSG _SIOWR('C', 8, copr_msg)
-#define SNDCTL_COPR_RCVMSG _SIOR ('C', 9, copr_msg)
-
-/*********************************************
- * IOCTL commands for /dev/mixer
- */
-
-/*
- * Mixer devices
- *
- * There can be up to 20 different analog mixer channels. The
- * SOUND_MIXER_NRDEVICES gives the currently supported maximum.
- * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells
- * the devices supported by the particular mixer.
- */
-
-#define SOUND_MIXER_NRDEVICES 25
-#define SOUND_MIXER_VOLUME 0
-#define SOUND_MIXER_BASS 1
-#define SOUND_MIXER_TREBLE 2
-#define SOUND_MIXER_SYNTH 3
-#define SOUND_MIXER_PCM 4
-#define SOUND_MIXER_SPEAKER 5
-#define SOUND_MIXER_LINE 6
-#define SOUND_MIXER_MIC 7
-#define SOUND_MIXER_CD 8
-#define SOUND_MIXER_IMIX 9 /* Recording monitor */
-#define SOUND_MIXER_ALTPCM 10
-#define SOUND_MIXER_RECLEV 11 /* Recording level */
-#define SOUND_MIXER_IGAIN 12 /* Input gain */
-#define SOUND_MIXER_OGAIN 13 /* Output gain */
-/*
- * The AD1848 codec and compatibles have three line level inputs
- * (line, aux1 and aux2). Since each card manufacturer have assigned
- * different meanings to these inputs, it's impractical to assign
- * specific meanings (line, cd, synth etc.) to them.
- */
-#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */
-#define SOUND_MIXER_LINE2 15 /* Input source 2 (aux2) */
-#define SOUND_MIXER_LINE3 16 /* Input source 3 (line) */
-#define SOUND_MIXER_DIGITAL1 17 /* Digital (input) 1 */
-#define SOUND_MIXER_DIGITAL2 18 /* Digital (input) 2 */
-#define SOUND_MIXER_DIGITAL3 19 /* Digital (input) 3 */
-#define SOUND_MIXER_PHONEIN 20 /* Phone input */
-#define SOUND_MIXER_PHONEOUT 21 /* Phone output */
-#define SOUND_MIXER_VIDEO 22 /* Video/TV (audio) in */
-#define SOUND_MIXER_RADIO 23 /* Radio in */
-#define SOUND_MIXER_MONITOR 24 /* Monitor (usually mic) volume */
-
-/* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */
-/* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */
-#define SOUND_ONOFF_MIN 28
-#define SOUND_ONOFF_MAX 30
-
-/* Note! Number 31 cannot be used since the sign bit is reserved */
-#define SOUND_MIXER_NONE 31
-
-/*
- * The following unsupported macros are no longer functional.
- * Use SOUND_MIXER_PRIVATE# macros in future.
- */
-#define SOUND_MIXER_ENHANCE SOUND_MIXER_NONE
-#define SOUND_MIXER_MUTE SOUND_MIXER_NONE
-#define SOUND_MIXER_LOUD SOUND_MIXER_NONE
-
-
-#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
- "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \
- "Line1", "Line2", "Line3", "Digital1", "Digital2", "Digital3", \
- "PhoneIn", "PhoneOut", "Video", "Radio", "Monitor"}
-
-#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
- "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
- "line1", "line2", "line3", "dig1", "dig2", "dig3", \
- "phin", "phout", "video", "radio", "monitor"}
-
-/* Device bitmask identifiers */
-
-#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */
-#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */
-#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */
-#define SOUND_MIXER_CAPS 0xfc
-# define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */
-#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
-#define SOUND_MIXER_OUTSRC 0xfa /* Arg contains a bit for each input source to output */
-#define SOUND_MIXER_OUTMASK 0xf9 /* Arg contains a bit for each supported input source to output */
-
-/* Device mask bits */
-
-#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME)
-#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS)
-#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE)
-#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH)
-#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM)
-#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER)
-#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE)
-#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC)
-#define SOUND_MASK_CD (1 << SOUND_MIXER_CD)
-#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX)
-#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM)
-#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV)
-#define SOUND_MASK_IGAIN (1 << SOUND_MIXER_IGAIN)
-#define SOUND_MASK_OGAIN (1 << SOUND_MIXER_OGAIN)
-#define SOUND_MASK_LINE1 (1 << SOUND_MIXER_LINE1)
-#define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2)
-#define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3)
-#define SOUND_MASK_DIGITAL1 (1 << SOUND_MIXER_DIGITAL1)
-#define SOUND_MASK_DIGITAL2 (1 << SOUND_MIXER_DIGITAL2)
-#define SOUND_MASK_DIGITAL3 (1 << SOUND_MIXER_DIGITAL3)
-#define SOUND_MASK_PHONEIN (1 << SOUND_MIXER_PHONEIN)
-#define SOUND_MASK_PHONEOUT (1 << SOUND_MIXER_PHONEOUT)
-#define SOUND_MASK_RADIO (1 << SOUND_MIXER_RADIO)
-#define SOUND_MASK_VIDEO (1 << SOUND_MIXER_VIDEO)
-#define SOUND_MASK_MONITOR (1 << SOUND_MIXER_MONITOR)
-
-/* Obsolete macros */
-#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE)
-#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE)
-#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD)
-
-#define MIXER_READ(dev) _SIOR('M', dev, int)
-#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME)
-#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS)
-#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE)
-#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH)
-#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM)
-#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER)
-#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE)
-#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC)
-#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD)
-#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX)
-#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM)
-#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV)
-#define SOUND_MIXER_READ_IGAIN MIXER_READ(SOUND_MIXER_IGAIN)
-#define SOUND_MIXER_READ_OGAIN MIXER_READ(SOUND_MIXER_OGAIN)
-#define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1)
-#define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2)
-#define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3)
-
-/* Obsolete macros */
-#define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE)
-#define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE)
-#define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD)
-
-#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC)
-#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK)
-#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK)
-#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS)
-#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS)
-
-#define MIXER_WRITE(dev) _SIOWR('M', dev, int)
-#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME)
-#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS)
-#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE)
-#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH)
-#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM)
-#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER)
-#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE)
-#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC)
-#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD)
-#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX)
-#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM)
-#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV)
-#define SOUND_MIXER_WRITE_IGAIN MIXER_WRITE(SOUND_MIXER_IGAIN)
-#define SOUND_MIXER_WRITE_OGAIN MIXER_WRITE(SOUND_MIXER_OGAIN)
-#define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1)
-#define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2)
-#define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3)
-
-/* Obsolete macros */
-#define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE)
-#define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE)
-#define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD)
-
-#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC)
-
-typedef struct mixer_info
-{
- char id[16];
- char name[32];
- int modify_counter;
- int fillers[10];
-} mixer_info;
-
-typedef struct _old_mixer_info /* Obsolete */
-{
- char id[16];
- char name[32];
-} _old_mixer_info;
-
-#define SOUND_MIXER_INFO _SIOR ('M', 101, mixer_info)
-#define SOUND_OLD_MIXER_INFO _SIOR ('M', 101, _old_mixer_info)
-
-/*
- * A mechanism for accessing "proprietary" mixer features. This method
- * permits passing 128 bytes of arbitrary data between a mixer application
- * and the mixer driver. Interpretation of the record is defined by
- * the particular mixer driver.
- */
-typedef unsigned char mixer_record[128];
-
-#define SOUND_MIXER_ACCESS _SIOWR('M', 102, mixer_record)
-
-/*
- * Two ioctls for special soundcard function
- */
-#define SOUND_MIXER_AGC _SIOWR('M', 103, int)
-#define SOUND_MIXER_3DSE _SIOWR('M', 104, int)
-
-/*
- * The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers.
- * These features can be used when accessing device specific features.
- */
-#define SOUND_MIXER_PRIVATE1 _SIOWR('M', 111, int)
-#define SOUND_MIXER_PRIVATE2 _SIOWR('M', 112, int)
-#define SOUND_MIXER_PRIVATE3 _SIOWR('M', 113, int)
-#define SOUND_MIXER_PRIVATE4 _SIOWR('M', 114, int)
-#define SOUND_MIXER_PRIVATE5 _SIOWR('M', 115, int)
-
-/*
- * SOUND_MIXER_GETLEVELS and SOUND_MIXER_SETLEVELS calls can be used
- * for querying current mixer settings from the driver and for loading
- * default volume settings _prior_ activating the mixer (loading
- * doesn't affect current state of the mixer hardware). These calls
- * are for internal use only.
- */
-
-typedef struct mixer_vol_table {
- int num; /* Index to volume table */
- char name[32];
- int levels[32];
-} mixer_vol_table;
-
-#define SOUND_MIXER_GETLEVELS _SIOWR('M', 116, mixer_vol_table)
-#define SOUND_MIXER_SETLEVELS _SIOWR('M', 117, mixer_vol_table)
-
-/*
- * An ioctl for identifying the driver version. It will return value
- * of the SOUND_VERSION macro used when compiling the driver.
- * This call was introduced in OSS version 3.6 and it will not work
- * with earlier versions (returns EINVAL).
- */
-#define OSS_GETVERSION _SIOR ('M', 118, int)
-
-/*
- * Level 2 event types for /dev/sequencer
- */
-
-/*
- * The 4 most significant bits of byte 0 specify the class of
- * the event:
- *
- * 0x8X = system level events,
- * 0x9X = device/port specific events, event[1] = device/port,
- * The last 4 bits give the subtype:
- * 0x02 = Channel event (event[3] = chn).
- * 0x01 = note event (event[4] = note).
- * (0x01 is not used alone but always with bit 0x02).
- * event[2] = MIDI message code (0x80=note off etc.)
- *
- */
-
-#define EV_SEQ_LOCAL 0x80
-#define EV_TIMING 0x81
-#define EV_CHN_COMMON 0x92
-#define EV_CHN_VOICE 0x93
-#define EV_SYSEX 0x94
-/*
- * Event types 200 to 220 are reserved for application use.
- * These numbers will not be used by the driver.
- */
-
-/*
- * Events for event type EV_CHN_VOICE
- */
-
-#define MIDI_NOTEOFF 0x80
-#define MIDI_NOTEON 0x90
-#define MIDI_KEY_PRESSURE 0xA0
-
-/*
- * Events for event type EV_CHN_COMMON
- */
-
-#define MIDI_CTL_CHANGE 0xB0
-#define MIDI_PGM_CHANGE 0xC0
-#define MIDI_CHN_PRESSURE 0xD0
-#define MIDI_PITCH_BEND 0xE0
-
-#define MIDI_SYSTEM_PREFIX 0xF0
-
-/*
- * Timer event types
- */
-#define TMR_WAIT_REL 1 /* Time relative to the prev time */
-#define TMR_WAIT_ABS 2 /* Absolute time since TMR_START */
-#define TMR_STOP 3
-#define TMR_START 4
-#define TMR_CONTINUE 5
-#define TMR_TEMPO 6
-#define TMR_ECHO 8
-#define TMR_CLOCK 9 /* MIDI clock */
-#define TMR_SPP 10 /* Song position pointer */
-#define TMR_TIMESIG 11 /* Time signature */
-
-/*
- * Local event types
- */
-#define LOCL_STARTAUDIO 1
-
-#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS)
-/*
- * Some convenience macros to simplify programming of the
- * /dev/sequencer interface
- *
- * These macros define the API which should be used when possible.
- */
-#define SEQ_DECLAREBUF() SEQ_USE_EXTBUF()
-
-void seqbuf_dump(void); /* This function must be provided by programs */
-
-extern int OSS_init(int seqfd, int buflen);
-extern void OSS_seqbuf_dump(int fd, unsigned char *buf, int buflen);
-extern void OSS_seq_advbuf(int len, int fd, unsigned char *buf, int buflen);
-extern void OSS_seq_needbuf(int len, int fd, unsigned char *buf, int buflen);
-extern void OSS_patch_caching(int dev, int chn, int patch,
- int fd, unsigned char *buf, int buflen);
-extern void OSS_drum_caching(int dev, int chn, int patch,
- int fd, unsigned char *buf, int buflen);
-extern void OSS_write_patch(int fd, unsigned char *buf, int len);
-extern int OSS_write_patch2(int fd, unsigned char *buf, int len);
-
-#define SEQ_PM_DEFINES int __foo_bar___
-#ifdef OSSLIB
-# define SEQ_USE_EXTBUF() \
- extern unsigned char *_seqbuf; \
- extern int _seqbuflen;extern int _seqbufptr
-# define SEQ_DEFINEBUF(len) SEQ_USE_EXTBUF();static int _requested_seqbuflen=len
-# define _SEQ_ADVBUF(len) OSS_seq_advbuf(len, seqfd, _seqbuf, _seqbuflen)
-# define _SEQ_NEEDBUF(len) OSS_seq_needbuf(len, seqfd, _seqbuf, _seqbuflen)
-# define SEQ_DUMPBUF() OSS_seqbuf_dump(seqfd, _seqbuf, _seqbuflen)
-
-# define SEQ_LOAD_GMINSTR(dev, instr) \
- OSS_patch_caching(dev, -1, instr, seqfd, _seqbuf, _seqbuflen)
-# define SEQ_LOAD_GMDRUM(dev, drum) \
- OSS_drum_caching(dev, -1, drum, seqfd, _seqbuf, _seqbuflen)
-#else /* !OSSLIB */
-
-# define SEQ_LOAD_GMINSTR(dev, instr)
-# define SEQ_LOAD_GMDRUM(dev, drum)
-
-# define SEQ_USE_EXTBUF() \
- extern unsigned char _seqbuf[]; \
- extern int _seqbuflen;extern int _seqbufptr
-
-#ifndef USE_SIMPLE_MACROS
-/* Sample seqbuf_dump() implementation:
- *
- * SEQ_DEFINEBUF (2048); -- Defines a buffer for 2048 bytes
- *
- * int seqfd; -- The file descriptor for /dev/sequencer.
- *
- * void
- * seqbuf_dump ()
- * {
- * if (_seqbufptr)
- * if (write (seqfd, _seqbuf, _seqbufptr) == -1)
- * {
- * perror ("write /dev/sequencer");
- * exit (-1);
- * }
- * _seqbufptr = 0;
- * }
- */
-
-#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0
-#define _SEQ_NEEDBUF(len) if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump()
-#define _SEQ_ADVBUF(len) _seqbufptr += len
-#define SEQ_DUMPBUF seqbuf_dump
-#else
-/*
- * This variation of the sequencer macros is used just to format one event
- * using fixed buffer.
- *
- * The program using the macro library must define the following macros before
- * using this library.
- *
- * #define _seqbuf name of the buffer (unsigned char[])
- * #define _SEQ_ADVBUF(len) If the applic needs to know the exact
- * size of the event, this macro can be used.
- * Otherwise this must be defined as empty.
- * #define _seqbufptr Define the name of index variable or 0 if
- * not required.
- */
-#define _SEQ_NEEDBUF(len) /* empty */
-#endif
-#endif /* !OSSLIB */
-
-#define SEQ_VOLUME_MODE(dev, mode) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
- _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
- _seqbuf[_seqbufptr+2] = (dev);\
- _seqbuf[_seqbufptr+3] = (mode);\
- _seqbuf[_seqbufptr+4] = 0;\
- _seqbuf[_seqbufptr+5] = 0;\
- _seqbuf[_seqbufptr+6] = 0;\
- _seqbuf[_seqbufptr+7] = 0;\
- _SEQ_ADVBUF(8);}
-
-/*
- * Midi voice messages
- */
-
-#define _CHN_VOICE(dev, event, chn, note, parm) \
- {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = EV_CHN_VOICE;\
- _seqbuf[_seqbufptr+1] = (dev);\
- _seqbuf[_seqbufptr+2] = (event);\
- _seqbuf[_seqbufptr+3] = (chn);\
- _seqbuf[_seqbufptr+4] = (note);\
- _seqbuf[_seqbufptr+5] = (parm);\
- _seqbuf[_seqbufptr+6] = (0);\
- _seqbuf[_seqbufptr+7] = 0;\
- _SEQ_ADVBUF(8);}
-
-#define SEQ_START_NOTE(dev, chn, note, vol) \
- _CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol)
-
-#define SEQ_STOP_NOTE(dev, chn, note, vol) \
- _CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol)
-
-#define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \
- _CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure)
-
-/*
- * Midi channel messages
- */
-
-#define _CHN_COMMON(dev, event, chn, p1, p2, w14) \
- {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = EV_CHN_COMMON;\
- _seqbuf[_seqbufptr+1] = (dev);\
- _seqbuf[_seqbufptr+2] = (event);\
- _seqbuf[_seqbufptr+3] = (chn);\
- _seqbuf[_seqbufptr+4] = (p1);\
- _seqbuf[_seqbufptr+5] = (p2);\
- *(short *)&_seqbuf[_seqbufptr+6] = (w14);\
- _SEQ_ADVBUF(8);}
-/*
- * SEQ_SYSEX permits sending of sysex messages. (It may look that it permits
- * sending any MIDI bytes but it's absolutely not possible. Trying to do
- * so _will_ cause problems with MPU401 intelligent mode).
- *
- * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be
- * sent by calling SEQ_SYSEX() several times (there must be no other events
- * between them). First sysex fragment must have 0xf0 in the first byte
- * and the last byte (buf[len-1] of the last fragment must be 0xf7. No byte
- * between these sysex start and end markers cannot be larger than 0x7f. Also
- * lengths of each fragments (except the last one) must be 6.
- *
- * Breaking the above rules may work with some MIDI ports but is likely to
- * cause fatal problems with some other devices (such as MPU401).
- */
-#define SEQ_SYSEX(dev, buf, len) \
- {int ii, ll=(len); \
- unsigned char *bufp=buf;\
- if (ll>6)ll=6;\
- _SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = EV_SYSEX;\
- _seqbuf[_seqbufptr+1] = (dev);\
- for(ii=0;ii<ll;ii++)\
- _seqbuf[_seqbufptr+ii+2] = bufp[ii];\
- for(ii=ll;ii<6;ii++)\
- _seqbuf[_seqbufptr+ii+2] = 0xff;\
- _SEQ_ADVBUF(8);}
-
-#define SEQ_CHN_PRESSURE(dev, chn, pressure) \
- _CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0)
-
-#define SEQ_SET_PATCH SEQ_PGM_CHANGE
-#ifdef OSSLIB
-# define SEQ_PGM_CHANGE(dev, chn, patch) \
- {OSS_patch_caching(dev, chn, patch, seqfd, _seqbuf, _seqbuflen); \
- _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0);}
-#else
-# define SEQ_PGM_CHANGE(dev, chn, patch) \
- _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0)
-#endif
-
-#define SEQ_CONTROL(dev, chn, controller, value) \
- _CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value)
-
-#define SEQ_BENDER(dev, chn, value) \
- _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value)
-
-
-#define SEQ_V2_X_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
- _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
- _seqbuf[_seqbufptr+2] = (dev);\
- _seqbuf[_seqbufptr+3] = (voice);\
- _seqbuf[_seqbufptr+4] = (controller);\
- _seqbuf[_seqbufptr+5] = ((value)&0xff);\
- _seqbuf[_seqbufptr+6] = ((value>>8)&0xff);\
- _seqbuf[_seqbufptr+7] = 0;\
- _SEQ_ADVBUF(8);}
-/*
- * The following 5 macros are incorrectly implemented and obsolete.
- * Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead.
- */
-#define SEQ_PITCHBEND(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
-#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
-#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128)
-#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100)
-#define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
-
-/*
- * Timing and synchronization macros
- */
-
-#define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr+0] = EV_TIMING; \
- _seqbuf[_seqbufptr+1] = (ev); \
- _seqbuf[_seqbufptr+2] = 0;\
- _seqbuf[_seqbufptr+3] = 0;\
- *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
- _SEQ_ADVBUF(8);}
-
-#define SEQ_START_TIMER() _TIMER_EVENT(TMR_START, 0)
-#define SEQ_STOP_TIMER() _TIMER_EVENT(TMR_STOP, 0)
-#define SEQ_CONTINUE_TIMER() _TIMER_EVENT(TMR_CONTINUE, 0)
-#define SEQ_WAIT_TIME(ticks) _TIMER_EVENT(TMR_WAIT_ABS, ticks)
-#define SEQ_DELTA_TIME(ticks) _TIMER_EVENT(TMR_WAIT_REL, ticks)
-#define SEQ_ECHO_BACK(key) _TIMER_EVENT(TMR_ECHO, key)
-#define SEQ_SET_TEMPO(value) _TIMER_EVENT(TMR_TEMPO, value)
-#define SEQ_SONGPOS(pos) _TIMER_EVENT(TMR_SPP, pos)
-#define SEQ_TIME_SIGNATURE(sig) _TIMER_EVENT(TMR_TIMESIG, sig)
-
-/*
- * Local control events
- */
-
-#define _LOCAL_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr+0] = EV_SEQ_LOCAL; \
- _seqbuf[_seqbufptr+1] = (ev); \
- _seqbuf[_seqbufptr+2] = 0;\
- _seqbuf[_seqbufptr+3] = 0;\
- *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
- _SEQ_ADVBUF(8);}
-
-#define SEQ_PLAYAUDIO(devmask) _LOCAL_EVENT(LOCL_STARTAUDIO, devmask)
-/*
- * Events for the level 1 interface only
- */
-
-#define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\
- _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
- _seqbuf[_seqbufptr+1] = (byte);\
- _seqbuf[_seqbufptr+2] = (device);\
- _seqbuf[_seqbufptr+3] = 0;\
- _SEQ_ADVBUF(4);}
-
-/*
- * Patch loading.
- */
-#ifdef OSSLIB
-# define SEQ_WRPATCH(patchx, len) \
- OSS_write_patch(seqfd, (char*)(patchx), len)
-# define SEQ_WRPATCH2(patchx, len) \
- OSS_write_patch2(seqfd, (char*)(patchx), len)
-#else
-# define SEQ_WRPATCH(patchx, len) \
- {if (_seqbufptr) SEQ_DUMPBUF();\
- if (write(seqfd, (char*)(patchx), len)==-1) \
- perror("Write patch: /dev/sequencer");}
-# define SEQ_WRPATCH2(patchx, len) \
- (SEQ_DUMPBUF(), write(seqfd, (char*)(patchx), len))
-#endif
-
-#endif
-#endif
diff --git a/src/VBox/Runtime/testcase/tstDir-2.cpp b/src/VBox/Runtime/testcase/tstDir-2.cpp
index a8213cf5..aea861fe 100644
--- a/src/VBox/Runtime/testcase/tstDir-2.cpp
+++ b/src/VBox/Runtime/testcase/tstDir-2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstDir-3.cpp b/src/VBox/Runtime/testcase/tstDir-3.cpp
index 45aa691c..5b453d0b 100644
--- a/src/VBox/Runtime/testcase/tstDir-3.cpp
+++ b/src/VBox/Runtime/testcase/tstDir-3.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstDir.cpp b/src/VBox/Runtime/testcase/tstDir.cpp
index fe9907db..470414ef 100644
--- a/src/VBox/Runtime/testcase/tstDir.cpp
+++ b/src/VBox/Runtime/testcase/tstDir.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -39,8 +39,10 @@ int main(int argc, char **argv)
/*
* Iterate arguments.
*/
- bool fLong = false;
+ bool fLong = false;
bool fShortName = false;
+ bool fFiltered = false;
+ bool fQuiet = false;
for (int i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
@@ -55,6 +57,12 @@ int main(int argc, char **argv)
case 's':
fShortName = true;
break;
+ case 'f':
+ fFiltered = true;
+ break;
+ case 'q':
+ fQuiet = true;
+ break;
default:
RTPrintf("Unknown option '%c' ignored!\n", argv[i][j]);
break;
@@ -65,7 +73,11 @@ int main(int argc, char **argv)
{
/* open */
PRTDIR pDir;
- int rc = RTDirOpen(&pDir, argv[i]);
+ int rc;
+ if (!fFiltered)
+ rc = RTDirOpen(&pDir, argv[i]);
+ else
+ rc = RTDirOpenFiltered(&pDir, argv[i], RTDIRFILTER_WINNT, 0);
if (RT_SUCCESS(rc))
{
/* list */
@@ -77,24 +89,27 @@ int main(int argc, char **argv)
rc = RTDirRead(pDir, &DirEntry, NULL);
if (RT_FAILURE(rc))
break;
- switch (DirEntry.enmType)
+ if (!fQuiet)
{
- case RTDIRENTRYTYPE_UNKNOWN: RTPrintf("u"); break;
- case RTDIRENTRYTYPE_FIFO: RTPrintf("f"); break;
- case RTDIRENTRYTYPE_DEV_CHAR: RTPrintf("c"); break;
- case RTDIRENTRYTYPE_DIRECTORY: RTPrintf("d"); break;
- case RTDIRENTRYTYPE_DEV_BLOCK: RTPrintf("b"); break;
- case RTDIRENTRYTYPE_FILE: RTPrintf("-"); break;
- case RTDIRENTRYTYPE_SYMLINK: RTPrintf("l"); break;
- case RTDIRENTRYTYPE_SOCKET: RTPrintf("s"); break;
- case RTDIRENTRYTYPE_WHITEOUT: RTPrintf("w"); break;
- default:
- rcRet = 1;
- RTPrintf("?");
- break;
+ switch (DirEntry.enmType)
+ {
+ case RTDIRENTRYTYPE_UNKNOWN: RTPrintf("u"); break;
+ case RTDIRENTRYTYPE_FIFO: RTPrintf("f"); break;
+ case RTDIRENTRYTYPE_DEV_CHAR: RTPrintf("c"); break;
+ case RTDIRENTRYTYPE_DIRECTORY: RTPrintf("d"); break;
+ case RTDIRENTRYTYPE_DEV_BLOCK: RTPrintf("b"); break;
+ case RTDIRENTRYTYPE_FILE: RTPrintf("-"); break;
+ case RTDIRENTRYTYPE_SYMLINK: RTPrintf("l"); break;
+ case RTDIRENTRYTYPE_SOCKET: RTPrintf("s"); break;
+ case RTDIRENTRYTYPE_WHITEOUT: RTPrintf("w"); break;
+ default:
+ rcRet = 1;
+ RTPrintf("?");
+ break;
+ }
+ RTPrintf(" %#18llx %3d %s\n", (uint64_t)DirEntry.INodeId,
+ DirEntry.cbName, DirEntry.szName);
}
- RTPrintf(" %#18llx %3d %s\n", (uint64_t)DirEntry.INodeId,
- DirEntry.cbName, DirEntry.szName);
}
}
else
@@ -106,64 +121,66 @@ int main(int argc, char **argv)
if (RT_FAILURE(rc))
break;
- RTFMODE fMode = DirEntry.Info.Attr.fMode;
- switch (fMode & RTFS_TYPE_MASK)
+ if (!fQuiet)
{
- case RTFS_TYPE_FIFO: RTPrintf("f"); break;
- case RTFS_TYPE_DEV_CHAR: RTPrintf("c"); break;
- case RTFS_TYPE_DIRECTORY: RTPrintf("d"); break;
- case RTFS_TYPE_DEV_BLOCK: RTPrintf("b"); break;
- case RTFS_TYPE_FILE: RTPrintf("-"); break;
- case RTFS_TYPE_SYMLINK: RTPrintf("l"); break;
- case RTFS_TYPE_SOCKET: RTPrintf("s"); break;
- case RTFS_TYPE_WHITEOUT: RTPrintf("w"); break;
- default:
- rcRet = 1;
- RTPrintf("?");
- break;
- }
- /** @todo sticy bits++ */
- RTPrintf("%c%c%c",
- fMode & RTFS_UNIX_IRUSR ? 'r' : '-',
- fMode & RTFS_UNIX_IWUSR ? 'w' : '-',
- fMode & RTFS_UNIX_IXUSR ? 'x' : '-');
- RTPrintf("%c%c%c",
- fMode & RTFS_UNIX_IRGRP ? 'r' : '-',
- fMode & RTFS_UNIX_IWGRP ? 'w' : '-',
- fMode & RTFS_UNIX_IXGRP ? 'x' : '-');
- RTPrintf("%c%c%c",
- fMode & RTFS_UNIX_IROTH ? 'r' : '-',
- fMode & RTFS_UNIX_IWOTH ? 'w' : '-',
- fMode & RTFS_UNIX_IXOTH ? 'x' : '-');
- RTPrintf(" %c%c%c%c%c%c%c%c%c%c%c%c%c%c",
- fMode & RTFS_DOS_READONLY ? 'R' : '-',
- fMode & RTFS_DOS_HIDDEN ? 'H' : '-',
- fMode & RTFS_DOS_SYSTEM ? 'S' : '-',
- fMode & RTFS_DOS_DIRECTORY ? 'D' : '-',
- fMode & RTFS_DOS_ARCHIVED ? 'A' : '-',
- fMode & RTFS_DOS_NT_DEVICE ? 'd' : '-',
- fMode & RTFS_DOS_NT_NORMAL ? 'N' : '-',
- fMode & RTFS_DOS_NT_TEMPORARY ? 'T' : '-',
- fMode & RTFS_DOS_NT_SPARSE_FILE ? 'P' : '-',
- fMode & RTFS_DOS_NT_REPARSE_POINT ? 'J' : '-',
- fMode & RTFS_DOS_NT_COMPRESSED ? 'C' : '-',
- fMode & RTFS_DOS_NT_OFFLINE ? 'O' : '-',
- fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED ? 'I' : '-',
- fMode & RTFS_DOS_NT_ENCRYPTED ? 'E' : '-');
- RTPrintf(" %d %4d %4d %10lld %10lld %#llx %#llx %#llx %#llx",
- DirEntry.Info.Attr.u.Unix.cHardlinks,
- DirEntry.Info.Attr.u.Unix.uid,
- DirEntry.Info.Attr.u.Unix.gid,
- DirEntry.Info.cbObject,
- DirEntry.Info.cbAllocated,
- DirEntry.Info.BirthTime,
- DirEntry.Info.ChangeTime,
- DirEntry.Info.ModificationTime,
- DirEntry.Info.AccessTime);
- if (fShortName && DirEntry.cwcShortName)
- RTPrintf(" %2d %ls\n", DirEntry.cwcShortName, DirEntry.wszShortName);
- else
+ RTFMODE fMode = DirEntry.Info.Attr.fMode;
+ switch (fMode & RTFS_TYPE_MASK)
+ {
+ case RTFS_TYPE_FIFO: RTPrintf("f"); break;
+ case RTFS_TYPE_DEV_CHAR: RTPrintf("c"); break;
+ case RTFS_TYPE_DIRECTORY: RTPrintf("d"); break;
+ case RTFS_TYPE_DEV_BLOCK: RTPrintf("b"); break;
+ case RTFS_TYPE_FILE: RTPrintf("-"); break;
+ case RTFS_TYPE_SYMLINK: RTPrintf("l"); break;
+ case RTFS_TYPE_SOCKET: RTPrintf("s"); break;
+ case RTFS_TYPE_WHITEOUT: RTPrintf("w"); break;
+ default:
+ rcRet = 1;
+ RTPrintf("?");
+ break;
+ }
+ /** @todo sticy bits++ */
+ RTPrintf("%c%c%c",
+ fMode & RTFS_UNIX_IRUSR ? 'r' : '-',
+ fMode & RTFS_UNIX_IWUSR ? 'w' : '-',
+ fMode & RTFS_UNIX_IXUSR ? 'x' : '-');
+ RTPrintf("%c%c%c",
+ fMode & RTFS_UNIX_IRGRP ? 'r' : '-',
+ fMode & RTFS_UNIX_IWGRP ? 'w' : '-',
+ fMode & RTFS_UNIX_IXGRP ? 'x' : '-');
+ RTPrintf("%c%c%c",
+ fMode & RTFS_UNIX_IROTH ? 'r' : '-',
+ fMode & RTFS_UNIX_IWOTH ? 'w' : '-',
+ fMode & RTFS_UNIX_IXOTH ? 'x' : '-');
+ RTPrintf(" %c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ fMode & RTFS_DOS_READONLY ? 'R' : '-',
+ fMode & RTFS_DOS_HIDDEN ? 'H' : '-',
+ fMode & RTFS_DOS_SYSTEM ? 'S' : '-',
+ fMode & RTFS_DOS_DIRECTORY ? 'D' : '-',
+ fMode & RTFS_DOS_ARCHIVED ? 'A' : '-',
+ fMode & RTFS_DOS_NT_DEVICE ? 'd' : '-',
+ fMode & RTFS_DOS_NT_NORMAL ? 'N' : '-',
+ fMode & RTFS_DOS_NT_TEMPORARY ? 'T' : '-',
+ fMode & RTFS_DOS_NT_SPARSE_FILE ? 'P' : '-',
+ fMode & RTFS_DOS_NT_REPARSE_POINT ? 'J' : '-',
+ fMode & RTFS_DOS_NT_COMPRESSED ? 'C' : '-',
+ fMode & RTFS_DOS_NT_OFFLINE ? 'O' : '-',
+ fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED ? 'I' : '-',
+ fMode & RTFS_DOS_NT_ENCRYPTED ? 'E' : '-');
+ RTPrintf(" %d %4d %4d %10lld %10lld %#llx %#llx %#llx %#llx",
+ DirEntry.Info.Attr.u.Unix.cHardlinks,
+ DirEntry.Info.Attr.u.Unix.uid,
+ DirEntry.Info.Attr.u.Unix.gid,
+ DirEntry.Info.cbObject,
+ DirEntry.Info.cbAllocated,
+ DirEntry.Info.BirthTime,
+ DirEntry.Info.ChangeTime,
+ DirEntry.Info.ModificationTime,
+ DirEntry.Info.AccessTime);
+ if (fShortName)
+ RTPrintf(" %2d %-12ls ", DirEntry.cwcShortName, DirEntry.wszShortName);
RTPrintf(" %2d %s\n", DirEntry.cbName, DirEntry.szName);
+ }
if (rc != VINF_SUCCESS)
RTPrintf("^^ %Rrc\n", rc);
}
diff --git a/src/VBox/Runtime/testcase/tstEnv.cpp b/src/VBox/Runtime/testcase/tstEnv.cpp
index 6c7ea9f3..2ffa30d8 100644
--- a/src/VBox/Runtime/testcase/tstEnv.cpp
+++ b/src/VBox/Runtime/testcase/tstEnv.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstFile.cpp b/src/VBox/Runtime/testcase/tstFile.cpp
index f2f675d3..61d57a78 100644
--- a/src/VBox/Runtime/testcase/tstFile.cpp
+++ b/src/VBox/Runtime/testcase/tstFile.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstFileAppendWin-1.cpp b/src/VBox/Runtime/testcase/tstFileAppendWin-1.cpp
index 7ffd7fe1..25ab780e 100644
--- a/src/VBox/Runtime/testcase/tstFileAppendWin-1.cpp
+++ b/src/VBox/Runtime/testcase/tstFileAppendWin-1.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstFileLock.cpp b/src/VBox/Runtime/testcase/tstFileLock.cpp
index fc4c0bfc..63942450 100644
--- a/src/VBox/Runtime/testcase/tstFileLock.cpp
+++ b/src/VBox/Runtime/testcase/tstFileLock.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstFork.cpp b/src/VBox/Runtime/testcase/tstFork.cpp
index 8d511f7c..61ccb48f 100644
--- a/src/VBox/Runtime/testcase/tstFork.cpp
+++ b/src/VBox/Runtime/testcase/tstFork.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstHandleTable.cpp b/src/VBox/Runtime/testcase/tstHandleTable.cpp
index ab0dce0f..1759ca00 100644
--- a/src/VBox/Runtime/testcase/tstHandleTable.cpp
+++ b/src/VBox/Runtime/testcase/tstHandleTable.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -119,7 +119,7 @@ static int tstHandleTableTest1(uint32_t uBase, uint32_t cMax, uint32_t cDelta, u
RTPrintf(" c=%#x\n", c);
if (fCallbacks && cRetainerCalls != 0)
{
- RTPrintf("tstHandleTable: FAILURE (%d) - cRetainerCalls=%#x expected 0!\n", __LINE__, i, cRetainerCalls);
+ RTPrintf("tstHandleTable: FAILURE (%d) - cRetainerCalls=%#x expected 0!\n", __LINE__, cRetainerCalls);
g_cErrors++;
}
@@ -243,7 +243,7 @@ static int tstHandleTableTest1(uint32_t uBase, uint32_t cMax, uint32_t cDelta, u
&& RTHandleTableLookupWithCtx(hHT, hLookup, &i))
{
RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, j=%d, RTHandleTableLookupWithCtx: succeeded with bad context\n",
- __LINE__, i, j, pvObj, pvExpect);
+ __LINE__, i, j);
g_cErrors++;
}
}
@@ -487,7 +487,7 @@ int main(int argc, char **argv)
return 1;
case 'V':
- RTPrintf("$Revision: $\n");
+ RTPrintf("$Revision: 92648 $\n");
return 0;
default:
diff --git a/src/VBox/Runtime/testcase/tstIoCtl.cpp b/src/VBox/Runtime/testcase/tstIoCtl.cpp
deleted file mode 100644
index 31e901ef..00000000
--- a/src/VBox/Runtime/testcase/tstIoCtl.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/* $Id: tstIoCtl.cpp $ */
-/** @file
- * IPRT Testcase - file IoCtl.
- */
-
-/*
- * Copyright (C) 2006-2007 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-//#include <sys/types.h>
-#include "soundcard.h"
-//#include <VBox/pdm.h>
-#include <VBox/err.h>
-
-#include <iprt/log.h>
-#include <VBox/log.h>
-#define LOG_GROUP LOG_GROUP_DEV_AUDIO
-//#include <iprt/assert.h>
-//#include <iprt/uuid.h>
-//#include <iprt/string.h>
-//#include <iprt/alloc.h>
-#include <iprt/file.h>
-
-//#include "audio.h"
-//#include "audio_int.h"
-
-#include <stdio.h>
-#include <iprt/uuid.h>
-
-#ifdef RT_OS_L4
-extern char **__environ;
-char *myenv[] = { "+all.e", NULL };
-#endif
-
-int main()
-{
-#ifdef RT_OS_L4
- __environ = myenv;
-#endif
- int rcRet = 0;
- int ret, err;
- printf("tstIoCtl: TESTING\n");
-
- RTFILE File;
-
- err = RTFileOpen(&File, "/dev/dsp", RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK);
- if (RT_FAILURE(err)) {
- printf("Fatal error: failed to open /dev/dsp:\n"
- "VBox error code: %d\n", err);
- return 1;
- }
-
- int rate = 100;
-
- if (RT_FAILURE(err = RTFileIoCtl(File, SNDCTL_DSP_SPEED, &rate, sizeof(rate), &ret)) || ret) {
- printf("Failed to set playback speed on /dev/dsp\n"
- "VBox error code: %d, IOCTL return value: %d\n",
- err, ret);
- rcRet++;
- } else printf("Playback speed successfully set to 100, reported speed is %d\n",
- rate);
-
- rate = 48000;
-
- if (RT_FAILURE(err = RTFileIoCtl(File, SNDCTL_DSP_SPEED, &rate, sizeof(rate), &ret)) || ret) {
- printf("Failed to set playback speed on /dev/dsp\n"
- "VBox error code: %d, IOCTL return value: %d\n",
- err, ret);
- rcRet++;
- } else printf("Playback speed successfully set to 48000, reported speed is %d\n",
- rate);
-
- /*
- * Cleanup.
- */
- ret = RTFileClose(File);
- if (RT_FAILURE(ret))
- {
- printf("Failed to close /dev/dsp. ret=%d\n", ret);
- rcRet++;
- }
-
- /* Under Linux and L4, this involves ioctls internally */
- RTUUID TestUuid;
- if (RT_FAILURE(RTUuidCreate(&TestUuid)))
- {
- printf("Failed to create a UUID. ret=%d\n", ret);
- rcRet++;
- }
-
- /*
- * Summary
- */
- if (rcRet == 0)
- printf("tstIoCtl: SUCCESS\n");
- else
- printf("tstIoCtl: FAILURE - %d errors\n", rcRet);
- return rcRet;
-}
diff --git a/src/VBox/Runtime/testcase/tstIprtList.cpp b/src/VBox/Runtime/testcase/tstIprtList.cpp
index eb5785fc..283807d6 100644
--- a/src/VBox/Runtime/testcase/tstIprtList.cpp
+++ b/src/VBox/Runtime/testcase/tstIprtList.cpp
@@ -33,6 +33,7 @@
#include <iprt/test.h>
#include <iprt/rand.h>
#include <iprt/thread.h>
+#include <iprt/time.h>
/*******************************************************************************
@@ -165,7 +166,7 @@ static void test1(const char *pcszDesc, T3 paTestData[], size_t cTestItems)
/* Create a test list */
L<T1, T2> testList;
- const size_t defCap = L<T1, T2>::DefaultCapacity;
+ const size_t defCap = L<T1, T2>::kDefaultCapacity;
RTTESTI_CHECK(testList.isEmpty());
RTTESTI_CHECK(testList.size() == 0);
RTTESTI_CHECK(testList.capacity() == defCap);
@@ -375,13 +376,116 @@ static void test1(const char *pcszDesc, T3 paTestData[], size_t cTestItems)
RTTESTI_CHECK_RETV(testList5.size() == 0);
RTTESTI_CHECK(testList5.capacity() == 0);
+ /*
+ * Negative testing.
+ */
+ bool fMayPanic = RTAssertMayPanic();
+ bool fQuiet = RTAssertAreQuiet();
+ RTAssertSetMayPanic(false);
+ RTAssertSetQuiet(true);
+
+ L<T1, T2> testList6;
+ for (size_t i = 0; i < cTestItems; ++i)
+ testList6.insert(i, paTestData[i]);
+ RTTESTI_CHECK(testList6.size() == cTestItems);
+
+ /* Insertion beyond the end of the array ends up at the end. */
+ size_t cBefore = testList6.size();
+ testList6.insert(cBefore + 3, paTestData[0]);
+ RTTESTI_CHECK(testList6.size() == cBefore + 1);
+ RTTESTI_CHECK(testList6.at(cBefore) == paTestData[0]);
+
+ cBefore = testList6.size();
+ L<T1, T2> testList7(testList6);
+ testList6.insert(testList6.size() + 42, testList7);
+ RTTESTI_CHECK(testList6.size() == cBefore + testList7.size());
+
+ /* Inserting, appending or prepending a list to itself is not supported. */
+ cBefore = testList6.size();
+ testList6.insert(3, testList6);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ cBefore = testList6.size();
+ testList6.append(testList6);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ cBefore = testList6.size();
+ testList6.prepend(testList6);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ /* Replace does nothing if the index is bad. */
+ cBefore = testList6.size();
+ testList6.replace(cBefore, testList6[6]);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ cBefore = testList6.size();
+ testList6.replace(cBefore + 64, testList6[6]);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ /* Indexing beyond the array returns the last element. */
+ cBefore = testList6.size();
+ RTTESTI_CHECK(testList6[cBefore] == testList6.last());
+ RTTESTI_CHECK(testList6[cBefore + 42] == testList6.last());
+
+ RTTESTI_CHECK(&testList6[cBefore] == &testList6[cBefore - 1]);
+ RTTESTI_CHECK(&testList6[cBefore + 42] == &testList6[cBefore - 1]);
+
+ /* removeAt does nothing if the index is bad. */
+ cBefore = testList6.size();
+ testList6.removeAt(cBefore);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ cBefore = testList6.size();
+ testList6.removeAt(cBefore + 42);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ L<T1, T2> testListEmpty1; RTTESTI_CHECK(!testListEmpty1.size());
+ testListEmpty1.removeFirst();
+ RTTESTI_CHECK(!testListEmpty1.size());
+
+ testListEmpty1.removeLast();
+ RTTESTI_CHECK(!testListEmpty1.size());
+
+ testListEmpty1.removeAt(128);
+ RTTESTI_CHECK(!testListEmpty1.size());
+
+ /* removeRange interprets indexes beyond the end as the end of array (asserted). */
+ testListEmpty1.removeRange(42, 128);
+ RTTESTI_CHECK(!testListEmpty1.size());
+
+ cBefore = testList6.size();
+ testList6.removeRange(cBefore, cBefore);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ cBefore = testList6.size();
+ testList6.removeRange(cBefore + 12, cBefore + 128);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ /* If end is less or equal to the start, nothing is done. */
+ testListEmpty1.removeRange(128, 0);
+ RTTESTI_CHECK(!testListEmpty1.size());
+
+ cBefore = testList6.size();
+ testList6.removeRange(cBefore, 0);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ cBefore = testList6.size();
+ testList6.removeRange(0, 0);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ cBefore = testList6.size();
+ testList6.removeRange(0, 0);
+ RTTESTI_CHECK(testList6.size() == cBefore);
+
+ RTAssertSetQuiet(fQuiet);
+ RTAssertSetMayPanic(fMayPanic);
}
/* define RTCList here to see what happens without MT support ;)
* (valgrind is the preferred tool to check). */
-#define MTTESTLISTTYPE RTCMTList
-#define MTTESTTYPE uint32_t
-#define MTTESTITEMS 1000
+#define MTTESTLISTTYPE RTCMTList
+#define MTTESTTYPE uint32_t
+#define MTTESTITEMS 1000
/**
* Thread for prepending items to a shared list.
@@ -389,7 +493,7 @@ static void test1(const char *pcszDesc, T3 paTestData[], size_t cTestItems)
* @param hSelf The thread handle.
* @param pvUser The provided user data.
*/
-DECLCALLBACK(int) mttest1(RTTHREAD hSelf, void *pvUser)
+static DECLCALLBACK(int) MtTest1ThreadProc(RTTHREAD hSelf, void *pvUser)
{
MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
@@ -406,7 +510,7 @@ DECLCALLBACK(int) mttest1(RTTHREAD hSelf, void *pvUser)
* @param hSelf The thread handle.
* @param pvUser The provided user data.
*/
-DECLCALLBACK(int) mttest2(RTTHREAD hSelf, void *pvUser)
+static DECLCALLBACK(int) MtTest2ThreadProc(RTTHREAD hSelf, void *pvUser)
{
MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
@@ -423,7 +527,7 @@ DECLCALLBACK(int) mttest2(RTTHREAD hSelf, void *pvUser)
* @param hSelf The thread handle.
* @param pvUser The provided user data.
*/
-DECLCALLBACK(int) mttest3(RTTHREAD hSelf, void *pvUser)
+static DECLCALLBACK(int) MtTest3ThreadProc(RTTHREAD hSelf, void *pvUser)
{
MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
@@ -440,7 +544,7 @@ DECLCALLBACK(int) mttest3(RTTHREAD hSelf, void *pvUser)
* @param hSelf The thread handle.
* @param pvUser The provided user data.
*/
-DECLCALLBACK(int) mttest4(RTTHREAD hSelf, void *pvUser)
+static DECLCALLBACK(int) MtTest4ThreadProc(RTTHREAD hSelf, void *pvUser)
{
MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
@@ -449,7 +553,8 @@ DECLCALLBACK(int) mttest4(RTTHREAD hSelf, void *pvUser)
for (size_t i = 0; i < MTTESTITEMS; ++i)
{
/* Make sure there is at least one item in the list. */
- while (pTestList->isEmpty()) {};
+ while (pTestList->isEmpty())
+ RTThreadYield();
a = pTestList->at(RTRandU32Ex(0, (uint32_t)pTestList->size() - 1));
}
@@ -462,7 +567,7 @@ DECLCALLBACK(int) mttest4(RTTHREAD hSelf, void *pvUser)
* @param hSelf The thread handle.
* @param pvUser The provided user data.
*/
-DECLCALLBACK(int) mttest5(RTTHREAD hSelf, void *pvUser)
+static DECLCALLBACK(int) MtTest5ThreadProc(RTTHREAD hSelf, void *pvUser)
{
MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
@@ -470,7 +575,8 @@ DECLCALLBACK(int) mttest5(RTTHREAD hSelf, void *pvUser)
for (size_t i = 0; i < MTTESTITEMS; ++i)
{
/* Make sure there is at least one item in the list. */
- while (pTestList->isEmpty()) {};
+ while (pTestList->isEmpty())
+ RTThreadYield();
pTestList->replace(RTRandU32Ex(0, (uint32_t)pTestList->size() - 1), 0xFF00FF00);
}
@@ -483,7 +589,7 @@ DECLCALLBACK(int) mttest5(RTTHREAD hSelf, void *pvUser)
* @param hSelf The thread handle.
* @param pvUser The provided user data.
*/
-DECLCALLBACK(int) mttest6(RTTHREAD hSelf, void *pvUser)
+static DECLCALLBACK(int) MtTest6ThreadProc(RTTHREAD hSelf, void *pvUser)
{
MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
@@ -491,7 +597,8 @@ DECLCALLBACK(int) mttest6(RTTHREAD hSelf, void *pvUser)
for (size_t i = 0; i < MTTESTITEMS; ++i)
{
/* Make sure there is at least one item in the list. */
- while (pTestList->isEmpty()) {};
+ while (pTestList->isEmpty())
+ RTThreadYield();
pTestList->removeAt(RTRandU32Ex(0, (uint32_t)pTestList->size() - 1));
}
@@ -507,35 +614,27 @@ static void test2()
{
RTTestISubF("MT test with 6 threads (%u tests per thread).", MTTESTITEMS);
- RTTHREAD hThread1, hThread2, hThread3, hThread4, hThread5, hThread6;
- int rc = VINF_SUCCESS;
-
- MTTESTLISTTYPE<MTTESTTYPE> testList;
- rc = RTThreadCreate(&hThread1, &mttest1, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest1");
- AssertRC(rc);
- rc = RTThreadCreate(&hThread2, &mttest2, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest2");
- AssertRC(rc);
- rc = RTThreadCreate(&hThread3, &mttest3, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest3");
- AssertRC(rc);
- rc = RTThreadCreate(&hThread4, &mttest4, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest4");
- AssertRC(rc);
- rc = RTThreadCreate(&hThread5, &mttest5, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest5");
- AssertRC(rc);
- rc = RTThreadCreate(&hThread6, &mttest6, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest6");
- AssertRC(rc);
-
- rc = RTThreadWait(hThread1, RT_INDEFINITE_WAIT, 0);
- AssertRC(rc);
- rc = RTThreadWait(hThread2, RT_INDEFINITE_WAIT, 0);
- AssertRC(rc);
- rc = RTThreadWait(hThread3, RT_INDEFINITE_WAIT, 0);
- AssertRC(rc);
- rc = RTThreadWait(hThread4, RT_INDEFINITE_WAIT, 0);
- AssertRC(rc);
- rc = RTThreadWait(hThread5, RT_INDEFINITE_WAIT, 0);
- AssertRC(rc);
- rc = RTThreadWait(hThread6, RT_INDEFINITE_WAIT, 0);
- AssertRC(rc);
+ int rc;
+ MTTESTLISTTYPE<MTTESTTYPE> testList;
+ RTTHREAD ahThreads[6];
+ static PFNRTTHREAD apfnThreads[6] =
+ {
+ MtTest1ThreadProc, MtTest2ThreadProc, MtTest3ThreadProc, MtTest4ThreadProc, MtTest5ThreadProc, MtTest6ThreadProc
+ };
+
+ for (unsigned i = 0; i < RT_ELEMENTS(ahThreads); i++)
+ {
+ RTTESTI_CHECK_RC_RETV(RTThreadCreateF(&ahThreads[i], apfnThreads[i], &testList, 0,
+ RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest%u", i), VINF_SUCCESS);
+ }
+
+ uint64_t tsMsDeadline = RTTimeMilliTS() + 60000;
+ for (unsigned i = 0; i < RT_ELEMENTS(ahThreads); i++)
+ {
+ uint64_t tsNow = RTTimeMilliTS();
+ uint32_t cWait = tsNow > tsMsDeadline ? 5000 : tsMsDeadline - tsNow;
+ RTTESTI_CHECK_RC(RTThreadWait(ahThreads[i], tsNow, NULL), VINF_SUCCESS);
+ }
RTTESTI_CHECK_RETV(testList.size() == MTTESTITEMS * 2);
for (size_t i = 0; i < testList.size(); ++i)
@@ -556,13 +655,6 @@ int main()
return rcExit;
RTTestBanner(hTest);
- /* Some host info. */
- RTTestIPrintf(RTTESTLVL_ALWAYS, "sizeof(void*)=%d", sizeof(void*));
-
- /*
- * The tests.
- */
-
/*
* Native types.
*/
diff --git a/src/VBox/Runtime/testcase/tstLdr-2.cpp b/src/VBox/Runtime/testcase/tstLdr-2.cpp
index d52bcbeb..7253680f 100644
--- a/src/VBox/Runtime/testcase/tstLdr-2.cpp
+++ b/src/VBox/Runtime/testcase/tstLdr-2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstLdr-3.cpp b/src/VBox/Runtime/testcase/tstLdr-3.cpp
index acf0e981..90856bfd 100644
--- a/src/VBox/Runtime/testcase/tstLdr-3.cpp
+++ b/src/VBox/Runtime/testcase/tstLdr-3.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstLdr-4.cpp b/src/VBox/Runtime/testcase/tstLdr-4.cpp
index 9b6db489..fa3768a4 100644
--- a/src/VBox/Runtime/testcase/tstLdr-4.cpp
+++ b/src/VBox/Runtime/testcase/tstLdr-4.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -125,7 +125,7 @@ static int testLdrOne(const char *pszFilename)
*/
for (i = 0; i < RT_ELEMENTS(aLoads); i++)
{
- if (!strncmp(aLoads[i].pszName, "kLdr-", sizeof("kLdr-") - 1))
+ if (!strncmp(aLoads[i].pszName, RT_STR_TUPLE("kLdr-")))
rc = RTLdrOpenkLdr(pszFilename, 0, RTLDRARCH_WHATEVER, &aLoads[i].hLdrMod);
else
rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_WHATEVER, &aLoads[i].hLdrMod);
diff --git a/src/VBox/Runtime/testcase/tstLdr-4Imp-os2.def b/src/VBox/Runtime/testcase/tstLdr-4Imp-os2.def
index 1dd8d2af..9d92af4b 100644
--- a/src/VBox/Runtime/testcase/tstLdr-4Imp-os2.def
+++ b/src/VBox/Runtime/testcase/tstLdr-4Imp-os2.def
@@ -2,7 +2,7 @@
; tstLdr-4 fake DLL - Definition file.
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstLdr-4Imp-win.def b/src/VBox/Runtime/testcase/tstLdr-4Imp-win.def
index 7508275c..e58384a1 100644
--- a/src/VBox/Runtime/testcase/tstLdr-4Imp-win.def
+++ b/src/VBox/Runtime/testcase/tstLdr-4Imp-win.def
@@ -2,7 +2,7 @@
; tstLdr-4 fake DLL - Definition file.
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstLdr.cpp b/src/VBox/Runtime/testcase/tstLdr.cpp
index 9a02f67f..2757c4c8 100644
--- a/src/VBox/Runtime/testcase/tstLdr.cpp
+++ b/src/VBox/Runtime/testcase/tstLdr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -121,7 +121,7 @@ static int testLdrOne(const char *pszFilename)
/* open it */
int rc;
- if (!strncmp(aLoads[i].pszName, "kLdr-", sizeof("kLdr-") - 1))
+ if (!strncmp(aLoads[i].pszName, RT_STR_TUPLE("kLdr-")))
rc = RTLdrOpenkLdr(pszFilename, 0, RTLDRARCH_WHATEVER, &aLoads[i].hLdrMod);
else
rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_WHATEVER, &aLoads[i].hLdrMod);
diff --git a/src/VBox/Runtime/testcase/tstLdrDisasmTest.cpp b/src/VBox/Runtime/testcase/tstLdrDisasmTest.cpp
index 1cb7654f..bc14072d 100644
--- a/src/VBox/Runtime/testcase/tstLdrDisasmTest.cpp
+++ b/src/VBox/Runtime/testcase/tstLdrDisasmTest.cpp
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstLdrLoad.cpp b/src/VBox/Runtime/testcase/tstLdrLoad.cpp
index 5be78da8..57b2bb70 100644
--- a/src/VBox/Runtime/testcase/tstLdrLoad.cpp
+++ b/src/VBox/Runtime/testcase/tstLdrLoad.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstLdrObj.cpp b/src/VBox/Runtime/testcase/tstLdrObj.cpp
index 26435222..2424e9da 100644
--- a/src/VBox/Runtime/testcase/tstLdrObj.cpp
+++ b/src/VBox/Runtime/testcase/tstLdrObj.cpp
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstLdrObjR0.cpp b/src/VBox/Runtime/testcase/tstLdrObjR0.cpp
index 5471d4e6..94e6edaf 100644
--- a/src/VBox/Runtime/testcase/tstLdrObjR0.cpp
+++ b/src/VBox/Runtime/testcase/tstLdrObjR0.cpp
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstLog.cpp b/src/VBox/Runtime/testcase/tstLog.cpp
index 75813604..348aa2cf 100644
--- a/src/VBox/Runtime/testcase/tstLog.cpp
+++ b/src/VBox/Runtime/testcase/tstLog.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstMemAutoPtr.cpp b/src/VBox/Runtime/testcase/tstMemAutoPtr.cpp
index 1c6de939..2354d7b0 100644
--- a/src/VBox/Runtime/testcase/tstMemAutoPtr.cpp
+++ b/src/VBox/Runtime/testcase/tstMemAutoPtr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -100,12 +100,12 @@ void tstMemAutoPtrDestructorCounter(T *aMem)
{
if (aMem == NULL)
{
- RTPrintf("tstMemAutoPtr(%d): Destructor called with NILL handle!\n");
+ RTPrintf("tstMemAutoPtr(): Destructor called with NULL handle!\n");
g_cErrors++;
}
else if (!VALID_PTR(aMem))
{
- RTPrintf("tstMemAutoPtr(%d): Destructor called with a bad handle %p\n", aMem);
+ RTPrintf("tstMemAutoPtr(): Destructor called with a bad handle %p\n", aMem);
g_cErrors++;
}
RTMemEfFreeNP(aMem);
diff --git a/src/VBox/Runtime/testcase/tstMove.cpp b/src/VBox/Runtime/testcase/tstMove.cpp
index 98117800..e92dde7e 100644
--- a/src/VBox/Runtime/testcase/tstMove.cpp
+++ b/src/VBox/Runtime/testcase/tstMove.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstMp-1.cpp b/src/VBox/Runtime/testcase/tstMp-1.cpp
deleted file mode 100644
index 6039762b..00000000
--- a/src/VBox/Runtime/testcase/tstMp-1.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/* $Id: tstMp-1.cpp $ */
-/** @file
- * IPRT Testcase - RTMp.
- */
-
-/*
- * Copyright (C) 2008 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-#include <iprt/mp.h>
-#include <iprt/cpuset.h>
-#include <iprt/err.h>
-#include <iprt/initterm.h>
-#include <iprt/stream.h>
-#include <iprt/string.h>
-
-
-/*******************************************************************************
-* Global Variables *
-*******************************************************************************/
-static unsigned g_cErrors = 0;
-
-
-int main()
-{
- RTR3InitExeNoArguments(0);
- RTPrintf("tstMp-1: TESTING...\n");
-
- /*
- * Present and possible CPUs.
- */
- RTCPUID cCpus = RTMpGetCount();
- if (cCpus > 0)
- RTPrintf("tstMp-1: RTMpGetCount -> %d\n", (int)cCpus);
- else
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetCount -> %d\n", (int)cCpus);
- g_cErrors++;
- cCpus = 1;
- }
-
- RTCPUSET Set;
- PRTCPUSET pSet = RTMpGetSet(&Set);
- if (pSet == &Set)
- {
- if ((RTCPUID)RTCpuSetCount(&Set) != cCpus)
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetSet returned a set with a different cpu count; %d, expected %d\n",
- RTCpuSetCount(&Set), cCpus);
- g_cErrors++;
- }
- RTPrintf("tstMp-1: Possible CPU mask:\n");
- for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
- {
- RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu);
- if (RTCpuSetIsMemberByIndex(&Set, iCpu))
- {
- RTPrintf("tstMp-1: %2d - id %d: %u/%u MHz", iCpu, (int)idCpu,
- RTMpGetCurFrequency(idCpu), RTMpGetMaxFrequency(idCpu));
- if (RTMpIsCpuPresent(idCpu))
- RTPrintf(RTMpIsCpuOnline(idCpu) ? " online\n" : " offline\n");
- else
- {
- if (!RTMpIsCpuOnline(idCpu))
- RTPrintf(" absent\n");
- else
- {
- RTPrintf(" online but absent!\n");
- RTPrintf("tstMp-1: FAILURE: Cpu with index %d is report as !RTIsCpuPresent while RTIsCpuOnline returns true!\n", iCpu);
- g_cErrors++;
- }
- }
- if (!RTMpIsCpuPossible(idCpu))
- {
- RTPrintf("tstMp-1: FAILURE: Cpu with index %d is returned by RTCpuSet but not RTMpIsCpuPossible!\n", iCpu);
- g_cErrors++;
- }
- }
- else if (RTMpIsCpuPossible(idCpu))
- {
- RTPrintf("tstMp-1: FAILURE: Cpu with index %d is returned by RTMpIsCpuPossible but not RTCpuSet!\n", iCpu);
- g_cErrors++;
- }
- else if (RTMpGetCurFrequency(idCpu) != 0)
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetCurFrequency(%d[idx=%d]) didn't return 0 as it should\n", (int)idCpu, iCpu);
- g_cErrors++;
- }
- else if (RTMpGetMaxFrequency(idCpu) != 0)
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetMaxFrequency(%d[idx=%d]) didn't return 0 as it should\n", (int)idCpu, iCpu);
- g_cErrors++;
- }
- }
- }
- else
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetSet -> %p, expected %p\n", pSet, &Set);
- g_cErrors++;
- RTCpuSetEmpty(&Set);
- RTCpuSetAdd(&Set, RTMpCpuIdFromSetIndex(0));
- }
-
- /*
- * Online CPUs.
- */
- RTCPUID cCpusOnline = RTMpGetOnlineCount();
- if (cCpusOnline > 0)
- {
- if (cCpusOnline <= cCpus)
- RTPrintf("tstMp-1: RTMpGetOnlineCount -> %d\n", (int)cCpusOnline);
- else
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineCount -> %d, expected <= %d\n", (int)cCpusOnline, (int)cCpus);
- g_cErrors++;
- cCpusOnline = cCpus;
- }
- }
- else
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineCount -> %d\n", (int)cCpusOnline);
- g_cErrors++;
- cCpusOnline = 1;
- }
-
- RTCPUSET SetOnline;
- pSet = RTMpGetOnlineSet(&SetOnline);
- if (pSet == &SetOnline)
- {
- if (RTCpuSetCount(&SetOnline) <= 0)
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineSet returned an empty set!\n");
- g_cErrors++;
- }
- else if ((RTCPUID)RTCpuSetCount(&SetOnline) > cCpus)
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineSet returned a too high value; %d, expected <= %d\n",
- RTCpuSetCount(&SetOnline), cCpus);
- g_cErrors++;
- }
- RTPrintf("tstMp-1: Online CPU mask:\n");
- for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
- if (RTCpuSetIsMemberByIndex(&SetOnline, iCpu))
- {
- RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu);
- RTPrintf("tstMp-1: %2d - id %d: %u/%u MHz %s\n", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu),
- RTMpGetMaxFrequency(idCpu), RTMpIsCpuOnline(idCpu) ? "online" : "offline");
- if (!RTCpuSetIsMemberByIndex(&Set, iCpu))
- {
- RTPrintf("tstMp-1: FAILURE: online cpu with index %2d is not a member of the possible cpu set!\n", iCpu);
- g_cErrors++;
- }
- }
-
- /* There isn't any sane way of testing RTMpIsCpuOnline really... :-/ */
- }
- else
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineSet -> %p, expected %p\n", pSet, &Set);
- g_cErrors++;
- }
-
- /*
- * Present CPUs.
- */
- RTCPUID cCpusPresent = RTMpGetPresentCount();
- if (cCpusPresent > 0)
- {
- if ( cCpusPresent <= cCpus
- && cCpusPresent >= cCpusOnline)
- RTPrintf("tstMp-1: RTMpGetPresentCount -> %d\n", (int)cCpusPresent);
- else
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetPresentCount -> %d, expected <= %d and >= %d\n", (int)cCpusPresent, (int)cCpus, (int)cCpusOnline);
- g_cErrors++;
- }
- }
- else
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetPresentCount -> %d\n", (int)cCpusPresent);
- g_cErrors++;
- cCpusPresent = 1;
- }
-
- RTCPUSET SetPresent;
- pSet = RTMpGetPresentSet(&SetPresent);
- if (pSet == &SetPresent)
- {
- if (RTCpuSetCount(&SetPresent) <= 0)
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetPresentSet returned an empty set!\n");
- g_cErrors++;
- }
- else if ((RTCPUID)RTCpuSetCount(&SetPresent) != cCpusPresent)
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetPresentSet returned a bad value; %d, expected = %d\n",
- RTCpuSetCount(&SetPresent), cCpusPresent);
- g_cErrors++;
- }
- RTPrintf("tstMp-1: Present CPU mask:\n");
- for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
- if (RTCpuSetIsMemberByIndex(&SetPresent, iCpu))
- {
- RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu);
- RTPrintf("tstMp-1: %2d - id %d: %u/%u MHz %s\n", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu),
- RTMpGetMaxFrequency(idCpu), RTMpIsCpuPresent(idCpu) ? "present" : "absent");
- if (!RTCpuSetIsMemberByIndex(&Set, iCpu))
- {
- RTPrintf("tstMp-1: FAILURE: online cpu with index %2d is not a member of the possible cpu set!\n", iCpu);
- g_cErrors++;
- }
- }
-
- /* There isn't any sane way of testing RTMpIsCpuPresent really... :-/ */
- }
- else
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetPresentSet -> %p, expected %p\n", pSet, &Set);
- g_cErrors++;
- }
-
-
- /* Find an online cpu for the next test. */
- RTCPUID idCpuOnline;
- for (idCpuOnline = 0; idCpuOnline < RTCPUSET_MAX_CPUS; idCpuOnline++)
- if (RTMpIsCpuOnline(idCpuOnline))
- break;
-
- /*
- * Quick test of RTMpGetDescription.
- */
- char szBuf[64];
- int rc = RTMpGetDescription(idCpuOnline, &szBuf[0], sizeof(szBuf));
- if (RT_SUCCESS(rc))
- {
- RTPrintf("tstMp-1: RTMpGetDescription -> '%s'\n", szBuf);
-
- size_t cch = strlen(szBuf);
- rc = RTMpGetDescription(idCpuOnline, &szBuf[0], cch);
- if (rc != VERR_BUFFER_OVERFLOW)
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetDescription -> %Rrc, expected VERR_BUFFER_OVERFLOW\n", rc);
- g_cErrors++;
- }
- rc = RTMpGetDescription(idCpuOnline, &szBuf[0], cch + 1);
- if (RT_FAILURE(rc))
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetDescription -> %Rrc, expected VINF_SUCCESS\n", rc);
- g_cErrors++;
- }
- }
- else
- {
- RTPrintf("tstMp-1: FAILURE: RTMpGetDescription -> %Rrc\n", rc);
- g_cErrors++;
- }
-
-
- if (!g_cErrors)
- RTPrintf("tstMp-1: SUCCESS\n", g_cErrors);
- else
- RTPrintf("tstMp-1: FAILURE - %d errors\n", g_cErrors);
- return !!g_cErrors;
-}
-
diff --git a/src/VBox/Runtime/testcase/tstNoCrt-1.cpp b/src/VBox/Runtime/testcase/tstNoCrt-1.cpp
index 9131b6c1..52e2099a 100644
--- a/src/VBox/Runtime/testcase/tstNoCrt-1.cpp
+++ b/src/VBox/Runtime/testcase/tstNoCrt-1.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstOnce.cpp b/src/VBox/Runtime/testcase/tstOnce.cpp
index b6c05551..e09d93bd 100644
--- a/src/VBox/Runtime/testcase/tstOnce.cpp
+++ b/src/VBox/Runtime/testcase/tstOnce.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -48,13 +48,13 @@ static RTONCE g_Once2 = RTONCE_INITIALIZER;
static RTSEMEVENTMULTI g_hEventMulti = NIL_RTSEMEVENTMULTI;
-static DECLCALLBACK(int) Once1CB(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int) Once1CB(void *pvUser)
{
if (g_fOnceCB1)
return VERR_WRONG_ORDER;
- if (pvUser1 != (void *)1 || pvUser2 != (void *)42)
+ if (pvUser != (void *)1)
{
- RTPrintf("tstOnce: ERROR - Once1CB: pvUser1=%p pvUser2=%p!\n", pvUser1, pvUser2);
+ RTPrintf("tstOnce: ERROR - Once1CB: pvUser=%p!\n", pvUser);
g_cErrors++;
return VERR_INVALID_PARAMETER;
}
@@ -62,7 +62,7 @@ static DECLCALLBACK(int) Once1CB(void *pvUser1, void *pvUser2)
}
-static DECLCALLBACK(int) Once2CB(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int) Once2CB(void *pvUser)
{
if (ASMAtomicIncU32(&g_cOnce2CB) != 1)
{
@@ -70,9 +70,9 @@ static DECLCALLBACK(int) Once2CB(void *pvUser1, void *pvUser2)
g_cErrors++;
return VERR_WRONG_ORDER;
}
- if (pvUser1 != (void *)42 || pvUser2 != (void *)1)
+ if (pvUser != (void *)42)
{
- RTPrintf("tstOnce: ERROR - Once2CB: pvUser1=%p pvUser2=%p!\n", pvUser1, pvUser2);
+ RTPrintf("tstOnce: ERROR - Once2CB: pvUser=%p!\n", pvUser);
g_cErrors++;
return VERR_INVALID_PARAMETER;
}
@@ -89,7 +89,7 @@ static DECLCALLBACK(int) Once2Thread(RTTHREAD hThread, void *pvUser)
int rc = RTSemEventMultiWait(g_hEventMulti, RT_INDEFINITE_WAIT);
if (RT_FAILURE(rc))
return rc;
- rc = RTOnce(&g_Once2, Once2CB, (void *)42, (void *)1);
+ rc = RTOnce(&g_Once2, Once2CB, (void *)42);
if (RT_SUCCESS(rc))
{
if (!ASMAtomicUoReadBool(&g_fOnce2Ready))
@@ -112,11 +112,11 @@ int main()
RTPrintf("tstOnce: TESTING - smoke...\n");
RTONCE Once1 = RTONCE_INITIALIZER;
g_fOnceCB1 = false;
- int rc = RTOnce(&Once1, Once1CB, (void *)1, (void *)42);
+ int rc = RTOnce(&Once1, Once1CB, (void *)1);
if (rc != VINF_SUCCESS)
RTPrintf("tstOnce: ERROR - Once1, 1 failed, rc=%Rrc\n", rc);
g_fOnceCB1 = false;
- rc = RTOnce(&Once1, Once1CB, (void *)1, (void *)42);
+ rc = RTOnce(&Once1, Once1CB, (void *)1);
if (rc != VINF_SUCCESS)
RTPrintf("tstOnce: ERROR - Once1, 2 failed, rc=%Rrc\n", rc);
diff --git a/src/VBox/Runtime/testcase/tstPrfRT.cpp b/src/VBox/Runtime/testcase/tstPrfRT.cpp
index 27a26e9a..05a08836 100644
--- a/src/VBox/Runtime/testcase/tstPrfRT.cpp
+++ b/src/VBox/Runtime/testcase/tstPrfRT.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp b/src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp
index ad2dccda..85b66668 100644
--- a/src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp
+++ b/src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,12 +31,127 @@
#include <iprt/asm-amd64-x86.h>
#include <iprt/err.h>
+#include <iprt/mem.h>
#include <iprt/time.h>
#include <iprt/string.h>
#include <VBox/sup.h>
#include "tstR0ThreadPreemption.h"
+#define TSTRTR0THREADCTXDATA_MAGIC 0xc01a50da
+
+/**
+ * Thread-context hook data.
+ */
+typedef struct TSTRTR0THREADCTXDATA
+{
+ uint32_t volatile u32Magic;
+ RTCPUID uSourceCpuId;
+ RTNATIVETHREAD hSourceThread;
+ RTTHREADCTX hThreadCtx;
+
+ /* For RTTHREADCTXEVENT_PREEMPTING. */
+ bool fPreemptingSuccess;
+ volatile bool fPreemptingInvoked;
+
+ /* For RTTHREADCTXEVENT_RESUMED. */
+ bool fResumedSuccess;
+ volatile bool fResumedInvoked;
+
+ char achResult[512];
+} TSTRTR0THREADCTXDATA, *PTSTRTR0THREADCTXDATA;
+
+
+/**
+ * Thread-context hook function.
+ *
+ * @param enmEvent The thread-context event.
+ * @param pvUser Pointer to the user argument.
+ */
+static DECLCALLBACK(void) tstR0ThreadCtxHook(RTTHREADCTXEVENT enmEvent, void *pvUser)
+{
+ PTSTRTR0THREADCTXDATA pData = (PTSTRTR0THREADCTXDATA)pvUser;
+ AssertPtrReturnVoid(pData);
+
+ if (pData->u32Magic != TSTRTR0THREADCTXDATA_MAGIC)
+ {
+ RTStrPrintf(pData->achResult, sizeof(pData->achResult), "!tstR0ThreadCtxHook: Invalid magic.");
+ return;
+ }
+
+ switch (enmEvent)
+ {
+ case RTTHREADCTXEVENT_PREEMPTING:
+ {
+ ASMAtomicWriteBool(&pData->fPreemptingInvoked, true);
+
+ /* We've already been called once, we now might very well be on another CPU. Nothing to do here. */
+ if (pData->fPreemptingSuccess)
+ return;
+
+ if (RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+ {
+ RTStrPrintf(pData->achResult, sizeof(pData->achResult),
+ "!tstR0ThreadCtxHook[RTTHREADCTXEVENT_PREEMPTING]: Called with preemption enabled");
+ break;
+ }
+
+ RTNATIVETHREAD hCurrentThread = RTThreadNativeSelf();
+ if (pData->hSourceThread != hCurrentThread)
+ {
+ RTStrPrintf(pData->achResult, sizeof(pData->achResult),
+ "!tstR0ThreadCtxHook[RTTHREADCTXEVENT_PREEMPTING]: Thread switched! Source=%RTnthrd Current=%RTnthrd.",
+ pData->hSourceThread, hCurrentThread);
+ break;
+ }
+
+ RTCPUID uCurrentCpuId = RTMpCpuId();
+ if (pData->uSourceCpuId != uCurrentCpuId)
+ {
+ RTStrPrintf(pData->achResult, sizeof(pData->achResult),
+ "!tstR0ThreadCtxHook[RTTHREADCTXEVENT_PREEMPTING]: migrated uSourceCpuId=%RU32 uCurrentCpuId=%RU32",
+ pData->uSourceCpuId, uCurrentCpuId);
+ break;
+ }
+
+ pData->fPreemptingSuccess = true;
+ break;
+ }
+
+ case RTTHREADCTXEVENT_RESUMED:
+ {
+ ASMAtomicWriteBool(&pData->fResumedInvoked, true);
+
+ /* We've already been called once successfully, nothing more to do. */
+ if (ASMAtomicReadBool(&pData->fResumedSuccess))
+ return;
+
+ if (!pData->fPreemptingSuccess)
+ {
+ RTStrPrintf(pData->achResult, sizeof(pData->achResult),
+ "!tstR0ThreadCtxHook[RTTHREADCTXEVENT_RESUMED]: Called before preempting callback was invoked.");
+ break;
+ }
+
+ RTNATIVETHREAD hCurrentThread = RTThreadNativeSelf();
+ if (pData->hSourceThread != hCurrentThread)
+ {
+ RTStrPrintf(pData->achResult, sizeof(pData->achResult),
+ "!tstR0ThreadCtxHook[RTTHREADCTXEVENT_RESUMED]: Thread switched! Source=%RTnthrd Current=%RTnthrd.",
+ pData->hSourceThread, hCurrentThread);
+ break;
+ }
+
+ ASMAtomicWriteBool(&pData->fResumedSuccess, true);
+ break;
+ }
+
+ default:
+ AssertMsgFailed(("Invalid event %#x\n", enmEvent));
+ break;
+ }
+}
+
/**
* Service request callback function.
@@ -91,12 +206,22 @@ DECLEXPORT(int) TSTR0ThreadPreemptionSrvReqHandler(PSUPDRVSESSION pSession, uint
break;
}
+ case TSTR0THREADPREMEPTION_IS_TRUSTY:
+ if (!RTThreadPreemptIsPendingTrusty())
+ RTStrPrintf(pszErr, cchErr, "!Untrusty");
+ break;
+
case TSTR0THREADPREMEPTION_IS_PENDING:
{
RTTHREADPREEMPTSTATE State = RTTHREADPREEMPTSTATE_INITIALIZER;
RTThreadPreemptDisable(&State);
if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
{
+#ifdef RT_OS_DARWIN
+ uint64_t const cNsMax = UINT64_C(8)*1000U*1000U*1000U;
+#else
+ uint64_t const cNsMax = UINT64_C(2)*1000U*1000U*1000U;
+#endif
if (ASMIntAreEnabled())
{
uint64_t u64StartTS = RTTimeNanoTS();
@@ -112,8 +237,8 @@ DECLEXPORT(int) TSTR0ThreadPreemptionSrvReqHandler(PSUPDRVSESSION pSession, uint
cNanosSysElapsed = RTTimeSystemNanoTS() - u64StartSysTS;
cLoops++;
} while ( !fPending
- && cNanosElapsed < UINT64_C(2)*1000U*1000U*1000U
- && cNanosSysElapsed < UINT64_C(2)*1000U*1000U*1000U
+ && cNanosElapsed < cNsMax
+ && cNanosSysElapsed < cNsMax
&& cLoops < 100U*_1M);
if (!fPending)
RTStrPrintf(pszErr, cchErr, "!Preempt not pending after %'llu loops / %'llu ns / %'llu ns (sys)",
@@ -168,6 +293,159 @@ DECLEXPORT(int) TSTR0ThreadPreemptionSrvReqHandler(PSUPDRVSESSION pSession, uint
break;
}
+ case TSTR0THREADPREEMPTION_CTXHOOKS:
+ {
+ if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+ {
+ RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksCreate must be called with preemption enabled");
+ break;
+ }
+
+ bool fRegistered = RTThreadCtxHooksAreRegistered(NIL_RTTHREADCTX);
+ if (fRegistered)
+ {
+ RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksAreRegistered returns true before creating any hooks");
+ break;
+ }
+
+ RTTHREADCTX hThreadCtx;
+ int rc = RTThreadCtxHooksCreate(&hThreadCtx);
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_NOT_SUPPORTED)
+ RTStrPrintf(pszErr, cchErr, "RTThreadCtxHooksCreate returns VERR_NOT_SUPPORTED");
+ else
+ RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksCreate returns %Rrc", rc);
+ break;
+ }
+
+ fRegistered = RTThreadCtxHooksAreRegistered(hThreadCtx);
+ if (fRegistered)
+ {
+ RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksAreRegistered returns true before registering any hooks");
+ RTThreadCtxHooksRelease(hThreadCtx);
+ break;
+ }
+
+ PTSTRTR0THREADCTXDATA pCtxData = (PTSTRTR0THREADCTXDATA)RTMemAllocZ(sizeof(*pCtxData));
+ AssertReturn(pCtxData, VERR_NO_MEMORY);
+ pCtxData->u32Magic = TSTRTR0THREADCTXDATA_MAGIC;
+ pCtxData->hThreadCtx = hThreadCtx;
+ pCtxData->fPreemptingSuccess = false;
+ pCtxData->fPreemptingInvoked = false;
+ pCtxData->fResumedInvoked = false;
+ pCtxData->fResumedSuccess = false;
+ pCtxData->hSourceThread = RTThreadNativeSelf();
+ RT_ZERO(pCtxData->achResult);
+
+ RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
+ RTThreadPreemptDisable(&PreemptState);
+ Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
+ pCtxData->uSourceCpuId = RTMpCpuId();
+
+ rc = RTThreadCtxHooksRegister(hThreadCtx, &tstR0ThreadCtxHook, pCtxData);
+ if (RT_FAILURE(rc))
+ {
+ RTThreadPreemptRestore(&PreemptState);
+ RTMemFree(pCtxData);
+ RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksRegister returns %Rrc", rc);
+ break;
+ }
+
+ fRegistered = RTThreadCtxHooksAreRegistered(hThreadCtx);
+ if (!fRegistered)
+ {
+ RTThreadPreemptRestore(&PreemptState);
+ RTMemFree(pCtxData);
+ RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksAreRegistered return false when hooks are supposedly registered");
+ break;
+ }
+
+ RTThreadPreemptRestore(&PreemptState);
+
+ /* Check if the preempting callback has/will been invoked. */
+ const uint32_t cMsTimeout = 10000;
+ const uint32_t cMsSleepGranularity = 50;
+ uint32_t cMsSlept = 0;
+ RTCPUID uCurrentCpuId = NIL_RTCPUID;
+ for (;;)
+ {
+ RTThreadYield();
+ RTThreadPreemptDisable(&PreemptState);
+ uCurrentCpuId = RTMpCpuId();
+ RTThreadPreemptRestore(&PreemptState);
+
+ if ( pCtxData->uSourceCpuId != uCurrentCpuId
+ || cMsSlept >= cMsTimeout)
+ {
+ break;
+ }
+
+ RTThreadSleep(cMsSleepGranularity);
+ cMsSlept += cMsSleepGranularity;
+ }
+
+ if (!ASMAtomicReadBool(&pCtxData->fPreemptingInvoked))
+ {
+ if (pCtxData->uSourceCpuId != uCurrentCpuId)
+ {
+ RTStrPrintf(pszErr, cchErr,
+ "!tstR0ThreadCtxHooks[RTTHREADCTXEVENT_PREEMPTING] not invoked before migrating from CPU %RU32 to %RU32",
+ pCtxData->uSourceCpuId, uCurrentCpuId);
+ }
+ else
+ {
+ RTStrPrintf(pszErr, cchErr, "!tstR0ThreadCtxHooks[RTTHREADCTXEVENT_PREEMPTING] not invoked after ca. %u ms",
+ cMsSlept);
+ }
+ }
+ else if (!pCtxData->fPreemptingSuccess)
+ RTStrCopy(pszErr, cchErr, pCtxData->achResult);
+ else
+ {
+ /* Preempting callback succeeded, now check if the resumed callback has/will been invoked. */
+ cMsSlept = 0;
+ for (;;)
+ {
+ if ( ASMAtomicReadBool(&pCtxData->fResumedInvoked)
+ || cMsSlept >= cMsTimeout)
+ {
+ break;
+ }
+
+ RTThreadSleep(cMsSleepGranularity);
+ cMsSlept += cMsSleepGranularity;
+ }
+
+ if (!ASMAtomicReadBool(&pCtxData->fResumedInvoked))
+ {
+ RTStrPrintf(pszErr, cchErr, "!tstR0ThreadCtxHooks[RTTHREADCTXEVENT_RESUMED] not invoked after ca. %u ms",
+ cMsSlept);
+ }
+ else if (!pCtxData->fResumedSuccess)
+ RTStrCopy(pszErr, cchErr, pCtxData->achResult);
+ }
+
+ RTThreadCtxHooksDeregister(hThreadCtx);
+
+ fRegistered = RTThreadCtxHooksAreRegistered(hThreadCtx);
+ if (fRegistered)
+ {
+ RTMemFree(pCtxData);
+ RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksAreRegistered return true when hooks are deregistered");
+ break;
+ }
+
+ Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+ uint32_t cRefs = RTThreadCtxHooksRelease(hThreadCtx);
+ if (cRefs == UINT32_MAX)
+ RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksRelease returns invalid cRefs!");
+
+ RTMemFree(pCtxData);
+ break;
+ }
+
default:
RTStrPrintf(pszErr, cchErr, "!Unknown test #%d", uOperation);
break;
diff --git a/src/VBox/Runtime/testcase/tstR0ThreadPreemption.h b/src/VBox/Runtime/testcase/tstR0ThreadPreemption.h
index f3737642..a6e716ba 100644
--- a/src/VBox/Runtime/testcase/tstR0ThreadPreemption.h
+++ b/src/VBox/Runtime/testcase/tstR0ThreadPreemption.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -36,7 +36,9 @@ typedef enum TSTR0THREADPREMEPTION
TSTR0THREADPREMEPTION_SANITY_OK = 1,
TSTR0THREADPREMEPTION_SANITY_FAILURE,
TSTR0THREADPREMEPTION_BASIC,
+ TSTR0THREADPREMEPTION_IS_TRUSTY,
TSTR0THREADPREMEPTION_IS_PENDING,
- TSTR0THREADPREMEPTION_NESTED
+ TSTR0THREADPREMEPTION_NESTED,
+ TSTR0THREADPREEMPTION_CTXHOOKS
} TSTR0THREADPREMEPTION;
diff --git a/src/VBox/Runtime/testcase/tstR0ThreadPreemptionDriver.cpp b/src/VBox/Runtime/testcase/tstR0ThreadPreemptionDriver.cpp
index 92126939..98263305 100644
--- a/src/VBox/Runtime/testcase/tstR0ThreadPreemptionDriver.cpp
+++ b/src/VBox/Runtime/testcase/tstR0ThreadPreemptionDriver.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -29,18 +29,50 @@
*******************************************************************************/
#include <iprt/initterm.h>
+#include <iprt/asm.h>
+#include <iprt/cpuset.h>
#include <iprt/err.h>
#include <iprt/path.h>
#include <iprt/param.h>
#include <iprt/stream.h>
#include <iprt/string.h>
#include <iprt/test.h>
+#include <iprt/time.h>
#include <iprt/thread.h>
#ifdef VBOX
# include <VBox/sup.h>
# include "tstR0ThreadPreemption.h"
#endif
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+static bool volatile g_fTerminate = false;
+
+
+/**
+ * Try make sure all online CPUs will be engaged.
+ */
+static DECLCALLBACK(int) MyThreadProc(RTTHREAD hSelf, void *pvCpuIdx)
+{
+ RTCPUSET Affinity;
+ RTCpuSetEmpty(&Affinity);
+ RTCpuSetAddByIndex(&Affinity, (intptr_t)pvCpuIdx);
+ RTThreadSetAffinity(&Affinity); /* ignore return code as it's not supported on all hosts. */
+
+ while (!g_fTerminate)
+ {
+ uint64_t tsStart = RTTimeMilliTS();
+ do
+ {
+ ASMNopPause();
+ } while (RTTimeMilliTS() - tsStart < 8);
+ RTThreadSleep(4);
+ }
+
+ return VINF_SUCCESS;
+}
+
int main(int argc, char **argv)
{
@@ -114,8 +146,8 @@ int main(int argc, char **argv)
TSTR0THREADPREMEPTION_SANITY_FAILURE, 0, &Req.Hdr), VINF_SUCCESS);
if (RT_FAILURE(rc))
return RTTestSummaryAndDestroy(hTest);
- RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1), ("%s", Req.szMsg));
- if (strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1))
+ RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")), ("%s", Req.szMsg));
+ if (strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")))
return RTTestSummaryAndDestroy(hTest);
/*
@@ -138,10 +170,39 @@ int main(int argc, char **argv)
RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
/*
+ * Is it trusty.
+ */
+ RTTestSub(hTest, "RTThreadPreemptIsPendingTrusty");
+ Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+ Req.Hdr.cbReq = sizeof(Req);
+ Req.szMsg[0] = '\0';
+ RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstR0ThreadPreemption", sizeof("tstR0ThreadPreemption") - 1,
+ TSTR0THREADPREMEPTION_IS_TRUSTY, 0, &Req.Hdr), VINF_SUCCESS);
+ if (RT_FAILURE(rc))
+ return RTTestSummaryAndDestroy(hTest);
+ if (Req.szMsg[0] == '!')
+ RTTestIFailed("%s", &Req.szMsg[1]);
+ else if (Req.szMsg[0])
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
+
+ /*
* Stay in ring-0 until preemption is pending.
*/
-RTThreadSleep(250); /** @todo fix GIP initialization? */
+ RTTHREAD ahThreads[RTCPUSET_MAX_CPUS];
+ uint32_t cThreads = RTMpGetCount();
+ RTCPUSET OnlineSet;
+ RTMpGetOnlineSet(&OnlineSet);
+ for (uint32_t i = 0; i < RT_ELEMENTS(ahThreads); i++)
+ {
+ ahThreads[i] = NIL_RTTHREAD;
+ if (RTCpuSetIsMemberByIndex(&OnlineSet, i))
+ RTThreadCreateF(&ahThreads[i], MyThreadProc, (void *)(uintptr_t)i, 0, RTTHREADTYPE_DEFAULT,
+ RTTHREADFLAGS_WAITABLE, "cpu=%u", i);
+ }
+
+
RTTestSub(hTest, "Pending Preemption");
+ RTThreadSleep(250); /** @todo fix GIP initialization? */
for (int i = 0; ; i++)
{
Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
@@ -149,7 +210,7 @@ RTThreadSleep(250); /** @todo fix GIP initialization? */
Req.szMsg[0] = '\0';
RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstR0ThreadPreemption", sizeof("tstR0ThreadPreemption") - 1,
TSTR0THREADPREMEPTION_IS_PENDING, 0, &Req.Hdr), VINF_SUCCESS);
- if ( strcmp(Req.szMsg, "cLoops=1\n")
+ if ( strcmp(Req.szMsg, "!cLoops=1\n")
|| i >= 64)
{
if (Req.szMsg[0] == '!')
@@ -160,8 +221,15 @@ RTThreadSleep(250); /** @todo fix GIP initialization? */
}
if ((i % 3) == 0)
RTThreadYield();
+ else if ((i % 16) == 0)
+ RTThreadSleep(8);
}
+ ASMAtomicWriteBool(&g_fTerminate, true);
+ for (uint32_t i = 0; i < RT_ELEMENTS(ahThreads); i++)
+ if (ahThreads[i] != NIL_RTTHREAD)
+ RTThreadWait(ahThreads[i], 5000, NULL);
+
/*
* Test nested RTThreadPreemptDisable calls.
*/
@@ -176,6 +244,40 @@ RTThreadSleep(250); /** @todo fix GIP initialization? */
else if (Req.szMsg[0])
RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
+
+ /*
+ * Test thread-context hooks.
+ */
+ RTTestSub(hTest, "RTThreadCtxHooks");
+ uint64_t u64StartTS = RTTimeMilliTS();
+ uint64_t cMsMax = 60000; /* ca. 1 minute timeout. */
+ uint64_t cMsElapsed;
+ for (unsigned i = 0; i < 50; i++)
+ {
+ Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+ Req.Hdr.cbReq = sizeof(Req);
+ Req.szMsg[0] = '\0';
+ RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstR0ThreadPreemption", sizeof("tstR0ThreadPreemption") - 1,
+ TSTR0THREADPREEMPTION_CTXHOOKS, 0, &Req.Hdr), VINF_SUCCESS);
+ if (RT_FAILURE(rc))
+ return RTTestSummaryAndDestroy(hTest);
+ if (Req.szMsg[0] == '!')
+ RTTestIFailed("%s", &Req.szMsg[1]);
+ else if (Req.szMsg[0])
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
+ if (!(i % 10))
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "RTThreadCtxHooks passed %u iteration(s)\n", i);
+
+ /* Check timeout and bail. */
+ cMsElapsed = RTTimeMilliTS() - u64StartTS;
+ if (cMsElapsed > cMsMax)
+ {
+ RTTestIPrintf(RTTESTLVL_INFO, "RTThreadCtxHooks Stopping iterations. %RU64 ms. for %u iterations.\n",
+ cMsElapsed, i);
+ break;
+ }
+ }
+
/*
* Done.
*/
diff --git a/src/VBox/Runtime/testcase/tstRTAssertCompile.cpp b/src/VBox/Runtime/testcase/tstRTAssertCompile.cpp
index 4749e495..a14f86e3 100644
--- a/src/VBox/Runtime/testcase/tstRTAssertCompile.cpp
+++ b/src/VBox/Runtime/testcase/tstRTAssertCompile.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTAvl.cpp b/src/VBox/Runtime/testcase/tstRTAvl.cpp
index e77f6811..b460946d 100644
--- a/src/VBox/Runtime/testcase/tstRTAvl.cpp
+++ b/src/VBox/Runtime/testcase/tstRTAvl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTBase64.cpp b/src/VBox/Runtime/testcase/tstRTBase64.cpp
index 57dc7d0a..6f86c6be 100644
--- a/src/VBox/Runtime/testcase/tstRTBase64.cpp
+++ b/src/VBox/Runtime/testcase/tstRTBase64.cpp
@@ -174,31 +174,31 @@ int main()
/*
* Test for buffer overruns.
*/
+ RTTestSubF(hTest, "Test 3");
static uint8_t s_abData4[32768];
for (size_t i = 0; i < sizeof(s_abData4); i++)
s_abData4[i] = i % 256;
for (size_t cbSrc = 1; cbSrc <= sizeof(s_abData4); cbSrc++)
{
- RTTestSubF(hTest, "Test 3-%zu", cbSrc);
char szEnc[49152];
memset(szEnc, '\0', sizeof(szEnc));
size_t cchEnc = RTBase64EncodedLength(cbSrc);
if (cchEnc >= sizeof(szEnc))
- RTTestIFailed("RTBase64EncodedLength returned %zu bytes, too big\n", cchEnc);
+ RTTestIFailed("RTBase64EncodedLength(%zu) returned %zu bytes, too big\n", cbSrc, cchEnc);
size_t cchOut = 0;
rc = RTBase64Encode(s_abData4, cbSrc, szEnc, cchEnc, &cchOut);
if (rc != VERR_BUFFER_OVERFLOW)
- RTTestIFailed("RTBase64Encode has no buffer overflow with too small buffer -> %Rrc\n", rc);
+ RTTestIFailed("RTBase64Encode(,%zu,) has no buffer overflow with too small buffer -> %Rrc\n", cbSrc, rc);
rc = RTBase64Encode(s_abData4, cbSrc, szEnc, cchEnc + 1, &cchOut);
if (RT_FAILURE(rc))
RTTestIFailed("RTBase64Encode -> %Rrc\n", rc);
if (cchOut != cchEnc)
- RTTestIFailed("RTBase64EncodedLength returned %zu bytes, expected %zu.\n",
- cchEnc, cchOut);
+ RTTestIFailed("RTBase64EncodedLength(%zu) returned %zu bytes, expected %zu.\n",
+ cbSrc, cchEnc, cchOut);
if (szEnc[cchOut + 1] != '\0')
- RTTestIFailed("RTBase64Encode returned string which is not zero terminated\n");
+ RTTestIFailed("RTBase64Encode(,%zu,) returned string which is not zero terminated\n", cbSrc);
if (strlen(szEnc) != cchOut)
- RTTestIFailed("RTBase64Encode returned incorrect string, length %lu\n", cchOut);
+ RTTestIFailed("RTBase64Encode(,%zu,) returned incorrect string, length %lu\n", cbSrc, cchOut);
}
/*
diff --git a/src/VBox/Runtime/testcase/tstRTBitOperations.cpp b/src/VBox/Runtime/testcase/tstRTBitOperations.cpp
index a38f389e..d45bfcd7 100644
--- a/src/VBox/Runtime/testcase/tstRTBitOperations.cpp
+++ b/src/VBox/Runtime/testcase/tstRTBitOperations.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTCidr.cpp b/src/VBox/Runtime/testcase/tstRTCidr.cpp
index 48c5ed37..ab132585 100644
--- a/src/VBox/Runtime/testcase/tstRTCidr.cpp
+++ b/src/VBox/Runtime/testcase/tstRTCidr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2009 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -40,7 +40,7 @@
*******************************************************************************/
#define CHECKNETWORK(String, rcExpected, ExpectedNetwork, ExpectedNetMask) \
do { \
- RTIPV4ADDR Network, NetMask; \
+ RTNETADDRIPV4 Network, NetMask; \
int rc2 = RTCidrStrToIPv4(String, &Network, &NetMask); \
if ((rcExpected) && !rc2) \
{ \
@@ -49,11 +49,11 @@
} \
else if ( (rcExpected) != rc2 \
|| ( rc2 == VINF_SUCCESS \
- && ( (ExpectedNetwork) != Network \
- || (ExpectedNetMask) != NetMask))) \
+ && ( (ExpectedNetwork) != Network.u \
+ || (ExpectedNetMask) != NetMask.u))) \
{ \
- RTTestIFailed("at line %d: '%s': expected %Rrc got %Rrc, expected network %08x got %08x, expected netmask %08x got %08x\n", \
- __LINE__, String, rcExpected, rc2, (ExpectedNetwork), Network, (ExpectedNetMask), NetMask); \
+ RTTestIFailed("at line %d: '%s': expected %Rrc got %Rrc, expected network %RTnaipv4 got %RTnaipv4, expected netmask %RTnaipv4 got %RTnaipv4\n", \
+ __LINE__, String, rcExpected, rc2, (ExpectedNetwork), Network.u, (ExpectedNetMask), NetMask.u); \
} \
} while (0)
diff --git a/src/VBox/Runtime/testcase/tstRTCircBuf.cpp b/src/VBox/Runtime/testcase/tstRTCircBuf.cpp
index 60b2c177..be82ed56 100644
--- a/src/VBox/Runtime/testcase/tstRTCircBuf.cpp
+++ b/src/VBox/Runtime/testcase/tstRTCircBuf.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTCritSect.cpp b/src/VBox/Runtime/testcase/tstRTCritSect.cpp
index 0f046cd0..c143a8b7 100644
--- a/src/VBox/Runtime/testcase/tstRTCritSect.cpp
+++ b/src/VBox/Runtime/testcase/tstRTCritSect.cpp
@@ -491,7 +491,7 @@ int main(int argc, char **argv)
return 1;
case 'V':
- RTPrintf("$Revision: $\n");
+ RTPrintf("$Revision: 89632 $\n");
return 0;
default:
diff --git a/src/VBox/Runtime/testcase/tstRTCritSectRw.cpp b/src/VBox/Runtime/testcase/tstRTCritSectRw.cpp
new file mode 100644
index 00000000..f946a1b1
--- /dev/null
+++ b/src/VBox/Runtime/testcase/tstRTCritSectRw.cpp
@@ -0,0 +1,491 @@
+/* $Id: tstRTCritSectRw.cpp $ */
+/** @file
+ * IPRT Testcase - Reader/Writer Critical Sections.
+ */
+
+/*
+ * Copyright (C) 2009-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/critsect.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/initterm.h>
+#include <iprt/lockvalidator.h>
+#include <iprt/rand.h>
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+#include <iprt/stream.h>
+#include <iprt/test.h>
+#include <iprt/time.h>
+#include <iprt/thread.h>
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+static RTTEST g_hTest;
+static RTCRITSECTRW g_CritSectRw;
+static bool volatile g_fTerminate;
+static bool g_fYield;
+static bool g_fQuiet;
+static unsigned g_uWritePercent;
+static uint32_t volatile g_cConcurrentWriters;
+static uint32_t volatile g_cConcurrentReaders;
+
+
+static DECLCALLBACK(int) Test4Thread(RTTHREAD ThreadSelf, void *pvUser)
+{
+ /* Use randomization to get a little more variation of the sync pattern.
+ We use a pseudo random generator here so that we don't end up testing
+ the speed of the /dev/urandom implementation, but rather the read-write
+ semaphores. */
+ int rc;
+ RTRAND hRand;
+ RTTEST_CHECK_RC_OK_RET(g_hTest, rc = RTRandAdvCreateParkMiller(&hRand), rc);
+ RTTEST_CHECK_RC_OK_RET(g_hTest, rc = RTRandAdvSeed(hRand, (uintptr_t)ThreadSelf), rc);
+ unsigned c100 = RTRandAdvU32Ex(hRand, 0, 99);
+
+ uint64_t *pcItr = (uint64_t *)pvUser;
+ bool fWrite;
+ for (;;)
+ {
+ unsigned readrec = RTRandAdvU32Ex(hRand, 0, 3);
+ unsigned writerec = RTRandAdvU32Ex(hRand, 0, 3);
+ /* Don't overdo recursion testing. */
+ if (readrec > 1)
+ readrec--;
+ if (writerec > 1)
+ writerec--;
+
+ fWrite = (c100 < g_uWritePercent);
+ if (fWrite)
+ {
+ for (unsigned i = 0; i <= writerec; i++)
+ {
+ rc = RTCritSectRwEnterExcl(&g_CritSectRw);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "Write recursion %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
+ break;
+ }
+ }
+ if (RT_FAILURE(rc))
+ break;
+ if (ASMAtomicIncU32(&g_cConcurrentWriters) != 1)
+ {
+ RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s after write locking it",
+ g_cConcurrentWriters, RTThreadSelfName());
+ break;
+ }
+ if (g_cConcurrentReaders != 0)
+ {
+ RTTestFailed(g_hTest, "g_cConcurrentReaders=%u on %s after write locking it",
+ g_cConcurrentReaders, RTThreadSelfName());
+ break;
+ }
+ }
+ else
+ {
+ rc = RTCritSectRwEnterShared(&g_CritSectRw);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "Read locking on %s failed with rc=%Rrc", RTThreadSelfName(), rc);
+ break;
+ }
+ ASMAtomicIncU32(&g_cConcurrentReaders);
+ if (g_cConcurrentWriters != 0)
+ {
+ RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s after read locking it",
+ g_cConcurrentWriters, RTThreadSelfName());
+ break;
+ }
+ }
+ for (unsigned i = 0; i < readrec; i++)
+ {
+ rc = RTCritSectRwEnterShared(&g_CritSectRw);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "Read recursion %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
+ break;
+ }
+ }
+ if (RT_FAILURE(rc))
+ break;
+
+ /*
+ * Check for fairness: The values of the threads should not differ too much
+ */
+ (*pcItr)++;
+
+ /*
+ * Check for correctness: Give other threads a chance. If the implementation is
+ * correct, no other thread will be able to enter this lock now.
+ */
+ if (g_fYield)
+ RTThreadYield();
+
+ for (unsigned i = 0; i < readrec; i++)
+ {
+ rc = RTCritSectRwLeaveShared(&g_CritSectRw);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "Read release %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
+ break;
+ }
+ }
+ if (RT_FAILURE(rc))
+ break;
+
+ if (fWrite)
+ {
+ if (ASMAtomicDecU32(&g_cConcurrentWriters) != 0)
+ {
+ RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s before write release",
+ g_cConcurrentWriters, RTThreadSelfName());
+ break;
+ }
+ if (g_cConcurrentReaders != 0)
+ {
+ RTTestFailed(g_hTest, "g_cConcurrentReaders=%u on %s before write release",
+ g_cConcurrentReaders, RTThreadSelfName());
+ break;
+ }
+ for (unsigned i = 0; i <= writerec; i++)
+ {
+ rc = RTCritSectRwLeaveExcl(&g_CritSectRw);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "Write release %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (g_cConcurrentWriters != 0)
+ {
+ RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s before read release",
+ g_cConcurrentWriters, RTThreadSelfName());
+ break;
+ }
+ ASMAtomicDecU32(&g_cConcurrentReaders);
+ rc = RTCritSectRwLeaveShared(&g_CritSectRw);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "Read release on %s failed with rc=%Rrc", RTThreadSelfName(), rc);
+ break;
+ }
+ }
+
+ if (g_fTerminate)
+ break;
+
+ c100++;
+ c100 %= 100;
+ }
+ if (!g_fQuiet)
+ RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Thread %s exited with %lld\n", RTThreadSelfName(), *pcItr);
+ RTRandAdvDestroy(hRand);
+ return VINF_SUCCESS;
+}
+
+
+static void Test4(unsigned cThreads, unsigned cSeconds, unsigned uWritePercent, bool fYield, bool fQuiet)
+{
+ unsigned i;
+ uint64_t acIterations[32];
+ RTTHREAD aThreads[RT_ELEMENTS(acIterations)];
+ AssertRelease(cThreads <= RT_ELEMENTS(acIterations));
+
+ RTTestSubF(g_hTest, "Test4 - %u threads, %u sec, %u%% writes, %syielding",
+ cThreads, cSeconds, uWritePercent, fYield ? "" : "non-");
+
+ /*
+ * Init globals.
+ */
+ g_fYield = fYield;
+ g_fQuiet = fQuiet;
+ g_fTerminate = false;
+ g_uWritePercent = uWritePercent;
+ g_cConcurrentWriters = 0;
+ g_cConcurrentReaders = 0;
+
+ RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectRwInit(&g_CritSectRw), VINF_SUCCESS);
+
+ /*
+ * Create the threads and let them block on the semrw.
+ */
+ RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectRwEnterExcl(&g_CritSectRw), VINF_SUCCESS);
+
+ for (i = 0; i < cThreads; i++)
+ {
+ acIterations[i] = 0;
+ RTTEST_CHECK_RC_RETV(g_hTest, RTThreadCreateF(&aThreads[i], Test4Thread, &acIterations[i], 0,
+ RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
+ "test-%u", i), VINF_SUCCESS);
+ }
+
+ /*
+ * Do the test run.
+ */
+ uint32_t cErrorsBefore = RTTestErrorCount(g_hTest);
+ uint64_t u64StartTS = RTTimeNanoTS();
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveExcl(&g_CritSectRw), VINF_SUCCESS);
+ RTThreadSleep(cSeconds * 1000);
+ ASMAtomicWriteBool(&g_fTerminate, true);
+ uint64_t ElapsedNS = RTTimeNanoTS() - u64StartTS;
+
+ /*
+ * Clean up the threads and semaphore.
+ */
+ for (i = 0; i < cThreads; i++)
+ RTTEST_CHECK_RC(g_hTest, RTThreadWait(aThreads[i], 5000, NULL), VINF_SUCCESS);
+
+ RTTEST_CHECK_MSG(g_hTest, g_cConcurrentWriters == 0, (g_hTest, "g_cConcurrentWriters=%u at end of test\n", g_cConcurrentWriters));
+ RTTEST_CHECK_MSG(g_hTest, g_cConcurrentReaders == 0, (g_hTest, "g_cConcurrentReaders=%u at end of test\n", g_cConcurrentReaders));
+
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwDelete(&g_CritSectRw), VINF_SUCCESS);
+
+ if (RTTestErrorCount(g_hTest) != cErrorsBefore)
+ RTThreadSleep(100);
+
+ /*
+ * Collect and display the results.
+ */
+ uint64_t cItrTotal = acIterations[0];
+ for (i = 1; i < cThreads; i++)
+ cItrTotal += acIterations[i];
+
+ uint64_t cItrNormal = cItrTotal / cThreads;
+ uint64_t cItrMinOK = cItrNormal / 20; /* 5% */
+ uint64_t cItrMaxDeviation = 0;
+ for (i = 0; i < cThreads; i++)
+ {
+ uint64_t cItrDelta = RT_ABS((int64_t)(acIterations[i] - cItrNormal));
+ if (acIterations[i] < cItrMinOK)
+ RTTestFailed(g_hTest, "Thread %u did less than 5%% of the iterations - %llu (it) vs. %llu (5%%) - %llu%%\n",
+ i, acIterations[i], cItrMinOK, cItrDelta * 100 / cItrNormal);
+ else if (cItrDelta > cItrNormal / 2)
+ RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
+ "Warning! Thread %u deviates by more than 50%% - %llu (it) vs. %llu (avg) - %llu%%\n",
+ i, acIterations[i], cItrNormal, cItrDelta * 100 / cItrNormal);
+ if (cItrDelta > cItrMaxDeviation)
+ cItrMaxDeviation = cItrDelta;
+
+ }
+
+ //RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
+ // "Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n",
+ // cThreads,
+ // cItrTotal,
+ // cItrTotal / cSeconds,
+ // ElapsedNS / cItrTotal,
+ // cItrMaxDeviation * 100 / cItrNormal
+ // );
+ //
+ RTTestValue(g_hTest, "Thruput", cItrTotal * UINT32_C(1000000000) / ElapsedNS, RTTESTUNIT_CALLS_PER_SEC);
+ RTTestValue(g_hTest, "Max diviation", cItrMaxDeviation * 100 / cItrNormal, RTTESTUNIT_PCT);
+}
+
+
+static void TestNegative(void)
+{
+ RTTestSub(g_hTest, "Negative");
+ bool fSavedAssertQuiet = RTAssertSetQuiet(true);
+ bool fSavedAssertMayPanic = RTAssertSetMayPanic(false);
+ bool fSavedLckValEnabled = RTLockValidatorSetEnabled(false);
+
+ RTCRITSECTRW CritSectRw;
+ RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectRwInit(&CritSectRw), VINF_SUCCESS);
+
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VERR_NOT_OWNER);
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VERR_NOT_OWNER);
+
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwEnterExcl(&CritSectRw), VINF_SUCCESS);
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VERR_NOT_OWNER);
+
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwEnterShared(&CritSectRw), VINF_SUCCESS);
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VERR_WRONG_ORDER); /* cannot release the final write before the reads. */
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS);
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS);
+
+ RTTEST_CHECK_RC(g_hTest, RTCritSectRwDelete(&CritSectRw), VINF_SUCCESS);
+
+ RTLockValidatorSetEnabled(fSavedLckValEnabled);
+ RTAssertSetMayPanic(fSavedAssertMayPanic);
+ RTAssertSetQuiet(fSavedAssertQuiet);
+}
+
+
+static bool Test1(void)
+{
+ RTTestSub(g_hTest, "Basics");
+
+ RTCRITSECTRW CritSectRw;
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwInit(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsInitialized(&CritSectRw), false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+
+ for (int iRun = 0; iRun < 3; iRun++)
+ {
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriteRecursion(&CritSectRw) == 1, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriterReadRecursion(&CritSectRw) == 0, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsWriteOwner(&CritSectRw) == true, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriteRecursion(&CritSectRw) == 2, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriterReadRecursion(&CritSectRw) == 0, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsWriteOwner(&CritSectRw) == true, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriteRecursion(&CritSectRw) == 2, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriterReadRecursion(&CritSectRw) == 1, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsWriteOwner(&CritSectRw) == true, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriteRecursion(&CritSectRw) == 3, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriterReadRecursion(&CritSectRw) == 1, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsWriteOwner(&CritSectRw) == true, false);
+
+ /* midway */
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriteRecursion(&CritSectRw) == 2, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriterReadRecursion(&CritSectRw) == 1, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsWriteOwner(&CritSectRw) == true, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriteRecursion(&CritSectRw) == 2, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriterReadRecursion(&CritSectRw) == 0, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsWriteOwner(&CritSectRw) == true, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriteRecursion(&CritSectRw) == 1, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriterReadRecursion(&CritSectRw) == 0, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsWriteOwner(&CritSectRw) == true, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriteRecursion(&CritSectRw) == 0, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwGetWriterReadRecursion(&CritSectRw) == 0, false);
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsWriteOwner(&CritSectRw) == false, false);
+ }
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwTryEnterShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwTryEnterShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwTryEnterShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwTryEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwTryEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwTryEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwTryEnterExcl(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwTryEnterShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS, false);
+
+
+ RTTEST_CHECK_RET(g_hTest, RTCritSectRwIsInitialized(&CritSectRw), false);
+ RTTEST_CHECK_RC_RET(g_hTest, RTCritSectRwDelete(&CritSectRw), VINF_SUCCESS, false);
+ RTTEST_CHECK_RET(g_hTest, !RTCritSectRwIsInitialized(&CritSectRw), false);
+
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ int rc = RTTestInitAndCreate("tstRTCritSectRw", &g_hTest);
+ if (rc)
+ return 1;
+ RTTestBanner(g_hTest);
+
+ if (Test1())
+ {
+ if (argc == 1)
+ {
+ TestNegative();
+
+ /* threads, seconds, writePercent, yield, quiet */
+ Test4( 1, 1, 0, true, false);
+ Test4( 1, 1, 1, true, false);
+ Test4( 1, 1, 5, true, false);
+ Test4( 2, 1, 3, true, false);
+ Test4( 10, 1, 5, true, false);
+ Test4( 10, 10, 10, false, false);
+
+ RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "benchmarking...\n");
+ for (unsigned cThreads = 1; cThreads < 32; cThreads++)
+ Test4(cThreads, 2, 1, false, true);
+
+ /** @todo add a testcase where some stuff times out. */
+ }
+ else
+ {
+ /* threads, seconds, writePercent, yield, quiet */
+ RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "benchmarking...\n");
+ Test4( 1, 3, 1, false, true);
+ Test4( 1, 3, 1, false, true);
+ Test4( 1, 3, 1, false, true);
+ Test4( 2, 3, 1, false, true);
+ Test4( 2, 3, 1, false, true);
+ Test4( 2, 3, 1, false, true);
+ Test4( 3, 3, 1, false, true);
+ Test4( 3, 3, 1, false, true);
+ Test4( 3, 3, 1, false, true);
+ }
+ }
+
+ return RTTestSummaryAndDestroy(g_hTest);
+}
+
diff --git a/src/VBox/Runtime/testcase/tstRTDigest.cpp b/src/VBox/Runtime/testcase/tstRTDigest.cpp
index bd579892..5092ea20 100644
--- a/src/VBox/Runtime/testcase/tstRTDigest.cpp
+++ b/src/VBox/Runtime/testcase/tstRTDigest.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -159,6 +159,16 @@ int main(int argc, char **argv)
break;
}
+ case kDigestType_SHA256:
+ {
+ char *pszDigest;
+ int rc = RTSha256DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL);
+ if (RT_FAILURE(rc))
+ return Error("RTSha256Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc);
+ RTPrintf("%s %s\n", pszDigest, ValueUnion.psz);
+ RTStrFree(pszDigest);
+ break;
+ }
default:
return Error("The file method isn't implemented for this digest\n");
}
diff --git a/src/VBox/Runtime/testcase/tstRTDirCreateUniqueNumbered.cpp b/src/VBox/Runtime/testcase/tstRTDirCreateUniqueNumbered.cpp
index 448c52e5..076a3c85 100644
--- a/src/VBox/Runtime/testcase/tstRTDirCreateUniqueNumbered.cpp
+++ b/src/VBox/Runtime/testcase/tstRTDirCreateUniqueNumbered.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTDvm.cpp b/src/VBox/Runtime/testcase/tstRTDvm.cpp
index 7b2cc132..561b4ee1 100644
--- a/src/VBox/Runtime/testcase/tstRTDvm.cpp
+++ b/src/VBox/Runtime/testcase/tstRTDvm.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTFileAio.cpp b/src/VBox/Runtime/testcase/tstRTFileAio.cpp
index b164083f..0eec4720 100644
--- a/src/VBox/Runtime/testcase/tstRTFileAio.cpp
+++ b/src/VBox/Runtime/testcase/tstRTFileAio.cpp
@@ -84,7 +84,7 @@ void tstFileAioTestReadWriteBasic(RTFILE File, bool fWrite, void *pvTestBuf,
/* Create a context and associate the file handle with it. */
RTFILEAIOCTX hAioContext;
- RTTESTI_CHECK_RC_RETV(RTFileAioCtxCreate(&hAioContext, cMaxReqsInFlight), VINF_SUCCESS);
+ RTTESTI_CHECK_RC_RETV(RTFileAioCtxCreate(&hAioContext, cMaxReqsInFlight, 0 /* fFlags */), VINF_SUCCESS);
RTTESTI_CHECK_RC_RETV(RTFileAioCtxAssociateWithFile(hAioContext, File), VINF_SUCCESS);
/* Initialize requests. */
diff --git a/src/VBox/Runtime/testcase/tstRTFileGetSize-1.cpp b/src/VBox/Runtime/testcase/tstRTFileGetSize-1.cpp
index 168a949b..923b5194 100644
--- a/src/VBox/Runtime/testcase/tstRTFileGetSize-1.cpp
+++ b/src/VBox/Runtime/testcase/tstRTFileGetSize-1.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -60,7 +60,7 @@ static void test1(const char *pszSubTest, const char *pszFilename)
if (RT_SUCCESS(rc))
{
RTTESTI_CHECK(cbFile != UINT64_MAX - 42);
- RTTestIValue(pszFilename, cbFile, RTTESTUNIT_BYTES);
+ RTTestIValue(pszSubTest, cbFile, RTTESTUNIT_BYTES);
}
RTFileClose(hFile);
@@ -85,15 +85,15 @@ int main(int argc, char **argv)
}
#ifdef RT_OS_WINDOWS
- test1("PhysicalDrive0", "//./PhysicalDrive0");
- test1("HarddiskVolume1", "//./HarddiskVolume1");
- test1("null", "//./nul");
+ test1("//./PhysicalDrive0", "//./PhysicalDrive0");
+ test1("//./HarddiskVolume1", "//./HarddiskVolume1");
+ test1("//./null", "//./nul");
#else
- test1("null", "/dev/null");
+ test1("/dev/null", "/dev/null");
# ifdef RT_OS_LINUX
- test1("sda", "/dev/sda");
- test1("sda1", "/dev/sda1");
- test1("sda5", "/dev/sda5");
+ test1("/dev/sda", "/dev/sda");
+ test1("/dev/sda1", "/dev/sda1");
+ test1("/dev/sda5", "/dev/sda5");
# endif
#endif
diff --git a/src/VBox/Runtime/testcase/tstRTFileModeStringToFlags.cpp b/src/VBox/Runtime/testcase/tstRTFileModeStringToFlags.cpp
new file mode 100644
index 00000000..dab42031
--- /dev/null
+++ b/src/VBox/Runtime/testcase/tstRTFileModeStringToFlags.cpp
@@ -0,0 +1,222 @@
+/* $Id: tstRTFileModeStringToFlags.cpp $ */
+/** @file
+ * IPRT Testcase - File mode string to IPRT file mode flags.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/file.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+
+int main()
+{
+ RTTEST hTest;
+ int rc = RTTestInitAndCreate("tstRTStrVersion", &hTest);
+ if (rc)
+ return rc;
+ RTTestBanner(hTest);
+
+ RTTestSub(hTest, "RTFileModeToFlags");
+ static struct
+ {
+ int iResult;
+ const char *pszMode;
+ uint64_t uMode;
+ } const aTests[] =
+ {
+ /* Invalid parameters. */
+ { VERR_INVALID_PARAMETER, "", 0 },
+ { VERR_INVALID_PARAMETER, "foo", 0 },
+ { VERR_INVALID_PARAMETER, "--", 0 },
+ { VERR_INVALID_PARAMETER, "++", 0 },
+ { VERR_INVALID_PARAMETER, "++", 0 },
+ /* Missing action. */
+ { VERR_INVALID_PARAMETER, "z", 0 },
+ /* Open for reading ("r"). */
+ { VINF_SUCCESS , "r", RTFILE_O_OPEN | RTFILE_O_READ },
+ { VINF_SUCCESS , "r+", RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "r+++", RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "+++r", RTFILE_O_OPEN | RTFILE_O_READ },
+ { VINF_SUCCESS , "r+t", RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "r+b", RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE },
+ /* Open / append ("a"). */
+ { VINF_SUCCESS , "a", RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_APPEND },
+ { VINF_SUCCESS , "a+", RTFILE_O_OPEN_CREATE | RTFILE_O_READ | RTFILE_O_WRITE | RTFILE_O_APPEND },
+ { VINF_SUCCESS , "a+++", RTFILE_O_OPEN_CREATE | RTFILE_O_READ | RTFILE_O_WRITE | RTFILE_O_APPEND },
+ { VINF_SUCCESS , "+++a", RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_APPEND },
+ { VINF_SUCCESS , "a+t", RTFILE_O_OPEN_CREATE | RTFILE_O_READ | RTFILE_O_WRITE | RTFILE_O_APPEND },
+ { VINF_SUCCESS , "a+b", RTFILE_O_OPEN_CREATE | RTFILE_O_READ | RTFILE_O_WRITE | RTFILE_O_APPEND },
+ /* Create / open ("c"). */
+ { VINF_SUCCESS , "c", RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "c+", RTFILE_O_OPEN_CREATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "c+++", RTFILE_O_OPEN_CREATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VERR_INVALID_PARAMETER, "cr", 0 },
+ { VERR_INVALID_PARAMETER, "cr+", 0 },
+ /* Create / replace ("w"). */
+ { VINF_SUCCESS , "w", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE },
+ { VERR_INVALID_PARAMETER, "ww", 0 },
+ { VERR_INVALID_PARAMETER, "wc", 0 },
+ { VINF_SUCCESS , "wb", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE },
+ { VINF_SUCCESS , "wb+", RTFILE_O_CREATE_REPLACE | RTFILE_O_READ | RTFILE_O_WRITE | RTFILE_O_TRUNCATE },
+ { VINF_SUCCESS , "w+", RTFILE_O_CREATE_REPLACE | RTFILE_O_READ | RTFILE_O_WRITE | RTFILE_O_TRUNCATE },
+ { VINF_SUCCESS , "w++", RTFILE_O_CREATE_REPLACE | RTFILE_O_READ | RTFILE_O_WRITE | RTFILE_O_TRUNCATE },
+ /* Create only ("x"). */
+ { VINF_SUCCESS , "x", RTFILE_O_CREATE | RTFILE_O_WRITE },
+ { VERR_INVALID_PARAMETER, "xx", 0 },
+ { VERR_INVALID_PARAMETER, "xc", 0 },
+ { VINF_SUCCESS , "xb", RTFILE_O_CREATE | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "xb+", RTFILE_O_CREATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "x+", RTFILE_O_CREATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "x++", RTFILE_O_CREATE | RTFILE_O_READ | RTFILE_O_WRITE }
+ };
+
+ for (unsigned iTest = 0; iTest < RT_ELEMENTS(aTests); iTest++)
+ {
+ uint64_t uMode;
+ int iResult = RTFileModeToFlags(aTests[iTest].pszMode, &uMode);
+ if (iResult != aTests[iTest].iResult)
+ {
+ RTTestFailed(hTest, "#%u: mode string '%s', result is %Rrc, expected %Rrc",
+ iTest, aTests[iTest].pszMode, iResult, aTests[iTest].iResult);
+ break;
+ }
+
+ /** @todo Testing sharing modes are not implemented yet,
+ * so just remove them from testing. */
+ uMode &= ~RTFILE_O_DENY_NONE;
+
+ if ( RT_SUCCESS(iResult)
+ && uMode != aTests[iTest].uMode)
+ {
+ RTTestFailed(hTest, "#%u: mode string '%s', got 0x%x, expected 0x%x",
+ iTest, aTests[iTest].pszMode, uMode, aTests[iTest].uMode);
+ break;
+ }
+ }
+
+ RTTestSub(hTest, "RTFileModeToFlagsEx");
+ static struct
+ {
+ int iResult;
+ const char *pszDisposition;
+ const char *pszMode;
+ /** @todo pszSharing not used yet. */
+ uint64_t uMode;
+ } const aTestsEx[] =
+ {
+ /* Invalid parameters. */
+ { VERR_INVALID_PARAMETER, "", "", 0 },
+ { VERR_INVALID_PARAMETER, "foo", "", 0 },
+ { VERR_INVALID_PARAMETER, "--", "", 0 },
+ { VERR_INVALID_PARAMETER, "++", "", 0 },
+ { VERR_INVALID_PARAMETER, "++", "", 0 },
+ /* Missing action. */
+ { VERR_INVALID_PARAMETER, "z", "", 0 },
+ /* Open existing ("oe"). */
+ { VINF_SUCCESS , "oe", "r", RTFILE_O_OPEN | RTFILE_O_READ },
+ { VINF_SUCCESS , "oe", "w", RTFILE_O_OPEN | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "oe", "rw", RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "oe", "rw+", RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "oe", "++r", RTFILE_O_OPEN | RTFILE_O_READ },
+ { VINF_SUCCESS , "oe", "r+t", RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "oe", "r+b", RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE },
+ /* Open / create ("oc"). */
+ { VINF_SUCCESS , "oc", "r", RTFILE_O_OPEN_CREATE | RTFILE_O_READ },
+ { VINF_SUCCESS , "oc", "r+", RTFILE_O_OPEN_CREATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "oc", "r+++", RTFILE_O_OPEN_CREATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "oc", "+++r", RTFILE_O_OPEN_CREATE | RTFILE_O_READ },
+ { VINF_SUCCESS , "oc", "w+t", RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "oc", "w+b", RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "oc", "w+t", RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "oc", "wr", RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "oc", "rw", RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ /* Open and truncate ("ot"). */
+ { VINF_SUCCESS , "ot", "r", RTFILE_O_OPEN | RTFILE_O_TRUNCATE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ot", "r+", RTFILE_O_OPEN | RTFILE_O_TRUNCATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "ot", "r+++", RTFILE_O_OPEN | RTFILE_O_TRUNCATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "ot", "+++r", RTFILE_O_OPEN | RTFILE_O_TRUNCATE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ot", "w+t", RTFILE_O_OPEN | RTFILE_O_TRUNCATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ot", "w+b", RTFILE_O_OPEN | RTFILE_O_TRUNCATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ot", "w+t", RTFILE_O_OPEN | RTFILE_O_TRUNCATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ot", "wr", RTFILE_O_OPEN | RTFILE_O_TRUNCATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ot", "rw", RTFILE_O_OPEN | RTFILE_O_TRUNCATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ /* Create always ("ca"). */
+ { VINF_SUCCESS , "ca", "r", RTFILE_O_CREATE_REPLACE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ca", "r+", RTFILE_O_CREATE_REPLACE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "ca", "r+++", RTFILE_O_CREATE_REPLACE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "ca", "+++r", RTFILE_O_CREATE_REPLACE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ca", "w+t", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ca", "w+b", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ca", "w+t", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ca", "wr", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ca", "rw", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_READ },
+ /* Create if not exist ("ce"). */
+ { VINF_SUCCESS , "ce", "r", RTFILE_O_CREATE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ce", "r+", RTFILE_O_CREATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "ce", "r+++", RTFILE_O_CREATE | RTFILE_O_READ | RTFILE_O_WRITE },
+ { VINF_SUCCESS , "ce", "+++r", RTFILE_O_CREATE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ce", "w+t", RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ce", "w+b", RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ce", "w+t", RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ce", "wr", RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_READ },
+ { VINF_SUCCESS , "ce", "rw", RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_READ }
+ };
+
+ for (unsigned iTest = 0; iTest < RT_ELEMENTS(aTestsEx); iTest++)
+ {
+ uint64_t uMode;
+ int iResult = RTFileModeToFlagsEx(aTestsEx[iTest].pszMode, aTestsEx[iTest].pszDisposition,
+ NULL /* pszSharing */, &uMode);
+ if (iResult != aTestsEx[iTest].iResult)
+ {
+ RTTestFailed(hTest, "#%u: disp '%s', mode '%s', result is %Rrc, expected %Rrc",
+ iTest, aTestsEx[iTest].pszDisposition, aTestsEx[iTest].pszMode,
+ iResult, aTestsEx[iTest].iResult);
+ break;
+ }
+
+ /** @todo Testing sharing modes are not implemented yet,
+ * so just remove them from testing. */
+ uMode &= ~RTFILE_O_DENY_NONE;
+
+ if ( RT_SUCCESS(iResult)
+ && uMode != aTestsEx[iTest].uMode)
+ {
+ RTTestFailed(hTest, "#%u: disp '%s', mode '%s', got 0x%x, expected 0x%x",
+ iTest, aTestsEx[iTest].pszDisposition, aTestsEx[iTest].pszMode,
+ uMode, aTestsEx[iTest].uMode);
+ break;
+ }
+ }
+
+ /*
+ * Summary.
+ */
+ return RTTestSummaryAndDestroy(hTest);
+}
+
diff --git a/src/VBox/Runtime/testcase/tstRTFsQueries.cpp b/src/VBox/Runtime/testcase/tstRTFsQueries.cpp
index 5a6640c5..e1410939 100644
--- a/src/VBox/Runtime/testcase/tstRTFsQueries.cpp
+++ b/src/VBox/Runtime/testcase/tstRTFsQueries.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTHeapOffset.cpp b/src/VBox/Runtime/testcase/tstRTHeapOffset.cpp
index 467619a2..25574239 100644
--- a/src/VBox/Runtime/testcase/tstRTHeapOffset.cpp
+++ b/src/VBox/Runtime/testcase/tstRTHeapOffset.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTHeapSimple.cpp b/src/VBox/Runtime/testcase/tstRTHeapSimple.cpp
index ef763466..930e48be 100644
--- a/src/VBox/Runtime/testcase/tstRTHeapSimple.cpp
+++ b/src/VBox/Runtime/testcase/tstRTHeapSimple.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTHttp.cpp b/src/VBox/Runtime/testcase/tstRTHttp.cpp
new file mode 100644
index 00000000..10ad1840
--- /dev/null
+++ b/src/VBox/Runtime/testcase/tstRTHttp.cpp
@@ -0,0 +1,253 @@
+/* $Id: tstRTHttp.cpp $ */
+/** @file
+ * IPRT Testcase - Simple cURL testcase.
+ */
+
+/*
+ * Copyright (C) 2012-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/err.h>
+#include <iprt/http.h>
+#include <iprt/mem.h>
+#include <iprt/file.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/initterm.h>
+
+#define CAFILE_NAME "tstHttp-tempcafile.crt"
+
+int main(int argc, char **argv)
+{
+ unsigned cErrors = 0;
+
+ RTR3InitExe(argc, &argv, 0);
+
+ if (argc <= 1)
+ {
+ RTPrintf("usage: %s default\n", argv[0]);
+ return 1;
+ }
+
+ for (int i = 1; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "default"))
+ ;
+ else
+ {
+ RTPrintf("Unknown parameter '%s'\n", argv[i]);
+ return 1;
+ }
+ }
+
+ RTHTTP hHttp;
+ char *pszBuf = NULL;
+ PRTSTREAM CAFile = NULL;
+
+ int rc = RTHttpCreate(&hHttp);
+
+ // create certificate file
+ if (RT_SUCCESS(rc))
+ rc = RTStrmOpen(CAFILE_NAME, "w+b", &CAFile);
+
+ // fetch root CA certificate (new one, often avoided in cert chains by
+ // using an intermediate cert which is signed by old root)
+ if (RT_SUCCESS(rc))
+ rc = RTHttpGet(hHttp,
+ "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem",
+ &pszBuf);
+ if (RT_SUCCESS(rc) && pszBuf)
+ {
+ uint8_t *abSha1;
+ size_t cbSha1;
+ uint8_t *abSha512;
+ size_t cbSha512;
+ size_t cbBuf = strlen(pszBuf);
+ const uint8_t abSha1PCA3G5[] =
+ {
+ 0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
+ 0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5
+ };
+ const uint8_t abSha512PCA3G5[] =
+ {
+ 0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d,
+ 0xe3, 0x17, 0xb3, 0xcf, 0xed, 0x61, 0xae, 0x5c,
+ 0x5d, 0x3e, 0xde, 0xa1, 0x41, 0x35, 0xb2, 0xdf,
+ 0x60, 0xe2, 0x61, 0xfe, 0x3a, 0xc1, 0x66, 0xa3,
+ 0x3c, 0x88, 0x54, 0x04, 0x4f, 0x1d, 0x13, 0x46,
+ 0xe3, 0x8c, 0x06, 0x92, 0x9d, 0x70, 0x54, 0xc3,
+ 0x44, 0xeb, 0x2c, 0x74, 0x25, 0x9e, 0x5d, 0xfb,
+ 0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01
+ };
+ rc = RTHttpCertDigest(hHttp, pszBuf, cbBuf,
+ &abSha1, &cbSha1, &abSha512, &cbSha512);
+ if (RT_SUCCESS(rc))
+ {
+ if (cbSha1 != sizeof(abSha1PCA3G5))
+ {
+ RTPrintf("Wrong SHA1 digest size of PCA-3G5\n");
+ rc = VERR_INTERNAL_ERROR;
+ }
+ else if (memcmp(abSha1PCA3G5, abSha1, cbSha1))
+ {
+ RTPrintf("Wrong SHA1 digest for PCA-3G5:\n"
+ "Got: %.*Rhxs\n"
+ "Expected: %.*Rhxs\n",
+ cbSha1, abSha1, sizeof(abSha1PCA3G5), abSha1PCA3G5);
+ rc = VERR_INTERNAL_ERROR;
+ }
+ if (cbSha512 != sizeof(abSha512PCA3G5))
+ {
+ RTPrintf("Wrong SHA512 digest size of PCA-3G5\n");
+ rc = VERR_INTERNAL_ERROR;
+ }
+ else if (memcmp(abSha512PCA3G5, abSha512, cbSha512))
+ {
+ RTPrintf("Wrong SHA512 digest for PCA-3G5:\n"
+ "Got: %.*Rhxs\n"
+ "Expected: %.*Rhxs\n",
+ cbSha512, abSha512, sizeof(abSha512PCA3G5), abSha512PCA3G5);
+ rc = VERR_INTERNAL_ERROR;
+ }
+ RTMemFree(abSha1);
+ RTMemFree(abSha512);
+ if (RT_SUCCESS(rc))
+ rc = RTStrmWrite(CAFile, pszBuf, cbBuf);
+ if (RT_SUCCESS(rc))
+ rc = RTStrmWrite(CAFile, RTFILE_LINEFEED, strlen(RTFILE_LINEFEED));
+ }
+ }
+ if (pszBuf)
+ {
+ RTMemFree(pszBuf);
+ pszBuf = NULL;
+ }
+
+ // fetch root CA certificate (old one, but still very widely used)
+ if (RT_SUCCESS(rc))
+ rc = RTHttpGet(hHttp,
+ "http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem",
+ &pszBuf);
+ if (RT_SUCCESS(rc) && pszBuf)
+ {
+ uint8_t *abSha1;
+ size_t cbSha1;
+ uint8_t *abSha512;
+ size_t cbSha512;
+ size_t cbBuf = strlen(pszBuf);
+ const uint8_t abSha1PCA3[] =
+ {
+ 0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55,
+ 0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b
+ };
+ const uint8_t abSha512PCA3[] =
+ {
+ 0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2,
+ 0xce, 0xc8, 0xaf, 0xe3, 0xd6, 0x22, 0x54, 0x20,
+ 0x74, 0x67, 0x6e, 0xa5, 0x19, 0xb7, 0x62, 0x1e,
+ 0xc1, 0x2f, 0xd5, 0x08, 0xf4, 0x64, 0xc4, 0xc6,
+ 0xbb, 0xc2, 0xf2, 0x35, 0xe7, 0xbe, 0x32, 0x0b,
+ 0xde, 0xb2, 0xfc, 0x44, 0x92, 0x5b, 0x8b, 0x9b,
+ 0x77, 0xa5, 0x40, 0x22, 0x18, 0x12, 0xcb, 0x3d,
+ 0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99
+ };
+ rc = RTHttpCertDigest(hHttp, pszBuf, cbBuf,
+ &abSha1, &cbSha1, &abSha512, &cbSha512);
+ if (RT_SUCCESS(rc))
+ {
+ if (cbSha1 != sizeof(abSha1PCA3))
+ {
+ RTPrintf("Wrong SHA1 digest size of PCA-3\n");
+ rc = VERR_INTERNAL_ERROR;
+ }
+ else if (memcmp(abSha1PCA3, abSha1, cbSha1))
+ {
+ RTPrintf("Wrong SHA1 digest for PCA-3:\n"
+ "Got: %.*Rhxs\n"
+ "Expected: %.*Rhxs\n",
+ cbSha1, abSha1, sizeof(abSha1PCA3), abSha1PCA3);
+ rc = VERR_INTERNAL_ERROR;
+ }
+ if (cbSha512 != sizeof(abSha512PCA3))
+ {
+ RTPrintf("Wrong SHA512 digest size of PCA-3\n");
+ rc = VERR_INTERNAL_ERROR;
+ }
+ else if (memcmp(abSha512PCA3, abSha512, cbSha512))
+ {
+ RTPrintf("Wrong SHA512 digest for PCA-3:\n"
+ "Got: %.*Rhxs\n"
+ "Expected: %.*Rhxs\n",
+ cbSha512, abSha512, sizeof(abSha512PCA3), abSha512PCA3);
+ rc = VERR_INTERNAL_ERROR;
+ }
+ RTMemFree(abSha1);
+ RTMemFree(abSha512);
+ if (RT_SUCCESS(rc))
+ rc = RTStrmWrite(CAFile, pszBuf, cbBuf);
+ if (RT_SUCCESS(rc))
+ rc = RTStrmWrite(CAFile, RTFILE_LINEFEED, strlen(RTFILE_LINEFEED));
+ }
+ }
+ if (pszBuf)
+ {
+ RTMemFree(pszBuf);
+ pszBuf = NULL;
+ }
+
+ // close certificate file
+ if (CAFile)
+ {
+ RTStrmClose(CAFile);
+ CAFile = NULL;
+ }
+
+ if (RT_SUCCESS(rc))
+ rc = RTHttpSetCAFile(hHttp, CAFILE_NAME);
+
+ if (RT_SUCCESS(rc))
+ rc = RTHttpGet(hHttp,
+ "https://update.virtualbox.org/query.php?platform=LINUX_32BITS_UBUNTU_12_04&version=4.1.18",
+ &pszBuf);
+
+ if ( RT_FAILURE(rc)
+ && rc != VERR_HTTP_COULDNT_CONNECT)
+ cErrors++;
+
+ if (RT_FAILURE(rc))
+ RTPrintf("Error code: %Rrc\n", rc);
+ else
+ RTPrintf("Success!\n");
+ RTPrintf("Got: %s\n", pszBuf);
+ if (pszBuf)
+ {
+ RTMemFree(pszBuf);
+ pszBuf = NULL;
+ }
+
+ RTHttpDestroy(hHttp);
+
+// RTFileDelete(CAFILE_NAME);
+
+ return !!cErrors;
+}
diff --git a/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp b/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp
index 925b23b5..c78a511a 100644
--- a/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp
+++ b/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -191,6 +191,16 @@ void tstASMCpuId(void)
CHECKVAL(uECX2, s.uECX, "%x");
CHECKVAL(uEDX2, s.uEDX, "%x");
+ uint32_t uEAX2 = s.uEAX - 1;
+ uint32_t uEBX2 = s.uEBX - 1;
+ uECX2 = s.uECX - 1;
+ uEDX2 = s.uEDX - 1;
+ ASMCpuIdExSlow(0, 0, 0, 0, &uEAX2, &uEBX2, &uECX2, &uEDX2);
+ CHECKVAL(uEAX2, s.uEAX, "%x");
+ CHECKVAL(uEBX2, s.uEBX, "%x");
+ CHECKVAL(uECX2, s.uECX, "%x");
+ CHECKVAL(uEDX2, s.uEDX, "%x");
+
/*
* Done testing, dump the information.
*/
@@ -209,24 +219,54 @@ void tstASMCpuId(void)
RTTestIPrintf(RTTESTLVL_ALWAYS, "%08x %08x %08x %08x %08x%s\n",
iStd, s.uEAX, s.uEBX, s.uECX, s.uEDX, iStd <= cFunctions ? "" : "*");
- if (iStd == 0x04 || iStd == 0x0b || iStd == 0x0d || iStd > cFunctions)
- continue; /* Leaf 04 and leaf 0d output depend on the initial value of ECX
- * The same seems to apply to invalid standard functions */
-
- u32 = ASMCpuId_EAX(iStd);
- CHECKVAL(u32, s.uEAX, "%x");
- u32 = ASMCpuId_EBX(iStd);
- CHECKVAL(u32, s.uEBX, "%x");
- u32 = ASMCpuId_ECX(iStd);
- CHECKVAL(u32, s.uECX, "%x");
- u32 = ASMCpuId_EDX(iStd);
- CHECKVAL(u32, s.uEDX, "%x");
-
- uECX2 = s.uECX - 1;
- uEDX2 = s.uEDX - 1;
- ASMCpuId_ECX_EDX(iStd, &uECX2, &uEDX2);
- CHECKVAL(uECX2, s.uECX, "%x");
- CHECKVAL(uEDX2, s.uEDX, "%x");
+ /* Leaf 04 and leaf 0d output depend on the initial value of ECX
+ * The same seems to apply to invalid standard functions */
+ if (iStd > cFunctions)
+ continue;
+ if (iStd != 0x04 && iStd != 0x0b && iStd != 0x0d)
+ {
+ u32 = ASMCpuId_EAX(iStd);
+ CHECKVAL(u32, s.uEAX, "%x");
+
+ uint32_t u32EbxMask = UINT32_MAX;
+ if (iStd == 1)
+ u32EbxMask = UINT32_C(0x00ffffff); /* Omit the local apic ID in case we're rescheduled. */
+ u32 = ASMCpuId_EBX(iStd);
+ CHECKVAL(u32 & u32EbxMask, s.uEBX & u32EbxMask, "%x");
+
+ u32 = ASMCpuId_ECX(iStd);
+ CHECKVAL(u32, s.uECX, "%x");
+ u32 = ASMCpuId_EDX(iStd);
+ CHECKVAL(u32, s.uEDX, "%x");
+
+ uECX2 = s.uECX - 1;
+ uEDX2 = s.uEDX - 1;
+ ASMCpuId_ECX_EDX(iStd, &uECX2, &uEDX2);
+ CHECKVAL(uECX2, s.uECX, "%x");
+ CHECKVAL(uEDX2, s.uEDX, "%x");
+ }
+
+ if (iStd == 0x04)
+ for (uint32_t uECX = 1; s.uEAX & 0x1f; uECX++)
+ {
+ ASMCpuId_Idx_ECX(iStd, uECX, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, " [%02x] %08x %08x %08x %08x\n", uECX, s.uEAX, s.uEBX, s.uECX, s.uEDX);
+ RTTESTI_CHECK_BREAK(uECX < 128);
+ }
+ else if (iStd == 0x0b)
+ for (uint32_t uECX = 1; (s.uEAX & 0x1f) && (s.uEBX & 0xffff); uECX++)
+ {
+ ASMCpuId_Idx_ECX(iStd, uECX, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, " [%02x] %08x %08x %08x %08x\n", uECX, s.uEAX, s.uEBX, s.uECX, s.uEDX);
+ RTTESTI_CHECK_BREAK(uECX < 128);
+ }
+ else if (iStd == 0x0d)
+ for (uint32_t uECX = 1; s.uEAX != 0 || s.uEBX != 0 || s.uECX != 0 || s.uEDX != 0; uECX++)
+ {
+ ASMCpuId_Idx_ECX(iStd, uECX, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, " [%02x] %08x %08x %08x %08x\n", uECX, s.uEAX, s.uEBX, s.uECX, s.uEDX);
+ RTTESTI_CHECK_BREAK(uECX < 128);
+ }
}
/*
@@ -338,6 +378,8 @@ void tstASMCpuId(void)
if (iExt > cExtFunctions)
continue; /* Invalid extended functions seems change the value if ECX changes */
+ if (iExt == 0x8000001d)
+ continue; /* Takes cache level in ecx. */
u32 = ASMCpuId_EAX(iExt);
CHECKVAL(u32, s.uEAX, "%x");
@@ -1519,6 +1561,7 @@ int main(int argc, char *argv[])
#if !defined(GCC44_32BIT_PIC) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
tstASMCpuId();
#endif
+#if 1
tstASMAtomicXchgU8();
tstASMAtomicXchgU16();
tstASMAtomicXchgU32();
@@ -1549,6 +1592,7 @@ int main(int argc, char *argv[])
tstASMByteSwap();
tstASMBench();
+#endif
/*
* Show the result.
diff --git a/src/VBox/Runtime/testcase/tstRTList.cpp b/src/VBox/Runtime/testcase/tstRTList.cpp
index 12f31751..bfa8884c 100644
--- a/src/VBox/Runtime/testcase/tstRTList.cpp
+++ b/src/VBox/Runtime/testcase/tstRTList.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTLocalIpc.cpp b/src/VBox/Runtime/testcase/tstRTLocalIpc.cpp
new file mode 100644
index 00000000..476cc042
--- /dev/null
+++ b/src/VBox/Runtime/testcase/tstRTLocalIpc.cpp
@@ -0,0 +1,644 @@
+/* $Id: tstRTLocalIpc.cpp $ */
+/** @file
+ * IPRT Testcase - RTLocalIpc.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/env.h>
+#include <iprt/localipc.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/process.h>
+#include <iprt/rand.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+
+typedef struct LOCALIPCTHREADCTX
+{
+ /** The IPC server handle. */
+ RTLOCALIPCSERVER hServer;
+ /** The test handle. */
+ RTTEST hTest;
+} LOCALIPCTHREADCTX, *PLOCALIPCTHREADCTX;
+
+static int testServerListenAndCancel2(const char *pszExecPath)
+{
+ const char *apszArgs[4] = { pszExecPath, "child", "testServerListenAndCancel", NULL };
+ RTPROCESS hProc;
+ int rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hProc);
+
+ return rc;
+}
+
+static DECLCALLBACK(int) testServerListenAndCancelThread(RTTHREAD hSelf, void *pvUser)
+{
+ PRTLOCALIPCSERVER pServer = (PRTLOCALIPCSERVER)pvUser;
+ AssertPtr(pServer);
+
+ RTThreadSleep(5000); /* Wait a bit to simulate waiting in main thread. */
+
+ int rc = RTLocalIpcServerCancel(*pServer);
+ AssertRC(rc);
+
+ return 0;
+}
+
+static int testServerListenAndCancel(RTTEST hTest, const char *pszExecPath)
+{
+ RTTestSub(hTest, "testServerListenAndCancel");
+
+ RTLOCALIPCSERVER ipcServer;
+ int rc = RTLocalIpcServerCreate(&ipcServer, "testServerListenAndCancel",
+ RTLOCALIPC_FLAGS_MULTI_SESSION);
+ if (RT_SUCCESS(rc))
+ {
+ /* Spawn a simple worker thread and let it listen for incoming connections.
+ * In the meanwhile we try to cancel the server and see what happens. */
+ RTTHREAD hThread;
+ rc = RTThreadCreate(&hThread, testServerListenAndCancelThread,
+ &ipcServer, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc1");
+ if (RT_SUCCESS(rc))
+ {
+ do
+ {
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "Listening for incoming connections ...\n");
+ RTLOCALIPCSESSION ipcSession;
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerListen(ipcServer, &ipcSession), VERR_CANCELLED);
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS);
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
+
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "Waiting for thread to exit ...\n");
+ RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
+ 30 * 1000 /* 30s timeout */, NULL), VINF_SUCCESS);
+ } while (0);
+ }
+ else
+ RTTestIFailed("Unable to create thread for cancelling server, rc=%Rrc\n", rc);
+ }
+ else
+ RTTestIFailed("Unable to create IPC server, rc=%Rrc\n", rc);
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) testSessionConnectionThread(RTTHREAD hSelf, void *pvUser)
+{
+ PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser;
+ AssertPtr(pCtx);
+
+ int rc;
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Listening for incoming connections ...\n");
+ for (;;)
+ {
+ RTLOCALIPCSESSION ipcSession;
+ rc = RTLocalIpcServerListen(pCtx->hServer, &ipcSession);
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_DEBUG, "testSessionConnectionThread: Listening returned with rc=%Rrc\n", rc);
+ if (RT_SUCCESS(rc))
+ {
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Got new client connection\n");
+ }
+ else
+ break;
+ }
+
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Ended with rc=%Rrc\n", rc);
+ return rc;
+}
+
+static RTEXITCODE testSessionConnectionChild(int argc, char **argv, RTTEST hTest)
+{
+ do
+ {
+ RTThreadSleep(2000); /* Fudge */
+ RTLOCALIPCSESSION clientSession;
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&clientSession, "tstRTLocalIpcSessionConnection",
+ 0 /* Flags */), VINF_SUCCESS);
+ RTThreadSleep(5000); /* Fudge */
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(clientSession), VINF_SUCCESS);
+
+ } while (0);
+
+ return !RTTestErrorCount(hTest) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static int testSessionConnection(RTTEST hTest, const char *pszExecPath)
+{
+ RTTestSub(hTest, "testSessionConnection");
+
+ RTLOCALIPCSERVER ipcServer;
+ int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionConnection",
+ RTLOCALIPC_FLAGS_MULTI_SESSION);
+ if (RT_SUCCESS(rc))
+ {
+#ifndef VBOX_TESTCASES_WITH_NO_THREADING
+ LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };
+
+ /* Spawn a simple worker thread and let it listen for incoming connections.
+ * In the meanwhile we try to cancel the server and see what happens. */
+ RTTHREAD hThread;
+ rc = RTThreadCreate(&hThread, testSessionConnectionThread,
+ &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc2");
+ if (RT_SUCCESS(rc))
+ {
+ do
+ {
+ RTPROCESS hProc;
+ const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionConnectionFork", NULL };
+ RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
+ RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
+ RTPROCSTATUS stsChild;
+ RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated, waiting for server thread ...\n");
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS);
+ int threadRc;
+ RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
+ 30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS);
+ RTTEST_CHECK_RC_BREAK(hTest, threadRc, VERR_CANCELLED);
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
+ RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
+ RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
+ }
+ while (0);
+ }
+ else
+ RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
+#else
+ do
+ {
+ RTPROCESS hProc;
+ const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionConnectionFork", NULL };
+ RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
+ RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
+ RTLOCALIPCSESSION ipcSession;
+ rc = RTLocalIpcServerListen(ipcServer, &ipcSession);
+ if (RT_SUCCESS(rc))
+ {
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Got new client connection\n");
+ }
+ else
+ RTTestFailed(hTest, "Error while listening, rc=%Rrc\n", rc);
+
+ } while (0);
+#endif
+ }
+ else
+ RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) testSessionWaitThread(RTTHREAD hSelf, void *pvUser)
+{
+ PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser;
+ AssertPtr(pCtx);
+
+ int rc;
+ for (;;)
+ {
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening for incoming connections ...\n");
+ RTLOCALIPCSESSION ipcSession;
+ rc = RTLocalIpcServerListen(pCtx->hServer, &ipcSession);
+ if (RT_SUCCESS(rc))
+ {
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Got new client connection, waiting a bit ...\n");
+ RTThreadSleep(2000);
+ rc = RTLocalIpcSessionClose(ipcSession);
+ }
+ else
+ {
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening ended with rc=%Rrc\n", rc);
+ break;
+ }
+ }
+
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Ended with rc=%Rrc\n", rc);
+ return rc;
+}
+
+static RTEXITCODE testSessionWaitChild(int argc, char **argv, RTTEST hTest)
+{
+ do
+ {
+ RTThreadSleep(2000); /* Fudge. */
+ RTLOCALIPCSESSION clientSession;
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&clientSession, "tstRTLocalIpcSessionWait",
+ 0 /* Flags */), VINF_SUCCESS);
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 100 /* 100ms timeout */),
+ VERR_TIMEOUT);
+ /* Next, try 60s timeout. Should be returning way earlier because the server closed the
+ * connection after the first client connected. */
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 60 * 1000),
+ VERR_BROKEN_PIPE);
+ /* Last try, also should fail because the server should be not around anymore. */
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 5 * 1000),
+ VERR_BROKEN_PIPE);
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(clientSession), VINF_SUCCESS);
+
+ } while (0);
+
+ return !RTTestErrorCount(hTest) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static int testSessionWait(RTTEST hTest, const char *pszExecPath)
+{
+ RTTestSub(hTest, "testSessionWait");
+
+ RTLOCALIPCSERVER ipcServer;
+ int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionWait",
+ RTLOCALIPC_FLAGS_MULTI_SESSION);
+ if (RT_SUCCESS(rc))
+ {
+ LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };
+
+ /* Spawn a simple worker thread and let it listen for incoming connections.
+ * In the meanwhile we try to cancel the server and see what happens. */
+ RTTHREAD hThread;
+ rc = RTThreadCreate(&hThread, testSessionWaitThread,
+ &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc3");
+ if (RT_SUCCESS(rc))
+ {
+ do
+ {
+ RTPROCESS hProc;
+ const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionWaitFork", NULL };
+ RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
+ RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
+ RTThreadSleep(5000); /* Let the server run for some time ... */
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "Cancelling server listening\n");
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS);
+ /* Wait for the server thread to terminate. */
+ int threadRc;
+ RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
+ 30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS);
+ RTTEST_CHECK_RC_BREAK(hTest, threadRc, VERR_CANCELLED);
+ RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
+ /* Check if the child ran successfully. */
+ RTPROCSTATUS stsChild;
+ RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated\n");
+ RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
+ RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
+ }
+ while (0);
+ }
+ else
+ RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
+ }
+ else
+ RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * Simple structure holding the test IPC messages.
+ */
+typedef struct LOCALIPCTESTMSG
+{
+ /** The actual message. */
+ char szOp[255];
+} LOCALIPCTESTMSG, *PLOCALIPCTESTMSG;
+
+static int testSessionDataReadTestMsg(RTTEST hTest, RTLOCALIPCSESSION hSession,
+ void *pvBuffer, size_t cbBuffer, const char *pszMsg)
+{
+ AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszMsg, VERR_INVALID_POINTER);
+
+ void *pvBufCur = pvBuffer;
+ size_t cbReadTotal = 0;
+ for (;;)
+ {
+ size_t cbRead = RTRandU32Ex(1, sizeof(LOCALIPCTESTMSG) - cbReadTotal); /* Force a bit of fragmentation. */
+ RTTEST_CHECK_BREAK(hTest, cbRead);
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionRead(hSession, pvBufCur,
+ cbBuffer,
+ &cbRead), VINF_SUCCESS);
+ RTTEST_CHECK_BREAK(hTest, cbRead);
+ pvBufCur = (uint8_t *)pvBufCur + cbRead; /* Advance. */
+ cbReadTotal += cbRead;
+ RTTEST_CHECK_BREAK(hTest, cbReadTotal <= cbBuffer);
+ if (cbReadTotal >= sizeof(LOCALIPCTESTMSG)) /* Got a complete test message? */
+ {
+ RTTEST_CHECK_BREAK(hTest, cbReadTotal == sizeof(LOCALIPCTESTMSG));
+ PLOCALIPCTESTMSG pMsg = (PLOCALIPCTESTMSG)pvBuffer;
+ RTTEST_CHECK_BREAK(hTest, pMsg != NULL);
+ RTTEST_CHECK_BREAK(hTest, !RTStrCmp(pMsg->szOp, pszMsg));
+ break;
+ }
+ /* Try receiving next part of the message in another round. */
+ }
+
+ return !RTTestErrorCount(hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */;
+}
+
+static int testSessionDataThreadWorker(PLOCALIPCTHREADCTX pCtx)
+{
+ AssertPtr(pCtx);
+
+ size_t cbScratchBuf = _1K; /** @todo Make this random in future. */
+ uint8_t *pvScratchBuf = (uint8_t*)RTMemAlloc(cbScratchBuf);
+ RTTEST_CHECK_RET(pCtx->hTest, pvScratchBuf != NULL, VERR_NO_MEMORY);
+
+ do
+ {
+ /* Note: At the moment we only support one client per run. */
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Listening for incoming connections ...\n");
+ RTLOCALIPCSESSION hSession;
+ RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcServerListen(pCtx->hServer, &hSession), VINF_SUCCESS);
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Got new client connection\n");
+ uint32_t cRounds = 256; /** @todo Use RTRand(). */
+ /* Write how many rounds we're going to send data. */
+ RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcSessionWrite(hSession, &cRounds, sizeof(cRounds)), VINF_SUCCESS);
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Written number of rounds\n");
+ for (uint32_t i = 0; i < cRounds; i++)
+ {
+ LOCALIPCTESTMSG msg;
+ RTTEST_CHECK_BREAK(pCtx->hTest, RTStrPrintf(msg.szOp, sizeof(msg.szOp),
+ "YayIGotRound%RU32FromTheServer", i) > 0);
+ RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcSessionWrite(hSession, &msg, sizeof(msg)), VINF_SUCCESS);
+ }
+ if (!RTTestErrorCount(pCtx->hTest))
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Data successfully written\n");
+ /* Try to receive the same amount of rounds from the client. */
+ for (uint32_t i = 0; i < cRounds; i++)
+ {
+ RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT),
+ VINF_SUCCESS);
+ char szMsg[32];
+ RTTEST_CHECK_BREAK(pCtx->hTest, RTStrPrintf(szMsg, sizeof(szMsg), "YayIGotRound%RU32FromTheClient", i) > 0);
+ RTTEST_CHECK_RC_BREAK(pCtx->hTest, testSessionDataReadTestMsg(pCtx->hTest, hSession,
+ pvScratchBuf, cbScratchBuf,
+ szMsg), VINF_SUCCESS);
+ if (RTTestErrorCount(pCtx->hTest))
+ break;
+ }
+ if (!RTTestErrorCount(pCtx->hTest))
+ RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Data successfully read\n");
+ RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcSessionClose(hSession), VINF_SUCCESS);
+
+ } while (0);
+
+ RTMemFree(pvScratchBuf);
+ return !RTTestErrorCount(pCtx->hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */;
+}
+
+static DECLCALLBACK(int) testSessionDataThread(RTTHREAD hSelf, void *pvUser)
+{
+ PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser;
+ AssertPtr(pCtx);
+
+ return testSessionDataThreadWorker(pCtx);
+}
+
+static int testSessionDataChildWorker(RTTEST hTest)
+{
+ size_t cbScratchBuf = _1K; /** @todo Make this random in future. */
+ uint8_t *pvScratchBuf = (uint8_t*)RTMemAlloc(cbScratchBuf);
+ RTTEST_CHECK_RET(hTest, pvScratchBuf != NULL, RTEXITCODE_FAILURE);
+
+ do
+ {
+ RTThreadSleep(2000); /* Fudge. */
+ RTLOCALIPCSESSION hSession;
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&hSession, "tstRTLocalIpcSessionData",
+ 0 /* Flags */), VINF_SUCCESS);
+ /* Get number of rounds we want to read/write. */
+ uint32_t cRounds = 0;
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT),
+ VINF_SUCCESS);
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionRead(hSession, &cRounds, sizeof(cRounds),
+ NULL /* Get exactly sizeof(cRounds) bytes */), VINF_SUCCESS);
+ RTTEST_CHECK_BREAK(hTest, cRounds == 256); /** @todo Check for != 0 when using RTRand(). */
+ /* Receive all rounds. */
+ for (uint32_t i = 0; i < cRounds; i++)
+ {
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT),
+ VINF_SUCCESS);
+ char szMsg[32];
+ RTTEST_CHECK_BREAK(hTest, RTStrPrintf(szMsg, sizeof(szMsg), "YayIGotRound%RU32FromTheServer", i) > 0);
+ RTTEST_CHECK_RC_BREAK(hTest, testSessionDataReadTestMsg(hTest, hSession,
+ pvScratchBuf, cbScratchBuf,
+ szMsg), VINF_SUCCESS);
+ if (RTTestErrorCount(hTest))
+ break;
+ }
+ /* Send all rounds back to the server. */
+ for (uint32_t i = 0; i < cRounds; i++)
+ {
+ LOCALIPCTESTMSG msg;
+ RTTEST_CHECK_BREAK(hTest, RTStrPrintf(msg.szOp, sizeof(msg.szOp),
+ "YayIGotRound%RU32FromTheClient", i) > 0);
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWrite(hSession, &msg, sizeof(msg)), VINF_SUCCESS);
+ }
+ RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(hSession), VINF_SUCCESS);
+
+ } while (0);
+
+ RTMemFree(pvScratchBuf);
+ return !RTTestErrorCount(hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */;
+}
+
+static DECLCALLBACK(int) testSessionDataChildAsThread(RTTHREAD hSelf, void *pvUser)
+{
+ PRTTEST phTest = (PRTTEST)pvUser;
+ AssertPtr(phTest);
+ return testSessionDataChildWorker(*phTest);
+}
+
+static RTEXITCODE testSessionDataChild(int argc, char **argv, RTTEST hTest)
+{
+ return RT_SUCCESS(testSessionDataChildWorker(hTest)) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static int testSessionData(RTTEST hTest, const char *pszExecPath)
+{
+ RTTestSub(hTest, "testSessionData");
+
+ RTLOCALIPCSERVER ipcServer;
+ int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionData",
+ RTLOCALIPC_FLAGS_MULTI_SESSION);
+ if (RT_SUCCESS(rc))
+ {
+ LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };
+#if 0
+ /* Run server + client in threads instead of fork'ed processes (useful for debugging). */
+ RTTHREAD hThreadServer, hThreadClient;
+ rc = RTThreadCreate(&hThreadServer, testSessionDataThread,
+ &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc4");
+ if (RT_SUCCESS(rc))
+ rc = RTThreadCreate(&hThreadClient, testSessionDataChildAsThread,
+ &hTest, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc5");
+ if (RT_SUCCESS(rc))
+ {
+ do
+ {
+ int threadRc;
+ RTTEST_CHECK_RC(hTest, RTThreadWait(hThreadServer,
+ 5 * 60 * 1000 /* 5 minutes timeout */, &threadRc), VINF_SUCCESS);
+ RTTEST_CHECK_RC_BREAK(hTest, threadRc, VINF_SUCCESS);
+ RTTEST_CHECK_RC(hTest, RTThreadWait(hThreadClient,
+ 5 * 60 * 1000 /* 5 minutes timeout */, &threadRc), VINF_SUCCESS);
+ RTTEST_CHECK_RC_BREAK(hTest, threadRc, VINF_SUCCESS);
+
+ } while (0);
+ }
+#else
+ /* Spawn a simple worker thread and let it listen for incoming connections.
+ * In the meanwhile we try to cancel the server and see what happens. */
+ RTTHREAD hThread;
+ rc = RTThreadCreate(&hThread, testSessionDataThread,
+ &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc4");
+ if (RT_SUCCESS(rc))
+ {
+ do
+ {
+ RTPROCESS hProc;
+ const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionDataFork", NULL };
+ RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
+ RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
+ /* Wait for the server thread to terminate. */
+ int threadRc;
+ RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
+ 5 * 60 * 1000 /* 5 minutes timeout */, &threadRc), VINF_SUCCESS);
+ RTTEST_CHECK_RC_BREAK(hTest, threadRc, VINF_SUCCESS);
+ RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
+ /* Check if the child ran successfully. */
+ RTPROCSTATUS stsChild;
+ RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated\n");
+ RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
+ RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
+ }
+ while (0);
+ }
+ else
+ RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
+#endif
+ }
+ else
+ RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
+
+ return !RTTestErrorCount(hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */;
+}
+
+static RTEXITCODE mainChild(int argc, char **argv)
+{
+ if (argc < 3) /* Safety first. */
+ return RTEXITCODE_FAILURE;
+ /* Note: We assume argv[2] always contains the actual test type to perform. */
+ RTTEST hTest;
+ RTEXITCODE rcExit = RTTestInitAndCreate(argv[2], &hTest);
+ if (rcExit)
+ return rcExit;
+ RTTestBanner(hTest);
+
+ RTAssertSetMayPanic(false);
+#ifdef DEBUG_andy
+ RTAssertSetQuiet(false);
+#endif
+
+ if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionConnectionFork"))
+ rcExit = testSessionConnectionChild(argc, argv, hTest);
+ else if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionWaitFork"))
+ rcExit = testSessionWaitChild(argc, argv, hTest);
+ else if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionDataFork"))
+ rcExit = testSessionDataChild(argc, argv, hTest);
+
+ return RTTestSummaryAndDestroy(hTest);
+}
+
+int main(int argc, char **argv)
+{
+ if ( argc > 2
+ && !RTStrICmp(argv[1], "child"))
+ return mainChild(argc, argv);
+
+ RTTEST hTest;
+ RTEXITCODE rcExit = RTTestInitAndCreate("tstRTLocalIpc", &hTest);
+ if (rcExit)
+ return rcExit;
+ RTTestBanner(hTest);
+
+ char szExecPath[RTPATH_MAX];
+ if (!RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
+ RTStrCopy(szExecPath, sizeof(szExecPath), argv[0]);
+
+ RTTestISub("Basics");
+
+ RTAssertSetMayPanic(false);
+#ifdef DEBUG_andy
+ RTAssertSetQuiet(false);
+#endif
+
+ /* Server-side. */
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(NULL, NULL, 0), VERR_INVALID_POINTER, 1);
+ RTLOCALIPCSERVER ipcServer;
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, NULL, 0), VERR_INVALID_POINTER, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, "", 0), VERR_INVALID_PARAMETER, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, "BasicTest", 0 /* Invalid flags */), VERR_INVALID_PARAMETER, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, "BasicTest", 1234 /* Invalid flags */), VERR_INVALID_PARAMETER, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerCancel(NULL), VERR_INVALID_HANDLE, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerDestroy(NULL), VINF_SUCCESS, 1);
+ /* Basic server creation / destruction. */
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, "BasicTest", RTLOCALIPC_FLAGS_MULTI_SESSION), VINF_SUCCESS, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS, 1);
+
+ /* Client-side (per session). */
+ RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(NULL, NULL, 0), VERR_INVALID_POINTER, 1);
+ RTLOCALIPCSESSION ipcSession;
+ RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&ipcSession, NULL, 0), VERR_INVALID_POINTER, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&ipcSession, "", 0), VERR_INVALID_PARAMETER, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&ipcSession, "BasicTest", 1234 /* Invalid flags */), VERR_INVALID_PARAMETER, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcSessionCancel(NULL), VERR_INVALID_HANDLE, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcSessionClose(NULL), VINF_SUCCESS, 1);
+ /* Basic client creation / destruction. */
+ RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&ipcSession, "BasicTest", 0), VERR_FILE_NOT_FOUND, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerCancel(ipcServer), VERR_INVALID_MAGIC, 1);
+ RTTESTI_CHECK_RC_RET(RTLocalIpcServerDestroy(ipcServer), VERR_INVALID_MAGIC, 1);
+
+ if (RTTestErrorCount(hTest) == 0)
+ {
+ RTTESTI_CHECK_RC_RET(testServerListenAndCancel(hTest, szExecPath), VINF_SUCCESS, 1);
+ RTTESTI_CHECK_RC_RET(testSessionConnection(hTest, szExecPath), VINF_SUCCESS, 1);
+ RTTESTI_CHECK_RC_RET(testSessionWait(hTest, szExecPath), VINF_SUCCESS, 1);
+ RTTESTI_CHECK_RC_RET(testSessionData(hTest, szExecPath), VINF_SUCCESS, 1);
+ }
+
+ /*
+ * Summary.
+ */
+ return RTTestSummaryAndDestroy(hTest);
+}
+
diff --git a/src/VBox/Runtime/testcase/tstRTLockValidator.cpp b/src/VBox/Runtime/testcase/tstRTLockValidator.cpp
index 7a323833..bda75195 100644
--- a/src/VBox/Runtime/testcase/tstRTLockValidator.cpp
+++ b/src/VBox/Runtime/testcase/tstRTLockValidator.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTManifest.cpp b/src/VBox/Runtime/testcase/tstRTManifest.cpp
index 65e5c26e..766d36f4 100644
--- a/src/VBox/Runtime/testcase/tstRTManifest.cpp
+++ b/src/VBox/Runtime/testcase/tstRTManifest.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTMemEf.cpp b/src/VBox/Runtime/testcase/tstRTMemEf.cpp
index e47eb5b8..904c6ed1 100644
--- a/src/VBox/Runtime/testcase/tstRTMemEf.cpp
+++ b/src/VBox/Runtime/testcase/tstRTMemEf.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTMemPool.cpp b/src/VBox/Runtime/testcase/tstRTMemPool.cpp
index 2956eb0f..fc59a8bd 100644
--- a/src/VBox/Runtime/testcase/tstRTMemPool.cpp
+++ b/src/VBox/Runtime/testcase/tstRTMemPool.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTMp-1.cpp b/src/VBox/Runtime/testcase/tstRTMp-1.cpp
new file mode 100644
index 00000000..4a09ba52
--- /dev/null
+++ b/src/VBox/Runtime/testcase/tstRTMp-1.cpp
@@ -0,0 +1,241 @@
+/* $Id: tstRTMp-1.cpp $ */
+/** @file
+ * IPRT Testcase - RTMp.
+ */
+
+/*
+ * Copyright (C) 2008-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/mp.h>
+#include <iprt/cpuset.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+
+
+int main()
+{
+ RTTEST hTest;
+ RTEXITCODE rcExit = RTTestInitAndCreate("tstRTMp-1", &hTest);
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return rcExit;
+ RTTestBanner(hTest);
+
+ /*
+ * Present and possible CPUs.
+ */
+ RTCPUID cCpus = RTMpGetCount();
+ if (cCpus > 0)
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetCount -> %u\n", cCpus);
+ else
+ {
+ RTTestIFailed("RTMpGetCount returned zero");
+ cCpus = 1;
+ }
+
+ RTCPUID cCoreCpus = RTMpGetCoreCount();
+ if (cCoreCpus > 0)
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetCoreCount -> %d\n", (int)cCoreCpus);
+ else
+ {
+ RTTestIFailed("RTMpGetCoreCount returned zero");
+ cCoreCpus = 1;
+ }
+ RTTESTI_CHECK(cCoreCpus <= cCpus);
+
+ RTCPUSET Set;
+ PRTCPUSET pSet = RTMpGetSet(&Set);
+ RTTESTI_CHECK(pSet == &Set);
+ if (pSet == &Set)
+ {
+ RTTESTI_CHECK((RTCPUID)RTCpuSetCount(&Set) == cCpus);
+
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "Possible CPU mask:\n");
+ for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
+ {
+ RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu);
+ if (RTCpuSetIsMemberByIndex(&Set, iCpu))
+ {
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "%2d - id %d: %u/%u MHz", iCpu, (int)idCpu,
+ RTMpGetCurFrequency(idCpu), RTMpGetMaxFrequency(idCpu));
+ if (RTMpIsCpuPresent(idCpu))
+ RTTestIPrintf(RTTESTLVL_ALWAYS, RTMpIsCpuOnline(idCpu) ? " online\n" : " offline\n");
+ else
+ {
+ if (!RTMpIsCpuOnline(idCpu))
+ RTTestIPrintf(RTTESTLVL_ALWAYS, " absent\n");
+ else
+ {
+ RTTestIPrintf(RTTESTLVL_ALWAYS, " online but absent!\n");
+ RTTestIFailed("Cpu with index %d is report as !RTIsCpuPresent while RTIsCpuOnline returns true!\n", iCpu);
+ }
+ }
+ if (!RTMpIsCpuPossible(idCpu))
+ RTTestIFailed("Cpu with index %d is returned by RTCpuSet but not RTMpIsCpuPossible!\n", iCpu);
+ }
+ else if (RTMpIsCpuPossible(idCpu))
+ RTTestIFailed("Cpu with index %d is returned by RTMpIsCpuPossible but not RTCpuSet!\n", iCpu);
+ else if (RTMpGetCurFrequency(idCpu) != 0)
+ RTTestIFailed("RTMpGetCurFrequency(%d[idx=%d]) didn't return 0 as it should\n", (int)idCpu, iCpu);
+ else if (RTMpGetMaxFrequency(idCpu) != 0)
+ RTTestIFailed("RTMpGetMaxFrequency(%d[idx=%d]) didn't return 0 as it should\n", (int)idCpu, iCpu);
+ }
+ }
+ else
+ {
+ RTCpuSetEmpty(&Set);
+ RTCpuSetAdd(&Set, RTMpCpuIdFromSetIndex(0));
+ }
+
+ /*
+ * Online CPUs.
+ */
+ RTCPUID cCpusOnline = RTMpGetOnlineCount();
+ if (cCpusOnline > 0)
+ {
+ if (cCpusOnline <= cCpus)
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetOnlineCount -> %d\n", (int)cCpusOnline);
+ else
+ {
+ RTTestIFailed("RTMpGetOnlineCount -> %d, expected <= %d\n", (int)cCpusOnline, (int)cCpus);
+ cCpusOnline = cCpus;
+ }
+ }
+ else
+ {
+ RTTestIFailed("RTMpGetOnlineCount -> %d\n", (int)cCpusOnline);
+ cCpusOnline = 1;
+ }
+
+ RTCPUID cCoresOnline = RTMpGetOnlineCoreCount();
+ if (cCoresOnline > 0)
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetOnlineCoreCount -> %d\n", (int)cCoresOnline);
+ else
+ {
+ RTTestIFailed("RTMpGetOnlineCoreCount -> %d, expected <= %d\n", (int)cCoresOnline, (int)cCpusOnline);
+ cCoresOnline = 1;
+ }
+ RTTESTI_CHECK(cCoresOnline <= cCpusOnline);
+
+ RTCPUSET SetOnline;
+ pSet = RTMpGetOnlineSet(&SetOnline);
+ if (pSet == &SetOnline)
+ {
+ if (RTCpuSetCount(&SetOnline) <= 0)
+ RTTestIFailed("RTMpGetOnlineSet returned an empty set!\n");
+ else if ((RTCPUID)RTCpuSetCount(&SetOnline) > cCpus)
+ RTTestIFailed("RTMpGetOnlineSet returned a too high value; %d, expected <= %d\n",
+ RTCpuSetCount(&SetOnline), cCpus);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "Online CPU mask:\n");
+ for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
+ if (RTCpuSetIsMemberByIndex(&SetOnline, iCpu))
+ {
+ RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "%2d - id %d: %u/%u MHz %s\n", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu),
+ RTMpGetMaxFrequency(idCpu), RTMpIsCpuOnline(idCpu) ? "online" : "offline");
+ if (!RTCpuSetIsMemberByIndex(&Set, iCpu))
+ RTTestIFailed("online cpu with index %2d is not a member of the possible cpu set!\n", iCpu);
+ }
+
+ /* There isn't any sane way of testing RTMpIsCpuOnline really... :-/ */
+ }
+ else
+ RTTestIFailed("RTMpGetOnlineSet -> %p, expected %p\n", pSet, &Set);
+
+ /*
+ * Present CPUs.
+ */
+ RTCPUID cCpusPresent = RTMpGetPresentCount();
+ if (cCpusPresent > 0)
+ {
+ if ( cCpusPresent <= cCpus
+ && cCpusPresent >= cCpusOnline)
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetPresentCount -> %d\n", (int)cCpusPresent);
+ else
+ RTTestIFailed("RTMpGetPresentCount -> %d, expected <= %d and >= %d\n",
+ (int)cCpusPresent, (int)cCpus, (int)cCpusOnline);
+ }
+ else
+ {
+ RTTestIFailed("RTMpGetPresentCount -> %d\n", (int)cCpusPresent);
+ cCpusPresent = 1;
+ }
+
+ RTCPUSET SetPresent;
+ pSet = RTMpGetPresentSet(&SetPresent);
+ if (pSet == &SetPresent)
+ {
+ if (RTCpuSetCount(&SetPresent) <= 0)
+ RTTestIFailed("RTMpGetPresentSet returned an empty set!\n");
+ else if ((RTCPUID)RTCpuSetCount(&SetPresent) != cCpusPresent)
+ RTTestIFailed("RTMpGetPresentSet returned a bad value; %d, expected = %d\n",
+ RTCpuSetCount(&SetPresent), cCpusPresent);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "Present CPU mask:\n");
+ for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
+ if (RTCpuSetIsMemberByIndex(&SetPresent, iCpu))
+ {
+ RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "%2d - id %d: %u/%u MHz %s\n", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu),
+ RTMpGetMaxFrequency(idCpu), RTMpIsCpuPresent(idCpu) ? "present" : "absent");
+ if (!RTCpuSetIsMemberByIndex(&Set, iCpu))
+ RTTestIFailed("online cpu with index %2d is not a member of the possible cpu set!\n", iCpu);
+ }
+
+ /* There isn't any sane way of testing RTMpIsCpuPresent really... :-/ */
+ }
+ else
+ RTTestIFailed("RTMpGetPresentSet -> %p, expected %p\n", pSet, &Set);
+
+
+ /* Find an online cpu for the next test. */
+ RTCPUID idCpuOnline;
+ for (idCpuOnline = 0; idCpuOnline < RTCPUSET_MAX_CPUS; idCpuOnline++)
+ if (RTMpIsCpuOnline(idCpuOnline))
+ break;
+
+ /*
+ * Quick test of RTMpGetDescription.
+ */
+ char szBuf[64];
+ int rc = RTMpGetDescription(idCpuOnline, &szBuf[0], sizeof(szBuf));
+ if (RT_SUCCESS(rc))
+ {
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetDescription -> '%s'\n", szBuf);
+
+ size_t cch = strlen(szBuf);
+ rc = RTMpGetDescription(idCpuOnline, &szBuf[0], cch);
+ if (rc != VERR_BUFFER_OVERFLOW)
+ RTTestIFailed("RTMpGetDescription -> %Rrc, expected VERR_BUFFER_OVERFLOW\n", rc);
+
+ rc = RTMpGetDescription(idCpuOnline, &szBuf[0], cch + 1);
+ if (RT_FAILURE(rc))
+ RTTestIFailed("RTMpGetDescription -> %Rrc, expected VINF_SUCCESS\n", rc);
+ }
+ else
+ RTTestIFailed("RTMpGetDescription -> %Rrc\n", rc);
+
+ return RTTestSummaryAndDestroy(hTest);
+}
+
diff --git a/src/VBox/Runtime/testcase/tstRTPath.cpp b/src/VBox/Runtime/testcase/tstRTPath.cpp
index cd97f55f..131466a7 100644
--- a/src/VBox/Runtime/testcase/tstRTPath.cpp
+++ b/src/VBox/Runtime/testcase/tstRTPath.cpp
@@ -38,6 +38,160 @@
#include <iprt/test.h>
+static void testParserAndSplitter(RTTEST hTest)
+{
+ static struct
+ {
+ uint16_t cComps;
+ uint16_t cchPath;
+ uint16_t offSuffix;
+ const char *pszPath;
+ uint16_t fProps;
+ uint32_t fFlags;
+ } const s_aTests[] =
+ {
+ { 2, 5, 5, "/bin/", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_DIR_SLASH, RTPATH_STR_F_STYLE_UNIX },
+ { 2, 13, 9, "C:/Config.sys", RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_SUFFIX, RTPATH_STR_F_STYLE_DOS },
+ { 2, 13, 10, "C://Config.sys", RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_SUFFIX | RTPATH_PROP_EXTRA_SLASHES, RTPATH_STR_F_STYLE_DOS },
+ { 2, 12, 8, "C:Config.sys", RTPATH_PROP_VOLUME | RTPATH_PROP_RELATIVE | RTPATH_PROP_FILENAME | RTPATH_PROP_SUFFIX, RTPATH_STR_F_STYLE_DOS },
+ { 1, 10, 6, "Config.sys", RTPATH_PROP_RELATIVE | RTPATH_PROP_FILENAME | RTPATH_PROP_SUFFIX, RTPATH_STR_F_STYLE_DOS },
+ { 1, 4, 4, "//./", RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE, RTPATH_STR_F_STYLE_DOS },
+ { 2, 5, 5, "//./f", RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_DOS },
+ { 2, 5, 6, "//.//f", RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_EXTRA_SLASHES, RTPATH_STR_F_STYLE_DOS },
+ { 3, 7, 7, "//././f", RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_DOT_REFS, RTPATH_STR_F_STYLE_DOS },
+ { 3, 8, 8, "//.././f", RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_DOT_REFS, RTPATH_STR_F_STYLE_DOS },
+ { 3, 9, 9, "//../../f", RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_RELATIVE | RTPATH_PROP_FILENAME | RTPATH_PROP_DOTDOT_REFS, RTPATH_STR_F_STYLE_DOS },
+ { 1, 1, 1, "/", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE, RTPATH_STR_F_STYLE_UNIX },
+ { 2, 4, 4, "/bin", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 2, 5, 5, "/bin/", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_DIR_SLASH, RTPATH_STR_F_STYLE_UNIX },
+ { 3, 7, 7, "/bin/ls", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 3, 12, 7, "/etc/rc.conf", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_SUFFIX, RTPATH_STR_F_STYLE_UNIX },
+ { 1, 1, 2, "//", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_EXTRA_SLASHES, RTPATH_STR_F_STYLE_UNIX },
+ { 1, 1, 3, "///", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_EXTRA_SLASHES, RTPATH_STR_F_STYLE_UNIX },
+ { 3, 6, 7, "/.//bin", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_EXTRA_SLASHES | RTPATH_PROP_DOT_REFS | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 1, 3, 3, "bin", RTPATH_PROP_RELATIVE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 1, 4, 4, "bin/", RTPATH_PROP_RELATIVE | RTPATH_PROP_DIR_SLASH, RTPATH_STR_F_STYLE_UNIX },
+ { 1, 4, 7, "bin////", RTPATH_PROP_RELATIVE | RTPATH_PROP_DIR_SLASH | RTPATH_PROP_EXTRA_SLASHES, RTPATH_STR_F_STYLE_UNIX },
+ { 3, 10, 10, "bin/../usr", RTPATH_PROP_RELATIVE | RTPATH_PROP_DOTDOT_REFS | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 4, 11, 11, "/bin/../usr", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_RELATIVE | RTPATH_PROP_DOTDOT_REFS | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 4, 8, 8, "/a/.../u", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 4, 8, 8, "/a/.b./u", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 4, 8, 8, "/a/..c/u", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 4, 8, 8, "/a/d../u", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 4, 8, 8, "/a/.e/.u", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 4, 8, 8, "/a/.f/.u", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 4, 8, 8, "/a/.g/u.", RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME, RTPATH_STR_F_STYLE_UNIX },
+ { 3, 9, 10, "/a/h/u.ext", RTPATH_PROP_EXTRA_SLASHES | RTPATH_PROP_RELATIVE, RTPATH_STR_F_STYLE_UNIX | RTPATH_STR_F_MIDDLE },
+ { 3, 9, 9, "a/h/u.ext", RTPATH_PROP_RELATIVE, RTPATH_STR_F_STYLE_UNIX | RTPATH_STR_F_MIDDLE },
+ { 3, 9, 10, "a/h/u.ext/", RTPATH_PROP_EXTRA_SLASHES | RTPATH_PROP_RELATIVE, RTPATH_STR_F_STYLE_UNIX | RTPATH_STR_F_MIDDLE },
+ };
+
+ char szPath1[RTPATH_MAX];
+ union
+ {
+ RTPATHPARSED Parsed;
+ RTPATHSPLIT Split;
+ uint8_t ab[4096];
+ } u;
+
+ RTTestSub(hTest, "RTPathParse");
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aTests); i++)
+ {
+ memset(&u, i & 1 ? 0xff : 0, sizeof(u));
+ int rc = RTPathParse(s_aTests[i].pszPath, &u.Parsed, sizeof(u), s_aTests[i].fFlags);
+ if ( rc != VINF_SUCCESS
+ || s_aTests[i].cComps != u.Parsed.cComps
+ || s_aTests[i].fProps != u.Parsed.fProps
+ || s_aTests[i].offSuffix != u.Parsed.offSuffix
+ || s_aTests[i].cchPath != u.Parsed.cchPath)
+ {
+ RTTestFailed(hTest, "i=%d rc=%Rrc %s", i, rc, s_aTests[i].pszPath);
+ RTTestFailureDetails(hTest,
+ " cComps %u, got %u\n"
+ " fProps %#x, got %#x, xor=>%#x\n"
+ " offSuffix %u, got %u\n"
+ " cchPath %u, got %u\n"
+ ,
+ s_aTests[i].cComps, u.Parsed.cComps,
+ s_aTests[i].fProps, u.Parsed.fProps, s_aTests[i].fProps ^ u.Parsed.fProps,
+ s_aTests[i].offSuffix, u.Parsed.offSuffix,
+ s_aTests[i].cchPath, u.Parsed.cchPath);
+ }
+ else
+ {
+ rc = RTPathParsedReassemble(s_aTests[i].pszPath, &u.Parsed, s_aTests[i].fFlags & ~RTPATH_STR_F_MIDDLE,
+ szPath1, sizeof(szPath1));
+ if (rc == VINF_SUCCESS)
+ {
+ RTTESTI_CHECK_MSG(strlen(szPath1) == s_aTests[i].cchPath, ("%s\n", szPath1));
+ if ( !(u.Parsed.fProps & RTPATH_PROP_EXTRA_SLASHES)
+ && (s_aTests[i].fFlags & RTPATH_STR_F_STYLE_MASK) != RTPATH_STR_F_STYLE_DOS)
+ RTTESTI_CHECK_MSG(strcmp(szPath1, s_aTests[i].pszPath) == 0, ("%s\n", szPath1));
+ }
+ else
+ RTTestIFailed("RTPathParsedReassemble -> %Rrc", rc);
+ }
+ }
+
+ RTTestSub(hTest, "RTPathSplit");
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aTests); i++)
+ {
+ memset(&u, i & 1 ? 0xff : 0, sizeof(u));
+ int rc = RTPathSplit(s_aTests[i].pszPath, &u.Split, sizeof(u), s_aTests[i].fFlags);
+ if ( rc != VINF_SUCCESS
+ || s_aTests[i].cComps != u.Split.cComps
+ || s_aTests[i].fProps != u.Split.fProps
+ || s_aTests[i].cchPath != u.Split.cchPath)
+ {
+ RTTestFailed(hTest, "i=%d rc=%Rrc %s", i, rc, s_aTests[i].pszPath);
+ RTTestFailureDetails(hTest,
+ " cComps %u, got %u\n"
+ " fProps %#x, got %#x, xor=>%#x\n"
+ " cchPath %u, got %u\n"
+ ,
+ s_aTests[i].cComps, u.Split.cComps,
+ s_aTests[i].fProps, u.Split.fProps, s_aTests[i].fProps ^ u.Split.fProps,
+ s_aTests[i].cchPath, u.Split.cchPath);
+ }
+ else
+ {
+ RTTESTI_CHECK_MSG(*u.Split.pszSuffix == '\0' || *u.Split.pszSuffix == '.', ("%s", u.Split.pszSuffix));
+ for (uint32_t idxComp = RTPATH_PROP_HAS_ROOT_SPEC(u.Split.fProps); idxComp < u.Split.cComps; idxComp++)
+ if ( (s_aTests[i].fFlags & RTPATH_STR_F_STYLE_MASK) == RTPATH_STR_F_STYLE_DOS
+ ? strpbrk(u.Split.apszComps[idxComp], "/\\")
+ : strchr(u.Split.apszComps[idxComp], RTPATH_SLASH) )
+ RTTestFailed(hTest, "i=%d idxComp=%d '%s'", i, idxComp, u.Split.apszComps[idxComp]);
+
+ PRTPATHSPLIT pSplit = NULL;
+ RTTESTI_CHECK_RC(rc = RTPathSplitA(s_aTests[i].pszPath, &pSplit, s_aTests[i].fFlags), VINF_SUCCESS);
+ if (RT_SUCCESS(rc))
+ {
+ RTTESTI_CHECK(pSplit);
+ RTTESTI_CHECK(pSplit->cComps == u.Split.cComps);
+ RTTESTI_CHECK(pSplit->fProps == u.Split.fProps);
+ RTTESTI_CHECK(pSplit->cchPath == u.Split.cchPath);
+ RTTESTI_CHECK(pSplit->cbNeeded == u.Split.cbNeeded);
+ RTTESTI_CHECK(!strcmp(pSplit->pszSuffix, u.Split.pszSuffix));
+ for (uint32_t idxComp = 0; idxComp < u.Split.cComps; idxComp++)
+ RTTESTI_CHECK(!strcmp(pSplit->apszComps[idxComp], pSplit->apszComps[idxComp]));
+ RTPathSplitFree(pSplit);
+ }
+
+ rc = RTPathSplitReassemble(&u.Split, s_aTests[i].fFlags & ~RTPATH_STR_F_MIDDLE, szPath1, sizeof(szPath1));
+ if (rc == VINF_SUCCESS)
+ {
+ RTTESTI_CHECK_MSG(strlen(szPath1) == s_aTests[i].cchPath, ("%s\n", szPath1));
+ if ( !(u.Parsed.fProps & RTPATH_PROP_EXTRA_SLASHES)
+ && (s_aTests[i].fFlags & RTPATH_STR_F_STYLE_MASK) != RTPATH_STR_F_STYLE_DOS)
+ RTTESTI_CHECK_MSG(strcmp(szPath1, s_aTests[i].pszPath) == 0, ("%s\n", szPath1));
+ }
+ else
+ RTTestIFailed("RTPathSplitReassemble -> %Rrc", rc);
+ }
+ }
+}
+
+
int main()
{
char szPath[RTPATH_MAX];
@@ -51,6 +205,32 @@ int main()
return rc;
RTTestBanner(hTest);
+ RTTestSub(hTest, "Environment");
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+ RTTESTI_CHECK(RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS);
+# if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
+# else
+ RTTestIFailed("#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS");
+# endif
+ RTTESTI_CHECK(strcmp(RTPATH_SLASH_STR, "\\") == 0);
+ RTTESTI_CHECK(RTPATH_SLASH == '\\');
+ RTTESTI_CHECK(RTPATH_IS_SEP('/'));
+ RTTESTI_CHECK(RTPATH_IS_SEP('\\'));
+ RTTESTI_CHECK(RTPATH_IS_SEP(':'));
+
+#else
+ RTTESTI_CHECK(RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX);
+# if RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX
+# else
+ RTTestIFailed("#if RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX");
+# endif
+ RTTESTI_CHECK(strcmp(RTPATH_SLASH_STR, "/") == 0);
+ RTTESTI_CHECK(RTPATH_SLASH == '/');
+ RTTESTI_CHECK(RTPATH_IS_SEP('/'));
+ RTTESTI_CHECK(!RTPATH_IS_SEP('\\'));
+ RTTESTI_CHECK(!RTPATH_IS_SEP(':'));
+#endif
+
/*
* RTPathExecDir, RTPathUserHome and RTProcGetExecutablePath.
*/
@@ -553,6 +733,49 @@ int main()
pszInput, szPath, pszResult);
}
+ /*
+ * RTPathCalcRelative
+ */
+ RTTestSub(hTest, "RTPathCalcRelative");
+ struct
+ {
+ const char *pszFrom;
+ const char *pszTo;
+ int rc;
+ const char *pszExpected;
+ } s_aRelPath[] =
+ {
+ { "/home/test.ext", "/home/test2.ext", VINF_SUCCESS, "test2.ext"},
+ { "/dir/test.ext", "/dir/dir2/test2.ext", VINF_SUCCESS, "dir2/test2.ext"},
+ { "/dir/dir2/test.ext", "/dir/test2.ext", VINF_SUCCESS, "../test2.ext"},
+ { "/dir/dir2/test.ext", "/dir/dir3/test2.ext", VINF_SUCCESS, "../dir3/test2.ext"},
+#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+ { "\\\\server\\share\\test.ext", "\\\\server\\share2\\test2.ext", VERR_NOT_SUPPORTED, ""},
+ { "c:\\dir\\test.ext", "f:\\dir\\test.ext", VERR_NOT_SUPPORTED, ""}
+#endif
+ };
+ for (unsigned i = 0; i < RT_ELEMENTS(s_aRelPath); i++)
+ {
+ const char *pszFrom = s_aRelPath[i].pszFrom;
+ const char *pszTo = s_aRelPath[i].pszTo;
+
+ rc = RTPathCalcRelative(szPath, sizeof(szPath), pszFrom, pszTo);
+ if (rc != s_aRelPath[i].rc)
+ RTTestIFailed("Unexpected return code\n"
+ " got: %Rrc\n"
+ "expected: %Rrc",
+ rc, s_aRelPath[i].rc);
+ else if ( RT_SUCCESS(rc)
+ && strcmp(szPath, s_aRelPath[i].pszExpected))
+ RTTestIFailed("Unexpected result\n"
+ " from: '%s'\n"
+ " to: '%s'\n"
+ " output: '%s'\n"
+ "expected: '%s'",
+ pszFrom, pszTo, szPath, s_aRelPath[i].pszExpected);
+ }
+
+ testParserAndSplitter(hTest);
/*
* Summary.
diff --git a/src/VBox/Runtime/testcase/tstRTPipe.cpp b/src/VBox/Runtime/testcase/tstRTPipe.cpp
index 6944aef3..f0348993 100644
--- a/src/VBox/Runtime/testcase/tstRTPipe.cpp
+++ b/src/VBox/Runtime/testcase/tstRTPipe.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp b/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp
index 7e36c64a..af837a86 100644
--- a/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp
+++ b/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -170,8 +170,6 @@ static void tstRTCreateProcEx5(const char *pszUser, const char *pszPassword)
if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
- else
- RTTestIPassed(NULL);
}
@@ -207,8 +205,6 @@ static void tstRTCreateProcEx4(const char *pszAsUser, const char *pszPassword)
if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
- else
- RTTestIPassed(NULL);
}
@@ -277,8 +273,6 @@ static void tstRTCreateProcEx3(const char *pszAsUser, const char *pszPassword)
else if ( offOutput != sizeof("works") - 1
|| strcmp(szOutput, "works"))
RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
- else
- RTTestIPassed(NULL);
}
@@ -344,8 +338,6 @@ static void tstRTCreateProcEx2(const char *pszAsUser, const char *pszPassword)
else if ( offOutput != sizeof("howdy") - 1
|| strcmp(szOutput, "howdy"))
RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
- else
- RTTestIPassed(NULL);
}
@@ -411,8 +403,6 @@ static void tstRTCreateProcEx1(const char *pszAsUser, const char *pszPassword)
else if ( offOutput != sizeof("it works") - 1
|| strcmp(szOutput, "it works"))
RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
- else
- RTTestIPassed(NULL);
}
diff --git a/src/VBox/Runtime/testcase/tstRTProcCreatePrf.cpp b/src/VBox/Runtime/testcase/tstRTProcCreatePrf.cpp
index f17d0985..b2eaa26a 100644
--- a/src/VBox/Runtime/testcase/tstRTProcCreatePrf.cpp
+++ b/src/VBox/Runtime/testcase/tstRTProcCreatePrf.cpp
@@ -56,7 +56,7 @@ int main(int argc, char **argv)
uint64_t NsStart = RTTimeNanoTS();
uint32_t i;
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) || defined(RT_OS_DARWIN)
for (i = 0; i < 1000; i++)
#else
for (i = 0; i < 10000; i++)
@@ -81,4 +81,3 @@ int main(int argc, char **argv)
return RTTestSummaryAndDestroy(hTest);
}
-
diff --git a/src/VBox/Runtime/testcase/tstRTProcIsRunningByName.cpp b/src/VBox/Runtime/testcase/tstRTProcIsRunningByName.cpp
index c846f587..f784d949 100644
--- a/src/VBox/Runtime/testcase/tstRTProcIsRunningByName.cpp
+++ b/src/VBox/Runtime/testcase/tstRTProcIsRunningByName.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTProcWait.cpp b/src/VBox/Runtime/testcase/tstRTProcWait.cpp
index a4f45346..fb555678 100644
--- a/src/VBox/Runtime/testcase/tstRTProcWait.cpp
+++ b/src/VBox/Runtime/testcase/tstRTProcWait.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTR0Common.h b/src/VBox/Runtime/testcase/tstRTR0Common.h
index 196e5f9d..ed8a5a7e 100644
--- a/src/VBox/Runtime/testcase/tstRTR0Common.h
+++ b/src/VBox/Runtime/testcase/tstRTR0Common.h
@@ -176,6 +176,24 @@ static uint32_t volatile g_cErrors;
} \
} while (0)
+/**
+ * Macro for skipping a test in the ring-0 testcase.
+ */
+#define RTR0TESTR0_SKIP() \
+ do { \
+ RTR0TestR0Skip("line %u: SKIPPED", __LINE__); \
+ } while (0)
+
+/**
+ * Same as RTR0TESTR0_SKIP + break.
+ */
+#define RTR0TESTR0_SKIP_BREAK() \
+ if (1) \
+ { \
+ RTR0TestR0Skip("line %u: SKIPPED", __LINE__); \
+ break; \
+ } else do { } while (0)
+
/**
* Report an error.
@@ -244,6 +262,35 @@ void RTR0TestR0Info(const char *pszFormat, ...)
}
}
+
+/**
+ * Report an error.
+ */
+void RTR0TestR0Skip(const char *pszFormat, ...)
+{
+ size_t off = RTStrNLen(g_szErr, sizeof(g_szErr) - 1);
+ size_t cbLeft = sizeof(g_szErr) - off;
+ if (cbLeft > 10)
+ {
+ char *psz = &g_szErr[off];
+ if (off)
+ {
+ *psz++ = '\n';
+ *psz++ = '\n';
+ cbLeft -= 2;
+ }
+ *psz++ = '$';
+ cbLeft--;
+
+ va_list va;
+ va_start(va, pszFormat);
+ RTStrPrintfV(psz, cbLeft, pszFormat, va);
+ va_end(va);
+ }
+ ASMAtomicIncU32(&g_cErrors);
+}
+
+
/**
* Checks if we have any error reports.
*
diff --git a/src/VBox/Runtime/testcase/tstRTR0CommonDriver.h b/src/VBox/Runtime/testcase/tstRTR0CommonDriver.h
index b381383c..17d55667 100644
--- a/src/VBox/Runtime/testcase/tstRTR0CommonDriver.h
+++ b/src/VBox/Runtime/testcase/tstRTR0CommonDriver.h
@@ -177,7 +177,8 @@ static bool rtR3TestR0ProcessMessages(PRTTSTR0REQ pReq)
*
* We can have multiple failures and info messages packed into szMsg. They
* are separated by a double newline. The kind of message is indicated by
- * the first character, '!' means error and '?' means info message.
+ * the first character, '!' means error and '?' means info message. '$' means
+ * the test was skipped because a feature is not supported on the host.
*/
bool fRc = true;
if (pReq->szMsg[0])
@@ -189,7 +190,7 @@ static bool rtR3TestR0ProcessMessages(PRTTSTR0REQ pReq)
{
char *pszCur = pszNext;
do
- pszNext = strpbrk(pszNext + 1, "!?");
+ pszNext = strpbrk(pszNext + 1, "!?$");
while (pszNext && (pszNext[-1] != '\n' || pszNext[-2] != '\n'));
char *pszEnd = pszNext ? pszNext - 1 : strchr(pszCur, '\0');
@@ -202,6 +203,10 @@ static bool rtR3TestR0ProcessMessages(PRTTSTR0REQ pReq)
RTTestFailed(g_hTest, "%s", pszCur + 1);
fRc = false;
}
+ else if (*pszCur == '$')
+ {
+ RTTestSkipped(g_hTest, "%s", pszCur + 1);
+ }
else
RTTestPrintfNl(g_hTest, RTTESTLVL_ALWAYS, "%s", pszCur + 1);
} while (pszNext);
diff --git a/src/VBox/Runtime/testcase/tstRTR0DbgKrnlInfoDriver.cpp b/src/VBox/Runtime/testcase/tstRTR0DbgKrnlInfoDriver.cpp
index 2e3dff7e..2ffb761c 100644
--- a/src/VBox/Runtime/testcase/tstRTR0DbgKrnlInfoDriver.cpp
+++ b/src/VBox/Runtime/testcase/tstRTR0DbgKrnlInfoDriver.cpp
@@ -83,7 +83,7 @@ int main (int argc, char **argv)
void *pvImageBase;
rc = SUPR3LoadServiceModule(szPath, "tstRTR0DbgKrnlInfo",
- "tstRTR0DbgKrnlInfoSrvReqHandler",
+ "TSTR0DbgKrnlInfoSrvReqHandler",
&pvImageBase);
if (RT_FAILURE(rc))
{
@@ -120,8 +120,8 @@ int main (int argc, char **argv)
TSTRTR0DBGKRNLINFO_SANITY_FAILURE, 0, &Req.Hdr), VINF_SUCCESS);
if (RT_FAILURE(rc))
return RTTestSummaryAndDestroy(hTest);
- RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1), ("%s", Req.szMsg));
- if (strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1))
+ RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")), ("%s", Req.szMsg));
+ if (strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")))
return RTTestSummaryAndDestroy(hTest);
/*
diff --git a/src/VBox/Runtime/testcase/tstRTR0MemUserKernel.cpp b/src/VBox/Runtime/testcase/tstRTR0MemUserKernel.cpp
index 7b9a63f3..49c61d39 100644
--- a/src/VBox/Runtime/testcase/tstRTR0MemUserKernel.cpp
+++ b/src/VBox/Runtime/testcase/tstRTR0MemUserKernel.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTR0MemUserKernel.h b/src/VBox/Runtime/testcase/tstRTR0MemUserKernel.h
index 7efbeed5..c4795b1f 100644
--- a/src/VBox/Runtime/testcase/tstRTR0MemUserKernel.h
+++ b/src/VBox/Runtime/testcase/tstRTR0MemUserKernel.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTR0MemUserKernelDriver.cpp b/src/VBox/Runtime/testcase/tstRTR0MemUserKernelDriver.cpp
index dddcb775..e789dffc 100644
--- a/src/VBox/Runtime/testcase/tstRTR0MemUserKernelDriver.cpp
+++ b/src/VBox/Runtime/testcase/tstRTR0MemUserKernelDriver.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -121,8 +121,8 @@ int main(int argc, char **argv)
TSTRTR0MEMUSERKERNEL_SANITY_FAILURE, 0, &Req.Hdr), VINF_SUCCESS);
if (RT_FAILURE(rc))
return RTTestSummaryAndDestroy(hTest);
- RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1), ("%s", Req.szMsg));
- if (strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1))
+ RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")), ("%s", Req.szMsg));
+ if (strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")))
return RTTestSummaryAndDestroy(hTest);
/*
diff --git a/src/VBox/Runtime/testcase/tstRTR0SemMutex.cpp b/src/VBox/Runtime/testcase/tstRTR0SemMutex.cpp
index 8c17a095..b33ba500 100644
--- a/src/VBox/Runtime/testcase/tstRTR0SemMutex.cpp
+++ b/src/VBox/Runtime/testcase/tstRTR0SemMutex.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTR0SemMutexDriver.cpp b/src/VBox/Runtime/testcase/tstRTR0SemMutexDriver.cpp
index 62bfaabf..21ee35cd 100644
--- a/src/VBox/Runtime/testcase/tstRTR0SemMutexDriver.cpp
+++ b/src/VBox/Runtime/testcase/tstRTR0SemMutexDriver.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -237,8 +237,8 @@ int main(int argc, char **argv)
TSTRTR0SEMMUTEX_SANITY_FAILURE, 0, &Req.Hdr), VINF_SUCCESS);
if (RT_FAILURE(rc))
return RTTestSummaryAndDestroy(hTest);
- RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1), ("%s", Req.szMsg));
- if (strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1))
+ RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")), ("%s", Req.szMsg));
+ if (strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")))
return RTTestSummaryAndDestroy(hTest);
/*
diff --git a/src/VBox/Runtime/testcase/tstRTR0Timer.cpp b/src/VBox/Runtime/testcase/tstRTR0Timer.cpp
index 8e12602e..ad41354b 100644
--- a/src/VBox/Runtime/testcase/tstRTR0Timer.cpp
+++ b/src/VBox/Runtime/testcase/tstRTR0Timer.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,6 +31,7 @@
#include <iprt/timer.h>
#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
#include <iprt/cpuset.h>
#include <iprt/err.h>
#include <iprt/mem.h>
@@ -107,6 +108,53 @@ typedef struct TSTRTR0TIMEROMNI1
typedef TSTRTR0TIMEROMNI1 *PTSTRTR0TIMEROMNI1;
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * Latency data.
+ */
+static struct TSTRTR0TIMEROMNILATENCY
+{
+ /** The number of samples. */
+ volatile uint32_t cSamples;
+ uint32_t auPadding[3];
+ struct
+ {
+ uint64_t uTsc;
+ uint64_t uNanoTs;
+ } aSamples[4096];
+} g_aOmniLatency[16];
+
+
+/**
+ * Callback for the omni timer latency test, adds a sample to g_aOmniLatency.
+ *
+ * @param pTimer The timer.
+ * @param iTick The current tick.
+ * @param pvUser The user argument.
+ */
+static DECLCALLBACK(void) tstRTR0TimerCallbackLatencyOmni(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
+{
+ RTCPUID idCpu = RTMpCpuId();
+ uint32_t iCpu = RTMpCpuIdToSetIndex(idCpu);
+ NOREF(pTimer); NOREF(pvUser); NOREF(iTick);
+
+ RTR0TESTR0_CHECK_MSG(iCpu < RT_ELEMENTS(g_aOmniLatency), ("iCpu=%d idCpu=%u\n", iCpu, idCpu));
+ if (iCpu < RT_ELEMENTS(g_aOmniLatency))
+ {
+ uint32_t iSample = g_aOmniLatency[iCpu].cSamples;
+ if (iSample < RT_ELEMENTS(g_aOmniLatency[iCpu].aSamples))
+ {
+ g_aOmniLatency[iCpu].aSamples[iSample].uTsc = ASMReadTSC();
+ g_aOmniLatency[iCpu].aSamples[iSample].uNanoTs = RTTimeSystemNanoTS();
+ g_aOmniLatency[iCpu].cSamples = iSample + 1;
+ }
+ }
+}
+
+
+
/**
* Callback which increments a 32-bit counter.
*
@@ -394,33 +442,38 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
/* Create a one-shot timer and take one shot. */
PRTTIMER pTimer;
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
- RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State),
- VINF_SUCCESS);
+ int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TestR0Info("one-shot timer are not supported, skipping\n");
+ break;
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
do /* break loop */
{
- RT_ZERO(State);
+ RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
RTThreadSleep(5);
RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
/* check that it is restartable. */
- RT_ZERO(State);
+ RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
RTThreadSleep(5);
RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
/* check that it respects the timeout value and can be cancelled. */
- RT_ZERO(State);
+ RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
RTThreadSleep(1);
RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
/* Check some double starts and stops (shall not assert). */
- RT_ZERO(State);
+ RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 0), VERR_TIMER_ACTIVE);
RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
@@ -442,11 +495,17 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
for (uint32_t iTest = 0; iTest < 2; iTest++)
{
- RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State),
- VINF_SUCCESS);
+ int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TestR0Info("one-shot timer are not supported, skipping\n");
+ break;
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
RT_ZERO(State);
State.iActionShot = 0;
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
do /* break loop */
{
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
@@ -469,16 +528,22 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
for (uint32_t iTest = 0; iTest < 2; iTest++)
{
- RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State),
- VINF_SUCCESS);
+ int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TestR0Info("one-shot timer are not supported, skipping\n");
+ break;
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
RT_ZERO(State);
State.rc = VERR_IPE_UNINITIALIZED_STATUS;
State.iActionShot = 0;
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
do /* break loop */
{
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
- for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; i++)
+ for (uint32_t i = 0; i < 1000 && (ASMAtomicUoReadU32(&State.cShots) < 1 || State.rc == VERR_IPE_UNINITIALIZED_STATUS); i++)
RTThreadSleep(5);
RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
@@ -503,13 +568,14 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
State.iActionShot = 0;
State.rc = VINF_SUCCESS;
State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
fFlags |= RTTIMER_FLAGS_CPU(iCpu);
int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackSpecific, &State);
if (rc == VERR_NOT_SUPPORTED)
{
- RTR0TestR0Info("specific timer are not supported, skipping\n");
+ RTR0TestR0Info("one-shot specific timer are not supported, skipping\n");
break;
}
RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
@@ -556,6 +622,8 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
{
RT_ZERO(State);
State.fPeriodic = true;
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
+
uint64_t uStartNsTS = RTTimeSystemNanoTS();
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
@@ -584,6 +652,8 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
{
RT_ZERO(State);
State.fPeriodic = true;
+ ASMAtomicWriteU32(&State.cShots, State.cShots); /* ordered, necessary? */
+
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, i < 20 ? 0 : cNsSysHz), VINF_SUCCESS);
for (uint32_t k = 0; k < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; k++)
RTThreadSleep(1);
@@ -620,6 +690,7 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
State.u.ChgInt.cStepsBetween = u64Arg & 4 ? 1 : 3;
RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMinInterval > 1000, ("%u\n", State.u.ChgInt.cNsMinInterval));
RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMaxInterval > State.u.ChgInt.cNsMinInterval, ("max=%u min=%u\n", State.u.ChgInt.cNsMaxInterval, State.u.ChgInt.cNsMinInterval));
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
/* create the timer and check if RTTimerChangeInterval is supported. */
PRTTIMER pTimer;
@@ -663,6 +734,7 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
State.rc = VINF_SUCCESS;
State.fPeriodic = true;
State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
fFlags |= RTTIMER_FLAGS_CPU(iCpu);
@@ -714,8 +786,12 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
PRTTIMER pTimer;
uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
| RTTIMER_FLAGS_CPU_ALL;
- RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates),
- VINF_SUCCESS);
+ int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TESTR0_SKIP_BREAK();
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
for (uint32_t iTest = 0; iTest < 3 && !RTR0TestR0HaveErrors(); iTest++)
{
@@ -778,6 +854,72 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
RTMemFree(paStates);
break;
}
+
+ case TSTRTR0TIMER_LATENCY_OMNI:
+ case TSTRTR0TIMER_LATENCY_OMNI_HIRES:
+ {
+ /*
+ * Create a periodic timer running at max host frequency, but no more than 1000 Hz.
+ */
+ PRTTIMER pTimer;
+ uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
+ | RTTIMER_FLAGS_CPU_ALL;
+ uint32_t cNsInterval = cNsSysHz;
+ while (cNsInterval < UINT32_C(1000000))
+ cNsInterval *= 2;
+ int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackLatencyOmni, NULL);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TESTR0_SKIP_BREAK();
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
+
+ /*
+ * Reset the state and run the test for 4 seconds.
+ */
+ RT_ZERO(g_aOmniLatency);
+
+ RTCPUSET OnlineSet;
+ uint64_t uStartNsTS = RTTimeSystemNanoTS();
+ RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
+ RTMpGetOnlineSet(&OnlineSet);
+
+ for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT64_C(4000000000); i++)
+ RTThreadSleep(2);
+
+ RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
+ uint64_t cNsElapsedX = RTTimeNanoTS() - uStartNsTS;
+
+ /*
+ * Process the result.
+ */
+ int32_t cNsLow = cNsInterval / 4 * 3; /* 75% */
+ int32_t cNsHigh = cNsInterval / 4 * 5; /* 125% */
+ uint32_t cTotal = 0;
+ uint32_t cLow = 0;
+ uint32_t cHigh = 0;
+ for (uint32_t iCpu = 0; iCpu < RT_ELEMENTS(g_aOmniLatency); iCpu++)
+ {
+ uint32_t cSamples = g_aOmniLatency[iCpu].cSamples;
+ if (cSamples > 1)
+ {
+ cTotal += cSamples - 1;
+ for (uint32_t iSample = 1; iSample < cSamples; iSample++)
+ {
+ int64_t cNsDelta = g_aOmniLatency[iCpu].aSamples[iSample - 1].uNanoTs
+ - g_aOmniLatency[iCpu].aSamples[iSample].uNanoTs;
+ if (cNsDelta < cNsLow)
+ cLow++;
+ else if (cNsDelta > cNsHigh)
+ cHigh++;
+ }
+ }
+ }
+ RTR0TestR0Info("125%%: %u; 75%%: %u; total: %u", cHigh, cLow, cTotal);
+ RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
+ break;
+ }
+
}
RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
diff --git a/src/VBox/Runtime/testcase/tstRTR0Timer.h b/src/VBox/Runtime/testcase/tstRTR0Timer.h
index 8699490f..8edf273e 100644
--- a/src/VBox/Runtime/testcase/tstRTR0Timer.h
+++ b/src/VBox/Runtime/testcase/tstRTR0Timer.h
@@ -54,6 +54,8 @@ typedef enum TSTRTR0TIMER
TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES,
TSTRTR0TIMER_PERIODIC_OMNI,
TSTRTR0TIMER_PERIODIC_OMNI_HIRES,
+ TSTRTR0TIMER_LATENCY_OMNI,
+ TSTRTR0TIMER_LATENCY_OMNI_HIRES,
TSTRTR0TIMER_END
} TSTRTR0TIMER;
@@ -68,5 +70,6 @@ typedef enum TSTRTR0TIMER
|| (uOperation) == TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES \
|| (uOperation) == TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES \
|| (uOperation) == TSTRTR0TIMER_PERIODIC_OMNI_HIRES \
+ || (uOperation) == TSTRTR0TIMER_LATENCY_OMNI_HIRES \
)
diff --git a/src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp b/src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp
index 8b34cbd1..0fd6b3c8 100644
--- a/src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp
+++ b/src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp
@@ -56,47 +56,59 @@ int main(int argc, char **argv)
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
-# if 1
- /*
- * Standard timers.
- */
- RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_BASIC, "Basic one shot");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_BASIC, "Basic periodic");
- if (RTTestErrorCount(g_hTest) == 0)
+ if (argc == 2 && !strcmp(argv[1], "latency"))
{
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_LATENCY_OMNI, "Latency omni timer");
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_LATENCY_OMNI_HIRES, "Latency omni hires timer");
+ }
+ else
+ {
+# if 1
+ /*
+ * Standard timers.
+ */
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_BASIC, "Basic one shot");
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_BASIC, "Basic periodic");
+ if (RTTestErrorCount(g_hTest) == 0)
+ {
# if 1
- RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_RESTART, "Restart one shot from callback");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_DESTROY, "Destroy one shot from callback");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_CSSD_LOOPS, "Create-start-stop-destroy loops");
- for (uint32_t i = 0; i <= 7; i++)
- RTR3TestR0SimpleTestWithArg(TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL, i, "Change interval from callback, variation %u", i);
+# ifndef RT_OS_SOLARIS /* Solaris cannot call back into cyclic subsystem from a cyclic callback. */
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_RESTART, "Restart one shot from callback");
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_DESTROY, "Destroy one shot from callback");
+# endif
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_CSSD_LOOPS, "Create-start-stop-destroy loops");
+ for (uint32_t i = 0; i <= 7; i++)
+ RTR3TestR0SimpleTestWithArg(TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL, i, "Change interval from callback, variation %u", i);
# endif
- RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_SPECIFIC, "One shot cpu specific");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_SPECIFIC, "Periodic cpu specific");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_OMNI, "Periodic omni timer");
- }
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_SPECIFIC, "One shot cpu specific");
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_SPECIFIC, "Periodic cpu specific");
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_OMNI, "Periodic omni timer");
+ }
# endif
# if 1
- /*
- * High resolution timers.
- */
- RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES, "Basic hires one shot");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_BASIC_HIRES, "Basic hires periodic");
- if (RTTestErrorCount(g_hTest) == 0)
- {
+ /*
+ * High resolution timers.
+ */
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES, "Basic hires one shot");
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_BASIC_HIRES, "Basic hires periodic");
+ if (RTTestErrorCount(g_hTest) == 0)
+ {
# if 1
- RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES, "Restart hires one shot from callback");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES, "Destroy hires one shot from callback");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES, "Create-start-stop-destroy loops, hires");
- for (uint32_t i = 0; i <= 7; i++)
- RTR3TestR0SimpleTestWithArg(TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL, i, "Change interval from callback, hires, variation %u", i);
+# ifndef RT_OS_SOLARIS /* Solaris cannot call back into cyclic subsystem from a cyclic callback. */
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES, "Restart hires one shot from callback");
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES, "Destroy hires one shot from callback");
+# endif
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES, "Create-start-stop-destroy loops, hires");
+ for (uint32_t i = 0; i <= 7; i++)
+ RTR3TestR0SimpleTestWithArg(TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL, i, "Change interval from callback, hires, variation %u", i);
# endif
- RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_SPECIFIC_HIRES, "One shot hires cpu specific");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES, "Periodic hires cpu specific");
- RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_OMNI, "Periodic omni hires timer");
- }
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_SPECIFIC_HIRES, "One shot hires cpu specific");
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES, "Periodic hires cpu specific");
+ RTR3TestR0SimpleTest(TSTRTR0TIMER_PERIODIC_OMNI, "Periodic omni hires timer");
+ }
# endif
+ }
/*
* Done.
diff --git a/src/VBox/Runtime/testcase/tstRTS3.cpp b/src/VBox/Runtime/testcase/tstRTS3.cpp
index 6dda0054..3b5b0514 100644
--- a/src/VBox/Runtime/testcase/tstRTS3.cpp
+++ b/src/VBox/Runtime/testcase/tstRTS3.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTSemRW.cpp b/src/VBox/Runtime/testcase/tstRTSemRW.cpp
index 06575bce..ea2a7609 100644
--- a/src/VBox/Runtime/testcase/tstRTSemRW.cpp
+++ b/src/VBox/Runtime/testcase/tstRTSemRW.cpp
@@ -297,14 +297,17 @@ static void Test4(unsigned cThreads, unsigned cSeconds, unsigned uWritePercent,
}
- RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
- "Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n",
- cThreads,
- cItrTotal,
- cItrTotal / cSeconds,
- ElapsedNS / cItrTotal,
- cItrMaxDeviation * 100 / cItrNormal
- );
+ //RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
+ // "Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n",
+ // cThreads,
+ // cItrTotal,
+ // cItrTotal / cSeconds,
+ // ElapsedNS / cItrTotal,
+ // cItrMaxDeviation * 100 / cItrNormal
+ // );
+ //
+ RTTestValue(g_hTest, "Thruput", cItrTotal * UINT32_C(1000000000) / ElapsedNS, RTTESTUNIT_CALLS_PER_SEC);
+ RTTestValue(g_hTest, "Max diviation", cItrMaxDeviation * 100 / cItrNormal, RTTESTUNIT_PCT);
}
diff --git a/src/VBox/Runtime/testcase/tstRTSemXRoads.cpp b/src/VBox/Runtime/testcase/tstRTSemXRoads.cpp
index bd5f31a4..a6759a6f 100644
--- a/src/VBox/Runtime/testcase/tstRTSemXRoads.cpp
+++ b/src/VBox/Runtime/testcase/tstRTSemXRoads.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTStrAlloc.cpp b/src/VBox/Runtime/testcase/tstRTStrAlloc.cpp
index 6f49cb0e..b1240c2f 100644
--- a/src/VBox/Runtime/testcase/tstRTStrAlloc.cpp
+++ b/src/VBox/Runtime/testcase/tstRTStrAlloc.cpp
@@ -189,13 +189,13 @@ static void tst1(void)
/* RTStrAAppendExN / RTStrAAppendExNV */
psz = NULL;
- RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 5, "a", 1, "bc", 1, "cdefg", RTSTR_MAX, "hijkl", 2, "jklmnopqrstuvwxyz", RTSTR_MAX), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 5, "a", (size_t)1, "bc", (size_t)1, "cdefg", RTSTR_MAX, "hijkl", (size_t)2, "jklmnopqrstuvwxyz", RTSTR_MAX), VINF_SUCCESS);
RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz"));
RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 0), VINF_SUCCESS);
RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz"));
- RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 2, NULL, 0, "", 0), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 2, NULL, (size_t)0, "", (size_t)0), VINF_SUCCESS);
RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz"));
- RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 1, "-", 1), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 1, "-", (size_t)1), VINF_SUCCESS);
RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz-"));
RTStrFree(psz);
diff --git a/src/VBox/Runtime/testcase/tstRTStrCache.cpp b/src/VBox/Runtime/testcase/tstRTStrCache.cpp
index ef466554..15d9da86 100644
--- a/src/VBox/Runtime/testcase/tstRTStrCache.cpp
+++ b/src/VBox/Runtime/testcase/tstRTStrCache.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,12 +30,108 @@
#include <iprt/strcache.h>
#include <iprt/asm.h>
+#include <iprt/ctype.h>
#include <iprt/err.h>
#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/rand.h>
#include <iprt/string.h>
#include <iprt/test.h>
#include <iprt/thread.h>
-#include <iprt/rand.h>
+#include <iprt/time.h>
+
+
+static void tstShowStats(RTSTRCACHE hStrCache)
+{
+ size_t cbStrings;
+ size_t cbChunks;
+ size_t cbBigEntries;
+ uint32_t cHashCollisions;
+ uint32_t cHashCollisions2;
+ uint32_t cHashInserts;
+ uint32_t cRehashes;
+ uint32_t cStrings = RTStrCacheGetStats(hStrCache, &cbStrings, &cbChunks, &cbBigEntries,
+ &cHashCollisions, &cHashCollisions2, &cHashInserts, &cRehashes);
+ if (cbStrings == UINT32_MAX)
+ {
+ RTTESTI_CHECK(!RTStrCacheIsRealImpl());
+ return;
+ }
+
+ RTTestIValue("Strings", cStrings, RTTESTUNIT_OCCURRENCES);
+ RTTestIValue("Memory overhead", (uint64_t)(cbChunks + cbBigEntries - cbStrings) * 100 / cbStrings, RTTESTUNIT_PCT);
+ if (cHashInserts > 0)
+ {
+ RTTestIValue("Collisions", (uint64_t)cHashCollisions * 100 / cHashInserts, RTTESTUNIT_PCT);
+ RTTestIValue("Collisions2", (uint64_t)cHashCollisions2 * 100 / cHashInserts, RTTESTUNIT_PCT);
+ }
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "cHashInserts=%u cHashCollisions=%u cHashCollisions2=%u cRehashes=%u\n",
+ cHashInserts, cHashCollisions, cHashCollisions2, cRehashes);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "cbChunks=%zu cbBigEntries=%zu cbStrings=%zu\n", cbChunks, cbBigEntries, cbStrings);
+}
+
+
+/**
+ * Check hash and memory performance.
+ */
+static void tst2(void)
+{
+ RTTestISub("Hash performance");
+
+ /*
+ * Generate test strings using a specific pseudo random generator.
+ */
+ size_t cbStrings = 0;
+ char *apszTests[8192];
+ RTRAND hRand;
+ RTTESTI_CHECK_RC_RETV(RTRandAdvCreateParkMiller(&hRand), VINF_SUCCESS);
+ for (uint32_t i = 0; i < 8192; i++)
+ {
+ char szBuf[8192];
+ uint32_t cch = RTRandAdvU32Ex(hRand, 3, sizeof(szBuf) - 1);
+ RTRandAdvBytes(hRand, szBuf, cch);
+ szBuf[cch] = '\0';
+ for (uint32_t off = 0; off < cch; off++)
+ {
+ uint8_t b = szBuf[off];
+ b &= 0x7f;
+ if (!b || b == 0x7f)
+ b = ' ';
+ else if (RTLocCIsCntrl(b) && b != '\n' && b != '\r' && b != '\t')
+ b += 0x30;
+ szBuf[off] = b;
+ }
+ apszTests[i] = (char *)RTMemDup(szBuf, cch + 1);
+ RTTESTI_CHECK_RETV(apszTests[i] != NULL);
+ cbStrings += cch + 1;
+ }
+ RTRandAdvDestroy(hRand);
+ RTTestIValue("Average string", cbStrings / RT_ELEMENTS(apszTests), RTTESTUNIT_BYTES);
+
+ /*
+ * Test new insertion first time around.
+ */
+ RTSTRCACHE hStrCache;
+ RTTESTI_CHECK_RC_RETV(RTStrCacheCreate(&hStrCache, "hash performance"), VINF_SUCCESS);
+
+ uint64_t nsTsStart = RTTimeNanoTS();
+ for (uint32_t i = 0; i < RT_ELEMENTS(apszTests); i++)
+ RTTESTI_CHECK_RETV(RTStrCacheEnter(hStrCache, apszTests[i]) != NULL);
+ uint64_t cNsElapsed = RTTimeNanoTS() - nsTsStart;
+ RTTestIValue("First insert", cNsElapsed / RT_ELEMENTS(apszTests), RTTESTUNIT_NS_PER_CALL);
+
+ /*
+ * Insert existing strings.
+ */
+ nsTsStart = RTTimeNanoTS();
+ for (uint32_t i = 0; i < 8192; i++)
+ RTTESTI_CHECK(RTStrCacheEnter(hStrCache, apszTests[i]) != NULL);
+ cNsElapsed = RTTimeNanoTS() - nsTsStart;
+ RTTestIValue("Duplicate insert", cNsElapsed / RT_ELEMENTS(apszTests), RTTESTUNIT_NS_PER_CALL);
+
+ tstShowStats(hStrCache);
+ RTTESTI_CHECK_RC(RTStrCacheDestroy(hStrCache), VINF_SUCCESS);
+}
/**
@@ -87,8 +183,8 @@ static void tst1(RTSTRCACHE hStrCache)
RTTESTI_CHECK(RTStrCacheRetain(psz) == 4);
RTTESTI_CHECK(RTStrCacheRetain(psz) == 5);
RTTESTI_CHECK(RTStrCacheRetain(psz) == 6);
- RTTESTI_CHECK(RTStrCacheRelease(NIL_RTSTRCACHE, psz) == 5);
- RTTESTI_CHECK(RTStrCacheRelease(NIL_RTSTRCACHE, psz) == 4);
+ RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == 5);
+ RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == 4);
RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemIsAll8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz));
for (uint32_t cRefs = 3;; cRefs--)
@@ -107,6 +203,41 @@ static void tst1(RTSTRCACHE hStrCache)
}
}
}
+
+ /* Lots of allocations. */
+ memset(szTest, 'b', sizeof(szTest));
+ memset(szTest2, 'e', sizeof(szTest));
+ const char *pszTest1Rets[4096 + 16];
+ const char *pszTest2Rets[4096 + 16];
+ for (uint32_t i = 1; i < RT_ELEMENTS(pszTest1Rets); i++)
+ {
+ RTTESTI_CHECK(pszTest1Rets[i] = RTStrCacheEnterN(hStrCache, szTest, i));
+ RTTESTI_CHECK(strlen(pszTest1Rets[i]) == i);
+ RTTESTI_CHECK(pszTest2Rets[i] = RTStrCacheEnterN(hStrCache, szTest2, i));
+ RTTESTI_CHECK(strlen(pszTest2Rets[i]) == i);
+ }
+
+ if (RTStrCacheIsRealImpl())
+ {
+ for (uint32_t i = 1; i < RT_ELEMENTS(pszTest1Rets); i++)
+ {
+ uint32_t cRefs;
+ const char *psz1, *psz2;
+ RTTESTI_CHECK((psz1 = RTStrCacheEnterN(hStrCache, szTest, i)) == pszTest1Rets[i]);
+ RTTESTI_CHECK((psz2 = RTStrCacheEnterN(hStrCache, szTest2, i)) == pszTest2Rets[i]);
+ RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, psz1)) == 1, ("cRefs=%#x i=%#x\n", cRefs, i));
+ RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, psz2)) == 1, ("cRefs=%#x i=%#x\n", cRefs, i));
+ }
+ }
+
+ for (uint32_t i = 1; i < RT_ELEMENTS(pszTest1Rets); i++)
+ {
+ uint32_t cRefs;
+ RTTESTI_CHECK(strlen(pszTest1Rets[i]) == i);
+ RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, pszTest1Rets[i])) == 0, ("cRefs=%#x i=%#x\n", cRefs, i));
+ RTTESTI_CHECK(strlen(pszTest2Rets[i]) == i);
+ RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, pszTest2Rets[i])) == 0, ("cRefs=%#x i=%#x\n", cRefs, i));
+ }
}
@@ -141,6 +272,11 @@ int main()
}
/*
+ * Cache performance on relatively real world examples.
+ */
+ tst2();
+
+ /*
* Summary.
*/
return RTTestSummaryAndDestroy(hTest);
diff --git a/src/VBox/Runtime/testcase/tstRTStrFormat.cpp b/src/VBox/Runtime/testcase/tstRTStrFormat.cpp
index 7af97859..e0504e5f 100644
--- a/src/VBox/Runtime/testcase/tstRTStrFormat.cpp
+++ b/src/VBox/Runtime/testcase/tstRTStrFormat.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -336,6 +336,97 @@ int main()
CHECK42("%RTnaipv4", Ipv4Addr.u, "255.255.255.255");
RTNETADDRIPV6 Ipv6Addr;
+
+ /* any */
+ memset(&Ipv6Addr, 0, sizeof(Ipv6Addr));
+ CHECK42("%RTnaipv6", &Ipv6Addr, "::");
+
+ /* loopback */
+ Ipv6Addr.au8[15] = 1;
+ CHECK42("%RTnaipv6", &Ipv6Addr, "::1");
+
+ /* IPv4-compatible */
+ Ipv6Addr.au8[12] = 1;
+ Ipv6Addr.au8[13] = 1;
+ Ipv6Addr.au8[14] = 1;
+ Ipv6Addr.au8[15] = 1;
+ CHECK42("%RTnaipv6", &Ipv6Addr, "::1.1.1.1");
+
+ /* IPv4-mapped */
+ Ipv6Addr.au16[5] = RT_H2N_U16_C(0xffff);
+ CHECK42("%RTnaipv6", &Ipv6Addr, "::ffff:1.1.1.1");
+
+ /* IPv4-translated */
+ Ipv6Addr.au16[4] = RT_H2N_U16_C(0xffff);
+ Ipv6Addr.au16[5] = RT_H2N_U16_C(0x0000);
+ CHECK42("%RTnaipv6", &Ipv6Addr, "::ffff:0:1.1.1.1");
+
+ /* single zero word is not abbreviated, leading zeroes are not printed */
+ Ipv6Addr.au16[0] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[1] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[2] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[3] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[4] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[5] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[6] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[7] = RT_H2N_U16_C(0x0001);
+ CHECK42("%RTnaipv6", &Ipv6Addr, "0:1:0:1:0:1:0:1");
+
+ /* longest run is abbreviated (here: at the beginning) */
+ Ipv6Addr.au16[0] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[1] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[2] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[3] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[4] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[5] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[6] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[7] = RT_H2N_U16_C(0x0000);
+ CHECK42("%RTnaipv6", &Ipv6Addr, "::1:0:0:1:0");
+
+ /* longest run is abbreviated (here: first) */
+ Ipv6Addr.au16[0] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[1] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[2] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[3] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[4] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[5] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[6] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[7] = RT_H2N_U16_C(0x0001);
+ CHECK42("%RTnaipv6", &Ipv6Addr, "1::1:0:0:1");
+
+ /* longest run is abbreviated (here: second) */
+ Ipv6Addr.au16[0] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[1] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[2] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[3] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[4] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[5] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[6] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[7] = RT_H2N_U16_C(0x0001);
+ CHECK42("%RTnaipv6", &Ipv6Addr, "1:0:0:1::1");
+
+ /* longest run is abbreviated (here: at the end) */
+ Ipv6Addr.au16[0] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[1] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[2] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[3] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[4] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[5] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[6] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[7] = RT_H2N_U16_C(0x0000);
+ CHECK42("%RTnaipv6", &Ipv6Addr, "1:0:0:1::");
+
+ /* first of the two runs of equal length is abbreviated */
+ Ipv6Addr.au16[0] = RT_H2N_U16_C(0x2001);
+ Ipv6Addr.au16[1] = RT_H2N_U16_C(0x0db8);
+ Ipv6Addr.au16[2] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[3] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[4] = RT_H2N_U16_C(0x0001);
+ Ipv6Addr.au16[5] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[6] = RT_H2N_U16_C(0x0000);
+ Ipv6Addr.au16[7] = RT_H2N_U16_C(0x0001);
+ CHECK42("%RTnaipv6", &Ipv6Addr, "2001:db8::1:0:0:1");
+
Ipv6Addr.au16[0] = RT_H2N_U16_C(0x2001);
Ipv6Addr.au16[1] = RT_H2N_U16_C(0x0db8);
Ipv6Addr.au16[2] = RT_H2N_U16_C(0x85a3);
@@ -344,11 +435,26 @@ int main()
Ipv6Addr.au16[5] = RT_H2N_U16_C(0x8a2e);
Ipv6Addr.au16[6] = RT_H2N_U16_C(0x0370);
Ipv6Addr.au16[7] = RT_H2N_U16_C(0x7334);
- CHECK42("%RTnaipv6", &Ipv6Addr, "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+ CHECK42("%RTnaipv6", &Ipv6Addr, "2001:db8:85a3::8a2e:370:7334");
+
Ipv6Addr.au64[0] = UINT64_MAX;
Ipv6Addr.au64[1] = UINT64_MAX;
CHECK42("%RTnaipv6", &Ipv6Addr, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+ RTNETADDR NetAddr;
+ memset(&NetAddr, 0, sizeof(NetAddr));
+
+ /* plain IPv6 address if port is not specified */
+ NetAddr.enmType = RTNETADDRTYPE_IPV6;
+ NetAddr.uAddr.au16[0] = RT_H2N_U16_C(0x0001);
+ NetAddr.uAddr.au16[7] = RT_H2N_U16_C(0x0001);
+ NetAddr.uPort = RTNETADDR_PORT_NA;
+ CHECK42("%RTnaddr", &NetAddr, "1::1");
+
+ /* square brackets around IPv6 address if port is specified */
+ NetAddr.uPort = 1;
+ CHECK42("%RTnaddr", &NetAddr, "[1::1]:1");
+
CHECK42("%RTproc", (RTPROCESS)0xffffff, "00ffffff");
CHECK42("%RTproc", (RTPROCESS)0x43455443, "43455443");
diff --git a/src/VBox/Runtime/testcase/tstRTSymlink.cpp b/src/VBox/Runtime/testcase/tstRTSymlink.cpp
index 259d522f..46188eca 100644
--- a/src/VBox/Runtime/testcase/tstRTSymlink.cpp
+++ b/src/VBox/Runtime/testcase/tstRTSymlink.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -121,7 +121,7 @@ static void test1(RTTEST hTest, const char *pszBaseDir)
/*
* Making some assumptions about how we are executed from to start with...
*/
- RTTestISub("Negative RTSymlinkRead, RTSymlinkExists and RTSymlinkIsDangling");
+ RTTestISub("Negative RTSymlinkRead, Exists & IsDangling");
char szExecDir[RTPATH_MAX];
RTTESTI_CHECK_RC_OK_RETV(RTPathExecDir(szExecDir, sizeof(szExecDir)));
size_t cchExecDir = strlen(szExecDir);
diff --git a/src/VBox/Runtime/testcase/tstRTSystemQueryOsInfo.cpp b/src/VBox/Runtime/testcase/tstRTSystemQueryOsInfo.cpp
index d2febda3..338e59f4 100644
--- a/src/VBox/Runtime/testcase/tstRTSystemQueryOsInfo.cpp
+++ b/src/VBox/Runtime/testcase/tstRTSystemQueryOsInfo.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -65,6 +65,16 @@ int main()
rc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szInfo, sizeof(szInfo));
RTTestIPrintf(RTTESTLVL_ALWAYS, "SERVICE_PACK: \"%s\", rc=%Rrc\n", szInfo, rc);
+ uint64_t cbTotal;
+ rc = RTSystemQueryTotalRam(&cbTotal);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "Total RAM: %'RU64 Bytes (%RU64 KB, %RU64 MB)\n",
+ cbTotal, cbTotal / _1K, cbTotal / _1M);
+
+ uint64_t cbAvailable;
+ rc = RTSystemQueryAvailableRam(&cbAvailable);
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "Available RAM: %'RU64 Bytes (%RU64 KB, %RU64 MB)\n",
+ cbAvailable, cbAvailable / _1K, cbAvailable / _1M);
+
/*
* Check that unsupported stuff is terminated correctly.
*/
diff --git a/src/VBox/Runtime/testcase/tstRTTcp-1.cpp b/src/VBox/Runtime/testcase/tstRTTcp-1.cpp
index 94f60973..1ee7c15c 100644
--- a/src/VBox/Runtime/testcase/tstRTTcp-1.cpp
+++ b/src/VBox/Runtime/testcase/tstRTTcp-1.cpp
@@ -45,10 +45,22 @@ void test3()
for (unsigned i = 0; i < 100 && cStartErrors == RTTestErrorCount(g_hTest); i++)
{
PRTTCPSERVER pServer;
- RTTESTI_CHECK_RC_RETV(RTTcpServerCreate("localhost", 9999, RTTHREADTYPE_DEFAULT, "server-2",
- test3Server, NULL, &pServer), VINF_SUCCESS);
+ int rc = RTTcpServerCreate("localhost", 9999, RTTHREADTYPE_DEFAULT, "server-2", test3Server, NULL, &pServer);
+#ifdef RT_OS_SOLARIS
+ /** @todo testboxsh1 occationally hits this for some stupid reason. i=21 in
+ * one occurrence. Fudge a bit for now and see if it helps. */
+ if (rc == VERR_NET_ADDRESS_IN_USE)
+ {
+ RTThreadSleep(500);
+ rc = RTTcpServerCreate("localhost", 9999, RTTHREADTYPE_DEFAULT, "server-2", test3Server, NULL, &pServer);
+ }
+#endif
+ if (rc != VINF_SUCCESS)
+ {
+ RTTestIFailed("RTTcpServerCreate -> %Rrc, i=%d", rc, i);
+ return;
+ }
- int rc;
RTSOCKET hSocket;
RTTESTI_CHECK_RC(rc = RTTcpClientConnect("localhost", 9999, &hSocket), VINF_SUCCESS);
if (RT_SUCCESS(rc))
diff --git a/src/VBox/Runtime/testcase/tstRTTemp.cpp b/src/VBox/Runtime/testcase/tstRTTemp.cpp
index 8eb66206..758f5387 100644
--- a/src/VBox/Runtime/testcase/tstRTTemp.cpp
+++ b/src/VBox/Runtime/testcase/tstRTTemp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -130,7 +130,7 @@ static void tstDirCreateTemp(const char *pszSubTest, const char *pszTemplate, RT
static void tstBothCreateTemp(const char *pszSubTest, const char *pszTemplate, RTFMODE fMode, unsigned cTimes, bool fSkipXCheck)
{
char pszSubTestLong[128];
-
+
RTStrPrintf(pszSubTestLong, sizeof(pszSubTestLong), "RTFileCreateTemp %s",
pszSubTest);
tstFileCreateTemp(pszSubTestLong, pszTemplate, fMode, cTimes,
diff --git a/src/VBox/Runtime/testcase/tstTime.cpp b/src/VBox/Runtime/testcase/tstRTTime.cpp
index 63841e99..302acc7f 100644
--- a/src/VBox/Runtime/testcase/tstTime.cpp
+++ b/src/VBox/Runtime/testcase/tstRTTime.cpp
@@ -1,10 +1,10 @@
-/* $Id: tstTime.cpp $ */
+/* $Id: tstRTTime.cpp $ */
/** @file
- * IPRT Testcase - Simple RTTime tests.
+ * IPRT Testcase - Simple RTTime tests (requires GIP).
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,19 +28,23 @@
* Header Files *
*******************************************************************************/
#include <iprt/time.h>
-#include <iprt/stream.h>
+
+#include <iprt/err.h>
#include <iprt/initterm.h>
+#include <iprt/message.h>
+#include <iprt/test.h>
#include <iprt/thread.h>
-#include <VBox/sup.h>
-
int main()
{
- unsigned cErrors = 0;
- int i;
-
- RTR3InitExeNoArguments(RTR3INIT_FLAGS_SUPLIB);
- RTPrintf("tstTime: TESTING...\n");
+ /*
+ * Init.
+ */
+ RTTEST hTest;
+ RTEXITCODE rcExit = RTTestInitExAndCreate(0, NULL, RTR3INIT_FLAGS_SUPLIB, "tstRTTime", &hTest);
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return rcExit;
+ RTTestBanner(hTest);
/*
* RTNanoTimeTS() shall never return something which
@@ -51,6 +55,7 @@ int main()
uint64_t u64RTStartTS = RTTimeNanoTS();
uint64_t u64OSStartTS = RTTimeSystemNanoTS();
+ uint32_t i;
uint64_t u64Prev = RTTimeNanoTS();
for (i = 0; i < 100*_1M; i++)
{
@@ -58,21 +63,23 @@ int main()
if (u64 <= u64Prev)
{
/** @todo wrapping detection. */
- RTPrintf("tstTime: error: i=%#010x u64=%#llx u64Prev=%#llx (1)\n", i, u64, u64Prev);
- cErrors++;
+ RTTestFailed(hTest, "i=%#010x u64=%#llx u64Prev=%#llx (1)\n", i, u64, u64Prev);
+ if (RTTestErrorCount(hTest) >= 256)
+ break;
RTThreadYield();
u64 = RTTimeNanoTS();
}
else if (u64 - u64Prev > 1000000000 /* 1sec */)
{
- RTPrintf("tstTime: error: i=%#010x u64=%#llx u64Prev=%#llx delta=%lld\n", i, u64, u64Prev, u64 - u64Prev);
- cErrors++;
+ RTTestFailed(hTest, "i=%#010x u64=%#llx u64Prev=%#llx delta=%lld\n", i, u64, u64Prev, u64 - u64Prev);
+ if (RTTestErrorCount(hTest) >= 256)
+ break;
RTThreadYield();
u64 = RTTimeNanoTS();
}
if (!(i & (_1M*2 - 1)))
{
- RTPrintf("tstTime: i=%#010x u64=%#llx u64Prev=%#llx delta=%lld\n", i, u64, u64Prev, u64 - u64Prev);
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "i=%#010x u64=%#llx u64Prev=%#llx delta=%lld\n", i, u64, u64Prev, u64 - u64Prev);
RTThreadYield();
u64 = RTTimeNanoTS();
}
@@ -86,24 +93,25 @@ int main()
u64OSElapsedTS -= u64OSStartTS;
int64_t i64Diff = u64OSElapsedTS >= u64RTElapsedTS ? u64OSElapsedTS - u64RTElapsedTS : u64RTElapsedTS - u64OSElapsedTS;
if (i64Diff > (int64_t)(u64OSElapsedTS / 1000))
+ RTTestFailed(hTest, "total time differs too much! u64OSElapsedTS=%#llx u64RTElapsedTS=%#llx delta=%lld\n",
+ u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS);
+ else
{
- RTPrintf("tstTime: error: total time differs too much! u64OSElapsedTS=%#llx u64RTElapsedTS=%#llx delta=%lld\n",
- u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS);
- cErrors++;
+ RTTestValue(hTest, "Total time delta", u64OSElapsedTS - u64RTElapsedTS, RTTESTUNIT_NS);
+ RTTestPrintf(hTest, RTTESTLVL_INFO, "total time difference: u64OSElapsedTS=%#llx u64RTElapsedTS=%#llx delta=%lld\n",
+ u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS);
}
- else
- RTPrintf("tstTime: total time difference: u64OSElapsedTS=%#llx u64RTElapsedTS=%#llx delta=%lld\n",
- u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS);
#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) /** @todo This isn't really x86 or AMD64 specific... */
- RTPrintf("RTTimeDbgSteps -> %u (%d ppt)\n", RTTimeDbgSteps(), ((uint64_t)RTTimeDbgSteps() * 1000) / i);
- RTPrintf("RTTimeDbgExpired -> %u (%d ppt)\n", RTTimeDbgExpired(), ((uint64_t)RTTimeDbgExpired() * 1000) / i);
- RTPrintf("RTTimeDbgBad -> %u (%d ppt)\n", RTTimeDbgBad(), ((uint64_t)RTTimeDbgBad() * 1000) / i);
- RTPrintf("RTTimeDbgRaces -> %u (%d ppt)\n", RTTimeDbgRaces(), ((uint64_t)RTTimeDbgRaces() * 1000) / i);
+ RTTestValue(hTest, "RTTimeDbgSteps", RTTimeDbgSteps(), RTTESTUNIT_OCCURRENCES);
+ RTTestValue(hTest, "RTTimeDbgSteps pp", ((uint64_t)RTTimeDbgSteps() * 1000) / i, RTTESTUNIT_PP1K);
+ RTTestValue(hTest, "RTTimeDbgExpired", RTTimeDbgExpired(), RTTESTUNIT_OCCURRENCES);
+ RTTestValue(hTest, "RTTimeDbgExpired pp", ((uint64_t)RTTimeDbgExpired() * 1000) / i, RTTESTUNIT_PP1K);
+ RTTestValue(hTest, "RTTimeDbgBad", RTTimeDbgBad(), RTTESTUNIT_OCCURRENCES);
+ RTTestValue(hTest, "RTTimeDbgBad pp", ((uint64_t)RTTimeDbgBad() * 1000) / i, RTTESTUNIT_PP1K);
+ RTTestValue(hTest, "RTTimeDbgRaces", RTTimeDbgRaces(), RTTESTUNIT_OCCURRENCES);
+ RTTestValue(hTest, "RTTimeDbgRaces pp", ((uint64_t)RTTimeDbgRaces() * 1000) / i, RTTESTUNIT_PP1K);
#endif
- if (!cErrors)
- RTPrintf("tstTime: SUCCESS\n");
- else
- RTPrintf("tstTime: FAILURE - %d errors\n", cErrors);
- return !!cErrors;
+
+ return RTTestSummaryAndDestroy(hTest);
}
diff --git a/src/VBox/Runtime/testcase/tstRTTimeSpec.cpp b/src/VBox/Runtime/testcase/tstRTTimeSpec.cpp
index 08f5cc90..450041f6 100644
--- a/src/VBox/Runtime/testcase/tstRTTimeSpec.cpp
+++ b/src/VBox/Runtime/testcase/tstRTTimeSpec.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRTUri.cpp b/src/VBox/Runtime/testcase/tstRTUri.cpp
index 5a2c39ba..e94ade2a 100644
--- a/src/VBox/Runtime/testcase/tstRTUri.cpp
+++ b/src/VBox/Runtime/testcase/tstRTUri.cpp
@@ -38,7 +38,7 @@
* Test data *
*******************************************************************************/
-static const char *gs_apcszTestURIs[] =
+static const char *g_apcszTestURIs[] =
{
"foo://tt:tt@example.com:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
"foo://tt:tt@example.com:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret",
@@ -58,7 +58,7 @@ static const char *gs_apcszTestURIs[] =
"foo://"
};
-static const char *gs_apcszSchemeResult[] =
+static const char *g_apcszSchemeResult[] =
{
"foo",
"foo",
@@ -78,7 +78,7 @@ static const char *gs_apcszSchemeResult[] =
"foo"
};
-static const char *gs_apcszAuthorityResult[] =
+static const char *g_apcszAuthorityResult[] =
{
"tt:tt@example.com:8042",
"tt:tt@example.com:8042",
@@ -98,7 +98,7 @@ static const char *gs_apcszAuthorityResult[] =
NULL
};
-static const char *gs_apcszPathResult[] =
+static const char *g_apcszPathResult[] =
{
"/over/ <>#%\"{}|^[]`/there",
"/over/ <>#%\"{}|^[]`/there",
@@ -118,7 +118,7 @@ static const char *gs_apcszPathResult[] =
NULL
};
-static const char *gs_apcszQueryResult[] =
+static const char *g_apcszQueryResult[] =
{
"name= <>#%\"{}|^[]`ferret",
"name= <>#%\"{}|^[]`ferret",
@@ -138,7 +138,7 @@ static const char *gs_apcszQueryResult[] =
NULL
};
-static const char *gs_apcszFragmentResult[] =
+static const char *g_apcszFragmentResult[] =
{
"nose <>#%\"{}|^[]`",
NULL,
@@ -158,7 +158,7 @@ static const char *gs_apcszFragmentResult[] =
NULL
};
-static const char *gs_apcszCreateURIs[][5] =
+static const char *g_apcszCreateURIs[][5] =
{
{ "foo", "tt:tt@example.com:8042", "/over/ <>#%\"{}|^[]`/there", "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
{ "foo", "tt:tt@example.com:8042", "/over/ <>#%\"{}|^[]`/there", "name= <>#%\"{}|^[]`ferret", NULL },
@@ -184,7 +184,7 @@ struct URIFILETEST
const char *pcszUri;
uint32_t uFormat;
}
-gs_apCreateFileURIs[] =
+g_apCreateFileURIs[] =
{
{ "C:\\over\\ <>#%\"{}|^[]`\\there", "file:///C:%5Cover%5C%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60%5Cthere", URI_FILE_FORMAT_WIN },
{ "/over/ <>#%\"{}|^[]`/there", "file:///over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there", URI_FILE_FORMAT_UNIX },
@@ -198,8 +198,6 @@ gs_apCreateFileURIs[] =
*/
static void tstScheme(size_t iCount, const char *pszUri, const char *pszTest)
{
- RTTestISubF("Uri scheme parsing %2u: '%s' -> '%s'", iCount, pszUri, pszTest);
-
char *pszResult = RTUriScheme(pszUri);
if (pszTest)
{
@@ -215,8 +213,6 @@ static void tstScheme(size_t iCount, const char *pszUri, const char *pszTest)
static void tstAuthority(size_t iCount, const char *pszUri, const char *pszTest)
{
- RTTestISubF("Uri authority parsing %2u: '%s' -> '%s'", iCount, pszUri, pszTest);
-
char *pszResult = RTUriAuthority(pszUri);
if (pszTest)
{
@@ -232,8 +228,6 @@ static void tstAuthority(size_t iCount, const char *pszUri, const char *pszTest)
static void tstPath(size_t iCount, const char *pszUri, const char *pszTest)
{
- RTTestISubF("Uri path parsing %2u: '%s' -> '%s'", iCount, pszUri, pszTest);
-
char *pszResult = RTUriPath(pszUri);
if (pszTest)
{
@@ -249,8 +243,6 @@ static void tstPath(size_t iCount, const char *pszUri, const char *pszTest)
static void tstQuery(size_t iCount, const char *pszUri, const char *pszTest)
{
- RTTestISubF("Uri query parsing %2u: '%s' -> '%s'", iCount, pszUri, pszTest);
-
char *pszResult = RTUriQuery(pszUri);
if (pszTest)
{
@@ -266,8 +258,6 @@ static void tstQuery(size_t iCount, const char *pszUri, const char *pszTest)
static void tstFragment(size_t iCount, const char *pszUri, const char *pszTest)
{
- RTTestISubF("Uri fragment parsing %2u: '%s' -> '%s'", iCount, pszUri, pszTest);
-
char *pszResult = RTUriFragment(pszUri);
if (pszTest)
{
@@ -283,8 +273,6 @@ static void tstFragment(size_t iCount, const char *pszUri, const char *pszTest)
static void tstCreate(size_t iCount, const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, const char *pszFragment, const char *pszTest)
{
- RTTestISubF("Uri creating %2u: Scheme: '%s', Authority: '%s', Path: '%s', Query: '%s', Fragment: '%s'", iCount, pszScheme, pszAuthority, pszPath, pszQuery, pszFragment);
-
char *pszResult = RTUriCreate(pszScheme, pszAuthority, pszPath, pszQuery, pszFragment);
if (pszTest)
{
@@ -301,8 +289,6 @@ static void tstCreate(size_t iCount, const char *pszScheme, const char *pszAutho
static void tstFileCreate(size_t iCount, const char *pszPath, const char *pszTest)
{
- RTTestISubF("Uri file creating %2u: Path: '%s'", iCount, pszPath);
-
char *pszResult = RTUriFileCreate(pszPath);
if (pszTest)
{
@@ -319,8 +305,6 @@ static void tstFileCreate(size_t iCount, const char *pszPath, const char *pszTes
static void tstFilePath(size_t iCount, const char *pszUri, const char *pszTest, uint32_t uFormat)
{
- RTTestISubF("Uri file path parsing %2u: '%s' -> '%s'", iCount, pszUri, pszTest);
-
char *pszResult = RTUriFilePath(pszUri, uFormat);
if (pszTest)
{
@@ -344,42 +328,51 @@ int main()
RTTestBanner(hTest);
/* Scheme */
- Assert(RT_ELEMENTS(gs_apcszTestURIs) == RT_ELEMENTS(gs_apcszSchemeResult));
- for (size_t i = 0; i < RT_ELEMENTS(gs_apcszTestURIs); ++i)
- tstScheme(i+1, gs_apcszTestURIs[i], gs_apcszSchemeResult[i]);
+ RTTestISubF("RTUriScheme");
+ Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszSchemeResult));
+ for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
+ tstScheme(i+1, g_apcszTestURIs[i], g_apcszSchemeResult[i]);
/* Authority */
- Assert(RT_ELEMENTS(gs_apcszTestURIs) == RT_ELEMENTS(gs_apcszAuthorityResult));
- for (size_t i = 0; i < RT_ELEMENTS(gs_apcszTestURIs); ++i)
- tstAuthority(i+1, gs_apcszTestURIs[i], gs_apcszAuthorityResult[i]);
+ RTTestISubF("RTUriAuthority");
+ Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszAuthorityResult));
+ for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
+ tstAuthority(i+1, g_apcszTestURIs[i], g_apcszAuthorityResult[i]);
/* Path */
- Assert(RT_ELEMENTS(gs_apcszTestURIs) == RT_ELEMENTS(gs_apcszPathResult));
- for (size_t i = 0; i < RT_ELEMENTS(gs_apcszTestURIs); ++i)
- tstPath(i+1, gs_apcszTestURIs[i], gs_apcszPathResult[i]);
+ RTTestISubF("RTUriPath");
+ Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszPathResult));
+ for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
+ tstPath(i+1, g_apcszTestURIs[i], g_apcszPathResult[i]);
/* Query */
- Assert(RT_ELEMENTS(gs_apcszTestURIs) == RT_ELEMENTS(gs_apcszQueryResult));
- for (size_t i = 0; i < RT_ELEMENTS(gs_apcszTestURIs); ++i)
- tstQuery(i+1, gs_apcszTestURIs[i], gs_apcszQueryResult[i]);
+ RTTestISubF("RTUriQuery");
+ Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszQueryResult));
+ for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
+ tstQuery(i+1, g_apcszTestURIs[i], g_apcszQueryResult[i]);
/* Fragment */
- Assert(RT_ELEMENTS(gs_apcszTestURIs) == RT_ELEMENTS(gs_apcszFragmentResult));
- for (size_t i = 0; i < RT_ELEMENTS(gs_apcszTestURIs); ++i)
- tstFragment(i+1, gs_apcszTestURIs[i], gs_apcszFragmentResult[i]);
+ RTTestISubF("RTUriFragment");
+ Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszFragmentResult));
+ for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
+ tstFragment(i+1, g_apcszTestURIs[i], g_apcszFragmentResult[i]);
/* Creation */
- Assert(RT_ELEMENTS(gs_apcszTestURIs) == RT_ELEMENTS(gs_apcszCreateURIs));
- for (size_t i = 0; i < RT_ELEMENTS(gs_apcszTestURIs); ++i)
- tstCreate(i+1, gs_apcszCreateURIs[i][0], gs_apcszCreateURIs[i][1], gs_apcszCreateURIs[i][2], gs_apcszCreateURIs[i][3], gs_apcszCreateURIs[i][4], gs_apcszTestURIs[i]);
+ RTTestISubF("RTUriCreate");
+ Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszCreateURIs));
+ for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
+ tstCreate(i+1, g_apcszCreateURIs[i][0], g_apcszCreateURIs[i][1], g_apcszCreateURIs[i][2],
+ g_apcszCreateURIs[i][3], g_apcszCreateURIs[i][4], g_apcszTestURIs[i]);
/* File Uri path */
- for (size_t i = 0; i < RT_ELEMENTS(gs_apCreateFileURIs); ++i)
- tstFilePath(i+1, gs_apCreateFileURIs[i].pcszUri, gs_apCreateFileURIs[i].pcszPath, gs_apCreateFileURIs[i].uFormat);
+ RTTestISubF("RTUriFilePath");
+ for (size_t i = 0; i < RT_ELEMENTS(g_apCreateFileURIs); ++i)
+ tstFilePath(i+1, g_apCreateFileURIs[i].pcszUri, g_apCreateFileURIs[i].pcszPath, g_apCreateFileURIs[i].uFormat);
/* File Uri creation */
+ RTTestISubF("RTUriFileCreate");
for (size_t i = 0; i < 3; ++i)
- tstFileCreate(i+1, gs_apCreateFileURIs[i].pcszPath, gs_apCreateFileURIs[i].pcszUri);
+ tstFileCreate(i+1, g_apCreateFileURIs[i].pcszPath, g_apCreateFileURIs[i].pcszUri);
return RTTestSummaryAndDestroy(hTest);
}
diff --git a/src/VBox/Runtime/testcase/tstRTUuid.cpp b/src/VBox/Runtime/testcase/tstRTUuid.cpp
index 692bcb94..a2fd7e08 100644
--- a/src/VBox/Runtime/testcase/tstRTUuid.cpp
+++ b/src/VBox/Runtime/testcase/tstRTUuid.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstRand.cpp b/src/VBox/Runtime/testcase/tstRand.cpp
index 5205ceae..88edf856 100644
--- a/src/VBox/Runtime/testcase/tstRand.cpp
+++ b/src/VBox/Runtime/testcase/tstRand.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstSemMutex.cpp b/src/VBox/Runtime/testcase/tstSemMutex.cpp
index 373c2b61..1bdb4a91 100644
--- a/src/VBox/Runtime/testcase/tstSemMutex.cpp
+++ b/src/VBox/Runtime/testcase/tstSemMutex.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstSemPingPong.cpp b/src/VBox/Runtime/testcase/tstSemPingPong.cpp
index 37db163b..0be9f7ef 100644
--- a/src/VBox/Runtime/testcase/tstSemPingPong.cpp
+++ b/src/VBox/Runtime/testcase/tstSemPingPong.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstStrSimplePattern.cpp b/src/VBox/Runtime/testcase/tstStrSimplePattern.cpp
index f9f11cc6..756b8431 100644
--- a/src/VBox/Runtime/testcase/tstStrSimplePattern.cpp
+++ b/src/VBox/Runtime/testcase/tstStrSimplePattern.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstStrToNum.cpp b/src/VBox/Runtime/testcase/tstStrToNum.cpp
index 43f89923..53b92275 100644
--- a/src/VBox/Runtime/testcase/tstStrToNum.cpp
+++ b/src/VBox/Runtime/testcase/tstStrToNum.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstTSC.cpp b/src/VBox/Runtime/testcase/tstTSC.cpp
index 2ebed4fe..b18d8432 100644
--- a/src/VBox/Runtime/testcase/tstTSC.cpp
+++ b/src/VBox/Runtime/testcase/tstTSC.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -437,7 +437,7 @@ int main(int argc, char **argv)
return 1;
case 'V':
- RTPrintf("$Revision: $\n");
+ RTPrintf("$Revision: 89632 $\n");
return 0;
default:
diff --git a/src/VBox/Runtime/testcase/tstTermCallbacks.cpp b/src/VBox/Runtime/testcase/tstTermCallbacks.cpp
index e72e16b5..ea33f889 100644
--- a/src/VBox/Runtime/testcase/tstTermCallbacks.cpp
+++ b/src/VBox/Runtime/testcase/tstTermCallbacks.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstThread-1.cpp b/src/VBox/Runtime/testcase/tstThread-1.cpp
index 715fa491..e4cfebe8 100644
--- a/src/VBox/Runtime/testcase/tstThread-1.cpp
+++ b/src/VBox/Runtime/testcase/tstThread-1.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstTime-2.cpp b/src/VBox/Runtime/testcase/tstTime-2.cpp
index aa8288e4..8d2405d9 100644
--- a/src/VBox/Runtime/testcase/tstTime-2.cpp
+++ b/src/VBox/Runtime/testcase/tstTime-2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstTime-3.cpp b/src/VBox/Runtime/testcase/tstTime-3.cpp
index 45985c0f..436b0955 100644
--- a/src/VBox/Runtime/testcase/tstTime-3.cpp
+++ b/src/VBox/Runtime/testcase/tstTime-3.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,8 +30,6 @@
#ifdef RT_OS_WINDOWS
# include <Windows.h>
-#elif defined RT_OS_L4
-
#else /* posix */
# include <sys/time.h>
#endif
@@ -51,10 +49,6 @@ DECLINLINE(uint64_t) OSNanoTS(void)
GetSystemTimeAsFileTime((LPFILETIME)&u64);
return u64 * 100;
-#elif defined RT_OS_L4
- /** @todo fix a different timesource on l4. */
- return RTTimeNanoTS();
-
#else /* posix */
struct timeval tv;
diff --git a/src/VBox/Runtime/testcase/tstTime-4.cpp b/src/VBox/Runtime/testcase/tstTime-4.cpp
index 305ce7ce..c9d1cf65 100644
--- a/src/VBox/Runtime/testcase/tstTime-4.cpp
+++ b/src/VBox/Runtime/testcase/tstTime-4.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -64,11 +64,12 @@ int main()
cErrors++;
RTPrintf("tstTime-4: Bad Gip time!\n");
}
- int64_t Delta = GipPrevTS - SysPrevTS;
- if (Delta > 0 ? Delta > 100000000 /* 100 ms */ : Delta < -100000000 /* -100 ms */)
+ uint64_t Delta = GipPrevTS > SysPrevTS ? GipPrevTS - SysPrevTS :
+ SysPrevTS - GipPrevTS;
+ if (Delta > 100000000ULL /* 100 ms */ )
{
cErrors++;
- RTPrintf("tstTime-4: Delta=%lld!\n", Delta);
+ RTPrintf("tstTime-4: Delta=%llu (GipPrevTS=%llu, SysPrevTS=%llu)!\n", Delta, GipPrevTS, SysPrevTS);
}
} while (SysPrevTS - SysStartTS < 2000000000 /* 2s */);
diff --git a/src/VBox/Runtime/testcase/tstTimer.cpp b/src/VBox/Runtime/testcase/tstTimer.cpp
index 2ac2c159..6fdee70b 100644
--- a/src/VBox/Runtime/testcase/tstTimer.cpp
+++ b/src/VBox/Runtime/testcase/tstTimer.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstTimerLR.cpp b/src/VBox/Runtime/testcase/tstTimerLR.cpp
index 8bba2339..b179ed79 100644
--- a/src/VBox/Runtime/testcase/tstTimerLR.cpp
+++ b/src/VBox/Runtime/testcase/tstTimerLR.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/testcase/tstUtf8.cpp b/src/VBox/Runtime/testcase/tstUtf8.cpp
index 890c644b..7f81f103 100644
--- a/src/VBox/Runtime/testcase/tstUtf8.cpp
+++ b/src/VBox/Runtime/testcase/tstUtf8.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -29,15 +29,16 @@
*******************************************************************************/
#include <iprt/string.h>
-#include <iprt/uni.h>
-#include <iprt/uuid.h>
-#include <iprt/time.h>
-#include <iprt/stream.h>
#include <iprt/alloc.h>
#include <iprt/assert.h>
+#include <iprt/env.h>
#include <iprt/err.h>
#include <iprt/rand.h>
+#include <iprt/stream.h>
#include <iprt/test.h>
+#include <iprt/time.h>
+#include <iprt/uni.h>
+#include <iprt/uuid.h>
@@ -49,7 +50,7 @@ static RTUTF16 GetRandUtf16(void)
RTUTF16 wc;
do
{
- wc = (RTUTF16)RTRandU32Ex(1, 0xffff);
+ wc = (RTUTF16)RTRandU32Ex(1, 0xfffd);
} while (wc >= 0xd800 && wc <= 0xdfff);
return wc;
}
@@ -103,6 +104,8 @@ static void test1(RTTEST hTest)
}
else if (rc == VERR_NO_TRANSLATION)
RTTestPassed(hTest, "The second part of random UTF-16 -> UTF-8 -> Current -> UTF-8 returned VERR_NO_TRANSLATION. This is probably as it should be.\n");
+ else if (rc == VWRN_NO_TRANSLATION)
+ RTTestPassed(hTest, "The second part of random UTF-16 -> UTF-8 -> Current -> UTF-8 returned VWRN_NO_TRANSLATION. This is probably as it should be.\n");
else
RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> Current -> UTF-8 failed with return value %Rrc.",
__LINE__, rc);
@@ -1395,14 +1398,15 @@ static void testNoTransation(RTTEST hTest)
RTTestSub(hTest, "VERR_NO_TRANSLATION/RTStrUtf8ToCurrentCP");
char *pszOut;
rc = RTStrUtf8ToCurrentCP(&pszOut, pszTest1);
- if (RT_SUCCESS(rc))
+ if (rc == VINF_SUCCESS)
{
RTTESTI_CHECK(!strcmp(pszOut, pszTest1));
- RTTestIPrintf(RTTESTLVL_ALWAYS, "CurrentCP is UTF-8 or similar\n");
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "CurrentCP is UTF-8 or similar (LC_ALL=%s LANG=%s LC_CTYPE=%s)\n",
+ RTEnvGet("LC_ALL"), RTEnvGet("LANG"), RTEnvGet("LC_CTYPE"));
RTStrFree(pszOut);
}
else
- RTTESTI_CHECK_RC(rc, VERR_NO_TRANSLATION);
+ RTTESTI_CHECK_MSG(rc == VWRN_NO_TRANSLATION || rc == VERR_NO_TRANSLATION, ("rc=%Rrc\n", rc));
RTTestSub(hTest, "VERR_NO_TRANSLATION/RTUtf16ToLatin1");
rc = RTUtf16ToLatin1(s_swzTest1, &pszOut);
diff --git a/src/VBox/Runtime/tools/Makefile.kmk b/src/VBox/Runtime/tools/Makefile.kmk
index 42f24d56..63b93c7f 100644
--- a/src/VBox/Runtime/tools/Makefile.kmk
+++ b/src/VBox/Runtime/tools/Makefile.kmk
@@ -4,7 +4,7 @@
#
#
-# Copyright (C) 2006-2012 Oracle Corporation
+# Copyright (C) 2006-2013 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
@@ -36,6 +36,11 @@ bldRTManifest_SOURCES = RTManifest.cpp
ifndef VBOX_ONLY_EXTPACKS_USE_IMPLIBS
# RTManifest is a tool for creating and verifying manifest files.
+ PROGRAMS += RTRm
+ RTRm_TEMPLATE = VBOXR3TSTEXE
+ RTRm_SOURCES = RTRm.cpp
+
+ # RTManifest is a tool for creating and verifying manifest files.
PROGRAMS += RTManifest
RTManifest_TEMPLATE = VBOXR3TSTEXE
RTManifest_SOURCES = RTManifest.cpp
@@ -60,6 +65,11 @@ ifndef VBOX_ONLY_EXTPACKS_USE_IMPLIBS
RTTar_TEMPLATE = VBOXR3TSTEXE
RTTar_SOURCES = RTTar.cpp
+ # RTNtDbgHelp - our tar clone (for testing the tar/gzip/gunzip streaming code)
+ PROGRAMS.win += RTNtDbgHelp
+ RTNtDbgHelp_TEMPLATE = VBOXR3TSTEXE
+ RTNtDbgHelp_SOURCES = RTNtDbgHelp.cpp
+
endif # !VBOX_ONLY_EXTPACKS_USE_IMPLIBS
include $(FILE_KBUILD_SUB_FOOTER)
diff --git a/src/VBox/Runtime/tools/RTGzip.cpp b/src/VBox/Runtime/tools/RTGzip.cpp
index a30c5871..aedb7d9d 100644
--- a/src/VBox/Runtime/tools/RTGzip.cpp
+++ b/src/VBox/Runtime/tools/RTGzip.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -36,15 +36,54 @@
#include <iprt/initterm.h>
#include <iprt/message.h>
#include <iprt/param.h>
+#include <iprt/path.h>
#include <iprt/stream.h>
#include <iprt/string.h>
#include <iprt/vfs.h>
#include <iprt/zip.h>
-static bool isStdHandleATty(int fd)
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Gzip command options.
+ */
+typedef struct RTGZIPCMDOPTS
{
- /** @todo IPRT is missing this */
+ bool fAscii;
+ bool fStdOut;
+ bool fDecompress;
+ bool fForce;
+ bool fKeep;
+ bool fList;
+ bool fName;
+ bool fQuiet;
+ bool fRecursive;
+ const char *pszSuff;
+ bool fTest;
+ unsigned uLevel;
+ /** The current output filename (for deletion). */
+ char szOutput[RTPATH_MAX];
+ /** The current input filename (for deletion and messages). */
+ const char *pszInput;
+} RTGZIPCMDOPTS;
+/** Pointer to GZIP options. */
+typedef RTGZIPCMDOPTS *PRTGZIPCMDOPTS;
+/** Pointer to const GZIP options. */
+typedef RTGZIPCMDOPTS const *PCRTGZIPCMDOPTS;
+
+
+
+/**
+ * Checks if the given standard handle is a TTY.
+ *
+ * @returns true / false
+ * @param enmStdHandle The standard handle.
+ */
+static bool gzipIsStdHandleATty(RTHANDLESTD enmStdHandle)
+{
+ /** @todo Add isatty() to IPRT. */
return false;
}
@@ -53,163 +92,334 @@ static bool isStdHandleATty(int fd)
* Pushes data from the input to the output I/O streams.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
- * @param hVfsIn The input I/O stream.
- * @param hVfsOut The input I/O stream.
+ * @param hVfsSrc The source I/O stream.
+ * @param hVfsDst The destination I/O stream.
*/
-static RTEXITCODE gzipPush(RTVFSIOSTREAM hVfsIn, RTVFSIOSTREAM hVfsOut)
+static RTEXITCODE gzipPush(RTVFSIOSTREAM hVfsSrc, RTVFSIOSTREAM hVfsDst)
{
for (;;)
{
uint8_t abBuf[_64K];
size_t cbRead;
- int rc = RTVfsIoStrmRead(hVfsIn, abBuf, sizeof(abBuf), true /*fBlocking*/, &cbRead);
+ int rc = RTVfsIoStrmRead(hVfsSrc, abBuf, sizeof(abBuf), true /*fBlocking*/, &cbRead);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsIoStrmRead failed: %Rrc", rc);
if (rc == VINF_EOF && cbRead == 0)
return RTEXITCODE_SUCCESS;
- rc = RTVfsIoStrmWrite(hVfsOut, abBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
+ rc = RTVfsIoStrmWrite(hVfsDst, abBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsIoStrmWrite failed: %Rrc", rc);
}
}
-static RTEXITCODE gzipCompress(RTVFSIOSTREAM hVfsIn, RTVFSIOSTREAM hVfsOut)
-{
- return RTMsgErrorExit(RTEXITCODE_FAILURE, "Compression is not yet implemented, sorry.");
-}
-
-static RTEXITCODE gzipCompressFile(const char *pszFile, bool fStdOut, bool fForce, PRTVFSIOSTREAM phVfsStdOut)
+/**
+ * Pushes the bytes from the input to the output stream, flushes the output
+ * stream and closes both of them.
+ *
+ * On failure, we will delete the output file, if it's a file. The input file
+ * may be deleted, if we're not told to keep it (--keep, --to-stdout).
+ *
+ * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
+ * @param phVfsSrc The input stream. Set to NIL if closed.
+ * @param pOpts The options.
+ * @param phVfsDst The output stream. Set to NIL if closed.
+ */
+static RTEXITCODE gzipPushFlushAndClose(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsDst)
{
- return RTMsgErrorExit(RTEXITCODE_FAILURE, "Compression is not yet implemented, sorry.");
-}
+ /*
+ * Push bytes, flush and close the streams.
+ */
+ RTEXITCODE rcExit = gzipPush(*phVfsSrc, *phVfsDst);
+ RTVfsIoStrmRelease(*phVfsSrc);
+ *phVfsSrc = NIL_RTVFSIOSTREAM;
-static RTEXITCODE gzipDecompress(RTVFSIOSTREAM hVfsIn, RTVFSIOSTREAM hVfsOut)
-{
- RTEXITCODE rcExit;
- RTVFSIOSTREAM hVfsGunzip;
- int rc = RTZipGzipDecompressIoStream(hVfsIn, 0 /*fFlags*/, &hVfsGunzip);
- if (RT_SUCCESS(rc))
+ int rc = RTVfsIoStrmFlush(*phVfsDst);
+ if (RT_FAILURE(rc))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to flush the output file: %Rrc", rc);
+ RTVfsIoStrmRelease(*phVfsDst);
+ *phVfsDst = NIL_RTVFSIOSTREAM;
+
+ /*
+ * Do the cleaning up, if needed. Remove the input file, if that's the
+ * desire of the user, or remove the output file on failure.
+ */
+ if (!pOpts->fStdOut)
{
- rcExit = gzipPush(hVfsGunzip, hVfsOut);
- RTVfsIoStrmRelease(hVfsGunzip);
+ if (rcExit == RTEXITCODE_SUCCESS)
+ {
+ if (!pOpts->fKeep)
+ {
+ rc = RTFileDelete(pOpts->pszInput);
+ if (RT_FAILURE(rc))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to delete '%s': %Rrc", pOpts->pszInput, rc);
+ }
+ }
+ else
+ {
+ rc = RTFileDelete(pOpts->szOutput);
+ if (RT_FAILURE(rc))
+ RTMsgError("Failed to delete '%s': %Rrc", pOpts->szOutput, rc);
+ }
}
- else
- rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTZipGzipDecompressIoStream failed: %Rrc", rc);
+
return rcExit;
}
/**
- * Handles a file on the command line.
+ * Compresses one stream to another.
*
- * @returns exit code.
- * @param pszFile The file to handle.
- * @param fStdOut Whether to output to standard output or not.
- * @param fForce Whether to output to or input from terminals.
- * @param phVfsStdOut Pointer to the standard out handle.
- * (input/output)
+ * @returns Exit code.
+ * @param phVfsSrc The input stream. Set to NIL if closed.
+ * @param pOpts The options.
+ * @param phVfsDst The output stream. Set to NIL if closed.
*/
-static RTEXITCODE gzipDecompressFile(const char *pszFile, bool fStdOut, bool fForce, PRTVFSIOSTREAM phVfsStdOut)
+static RTEXITCODE gzipCompressFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsDst)
{
/*
- * Open the specified input file.
+ * Attach the ompressor to the output stream.
*/
- const char *pszError;
- RTVFSIOSTREAM hVfsIn;
- int rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hVfsIn, &pszError);
+ RTVFSIOSTREAM hVfsGzip;
+ int rc = RTZipGzipCompressIoStream(*phVfsDst, 0 /*fFlags*/, pOpts->uLevel, &hVfsGzip);
if (RT_FAILURE(rc))
- {
- if (pszError && *pszError)
- return RTMsgErrorExit(RTEXITCODE_FAILURE,
- "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
- " '%s'\n",
- " %*s^\n",
- rc, pszFile, pszError - pszFile, "");
- return RTMsgErrorExit(RTEXITCODE_FAILURE,
- "RTVfsChainOpenIoStream failed with rc=%Rrc: '%s'",
- rc, pszFile);
- }
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTZipGzipCompressIoStream failed: %Rrc", rc);
+ uint32_t cRefs = RTVfsIoStrmRelease(*phVfsDst);
+ Assert(cRefs > 0);
+ *phVfsDst = hVfsGzip;
+
+ return gzipPushFlushAndClose(phVfsSrc, pOpts, phVfsDst);
+}
+
+
+/**
+ * Attach a decompressor to the given source stream, replacing and releasing the
+ * input handle with the decompressor.
+ *
+ * @returns Exit code.
+ * @param phVfsSrc The input stream. Replaced on success.
+ */
+static RTEXITCODE gzipSetupDecompressor(PRTVFSIOSTREAM phVfsSrc)
+{
/*
- * Output the output file.
+ * Attach the decompressor to the input stream.
*/
- RTVFSIOSTREAM hVfsOut;
- char szFinal[RTPATH_MAX];
- if (fStdOut)
+ RTVFSIOSTREAM hVfsGunzip;
+ int rc = RTZipGzipDecompressIoStream(*phVfsSrc, 0 /*fFlags*/, &hVfsGunzip);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTZipGzipDecompressIoStream failed: %Rrc", rc);
+
+ uint32_t cRefs = RTVfsIoStrmRelease(*phVfsSrc);
+ Assert(cRefs > 0);
+ *phVfsSrc = hVfsGunzip;
+
+ return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Decompresses one stream to another.
+ *
+ * @returns Exit code.
+ * @param phVfsSrc The input stream. Set to NIL if closed.
+ * @param pOpts The options.
+ * @param phVfsDst The output stream. Set to NIL if closed.
+ */
+static RTEXITCODE gzipDecompressFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsDst)
+{
+ RTEXITCODE rcExit = gzipSetupDecompressor(phVfsSrc);
+ if (rcExit == RTEXITCODE_SUCCESS)
+ rcExit = gzipPushFlushAndClose(phVfsSrc, pOpts, phVfsDst);
+ return rcExit;
+}
+
+
+/**
+ * For testing the archive (todo).
+ *
+ * @returns Exit code.
+ * @param phVfsSrc The input stream. Set to NIL if closed.
+ * @param pOpts The options.
+ */
+static RTEXITCODE gzipTestFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts)
+{
+ /*
+ * Read the whole stream.
+ */
+ RTEXITCODE rcExit = gzipSetupDecompressor(phVfsSrc);
+ if (rcExit == RTEXITCODE_SUCCESS)
{
- if (*phVfsStdOut == NIL_RTVFSIOSTREAM)
+ for (;;)
{
- rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, 0 /*fOpen*/, true /*fLeaveOpen*/, phVfsStdOut);
+ uint8_t abBuf[_64K];
+ size_t cbRead;
+ int rc = RTVfsIoStrmRead(*phVfsSrc, abBuf, sizeof(abBuf), true /*fBlocking*/, &cbRead);
if (RT_FAILURE(rc))
- return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to set up standard out: %Rrc", rc);
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsIoStrmRead failed: %Rrc", rc);
+ if (rc == VINF_EOF && cbRead == 0)
+ return RTEXITCODE_SUCCESS;
}
- hVfsOut = *phVfsStdOut;
- szFinal[0] = '\0';
- }
- else
- {
- rc = RTStrCopy(szFinal, sizeof(szFinal), pszFile);
- /** @todo remove the extension? Or are we supposed
- * to get the org name from the gzip stream? */
- return RTMsgErrorExit(RTEXITCODE_FAILURE, "Decompressing to file is not implemented");
}
+ return rcExit;
+}
- /*
- * Do the decompressing, then flush and close the output stream (unless
- * it is stdout).
- */
- RTEXITCODE rcExit = gzipDecompress(hVfsIn, hVfsOut);
- RTVfsIoStrmRelease(hVfsIn);
- rc = RTVfsIoStrmFlush(hVfsOut);
- if (RT_FAILURE(rc))
- rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to flush the output file: %Rrc", rc);
- RTVfsIoStrmRelease(hVfsOut);
- /*
- * Remove the input file, if that's the desire of the caller, or
- * remove the output file on decompression failure.
- */
- if (!fStdOut)
+static RTEXITCODE gzipListFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts)
+{
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Listing has not been implemented");
+}
+
+
+/**
+ * Opens the output file.
+ *
+ * @returns Command exit, error messages written using RTMsg*.
+ *
+ * @param pszFile The input filename.
+ * @param pOpts The options, szOutput will be filled in by this
+ * function on success.
+ * @param phVfsIos Where to return the output stream handle.
+ *
+ * @remarks This is actually not quite the way we need to do things.
+ *
+ * First of all, we need a GZIP file system stream for a real GZIP
+ * implementation, since there may be more than one file in the gzipped
+ * file.
+ *
+ * Second, we need to open the output files as we encounter files in the input
+ * file system stream. The gzip format contains timestamp and usually a
+ * filename, the default is to use this name (see the --no-name
+ * option).
+ */
+static RTEXITCODE gzipOpenOutput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos)
+{
+ int rc;
+ if (!strcmp(pszFile, "-") || pOpts->fStdOut)
{
- if (rcExit == RTEXITCODE_SUCCESS)
+ strcpy(pOpts->szOutput, "-");
+
+ if ( !pOpts->fForce
+ && !pOpts->fDecompress
+ && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT))
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX,
+ "Yeah, right. I'm not writing any compressed data to the terminal without --force.\n");
+
+ rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT,
+ RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
+ true /*fLeaveOpen*/,
+ phVfsIos);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard output: %Rrc", rc);
+ }
+ else
+ {
+ Assert(!RTVfsChainIsSpec(pszFile));
+
+ /* Construct an output filename. */
+ rc = RTStrCopy(pOpts->szOutput, sizeof(pOpts->szOutput), pszFile);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc);
+ if (pOpts->fDecompress)
{
- rc = RTFileDelete(pszFile);
- if (RT_FAILURE(rc))
- rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTFileDelete failed with %rc: '%s'", rc, pszFile);
+ /** @todo take filename from archive? */
+ size_t cchSuff = strlen(pOpts->pszSuff); Assert(cchSuff > 0);
+ size_t cch = strlen(pOpts->szOutput);
+ if ( cch <= cchSuff
+ || strcmp(&pOpts->szOutput[cch - cchSuff], pOpts->pszSuff))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Input file does not end with: '%s'", pOpts->pszSuff);
+ pOpts->szOutput[cch - cchSuff] = '\0';
+ if (!RTPathFilename(pOpts->szOutput))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: Input file name is all suffix.");
}
else
{
- /* should we do this? */
- rc = RTFileDelete(szFinal);
+ rc = RTStrCat(pOpts->szOutput, sizeof(pOpts->szOutput), pOpts->pszSuff);
if (RT_FAILURE(rc))
- RTMsgError("RTFileDelete failed with %rc: '%s'", rc, pszFile);
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc);
}
+
+ /* Open the output file. */
+ uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE;
+ if (pOpts->fForce)
+ fOpen |= RTFILE_O_CREATE_REPLACE;
+ else
+ fOpen |= RTFILE_O_CREATE;
+ rc = RTVfsIoStrmOpenNormal(pOpts->szOutput, fOpen, phVfsIos);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening output file '%s': %Rrc", pOpts->szOutput, rc);
}
- return rcExit;
+ return RTEXITCODE_SUCCESS;
}
-static RTEXITCODE gzipTestFile(const char *pszFile, bool fForce)
+/**
+ * Opens the input file.
+ *
+ * @returns Command exit, error messages written using RTMsg*.
+ *
+ * @param pszFile The input filename.
+ * @param pOpts The options, szOutput will be filled in by this
+ * function on success.
+ * @param phVfsIos Where to return the input stream handle.
+ */
+static RTEXITCODE gzipOpenInput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos)
{
- return RTMsgErrorExit(RTEXITCODE_FAILURE, "Testiong has not been implemented");
-}
+ int rc;
+ pOpts->pszInput = pszFile;
+ if (!strcmp(pszFile, "-"))
+ {
+ if ( !pOpts->fForce
+ && pOpts->fDecompress
+ && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT))
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX,
+ "Yeah, right. I'm not reading any compressed data from the terminal without --force.\n");
+
+ rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT,
+ RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
+ true /*fLeaveOpen*/,
+ phVfsIos);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard input: %Rrc", rc);
+ }
+ else
+ {
+ const char *pszError;
+ rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, phVfsIos, &pszError);
+ if (RT_FAILURE(rc))
+ {
+ if (pszError && *pszError)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE,
+ "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
+ " '%s'\n",
+ " %*s^\n",
+ rc, pszFile, pszError - pszFile, "");
+ return RTMsgErrorExit(RTEXITCODE_FAILURE,
+ "RTVfsChainOpenIoStream failed with rc=%Rrc: '%s'",
+ rc, pszFile);
+ }
+ }
+
+ return RTEXITCODE_SUCCESS;
-static RTEXITCODE gzipListFile(const char *pszFile, bool fForce)
-{
- return RTMsgErrorExit(RTEXITCODE_FAILURE, "Listing has not been implemented");
}
-int main(int argc, char **argv)
+/**
+ * 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.)
+ */
+RTEXITCODE RTZipGzipCmd(unsigned cArgs, char **papszArgs)
{
- int rc = RTR3InitExe(argc, &argv, 0);
- if (RT_FAILURE(rc))
- return RTMsgInitFailure(rc);
/*
* Parse the command line.
@@ -222,6 +432,7 @@ int main(int argc, char **argv)
{ "--decompress", 'd', RTGETOPT_REQ_NOTHING },
{ "--uncompress", 'd', RTGETOPT_REQ_NOTHING },
{ "--force", 'f', RTGETOPT_REQ_NOTHING },
+ { "--keep", 'k', RTGETOPT_REQ_NOTHING },
{ "--list", 'l', RTGETOPT_REQ_NOTHING },
{ "--no-name", 'n', RTGETOPT_REQ_NOTHING },
{ "--name", 'N', RTGETOPT_REQ_NOTHING },
@@ -243,73 +454,83 @@ int main(int argc, char **argv)
{ "--best", '9', RTGETOPT_REQ_NOTHING }
};
- bool fAscii = false;
- bool fStdOut = false;
- bool fDecompress = false;
- bool fForce = false;
- bool fList = false;
- bool fName = true;
- bool fQuiet = false;
- bool fRecursive = false;
- const char *pszSuff = ".gz";
- bool fTest = false;
- unsigned uLevel = 6;
+ RTGZIPCMDOPTS Opts;
+ Opts.fAscii = false;
+ Opts.fStdOut = false;
+ Opts.fDecompress = false;
+ Opts.fForce = false;
+ Opts.fKeep = false;
+ Opts.fList = false;
+ Opts.fName = true;
+ Opts.fQuiet = false;
+ Opts.fRecursive = false;
+ Opts.pszSuff = ".gz";
+ Opts.fTest = false;
+ Opts.uLevel = 6;
RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
unsigned cProcessed = 0;
RTVFSIOSTREAM hVfsStdOut= NIL_RTVFSIOSTREAM;
RTGETOPTSTATE GetState;
- rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
- RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
+ RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTGetOptInit: %Rrc", rc);
+
for (;;)
{
RTGETOPTUNION ValueUnion;
- rc = RTGetOpt(&GetState, &ValueUnion);
- switch (rc)
+ int chOpt = RTGetOpt(&GetState, &ValueUnion);
+ switch (chOpt)
{
case 0:
- {
/*
* If we've processed any files we're done. Otherwise take
* input from stdin and write the output to stdout.
*/
if (cProcessed > 0)
return rcExit;
-#if 0
- rc = RTVfsFileFromRTFile(1,
- RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
- true /*fLeaveOpen*/,
- &hVfsOut);
-
-
- if (!fForce && isStdHandleATty(fDecompress ? 0 : 1))
- return RTMsgErrorExit(RTEXITCODE_SYNTAX,
- "Yeah, right. I'm not %s any compressed data %s the terminal without --force.\n",
- fDecompress ? "reading" : "writing",
- fDecompress ? "from" : "to");
-#else
- rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "reading from standard input has not yet been implemented");
-#endif
- return rcExit;
- }
-
+ ValueUnion.psz = "-";
+ Opts.fStdOut = true;
+ /* Fall thru. */
case VINF_GETOPT_NOT_OPTION:
{
- if (!*pszSuff && !fStdOut)
+ if (!*Opts.pszSuff && !Opts.fStdOut)
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --suffix option specified an empty string");
- if (!fStdOut && RTVfsChainIsSpec(ValueUnion.psz))
+ if (!Opts.fStdOut && RTVfsChainIsSpec(ValueUnion.psz))
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Must use standard out with VFS chain specifications");
-
- RTEXITCODE rcExit2;
- if (fList)
- rcExit2 = gzipListFile(ValueUnion.psz, fForce);
- else if (fTest)
- rcExit2 = gzipTestFile(ValueUnion.psz, fForce);
- else if (fDecompress)
- rcExit2 = gzipDecompressFile(ValueUnion.psz, fStdOut, fForce, &hVfsStdOut);
- else
- rcExit2 = gzipCompressFile(ValueUnion.psz, fStdOut, fForce, &hVfsStdOut);
+ if (Opts.fName)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --name option has not yet been implemented. Use --no-name.");
+ if (Opts.fAscii)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --ascii option has not yet been implemented.");
+ if (Opts.fRecursive)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --recursive option has not yet been implemented.");
+
+ /* Open the input file. */
+ RTVFSIOSTREAM hVfsSrc;
+ RTEXITCODE rcExit2 = gzipOpenInput(ValueUnion.psz, &Opts, &hVfsSrc);
+ if (rcExit2 == RTEXITCODE_SUCCESS)
+ {
+ if (Opts.fList)
+ rcExit2 = gzipListFile(&hVfsSrc, &Opts);
+ else if (Opts.fTest)
+ rcExit2 = gzipTestFile(&hVfsSrc, &Opts);
+ else
+ {
+ RTVFSIOSTREAM hVfsDst;
+ rcExit2 = gzipOpenOutput(ValueUnion.psz, &Opts, &hVfsDst);
+ if (rcExit2 == RTEXITCODE_SUCCESS)
+ {
+ if (Opts.fDecompress)
+ rcExit2 = gzipDecompressFile(&hVfsSrc, &Opts, &hVfsDst);
+ else
+ rcExit2 = gzipCompressFile(&hVfsSrc, &Opts, &hVfsDst);
+ RTVfsIoStrmRelease(hVfsDst);
+ }
+ }
+ RTVfsIoStrmRelease(hVfsSrc);
+ }
if (rcExit2 != RTEXITCODE_SUCCESS)
rcExit = rcExit2;
@@ -317,27 +538,31 @@ int main(int argc, char **argv)
break;
}
- case 'a': fAscii = true; break;
- case 'c': fStdOut = true; break;
- case 'd': fDecompress = true; break;
- case 'f': fForce = true; break;
- case 'l': fList = true; break;
- case 'n': fName = false; break;
- case 'N': fName = true; break;
- case 'q': fQuiet = true; break;
- case 'r': fRecursive = true; break;
- case 'S': pszSuff = ValueUnion.psz; break;
- case 't': fTest = true; break;
- case 'v': fQuiet = false; break;
- case '1': uLevel = 1; break;
- case '2': uLevel = 2; break;
- case '3': uLevel = 3; break;
- case '4': uLevel = 4; break;
- case '5': uLevel = 5; break;
- case '6': uLevel = 6; break;
- case '7': uLevel = 7; break;
- case '8': uLevel = 8; break;
- case '9': uLevel = 9; break;
+ case 'a': Opts.fAscii = true; break;
+ case 'c':
+ Opts.fStdOut = true;
+ Opts.fKeep = true;
+ break;
+ case 'd': Opts.fDecompress = true; break;
+ case 'f': Opts.fForce = true; break;
+ case 'k': Opts.fKeep = true; break;
+ case 'l': Opts.fList = true; break;
+ case 'n': Opts.fName = false; break;
+ case 'N': Opts.fName = true; break;
+ case 'q': Opts.fQuiet = true; break;
+ case 'r': Opts.fRecursive = true; break;
+ case 'S': Opts.pszSuff = ValueUnion.psz; break;
+ case 't': Opts.fTest = true; break;
+ case 'v': Opts.fQuiet = false; break;
+ case '1': Opts.uLevel = 1; break;
+ case '2': Opts.uLevel = 2; break;
+ case '3': Opts.uLevel = 3; break;
+ case '4': Opts.uLevel = 4; break;
+ case '5': Opts.uLevel = 5; break;
+ case '6': Opts.uLevel = 6; break;
+ case '7': Opts.uLevel = 7; break;
+ case '8': Opts.uLevel = 8; break;
+ case '9': Opts.uLevel = 9; break;
case 'h':
RTPrintf("Usage: to be written\nOption dump:\n");
@@ -350,8 +575,17 @@ int main(int argc, char **argv)
return RTEXITCODE_SUCCESS;
default:
- return RTGetOptPrintError(rc, &ValueUnion);
+ return RTGetOptPrintError(chOpt, &ValueUnion);
}
}
}
+
+int main(int argc, char **argv)
+{
+ int rc = RTR3InitExe(argc, &argv, 0);
+ if (RT_FAILURE(rc))
+ return RTMsgInitFailure(rc);
+ return RTZipGzipCmd(argc, argv);
+}
+
diff --git a/src/VBox/Runtime/tools/RTLdrFlt.cpp b/src/VBox/Runtime/tools/RTLdrFlt.cpp
index 2f56c3b1..bae231fb 100644
--- a/src/VBox/Runtime/tools/RTLdrFlt.cpp
+++ b/src/VBox/Runtime/tools/RTLdrFlt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -129,19 +129,39 @@ int main(int argc, char **argv)
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDBgAsCreate -> %Rrc", rc);
+ /*
+ * Create a debugging configuration instance to work with so that we can
+ * make use of (i.e. test) path searching and such.
+ */
+ RTDBGCFG hDbgCfg;
+ rc = RTDbgCfgCreate(&hDbgCfg, "IPRT", true /*fNativePaths*/);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgCfgCreate -> %Rrc", rc);
/*
* Parse arguments.
*/
static const RTGETOPTDEF s_aOptions[] =
{
- { "--input", 'i', RTGETOPT_REQ_STRING },
- { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+ { "--input", 'i', RTGETOPT_REQ_STRING },
+ { "--local-file", 'l', RTGETOPT_REQ_NOTHING },
+ { "--cache-file", 'c', RTGETOPT_REQ_NOTHING },
+ { "--pe-image", 'p', RTGETOPT_REQ_NOTHING },
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+ { "--x86", '8', RTGETOPT_REQ_NOTHING },
+ { "--amd64", '6', RTGETOPT_REQ_NOTHING },
+ { "--whatever", '*', RTGETOPT_REQ_NOTHING },
};
PRTSTREAM pInput = g_pStdIn;
PRTSTREAM pOutput = g_pStdOut;
unsigned cVerbosityLevel = 0;
+ enum {
+ kOpenMethod_FromImage,
+ kOpenMethod_FromPeImage
+ } enmOpenMethod = kOpenMethod_FromImage;
+ bool fCacheFile = false;
+ RTLDRARCH enmArch = RTLDRARCH_WHATEVER;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
@@ -156,18 +176,46 @@ int main(int argc, char **argv)
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open '%s' for reading: %Rrc", ValueUnion.psz, rc);
break;
+ case 'c':
+ fCacheFile = true;
+ break;
+
+ case 'l':
+ fCacheFile = false;
+ break;
+
+ case 'p':
+ enmOpenMethod = kOpenMethod_FromPeImage;
+ break;
+
case 'v':
cVerbosityLevel++;
break;
+ case '8':
+ enmArch = RTLDRARCH_X86_32;
+ break;
+
+ case '6':
+ enmArch = RTLDRARCH_AMD64;
+ break;
+
+ case '*':
+ enmArch = RTLDRARCH_WHATEVER;
+ break;
+
case 'h':
RTPrintf("Usage: %s [options] <module> <address> [<module> <address> [..]]\n"
"\n"
"Options:\n"
" -i,--input=file\n"
" Specify a input file instead of standard input.\n"
+ " --pe-image\n"
+ " Use RTDbgModCreateFromPeImage to open the file."
" -v, --verbose\n"
" Display the address space before doing the filtering.\n"
+ " --amd64,--x86,--whatever\n"
+ " Selects the desired architecture.\n"
" -h, -?, --help\n"
" Display this help text and exit successfully.\n"
" -V, --version\n"
@@ -176,7 +224,7 @@ int main(int argc, char **argv)
return RTEXITCODE_SUCCESS;
case 'V':
- RTPrintf("$Revision: 78250 $\n");
+ RTPrintf("$Revision: 87101 $\n");
return RTEXITCODE_SUCCESS;
case VINF_GETOPT_NOT_OPTION:
@@ -189,8 +237,26 @@ int main(int argc, char **argv)
return RTGetOptPrintError(rc, &ValueUnion);
uint64_t u64Address = ValueUnion.u64;
+ uint32_t cbImage = 0;
+ uint32_t uTimestamp = 0;
+ if (fCacheFile)
+ {
+ rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX);
+ if (RT_FAILURE(rc))
+ return RTGetOptPrintError(rc, &ValueUnion);
+ cbImage = ValueUnion.u32;
+
+ rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX);
+ if (RT_FAILURE(rc))
+ return RTGetOptPrintError(rc, &ValueUnion);
+ uTimestamp = ValueUnion.u32;
+ }
+
RTDBGMOD hMod;
- rc = RTDbgModCreateFromImage(&hMod, pszModule, NULL, 0 /*fFlags*/);
+ if (enmOpenMethod == kOpenMethod_FromImage)
+ rc = RTDbgModCreateFromImage(&hMod, pszModule, NULL, enmArch, hDbgCfg);
+ else
+ rc = RTDbgModCreateFromPeImage(&hMod, pszModule, NULL, NIL_RTLDRMOD, cbImage, uTimestamp, hDbgCfg);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgModCreateFromImage(,%s,,) -> %Rrc", pszModule, rc);
@@ -339,7 +405,7 @@ int main(int argc, char **argv)
*/
RTDBGLINE Line;
RTINTPTR offLine;
- rc = RTDbgAsLineByAddr(hDbgAs, u64Address, &offLine, &Line);
+ rc = RTDbgAsLineByAddr(hDbgAs, u64Address, &offLine, &Line, NULL);
if (RT_SUCCESS(rc))
RTStrmPrintf(pOutput, " %Rbn(%u)", Line.szFilename, Line.uLineNo);
diff --git a/src/VBox/Runtime/tools/RTManifest.cpp b/src/VBox/Runtime/tools/RTManifest.cpp
index ba67df46..828204d0 100644
--- a/src/VBox/Runtime/tools/RTManifest.cpp
+++ b/src/VBox/Runtime/tools/RTManifest.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/tools/RTNtDbgHelp.cpp b/src/VBox/Runtime/tools/RTNtDbgHelp.cpp
new file mode 100644
index 00000000..c20864bf
--- /dev/null
+++ b/src/VBox/Runtime/tools/RTNtDbgHelp.cpp
@@ -0,0 +1,380 @@
+/* $Id: RTNtDbgHelp.cpp $ */
+/** @file
+ * IPRT - RTNtDbgHelp - Tool for working/exploring DbgHelp.dll.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <Windows.h>
+#include <Dbghelp.h>
+
+#include <iprt/alloca.h>
+#include <iprt/dir.h>
+#include <iprt/file.h>
+#include <iprt/getopt.h>
+#include <iprt/env.h>
+#include <iprt/initterm.h>
+#include <iprt/list.h>
+#include <iprt/mem.h>
+#include <iprt/message.h>
+#include <iprt/path.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/err.h>
+
+#include <iprt/win/lazy-dbghelp.h>
+
+#include <iprt/ldrlazy.h>
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Debug module record.
+ *
+ * Used for dumping the whole context.
+ */
+typedef struct RTNTDBGHELPMOD
+{
+ /** The list bits. */
+ RTLISTNODE ListEntry;
+ /** The module address. */
+ uint64_t uModAddr;
+ /** Pointer to the name part of szFullName. */
+ char *pszName;
+ /** The module name. */
+ char szFullName[1];
+} RTNTDBGHELPMOD;
+/** Pointer to a debug module. */
+typedef RTNTDBGHELPMOD *PRTNTDBGHELPMOD;
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** Verbosity level. */
+static int g_iOptVerbose = 1;
+
+/** Fake process handle. */
+static HANDLE g_hFake = (HANDLE)0x1234567;
+/** Number of modules in the list. */
+static uint32_t g_cModules = 0;
+/** Module list. */
+static RTLISTANCHOR g_ModuleList;
+/** Set when initialized, clear until then. Lazy init on first operation. */
+static bool g_fInitialized = false;
+
+/** The current address register. */
+static uint64_t g_uCurAddress = 0;
+
+
+
+/**
+ * For debug/verbose output.
+ *
+ * @param iMin The minimum verbosity level for this message.
+ * @param pszFormat The format string.
+ * @param ... The arguments referenced in the format string.
+ */
+static void infoPrintf(int iMin, const char *pszFormat, ...)
+{
+ if (g_iOptVerbose >= iMin)
+ {
+ va_list va;
+ va_start(va, pszFormat);
+ RTPrintf("info: ");
+ RTPrintfV(pszFormat, va);
+ va_end(va);
+ }
+}
+
+static BOOL CALLBACK symDebugCallback64(HANDLE hProcess, ULONG uAction, ULONG64 ullData, ULONG64 ullUserCtx)
+{
+ NOREF(hProcess); NOREF(ullUserCtx);
+ switch (uAction)
+ {
+ case CBA_DEBUG_INFO:
+ {
+ const char *pszMsg = (const char *)(uintptr_t)ullData;
+ size_t cchMsg = strlen(pszMsg);
+ if (cchMsg > 0 && pszMsg[cchMsg - 1] == '\n')
+ RTPrintf("cba_debug_info: %s", pszMsg);
+ else
+ RTPrintf("cba_debug_info: %s\n", pszMsg);
+ return TRUE;
+ }
+
+ case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
+ return FALSE;
+
+ case CBA_EVENT:
+ return FALSE;
+
+ default:
+ RTPrintf("cba_???: uAction=%#x ullData=%#llx\n", uAction, ullData);
+ break;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Lazy initialization.
+ * @returns Exit code with any relevant complaints printed.
+ */
+static RTEXITCODE ensureInitialized(void)
+{
+ if (!g_fInitialized)
+ {
+ if (!SymInitialize(g_hFake, NULL, FALSE))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "SymInitialied failed: %u\n", GetLastError());
+ if (!SymRegisterCallback64(g_hFake, symDebugCallback64, 0))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "SymRegisterCallback64 failed: %u\n", GetLastError());
+ g_fInitialized = true;
+ infoPrintf(2, "SymInitialized(,,)\n");
+ }
+ return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Loads the given module, the address is either automatic or a previously given
+ * one.
+ *
+ * @returns Exit code with any relevant complaints printed.
+ * @param pszFile The file to load.
+ */
+static RTEXITCODE loadModule(const char *pszFile)
+{
+ RTEXITCODE rcExit = ensureInitialized();
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return rcExit;
+
+ uint64_t uModAddrReq = g_uCurAddress == 0 ? UINT64_C(0x1000000) * g_cModules : g_uCurAddress;
+ uint64_t uModAddrGot = SymLoadModuleEx(g_hFake, NULL /*hFile*/, pszFile, NULL /*pszModuleName*/,
+ uModAddrReq, 0, NULL /*pData*/, 0 /*fFlags*/);
+ if (uModAddrGot == 0)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "SymLoadModuleEx failed: %u\n", GetLastError());
+
+ size_t cbFullName = strlen(pszFile) + 1;
+ PRTNTDBGHELPMOD pMod = (PRTNTDBGHELPMOD)RTMemAlloc(RT_OFFSETOF(RTNTDBGHELPMOD, szFullName[cbFullName + 1]));
+ memcpy(pMod->szFullName, pszFile, cbFullName);
+ pMod->pszName = RTPathFilename(pMod->szFullName);
+ pMod->uModAddr = uModAddrGot;
+ RTListAppend(&g_ModuleList, &pMod->ListEntry);
+ infoPrintf(1, "%#018x %s\n", pMod->uModAddr, pMod->pszName);
+
+ return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Translates SYM_TYPE to string.
+ *
+ * @returns String.
+ * @param enmType The symbol type value.
+ */
+static const char *symTypeName(SYM_TYPE enmType)
+{
+ switch (enmType)
+ {
+ case SymCoff: return "SymCoff";
+ case SymCv: return "SymCv";
+ case SymPdb: return "SymPdb";
+ case SymExport: return "SymExport";
+ case SymDeferred: return "SymDeferred";
+ case SymSym: return "SymSym";
+ case SymDia: return "SymDia";
+ case SymVirtual: return "SymVirtual";
+ }
+ static char s_szBuf[32];
+ RTStrPrintf(s_szBuf, sizeof(s_szBuf), "Unknown-%#x", enmType);
+ return s_szBuf;
+}
+
+
+/**
+ * Symbol enumeration callback.
+ *
+ * @returns TRUE (continue enum).
+ * @param pSymInfo The symbol info.
+ * @param cbSymbol The symbol length (calculated).
+ * @param pvUser NULL.
+ */
+static BOOL CALLBACK dumpSymbolCallback(PSYMBOL_INFO pSymInfo, ULONG cbSymbol, PVOID pvUser)
+{
+ NOREF(pvUser);
+ RTPrintf(" %#018x LB %#07x %s\n", pSymInfo->Address, cbSymbol, pSymInfo->Name);
+ return TRUE;
+}
+
+/**
+ * Dumps all info.
+ * @returns Exit code with any relevant complaints printed.
+ */
+static RTEXITCODE dumpAll(void)
+{
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ PRTNTDBGHELPMOD pMod;
+ RTListForEach(&g_ModuleList, pMod, RTNTDBGHELPMOD, ListEntry)
+ {
+ RTPrintf("*** %#018x - %s ***\n", pMod->uModAddr, pMod->szFullName);
+
+ static const int8_t s_acbVariations[] = { 0, -4, -8, -12, -16, -20, -24, -28, -32, 4, 8, 12, 16, 20, 24, 28, 32 };
+ unsigned iVariation = 0;
+ union
+ {
+ IMAGEHLP_MODULE64 ModInfo;
+ uint8_t abPadding[sizeof(IMAGEHLP_MODULE64) + 64];
+ } u;
+
+ BOOL fRc;
+ do
+ {
+ RT_ZERO(u.ModInfo);
+ u.ModInfo.SizeOfStruct = sizeof(u.ModInfo) + s_acbVariations[iVariation++];
+ fRc = SymGetModuleInfo64(g_hFake, pMod->uModAddr, &u.ModInfo);
+ } while (!fRc && GetLastError() == ERROR_INVALID_PARAMETER && iVariation < RT_ELEMENTS(s_acbVariations));
+
+ if (fRc)
+ {
+ RTPrintf(" BaseOfImage = %#018llx\n", u.ModInfo.BaseOfImage);
+ RTPrintf(" ImageSize = %#010x\n", u.ModInfo.ImageSize);
+ RTPrintf(" TimeDateStamp = %#010x\n", u.ModInfo.TimeDateStamp);
+ RTPrintf(" CheckSum = %#010x\n", u.ModInfo.CheckSum);
+ RTPrintf(" NumSyms = %#010x (%u)\n", u.ModInfo.NumSyms, u.ModInfo.NumSyms);
+ RTPrintf(" SymType = %s\n", symTypeName(u.ModInfo.SymType));
+ RTPrintf(" ModuleName = %.32s\n", u.ModInfo.ModuleName);
+ RTPrintf(" ImageName = %.256s\n", u.ModInfo.ImageName);
+ RTPrintf(" LoadedImageName = %.256s\n", u.ModInfo.LoadedImageName);
+ RTPrintf(" LoadedPdbName = %.256s\n", u.ModInfo.LoadedPdbName);
+ RTPrintf(" CVSig = %#010x\n", u.ModInfo.CVSig);
+ /** @todo CVData. */
+ RTPrintf(" PdbSig = %#010x\n", u.ModInfo.PdbSig);
+ RTPrintf(" PdbSig70 = %RTuuid\n", &u.ModInfo.PdbSig70);
+ RTPrintf(" PdbAge = %#010x\n", u.ModInfo.PdbAge);
+ RTPrintf(" PdbUnmatched = %RTbool\n", u.ModInfo.PdbUnmatched);
+ RTPrintf(" DbgUnmatched = %RTbool\n", u.ModInfo.DbgUnmatched);
+ RTPrintf(" LineNumbers = %RTbool\n", u.ModInfo.LineNumbers);
+ RTPrintf(" GlobalSymbols = %RTbool\n", u.ModInfo.GlobalSymbols);
+ RTPrintf(" TypeInfo = %RTbool\n", u.ModInfo.TypeInfo);
+ RTPrintf(" SourceIndexed = %RTbool\n", u.ModInfo.SourceIndexed);
+ RTPrintf(" Publics = %RTbool\n", u.ModInfo.Publics);
+ }
+ else
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymGetModuleInfo64 failed: %u\n", GetLastError());
+
+ if (!SymEnumSymbols(g_hFake, pMod->uModAddr, NULL, dumpSymbolCallback, NULL))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymEnumSymbols failed: %u\n", GetLastError());
+
+ }
+ return rcExit;
+}
+
+
+int main(int argc, char **argv)
+{
+ int rc = RTR3InitExe(argc, &argv, 0 /*fFlags*/);
+ if (RT_FAILURE(rc))
+ return RTMsgInitFailure(rc);
+
+ RTListInit(&g_ModuleList);
+
+ /*
+ * Parse options.
+ */
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ { "--dump-all", 'd', RTGETOPT_REQ_NOTHING },
+ { "--load", 'l', RTGETOPT_REQ_STRING },
+ { "--set-address", 'a', RTGETOPT_REQ_UINT64 },
+#define OPT_SET_DEBUG_INFO 0x1000
+ { "--set-debug-info", OPT_SET_DEBUG_INFO, RTGETOPT_REQ_NOTHING },
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+ { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
+ };
+
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ const char *pszOutput = "-";
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
+ RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
+ {
+ switch (ch)
+ {
+ case 'v':
+ g_iOptVerbose++;
+ break;
+
+ case 'q':
+ g_iOptVerbose++;
+ break;
+
+ case 'l':
+ rcExit = loadModule(ValueUnion.psz);
+ break;
+
+ case 'a':
+ g_uCurAddress = ValueUnion.u64;
+ break;
+
+ case 'd':
+ rcExit = dumpAll();
+ break;
+
+ case OPT_SET_DEBUG_INFO:
+ rcExit = ensureInitialized();
+ if (rcExit == RTEXITCODE_SUCCESS && !SymSetOptions(SymGetOptions() | SYMOPT_DEBUG))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymSetOptions failed: %u\n", GetLastError());
+ break;
+
+
+ case 'V':
+ RTPrintf("$Revision: 85818 $");
+ break;
+
+ case 'h':
+ RTPrintf("usage: %s [-v|--verbose] [-q|--quiet] [--set-debug-info] [-a <addr>] [-l <file>] [-d] [...]\n"
+ " or: %s [-V|--version]\n"
+ " or: %s [-h|--help]\n",
+ argv[0], argv[0], argv[0]);
+ return RTEXITCODE_SUCCESS;
+
+ case VINF_GETOPT_NOT_OPTION:
+ default:
+ return RTGetOptPrintError(ch, &ValueUnion);
+ }
+ if (rcExit != RTEXITCODE_SUCCESS)
+ break;
+ }
+ return rcExit;
+}
+
diff --git a/src/VBox/Runtime/tools/RTRm.cpp b/src/VBox/Runtime/tools/RTRm.cpp
new file mode 100644
index 00000000..3ae187f7
--- /dev/null
+++ b/src/VBox/Runtime/tools/RTRm.cpp
@@ -0,0 +1,45 @@
+/* $Id: RTRm.cpp $ */
+/** @file
+ * IPRT - Remove Directory Entries Utility.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/path.h>
+#include <iprt/err.h>
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+
+
+int main(int argc, char **argv)
+{
+ int rc = RTR3InitExe(argc, &argv, 0);
+ if (RT_FAILURE(rc))
+ return RTMsgInitFailure(rc);
+ return RTPathRmCmd(argc, argv);
+}
+
+
diff --git a/src/VBox/Runtime/tools/RTTar.cpp b/src/VBox/Runtime/tools/RTTar.cpp
index d204db2b..784dfe9b 100644
--- a/src/VBox/Runtime/tools/RTTar.cpp
+++ b/src/VBox/Runtime/tools/RTTar.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/RTErrConvertFromWin32.cpp b/src/VBox/Runtime/win/RTErrConvertFromWin32.cpp
index 4164eefe..347d185b 100644
--- a/src/VBox/Runtime/win/RTErrConvertFromWin32.cpp
+++ b/src/VBox/Runtime/win/RTErrConvertFromWin32.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -48,6 +48,7 @@ RTR3DECL(int) RTErrConvertFromWin32(unsigned uNativeCode)
case ERROR_PATH_NOT_FOUND: return VERR_PATH_NOT_FOUND;
case ERROR_TOO_MANY_OPEN_FILES: return VERR_TOO_MANY_OPEN_FILES;
case ERROR_ACCESS_DENIED: return VERR_ACCESS_DENIED;
+ case ERROR_NOACCESS: return VERR_ACCESS_DENIED;
case ERROR_INVALID_HANDLE:
case ERROR_DIRECT_ACCESS_HANDLE: return VERR_INVALID_HANDLE;
diff --git a/src/VBox/Runtime/win/amd64/ASMAtomicBitClear.asm b/src/VBox/Runtime/win/amd64/ASMAtomicBitClear.asm
index 781d2933..4cba3892 100644
--- a/src/VBox/Runtime/win/amd64/ASMAtomicBitClear.asm
+++ b/src/VBox/Runtime/win/amd64/ASMAtomicBitClear.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMAtomicBitTestAndToggle.asm b/src/VBox/Runtime/win/amd64/ASMAtomicBitTestAndToggle.asm
index d50ac621..c84ccd35 100644
--- a/src/VBox/Runtime/win/amd64/ASMAtomicBitTestAndToggle.asm
+++ b/src/VBox/Runtime/win/amd64/ASMAtomicBitTestAndToggle.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMAtomicBitToggle.asm b/src/VBox/Runtime/win/amd64/ASMAtomicBitToggle.asm
index c1dbb74f..21790e05 100644
--- a/src/VBox/Runtime/win/amd64/ASMAtomicBitToggle.asm
+++ b/src/VBox/Runtime/win/amd64/ASMAtomicBitToggle.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMAtomicReadU64.asm b/src/VBox/Runtime/win/amd64/ASMAtomicReadU64.asm
index d166f69e..b2012855 100644
--- a/src/VBox/Runtime/win/amd64/ASMAtomicReadU64.asm
+++ b/src/VBox/Runtime/win/amd64/ASMAtomicReadU64.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMAtomicXchgU16.asm b/src/VBox/Runtime/win/amd64/ASMAtomicXchgU16.asm
index 9689047c..d4e85be5 100644
--- a/src/VBox/Runtime/win/amd64/ASMAtomicXchgU16.asm
+++ b/src/VBox/Runtime/win/amd64/ASMAtomicXchgU16.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMAtomicXchgU8.asm b/src/VBox/Runtime/win/amd64/ASMAtomicXchgU8.asm
index 467feb32..a7abc347 100644
--- a/src/VBox/Runtime/win/amd64/ASMAtomicXchgU8.asm
+++ b/src/VBox/Runtime/win/amd64/ASMAtomicXchgU8.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMBitFirstClear.asm b/src/VBox/Runtime/win/amd64/ASMBitFirstClear.asm
index 63d7dbf6..acff245c 100644
--- a/src/VBox/Runtime/win/amd64/ASMBitFirstClear.asm
+++ b/src/VBox/Runtime/win/amd64/ASMBitFirstClear.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMBitFirstSet.asm b/src/VBox/Runtime/win/amd64/ASMBitFirstSet.asm
index ebd5df34..4d48d2e9 100644
--- a/src/VBox/Runtime/win/amd64/ASMBitFirstSet.asm
+++ b/src/VBox/Runtime/win/amd64/ASMBitFirstSet.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetCS.asm b/src/VBox/Runtime/win/amd64/ASMGetCS.asm
index 7541e3c7..b07e9e2b 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetCS.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetCS.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetDR0.asm b/src/VBox/Runtime/win/amd64/ASMGetDR0.asm
index bb66d7b9..9fdd308f 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetDR0.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetDR0.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetDR1.asm b/src/VBox/Runtime/win/amd64/ASMGetDR1.asm
index ca02acbb..7c4d091c 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetDR1.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetDR1.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetDR2.asm b/src/VBox/Runtime/win/amd64/ASMGetDR2.asm
index 6e3b45ef..be74bff3 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetDR2.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetDR2.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetDR3.asm b/src/VBox/Runtime/win/amd64/ASMGetDR3.asm
index 8d0ab5e0..68f37887 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetDR3.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetDR3.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetDR6.asm b/src/VBox/Runtime/win/amd64/ASMGetDR6.asm
index 04d512a1..7125ff0e 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetDR6.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetDR6.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetDR7.asm b/src/VBox/Runtime/win/amd64/ASMGetDR7.asm
index e961f68e..b97eceb3 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetDR7.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetDR7.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetDS.asm b/src/VBox/Runtime/win/amd64/ASMGetDS.asm
index 0135c1ad..3c155fc6 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetDS.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetDS.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetES.asm b/src/VBox/Runtime/win/amd64/ASMGetES.asm
index 06f502ca..a13dc06b 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetES.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetES.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetFS.asm b/src/VBox/Runtime/win/amd64/ASMGetFS.asm
index 01750c96..107b9cce 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetFS.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetFS.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetFlags.asm b/src/VBox/Runtime/win/amd64/ASMGetFlags.asm
index f6dd3033..6a2790d2 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetFlags.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetFlags.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetGS.asm b/src/VBox/Runtime/win/amd64/ASMGetGS.asm
index 6b958c46..ea50571b 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetGS.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetGS.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMGetSS.asm b/src/VBox/Runtime/win/amd64/ASMGetSS.asm
index c297d41d..206e35c3 100644
--- a/src/VBox/Runtime/win/amd64/ASMGetSS.asm
+++ b/src/VBox/Runtime/win/amd64/ASMGetSS.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMProbeReadByte.asm b/src/VBox/Runtime/win/amd64/ASMProbeReadByte.asm
index 06ab2c04..bfc6a53a 100644
--- a/src/VBox/Runtime/win/amd64/ASMProbeReadByte.asm
+++ b/src/VBox/Runtime/win/amd64/ASMProbeReadByte.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/win/amd64/ASMSetFlags.asm b/src/VBox/Runtime/win/amd64/ASMSetFlags.asm
index 22280c2c..8744def8 100644
--- a/src/VBox/Runtime/win/amd64/ASMSetFlags.asm
+++ b/src/VBox/Runtime/win/amd64/ASMSetFlags.asm
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;