From fb123f93f9f5ce42c8e5785d2f8e0edaf951740e Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Wed, 26 Mar 2014 19:21:20 +0000 Subject: Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2. --- src/VBox/Runtime/.scm-settings | 2 +- src/VBox/Runtime/Makefile.kmk | 466 +++- src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp | 2 +- src/VBox/Runtime/VBox/VBoxRTDeps.cpp | 4 +- src/VBox/Runtime/VBox/VBoxRTImp.def | 37 +- src/VBox/Runtime/VBox/dbus.cpp | 2 +- src/VBox/Runtime/VBox/errmsgvboxcom.xsl | 2 +- src/VBox/Runtime/VBox/log-vbox.cpp | 36 +- src/VBox/Runtime/VBox/logbackdoor.cpp | 2 +- src/VBox/Runtime/common/alloc/alloc.cpp | 2 +- src/VBox/Runtime/common/alloc/heapoffset.cpp | 2 +- src/VBox/Runtime/common/alloc/heapsimple.cpp | 2 +- src/VBox/Runtime/common/alloc/memcache.cpp | 28 +- .../Runtime/common/asm/ASMAtomicCmpXchgExU64.asm | 8 +- .../Runtime/common/asm/ASMAtomicCmpXchgU64.asm | 4 +- src/VBox/Runtime/common/asm/ASMAtomicCmpXchgU8.asm | 2 +- src/VBox/Runtime/common/asm/ASMAtomicReadU64.asm | 2 +- src/VBox/Runtime/common/asm/ASMAtomicUoAndU32.asm | 58 + src/VBox/Runtime/common/asm/ASMAtomicUoAndU64.asm | 77 + src/VBox/Runtime/common/asm/ASMAtomicUoOrU32.asm | 57 + src/VBox/Runtime/common/asm/ASMAtomicUoOrU64.asm | 76 + src/VBox/Runtime/common/asm/ASMCpuIdExSlow.asm | 137 + src/VBox/Runtime/common/asm/ASMCpuId_Idx_ECX.asm | 116 + src/VBox/Runtime/common/asm/ASMGetGDTR.asm | 52 + src/VBox/Runtime/common/asm/ASMGetIDTR.asm | 52 + src/VBox/Runtime/common/asm/ASMGetLDTR.asm | 43 + src/VBox/Runtime/common/asm/ASMGetSegAttr.asm | 61 + src/VBox/Runtime/common/asm/ASMGetTR.asm | 43 + .../Runtime/common/asm/ASMMultU64ByU32DivByU32.asm | 2 +- src/VBox/Runtime/common/asm/ASMNopPause.asm | 2 +- src/VBox/Runtime/common/asm/ASMRdMsrEx.asm | 84 + src/VBox/Runtime/common/asm/ASMWrMsrEx.asm | 79 + src/VBox/Runtime/common/asm/asm-fake.cpp | 2 +- .../Runtime/common/checksum/RTSha256Digest.cpp | 201 ++ src/VBox/Runtime/common/checksum/adler32.cpp | 2 +- src/VBox/Runtime/common/checksum/crc32-zlib.cpp | 2 +- src/VBox/Runtime/common/checksum/crc32.cpp | 2 +- src/VBox/Runtime/common/checksum/crc64.cpp | 2 +- src/VBox/Runtime/common/checksum/ipv4.cpp | 2 +- src/VBox/Runtime/common/checksum/ipv6.cpp | 2 +- src/VBox/Runtime/common/checksum/manifest.cpp | 107 +- src/VBox/Runtime/common/checksum/manifest2.cpp | 2 +- src/VBox/Runtime/common/checksum/manifest3.cpp | 2 +- src/VBox/Runtime/common/checksum/md5.cpp | 8 +- src/VBox/Runtime/common/checksum/md5str.cpp | 2 +- src/VBox/Runtime/common/checksum/sha1.cpp | 2 +- src/VBox/Runtime/common/checksum/sha1str.cpp | 2 +- src/VBox/Runtime/common/checksum/sha256.cpp | 2 +- src/VBox/Runtime/common/checksum/sha256str.cpp | 2 +- src/VBox/Runtime/common/checksum/sha512.cpp | 2 +- src/VBox/Runtime/common/checksum/sha512str.cpp | 2 +- src/VBox/Runtime/common/dbg/dbg.cpp | 2 +- src/VBox/Runtime/common/dbg/dbgas.cpp | 180 +- src/VBox/Runtime/common/dbg/dbgcfg.cpp | 2172 +++++++++++++++ src/VBox/Runtime/common/dbg/dbgmod.cpp | 1290 +++++---- src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp | 2786 +++++++++++++++++++ src/VBox/Runtime/common/dbg/dbgmodcontainer.cpp | 186 +- src/VBox/Runtime/common/dbg/dbgmoddbghelp.cpp | 502 ++++ src/VBox/Runtime/common/dbg/dbgmoddeferred.cpp | 642 +++++ src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp | 1647 +++++++++-- src/VBox/Runtime/common/dbg/dbgmodexports.cpp | 164 ++ src/VBox/Runtime/common/dbg/dbgmodldr.cpp | 102 +- src/VBox/Runtime/common/dbg/dbgmodnm.cpp | 6 +- src/VBox/Runtime/common/dvm/dvm.cpp | 2 +- src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp | 2 +- src/VBox/Runtime/common/dvm/dvmgpt.cpp | 2 +- src/VBox/Runtime/common/dvm/dvmmbr.cpp | 2 +- .../Runtime/common/err/RTErrConvertFromErrno.cpp | 2 + .../Runtime/common/err/RTErrConvertToErrno.cpp | 2 +- src/VBox/Runtime/common/err/errinfo.cpp | 2 +- src/VBox/Runtime/common/err/errmsg.cpp | 2 +- src/VBox/Runtime/common/err/errmsg.sed | 35 +- src/VBox/Runtime/common/err/errmsgcom.sed | 2 +- src/VBox/Runtime/common/err/errmsgxpcom.cpp | 2 +- src/VBox/Runtime/common/filesystem/filesystem.cpp | 1 - .../Runtime/common/filesystem/filesystemext.cpp | 2 + src/VBox/Runtime/common/ldr/ldr.cpp | 81 +- src/VBox/Runtime/common/ldr/ldrELF.cpp | 6 +- .../Runtime/common/ldr/ldrELFRelocatable.cpp.h | 837 +++++- src/VBox/Runtime/common/ldr/ldrEx.cpp | 42 +- src/VBox/Runtime/common/ldr/ldrFile.cpp | 5 +- src/VBox/Runtime/common/ldr/ldrMemory.cpp | 324 +++ src/VBox/Runtime/common/ldr/ldrNative.cpp | 88 +- src/VBox/Runtime/common/ldr/ldrPE.cpp | 806 +++++- src/VBox/Runtime/common/ldr/ldrkStuff.cpp | 151 +- src/VBox/Runtime/common/log/log.cpp | 29 +- src/VBox/Runtime/common/log/logcom.cpp | 2 +- src/VBox/Runtime/common/log/logellipsis.cpp | 2 +- src/VBox/Runtime/common/log/logformat.cpp | 2 +- src/VBox/Runtime/common/log/logrel.cpp | 2 +- src/VBox/Runtime/common/log/logrelellipsis.cpp | 2 +- src/VBox/Runtime/common/math/ceill.asm | 4 +- src/VBox/Runtime/common/math/cosl.asm | 6 +- src/VBox/Runtime/common/math/fabs.asm | 4 +- src/VBox/Runtime/common/math/fabsf.asm | 4 +- src/VBox/Runtime/common/math/fabsl.asm | 6 +- src/VBox/Runtime/common/math/floor.asm | 4 +- src/VBox/Runtime/common/math/floorf.asm | 4 +- src/VBox/Runtime/common/math/floorl.asm | 4 +- src/VBox/Runtime/common/math/ldexpl.asm | 8 +- src/VBox/Runtime/common/math/llrint.asm | 2 +- src/VBox/Runtime/common/math/llrintf.asm | 2 +- src/VBox/Runtime/common/math/llrintl.asm | 6 +- src/VBox/Runtime/common/math/logl.asm | 6 +- src/VBox/Runtime/common/math/lrint.asm | 2 +- src/VBox/Runtime/common/math/lrintf.asm | 2 +- src/VBox/Runtime/common/math/lrintl.asm | 6 +- src/VBox/Runtime/common/math/remainder.asm | 2 +- src/VBox/Runtime/common/math/remainderf.asm | 2 +- src/VBox/Runtime/common/math/remainderl.asm | 2 +- src/VBox/Runtime/common/math/sinl.asm | 6 +- src/VBox/Runtime/common/math/tanl.asm | 6 +- src/VBox/Runtime/common/math/trunc.asm | 4 +- src/VBox/Runtime/common/math/truncf.asm | 4 +- src/VBox/Runtime/common/math/truncl.asm | 4 +- src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp | 2 +- src/VBox/Runtime/common/misc/RTAssertMsg2.cpp | 2 +- src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp | 2 +- .../Runtime/common/misc/RTAssertMsg2AddWeak.cpp | 2 +- .../Runtime/common/misc/RTAssertMsg2AddWeakV.cpp | 2 +- src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp | 2 +- src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp | 2 +- src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp | 337 +++ src/VBox/Runtime/common/misc/RTFileOpenF.cpp | 2 +- src/VBox/Runtime/common/misc/RTFileOpenV.cpp | 2 +- src/VBox/Runtime/common/misc/aiomgr.cpp | 1314 +++++++++ src/VBox/Runtime/common/misc/assert.cpp | 6 +- src/VBox/Runtime/common/misc/buildconfig.cpp | 2 +- src/VBox/Runtime/common/misc/cidr.cpp | 8 +- src/VBox/Runtime/common/misc/getopt.cpp | 89 +- src/VBox/Runtime/common/misc/getoptargv.cpp | 2 +- src/VBox/Runtime/common/misc/handletable.cpp | 12 +- src/VBox/Runtime/common/misc/handletable.h | 4 +- src/VBox/Runtime/common/misc/handletablectx.cpp | 2 +- src/VBox/Runtime/common/misc/handletablesimple.cpp | 2 +- src/VBox/Runtime/common/misc/http.cpp | 550 ++++ src/VBox/Runtime/common/misc/lockvalidator.cpp | 39 +- src/VBox/Runtime/common/misc/message.cpp | 2 +- src/VBox/Runtime/common/misc/once.cpp | 135 +- src/VBox/Runtime/common/misc/req.cpp | 4 +- src/VBox/Runtime/common/misc/reqpool.cpp | 2 +- src/VBox/Runtime/common/misc/reqqueue.cpp | 12 +- src/VBox/Runtime/common/misc/sanity-c.c | 2 +- src/VBox/Runtime/common/misc/sanity-cpp.cpp | 2 +- src/VBox/Runtime/common/misc/sanity.h | 2 +- src/VBox/Runtime/common/misc/semspingpong.cpp | 2 +- src/VBox/Runtime/common/misc/setjmp.asm | 2 +- src/VBox/Runtime/common/misc/sg.cpp | 58 +- src/VBox/Runtime/common/misc/term.cpp | 12 +- src/VBox/Runtime/common/misc/thread.cpp | 16 +- src/VBox/Runtime/common/net/macstr.cpp | 91 + src/VBox/Runtime/common/net/netaddrstr.cpp | 10 +- src/VBox/Runtime/common/net/netaddrstr2.cpp | 72 + src/VBox/Runtime/common/path/RTPathAbsDup.cpp | 2 +- src/VBox/Runtime/common/path/RTPathAbsEx.cpp | 2 +- src/VBox/Runtime/common/path/RTPathAbsExDup.cpp | 2 +- src/VBox/Runtime/common/path/RTPathAppend.cpp | 2 +- src/VBox/Runtime/common/path/RTPathAppendEx.cpp | 2 +- .../Runtime/common/path/RTPathCalcRelative.cpp | 130 + src/VBox/Runtime/common/path/RTPathExt.cpp | 2 +- src/VBox/Runtime/common/path/RTPathFilename.cpp | 76 +- src/VBox/Runtime/common/path/RTPathParse.cpp | 109 +- src/VBox/Runtime/common/path/RTPathParse.cpp.h | 250 ++ src/VBox/Runtime/common/path/RTPathParseSimple.cpp | 118 + .../Runtime/common/path/RTPathParsedReassemble.cpp | 122 + src/VBox/Runtime/common/path/RTPathRealDup.cpp | 2 +- src/VBox/Runtime/common/path/RTPathRmCmd.cpp | 648 +++++ src/VBox/Runtime/common/path/RTPathSplit.cpp | 133 + src/VBox/Runtime/common/path/RTPathSplitA.cpp | 91 + .../Runtime/common/path/RTPathSplitReassemble.cpp | 120 + src/VBox/Runtime/common/path/RTPathStripExt.cpp | 2 +- .../Runtime/common/path/RTPathStripFilename.cpp | 2 +- .../Runtime/common/path/RTPathTraverseList.cpp | 2 +- src/VBox/Runtime/common/path/comparepaths.cpp | 2 +- src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp | 4 +- .../Runtime/common/path/rtPathVolumeSpecLen.cpp | 2 +- .../common/path/rtpath-expand-template.cpp.h | 82 + src/VBox/Runtime/common/rand/rand.cpp | 28 +- src/VBox/Runtime/common/rand/randadv.cpp | 2 +- src/VBox/Runtime/common/rand/randparkmiller.cpp | 2 +- src/VBox/Runtime/common/string/RTStrCmp.cpp | 2 +- src/VBox/Runtime/common/string/RTStrNCmp.cpp | 17 +- src/VBox/Runtime/common/string/RTStrNLen.cpp | 2 +- src/VBox/Runtime/common/string/RTStrNLenEx.cpp | 2 +- .../Runtime/common/string/RTStrPrintHexBytes.cpp | 2 +- src/VBox/Runtime/common/string/RTStrStr.cpp | 2 +- src/VBox/Runtime/common/string/base64.cpp | 2 +- src/VBox/Runtime/common/string/memchr.asm | 2 +- src/VBox/Runtime/common/string/memchr.cpp | 2 +- src/VBox/Runtime/common/string/memchr_alias.c | 2 +- src/VBox/Runtime/common/string/memcmp.asm | 2 +- src/VBox/Runtime/common/string/memcmp.cpp | 2 +- src/VBox/Runtime/common/string/memcmp_alias.c | 2 +- src/VBox/Runtime/common/string/memcpy.asm | 2 +- src/VBox/Runtime/common/string/memcpy.cpp | 2 +- src/VBox/Runtime/common/string/memcpy_alias.c | 2 +- src/VBox/Runtime/common/string/memmove.asm | 2 +- src/VBox/Runtime/common/string/memmove_alias.c | 2 +- src/VBox/Runtime/common/string/mempcpy.asm | 2 +- src/VBox/Runtime/common/string/memset.asm | 2 +- src/VBox/Runtime/common/string/memset.cpp | 2 +- src/VBox/Runtime/common/string/memset_alias.c | 2 +- src/VBox/Runtime/common/string/simplepattern.cpp | 2 +- src/VBox/Runtime/common/string/straprintf.cpp | 2 +- src/VBox/Runtime/common/string/strcache.cpp | 1163 +++++++- src/VBox/Runtime/common/string/strchr.asm | 2 +- src/VBox/Runtime/common/string/strchr_alias.c | 2 +- src/VBox/Runtime/common/string/strcmp.asm | 2 +- src/VBox/Runtime/common/string/strcmp_alias.c | 2 +- src/VBox/Runtime/common/string/strcpy.asm | 2 +- src/VBox/Runtime/common/string/strcpy.cpp | 2 +- src/VBox/Runtime/common/string/strcpy_alias.c | 2 +- src/VBox/Runtime/common/string/strformat.cpp | 2 +- src/VBox/Runtime/common/string/strformatnum.cpp | 4 +- src/VBox/Runtime/common/string/strformatrt.cpp | 189 +- src/VBox/Runtime/common/string/strformattype.cpp | 6 +- src/VBox/Runtime/common/string/strlen.asm | 2 +- src/VBox/Runtime/common/string/strlen.cpp | 2 +- src/VBox/Runtime/common/string/strlen_alias.c | 2 +- src/VBox/Runtime/common/string/strncmp.cpp | 2 +- src/VBox/Runtime/common/string/strpbrk.cpp | 2 +- src/VBox/Runtime/common/string/strprintf.cpp | 2 +- src/VBox/Runtime/common/string/strspace.cpp | 2 +- src/VBox/Runtime/common/string/strstrip.cpp | 2 +- src/VBox/Runtime/common/string/strtonum.cpp | 2 +- src/VBox/Runtime/common/string/strversion.cpp | 2 +- src/VBox/Runtime/common/string/uni.cpp | 2 +- src/VBox/Runtime/common/string/unidata.cpp | 2 +- src/VBox/Runtime/common/string/uniread.cpp | 4 +- src/VBox/Runtime/common/string/utf-16.cpp | 2 +- src/VBox/Runtime/common/string/utf-8-case.cpp | 79 + src/VBox/Runtime/common/string/utf-8.cpp | 2 +- src/VBox/Runtime/common/table/avl_Base.cpp.h | 2 +- src/VBox/Runtime/common/table/avl_Destroy.cpp.h | 10 +- src/VBox/Runtime/common/table/avl_DoWithAll.cpp.h | 14 +- src/VBox/Runtime/common/table/avl_Enum.cpp.h | 2 +- src/VBox/Runtime/common/table/avl_Get.cpp.h | 2 +- src/VBox/Runtime/common/table/avl_GetBestFit.cpp.h | 2 +- src/VBox/Runtime/common/table/avl_Range.cpp.h | 2 +- .../Runtime/common/table/avl_RemoveBestFit.cpp.h | 2 +- src/VBox/Runtime/common/table/avl_RemoveNode.cpp.h | 3 +- src/VBox/Runtime/common/table/avlgcphys.cpp | 3 +- src/VBox/Runtime/common/table/avlgcptr.cpp | 4 +- src/VBox/Runtime/common/table/avlhcphys.cpp | 3 +- src/VBox/Runtime/common/table/avllu32.cpp | 3 +- src/VBox/Runtime/common/table/avlogcphys.cpp | 3 +- src/VBox/Runtime/common/table/avlogcptr.cpp | 3 +- src/VBox/Runtime/common/table/avlohcphys.cpp | 3 +- src/VBox/Runtime/common/table/avloioport.cpp | 3 +- src/VBox/Runtime/common/table/avlou32.cpp | 3 +- src/VBox/Runtime/common/table/avlpv.cpp | 4 +- src/VBox/Runtime/common/table/avlrfoff.cpp | 3 +- src/VBox/Runtime/common/table/avlrgcptr.cpp | 3 +- src/VBox/Runtime/common/table/avlrogcphys.cpp | 3 +- src/VBox/Runtime/common/table/avlrogcptr.cpp | 3 +- src/VBox/Runtime/common/table/avlroioport.cpp | 3 +- src/VBox/Runtime/common/table/avlroogcptr.cpp | 3 +- src/VBox/Runtime/common/table/avlrpv.cpp | 4 +- src/VBox/Runtime/common/table/avlru64.cpp | 4 +- src/VBox/Runtime/common/table/avlruintptr.cpp | 3 +- src/VBox/Runtime/common/table/avlu32.cpp | 3 +- src/VBox/Runtime/common/table/avluintptr.cpp | 3 +- src/VBox/Runtime/common/table/avlul.cpp | 3 +- src/VBox/Runtime/common/table/table.cpp | 2 +- src/VBox/Runtime/common/time/time.cpp | 164 +- src/VBox/Runtime/common/time/timeprog.cpp | 2 +- src/VBox/Runtime/common/time/timesup.cpp | 2 +- src/VBox/Runtime/common/time/timesupA.asm | 2 +- src/VBox/Runtime/common/time/timesupA.mac | 2 +- src/VBox/Runtime/common/time/timesupref.h | 2 +- src/VBox/Runtime/common/time/timesysalias.cpp | 2 +- src/VBox/Runtime/common/vfs/vfsbase.cpp | 2 +- src/VBox/Runtime/common/vfs/vfschain.cpp | 12 +- src/VBox/Runtime/common/vfs/vfsmisc.cpp | 2 +- src/VBox/Runtime/common/vfs/vfsstdfile.cpp | 71 +- src/VBox/Runtime/common/zip/gzipvfs.cpp | 348 ++- src/VBox/Runtime/common/zip/tar.cpp | 170 +- src/VBox/Runtime/common/zip/tarcmd.cpp | 745 ++++- src/VBox/Runtime/common/zip/tarvfs.cpp | 2 +- src/VBox/Runtime/common/zip/xarvfs.cpp | 2111 ++++++++++++++ src/VBox/Runtime/common/zip/zip.cpp | 45 +- src/VBox/Runtime/darwin/RTErrConvertFromDarwin.cpp | 2 +- .../Runtime/darwin/RTErrConvertFromDarwinCOM.cpp | 2 +- .../Runtime/darwin/RTErrConvertFromDarwinIO.cpp | 2 +- .../Runtime/darwin/RTErrConvertFromDarwinKern.cpp | 2 +- src/VBox/Runtime/gc/initterm-gc.cpp | 2 +- .../generic/RTAssertShouldPanic-generic.cpp | 2 +- src/VBox/Runtime/generic/RTDirExists-generic.cpp | 2 +- .../Runtime/generic/RTDirQueryInfo-generic.cpp | 2 +- src/VBox/Runtime/generic/RTDirSetTimes-generic.cpp | 2 +- src/VBox/Runtime/generic/RTFileCopy-generic.cpp | 2 +- src/VBox/Runtime/generic/RTFileExists-generic.cpp | 2 +- src/VBox/Runtime/generic/RTFileMove-generic.cpp | 2 +- .../Runtime/generic/RTFileQuerySize-generic.cpp | 2 +- src/VBox/Runtime/generic/RTFileReadAll-generic.cpp | 2 +- .../generic/RTFileReadAllByHandle-generic.cpp | 2 +- .../generic/RTFileReadAllByHandleEx-generic.cpp | 2 +- .../Runtime/generic/RTFileReadAllEx-generic.cpp | 2 +- .../Runtime/generic/RTFileReadAllFree-generic.cpp | 2 +- .../Runtime/generic/RTLogDefaultInit-generic.cpp | 2 +- .../Runtime/generic/RTLogWriteDebugger-generic.cpp | 2 +- .../Runtime/generic/RTLogWriteStdErr-generic.cpp | 2 +- .../generic/RTLogWriteStdErr-stub-generic.cpp | 2 +- .../Runtime/generic/RTLogWriteStdOut-generic.cpp | 2 +- .../generic/RTLogWriteStdOut-stub-generic.cpp | 2 +- .../Runtime/generic/RTLogWriteUser-generic.cpp | 2 +- src/VBox/Runtime/generic/RTMpCpuId-generic.cpp | 2 +- .../generic/RTMpCpuIdFromSetIndex-generic.cpp | 2 +- .../generic/RTMpCpuIdToSetIndex-generic.cpp | 2 +- .../Runtime/generic/RTMpGetArraySize-generic.cpp | 2 +- .../Runtime/generic/RTMpGetCoreCount-generic.cpp | 40 + src/VBox/Runtime/generic/RTMpGetCount-generic.cpp | 2 +- .../generic/RTMpGetCurFrequency-generic.cpp | 2 +- .../generic/RTMpGetDescription-generic-stub.cpp | 2 +- .../Runtime/generic/RTMpGetDescription-generic.cpp | 9 +- .../Runtime/generic/RTMpGetMaxCpuId-generic.cpp | 2 +- .../generic/RTMpGetMaxFrequency-generic.cpp | 2 +- .../generic/RTMpGetOnlineCoreCount-generic.cpp | 40 + .../Runtime/generic/RTMpGetOnlineCount-generic.cpp | 2 +- .../Runtime/generic/RTMpGetOnlineSet-generic.cpp | 2 +- src/VBox/Runtime/generic/RTMpGetSet-generic.cpp | 2 +- .../Runtime/generic/RTMpIsCpuOnline-generic.cpp | 2 +- .../Runtime/generic/RTMpIsCpuPossible-generic.cpp | 2 +- src/VBox/Runtime/generic/RTPathIsSame-generic.cpp | 93 + .../Runtime/generic/RTProcDaemonize-generic.cpp | 5 +- .../generic/RTProcIsRunningByName-generic.cpp | 2 +- .../generic/RTProcessQueryUsernameA-generic.cpp | 2 +- .../RTRandAdvCreateSystemFaster-generic.cpp | 2 +- .../generic/RTRandAdvCreateSystemTruer-generic.cpp | 2 +- .../generic/RTSemEventMultiWait-2-ex-generic.cpp | 2 +- .../generic/RTSemEventMultiWait-generic.cpp | 2 +- .../RTSemEventMultiWaitNoResume-2-ex-generic.cpp | 2 +- .../generic/RTSemEventWait-2-ex-generic.cpp | 2 +- .../Runtime/generic/RTSemEventWait-generic.cpp | 2 +- .../RTSemEventWaitNoResume-2-ex-generic.cpp | 2 +- .../Runtime/generic/RTSemMutexRequest-generic.cpp | 2 +- .../generic/RTSemMutexRequestDebug-generic.cpp | 2 +- .../generic/RTSystemQueryOSInfo-generic.cpp | 2 +- .../generic/RTTimeLocalDeltaNano-generic.cpp | 2 +- .../Runtime/generic/RTTimeLocalExplode-generic.cpp | 2 +- .../Runtime/generic/RTTimeLocalNow-generic.cpp | 2 +- .../Runtime/generic/RTTimerLRCreate-generic.cpp | 2 +- src/VBox/Runtime/generic/RTUuidCreate-generic.cpp | 2 +- src/VBox/Runtime/generic/cdrom-generic.cpp | 1 - src/VBox/Runtime/generic/createtemp-generic.cpp | 4 +- src/VBox/Runtime/generic/critsect-generic.cpp | 2 +- src/VBox/Runtime/generic/critsectrw-generic.cpp | 917 ++++++ src/VBox/Runtime/generic/env-generic.cpp | 103 +- src/VBox/Runtime/generic/fs-stubs-generic.cpp | 2 +- src/VBox/Runtime/generic/mempool-generic.cpp | 2 +- src/VBox/Runtime/generic/mppresent-generic.cpp | 9 +- src/VBox/Runtime/generic/sched-generic.cpp | 2 +- src/VBox/Runtime/generic/semfastmutex-generic.cpp | 2 +- src/VBox/Runtime/generic/semrw-generic.cpp | 2 +- .../Runtime/generic/semrw-lockless-generic.cpp | 19 +- src/VBox/Runtime/generic/semxroads-generic.cpp | 2 +- .../Runtime/generic/strcache-stubs-generic.cpp | 39 +- src/VBox/Runtime/generic/timer-generic.cpp | 13 +- src/VBox/Runtime/generic/timerlr-generic.cpp | 2 +- src/VBox/Runtime/generic/tls-generic.cpp | 2 +- src/VBox/Runtime/generic/utf16locale-generic.cpp | 2 +- src/VBox/Runtime/generic/uuid-generic.cpp | 2 +- .../Runtime/include/internal/alignmentchecks.h | 2 +- src/VBox/Runtime/include/internal/assert.h | 2 +- src/VBox/Runtime/include/internal/dbgmod.h | 170 +- src/VBox/Runtime/include/internal/dir.h | 54 +- src/VBox/Runtime/include/internal/dvm.h | 2 +- src/VBox/Runtime/include/internal/file.h | 2 +- src/VBox/Runtime/include/internal/fileaio.h | 2 +- src/VBox/Runtime/include/internal/fs.h | 2 +- src/VBox/Runtime/include/internal/initterm.h | 2 +- src/VBox/Runtime/include/internal/iprt.h | 2 +- src/VBox/Runtime/include/internal/ldr.h | 57 +- src/VBox/Runtime/include/internal/ldrELF.h | 2 +- src/VBox/Runtime/include/internal/ldrELF32.h | 2 +- src/VBox/Runtime/include/internal/ldrELF64.h | 2 +- src/VBox/Runtime/include/internal/ldrMZ.h | 2 +- src/VBox/Runtime/include/internal/ldrMach-O.h | 625 ----- src/VBox/Runtime/include/internal/ldrPE.h | 565 +++- src/VBox/Runtime/include/internal/lockvalidator.h | 2 +- src/VBox/Runtime/include/internal/magics.h | 16 +- src/VBox/Runtime/include/internal/path.h | 2 +- src/VBox/Runtime/include/internal/pipe.h | 53 +- src/VBox/Runtime/include/internal/process.h | 2 +- src/VBox/Runtime/include/internal/rand.h | 2 +- src/VBox/Runtime/include/internal/sched.h | 2 +- src/VBox/Runtime/include/internal/socket.h | 6 +- src/VBox/Runtime/include/internal/strhash.h | 2 +- src/VBox/Runtime/include/internal/strict.h | 9 +- src/VBox/Runtime/include/internal/thread.h | 15 +- src/VBox/Runtime/nt/NtProcessStartup-stub.cpp | 2 +- src/VBox/Runtime/nt/RTErrConvertFromNtStatus.cpp | 31 +- src/VBox/Runtime/os2/RTErrConvertFromOS2.cpp | 2 +- .../Runtime/os2/rtSemWaitOs2ConvertTimeout.cpp | 10 +- src/VBox/Runtime/os2/sys0.asm | 2 +- src/VBox/Runtime/r0drv/alloc-r0drv.cpp | 6 +- src/VBox/Runtime/r0drv/alloc-r0drv.h | 2 +- .../darwin/RTLogWriteDebugger-r0drv-darwin.cpp | 2 +- .../r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp | 2 +- .../Runtime/r0drv/darwin/assert-r0drv-darwin.cpp | 2 +- .../r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp | 2 +- .../Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp | 2 +- .../Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp | 8 +- .../r0drv/darwin/memuserkernel-r0drv-darwin.cpp | 3 +- src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp | 2 +- .../Runtime/r0drv/darwin/process-r0drv-darwin.cpp | 2 +- .../Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp | 2 +- .../r0drv/darwin/semeventmulti-r0drv-darwin.cpp | 2 +- .../Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp | 2 +- .../Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp | 2 +- src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h | 8 +- .../Runtime/r0drv/darwin/thread-r0drv-darwin.cpp | 2 +- .../Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp | 2 +- .../r0drv/darwin/threadpreempt-r0drv-darwin.cpp | 6 +- .../Runtime/r0drv/darwin/time-r0drv-darwin.cpp | 2 +- .../Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c | 5 + .../Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c | 63 + .../r0drv/freebsd/memuserkernel-r0drv-freebsd.c | 3 +- src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c | 7 +- .../Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c | 2 +- .../r0drv/freebsd/sleepqueue-r0drv-freebsd.h | 6 +- .../Runtime/r0drv/freebsd/the-freebsd-kernel.h | 4 + .../Runtime/r0drv/freebsd/thread-r0drv-freebsd.c | 2 +- .../generic/RTMpIsCpuWorkPending-r0drv-generic.cpp | 2 +- .../Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp | 2 +- .../r0drv/generic/RTMpPokeCpu-r0drv-generic.cpp | 2 +- .../RTThreadPreemptDisable-r0drv-generic.cpp | 2 +- .../RTThreadPreemptIsEnabled-r0drv-generic.cpp | 2 +- .../RTThreadPreemptIsPending-r0drv-generic.cpp | 2 +- ...TThreadPreemptIsPendingTrusty-r0drv-generic.cpp | 2 +- .../RTThreadPreemptRestore-r0drv-generic.cpp | 2 +- .../r0drv/generic/mpnotification-r0drv-generic.cpp | 2 +- .../r0drv/generic/semspinmutex-r0drv-generic.c | 2 +- .../r0drv/generic/threadctxhooks-r0drv-generic.cpp | 84 + .../r0drv/haiku/RTLogWriteDebugger-r0drv-haiku.c | 42 + .../r0drv/haiku/RTLogWriteStdOut-r0drv-haiku.c | 41 + src/VBox/Runtime/r0drv/haiku/alloc-r0drv-haiku.c | 124 + src/VBox/Runtime/r0drv/haiku/assert-r0drv-haiku.c | 68 + .../Runtime/r0drv/haiku/initterm-r0drv-haiku.c | 48 + src/VBox/Runtime/r0drv/haiku/memobj-r0drv-haiku.c | 663 +++++ src/VBox/Runtime/r0drv/haiku/mp-r0drv-haiku.c | 218 ++ src/VBox/Runtime/r0drv/haiku/process-r0drv-haiku.c | 46 + .../Runtime/r0drv/haiku/semevent-r0drv-haiku.c | 264 ++ .../r0drv/haiku/semeventmulti-r0drv-haiku.c | 291 ++ .../Runtime/r0drv/haiku/semfastmutex-r0drv-haiku.c | 120 + .../Runtime/r0drv/haiku/semmutex-r0drv-haiku.c | 233 ++ .../Runtime/r0drv/haiku/spinlock-r0drv-haiku.c | 146 + src/VBox/Runtime/r0drv/haiku/the-haiku-kernel.h | 114 + src/VBox/Runtime/r0drv/haiku/thread-r0drv-haiku.c | 127 + src/VBox/Runtime/r0drv/haiku/thread2-r0drv-haiku.c | 131 + src/VBox/Runtime/r0drv/haiku/time-r0drv-haiku.c | 79 + src/VBox/Runtime/r0drv/initterm-r0drv.cpp | 17 +- .../r0drv/linux/RTLogWriteDebugger-r0drv-linux.c | 2 +- src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c | 10 +- src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c | 2 +- .../Runtime/r0drv/linux/initterm-r0drv-linux.c | 2 +- src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c | 33 +- .../r0drv/linux/memuserkernel-r0drv-linux.c | 2 +- src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c | 2 +- .../r0drv/linux/mpnotification-r0drv-linux.c | 2 +- src/VBox/Runtime/r0drv/linux/process-r0drv-linux.c | 2 +- .../Runtime/r0drv/linux/semevent-r0drv-linux.c | 2 +- .../r0drv/linux/semeventmulti-r0drv-linux.c | 2 +- .../Runtime/r0drv/linux/semmutex-r0drv-linux.c | 2 +- .../Runtime/r0drv/linux/spinlock-r0drv-linux.c | 15 +- src/VBox/Runtime/r0drv/linux/string.h | 2 +- src/VBox/Runtime/r0drv/linux/the-linux-kernel.h | 14 +- src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c | 6 +- src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c | 2 +- .../r0drv/linux/threadctxhooks-r0drv-linux.c | 330 +++ src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c | 2 +- src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c | 4 +- src/VBox/Runtime/r0drv/memobj-r0drv.cpp | 10 +- src/VBox/Runtime/r0drv/mp-r0drv.h | 2 +- src/VBox/Runtime/r0drv/mpnotification-r0drv.c | 4 +- .../r0drv/nt/RTLogWriteDebugger-r0drv-nt.cpp | 2 +- src/VBox/Runtime/r0drv/nt/alloc-r0drv-nt.cpp | 2 +- src/VBox/Runtime/r0drv/nt/assert-r0drv-nt.cpp | 2 +- src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp | 349 ++- src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h | 4 +- src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp | 2 +- .../Runtime/r0drv/nt/memuserkernel-r0drv-nt.cpp | 2 +- src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp | 2 +- .../Runtime/r0drv/nt/mpnotification-r0drv-nt.cpp | 2 +- src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp | 1203 ++++++++ src/VBox/Runtime/r0drv/nt/process-r0drv-nt.cpp | 2 +- src/VBox/Runtime/r0drv/nt/semevent-r0drv-nt.cpp | 2 +- .../Runtime/r0drv/nt/semeventmulti-r0drv-nt.cpp | 2 +- .../Runtime/r0drv/nt/semfastmutex-r0drv-nt.cpp | 2 +- src/VBox/Runtime/r0drv/nt/semmutex-r0drv-nt.cpp | 2 +- src/VBox/Runtime/r0drv/nt/spinlock-r0drv-nt.cpp | 8 +- src/VBox/Runtime/r0drv/nt/symdb.h | 85 + src/VBox/Runtime/r0drv/nt/symdbdata.h | 2920 ++++++++++++++++++++ src/VBox/Runtime/r0drv/nt/the-nt-kernel.h | 2 +- src/VBox/Runtime/r0drv/nt/thread-r0drv-nt.cpp | 7 +- src/VBox/Runtime/r0drv/nt/thread2-r0drv-nt.cpp | 2 +- src/VBox/Runtime/r0drv/nt/time-r0drv-nt.cpp | 26 +- src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp | 17 +- .../Runtime/r0drv/os2/memuserkernel-r0drv-os2.cpp | 2 +- src/VBox/Runtime/r0drv/os2/semevent-r0drv-os2.cpp | 4 +- .../Runtime/r0drv/os2/semeventmulti-r0drv-os2.cpp | 4 +- src/VBox/Runtime/r0drv/os2/spinlock-r0drv-os2.cpp | 3 + src/VBox/Runtime/r0drv/power-r0drv.h | 2 +- src/VBox/Runtime/r0drv/powernotification-r0drv.c | 2 +- .../solaris/RTLogWriteDebugger-r0drv-solaris.c | 11 +- .../r0drv/solaris/RTMpPokeCpu-r0drv-solaris.c | 2 +- .../Runtime/r0drv/solaris/alloc-r0drv-solaris.c | 4 +- .../Runtime/r0drv/solaris/assert-r0drv-solaris.c | 2 +- .../Runtime/r0drv/solaris/initterm-r0drv-solaris.c | 28 +- .../Runtime/r0drv/solaris/memobj-r0drv-solaris.c | 6 +- .../r0drv/solaris/memuserkernel-r0drv-solaris.c | 2 +- src/VBox/Runtime/r0drv/solaris/mp-r0drv-solaris.c | 8 +- .../r0drv/solaris/mpnotification-r0drv-solaris.c | 2 +- .../Runtime/r0drv/solaris/process-r0drv-solaris.c | 2 +- .../Runtime/r0drv/solaris/semevent-r0drv-solaris.c | 2 +- .../r0drv/solaris/semeventmulti-r0drv-solaris.c | 2 +- .../r0drv/solaris/semeventwait-r0drv-solaris.h | 2 +- .../r0drv/solaris/semfastmutex-r0drv-solaris.c | 2 +- .../Runtime/r0drv/solaris/semmutex-r0drv-solaris.c | 2 +- .../Runtime/r0drv/solaris/spinlock-r0drv-solaris.c | 2 +- .../Runtime/r0drv/solaris/the-solaris-kernel.h | 49 +- .../Runtime/r0drv/solaris/thread-r0drv-solaris.c | 2 +- .../Runtime/r0drv/solaris/thread2-r0drv-solaris.c | 2 +- .../r0drv/solaris/threadctxhooks-r0drv-solaris.c | 337 +++ .../Runtime/r0drv/solaris/time-r0drv-solaris.c | 2 +- .../Runtime/r0drv/solaris/timer-r0drv-solaris.c | 73 +- src/VBox/Runtime/r3/alloc-ef-cpp.cpp | 2 +- src/VBox/Runtime/r3/alloc-ef.cpp | 2 +- src/VBox/Runtime/r3/alloc.cpp | 6 +- src/VBox/Runtime/r3/allocex.cpp | 126 + src/VBox/Runtime/r3/allocex.h | 84 + .../r3/darwin/RTPathUserDocuments-darwin.cpp | 65 +- src/VBox/Runtime/r3/darwin/mp-darwin.cpp | 83 +- .../Runtime/r3/darwin/rtProcInitExePath-darwin.cpp | 13 +- src/VBox/Runtime/r3/darwin/sched-darwin.cpp | 2 +- src/VBox/Runtime/r3/darwin/time-darwin.cpp | 2 +- src/VBox/Runtime/r3/dir.cpp | 106 +- src/VBox/Runtime/r3/dir2.cpp | 2 +- src/VBox/Runtime/r3/fileio.cpp | 88 +- src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp | 12 +- src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp | 2 +- .../r3/freebsd/rtProcInitExePath-freebsd.cpp | 2 +- src/VBox/Runtime/r3/fs.cpp | 3 +- src/VBox/Runtime/r3/generic/allocex-r3-generic.cpp | 57 + .../Runtime/r3/generic/semspinmutex-r3-generic.cpp | 2 +- .../Runtime/r3/haiku/rtProcInitExePath-haiku.cpp | 60 + src/VBox/Runtime/r3/haiku/time-haiku.cpp | 84 + src/VBox/Runtime/r3/init.cpp | 157 +- src/VBox/Runtime/r3/init.h | 38 + src/VBox/Runtime/r3/isofs.cpp | 2 +- .../r3/linux/RTProcIsRunningByName-linux.cpp | 2 +- .../Runtime/r3/linux/RTSystemShutdown-linux.cpp | 13 +- src/VBox/Runtime/r3/linux/fileaio-linux.cpp | 12 +- src/VBox/Runtime/r3/linux/mp-linux.cpp | 70 +- .../Runtime/r3/linux/rtProcInitExePath-linux.cpp | 2 +- src/VBox/Runtime/r3/linux/sched-linux.cpp | 2 +- src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp | 2 +- src/VBox/Runtime/r3/linux/semmutex-linux.cpp | 2 +- src/VBox/Runtime/r3/linux/sysfs.cpp | 166 +- src/VBox/Runtime/r3/linux/systemmem-linux.cpp | 42 +- src/VBox/Runtime/r3/linux/time-linux.cpp | 2 +- src/VBox/Runtime/r3/nt/Makefile.kup | 0 src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp | 697 +++++ src/VBox/Runtime/r3/nt/fs-nt.cpp | 284 ++ src/VBox/Runtime/r3/nt/internal-r3-nt.h | 140 + src/VBox/Runtime/r3/nt/pathint-nt.cpp | 356 +++ src/VBox/Runtime/r3/os2/filelock-os2.cpp | 2 +- src/VBox/Runtime/r3/os2/mp-os2.cpp | 2 +- src/VBox/Runtime/r3/os2/pipe-os2.cpp | 956 ++++++- src/VBox/Runtime/r3/os2/poll-os2.cpp | 85 - src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp | 2 +- src/VBox/Runtime/r3/os2/sched-os2.cpp | 2 +- src/VBox/Runtime/r3/os2/sems-os2.cpp | 2 +- src/VBox/Runtime/r3/os2/systemmem-os2.cpp | 70 + src/VBox/Runtime/r3/os2/thread-os2.cpp | 25 +- src/VBox/Runtime/r3/path.cpp | 2 +- src/VBox/Runtime/r3/poll.cpp | 1109 ++++++++ .../Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp | 2 +- .../Runtime/r3/posix/RTHandleGetStandard-posix.cpp | 3 +- src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp | 2 +- src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp | 2 +- .../Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp | 2 +- src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp | 2 +- src/VBox/Runtime/r3/posix/allocex-r3-posix.cpp | 109 + src/VBox/Runtime/r3/posix/dir-posix.cpp | 31 +- src/VBox/Runtime/r3/posix/env-posix.cpp | 41 +- src/VBox/Runtime/r3/posix/fileaio-posix.cpp | 10 +- src/VBox/Runtime/r3/posix/fileio-posix.cpp | 16 +- src/VBox/Runtime/r3/posix/fileio2-posix.cpp | 36 +- src/VBox/Runtime/r3/posix/filelock-posix.cpp | 3 +- src/VBox/Runtime/r3/posix/fs-posix.cpp | 4 +- src/VBox/Runtime/r3/posix/fs2-posix.cpp | 5 +- src/VBox/Runtime/r3/posix/ldrNative-posix.cpp | 12 +- src/VBox/Runtime/r3/posix/path-posix.cpp | 7 +- src/VBox/Runtime/r3/posix/path2-posix.cpp | 4 - src/VBox/Runtime/r3/posix/pathhost-posix.cpp | 14 +- src/VBox/Runtime/r3/posix/pipe-posix.cpp | 19 +- src/VBox/Runtime/r3/posix/poll-posix.cpp | 519 ---- .../Runtime/r3/posix/process-creation-posix.cpp | 71 +- src/VBox/Runtime/r3/posix/process-posix.cpp | 3 +- src/VBox/Runtime/r3/posix/rand-posix.cpp | 8 +- .../r3/posix/rtmempage-exec-mmap-heap-posix.cpp | 19 +- src/VBox/Runtime/r3/posix/sched-posix.cpp | 2 +- src/VBox/Runtime/r3/posix/semevent-posix.cpp | 6 +- src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp | 4 +- src/VBox/Runtime/r3/posix/semmutex-posix.cpp | 59 +- src/VBox/Runtime/r3/posix/semrw-posix.cpp | 2 +- src/VBox/Runtime/r3/posix/symlink-posix.cpp | 2 +- src/VBox/Runtime/r3/posix/thread-posix.cpp | 148 +- src/VBox/Runtime/r3/posix/thread2-posix.cpp | 8 +- src/VBox/Runtime/r3/posix/time-posix.cpp | 2 +- src/VBox/Runtime/r3/posix/timelocal-posix.cpp | 2 +- src/VBox/Runtime/r3/posix/timer-posix.cpp | 20 +- src/VBox/Runtime/r3/posix/tls-posix.cpp | 2 +- src/VBox/Runtime/r3/posix/utf8-posix.cpp | 26 +- src/VBox/Runtime/r3/process.cpp | 2 +- src/VBox/Runtime/r3/socket.cpp | 119 +- src/VBox/Runtime/r3/solaris/Makefile.kup | 0 .../r3/solaris/RTSystemShutdown-solaris.cpp | 102 + src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp | 56 +- src/VBox/Runtime/r3/solaris/coredumper-solaris.h | 2 +- src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp | 14 +- src/VBox/Runtime/r3/solaris/mp-solaris.cpp | 182 +- .../r3/solaris/rtProcInitExePath-solaris.cpp | 2 +- src/VBox/Runtime/r3/solaris/systemmem-solaris.cpp | 172 ++ src/VBox/Runtime/r3/stream.cpp | 3 +- src/VBox/Runtime/r3/tcp.cpp | 48 +- src/VBox/Runtime/r3/test.cpp | 350 ++- src/VBox/Runtime/r3/testi.cpp | 2 +- src/VBox/Runtime/r3/udp.cpp | 2 +- .../Runtime/r3/win/RTHandleGetStandard-win.cpp | 2 +- src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp | 2 +- .../Runtime/r3/win/RTSystemQueryDmiString-win.cpp | 10 +- .../Runtime/r3/win/RTSystemQueryOSInfo-win.cpp | 228 +- src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp | 12 +- src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp | 2 +- src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def | 22 +- src/VBox/Runtime/r3/win/VBoxRT-openssl.def | 12 +- src/VBox/Runtime/r3/win/VBoxRT-win32.def | 2 +- src/VBox/Runtime/r3/win/VBoxRT-win64.def | 2 +- src/VBox/Runtime/r3/win/alloc-win.cpp | 2 +- src/VBox/Runtime/r3/win/allocex-win.cpp | 120 + src/VBox/Runtime/r3/win/dir-win.cpp | 342 +-- src/VBox/Runtime/r3/win/direnum-win.cpp | 389 +++ src/VBox/Runtime/r3/win/dllmain-win.cpp | 2 +- src/VBox/Runtime/r3/win/env-win.cpp | 268 ++ src/VBox/Runtime/r3/win/fileaio-win.cpp | 14 +- src/VBox/Runtime/r3/win/fs-win.cpp | 5 +- src/VBox/Runtime/r3/win/init-win.cpp | 273 ++ src/VBox/Runtime/r3/win/internal-r3-win.h | 72 + src/VBox/Runtime/r3/win/ldrNative-win.cpp | 54 +- src/VBox/Runtime/r3/win/localipc-win.cpp | 782 +++++- src/VBox/Runtime/r3/win/mp-win.cpp | 69 +- src/VBox/Runtime/r3/win/ntdll-mini-implib.c | 111 +- src/VBox/Runtime/r3/win/ntdll-mini-implib.def | 9 +- src/VBox/Runtime/r3/win/path-win.cpp | 4 +- src/VBox/Runtime/r3/win/pipe-win.cpp | 22 +- src/VBox/Runtime/r3/win/poll-win.cpp | 586 ---- src/VBox/Runtime/r3/win/process-win.cpp | 283 +- src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp | 2 +- src/VBox/Runtime/r3/win/sched-win.cpp | 2 +- src/VBox/Runtime/r3/win/semmutex-win.cpp | 2 +- src/VBox/Runtime/r3/win/symlink-win.cpp | 15 +- src/VBox/Runtime/r3/win/thread-win.cpp | 10 +- src/VBox/Runtime/r3/win/time-win.cpp | 25 +- src/VBox/Runtime/r3/win/timer-win.cpp | 2 +- src/VBox/Runtime/r3/win/tls-win.cpp | 2 +- src/VBox/Runtime/r3/win/utf16locale-win.cpp | 2 +- src/VBox/Runtime/r3/win/uuid-win.cpp | 2 +- src/VBox/Runtime/r3/xml.cpp | 975 ++++--- src/VBox/Runtime/testcase/Makefile.kmk | 40 +- src/VBox/Runtime/testcase/ioctl.h | 48 - src/VBox/Runtime/testcase/ntGetTimerResolution.cpp | 2 +- src/VBox/Runtime/testcase/soundcard.h | 1300 --------- src/VBox/Runtime/testcase/tstDir-2.cpp | 2 +- src/VBox/Runtime/testcase/tstDir-3.cpp | 2 +- src/VBox/Runtime/testcase/tstDir.cpp | 167 +- src/VBox/Runtime/testcase/tstEnv.cpp | 2 +- src/VBox/Runtime/testcase/tstFile.cpp | 2 +- src/VBox/Runtime/testcase/tstFileAppendWin-1.cpp | 2 +- src/VBox/Runtime/testcase/tstFileLock.cpp | 2 +- src/VBox/Runtime/testcase/tstFork.cpp | 2 +- src/VBox/Runtime/testcase/tstHandleTable.cpp | 8 +- src/VBox/Runtime/testcase/tstIoCtl.cpp | 119 - src/VBox/Runtime/testcase/tstIprtList.cpp | 190 +- src/VBox/Runtime/testcase/tstLdr-2.cpp | 2 +- src/VBox/Runtime/testcase/tstLdr-3.cpp | 2 +- src/VBox/Runtime/testcase/tstLdr-4.cpp | 4 +- src/VBox/Runtime/testcase/tstLdr-4Imp-os2.def | 2 +- src/VBox/Runtime/testcase/tstLdr-4Imp-win.def | 2 +- src/VBox/Runtime/testcase/tstLdr.cpp | 4 +- src/VBox/Runtime/testcase/tstLdrDisasmTest.cpp | 2 +- src/VBox/Runtime/testcase/tstLdrLoad.cpp | 2 +- src/VBox/Runtime/testcase/tstLdrObj.cpp | 2 +- src/VBox/Runtime/testcase/tstLdrObjR0.cpp | 2 +- src/VBox/Runtime/testcase/tstLog.cpp | 2 +- src/VBox/Runtime/testcase/tstMemAutoPtr.cpp | 6 +- src/VBox/Runtime/testcase/tstMove.cpp | 2 +- src/VBox/Runtime/testcase/tstMp-1.cpp | 285 -- src/VBox/Runtime/testcase/tstNoCrt-1.cpp | 2 +- src/VBox/Runtime/testcase/tstOnce.cpp | 20 +- src/VBox/Runtime/testcase/tstPrfRT.cpp | 2 +- .../Runtime/testcase/tstR0ThreadPreemption.cpp | 284 +- src/VBox/Runtime/testcase/tstR0ThreadPreemption.h | 6 +- .../testcase/tstR0ThreadPreemptionDriver.cpp | 112 +- src/VBox/Runtime/testcase/tstRTAssertCompile.cpp | 2 +- src/VBox/Runtime/testcase/tstRTAvl.cpp | 2 +- src/VBox/Runtime/testcase/tstRTBase64.cpp | 14 +- src/VBox/Runtime/testcase/tstRTBitOperations.cpp | 2 +- src/VBox/Runtime/testcase/tstRTCidr.cpp | 12 +- src/VBox/Runtime/testcase/tstRTCircBuf.cpp | 2 +- src/VBox/Runtime/testcase/tstRTCritSect.cpp | 2 +- src/VBox/Runtime/testcase/tstRTCritSectRw.cpp | 491 ++++ src/VBox/Runtime/testcase/tstRTDigest.cpp | 12 +- .../testcase/tstRTDirCreateUniqueNumbered.cpp | 2 +- src/VBox/Runtime/testcase/tstRTDvm.cpp | 2 +- src/VBox/Runtime/testcase/tstRTFileAio.cpp | 2 +- src/VBox/Runtime/testcase/tstRTFileGetSize-1.cpp | 18 +- .../testcase/tstRTFileModeStringToFlags.cpp | 222 ++ src/VBox/Runtime/testcase/tstRTFsQueries.cpp | 2 +- src/VBox/Runtime/testcase/tstRTHeapOffset.cpp | 2 +- src/VBox/Runtime/testcase/tstRTHeapSimple.cpp | 2 +- src/VBox/Runtime/testcase/tstRTHttp.cpp | 253 ++ src/VBox/Runtime/testcase/tstRTInlineAsm.cpp | 82 +- src/VBox/Runtime/testcase/tstRTList.cpp | 2 +- src/VBox/Runtime/testcase/tstRTLocalIpc.cpp | 644 +++++ src/VBox/Runtime/testcase/tstRTLockValidator.cpp | 2 +- src/VBox/Runtime/testcase/tstRTManifest.cpp | 2 +- src/VBox/Runtime/testcase/tstRTMemEf.cpp | 2 +- src/VBox/Runtime/testcase/tstRTMemPool.cpp | 2 +- src/VBox/Runtime/testcase/tstRTMp-1.cpp | 241 ++ src/VBox/Runtime/testcase/tstRTPath.cpp | 223 ++ src/VBox/Runtime/testcase/tstRTPipe.cpp | 2 +- src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp | 12 +- src/VBox/Runtime/testcase/tstRTProcCreatePrf.cpp | 3 +- .../Runtime/testcase/tstRTProcIsRunningByName.cpp | 2 +- src/VBox/Runtime/testcase/tstRTProcWait.cpp | 2 +- src/VBox/Runtime/testcase/tstRTR0Common.h | 47 + src/VBox/Runtime/testcase/tstRTR0CommonDriver.h | 9 +- .../Runtime/testcase/tstRTR0DbgKrnlInfoDriver.cpp | 6 +- src/VBox/Runtime/testcase/tstRTR0MemUserKernel.cpp | 2 +- src/VBox/Runtime/testcase/tstRTR0MemUserKernel.h | 2 +- .../testcase/tstRTR0MemUserKernelDriver.cpp | 6 +- src/VBox/Runtime/testcase/tstRTR0SemMutex.cpp | 2 +- .../Runtime/testcase/tstRTR0SemMutexDriver.cpp | 6 +- src/VBox/Runtime/testcase/tstRTR0Timer.cpp | 172 +- src/VBox/Runtime/testcase/tstRTR0Timer.h | 3 + src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp | 76 +- src/VBox/Runtime/testcase/tstRTS3.cpp | 2 +- src/VBox/Runtime/testcase/tstRTSemRW.cpp | 19 +- src/VBox/Runtime/testcase/tstRTSemXRoads.cpp | 2 +- src/VBox/Runtime/testcase/tstRTStrAlloc.cpp | 6 +- src/VBox/Runtime/testcase/tstRTStrCache.cpp | 144 +- src/VBox/Runtime/testcase/tstRTStrFormat.cpp | 110 +- src/VBox/Runtime/testcase/tstRTSymlink.cpp | 4 +- .../Runtime/testcase/tstRTSystemQueryOsInfo.cpp | 12 +- src/VBox/Runtime/testcase/tstRTTcp-1.cpp | 18 +- src/VBox/Runtime/testcase/tstRTTemp.cpp | 4 +- src/VBox/Runtime/testcase/tstRTTime.cpp | 117 + src/VBox/Runtime/testcase/tstRTTimeSpec.cpp | 2 +- src/VBox/Runtime/testcase/tstRTUri.cpp | 83 +- src/VBox/Runtime/testcase/tstRTUuid.cpp | 2 +- src/VBox/Runtime/testcase/tstRand.cpp | 2 +- src/VBox/Runtime/testcase/tstSemMutex.cpp | 2 +- src/VBox/Runtime/testcase/tstSemPingPong.cpp | 2 +- src/VBox/Runtime/testcase/tstStrSimplePattern.cpp | 2 +- src/VBox/Runtime/testcase/tstStrToNum.cpp | 2 +- src/VBox/Runtime/testcase/tstTSC.cpp | 4 +- src/VBox/Runtime/testcase/tstTermCallbacks.cpp | 2 +- src/VBox/Runtime/testcase/tstThread-1.cpp | 2 +- src/VBox/Runtime/testcase/tstTime-2.cpp | 2 +- src/VBox/Runtime/testcase/tstTime-3.cpp | 8 +- src/VBox/Runtime/testcase/tstTime-4.cpp | 9 +- src/VBox/Runtime/testcase/tstTime.cpp | 109 - src/VBox/Runtime/testcase/tstTimer.cpp | 2 +- src/VBox/Runtime/testcase/tstTimerLR.cpp | 2 +- src/VBox/Runtime/testcase/tstUtf8.cpp | 22 +- src/VBox/Runtime/tools/Makefile.kmk | 12 +- src/VBox/Runtime/tools/RTGzip.cpp | 566 ++-- src/VBox/Runtime/tools/RTLdrFlt.cpp | 78 +- src/VBox/Runtime/tools/RTManifest.cpp | 2 +- src/VBox/Runtime/tools/RTNtDbgHelp.cpp | 380 +++ src/VBox/Runtime/tools/RTRm.cpp | 45 + src/VBox/Runtime/tools/RTTar.cpp | 2 +- src/VBox/Runtime/win/RTErrConvertFromWin32.cpp | 3 +- src/VBox/Runtime/win/amd64/ASMAtomicBitClear.asm | 2 +- .../win/amd64/ASMAtomicBitTestAndToggle.asm | 2 +- src/VBox/Runtime/win/amd64/ASMAtomicBitToggle.asm | 2 +- src/VBox/Runtime/win/amd64/ASMAtomicReadU64.asm | 2 +- src/VBox/Runtime/win/amd64/ASMAtomicXchgU16.asm | 2 +- src/VBox/Runtime/win/amd64/ASMAtomicXchgU8.asm | 2 +- src/VBox/Runtime/win/amd64/ASMBitFirstClear.asm | 2 +- src/VBox/Runtime/win/amd64/ASMBitFirstSet.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetCS.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetDR0.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetDR1.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetDR2.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetDR3.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetDR6.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetDR7.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetDS.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetES.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetFS.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetFlags.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetGDTR.asm | 41 - src/VBox/Runtime/win/amd64/ASMGetGS.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetIDTR.asm | 42 - src/VBox/Runtime/win/amd64/ASMGetSS.asm | 2 +- src/VBox/Runtime/win/amd64/ASMGetTR.asm | 42 - src/VBox/Runtime/win/amd64/ASMProbeReadByte.asm | 2 +- src/VBox/Runtime/win/amd64/ASMSetFlags.asm | 2 +- 811 files changed, 46261 insertions(+), 8969 deletions(-) create mode 100644 src/VBox/Runtime/common/asm/ASMAtomicUoAndU32.asm create mode 100644 src/VBox/Runtime/common/asm/ASMAtomicUoAndU64.asm create mode 100644 src/VBox/Runtime/common/asm/ASMAtomicUoOrU32.asm create mode 100644 src/VBox/Runtime/common/asm/ASMAtomicUoOrU64.asm create mode 100644 src/VBox/Runtime/common/asm/ASMCpuIdExSlow.asm create mode 100644 src/VBox/Runtime/common/asm/ASMCpuId_Idx_ECX.asm create mode 100644 src/VBox/Runtime/common/asm/ASMGetGDTR.asm create mode 100644 src/VBox/Runtime/common/asm/ASMGetIDTR.asm create mode 100644 src/VBox/Runtime/common/asm/ASMGetLDTR.asm create mode 100644 src/VBox/Runtime/common/asm/ASMGetSegAttr.asm create mode 100644 src/VBox/Runtime/common/asm/ASMGetTR.asm create mode 100644 src/VBox/Runtime/common/asm/ASMRdMsrEx.asm create mode 100644 src/VBox/Runtime/common/asm/ASMWrMsrEx.asm create mode 100644 src/VBox/Runtime/common/checksum/RTSha256Digest.cpp create mode 100644 src/VBox/Runtime/common/dbg/dbgcfg.cpp create mode 100644 src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp create mode 100644 src/VBox/Runtime/common/dbg/dbgmoddbghelp.cpp create mode 100644 src/VBox/Runtime/common/dbg/dbgmoddeferred.cpp create mode 100644 src/VBox/Runtime/common/dbg/dbgmodexports.cpp create mode 100644 src/VBox/Runtime/common/ldr/ldrMemory.cpp create mode 100644 src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp create mode 100644 src/VBox/Runtime/common/misc/aiomgr.cpp create mode 100644 src/VBox/Runtime/common/misc/http.cpp create mode 100644 src/VBox/Runtime/common/net/macstr.cpp create mode 100644 src/VBox/Runtime/common/net/netaddrstr2.cpp create mode 100644 src/VBox/Runtime/common/path/RTPathCalcRelative.cpp create mode 100644 src/VBox/Runtime/common/path/RTPathParse.cpp.h create mode 100644 src/VBox/Runtime/common/path/RTPathParseSimple.cpp create mode 100644 src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp create mode 100644 src/VBox/Runtime/common/path/RTPathRmCmd.cpp create mode 100644 src/VBox/Runtime/common/path/RTPathSplit.cpp create mode 100644 src/VBox/Runtime/common/path/RTPathSplitA.cpp create mode 100644 src/VBox/Runtime/common/path/RTPathSplitReassemble.cpp create mode 100644 src/VBox/Runtime/common/path/rtpath-expand-template.cpp.h create mode 100644 src/VBox/Runtime/common/zip/xarvfs.cpp create mode 100644 src/VBox/Runtime/generic/RTMpGetCoreCount-generic.cpp create mode 100644 src/VBox/Runtime/generic/RTMpGetOnlineCoreCount-generic.cpp create mode 100644 src/VBox/Runtime/generic/RTPathIsSame-generic.cpp create mode 100644 src/VBox/Runtime/generic/critsectrw-generic.cpp delete mode 100644 src/VBox/Runtime/include/internal/ldrMach-O.h create mode 100644 src/VBox/Runtime/r0drv/generic/threadctxhooks-r0drv-generic.cpp create mode 100644 src/VBox/Runtime/r0drv/haiku/RTLogWriteDebugger-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/RTLogWriteStdOut-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/alloc-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/assert-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/initterm-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/memobj-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/mp-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/process-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/semevent-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/semeventmulti-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/semfastmutex-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/semmutex-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/spinlock-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/the-haiku-kernel.h create mode 100644 src/VBox/Runtime/r0drv/haiku/thread-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/thread2-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/haiku/time-r0drv-haiku.c create mode 100644 src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c create mode 100644 src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp create mode 100644 src/VBox/Runtime/r0drv/nt/symdb.h create mode 100644 src/VBox/Runtime/r0drv/nt/symdbdata.h create mode 100644 src/VBox/Runtime/r0drv/solaris/threadctxhooks-r0drv-solaris.c create mode 100644 src/VBox/Runtime/r3/allocex.cpp create mode 100644 src/VBox/Runtime/r3/allocex.h create mode 100644 src/VBox/Runtime/r3/generic/allocex-r3-generic.cpp create mode 100644 src/VBox/Runtime/r3/haiku/rtProcInitExePath-haiku.cpp create mode 100644 src/VBox/Runtime/r3/haiku/time-haiku.cpp create mode 100644 src/VBox/Runtime/r3/init.h create mode 100644 src/VBox/Runtime/r3/nt/Makefile.kup create mode 100644 src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp create mode 100644 src/VBox/Runtime/r3/nt/fs-nt.cpp create mode 100644 src/VBox/Runtime/r3/nt/internal-r3-nt.h create mode 100644 src/VBox/Runtime/r3/nt/pathint-nt.cpp delete mode 100644 src/VBox/Runtime/r3/os2/poll-os2.cpp create mode 100644 src/VBox/Runtime/r3/os2/systemmem-os2.cpp create mode 100644 src/VBox/Runtime/r3/poll.cpp create mode 100644 src/VBox/Runtime/r3/posix/allocex-r3-posix.cpp delete mode 100644 src/VBox/Runtime/r3/posix/poll-posix.cpp create mode 100644 src/VBox/Runtime/r3/solaris/Makefile.kup create mode 100644 src/VBox/Runtime/r3/solaris/RTSystemShutdown-solaris.cpp create mode 100644 src/VBox/Runtime/r3/solaris/systemmem-solaris.cpp create mode 100644 src/VBox/Runtime/r3/win/allocex-win.cpp create mode 100644 src/VBox/Runtime/r3/win/direnum-win.cpp create mode 100644 src/VBox/Runtime/r3/win/env-win.cpp create mode 100644 src/VBox/Runtime/r3/win/init-win.cpp create mode 100644 src/VBox/Runtime/r3/win/internal-r3-win.h delete mode 100644 src/VBox/Runtime/r3/win/poll-win.cpp delete mode 100644 src/VBox/Runtime/testcase/ioctl.h delete mode 100644 src/VBox/Runtime/testcase/soundcard.h delete mode 100644 src/VBox/Runtime/testcase/tstIoCtl.cpp delete mode 100644 src/VBox/Runtime/testcase/tstMp-1.cpp create mode 100644 src/VBox/Runtime/testcase/tstRTCritSectRw.cpp create mode 100644 src/VBox/Runtime/testcase/tstRTFileModeStringToFlags.cpp create mode 100644 src/VBox/Runtime/testcase/tstRTHttp.cpp create mode 100644 src/VBox/Runtime/testcase/tstRTLocalIpc.cpp create mode 100644 src/VBox/Runtime/testcase/tstRTMp-1.cpp create mode 100644 src/VBox/Runtime/testcase/tstRTTime.cpp delete mode 100644 src/VBox/Runtime/testcase/tstTime.cpp create mode 100644 src/VBox/Runtime/tools/RTNtDbgHelp.cpp create mode 100644 src/VBox/Runtime/tools/RTRm.cpp delete mode 100644 src/VBox/Runtime/win/amd64/ASMGetGDTR.asm delete mode 100644 src/VBox/Runtime/win/amd64/ASMGetIDTR.asm delete mode 100644 src/VBox/Runtime/win/amd64/ASMGetTR.asm (limited to 'src/VBox/Runtime') 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 \ @@ -1228,50 +1287,43 @@ RuntimeGuestR3Mini_SOURCES += \ VBox/logbackdoor-redirect.cpp -# -# 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: \ @@ -1379,6 +1422,71 @@ VBoxRT:: VBoxRTDummy 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. # @@ -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 @@ -2089,6 +2264,16 @@ RuntimeR3NtDll-x86_BLD_TRG_ARCH = x86 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. # @@ -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 #include -#include +#include #include #include #include @@ -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 # include # include +# elif defined(RT_OS_HAIKU) +# include # elif defined(RT_OS_SOLARIS) # define _STRUCTURED_PROC 1 # undef _FILE_OFFSET_BITS /* procfs doesn't like this */ # include # include -# elif defined(RT_OS_L4) -# include # elif defined(RT_OS_OS2) # include # endif @@ -162,6 +162,10 @@ # include # include #endif +#if defined(IN_RING0) && defined(RT_OS_DARWIN) +# include +# include +#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/common/asm/ASMGetIDTR.asm b/src/VBox/Runtime/common/asm/ASMGetIDTR.asm new file mode 100644 index 00000000..558a6d7b --- /dev/null +++ b/src/VBox/Runtime/common/asm/ASMGetIDTR.asm @@ -0,0 +1,52 @@ +; $Id: ASMGetIDTR.asm $ +;; @file +; IPRT - ASMGetIDTR(). +; + +; +; 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 IDTR CPU register. +; @param pIdtr Where to store the IDTR contents. +; msc=rcx, gcc=rdi, x86=[esp+4] +; +BEGINPROC_EXPORTED ASMGetIDTR +%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/common/asm/ASMGetLDTR.asm b/src/VBox/Runtime/common/asm/ASMGetLDTR.asm new file mode 100644 index 00000000..f7adf829 --- /dev/null +++ b/src/VBox/Runtime/common/asm/ASMGetLDTR.asm @@ -0,0 +1,43 @@ +; $Id: ASMGetLDTR.asm $ +;; @file +; IPRT - ASMGetLDTR(). +; + +; +; 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 + +;; +; Get the LDTR register. +; @returns LDTR. +; +BEGINPROC_EXPORTED ASMGetLDTR + sldt ax + movzx eax, ax + ret +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/common/asm/ASMGetTR.asm b/src/VBox/Runtime/common/asm/ASMGetTR.asm new file mode 100644 index 00000000..3d6fc68e --- /dev/null +++ b/src/VBox/Runtime/common/asm/ASMGetTR.asm @@ -0,0 +1,43 @@ +; $Id: ASMGetTR.asm $ +;; @file +; IPRT - ASMGetTR(). +; + +; +; 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 + +;; +; Get the TR register. +; @returns TR. +; +BEGINPROC_EXPORTED ASMGetTR + str ax + movzx eax, ax + ret +ENDPROC ASMGetTR + 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 + +#include +#include +#include +#include +#include + +#include + + +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 #include "internal/iprt.h" -#include /* for memcpy() */ +#include /* for memcpy() */ #if defined(RT_BIG_ENDIAN) # include /* 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; @@ -1282,6 +1302,37 @@ RTDECL(int) RTDbgAsSymbolAdd(RTDBGAS hDbgAs, const char *pszSymbol, RTUINTPTR Ad 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. * @@ -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; } /* @@ -1385,37 +1475,6 @@ RTDECL(int) RTDbgAsSymbolByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, uint32_t fFlags 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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef IPRT_WITH_HTTP +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#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 #include "internal/iprt.h" +#include #include #include #include #include #include +#include #include #include #include @@ -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. @@ -275,6 +279,12 @@ static DECLCALLBACK(int) rtDbgModInitOnce(void *pvUser1, void *pvUser2) rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgNm); 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) { - NOREF(phDbgMod); NOREF(pszFilename); NOREF(pszName); NOREF(cb); NOREF(fFlags); - return VERR_NOT_IMPLEMENTED; + /* + * 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; } -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) 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) +{ + 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; +} + + +/** @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)) { /* @@ -485,28 +893,175 @@ RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, } } - pDbgMod->pszImgFile = pDbgMod->pszDbgFile; - pDbgMod->pszDbgFile = NULL; + pDbgMod->pszImgFile = pDbgMod->pszDbgFile; + pDbgMod->pszDbgFile = NULL; + } + + /* bail out */ + RTSemRWReleaseRead(g_hDbgModRWSem); + } + RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified); + 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); + } + + RTMemFree(pDbgMod); + return rc; +} +RT_EXPORT_SYMBOL(RTDbgModCreateFromImage); + + + + + +/* + * + * 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; } - /* bail out */ - RTSemRWReleaseRead(g_hDbgModRWSem); + /* 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; } - RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName); } - RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile); + 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; } - RTCritSectDelete(&pDbgMod->CritSect); + else + LogFlow(("rtDbgModFromPeImageOpenCallback: Failed %Rrc - %s\n", rc, pszFilename)); } - RTMemFree(pDbgMod); + /* Restore image name. */ + pDbgMod->pszImgFile = pszOldImgFile; + RTStrCacheRelease(g_hDbgModStrCache, pszNewImgFile); return rc; } -RT_EXPORT_SYMBOL(RTDbgModCreateFromImage); -RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, - RTUINTPTR uSubtrahend, uint32_t fFlags) +/** @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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 #include #include +#define RTDBGMODCNT_WITH_MEM_CACHE +#ifdef RTDBGMODCNT_WITH_MEM_CACHE +# include +#endif #include #include #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.) */ @@ -685,6 +746,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. * @@ -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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal/dbgmod.h" + +#include +#include +#include + + +/******************************************************************************* +* 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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include +#include +#include +#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 #include #include +#define RTDBGMODDWARF_WITH_MEM_CACHE +#ifdef RTDBGMODDWARF_WITH_MEM_CACHE +# include +#endif #include #include +#include #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. + */ +static int rtDbgModDwarfAddSegmentsFromImage(PRTDBGMODDWARF pThis) +{ + 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. */ -DECLHIDDEN(int) rtDbgModHlpAddSegmentsFromImage(PRTDBGMODINT pMod) +static int rtDbgModDwarfRecordSegOffset(PRTDBGMODDWARF pThis, RTSEL uSeg, uint64_t offSeg) { - AssertReturn(pMod->pImgVt, VERR_INTERNAL_ERROR_2); - return pMod->pImgVt->pfnEnumSegments(pMod, rtDbgModHlpAddSegmentCallback, pMod); + /* 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; } @@ -1643,6 +2237,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. * @@ -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] - : ""; - 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] + : ""; + 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) - { - Cursor.rc = VERR_DWARF_BAD_ABBREV; - break; - } - - /* Cache it? */ - if (uCurCode <= pThis->cCachedAbbrevsAlloced) + /* 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) { - 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; +} /* * @@ -2790,6 +3722,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. * @@ -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; @@ -2920,6 +4009,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 @@ -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) + /* End of siblings, up one level. (Is this correct?) */ + if (pParentDie->pParent) { - 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) - { - 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 = ""; - 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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include +#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 #include #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) @@ -108,6 +141,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) { @@ -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. * @@ -278,10 +520,23 @@ static int RTLDRELF_NAME(RelocateSection)(PRTLDRMODELF pModElf, Elf_Addr BaseAdd 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 + + /* * 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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include +#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 #include #include +#include #include #include +#include #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 +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 -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 #include /* must come before getopt.h */ #include #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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#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 #include "internal/iprt.h" +#include +#include +#include +#include +#include #include #include -#include -#include -#include + + +/******************************************************************************* +* 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 #include #include +#include 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 +#include /* must come before getopt.h */ +#include "internal/iprt.h" + +#include +#include +#include +#include +#include + + +/** + * 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 + +#include +#include +#include +#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 +#include +#include +#include +#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 -#include + +#include -/** - * 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 +#include +#include +#include +#include -/** - * 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 + + +/** + * 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 + +#include +#include +#include + + +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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/******************************************************************************* +* 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 + +#include +#include +#include + + + +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 + +#include +#include +#include +#include + + + +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 + +#include +#include +#include + + +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 #include "internal/iprt.h" +#include #include #include +#include #include -#include -#include +#include +#include #include +#include +#include + +#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, "", sizeof("") - 1); + return pfnOutput(pvArgOutput, RT_STR_TUPLE("")); 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, "", sizeof("") - 1); + return pfnOutput(pvArgOutput, RT_STR_TUPLE("")); 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, "", sizeof("") - 1); + return pfnOutput(pvArgOutput, RT_STR_TUPLE("")); 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, "", sizeof("") - 1); + return pfnOutput(pvArgOutput, RT_STR_TUPLE("")); /* * 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, "", 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 #include +#include /* * 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 #include - +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include - +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include - +#include /* * 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 #include - +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include +#include /* * 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 #include "internal/iprt.h" +#include #include #include #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 #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 #include #include +#include #include #include #include #include #include #include +#include #include #include +#include #include /******************************************************************************* * 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 , --directory (-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 , --file (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 (-A, -C, -d, -r, -u, -x)\n" + " Set the owner of extracted and archived files to the user specified.\n" + " --group (-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 (-A, -C, -d, -r, -u)\n" + " Directory prefix to give the members added to the archive.\n" + " --file-mode-and-mask (-A, -C, -d, -r, -u, -x)\n" + " Restrict the access mode of regular and special files.\n" + " --file-mode-and-mask (-A, -C, -d, -r, -u, -x)\n" + " Include the given access mode for regular and special files.\n" + " --dir-mode-and-mask (-A, -C, -d, -r, -u, -x)\n" + " Restrict the access mode of directories.\n" + " --dir-mode-and-mask (-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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/******************************************************************************* +* 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(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 +#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 +#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 +#include "internal/iprt.h" + +#include + + +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 #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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include +#include +#include + +#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. @@ -115,6 +116,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. * @@ -139,17 +155,34 @@ typedef struct RTDBGMODVTIMG DECLCALLBACKMEMBER(int, pfnLinkAddressToSegOffset)(PRTDBGMODINT pMod, RTLDRADDR LinkAddress, 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. @@ -442,6 +506,64 @@ typedef struct RTDBGMODVTDBG 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. */ @@ -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 - -#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 +#include -#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 -/* 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 #include #include -#include "internal/ldrMach-O.h" +#include #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 /** - * 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 #include #include +#if __FreeBSD_version >= 1000030 +#include +#endif #include #include #include @@ -66,6 +69,7 @@ #include #include /* vm_phys_alloc_* */ #include /* kmem_alloc_attr */ +#include /* vm_contig_grow_cache */ #include /* cnt */ #include #include 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 +#include + +#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 + + +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 + + +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 +#include + +#include +#include +#include +#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 + +#include +#include +#include +#include + +#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 +#include +#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 +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#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 + + +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 + +#include +#include +#include +#include +#include + +#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 + +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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 + +#include +#include +#include +#include +#include +#include + +#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 + +#include +#include +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +#include +#endif +#include +#include +#include + +#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 +#include +#include + +#include + +#include +#include + +#include +#include +#include + +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 + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +#include +#endif +#include +#include +#include + + +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 + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +#include +#endif +#include +#include +#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 + +#include + + +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 #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) +# include +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7) # include #endif @@ -121,6 +124,11 @@ #include #include +/* For thread-context hooks. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) && defined(CONFIG_PREEMPT_NOTIFIERS) +# include +#endif + /* for workqueue / task queues. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41) # include @@ -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 +#include +#include +#include +#include +#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 #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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ] [...]\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 + + +/** + * 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 #include #include +#ifdef RT_STRICT +# include +#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 #endif #include +#include @@ -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. @@ -162,6 +166,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. */ 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 #include #include +#include #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 +#include +#include +#include +#include +#include +#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; @@ -123,6 +123,36 @@ typedef struct RTTIMER } while (0) +/** + * 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. * @@ -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 +#include "internal/iprt.h" + +#include +#include +#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 + +/** + * 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 -#include +#include "internal/iprt.h" + #include +#include +#include + +#include +#include +#ifdef IPRT_USE_CORE_SERVICE_FOR_USER_DOCUMENTS +# include +#endif -#include 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 #endif +#include +#include +#include #include #include #include @@ -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 -#else -# include -# include -# include -#endif - #include #include "internal/iprt.h" @@ -49,6 +41,7 @@ #include #include #include +#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; @@ -207,6 +207,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. @@ -228,6 +271,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. * 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/generic/allocex-r3-generic.cpp b/src/VBox/Runtime/r3/generic/allocex-r3-generic.cpp new file mode 100644 index 00000000..dd1dea61 --- /dev/null +++ b/src/VBox/Runtime/r3/generic/allocex-r3-generic.cpp @@ -0,0 +1,57 @@ +/* $Id: allocex-r3-generic.cpp $ */ +/** @file + * IPRT - Memory Allocation, Extended Alloc Workers, generic. + */ + +/* + * 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 +#include "internal/iprt.h" + +#include +#include +#include "../allocex.h" + + + +DECLHIDDEN(int) rtMemAllocEx16BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv) +{ + return VERR_NOT_SUPPORTED; +} + + +DECLHIDDEN(int) rtMemAllocEx32BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv) +{ + return VERR_NOT_SUPPORTED; +} + + +DECLHIDDEN(void) rtMemFreeExYyBitReach(void *pv, size_t cb, uint32_t fFlags) +{ + 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 +#endif + +#include +#include +#include +#include +#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 +#include +#include + +#include + +#include +#include +#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 +#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; @@ -315,6 +370,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 + +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 #include +#include "internal/iprt.h" + +#include #include #include #include @@ -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 #include +#include +#include #include /* 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 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 +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#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 +#ifdef IPRT_NT_USE_WINTERNL +# define WIN32_NO_STATUS +# include +# include +# include +# define IPRT_NT_NEED_API_GROUP_1 + +#elif defined(IPRT_NT_USE_WDM) +# include +# define IPRT_NT_NEED_API_GROUP_1 + +#else +# include +#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 +#include +#include +#include + + + +/** + * 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 + #include #include "internal/iprt.h" +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#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/poll-os2.cpp b/src/VBox/Runtime/r3/os2/poll-os2.cpp deleted file mode 100644 index 890cdc8c..00000000 --- a/src/VBox/Runtime/r3/os2/poll-os2.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* $Id: poll-os2.cpp $ */ -/** @file - * IPRT - Polling I/O Handles, OS/2 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 -#include "internal/iprt.h" - -#include -#include -#include "internal/magics.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) -{ - return VERR_NOT_IMPLEMENTED; -} - - -RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle) -{ - return VERR_NOT_IMPLEMENTED; -} - - -RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet) -{ - return UINT32_MAX; -} - 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 +#undef RT_MAX + +#include +#include "internal/iprt.h" + +#include +#include +#include + + +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 +#ifdef RT_OS_WINDOWS +# include + +#elif defined(RT_OS_OS2) +# define INCL_BASE +# include +# include +# include + +#else +# include +# include +# include +#endif + +#include +#include "internal/iprt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 #include #include -#include #include #ifdef _MSC_VER # include 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 +#include "internal/iprt.h" + +#include +#include +#include +#include "../allocex.h" + +#include + + +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 #include #include -#include #include #include #include @@ -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 #include #include -#include #include #ifdef _MSC_VER # include @@ -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 #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 #include #include @@ -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 #include #include -#include #include #include #include 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 #ifndef DEV_BSIZE # include +# 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 -#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 -#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 #include #include +#include #include #include #include "internal/magics.h" @@ -54,6 +55,8 @@ # include #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 -#include "internal/iprt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal/magics.h" - -#include -#include -#include - - -/******************************************************************************* -* 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 + #include #include #include @@ -37,20 +39,28 @@ #include #include #include +#include #if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) # include # include # include #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 #endif + #ifdef RT_OS_DARWIN # include #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)) @@ -580,6 +620,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. */ @@ -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 #include #include -#include #include #ifdef _MSC_VER # include @@ -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 -# 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 # 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 # include #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 #endif +#if defined(RT_OS_HAIKU) +# include +#endif #include #include #include #include #include +#include #include #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. @@ -411,6 +434,15 @@ RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUs *pKernelTime = ThreadInfo.system_time.seconds * 1000 + ThreadInfo.system_time.microseconds / 1000; *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; 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 #include #include +#include #include #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 #else /* !RT_OS_WINDOWS */ # include +# include # include # include # include @@ -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 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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include + + +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; @@ -118,6 +191,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. * @@ -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 +#include "internal/iprt.h" + +#include +#include +#include +#include +#include + +#include +#include + + +/******************************************************************************* +* 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; @@ -804,12 +804,20 @@ 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, "\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); } } @@ -794,43 +887,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. * @@ -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, "\n", pszTag); pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd; } - rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"", - pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors); - rtTestXmlOutput(pTest, "\n"); + + if (!pTest->fXmlOmitTopTest && pTest->fXmlTopTestDone) + { + rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"", + pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors); + rtTestXmlOutput(pTest, "\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 #include +#include "internal-r3-win.h" #include #include #include @@ -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 @@ -110,112 +83,6 @@ typedef enum RTWINPRODTYPE } 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. - *
-         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
-
- */ -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. * @@ -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 +#include "internal/iprt.h" + +#include +#include +#include +#include "../allocex.h" + +#include + + +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 -#include #include #include -#include +#include #include #include -#include #include #include #include #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 + +#include +#include +#include +#include +#include +#include +#include +#include +#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 + +#include +#include +#include +#include + +#include +#include + + +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 +#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 +#include +#include +#include +#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. + *
+         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
+
+ */ +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 + + +/******************************************************************************* +* 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 #include +#include "internal/iprt.h" + +#include #include -#include #include -#include +#include +#include +#include +#include + +#include #include #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 #include -#include -#include -#include #include +#include #include -#include +#include #include +#include +#include +#include #include -#include +#include +#include #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 * @@ -163,53 +192,125 @@ typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT; static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession); +/** + * 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 + #include -#include +#include "internal/iprt.h" + #include +#include +#include +#include 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 - -#include -#include "internal/iprt.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#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 #include -#include "internal/iprt.h" +#include "internal-r3-win.h" #include #include @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ #include + /******************************************************************************* * 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 #include +#include "internal-r3-win.h" #include #include @@ -40,7 +42,6 @@ #include #include "internal/path.h" -#include /******************************************************************************* @@ -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 #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 #include #include @@ -42,14 +46,11 @@ #include #include -#include -//////////////////////////////////////////////////////////////////////////////// -// -// 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 : ""; 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, compare_const_char > AttributesMap; - AttributesMap attribs; - - // child elements, if this is an element; can be empty - typedef std::list< boost::shared_ptr > 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 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 pNew; - - if (plibNode->type == XML_ELEMENT_NODE) - pNew = boost::shared_ptr(new ElementNode(&elmRoot, this, plibNode)); - else if (plibNode->type == XML_TEXT_NODE) - pNew = boost::shared_ptr(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; @@ -545,25 +504,53 @@ bool Node::nameEquals(const char *pcszNamespace, const char *pcsz) const return !strcmp(m_pcszNamespacePrefix, pcszNamespace); } +/** + * 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(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(p)); + children.push_back(static_cast(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((*it).get()); - if (pelm->nameEquals(pcszNamespace, pcszMatch)) + ElementNode *pelm = static_cast(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((*it).get()); - const AttributeNode *pAttr; - if ( ((pAttr = pelm->findAttribute("id"))) - && (!strcmp(pAttr->getValue(), pcszId)) - ) - return pelm; + const ElementNode *pElm = static_cast(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(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(p); + } + return NULL; +} + +const ElementNode *ElementNode::getLastChildElement() const +{ + const Node *p; + RTListForEachReverseCpp(&m_children, p, Node, m_listEntry) + { + if (p->isElement()) + return static_cast(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(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(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(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(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 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 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 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 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>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 -#include "soundcard.h" -//#include -#include - -#include -#include -#define LOG_GROUP LOG_GROUP_DEV_AUDIO -//#include -//#include -//#include -//#include -#include - -//#include "audio.h" -//#include "audio_int.h" - -#include -#include - -#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 #include #include +#include /******************************************************************************* @@ -165,7 +166,7 @@ static void test1(const char *pcszDesc, T3 paTestData[], size_t cTestItems) /* Create a test list */ L testList; - const size_t defCap = L::DefaultCapacity; + const size_t defCap = L::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 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 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 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 *pTestList = (MTTESTLISTTYPE *)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 *pTestList = (MTTESTLISTTYPE *)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 *pTestList = (MTTESTLISTTYPE *)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 *pTestList = (MTTESTLISTTYPE *)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 *pTestList = (MTTESTLISTTYPE *)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 *pTestList = (MTTESTLISTTYPE *)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 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 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 -#include -#include -#include -#include -#include - - -/******************************************************************************* -* 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 #include +#include #include #include #include #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 +#include +#include #include #include #include #include #include #include +#include #include #ifdef VBOX # include # 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); /* @@ -137,11 +169,40 @@ int main(int argc, char **argv) if (Req.szMsg[0]) 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/******************************************************************************* +* 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 +#include +#include +#include + + +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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 +#include +#include +#include +#include + + + +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 +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 #include +#include #include #include #include @@ -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 #include +#include #include #include +#include +#include #include #include #include -#include +#include + + +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)); + } } @@ -140,6 +271,11 @@ int main() RTTESTI_CHECK_RC(rc = RTStrCacheDestroy(hStrCache), VINF_SUCCESS); } + /* + * Cache performance on relatively real world examples. + */ + tst2(); + /* * Summary. */ 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/tstRTTime.cpp b/src/VBox/Runtime/testcase/tstRTTime.cpp new file mode 100644 index 00000000..302acc7f --- /dev/null +++ b/src/VBox/Runtime/testcase/tstRTTime.cpp @@ -0,0 +1,117 @@ +/* $Id: tstRTTime.cpp $ */ +/** @file + * IPRT Testcase - Simple RTTime tests (requires GIP). + */ + +/* + * 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 + +#include +#include +#include +#include +#include + +int main() +{ + /* + * 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 + * is less or equal to the return of the previous call. + */ + + RTTimeSystemNanoTS(); RTTimeNanoTS(); RTThreadYield(); + uint64_t u64RTStartTS = RTTimeNanoTS(); + uint64_t u64OSStartTS = RTTimeSystemNanoTS(); + + uint32_t i; + uint64_t u64Prev = RTTimeNanoTS(); + for (i = 0; i < 100*_1M; i++) + { + uint64_t u64 = RTTimeNanoTS(); + if (u64 <= u64Prev) + { + /** @todo wrapping detection. */ + 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 */) + { + 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))) + { + RTTestPrintf(hTest, RTTESTLVL_INFO, "i=%#010x u64=%#llx u64Prev=%#llx delta=%lld\n", i, u64, u64Prev, u64 - u64Prev); + RTThreadYield(); + u64 = RTTimeNanoTS(); + } + u64Prev = u64; + } + + RTTimeSystemNanoTS(); RTTimeNanoTS(); RTThreadYield(); + uint64_t u64RTElapsedTS = RTTimeNanoTS(); + uint64_t u64OSElapsedTS = RTTimeSystemNanoTS(); + u64RTElapsedTS -= u64RTStartTS; + 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 + { + 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); + } + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) /** @todo This isn't really x86 or AMD64 specific... */ + 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 + + 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 -#elif defined RT_OS_L4 - #else /* posix */ # include #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/tstTime.cpp b/src/VBox/Runtime/testcase/tstTime.cpp deleted file mode 100644 index 63841e99..00000000 --- a/src/VBox/Runtime/testcase/tstTime.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* $Id: tstTime.cpp $ */ -/** @file - * IPRT Testcase - Simple RTTime tests. - */ - -/* - * 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 -#include -#include -#include -#include - - -int main() -{ - unsigned cErrors = 0; - int i; - - RTR3InitExeNoArguments(RTR3INIT_FLAGS_SUPLIB); - RTPrintf("tstTime: TESTING...\n"); - - /* - * RTNanoTimeTS() shall never return something which - * is less or equal to the return of the previous call. - */ - - RTTimeSystemNanoTS(); RTTimeNanoTS(); RTThreadYield(); - uint64_t u64RTStartTS = RTTimeNanoTS(); - uint64_t u64OSStartTS = RTTimeSystemNanoTS(); - - uint64_t u64Prev = RTTimeNanoTS(); - for (i = 0; i < 100*_1M; i++) - { - uint64_t u64 = RTTimeNanoTS(); - if (u64 <= u64Prev) - { - /** @todo wrapping detection. */ - RTPrintf("tstTime: error: i=%#010x u64=%#llx u64Prev=%#llx (1)\n", i, u64, u64Prev); - cErrors++; - 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++; - RTThreadYield(); - u64 = RTTimeNanoTS(); - } - if (!(i & (_1M*2 - 1))) - { - RTPrintf("tstTime: i=%#010x u64=%#llx u64Prev=%#llx delta=%lld\n", i, u64, u64Prev, u64 - u64Prev); - RTThreadYield(); - u64 = RTTimeNanoTS(); - } - u64Prev = u64; - } - - RTTimeSystemNanoTS(); RTTimeNanoTS(); RTThreadYield(); - uint64_t u64RTElapsedTS = RTTimeNanoTS(); - uint64_t u64OSElapsedTS = RTTimeSystemNanoTS(); - u64RTElapsedTS -= u64RTStartTS; - u64OSElapsedTS -= u64OSStartTS; - int64_t i64Diff = u64OSElapsedTS >= u64RTElapsedTS ? u64OSElapsedTS - u64RTElapsedTS : u64RTElapsedTS - u64OSElapsedTS; - if (i64Diff > (int64_t)(u64OSElapsedTS / 1000)) - { - RTPrintf("tstTime: error: total time differs too much! u64OSElapsedTS=%#llx u64RTElapsedTS=%#llx delta=%lld\n", - u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS); - cErrors++; - } - 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); -#endif - if (!cErrors) - RTPrintf("tstTime: SUCCESS\n"); - else - RTPrintf("tstTime: FAILURE - %d errors\n", cErrors); - return !!cErrors; -} 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 -#include -#include -#include -#include #include #include +#include #include #include +#include #include +#include +#include +#include @@ -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; @@ -35,6 +35,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 @@ -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 #include #include +#include #include #include #include #include -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]
[
[..]]\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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +/******************************************************************************* +* 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 ] [-l ] [-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 +#include +#include +#include + + +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/ASMGetGDTR.asm b/src/VBox/Runtime/win/amd64/ASMGetGDTR.asm deleted file mode 100644 index 0356e3c5..00000000 --- a/src/VBox/Runtime/win/amd64/ASMGetGDTR.asm +++ /dev/null @@ -1,41 +0,0 @@ -;; @file -; IPRT - ASMGetGDTR(). -; - -; -; 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 "iprt/asmdefs.mac" - -BEGINCODE - -;; -; Gets the content of the GDTR CPU register. -; @param rcx pGdtr Where to store the GDTR contents. -; -BEGINPROC_EXPORTED ASMGetGDTR - sgdt [rcx] - ret -ENDPROC ASMGetGDTR - 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/ASMGetIDTR.asm b/src/VBox/Runtime/win/amd64/ASMGetIDTR.asm deleted file mode 100644 index 7f098fe4..00000000 --- a/src/VBox/Runtime/win/amd64/ASMGetIDTR.asm +++ /dev/null @@ -1,42 +0,0 @@ -;; @file -; IPRT - ASMGetIDTR(). -; - -; -; 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 "iprt/asmdefs.mac" - -BEGINCODE - -;; -; Gets the content of the IDTR CPU register. -; @param rcx pIdtr Where to store the IDTR contents. -; -BEGINPROC_EXPORTED ASMGetIDTR - sidt [rcx] - ret -ENDPROC ASMGetIDTR - - 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/ASMGetTR.asm b/src/VBox/Runtime/win/amd64/ASMGetTR.asm deleted file mode 100644 index 8a3f5ce8..00000000 --- a/src/VBox/Runtime/win/amd64/ASMGetTR.asm +++ /dev/null @@ -1,42 +0,0 @@ -;; @file -; IPRT - ASMGetTR(). -; - -; -; 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 "iprt/asmdefs.mac" - -BEGINCODE - -;; -; Get the TR register. -; @returns TR. -; -BEGINPROC_EXPORTED ASMGetTR - str ax - movzx eax, ax - ret -ENDPROC ASMGetTR - 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; -- cgit v1.2.1